#!/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() { 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"; } } }