File Coverage

blib/lib/Net/LDAP/LDIF.pm
Criterion Covered Total %
statement 277 364 76.1
branch 125 220 56.8
condition 57 147 38.7
subroutine 26 36 72.2
pod 13 17 76.4
total 498 784 63.5


line stmt bran cond sub pod time code
1             # Copyright (c) 1997-2008 Graham Barr . All rights reserved.
2             # This program is free software; you can redistribute it and/or
3             # modify it under the same terms as Perl itself.
4              
5             package Net::LDAP::LDIF;
6              
7 22     22   64517 use strict;
  22         56  
  22         928  
8             require Net::LDAP::Entry;
9              
10 22     22   113 use constant CHECK_UTF8 => $] > 5.007;
  22         38  
  22         1504  
11              
12             BEGIN {
13             require Encode
14 22     22   47978 if (CHECK_UTF8);
15             }
16              
17             our $VERSION = '0.26';
18              
19             # allow the letters r,w,a as mode letters
20             my %modes = qw(r < r+ +< w > w+ +> a >> a+ +>>);
21              
22             sub new {
23 12     12 1 720 my $pkg = shift;
24 12   50     38 my $file = shift || '-';
25 12 50 50     54 my $mode = @_ % 2 ? shift || 'r' : 'r';
26 12         31 my %opt = @_;
27 12         17 my $fh;
28 12         17 my $opened_fh = 0;
29              
30             # harmonize mode
31             $mode = $modes{$mode}
32 12 50       47 if (defined($modes{$mode}));
33              
34 12 100       32 if (ref($file)) {
35 4         6 $fh = $file;
36             }
37             else {
38 8 50       23 if ($file eq '-') {
39 0 0       0 ($file,$fh) = ($mode eq '<')
40             ? ('STDIN', \*STDIN)
41             : ('STDOUT',\*STDOUT);
42              
43 0 0       0 if ($mode =~ /(:.*$)/) {
44 0         0 my $layer = $1;
45 0         0 binmode($file, $layer);
46             }
47             }
48             else {
49 8 50       538 $opened_fh = ($file =~ /^\| | \|$/x)
50             ? open($fh, $file)
51             : open($fh, $mode, $file);
52 8 50       43 return unless ($opened_fh);
53             }
54             }
55              
56             # Default the encoding of DNs to 'none' unless the user specifies
57 12 50       49 $opt{encode} = 'none' unless (exists $opt{encode});
58              
59             # Default the error handling to die
60 12 50       38 $opt{onerror} = 'die' unless (exists $opt{onerror});
61              
62             # sanitize options
63 12   50     61 $opt{lowercase} ||= 0;
64 12   100     45 $opt{change} ||= 0;
65 12   50     49 $opt{sort} ||= 0;
66 12   100     56 $opt{version} ||= 0;
67              
68 12 50 33     137 my $self = {
69             changetype => 'modify',
70             modify => 'add',
71             wrap => 78,
72             %opt,
73             fh => $fh,
74             file => "$file",
75             opened_fh => $opened_fh,
76             _eof => 0,
77             write_count => ($mode =~ /^\s*\+?>>/ and tell($fh) > 0) ? 1 : 0,
78             };
79              
80 12         86 bless $self, $pkg;
81             }
82              
83             sub _read_lines {
84 17     17   26 my $self = shift;
85 17         23 my $fh = $self->{fh};
86 17         26 my @ldif = ();
87 17         26 my $entry = '';
88 17         22 my $in_comment = 0;
89 17         21 my $entry_completed = 0;
90 17         18 my $ln;
91              
92 17 100       37 return @ldif if ($self->eof());
93              
94 15   100     178 while (defined($ln = $self->{_buffered_line} || scalar <$fh>)) {
95 1021         1259 delete($self->{_buffered_line});
96 1021 50       1418 if ($ln =~ /^#/o) { # ignore 1st line of comments
97 0         0 $in_comment = 1;
98             }
99             else {
100 1021 100       1545 if ($ln =~ /^[ \t]/o) { # append wrapped line (if not in a comment)
101 25 50       93 $entry .= $ln if (!$in_comment);
102             }
103             else {
104 996         1042 $in_comment = 0;
105 996 100       1315 if ($ln =~ /^\r?\n$/o) {
106             # ignore empty line on start of entry
107             # empty line at non-empty entry indicate entry completion
108 12 100       58 $entry_completed++ if (length($entry));
109             }
110             else {
111 984 100       1207 if ($entry_completed) {
112 11         19 $self->{_buffered_line} = $ln;
113 11         16 last;
114             }
115             else {
116             # append non-empty line
117 973         3541 $entry .= $ln;
118             }
119             }
120             }
121             }
122             }
123 15 100       53 $self->eof(1) if (!defined($ln));
124 15         180 $self->{_current_lines} = $entry;
125 15         106 $entry =~ s/\r?\n //sgo; # un-wrap wrapped lines
126 15         37 $entry =~ s/\r?\n\t/ /sgo; # OpenLDAP extension !!!
127 15         399 @ldif = split(/^/, $entry);
128 15         36 map { s/\r?\n$//; } @ldif;
  973         2752  
129              
130 15         239 @ldif;
131             }
132              
133              
134             # read attribute value from URL
135             sub _read_url_attribute {
136 0     0   0 my $self = shift;
137 0         0 my $url = shift;
138 0         0 my @ldif = @_;
139 0         0 my $line;
140              
141 0 0 0     0 if ($url =~ s/^file:(?:\/\/)?//) {
    0          
142 0 0       0 open(my $fh, '<', $url)
143             or return $self->_error("can't open $url: $!", @ldif);
144              
145 0         0 binmode($fh);
146             { # slurp in whole file at once
147 0         0 local $/;
  0         0  
148 0         0 $line = <$fh>;
149             }
150 0         0 close($fh);
151             }
152             elsif ($url =~ /^(https?|ftp|gopher|news:)/ and
153 0         0 eval { require LWP::UserAgent; }) {
154 0         0 my $ua = LWP::UserAgent->new();
155 0         0 my $response = $ua->get($url);
156              
157 0 0       0 return $self->_error("can't get data from $url: $!", @ldif)
158             if (!$response->is_success);
159              
160 0         0 $line = $response->decoded_content();
161              
162 0 0       0 return $self->error("decoding data from $url failed: $@", @ldif)
163             if (!defined($line));
164             }
165             else {
166 0         0 return $self->_error('unsupported URL type', @ldif);
167             }
168              
169 0         0 $line;
170             }
171              
172              
173             # read attribute value (decode it based in its type)
174             sub _read_attribute_value {
175 15     15   24 my $self = shift;
176 15         22 my $type = shift;
177 15         22 my $value = shift;
178 15         112 my @ldif = @_;
179              
180             # Base64-encoded value: decode it
181 15 100 66     69 if ($type && $type eq ':') {
    50 33        
      33        
182 1         411 require MIME::Base64;
183 1         554 $value = MIME::Base64::decode($value);
184             }
185             # URL value: read from URL
186             elsif ($type && $type eq '<' and $value =~ s/^(.*?)\s*$/$1/) {
187 0         0 $value = $self->_read_url_attribute($value, @ldif);
188 0 0       0 return if (!defined($value));
189             }
190              
191 15         55 $value;
192             }
193              
194              
195             # _read_one() is deprecated and will be removed
196             # in a future version
197             *_read_one = \&_read_entry;
198              
199             sub _read_entry {
200 17     17   25 my $self = shift;
201 17         26 my @ldif;
202 17         41 $self->_clear_error();
203              
204 17         39 @ldif = $self->_read_lines;
205              
206 17 100       57 unless (@ldif) { # empty records are errors if not at eof
207 2 50       9 $self->_error('illegal empty LDIF entry') if (!$self->eof());
208 2         6 return;
209             }
210              
211 15 100 66     69 if (@ldif and $ldif[0] =~ /^version:\s+(\d+)/) {
212 1         4 $self->{version} = $1;
213 1         2 shift @ldif;
214 1 50       13 return $self->_read_entry
215             unless (@ldif);
216             }
217              
218 14 50       72 if (@ldif < 1) {
    50          
219 0         0 return $self->_error('LDIF entry is not valid', @ldif);
220             }
221             elsif ($ldif[0] !~ /^dn::? */) {
222 0         0 return $self->_error('First line of LDIF entry does not begin with "dn:"', @ldif);
223             }
224              
225 14         25 my $dn = shift @ldif;
226 14 50       74 my $xattr = $1 if ($dn =~ s/^dn:(:?) *//);
227              
228 14         45 $dn = $self->_read_attribute_value($xattr, $dn, @ldif);
229              
230 14         72 my $entry = Net::LDAP::Entry->new;
231             $dn = Encode::decode_utf8($dn)
232 14 50 33     48 if (CHECK_UTF8 && $self->{raw} && ('dn' !~ /$self->{raw}/));
233 14         54 $entry->dn($dn);
234              
235 14         25 my @controls = ();
236              
237             # optional control: line => change record
238 14   66     62 while (@ldif && ($ldif[0] =~ /^control:\s*/)) {
239 4         8 my $control = shift(@ldif);
240              
241 4 50       22 if ($control =~ /^control:\s*(\d+(?:\.\d+)*)(?:\s+(true|false))?(?:\s*\:(.*))?$/) {
242 4         21 my($oid,$critical,$value) = ($1,$2,$3);
243              
244 4 50 33     16 $critical = ($critical && $critical =~ /true/) ? 1 : 0;
245              
246 4 100       7 if (defined($value)) {
247 2 100       9 my $type = $1 if ($value =~ s/^([\<\:])\s*//);
248              
249 2         5 $value =~ s/^\s*//;
250              
251 2 100       4 if ($type) {
252 1         3 $value = $self->_read_attribute_value($type, $value, @ldif);
253 1 50       3 return $self->_error('Illegal value in control line given', @ldif)
254             if !defined($value);
255             }
256             }
257              
258 4         20 require Net::LDAP::Control;
259 4         16 my $ctrl = Net::LDAP::Control->new(type => $oid,
260             value => $value,
261             critical => $critical);
262              
263 4         6 push(@controls, $ctrl);
264              
265 4 50       21 return $self->_error('Illegally formatted control line given', @ldif)
266             if (!@ldif);
267             }
268             else {
269 0         0 return $self->_error('Illegally formatted control line given', @ldif);
270             }
271             }
272              
273             # LDIF change record
274 14 100 66     74 if ((scalar @ldif) && ($ldif[0] =~ /^changetype:\s*/)) {
275             my $changetype = $ldif[0] =~ s/^changetype:\s*//
276 6 50       20 ? shift(@ldif) : $self->{changetype};
277 6         18 $entry->changetype($changetype);
278              
279 6 50       11 if ($changetype eq 'delete') {
280 0 0       0 return $self->_error('LDIF "delete" entry is not valid', @ldif)
281             if (@ldif);
282 0         0 return $entry;
283             }
284              
285 6 50       13 return $self->_error('LDAP entry is not valid', @ldif)
286             unless (@ldif);
287              
288 6         8 while (@ldif) {
289 6         12 my $action = $self->{modify};
290 6         9 my $modattr;
291             my $lastattr;
292 6         0 my @values;
293              
294 6 50       18 if ($changetype eq 'modify') {
295 0 0       0 unless ((my $tmp = shift @ldif) =~ s/^(add|delete|replace|increment):\s*([-;\w]+)//) {
296 0         0 return $self->_error('LDAP entry is not valid', @ldif);
297             }
298 0         0 $lastattr = $modattr = $2;
299 0         0 $action = $1;
300             }
301              
302 6         9 while (@ldif) {
303 60         68 my $line = shift @ldif;
304              
305 60 50       81 if ($line eq '-') {
306 0 0 0     0 return $self->_error('LDAP entry is not valid', @ldif)
307             if (!defined($modattr) || !defined($lastattr));
308              
309 0         0 last;
310             }
311              
312 60 50       176 if ($line =~ /^([-;\w]+):([\<\:]?)\s*(.*)$/o) {
313 60         128 my ($attr,$xattr,$val) = ($1,$2,$3);
314              
315 60 50 33     99 return $self->_error('LDAP entry is not valid', @ldif)
316             if (defined($modattr) && $attr ne $modattr);
317              
318 60 50       70 $val = $self->_read_attribute_value($xattr, $val, $line)
319             if ($xattr);
320 60 50       77 return if !defined($val);
321              
322             $val = Encode::decode_utf8($val)
323 60 50 33     91 if (CHECK_UTF8 && $self->{raw} && ($attr !~ /$self->{raw}/));
324              
325 60 100 100     135 if (!defined($lastattr) || $lastattr ne $attr) {
326 30 100       78 $entry->$action($lastattr => \@values)
327             if (defined $lastattr);
328              
329 30         35 $lastattr = $attr;
330 30         38 @values = ();
331             }
332 60         103 push(@values, $val);
333             }
334             else {
335 0         0 return $self->_error('LDAP entry is not valid', @ldif);
336             }
337             }
338 6 50       18 $entry->$action($lastattr => \@values)
339             if (defined $lastattr);
340             }
341             }
342             # content record (i.e. no 'changetype' line; implicitly treated as 'add')
343             else {
344 8         16 my $last = '';
345 8         13 my @values;
346              
347 8 50       19 return $self->_error('Controls only allowed with LDIF change entries', @ldif)
348             if (@controls);
349              
350 8         25 foreach my $line (@ldif) {
351 888 50       2666 if ($line =~ /^([-;\w]+):([\<\:]?)\s*(.*)$/o) {
352 888         2245 my($attr,$xattr,$val) = ($1,$2,$3);
353              
354 888 100       1374 $last = $attr if (!$last);
355              
356 888 50       1272 $val = $self->_read_attribute_value($xattr, $val, $line)
357             if ($xattr);
358 888 50       1173 return if !defined($val);
359              
360             $val = Encode::decode_utf8($val)
361 888 50 33     1400 if (CHECK_UTF8 && $self->{raw} && ($attr !~ /$self->{raw}/));
362              
363 888 100       1273 if ($attr ne $last) {
364 32         107 $entry->add($last => \@values);
365 32         66 @values = ();
366 32         47 $last = $attr;
367             }
368 888         1441 push(@values, $val);
369             }
370             else {
371 0         0 return $self->_error("illegal LDIF line '$line'", @ldif);
372             }
373             }
374 8         26 $entry->add($last => \@values);
375             }
376              
377 14         33 $self->{_current_entry} = $entry;
378              
379 14         117 $entry;
380             }
381              
382             sub read_entry {
383 16     16 1 467 my $self = shift;
384              
385             return $self->_error('LDIF file handle not valid')
386 16 50       65 unless ($self->{fh});
387              
388 16         46 $self->_read_entry();
389             }
390              
391             # read() is deprecated and will be removed
392             # in a future version
393             sub read {
394 3     3 0 883 my $self = shift;
395              
396 3 100       14 return $self->read_entry() unless wantarray;
397              
398 1         2 my($entry, @entries);
399 1         4 push(@entries, $entry) while ($entry = $self->read_entry);
400              
401 1         4 @entries;
402             }
403              
404             sub eof {
405 23     23 1 30 my $self = shift;
406 23         29 my $eof = shift;
407              
408 23 100       46 $self->{_eof} = $eof
409             if ($eof);
410              
411 23         52 $self->{_eof};
412             }
413              
414             sub _wrap {
415 312     312   393 my $len = int($_[1]); # needs to be >= 2 to avoid division by zero
416 312 100 66     1192 return $_[0] if (length($_[0]) <= $len or $len <= 40);
417 22     22   34038 use integer;
  22         308  
  22         106  
418 41         50 my $l2 = $len - 1;
419 41         60 my $x = (length($_[0]) - $len) / $l2;
420 41 50       75 my $extra = (length($_[0]) == ($l2 * $x + $len)) ? '' : 'a*';
421 41         230 join("\n ", unpack("a$len" . "a$l2" x $x . $extra, $_[0]));
422             }
423              
424             sub _write_attr {
425 150     150   235 my($self, $attr, $val) = @_;
426 150         201 my $lower = $self->{lowercase};
427 150         191 my $fh = $self->{fh};
428 150         2069 my $res = 1; # result value
429              
430 150         227 foreach my $v (@$val) {
431 284 50       483 my $ln = $lower ? lc $attr : $attr;
432              
433 284 50       538 $v = Encode::encode_utf8($v)
434             if (CHECK_UTF8 and Encode::is_utf8($v));
435              
436 284 50       1592 if ($v =~ /(^[ :<]|[\x00-\x1f\x7f-\xff]| $)/) {
437 0         0 require MIME::Base64;
438 0         0 $ln .= ':: ' . MIME::Base64::encode($v, '');
439             }
440             else {
441 284         435 $ln .= ': ' . $v;
442             }
443 284   33     592 $res &&= print $fh _wrap($ln, $self->{wrap}), "\n";
444             }
445 150         410 $res;
446             }
447              
448             # helper function to compare attribute names (sort objectClass first)
449             sub _cmpAttrs {
450 0 0   0   0 ($a =~ /^objectclass$/io)
    0          
451             ? -1 : (($b =~ /^objectclass$/io) ? 1 : ($a cmp $b));
452             }
453              
454             sub _write_attrs {
455 22     22   34 my($self, $entry) = @_;
456 22         49 my @attributes = $entry->attributes();
457 22         35 my $res = 1; # result value
458              
459 22 50       43 @attributes = sort _cmpAttrs @attributes if ($self->{sort});
460              
461 22         32 foreach my $attr (@attributes) {
462 138         283 my $val = $entry->get_value($attr, asref => 1);
463 138   33     296 $res &&= $self->_write_attr($attr, $val);
464             }
465 22         62 $res;
466             }
467              
468             sub _write_controls {
469 3     3   5 my($self, @ctrls) = @_;
470 3         3 my $res = 1;
471 3         4 my $fh = $self->{fh};
472              
473 3         13 require Net::LDAP::Control;
474              
475 3         22 foreach my $ctrl (@ctrls) {
476 4 50       16 my $ln = 'control: ' . $ctrl->type . ($ctrl->critical ? ' true' : ' false');
477 4         9 my $v = $ctrl->value;
478              
479 4 100       8 if (defined($v)) {
480 2 50       5 $v = Encode::encode_utf8($v)
481             if (CHECK_UTF8 and Encode::is_utf8($v));
482              
483 2 100       12 if ($v =~ /(^[ :<]|[\x00-\x1f\x7f-\xff]| $)/) {
484 1         4 require MIME::Base64;
485 1         4 $v = MIME::Base64::encode($v, '');
486 1         2 $ln .= ':'; # indicate Base64-encoding of $v
487             }
488              
489 2         3 $ln .= ': ' . $v;
490             }
491 4   33     10 $res &&= print $fh _wrap($ln, $self->{wrap}), "\n";
492             }
493 3         9 $res;
494             }
495              
496             sub _write_dn {
497 24     24   47 my($self, $dn) = @_;
498 24         38 my $encode = $self->{encode};
499 24         30 my $fh = $self->{fh};
500              
501 24 50       63 $dn = Encode::encode_utf8($dn)
502             if (CHECK_UTF8 and Encode::is_utf8($dn));
503              
504 24 50       170 if ($dn =~ /^[ :<]|[\x00-\x1f\x7f-\xff]/) {
505 0 0       0 if ($encode =~ /canonical/i) {
    0          
506 0         0 require Net::LDAP::Util;
507 0         0 $dn = Net::LDAP::Util::canonical_dn($dn, mbcescape => 1);
508             # Canonicalizer won't fix leading spaces, colons or less-thans, which
509             # are special in LDIF, so we fix those up here.
510 0         0 $dn =~ s/^([ :<])/\\$1/;
511 0         0 $dn = "dn: $dn";
512             }
513             elsif ($encode =~ /base64/i) {
514 0         0 require MIME::Base64;
515 0         0 $dn = 'dn:: ' . MIME::Base64::encode($dn, '');
516             }
517             else {
518 0         0 $dn = "dn: $dn";
519             }
520             }
521             else {
522 24         54 $dn = "dn: $dn";
523             }
524 24         64 print $fh _wrap($dn, $self->{wrap}), "\n";
525             }
526              
527             # write() is deprecated and will be removed
528             # in a future version
529             sub write {
530 0     0 0 0 my $self = shift;
531              
532 0         0 $self->_write_entry(0, @_);
533             }
534              
535             sub write_entry {
536 8     8 1 340 my $self = shift;
537              
538 8         27 $self->_write_entry($self->{change}, @_);
539             }
540              
541             sub write_version {
542 8     8 1 13 my $self = shift;
543 8         10 my $fh = $self->{fh};
544 8         15 my $res = 1;
545              
546             $res &&= print $fh "version: $self->{version}\n"
547 8 100 33     47 if ($self->{version} && !$self->{version_written}++);
      66        
548              
549 8         39 return $res;
550             }
551              
552             # internal helper: write entry in different format depending on 1st arg
553             sub _write_entry {
554 9     9   13 my $self = shift;
555 9         16 my $change = shift;
556 9         13 my $res = 1; # result value
557 9         23 my @args = ();
558              
559             return $self->_error('LDIF file handle not valid')
560 9 50       26 unless ($self->{fh});
561              
562             # parse list of entries optionally interspersed with lists of option pairs
563             # each option-pair list belongs to the preceding entry
564             # e.g. $entry1, control => $ctrl1, $entry2, $entry3, control => [ $ctrl3a, $ctrl3b ], ...
565 9         22 foreach my $elem (@_) {
566 30 100       67 if (ref($elem)) {
    50          
567 27 100       57 if (scalar(@args) % 2) { # odd number of args: $entry + optional args
568 15   33     713 $res &&= $self->_write_one($change, @args);
569 15         26 @args = ();
570             }
571             }
572             elsif (!@args) { # 1st arg needs to be an N:L:E object
573 0         0 $self->_error("Entry '$elem' is not a valid Net::LDAP::Entry object.");
574 0         0 $res = 0;
575 0         0 @args = ();
576 0         0 next; # try to re-sync
577             }
578              
579 30         52 push(@args, $elem);
580             }
581              
582 9 50       21 if (scalar(@args) % 2) {
    0          
583 9   33     39 $res &&= $self->_write_one($change, @args);
584             }
585             elsif (@args) {
586 0         0 $self->error("Illegal argument list passed");
587 0         0 $res = 0;
588             }
589              
590 9 0 33     24 $self->_error($!) if (!$res && $!);
591              
592 9         20 $res;
593             }
594              
595             # internal helper to write exactly one entry
596             sub _write_one
597             {
598 24     24   34 my $self = shift;
599 24         29 my $change = shift;
600 24         33 my $entry = shift;
601 24         33 my %opt = @_;
602 24         41 my $fh = $self->{fh};
603 24         29 my $res = 1; # result value
604 24         64 local($\, $,); # output field and record separators
605              
606 24 100       40 if ($change) {
607 9         22 my @changes = $entry->changes;
608 9         19 my $type = $entry->changetype;
609              
610             # Skip entry if there is nothing to write
611 9 50 66     30 return $res if ($type eq 'modify' and !@changes);
612              
613 9 100 33     30 $res &&= $self->write_version() unless ($self->{write_count}++);
614 9   33     38 $res &&= print $fh "\n";
615 9   33     30 $res &&= $self->_write_dn($entry->dn);
616              
617             $res &&= $self->_write_controls(ref($opt{control}) eq 'ARRAY'
618 2         6 ? @{$opt{control}}
619             : ( $opt{control} ))
620 9 100 33     28 if ($opt{control});
    100          
621              
622 9   33     40 $res &&= print $fh "changetype: $type\n";
623              
624 9 50       28 if ($type eq 'delete') {
    100          
    50          
625 0         0 return $res;
626             }
627             elsif ($type eq 'add') {
628 7   33     21 $res &&= $self->_write_attrs($entry);
629 7         26 return $res;
630             }
631             elsif ($type =~ /modr?dn/o) {
632 0   0     0 my $deleteoldrdn = $entry->get_value('deleteoldrdn') || 0;
633 0   0     0 $res &&= $self->_write_attr('newrdn', $entry->get_value('newrdn', asref => 1));
634 0   0     0 $res &&= print $fh 'deleteoldrdn: ', $deleteoldrdn, "\n";
635 0         0 my $ns = $entry->get_value('newsuperior', asref => 1);
636 0 0 0     0 $res &&= $self->_write_attr('newsuperior', $ns) if (defined $ns);
637 0         0 return $res;
638             }
639              
640 2         5 my $dash = 0;
641             # changetype: modify
642 2         9 while (my($action,$attrs) = splice(@changes, 0, 2)) {
643 10         19 my @attrs = @$attrs;
644              
645 10         24 while (my($attr,$val) = splice(@attrs, 0, 2)) {
646 12 100 33     61 $res &&= print $fh "-\n" if (!$self->{version} && $dash++);
      66        
647 12   33     51 $res &&= print $fh "$action: $attr\n";
648 12   33     32 $res &&= $self->_write_attr($attr, $val);
649 12 50 0     52 $res &&= print $fh "-\n" if ($self->{version});
650             }
651             }
652             }
653             else {
654 15 100 33     70 $res &&= $self->write_version() unless ($self->{write_count}++);
655 15   33     84 $res &&= print $fh "\n";
656 15   33     51 $res &&= $self->_write_dn($entry->dn);
657 15   33     45 $res &&= $self->_write_attrs($entry);
658             }
659              
660 17         68 $res;
661             }
662              
663             # read_cmd() is deprecated in favor of read_entry()
664             # and will be removed in a future version
665             sub read_cmd {
666 0     0 0 0 my $self = shift;
667              
668 0 0       0 return $self->read_entry() unless wantarray;
669              
670 0         0 my($entry, @entries);
671 0         0 push(@entries, $entry) while ($entry = $self->read_entry);
672              
673 0         0 @entries;
674             }
675              
676             # _read_one_cmd() is deprecated in favor of _read_one()
677             # and will be removed in a future version
678             *_read_one_cmd = \&_read_entry;
679              
680             # write_cmd() is deprecated in favor of write_entry()
681             # and will be removed in a future version
682             sub write_cmd {
683 1     1 0 6 my $self = shift;
684              
685 1         4 $self->_write_entry(1, @_);
686             }
687              
688             sub done {
689 15     15 1 782 my $self = shift;
690 15         22 my $res = 1; # result value
691              
692 15 100       36 if ($self->{fh}) {
693 12 100       28 if ($self->{opened_fh}) {
694 8         250 $res = close($self->{fh});
695 8         30 undef $self->{opened_fh};
696             }
697 12         38 delete $self->{fh};
698             }
699 15         387 $res;
700             }
701              
702             sub handle {
703 0     0 1 0 my $self = shift;
704              
705 0         0 return $self->{fh};
706             }
707              
708             my %onerror = (
709             die => sub {
710             my $self = shift;
711             require Carp;
712             $self->done;
713             Carp::croak($self->error(@_));
714             },
715             warn => sub {
716             my $self = shift;
717             require Carp;
718             Carp::carp($self->error(@_));
719             },
720             undef => sub {
721             my $self = shift;
722             require Carp;
723             Carp::carp($self->error(@_)) if ($^W);
724             },
725             );
726              
727             sub _error {
728 0     0   0 my ($self, $errmsg, @errlines) = @_;
729 0         0 $self->{_err_msg} = $errmsg;
730 0         0 $self->{_err_lines} = join("\n", @errlines);
731              
732 0         0 scalar &{ $onerror{ $self->{onerror} } }($self, $self->{_err_msg})
733 0 0       0 if ($self->{onerror});
734              
735 0         0 return;
736             }
737              
738             sub _clear_error {
739 17     17   21 my $self = shift;
740              
741 17         27 undef $self->{_err_msg};
742 17         30 undef $self->{_err_lines};
743             }
744              
745             sub error {
746 0     0 1 0 my $self = shift;
747 0         0 $self->{_err_msg};
748             }
749              
750             sub error_lines {
751 0     0 1 0 my $self = shift;
752 0         0 $self->{_err_lines};
753             }
754              
755             sub current_entry {
756 0     0 1 0 my $self = shift;
757 0         0 $self->{_current_entry};
758             }
759              
760             sub current_lines {
761 1     1 1 6 my $self = shift;
762 1         4 $self->{_current_lines};
763             }
764              
765             sub version {
766 1     1 1 6 my $self = shift;
767 1 50       11 return $self->{version} unless (@_);
768 0   0     0 $self->{version} = shift || 0;
769             }
770              
771             sub next_lines {
772 0     0 1 0 my $self = shift;
773 0         0 $self->{_next_lines};
774             }
775              
776             sub DESTROY {
777 12     12   1681 my $self = shift;
778 12         34 $self->done();
779             }
780              
781             1;