#!/usr/bin/perl

#  $Header: /mhub4/sources/imap-tools/dumptoIMAP.pl,v 1.5 2012/03/29 16:48:10 rick Exp $

#######################################################################
#  dumptoIMAP.pl is used to load the mailboxes and messages exported  #
#  from an IMAP server by the imapdump.pl script.  See usage() notes  #
#  for a list of the arguments used to run it.                        #
#                                                                     #
#  If you ran imapdump.pl -S host/user/pwd -f /tmp/BACKUP             #
#  then you could restore all of the mailboxes & messages with the    #
#  following command:                                                 #
#                                                                     #
#  ./dumptoIMAP.pl -S host/user/pwd -D /tmp/BACKUP                    #
#                                                                     #
#  If you wanted to restore just the INBOX and the Sent mailboxes you #
#  would add -m "INBOX,Sent"                                          #
#######################################################################

use Socket;
use IO::Socket;
use FileHandle;
use File::Find;
use Fcntl;
use Getopt::Std;
use IMAP::Utils;

init();

connectToHost($imapHost, \$conn);

unless ( login($imapUser,$imapPwd, $conn) ) {
    Log("Check your username and password");
    print STDOUT "Login failed: Check your username and password\n";
    exit;
}

namespace( $conn, \$prefix, \$delim, $opt_x );
get_mbx_list( $dir, \@mbxs );

foreach $mbx ( @mbxs ) {
   Log("Copying messages from $dir/$mbx to $mbx folder on the IMAP server");
   get_messages( "$dir/$mbx", \@msgs );
   $n = scalar @msgs;
   Log("$mbx has $n messages");
   foreach $_ ( @msgs ) {
      next unless $_;
      my $msg; my $date;
      Log("Opening $_") if $debug;
      unless ( open(F, "<$_") ) {
         Log("Error opening $_: $!");
         next;
      }
      Log("Opened $_ successfully") if $debug;
      while( <F> ) {
         Log("Reading line $_") if $debug;
         if ( /^Date: (.+)/ )  {
            $date = $1 unless $date;
            $date =~ s/\r|\m//g;
            chomp $date;
         }
         $msg .= $_;
      }
      close F;
   
      $size = length( $msg );
      Log("The message is $size bytes") if $debug;
      Log("$msg") if $debug;
 
      if ( $size == 0 ) {
         Log("The message file is empty") if $debug;
         next;
      }

      if ( $prefix or $delim ne '/' ) {
         #  Need to adjust the mailbox name
         $mbx = $prefix . $mbx unless $mbx =~ /^INBOX/i;
         $mbx =~ s/\//$delim/g;
      }

      $copied++ if insertMsg($conn, $mbx, \$msg, '', $date);

      if ( $copied/100 == int($copied/100)) { Log("$copied messages copied "); }
   }

}

logout( $conn );

Log("Done. $copied messages were copied.");
exit;


