#!/usr/bin/perl -w
#
# Migrates a single user's inbox and mail/ folders to Cyrus
#
# This script makes the following important assumptions about your
# Cyrus settings:
#
#   hashimapspool: true
#   unixhierarchysep: no
#
# If you want to use "unixhierarchysep: yes" in Cyrus, I recommend
# doing the migration with it turned off, then enabling it after the
# migration.
#

if ($#ARGV < 0) {
	print "Usage: $0 username\n";
	print "  Migrates username's inbox and mail/ folders to Cyrus\n";
	exit(-1);
}

my $username = $ARGV[0];
my $prefix = substr($username, 0, 1);
my $adminuser = "cyrus";
my $adminpw = "XXXXXXX";
my $server = "localhost";
my $quota = 100 * 1024; # 100MB (quota is in kilobytes)
my $cyrusmailstore = "/var/spool/cyrus/mail"; # Where the cyrus mail lives
my $uwmailstore = "/var/mail"; # Where the uw-imap mail spool lives

use Cyrus::IMAP::Admin;


# Connect to Cyrus
$imap = Cyrus::IMAP::Admin->new($server) || die "Unable to connect to $server";

if (! $imap) {
    die "Error creating IMAP connection object\n";
}

$imap->authenticate(-user => $adminuser, 
		-mechanism => "LOGIN",
		-password => $adminpw,
		);

if ($imap->error) {
    die $imap->error;
}

print "Successfully connected to IMAP server.\n";


# Verify that user exists on system
if (! defined(getpwnam($username))) {
	print "ERROR: username '$username' not found\n";
	exit(-1);
}


# Get their home directory for later
my $homedir = (getpwnam($username))[7];


# Migrate inbox

# always create the top-level inbox, otherwise we can't create the subfolders
&createmailbox("user.$username");

# Set quota
$imap->setquota("user.$username", "STORAGE", $quota);
if ($imap->error) {
	print "ERROR: " . $imap->error . "\n";
}
else {
	print "Set quota to $quota on user.$username\n";
}

# Use formail to migrate messages in inbox
# pass the output of formail through an external perl script to
# filter out FOLDER INTERNAL DATA messages
if (-f "$uwmailstore/$username") {
	system("/bin/cat $uwmailstore/$username | /private/tools/filter.pl | /usr/bin/formail -n 20 -s /private/tools/cpmsg.pl '$cyrusmailstore/$prefix/user/$username'");
}


# Migrate folders

if (-d "$homedir/mail") {
	if (! open(IN, "/usr/bin/find $homedir/mail -type f |")) {
		print "ERROR: could not run find command\n";
		exit(-1);
	}

	while(<IN>) {
		chomp;
#		print;
		if (-T $_) {
#			print " - text\n";
		}
		else {
			print "$_ - binary\n";
			next;
		}
		if (/$homedir\/mail\/(.*)/) {
			$folder = $1;

			# Clean up folder name
			# Substitute _ for non-word characters
			$folder =~ s/[^\w\/-]/_/g;

			# Substitute . for /
			$folder =~ s/\//\./g;

			# Prepend user.username
			$folder = "user.$username." . $folder;

			# Does this folder already exist?
			while (defined($mapping{$folder})) {
				$folder .= "_";
			}

			# Escape any ' in the path
			s/'/'\"'\"'/g;

			$mapping{$folder} = $_;

#			print "Folder: $folder\n";
		}
		else {
			print "ERROR: Could not match folder name '$_' in regular expression\n";
		}
	}

	close(IN);


	foreach $key (sort keys %mapping) {
#		print "$key: $mapping{$key}\n";
		&createmailbox($key);

		$mbpath = $key;
		$mbpath =~ s/\./\//g;

		# migrate messages
		system("/bin/cat '$mapping{$key}' | /private/tools/filter.pl | /usr/bin/formail -n 20 -s /private/tools/cpmsg.pl '$cyrusmailstore/$prefix/$mbpath'");
	}
}


# Fix ownership of message files
system("chown -R $adminuser:mail $cyrusmailstore/$prefix/user/$username");

# Reconstruct mailbox now
system("su $adminuser -c '/usr/local/cyrus/bin/reconstruct -r user.$username'");

# And fix quota
# If doing a mass migration, run this command AFTER all the mailboxes
# have been migrated
#system("su $adminuser -c '/usr/local/cyrus/bin/quota -f'");


##########################
# Create a mailbox
##########################
sub createmailbox {
	my ($mailbox) = @_;

	if ($imap->list($mailbox)) {
		print "ERROR: mailbox $mailbox already exists\n";
	}
	else {
		$imap->create($mailbox);
		if ($imap->error) {
			print "ERROR: " . $imap->error . "\n";
		}
		else {
			print "Created mailbox $mailbox\n";
		}
	}
}


