#!/usr/bin/perl # Help: use perldoc -F jp2moz =pod =head1 Introduction and Presentation The script jp2moz (jpilot to mozilla) creates out of a CSV file exported by Jpilot 0.99.5, a CSV file readable by Mozilla. Two things need to be considered for this purpose: =over 4 =item * The fields are different between both formats =item * The format exported by JPilot uses indirection, i.e. field phoneLabelX contains the meaning of the content of field PhoneX; something Mozilla can't cope with at all... =back Well, nevertheless, here is how the stuff works: =over 4 =item 1 Create a CSV file from JPilot called jpilot.csv =item 2 Call 'jp2moz' in the directory where you created the file. =item 3 A new file 'mozPalmPilot.csv' is created in the same directory. =item 4 You can then import this last file using the 'Tools --> Import... --> Address Book' function from Mozilla (tested with 1.2.1 and 1.3.1). You might need to reshuffle the fields if you didn't keep the default order. =back (c) 2003, by Eric Lavarde (linux@zorglub.s.bawue.de) =head1 Annex, some useful knowledge =head2 jpilot fields (in order) Category Private Last First Title Company Phone1 Phone2 Phone3 Phone4 Phone5 Address City State ZipCode Country Custom1 Custom2 Custom3 Custom4 Note phoneLabel1 phoneLabel2 phoneLabel3 phoneLabel4 phoneLabel5 showPhone =head2 jpilot Phone Number meaning =over 4 =item 0 Work Phone =item 1 Home Phone =item 2 Fax =item 3 Other Phone =item 4 Email =item 5 Company Standard Phone =item 6 Pager (? Funkruf in German) =item 7 Mobile =back =head2 mozilla fields (in default order) First Last Display Nickname Email AdditionalEmail WorkPhone HomePhone Fax Pager Mobile HomeAddress1 HomeAddress2 HomeCity HomeState HomeZip HomeCountry WorkAddress1 WorkAddress2 WorkCity WorkState WorkZip WorkCountry WorkTitle WorkDepartment WorkOrganization WorkWebPage HomeWebPage BirthYear BirthMonth BirthDay Custom1 Custom2 Custom3 Custom4 Notes =head1 Annex, source code comments =cut use IO::File; require Text::CSV_XS; my $jpcsv = Text::CSV_XS->new({ 'binary' => 1, 'eol' => "\012" }); my $mozcsv = Text::CSV_XS->new({ 'binary' => 1, 'eol' => "\012", 'escape_char' => "\\" }); =pod The files used for conversion are defined in the variable '$jpfile' and '$mozfile' and can be, of course modified by the user. =cut my $jpfile = new IO::File "jpilot.csv", "r" || die; my $mozfile = new IO::File "mozPalmPilot.csv", "w" || die; my $jpcols; my $mozcols; =pod The main (and quite easy loop) of the program: take each line of the jpfile in an array, transform it for Mozilla using the function 'jp2moz' and write it to the Mozilla csv file. =cut $jpcols = $jpcsv->getline($jpfile); while ( @$jpcols ) { print @$jpcols,"\n"; $mozcsv->print($mozfile, jp2moz($jpcols) ) || die; $jpcols = $jpcsv->getline($jpfile); } exit 0; =pod The function 'jp2moz' is the main and unique function of the program. Input parameter is an array reference. Output parameter is as well an array reference. The idea is: $mozcols = jp2moz($jpcols); As many of the decisions taken in the function are discutable, the user should feel free to modify it as he likes it. I tried to mark the most interesting parts to modify with 3 arobases (@@@). =cut sub jp2moz { my $myjp=shift; my @jp = qw/Category Private Last First Title Company Phone1 Phone2 Phone3 Phone4 Phone5 Address City State ZipCode Country Custom1 Custom2 Custom3 Custom4 Note phoneLabel1 phoneLabel2 phoneLabel3 phoneLabel4 phoneLabel5 showPhone/; my %jp; # difference in the array between a phone and it's label my $phone2label=(21-6); my @palmlabels = qw/WorkPhone HomePhone Fax OtherPhone Email CompanyPhone Pager Mobile/; my @moz = qw/First Last Display Nickname Email AdditionalEmail WorkPhone HomePhone Fax Pager Mobile HomeAddress1 HomeAddress2 HomeCity HomeState HomeZip HomeCountry WorkAddress1 WorkAddress2 WorkCity WorkState WorkZip WorkCountry WorkTitle WorkDepartment WorkOrganization WorkWebPage HomeWebPage BirthYear BirthMonth BirthDay Custom1 Custom2 Custom3 Custom4 Notes/; my %moz; # we transform the jpilot and mozilla arrays in a hash, # makes things clearer. for(my $i=0;$i<@jp;$i++) { $jp{$jp[$i]} = $jpcols->[$i]; } for(my $i=0;$i<@moz;$i++) { $moz{$moz[$i]} = $moz[$i]; } # @@@ That's specific to my Palm, change it for you... $jp{"Birthday"}=$jp{"Custom1"}; $jp{"Department"}=$jp{"Custom2"}; $jp{"NickName"}=$jp{"Custom3"}; $jp{"WebPage"}=$jp{"Custom4"}; ## Now let's do the translation... @@@ you might not like mine. $moz{"First"}=$jp{"First"}; $moz{"Last"}=$jp{"Last"}; $moz{"Display"}=$jp{"First"}." ".$jp{"Last"}; $moz{"Nickname"}=$jp{"NickName"}; ## undirection of the phone/email for(my $i=6; $i<11; $i++) { if ($jp{$jp[$i]}) { # is the field at all non-empty ? if ($jp{$jp[$i+$phone2label]} == 0 && $moz{"WorkPhone"} eq "WorkPhone" ) { $moz{"WorkPhone"}=$jp{$jp[$i]}; } elsif ($jp{$jp[$i+$phone2label]} == 1 && $moz{"HomePhone"} eq "HomePhone" ) { $moz{"HomePhone"}=$jp{$jp[$i]}; } elsif ($jp{$jp[$i+$phone2label]} == 2 && $moz{"Fax"} eq "Fax" ) { $moz{"Fax"}=$jp{$jp[$i]}; } elsif ($jp{$jp[$i+$phone2label]} == 4 && ( $moz{"Email"} eq "Email" || $moz{"AdditionalEmail"} eq "AdditionalEmail" ) ) { if ($moz{"Email"} eq "Email") { $moz{"Email"}=$jp{$jp[$i]}; } else { $moz{"AdditionalEmail"}=$jp{$jp[$i]}; # 05 AdditionalEmail } } elsif ($jp{$jp[$i+$phone2label]} == 6 && $moz{"Pager"} eq "Pager" ) { $moz{"Pager"}=$jp{$jp[$i]}; } elsif ($jp{$jp[$i+$phone2label]} == 7 && $moz{"Mobile"} eq "Mobile" ) { $moz{"Mobile"}=$jp{$jp[$i]}; } else { if ( $moz{"Custom3"} eq "Custom3" ) { $moz{"Custom3"}=$palmlabels[$jp{$jp[$i+$phone2label]}]. ": ".$jp{$jp[$i]}; } elsif ( $moz{"Custom4"} eq "Custom4" ) { $moz{"Custom4"}=$palmlabels[$jp{$jp[$i+$phone2label]}]. ": ".$jp{$jp[$i]}; } else { # if we really don't want to loose any information $jp{"Note"}=$jp{"Note"}."\n@". $palmlabels[$jp{$jp[$i+$phone2label]}]. ": ".$jp{$jp[$i]}; } } # end of "else" part } # end of "if non-empty" question } # end of "for" loop # We need to reorganize the address fields... my @address=split /\n+/,$jp{"Address"}; if (@address > 2) { $address[0]=join " | ",@address[0..-2]; $address[1]=$address[-1]; } # we use the one Palm address depending on the privateness of the entry if ( $jp{"Private"} eq "0" ) { $moz{"HomeAddress1"}=""; $moz{"HomeAddress2"}=""; $moz{"HomeCity"}=""; $moz{"HomeState"}=""; $moz{"HomeZip"}=""; $moz{"HomeCountry"}=""; $moz{"HomeWebPage"}=""; $moz{"WorkAddress1"}=$address[0]; $moz{"WorkAddress2"}=$address[1]; $moz{"WorkCity"}=$jp{"City"}; $moz{"WorkState"}=$jp{"State"}; $moz{"WorkZip"}=$jp{"ZipCode"}; $moz{"WorkCountry"}=$jp{"Country"}; $moz{"WorkWebPage"}=$jp{"WebPage"}; } else { $moz{"HomeAddress1"}=$address[0]; $moz{"HomeAddress2"}=$address[1]; $moz{"HomeCity"}=$jp{"City"}; $moz{"HomeState"}=$jp{"State"}; $moz{"HomeZip"}=$jp{"ZipCode"}; $moz{"HomeCountry"}=$jp{"Country"}; $moz{"HomeWebPage"}=$jp{"WebPage"}; $moz{"WorkAddress1"}=""; $moz{"WorkAddress2"}=""; $moz{"WorkCity"}=""; $moz{"WorkState"}=""; $moz{"WorkZip"}=""; $moz{"WorkCountry"}=""; $moz{"WorkWebPage"}=""; } $moz{"WorkTitle"}=$jp{"Title"}; $moz{"WorkDepartment"}=$jp{"Department"}; $moz{"WorkOrganization"}=$jp{"Company"}; # The birthday doesn't appear in the GUI but is saved in the DB # (see bugzilla, searching for birthday...). $moz{"BirthYear"}=""; $moz{"BirthMonth"}=""; $moz{"BirthDay"}=""; ($moz{"BirthYear"},$moz{"BirthMonth"},$moz{"BirthDay"}) = split /-/,$jp{"Birthday"}; $moz{"Custom1"}=$jp{"Birthday"}; # to be sure to have it visible $moz{"Custom2"}="Category: ".$jp{"Category"}; $moz{"Notes"}=$jp{"Note"}; ## and we transform back the mozilla array... for(my $i=0;$i<@moz;$i++) { # for each, look if something has moved if ( $moz{$moz[$i]} eq $moz[$i] ) { # no $moz[$i]=""; } else { # yes $moz[$i] = $moz{$moz[$i]}; # following required due to Mozilla (1.2.1, SuSE 8.2) # not escaping double quotes at import time. $moz[$i] =~ s/"/'/g; } } return \@moz; }