#!/usr/bin/perl

use strict;
use warnings;
use Archive::Zip;
use Text::Iconv;

my $src = $ARGV[0];
my $dst = $ARGV[1];

die "usage: $0 source.pib dest/dir" if !defined( $src) or !defined($dst);

die("dest dir \"$dst\" exists, refusing to overwrite anything") if -e "$dst";
mkdir "$dst"; mkdir "$dst/inbox"; mkdir "$dst/sent";
mkdir "$dst/inbox/cur"; mkdir "$dst/inbox/new"; mkdir "$dst/inbox/tmp";
mkdir "$dst/sent/cur"; mkdir "$dst/sent/new"; mkdir "$dst/sent/tmp";

my $pib = Archive::Zip->new();
die("Couldn't open PIB file") unless $pib->read( $src ) == Archive::Zip::AZ_OK;

print "PIB file opened, searching for messages...\n";
my @matches = $pib->membersMatching( 'msgs_.*\.csm' );
die("Couldn't find messages inside file") unless @matches;
die("More than one message file found in file") if @matches > 1;

print "Message file found\n";
my $utf16_to_utf8 = Text::Iconv->new("UTF-16", "UTF-8");
my $messages = $pib->contents($matches[0]->{"fileName"});
$messages = $utf16_to_utf8->convert( $messages );

sub parse_csv ($) {
	my @out;
	my @tmp;

	while( $_[0] =~ m{
			\G # Start where you left off, don't auto-skip
			(?:;|^|(\x0d\x0a?|\x0a)) # fields start here
			(?: # first try to match quoted ones!
			  "(
			   (?:[^"\\]|\\.)* # non-" non-\ or escape-sequence
			  )"
			  | # or unquoted
			  ([^";\x0d\x0a]*)
			)
			}mgx ) {
		if( defined $1 ) {
			push @out, [ @tmp ];
			@tmp = ();
		}
		if( defined $2 ) {
			my $tmp = $2;
			$tmp =~ s/\\(.)/$1/g;
			push @tmp, $tmp;
		}
		push @tmp, $3 if defined $3;
	}
	push @out, [ @tmp ] if @tmp;

	return @out;
}

my @message = parse_csv($messages);

shift @message; # first and last line contain no data
pop @message;

my $i=0;
for my $msg (@message) {
	# 0  'Msg Id'
	# 1  'Sender Name'
	# 2  'Sender Address'
	# 3  'Sender AddressType'
	# 4  'Prefix'
	# 5  'Subject'
	# 6  'Body'
	# 7  'BodyType'
	# 8  'Folder'
	# 9  'Account'
	# 10  'Msg Class'
	# 11  'Content Length'
	# 12  'Msg Size'
	# 13  'Msg Flags'
	# 14  'Msg Status'
	# 15  'Modify Time'
	# 16  'Delivery Time'
	# 17  'Recipient Nbr'
	# 18  'Recipients'
	# 19  'Attachment Nbr'
	# 20  'Attachments'

	my $dir;
	if( $msg->[8] eq "\\%MDF1" ) {
		$dir = "inbox";
	} elsif( $msg->[8] eq "\\%MDF3" ) {
		$dir = "sent";
	} else {
		print STDERR "Failed to parse entry:\n";
		print STDERR map { "* $_\n" } @$msg;
		die;
	}

	my @date = split /,/, $msg->[16];
	my %month = ('01'=>'Jan', '02'=>'Feb', '03'=>'Mar', '04'=>'Apr', '05'=>'May', '06'=>'Jun',
			'07'=>'Jul', '08'=>'Aug', '09'=>'Sep', '10'=>'Oct', '11'=>'Nov', '12'=>'Dec');

	my $filename = join('',@date); # . ".$i";
	print "Writing file $filename in $dir\n";
	open my $file, ">", "$dst/$dir/cur/$filename" or die "Couldn't open file $dst/$dir/cur/$filename";

	print $file "From: $msg->[2]\n";
	my @to = split /;/, $msg->[18];
	print $file "To: $to[1] <$to[2]>\n";
	print $file "Date: $date[2] " . $month{$date[1]} . " $date[0] $date[3]:$date[4]:$date[5]\n";
	print $file "Subject: SMS\n";
	print $file "Content-Type: text/plain; charset=UTF8\n";
	print $file "\n";
	print $file "$msg->[5]";

	close $file;

	#link "$dst/$dir/tmp/$filename",
	#	"$dst/$dir/new/$filename";
	#unlink "$dst/$dir/tmp/$filename";

	$i++;
}
