File Coverage

blib/lib/Mail/Addressbook/Convert/Ldif.pm
Criterion Covered Total %
statement 160 190 84.2
branch 33 54 61.1
condition 5 12 41.6
subroutine 7 7 100.0
pod 3 3 100.0
total 208 266 78.2


line stmt bran cond sub pod time code
1             =head1 NAME
2              
3             Mail::Addressbook::Convert::Ldif - convert to and from Ldif formatted addressbooks
4              
5             =head1 SYNOPSIS
6              
7             use strict;
8              
9             use Mail::Addressbook::Convert::Ldif;
10              
11             my $LDIF = new Mail::Addressbook::Convert::Ldif();
12              
13             my $LdifInFile ="ldifSample.txt"; # name of the file containing the Ldif data
14              
15             # Convert Ldif to Standard Intermediate format
16              
17             # see documentation for details on format.
18              
19             my $raIntermediate = $LDIF->scan(\$LdifInFile);
20              
21             # This will also work
22              
23             #my @LdifInArray = @arrayContainingTheLdifData;
24              
25             #my $raIntermediate = $LDIF->scan(\@LdifInArray);
26              
27              
28             # Convert back to Ldif
29              
30             my $raLdifOut = $LDIF->output($raIntermediate);
31              
32             print join "", @$raIntermediate;
33              
34             print "\n\n\n\n";
35              
36             print join "", @$raLdifOut;
37              
38             =head1 REQUIRES
39              
40             Perl, version 5.001 or higher
41              
42             Carp
43              
44             =head1 DESCRIPTION
45              
46             This module is meant to be used as part of the Mail::Addressbook::Convert distribution.
47              
48             It can convert a Ldif addressbook to a Standard Intermediate format(STF) and a STF to Ldif
49             As part of the larger distribution, it will allow conversion between Ldif and many other
50             formats.
51              
52             To use to convert between Ldif and Eudora as an example, you would do the following
53              
54             use Mail::Addressbook::Convert::Ldif;
55              
56             use Mail::Addressbook::Convert::Eudora;
57              
58             my $Ldif = new Mail::Addressbook::Convert::Ldif();
59              
60             my $Eudora = new Mail::Addressbook::Convert::Eudora();
61              
62             my $LdifInFile ="ldifSample.txt"; # name of the file containing the Ldif data
63              
64             my $raIntermediate = $Ldif->scan(\$LdifInFile);
65              
66             my $raEudora = $Eudora->output($raIntermediate); # reference to an array containing a Eudora addressbook
67              
68              
69             =head1 DEFINITIONS
70            
71             Standard Intermediate Format(STF) :
72              
73             The addressbook format that is used as an intermediate
74             between conversions. It is rfc822 compliant and can
75             be used directly as a Eudora addressbook. Do not use
76             a Eudora addressbook as an STF. Some versions of
77             Eudora use a format, that while RFC822 compliant, will
78             not work as an STF. Run the Eudora addressbook
79             through $Eudora->scan()
80            
81             Ldif addressbook:
82             A ldif addressbook. (LDAP Data Interchange Format)
83             This module works on ldif
84             files ouputted by the Netscape Client and Netscape Server.
85             You can find information on various formats by searching
86             for B on google.com .
87            
88              
89             =head1 METHODS
90              
91             =head2 new
92              
93             no arguments needed.
94              
95             =head2 scan
96              
97             Input : a reference to an array containing a ldif file or a reference to a scalar containing
98             the file name with the ldif data.
99            
100             Returns: a reference to a STF ( see above).
101              
102             =head2 output
103              
104             Input: a reference to a STF ( see above).
105             Returns : a reference to an array containing a ldif file.
106              
107              
108             =head1 LIMITATIONS
109              
110             This only converts email address, aliases, and mailing lists. Phone numbers,
111             postal addresses and other such data are not converted.
112              
113             This has only been tested on Ldif files produced by Netscape Communicator and
114             the Netscape Server.
115              
116              
117             =head1 REFERENCES
118              
119             You can find information on the ldif format by searching for "ldif" on google.com .
120              
121             I derived the format by visually inspecting examples, not by reading a document.
122              
123            
124              
125             =head1 HISTORY
126              
127             This code is derived from the code used on www.interguru.com/mailconv.htm . The site
128             has been up since 1996 ( but ldif was only included on 1997, when Netscape 3 started
129             using it.) The site gets about 8000 unique visitors a month, many of whom make addressbook
130             conversions. The code has been well tested.
131              
132             =head1 FUTURE DIRECTIONS
133              
134              
135             Maybe use Net::LDAP::LDIF for the scan method.
136              
137             =head1 SEE ALSO
138              
139             Mozilla::LDAP::LDIF
140             Net::LDAP::LDIF
141              
142              
143              
144             =head1 BUGS
145              
146             =head1 CHANGES
147              
148             Original Version 2001-Sept-09
149            
150             =head1 COPYRIGHT
151              
152             Copyright (c) 2001 Joe Davidson. All rights reserved.
153             This program is free software; you can redistribute it
154             and/or modify it under the terms of the Perl Artistic License
155             (see http://www.perl.com/perl/misc/Artistic.html). or the
156             GPL copyleft license ( http://www.gnu.org/copyleft/gpl.html)
157              
158              
159             =head1 AUTHOR
160              
161             Mail::Addressbook::Convert was written by Joe Davidson in 2001.
162              
163             =cut
164              
165             #------------------------------------------------------------------------------
166              
167 1     1   3920 use strict;
  1         2  
  1         47  
168              
169              
170             package Mail::Addressbook::Convert::Ldif;
171              
172 1     1   657 use Mail::Addressbook::Convert::PersistentUtilities;
  1         3  
  1         25  
173 1     1   5 use Mail::Addressbook::Convert::Utilities;
  1         1  
  1         49  
174 1     1   22 use 5.001;
  1         3  
  1         2701  
175              
176             sub new {
177 1     1 1 16 bless {},shift;
178             }
179              
180             ######################################################################
181              
182              
183             sub scan {
184              
185 1     1 1 8 my $Ldif = shift;
186 1         1 my $inputParm = shift; # reference to input ldif data as an array or reference to a
187             # scalar containing the name of a file containing the ldif.
188            
189 1         9 my $perUtil = new Mail::Addressbook::Convert::PersistentUtilities();
190              
191 1         7 my $raLdifArray= getInput($inputParm);
192             #NOTE
193             # This method has been modified and never cleaned up
194             # There may be some sections of code which are either never
195             # executed, or irrelevant to the output.
196             #As it stands, it can process ldif output from Netscape Communicator
197             # and the Netscape LDAP server
198             # jhd 19980925
199              
200              
201              
202              
203 1         2 my ($alias, $fullName, $outLine, %aliasOf, @outputFile);
204              
205 1         4 push (@$raLdifArray,"dn:\n\n"); #put final dn: line in for processing purposes
206             # as "dn:" acts as an end of record marker in this code
207              
208 1         2 my (%group,$address);
209 1         5 foreach my $i (@$raLdifArray)
210             {
211 72         67 my ($temp,$isGroup, $xalias) ;
212 72         84 $i =~ s/[\x88\xa9\xd8]//g;
213 72         80 $i =~ s/[\x7e-\xff]//g;
214 72 100       145 if ($i =~ /^objectclass: groupOfNames|^objectclass: groupOfUniqueNames/)
215             {
216 2         2 $isGroup = 1;
217             }
218 72 100       109 if ($i =~ /^objectclass: person/)
219             {
220 4         4 $isGroup = 0;
221             }
222 72 100       280 if ($i =~ /^xnavnickname:|^xmozillanickname:/)
223             {
224 6         13 ($temp,$xalias) = split(/\:/,$i);
225 6         7 chomp $xalias;
226 6         20 $xalias =~ s/\s+//g;
227             }
228 72 100       118 if ($i =~ /^mail\:/)
229             {
230 4         9 $i =~ s/:\s+/:/;
231 4         10 ($temp,$address) = split(/\:/,$i);
232 4         4 chomp $address;
233 4         6 $address =~ s/\s+//g;
234             }
235 72 100       250 if ($i =~ /^member\:|^uniquemember\:/)
236             {
237 5         6 my ($rm, $rawMember);
238 5         13 $i =~ s/:\s+/:/;
239 5         13 ($temp, $rawMember) = split(/\:/,$i);
240 5         6 chomp $rawMember;
241 5 100       12 if ($rawMember =~ /,mail=/)
242             {
243 4         12 ($a,$rm) = split(/\,mail=/,$rawMember)
244             #($a,$rawMember) = split(/\,mail=/,$rawMember)
245             }
246             else
247             {
248 1         4 ($a,$rm) = split(/cn=/,$rawMember)
249             }
250 5         11 $rawMember = (split(",",$rm))[0];
251 5         7 $rawMember =~ tr/A-Z/a-z/;
252 5         10 $rawMember =~ s/ /_/g;
253 5 100       11 if ($aliasOf{$rawMember})
254             {
255 4         5 $rawMember = $aliasOf{$rawMember};
256             }
257 5         10 $group{$alias} .=$rawMember.',';
258 5         13 $group{$alias} =~ s/\n|\r//g;
259              
260             }
261 72 100       129 if ($i =~ /^dn/)
262             {
263 7         20 $i =~ s/:\s+/:/;
264 7         18 ($temp,$fullName) = split(/\:/,$i);
265 7         12 $fullName = (split(",",$fullName))[0];
266 7         10 {local $^W;
  7         15  
267 7         15 $fullName =~ s/cn=//;
268 7         8 $fullName =~ s/"//g;
269 7         9 chomp $fullName;
270 7         9 $alias = $fullName;
271 7         16 $alias =~ s/ /_/g ;
272             }
273            
274              
275             }
276 72 100       184 if ($i !~ /\S/)
277 6         12 { local $^W;
278 6         6 my ($outline);
279              
280 6 100 66     25 if(!$isGroup and $alias)
281             {
282 5 50       8 $alias = $xalias if $xalias;
283 5         24 $alias = $perUtil->makeAliasUnique($alias,"_");
284 5         20 $aliasOf{$address} = $alias;
285            
286 5 50       10 if ($fullName !~ /@/)
287             {
288 5         12 $outLine = qq(alias $alias "$fullName"<$address>);
289             }
290             else
291             {
292 0         0 $outLine = qq(alias $alias $address);
293             }
294 5         12 $outLine =~ s/\n|\r|\015//g;
295 5         9 push (@outputFile, $outLine."\n");
296 5         7 undef $address;
297 5         4 undef $outline;
298 5         5 undef $alias;
299 5         4 undef $xalias;
300 5         12 undef $fullName;
301             }
302             }
303             } #end of input array
304 1         9 foreach my $key (sort keys %group)
305             {
306 2         4 my $mems = $group{$key};
307 2         7 chop $mems;
308 2         4 my $hold = "alias $key $mems";
309 2         7 $hold =~ s/\n|\r//g;
310 2         6 push (@outputFile,
311             "$hold\n");
312              
313             }
314 1         19 return \@outputFile;
315             }
316              
317              
318             ########################### sub output #######################
319             sub output
320              
321             {
322              
323 1     1 1 7 my (@outputFile, $alias1,);
324              
325 1         2 my $Ldif = shift;
326 1         2 my $raInputArray = shift; # reference to input Input data as an array
327              
328              
329              
330 1         2 my $id = 0; my $k=0; my $numberOfGroups=0;
  1         1  
  1         2  
331              
332 1         2 my ($aliasold, %aliasid, %note, $firstName, $lastName, $name, $address, @groupaddr);
333 0         0 my (@indivname, @indivaddr, @indivalias, @groupalias, %indivnameForLists);
334 0         0 my (%indivaddrForLists, %isGroup, $aliasid1 , @groupmembers);
335              
336 1         3 foreach (@$raInputArray )
337             {
338 7         23 my @line = split(" ",$_,3);
339 7         11 my $alias= $line[1];
340 7         9 $aliasold = $alias;
341 7         18 $alias = &cleanalias($aliasold);
342 7         15 my $rest = $line[2];
343 7         7 my $rest1 = $rest;
344 7 50 33     21 if ($aliasid{$alias} && ($line[0] ne "note") )
345             # this alias alrady exists
346             {
347            
348             }
349            
350             else # unique alias, process the data
351             {
352            
353 7         7 my %aliasid;
354 7 50       14 if ($line[0] eq "alias") # This is an alias line
355             {
356 7         8 $id++;
357 7         16 $aliasid{$alias} = $id;
358 7         18 my $commas_outside_quotes1 = &commas_outside_quotes($rest);
359 7 100       13 if ($commas_outside_quotes1)
360             {
361             # There are commas not enclosed in quotes
362             #we have a group list.
363 2         5 $isGroup{$alias} = 1;
364 2         4 $groupalias[$numberOfGroups] = $alias;
365 2         4 $groupaddr[$numberOfGroups] = $rest;
366 2         37 $groupaddr[$numberOfGroups] =~ s/\s*//g; # get rid of all spaces
367 2         8 $numberOfGroups++;
368             }
369             else # we have an individual address
370             {
371 5         18 $indivalias[$k] = $alias;
372 5 50       14 if ( $rest =~ /
    0          
373             # compound address of form Name
374             {
375 5         15 ($name,$address) = split(/
376 5         9 chop ($address);
377 5         66 $address =~s/>*//g;
378 5         15 $name =~ s/\"//g;
379 5         7 $name =~ s/\'//g;
380 5         10 $indivname[$k] = $name;
381             #$holdname{$alias} = $name;
382 5         7 $rest = $address;
383             }
384             elsif ( $rest =~ /\(/)
385             # compound address of form Address(Name)
386             {
387 0         0 ($address,$name) = split(/\(/,$rest);
388 0         0 $name =~s/\)*//g;
389 0         0 $name =~ s/\"//g;
390 0         0 $name =~ s/\'//g;
391 0         0 chomp($name);
392 0         0 chop($address);
393 0         0 $indivname[$k] = $name;
394             #$holdname{$alias} = $name;
395 0         0 $rest = $address;
396             }
397             else # no name give, use the alias as a name
398             {
399 0         0 $indivname[$k] = $alias;
400             }
401 5         7 $indivaddr[$k] = $rest;
402 5         11 $indivaddrForLists{$alias} = $indivaddr[$k] ;
403 5         7 $indivnameForLists{$alias} = $indivname[$k] ;
404 5         16 $k++;
405             }
406             }
407             else #we have a note
408             {
409 0         0 $note{$alias} = $rest1;
410             }
411             } # end of processing addresses
412             }
413             # Write individual alias section
414              
415 1         3 foreach my $kk (0 .. $k-1)
416             {
417 5         6 my @hold;
418 5         7 $alias1 = $indivalias[$kk];
419 5 50       12 if ($note{$alias1})
420             {
421 0 0       0 if ($note{$alias1} =~ /name:(.+)>/)
422             {
423 0         0 @hold = split(/>/,$1);
424 0 0       0 $indivname[$kk] = $hold[0]
425             if length($hold[0]) =~ /\S/;
426             }
427             }
428 5         12 @hold = split(" ",$indivname[$kk]);
429 5         7 $lastName = pop(@hold);
430 5         10 $firstName = join(" ",@hold);
431 5         12 push (@outputFile,"\ndn: cn=$indivname[$kk],mail=$indivaddr[$kk]\n");
432 5         8 push (@outputFile,"cn: $indivname[$kk]\n");
433 5         11 push (@outputFile,"sn: $lastName\n");
434 5         6 push (@outputFile,"objectclass: top\n");
435 5         6 push (@outputFile,"objectclass: person\n");
436 5         15 push (@outputFile,"mail: $indivaddr[$kk]\n");
437 5         10 push (@outputFile,"givenname: $firstName\n");
438 5         8 push (@outputFile,"uid: $alias1\n");
439 5         9 push (@outputFile,"xnavnickname: $alias1\n");
440 5         10 push (@outputFile,"xmozillanickname: $alias1\n");
441 5 50       9 if ($note{$alias1})
442             {
443 0         0 push (@outputFile,"description: $note{$alias1}\n");
444 0 0       0 if ($note{$alias1} =~ /phone:(.+)>/)
445             {
446 0         0 @hold = split(/>/,$1);
447 0         0 push (@outputFile,
448             "telephonenumber: $hold[0]\n");
449             }
450             }
451 5 50 33     29 if ($note{$alias1} and $note{$alias1} =~ /fax:(.+)>/)
452             {
453 0         0 @hold = split(/>/,$1);
454 0         0 push (@outputFile,
455             "facsimiletelephonenumber: $hold[0]\n");
456             }
457 5 50 33     21 if ($note{$alias1} and $note{$alias1} =~ /Home phone.+:(.+)/)
458             {
459 0         0 @hold = split(/
460 0         0 $hold[0] =~ s/^\s+//;
461 0         0 push (@outputFile,
462             "homephone: $hold[0]\n");
463             }
464            
465              
466            
467             }
468              
469              
470             # Write group lists section
471 1         18 foreach my $jj (0 .. $numberOfGroups -1)
472             {
473 2         3 $alias1 = $groupalias[$jj];
474              
475              
476 2         5 push (@outputFile,"\ndn: cn=$alias1\n");
477 2         4 push (@outputFile,"cn: $alias1\n");
478 2         3 push (@outputFile,"objectclass: top\n");
479 2         3 push (@outputFile,"objectclass: groupOfNames\n");
480 2         3 push (@outputFile,"uid: $alias1\n");
481 2         4 push (@outputFile,"xnavnickname: $alias1\n");
482            
483 2         5 @groupmembers = split(",",$groupaddr[$jj]);
484 2         3 my $localalias;
485 2         3 for (@groupmembers)
486             {
487 5 50       10 if (!/\@/) # We do not have an internet address as a group member
488             {
489 5         12 $localalias = &cleanalias($_);
490             }
491             else # We have a internet address -- do not modify
492             # This makes the error message clearer
493             {
494 0         0 $localalias = $_;
495             }
496              
497 5 50       20 if ($aliasid{$localalias}) # alias exists
498             {
499 0         0 $aliasid1 = $aliasid{$localalias};
500 0 0       0 if ($isGroup{$localalias}) #The alias belongs
501             # to a group
502             {
503 0         0 push (@outputFile, "member: cn=$localalias\n");
504             }
505             else #An individual alias
506             {
507            
508 0         0 push (@outputFile,
509             "member: cn=$indivnameForLists{$localalias},mail=$indivaddrForLists{$localalias}\n");
510            
511             }
512            
513             }
514            
515             }
516              
517              
518              
519             }
520              
521 1         7 return \@outputFile;
522             }
523              
524              
525              
526             ########################### end sub output #######################
527             1;