sub init {

   if ( !getopts('m:L:i:dD:Ix:R') ) {
      usage();
   }

   $mbx_list = $opt_m;
   $dir      = $opt_D;
   $logfile  = $opt_L;
   $extension = $opt_x;
   $debug     = 1 if $opt_d;
   $showIMAP  = 1 if $opt_I;
   ($imapHost,$imapUser,$imapPwd) = split(/\//, $opt_i);

   IMAP::Utils::init();
   if ( $logfile ) {
      openLog($logfile);
   }
   Log("Starting");
}



sub usage {

   print "Usage: iu-restore\n";
   print "    -D <path to the mailboxes>\n";
   print "    -i <server/username/password>\n";
   print "    [-m <mbx1,mbx2,..,mbxn> copy only the listed mailboxes]\n";
   print "    [-x <extension> Import only files with this extension\n";
   print "    [-L <logfile>]\n";
   print "    [-d debug]\n";
   print "    [-I log IMAP protocol exchanges]\n";

}

sub get_messages {

my $dir  = shift;
my $msgs = shift;

   #  Get a list of the message files 

   opendir D, $dir;
   my @files = readdir( D );
   closedir D;
   foreach $_ ( @files ) {
      next if /^\./;
      if ( $extension ) {
         next unless /$extension$/;
      }
      push( @$msgs, "$dir/$_");
   }
}

sub get_mbx_list {

my $dir = shift;
my $mbxs = shift;
my %MBXS;

   if ( $mbx_list ) {
      #  The user has supplied a list of mailboxes.
      @$mbxs = split(/,/, $mbx_list );
      return;
   }

   @dirs = ();
   push( @dirs, $dir );
   @messages = ();
   find( \&findMsgs, @dirs );   #  Returns @messages
   foreach $fn ( @messages ) {
      $fn =~ s/$dir//;
      $i = rindex($fn,'/');
      my $mbx = substr($fn,1,$i);
      $mbx =~ s/\/$//;
      push( @$mbxs, $mbx ) if !$MBXS{"$mbx"};
      $MBXS{"$mbx"} = 1;
   }
}

sub findMsgs {

   return if not -f;

   my $fn = $File::Find::name;
   push( @messages, $fn );

}

sub mailboxName {

my $srcmbx    = shift;
my $srcPrefix = shift;
my $srcDelim  = shift;
my $dstPrefix = shift;
my $dstDelim  = shift;
my $dstmbx;
my $substChar = '_';

   if ( $public_mbxs ) {
      my ($public_src,$public_dst) = split(/:/, $public_mbxs );
      #  If the mailbox starts with the public mailbox prefix then
      #  map it to the public mailbox destination prefix

      if ( $srcmbx =~ /^$public_src/ ) {
         Log("src: $srcmbx is a public mailbox") if $debug;
         $dstmbx = $srcmbx;
         $dstmbx =~ s/$public_src/$public_dst/;
         Log("dst: $dstmbx") if $debug;
         return $dstmbx;
      }
   }

   #  Change the mailbox name if the user has supplied mapping rules.

   if ( $mbx_map{"$srcmbx"} ) {
      $srcmbx = $mbx_map{"$srcmbx"} 
   }

   #  Adjust the mailbox name if the source and destination server
   #  have different mailbox prefixes or hierarchy delimiters.

   if ( ($srcmbx =~ /[$dstDelim]/) and ($dstDelim ne $srcDelim) ) {
      #  The mailbox name has a character that is used on the destination
      #  as a mailbox hierarchy delimiter.  We have to replace it.
      $srcmbx =~ s^[$dstDelim]^$substChar^g;
   }

   if ( $debug ) {
      Log("src mbx      $srcmbx");
      Log("src prefix   $srcPrefix");
      Log("src delim    $srcDelim");
      Log("dst prefix   $dstPrefix");
      Log("dst delim    $dstDelim");
   }

   $srcmbx =~ s/^$srcPrefix//;
   $srcmbx =~ s/\\$srcDelim/\//g;
 
   if ( ($srcPrefix eq $dstPrefix) and ($srcDelim eq $dstDelim) ) {
      #  No adjustments necessary
      # $dstmbx = $srcmbx;
      if ( lc( $srcmbx ) eq 'inbox' ) {
         $dstmbx = $srcmbx;
      } else {
         $dstmbx = $srcPrefix . $srcmbx;
      }
      if ( $root_mbx ) {
         #  Put folders under a 'root' folder on the dst
         $dstmbx =~ s/^$dstPrefix//;
         $dstDelim =~ s/\./\\./g;
         $dstmbx =~ s/^$dstDelim//;
         $dstmbx = $dstPrefix . $root_mbx . $dstDelim . $dstmbx;
         if ( uc($srcmbx) eq 'INBOX' ) {
            #  Special case for the INBOX
            $dstmbx =~ s/INBOX$//i;
            $dstmbx =~ s/$dstDelim$//;
         }
         $dstmbx =~ s/\\//g;
      }
      return $dstmbx;
   }

   $srcmbx =~ s#^$srcPrefix##;
   $dstmbx = $srcmbx;

   if ( $srcDelim ne $dstDelim ) {
       #  Need to substitute the dst's hierarchy delimiter for the src's one
       $srcDelim = '\\' . $srcDelim if $srcDelim eq '.';
       $dstDelim = "\\" . $dstDelim if $dstDelim eq '.';
       $dstmbx =~ s#$srcDelim#$dstDelim#g;
       $dstmbx =~ s/\\//g;
   }
   if ( $srcPrefix ne $dstPrefix ) {
       #  Replace the source prefix with the dest prefix
       $dstmbx =~ s#^$srcPrefix## if $srcPrefix;
       if ( $dstPrefix ) {
          $dstmbx = "$dstPrefix$dstmbx" unless uc($srcmbx) eq 'INBOX';
       }
       $dstDelim = "\\$dstDelim" if $dstDelim eq '.';
       $dstmbx =~ s#^$dstDelim##;
   } 
      
   if ( $root_mbx ) {
      #  Put folders under a 'root' folder on the dst
      $dstDelim =~ s/\./\\./g;
      $dstmbx =~ s/^$dstPrefix//;
      $dstmbx =~ s/^$dstDelim//;
      $dstmbx = $dstPrefix . $root_mbx . $dstDelim . $dstmbx;
      if ( uc($srcmbx) eq 'INBOX' ) {
         #  Special case for the INBOX
         $dstmbx =~ s/INBOX$//i;
         $dstmbx =~ s/$dstDelim$//;
      }
      $dstmbx =~ s/\\//g;
   }

   return $dstmbx;
}
