Newer
Older
mailpiler / contrib / import / rewrite.pl
@Janos SUTO Janos SUTO on 9 Jul 2017 6 KB contrib: added import utilities
#!/usr/bin/perl

# Written by Rory McInerney, rorymcinerney@gmail.com
# feel free to use this for whatever, I make it public domain

use strict;
use warnings;
use Net::LDAP;
use File::Find;


# LDAP user name
my $uid = "cn=piler,cn=users,dc=yourdomain";
# LDAP user password
my $bindPass = "youpass";
# LDAP password 
my $ldapServer = "ldap://yourdc.yourdomain";
# dummy not found email address to use
my $notfound = "noexist\@domain.com";
# where the eml files are found (will recurse)
my $dir = "/var/pst-import/test";
# ldap base
my $base = "ou=Users,dc=domain";




# quick function to trim whitespace
sub  trim { my $s = shift; $s =~ s/^\s+|\s+$//g; return $s };

# this rewrites To: and Cc: headers
sub rewrite_to_headers {
	#initiate variables
	my @files;
	my $start_dir = "$_[0]";  # top level dir to search
	
	# find all the files and return the variable
	find( sub { push @files, $File::Find::name unless -d; }, $start_dir );
	
	# This iterates through all the email files found
	foreach my $mailpath (@files) {
	
		# REWRITE To: Headers
		# this matches to see if it's a sent item, based on the file structure of the PST
		if($mailpath =~ /Sent Items/i) { # if it's a sent item
			# this extracts the line in the header to manipulate 
			my $line =  `grep \"To:\" \"$mailpath\" -m 1`;
			# lose the newline
			chomp($line);
			my $origline = $line;
			# lose the To: bit off the start of the header
			$line =~ s/To: //g;
			# split the mush of addresses into an array of parts on the semicolons
			my @adds = split(/\;/, $line);
			my $newline = "To:";
			# cycle through all the address fragments
			foreach my $add (@adds) {
				$add = trim($add);
				# if it matches the format of an email address
				if($add =~ /\'.+\@.+\'/) {
					$newline = $newline . " ".$add.";";
				} else {
					my $email = find_ldap_mail($add);
					$email =~ s/\@/\\\@/gi;
					$newline = $newline . " ".$add." <$email>;";
				}
			}
			chop($newline);
			my $command = "perl -i -p -e \"s/$origline/$newline/g;\" \"$mailpath\"\n";
			`$command`;
			
			
			####  REWRITES CC: HEADERS
			my $result = `head -n 5 \"$mailpath\" | grep "Cc:" -i -m 1`;
			if($result) {
				my $line =  `grep \"Cc:\" \"$mailpath\" -m 1`;
				# lose the newline
				chomp($line);
				my $origline = $line;
				# lose the To: bit off the start of the header
				$line =~ s/Cc: //g;
				# split the mush of addresses into an array of parts on the semicolons
				my @adds = split(/\;/, $line);
				my $newline = "Cc:";
				# cycle through all the address fragments
				foreach my $add (@adds) {
					$add = trim($add);
					# if it matches the format of an email address
					if($add =~ /\'.+\@.+\'/) {
						$newline = $newline . " ".$add.";";
					} else {
						my $email = find_ldap_mail($add);
						$email =~ s/\@/\\\@/gi;
						$newline = $newline . " ".$add." <$email>;";
					}
				}
				chop($newline);
				my $command = "perl -i -p -e \"s/$origline/$newline/g;\" \"$mailpath\"\n";	
				`$command`;
			}
		}	
	}
}

sub rewrite_send_headers {
	# argument is the folder containing the unzipped (from pst) email files
	# get a list of the files in the directory (see subs)
	my @mails = getfiles(@_);
	# get the displayname from the emails (see subs)
	my $dN = get_displayname(@mails);
	# query active directory to get email to write from the dN
	my $result = find_ldap_mail($dN);
	# escape the special @ symbol to make system call work properly
	$result =~ s/\@/\\\@/;


	# for each email in the list of emails...
	foreach my $mailpath (@mails) { 
		if($mailpath =~ /Sent Items/i) {  # if it's a sent item
			system("perl -i -p -e \'s/MAILER-DAEMON/$result/g;\' \"$mailpath\"\n"); # rewrite the mailer daemon with the correct stuff
		}
	}
}

# this sub gets the DN from the first email in the sent items folder in the pst we are working with
sub get_displayname {
	my @fragments; # initialise this
	foreach my $mailpath (@_) { # the argument is all the files in the pst broken open
		if($mailpath =~ /Sent Items/i) { # if it's a sent item
			my $line =  `grep \"From:\" \"$mailpath\" -m 1`; # find the display name of the first email sent
			@fragments = split(/\"/, $line); # isolate it
			last;	# once we've found it, we've found it
		}
	}
	return $fragments[1]; #return it
}

# sub for getting the filenames, takes directory as argument
sub getfiles {
	#initiate variables
	my @files;
	my $start_dir = "$_[0]";  # top level dir to search
	# find all the files and return the variable
	find( sub { push @files, $File::Find::name unless -d; }, $start_dir );
	return @files;
}

#sub for finding the ldap mail attribute from a displayName
sub find_ldap_mail {

        # connect to ldap server
        my $ldap = Net::LDAP -> new ($ldapServer) || die "Could not connect to server\n";

        # bind to ldap server
        my $result = $ldap -> bind($uid, password => $bindPass);

        #we're looking for the mail attribute so tell it that
        my $attrs = [ 'cn','mail' ];

        # ask the ldap server, replace the base with your base
        $result =       $ldap->search(  base => $base,
                                        filter => "(&(objectClass=Person)(displayName=$_[0]))",
                                        attrs => $attrs
        );

        # not really sure what this does but it makes it work
        $result->code && die $result->error;

        # initialise this as you're not allowed inside the foreach loop
        my @foundemails;

        # look through the entries and put each result into an array
        foreach my $entry ($result->all_entries) {
                push @foundemails,$entry->get_value('mail');
        }
		if(@foundemails) {
			#return what we've found as a scalar value
			return $foundemails[0];
		} else { 
			return $notfound;
		}
        #unbind from the AD server
        $result = $ldap->unbind;
}

rewrite_send_headers($dir);									# rewrite the from: header from mailer-daemon
rewrite_to_headers($dir);									# rewrite to/cc headers