#!/usr/bin/perl -w
# Usage: perl ConvertVcard.pl infile.vcf outfile.csv

my $vcfpath = $ARGV[0]; my $csvpath = $ARGV[1];

my $finishedentry; my $name; my $address;

open (INFILE, "$vcfpath") or die "Couldn't open logfile: $!"; open
(OUTFILE, ">$csvpath") or die "Couldn't open outputfile: $!";

printf OUTFILE "Title,First Name,Middle Name,Last Name,Suffix,Company,Job Title,Business Street,Business Street 2,Business Street 3,Business City,Business State,Business Postal Code,Business Country,Home Street,Home Street 2,Home Street 3,Home City,Home State,Home Postal Code,Home Country,Business Fax,Business Phone,Home Fax,Home Phone,Mobile Phone,E-mail Address,Home Address PO Box,Notes,Web Page\n";

$thisline=get_line();
while (defined $thisline) {
    #Parse VCF
    $nextline=get_line();
    #print "thisline=$thisline\n";
    while ($thisline =~ /(.*)=[\r\n]*$/)
    {$thisline=$1;
     #print "line so far=$thisline\n";
     # no need: $nextline =~ s/\:/\//g;# ensure no colon in extra quoted lines else they'll be corrupted (converted to /)
     #print "next line=$nextline\n";
     $thisline.=$nextline;
     $nextline=get_line();
    }
    while (defined($nextline))
    {if ($nextline =~ /^ /)
     {# no need: $nextline =~ s/\:/\//g;# ensure no colon in extra quoted lines else they'll be corrupted (converted to /)
      $thisline.=$nextline;# include leading space as it should be there
      $nextline=get_line();
     }
     else
     {last;
     }
    }
    $_=$thisline;
    if (m/^BEGIN\:VCARD/)
    {$Title='';$FirstName='';$MiddleName='';$LastName='';$Suffix='';
     $Company='';$JobTitle='';
     $BusinessStreet='';$BusinessStreet2='';$BusinessStreet3='';$BusinessCity='';$BusinessState='';$BusinessPostalCode='';$BusinessCountry='';
     $HomeStreet='';$HomeStreet2='';$HomeStreet3='';$HomeCity='';$HomeState='';$HomePostalCode='';$HomeCountry='';
     $BusinessFax='';$BusinessPhone='';$HomeFax='';$HomePhone='';$MobilePhone='';$EmailAddress='';$HomeAddressPOBox='';$Notes='';$WebPage='';
     $name = ''; $address = '';#...
    }
    elsif (m/^N\;.*?\:([^\n\r]*)/) # line starts N;names:s;s;s;s;s #'?' makes search non-greedy (so stops at first colon)
    {
     $line = $1;#print "line=$1\n";
     ($LastName,$FirstName,$MiddleName,$Title,$Suffix)=split(/;/,$1);
     #print "\"$Title\",\"$FirstName\",\"$MiddleName\",\"$LastName\",\"$Suffix\"\n";
    }
    elsif (m/^ADR;HOME\;.*?\:([^\n\r]*)/)
    {$line = $1;print "line=$1\n";
     ($HomeAddressPOBox,$temp,$HomeStreet,$HomeCity,$HomeState,$HomePostalCode,$HomeCountry)=split(/;/,$1);
     # ^ $temp is Home ext address whatever that is, HomeStreet will be split into lines
     if ($HomeStreet=~/=0D|=0A/)
     {$HomeStreet=~s/=0D=0A/\;/g;$HomeStreet=~s/=0A/\;/g;$HomeStreet=~s/=0D/\;/g;#print "$HomeStreet\n";
      ($HomeStreet,$HomeStreet2,$HomeStreet3)=split (/\;/,$HomeStreet."\;");
     }
     print "$HomeAddressPOBox,$temp,$HomeStreet,$HomeStreet2,$HomeStreet3,$HomeCity,$HomeState,$HomePostalCode,$HomeCountry\n";
     if ($temp ne "") {print STDERR "Home ext address is $temp, nowhere to store it\n";}
    }
    elsif (m/^ADR;WORK\;.*?\:([^\n\r]*)/)
    {$line = $1;print "line=$1\n";
     ($BusinessAddressPOBox,$temp,$BusinessStreet,$BusinessCity,$BusinessState,$BusinessPostalCode,$BusinessCountry)=split(/;/,$1);
     # ^ $temp is Business ext address whatever that is, BusinessStreet will be split into lines
     if ($BusinessStreet=~/=0D|=0A/)
     {$BusinessStreet=~s/=0D=0A/\;/g;$BusinessStreet=~s/=0A/\;/g;$BusinessStreet=~s/=0D/\;/g;#print "$BusinessStreet\n";
      ($BusinessStreet,$BusinessStreet2,$BusinessStreet3)=split (/\;/,$BusinessStreet."\;");
     }
     print "$BusinessAddressPOBox,$temp,$BusinessStreet,$BusinessStreet2,$BusinessStreet3,$BusinessCity,$BusinessState,$BusinessPostalCode,$BusinessCountry\n";
     if ($temp ne "") {print STDERR "Business ext address is $temp, nowhere to store it\n";}
    }
    elsif (m/^NOTE\;.*?\:([^\n\r]*)/)
    {$Notes = $1;#print "notes=$1\n";
     $Notes=~s/=0D=0A/\r/g;$Notes=~s/=0A/\r/g;$Notes=~s/=0D/\r/g;#print "$Notes\n";# \r used to split lines in Outlook CSV
     $Notes=~s/\\;/\;/g;# real ; was \;
    }
    elsif (m/^TEL;HOME;FAX\;.*?\:([^\n\r]*)/)
    {$HomeFax = $1;
    }
    elsif (m/^TEL;HOME;MOBILE\;.*?\:([^\n\r]*)/)
    {$MobilePhone = $1;# same for work mobile
    }
    elsif (m/^TEL;HOME\;.*?\:([^\n\r]*)/)
    {$HomePhone = $1;
    }
    elsif (m/^TEL;WORK;FAX\;.*?\:([^\n\r]*)/)
    {$BusinessFax = $1;
    }
    elsif (m/^TEL;WORK;MOBILE\;.*?\:([^\n\r]*)/)
    {$MobilePhone = $1;# same for home mobile
    }
    elsif (m/^TEL;WORK\;.*?\:([^\n\r]*)/)
    {$BusinessPhone = $1;
    }
    elsif (m/^EMAIL;INTERNET;HOME\;.*?\:([^\n\r]*)/)
    {$EmailAddress = $1;
    }
    elsif (m/^EMAIL;INTERNET;WORK\;.*?\:([^\n\r]*)/)
    {$EmailAddress = $1;
    }
    elsif (m/^URL\;.*?\:([^\n\r]*)/)
    {$WebPage = $1;
    }
    elsif (m/^ORG\;.*?\:([^\n\r]*)/)
    {$Company = $1;
    }
    elsif (m/^TITLE\;.*?\:([^\n\r]*)/)
    {$JobTitle = $1;
    }
    elsif (m/^(REV|VERSION)([^\n\r]*)/)
    {# do nothing
    }
    elsif (m/^END\:VCARD/)
    {
     #if ($LastName ne '' && $address ne '')
     #{ 
     printf OUTFILE "\"$Title\",\"$FirstName\",\"$MiddleName\",\"$LastName\",\"$Suffix\",\"$Company\",\"$JobTitle\",\"$BusinessStreet\",\"$BusinessStreet2\",\"$BusinessStreet3\",\"$BusinessCity\",\"$BusinessState\",\"$BusinessPostalCode\",\"$BusinessCountry\",\"$HomeStreet\",\"$HomeStreet2\",\"$HomeStreet3\",\"$HomeCity\",\"$HomeState\",\"$HomePostalCode\",\"$HomeCountry\",\"$BusinessFax\",\"$BusinessPhone\",\"$HomeFax\",\"$HomePhone\",\"$MobilePhone\",\"$EmailAddress\",\"$HomeAddressPOBox\",\"$Notes\",\"$WebPage\"\n";
     #"$name,$address\n";
     #}
    }
    else
    {s/[\r\n]//;
     print STDERR "Unknown line: $_\n";
    }
    $thisline=$nextline;
}

close (OUTFILE); close (INFILE);
# end

sub get_line {
 local ($_);
 #print STDERR ":getline:\n";
 #if (eof) {print STDERR "eof=true";} else {print STDERR "eof=false";}
 $_=<INFILE>;
 if (defined($_)) {chomp;}#strip line endings
 #if (eof) {print STDERR "/eof=true\n";} else {print STDERR "/eof=false\n";}
 if (defined $_)
 {#print STDERR ":$_\n"; # ...
  s/[\n\r]//; # strip any line feed/CR
 }
 #else {print STDERR ":empty line\n"}
 $_; # return this value
}

