#!/usr/bin/perl

# $Header: /mhub4/sources/imap-tools/imapsync.pl,v 1.27 2012/03/01 05:32:58 rick Exp $

#######################################################################
#   Program name    imapsync.pl                                       #
#   Written by      Rick Sanders                                      #
#                                                                     #
#   Description                                                       #
#                                                                     #
#   imapsync is a utility for synchronizing a user's account on two   #
#   IMAP servers.  When supplied with host/user/password information  #
#   for two IMAP hosts imapsync does the following:                   #
#	1.  Adds any messages on the 1st host which aren't on the 2nd #
#       2.  Deletes any messages from the 2nd which aren't on the 1st #
#       3.  Sets the message flags on the 2nd to match the 1st's flags#  
#                                                                     #
#   imapsync is called like this:                                     #
#      ./imapsync -S host1/user1/password1 -D host2/user2/password2   # 
#                                                                     #
#   Optional arguments:                                               #
#	-d debug                                                      #
#       -L logfile                                                    #
#       -m mailbox list (sync only certain mailboxes,see usage notes) #
#######################################################################

use Socket;
use IO::Socket;
use IO::Socket::INET;
use FileHandle;
use Fcntl;
use Getopt::Std;
use IMAP::Utils;

#################################################################
#            Main program.                                      #
#################################################################

   init();

   #  Get list of all messages on the source host by Message-Id
   #
   connectToHost($sourceHost, \$src)    or exit;
   login($sourceUser,$sourcePwd, $src)  or exit;
   namespace( $src, \$srcPrefix, \$srcDelim, $opt_x );

   connectToHost( $destHost, \$dst ) or exit;
   login( $destUser,$destPwd, $dst ) or exit;
   namespace( $dst, \$dstPrefix, \$dstDelim, $opt_y );

   #  Create mailboxes on the dst if they don't already exist
   my @source_mbxs = getMailboxList( $src );

   #  Exclude certain ones if that's what the user wants
   exclude_mbxs( \@source_mbxs ) if $excludeMbxs;

   map_mbx_names( \%mbx_map, $srcDelim, $dstDelim );

   createDstMbxs( \@source_mbxs, $dst );

   #  Check for new messages and existing ones with new flags
   $adds=$updates=$deletes=0;
   ($added,$updated) = check_for_adds( \@source_mbxs, \%REVERSE, $src, $dst );

   #  Remove messages from the dst that no longer exist on the src
   $deleted = check_for_deletes( \%REVERSE, $dst, $src );

   logout( $src );
   logout( $dst );

   Log("\nSummary of results");
   Log("   Added   $added");
   Log("   Updated $updated");
   Log("   Deleted $deleted");

   exit;


sub init {

   $os = $ENV{'OS'};

   processArgs();

   $timeout = 60 unless $timeout;

   IMAP::Utils::init();

   #  Open the logFile
   #
   if ( $logfile ) {
      openLog($logfile);
   }
   Log("$0 starting\n");

   $debug = 1;
}

#  getMailboxList
#
#  get a list of the user's mailboxes from the source host
#
sub getMailboxList {

my $conn  = shift;
my $delim = shift;
my @mbxs;
my @mailboxes;

  #  Get a list of the user's mailboxes
  #
  if ( $mbxList ) {
      #  The user has supplied a list of mailboxes so only processes
      #  the ones in that list
      @mbxs = split(/,/, $mbxList);
      foreach $mbx ( @mbxs ) {
         # trim( *mbx );
         push( @mailboxes, $mbx );
      }
      return @mailboxes;
   }

   @mbxs = listMailboxes('*', $conn);

   return @mbxs;
}

#  getMsgList
#
#  Get a list of the user's messages in the indicated mailbox on
#  the source host
#

sub getMsgList {

my $mailbox = shift;
my $msgs    = shift;
my $conn    = shift;
my $seen;
my $empty;
my $msgnum;
my $from;
my $flags;
my $msgid;

   #  Get a list of the msgs in this mailbox

   @$msgs = ();
   trim( *mailbox );
   sendCommand ($conn, "1 EXAMINE \"$mailbox\"");
   undef @response;
   $empty=0;
   while ( 1 ) {
	$response = readResponse ( $conn );
	if ( $response =~ / 0 EXISTS/i ) { $empty=1; }
	if ( $response =~ /^1 OK/i ) {
		# print STDERR "response $response\n";
		last;
	}
	elsif ( $response !~ /^\*/ ) {
		Log ("unexpected response: $response");
		# print STDERR "Error: $response\n";
		return 0;
	}
   }

   return if $empty;

   sendCommand ( $conn, "1 FETCH 1:* (uid flags internaldate body[header.fields (From Date Message-ID Subject)])");
   undef @response;
   while ( 1 ) {
	$response = readResponse ( $conn );
	if ( $response =~ /^1 OK/i ) {
		# print STDERR "response $response\n";
		last;
	} 
        last if $response =~ /^1 NO|^1 BAD/;
   }

   @$msgs  = ();
   $flags = '';
   for $i (0 .. $#response) {
	last if $response[$i] =~ /^1 OK FETCH complete/i;

        if ($response[$i] =~ /FLAGS/) {
           #  Get the list of flags
           $response[$i] =~ /FLAGS \(([^\)]*)/;
           $flags = $1;
           $flags =~ s/\\Recent|\\Forwarded//ig;
        }

        # if ( $response[$i] =~ /^Message-ID:\s*\<(.+)\>/i ) {
        #  Consider the < and > to be part of the message-id.
        if ( $response[$i] =~ /^Message-ID:\s*(.+)/i ) {
           $msgid = $1;
        }

        if ( $response[$i] =~ /INTERNALDATE/) {
           $response[$i] =~ /INTERNALDATE (.+) BODY/i;
           $date = $1;
           
           $date =~ /"(.+)"/;
           $date = $1;
           $date =~ s/"//g;
        }

        # if ( $response[$i] =~ /\* (.+) [^FETCH]/ ) {
        if ( $response[$i] =~ /\* (.+) FETCH/ ) {
           ($msgnum) = split(/\s+/, $1);
        }

        if ( $msgnum and $date and $msgid ) {
	   push (@$msgs,"$msgid||||||$msgnum||||||$flags||||||$date");
           $msgnum=$msgid=$date=$flags='';
        }
   }

}

#  getDatedMsgList
#
#  Get a list of the user's messages in a mailbox on
#  the host which were sent after the specified date
#
sub getDatedMsgList {

my $mailbox = shift;
my $date    = shift;
my $msgs    = shift;
my $conn    = shift;
my ($seen, $empty, @list,$msgid);
my $loops;

    #  Get a list of messages sent after the specified date

    my @list;
    my @msgs;

    if (  $date !~ /-/ ) {
       # Delta in days, convert to DD-MMM-YYYY
       $date = get_date( $sync_since ); 
    }
    sendCommand ($conn, "1 SELECT \"$mailbox\"");
    while ( 1 ) {
        $response = readResponse ($conn);
        if ( $response =~ / EXISTS/i) {
            $response =~ /\* ([^EXISTS]*)/;
            Log("     There are $1 messages in $mailbox");
        } elsif ( $response =~ /^1 OK/i ) {
            last;
        } elsif ( $response !~ /^\*/ ) {
            Log ("unexpected SELECT response: $response");
            return 0;
        }
        if ( $loops++ > 1000 ) {
           Log("No response to SELECT command, skipping this mailbox"); 
           last;
        }
    }

    #
    #  Get list of messages sent before the reference date
    #
    Log("Get messages sent after $date") if $debug;
    $nums = "";
    sendCommand ($conn, "1 SEARCH SENTSINCE \"$date\"");
    while ( 1 ) {
	$response = readResponse ($conn);
	if ( $response =~ /^1 OK/i ) {
	    last;
	}
	elsif ( $response =~ /^\*\s+SEARCH/i ) {
	    ($nums) = ($response =~ /^\*\s+SEARCH\s+(.*)/i);
	}
	elsif ( $response !~ /^\*/ ) {
	    Log ("unexpected SEARCH response: $response");
	    return;
	}
    }
    if ( $nums eq "" ) {
	Log ("     $mailbox has no messages sent after $date") if $debug;
	return;
    }
    # Log("     Msgnums for messages in $mailbox sent after $date $nums") if $debug;
    $nums =~ s/\s+/ /g;
    @msgList = ();
    @msgList = split(/ /, $nums);

    if ($#msgList == -1) {
	#  No msgs in this mailbox
	return 1;
    }

@$msgs  = ();
for $num (@msgList) {

     sendCommand ( $conn, "1 FETCH $num (uid flags internaldate body[header.fields (Message-Id Date)])");
     
     undef @response;
     while ( 1 ) {
	$response = readResponse   ( $conn );
	if   ( $response =~ /^1 OK/i ) {
		last;
	}   
        last if $response =~ /^1 NO|^1 BAD|^\* BYE/;
     }

     $flags = '';
     foreach $_ ( @response ) {
	last   if /^1 OK FETCH complete/i;

          if ( /FLAGS/ ) {
             #  Get the list of flags
             /FLAGS \(([^\)]*)/;
             $flags = $1;
             $flags =~ s/\\Recent|\\Forwarded//ig;
          }
   
          if ( /Message-Id:\s*(.+)/i ) {
             $msgid = $1;
          }

          if ( /INTERNALDATE/) {
             /INTERNALDATE (.+) BODY/i;
             $date = $1;
             $date =~ /"(.+)"/;
             $date = $1;
             $date =~ s/"//g;
          }

          if ( /\* (.+) FETCH/ ) {
             ($msgnum) = split(/\s+/, $1);
          }

          if ( $msgid and $msgnum and $date and $msgid ) {
             push (@$msgs,"$msgid||||||$msgnum||||||$flags||||||$date");
             $msgnum=$msgid=$date=$flags='';
          }
      }
   }

#  @msgs = ();
#  @$msgs = @list;

   return 1;
}

sub fetchMsgFlags {

my $msgnum = shift;
my $conn   = shift;
my $flags;

   #  Read the IMAP flags for a message

   sendCommand( $conn, "1 FETCH $msgnum (flags)");
   while (1) {
        $response = readResponse ($conn);
        if ( $response =~ /^1 OK|^1 BAD|^1 NO/i ) {
           last;
        }
        if ( $response =~ /\* $msgnum FETCH \(FLAGS \((.+)\)\)/i ) {
           $flags = $1;
           Log("   $msgnum - flags $flags") if $verbose;
        }
   }

   return $flags;
}

sub usage {

   print STDOUT "usage:\n";
   print STDOUT " iu-sync -S sourceHost/sourceUser/sourcePassword\n";
   print STDOUT "          -D destHost/destUser/destPassword\n";
   print STDOUT "          -d debug\n";
   print STDOUT "          -L logfile\n";
   print STDOUT "          -s <since> Sync messages since this date (DD-MMM-YYYY) or number of days ago\n";
   print STDOUT "          -m mailbox list (eg \"Inbox, Drafts, Notes\". Default is all mailboxes)\n";
   print STDOUT "          -e exclude mailbox list\n";
   print STDOUT "          -n do not delete messages from destination\n";
   exit;

}

sub processArgs {

   if ( !getopts( "dvS:D:L:m:e:hIx:y:FM:s:nNQ" ) ) {
      usage();
   }

   ($sourceHost,$sourceUser,$sourcePwd) = split(/\//, $opt_S);
   ($destHost,  $destUser,  $destPwd)   = split(/\//, $opt_D);
   $mbxList     = $opt_m;
   $excludeMbxs = $opt_e;
   $logfile     = $opt_L;
   $mbx_map_fn  = $opt_M;
   $sync_since  = $opt_s;
   $no_deletes  = 1 if $opt_n;
   $debug    = 1 if $opt_d;
   $verbose  = 1 if $opt_v;
   $showIMAP = 1 if $opt_I;
   $include_nosel_mbxs = 1 if $opt_N;

   usage() if $opt_h;

}

sub check_for_adds {

my $source_mbxs = shift;
my $REVERSE     = shift;
my $src         = shift;
my $dst         = shift;
my @sourceMsgs;

   #  Compare the contents of the user's mailboxes on the source
   #  with those on the destination.  Add any new messages to the
   #  destination and update if necessary the flags on the existing
   #  ones.

   Log("Checking for adds & updates");
   my $added=$updated=0;
   foreach my $src_mbx ( @$source_mbxs ) {
        Log("Mailbox $src_mbx");
        if ( $include_nosel_mbxs ) {
           #  If a mailbox was 'Noselect' on the src but the user wants
           #  it created as a regular folder on the dst then do so.  They
           #  don't hold any messages so after creating them we don't need
           #  to do anything else.
           next if $nosel_mbxs{"$src_mbx"};
        }

        expungeMbx( $src, $src_mbx );
        $dst_mbx = mailboxName( $src_mbx,$srcPrefix,$srcDelim,$dstPrefix,$dstDelim );

        #  Record the association between source and dest mailboxes
        $$REVERSE{"$dst_mbx"} = $src_mbx;

        selectMbx( $src_mbx, $src, 'EXAMINE' );

	@sourceMsgs=();

        if ( $sync_since ) {
           getDatedMsgList( $src_mbx, $sync_since, \@sourceMsgs, $src );
        } else {
           getMsgList( $src_mbx, \@sourceMsgs, $src );
        }

        if ( $verbose ) {
          Log("src_mbx $src_mbx has the following messages");
          foreach $_ ( @sourceMsgs ) {
             Log("  $_");
          }
        }

        selectMbx( $dst_mbx, $dst, 'SELECT' );
        my $msgcount = $#sourceMsgs + 1;
        Log("$src_mbx has $msgcount messages");
        foreach $_ ( @sourceMsgs ) {
           Log("   $_") if $verbose;
           ($msgid,$msgnum,$src_flags,$date) = split(/\|\|\|\|\|\|/, $_,5);
           next if $src_flags =~ /\\Deleted/;  # Don't sync deleted messages

           Log("Searching on dst in $dst_mbx for $msgid ($msgnum)") if $verbose;

           my $dst_msgnum = findMsg( $msgid, $dst, $dst_mbx);
           if ( !$dst_msgnum ) {
              #  The msg doesn't exist in the mailbox on the dst, need to add it.
              $message = fetchMsg( $msgnum, $src );
              next unless $message;
              Log("   Need to insert $msgnum") if $verbose;
              insertMsg( $dst, $dst_mbx, *message, $src_flags, $date, $msgid );
              $added++;
           } else {
             #  The message exists, see if the flags have changed.
             Log("   msgnum=$msgnum exists, fetch its flags") if $verbose;
             $dst_flags = fetchMsgFlags( $dst_msgnum, $dst );

             sort_flags( \$src_flags );
             sort_flags( \$dst_flags );

             unless ( $dst_flags eq $src_flags ) {
                Log("   Updating the flags") if $verbose;
                setFlags( $dst_msgnum, $src_flags, $dst_flags, $dst );
                $updated++;
             }
           }
      }
   }
   return ($added,$updated);
}

sub check_for_deletes {

my $REVERSE = shift;
my $dst = shift;
my $src = shift;
my $deleted=0;
my $total_deletes=0;

   #  Delete any messages on the dst that are no longer on the src.

   return 0 if $no_deletes;

   Log("Checking for messages to delete on the dst");

   if ( %mbx_map ) {
      #  Reverse the mbx mapping
      my $new_map;
      while( my($src,$dst) = each( %mbx_map ) ) {
         $new_map{"$dst"} = $src;
      }
      %mbx_map = %new_map;
   }
   while( my($src,$dst) = each( %mbx_map ) ) {
       Log("Mapping $src  == > $dst");
   }

   my @dst_mbxs = getMailboxList( $dst );
   exclude_mbxs( \@dst_mbxs ) if $excludeMbxs;

   foreach my $dst_mbx ( @dst_mbxs ) {
        Log("Checking $dst_mbx for deletes") if $verbose;
        $deleted=0;
        ## $src_mbx = mailboxName( $dst_mbx,$dstPrefix,$dstDelim,$srcPrefix,$srcDelim );
        $src_mbx = $$REVERSE{"$dst_mbx"};

        if ( $sync_since ) {
           getDatedMsgList( $dst_mbx, $sync_since, \@dstMsgs, $dst );
        } else {
           getMsgList( $dst_mbx, \@dstMsgs, $dst );
        }

        selectMbx( $dst_mbx, $dst, 'SELECT' );
        selectMbx( $src_mbx, $src, 'EXAMINE' );
        foreach $_ ( @dstMsgs ) {
           ($msgid,$dst_msgnum,$dst_flags,$date) = split(/\|\|\|\|\|\|/, $_,5);
           if ( $verbose ) {
              Log("   msgid      $msgid");
              Log("   dst msgnum $dst_msgnum");
              Log("   dst_mbx    $dst_mbx");
           }
           my $src_msgnum = findMsg( $msgid, $src, $src_mbx);
           if ( !$src_msgnum ) {
              Log("Deleting $msgid from $dst_mbx on the dst");
              if ( deleteMsg( $dst, $dst_msgnum ) ) {
                 #  Need to expunge messages from this mailbox when we're done
                 $total_deletes++;
                 $deleted=1;
              }
           }
        }
        expungeMbx( $dst, $dst_mbx ) if $deleted;
   }
   return $total_deletes;
}

sub mailboxName {

my $srcmbx    = shift;
my $srcPrefix = shift;
my $srcDelim  = shift;
my $dstPrefix = shift;
my $dstDelim  = shift;
my $direction = shift;
my $dstmbx;

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

   #  Change the mailbox name if the user has supplied mapping rules.
   if ( $mbx_map{"$srcmbx"} ) {
      $srcmbx = $mbx_map{"$srcmbx"}
   }

   $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 = '\.' if $dstDelim eq '.';
       $dstmbx =~ s#^$dstDelim##;
   } 

   return $dstmbx;
}

sub flags {

my $flags = shift;
my @newflags;
my $newflags;

   #  Make sure the flags list contains only standard
   #  IMAP flags.

   return unless $flags;

   $flags =~ s/\\Recent|\\Forwarded//ig;

   foreach $_ ( split(/\s+/, $flags) ) {
      next unless substr($_,0,1) eq '\\';
      push( @newflags, $_ );
   }

   $newflags = join( ' ', @newflags );

   $newflags =~ s/\\Deleted//ig if $opt_r;
   $newflags =~ s/^\s+|\s+$//g;

   return $newflags;
}

sub createDstMbxs {

my $mbxs = shift;
my $dst  = shift;

   #  Create a corresponding mailbox on the dst for each one
   #  on the src.

   foreach my $mbx ( @$mbxs ) {
      $dstmbx = mailboxName( $mbx,$srcPrefix,$srcDelim,$dstPrefix,$dstDelim );
      createMbx( $dstmbx, $dst, true ) unless mbxExists( $dstmbx, $dst );
   }
}

sub sort_flags {

my $flags = shift;
my @newflags;
my $newflags;

   #  Make sure the flags list contains only standard
   #  IMAP flags.  Sort the list to make comparision
   #  easier.

   return unless $$flags;

   $$flags =~ s/\\Recent|\\Forwarded//ig;
   foreach $_ ( split(/\s+/, $$flags) ) {
      next unless substr($_,0,1) eq '\\';
      push( @newflags, $_ );
   }

   @newflags = sort @newflags;
   $newflags = join( ' ', @newflags );
   $newflags =~ s/^\s+|\s+$//g;

   $$flags = $newflags;
}

sub setFlags {

my $msgnum    = shift;
my $new_flags = shift;
my $old_flags = shift;
my $conn      = shift;
my $rc;

   #  Set the message flags as indicated.

   if ( $verbose ) {
      Log("old flags   $old_flags");
      Log("new flags   $new_flags");
   }

   # Clear the old flags

   sendCommand ( $conn, "1 STORE $msgnum -FLAGS ($old_flags)");
   while (1) {
        $response = readResponse ($conn);
        if ( $response =~ /^1 OK/i ) {
           $rc = 1;
           last;
        }

        if ( $response =~ /^1 BAD|^1 NO/i ) {
           Log("Error setting flags for msg $msgnum: $response");
           $rc = 0;
           last;
        }
   }

   # Set the new flags

   sendCommand ( $conn, "1 STORE $msgnum +FLAGS ($new_flags)");
   while (1) {
        $response = readResponse ($conn);
        if ( $response =~ /^1 OK/i ) {
           $rc = 1;
           last;
        }

        if ( $response =~ /^1 BAD|^1 NO/i ) {
           Log("Error setting flags for msg $msgnum: $response");
           $rc = 0;
           last;
        }
   }
}

sub selectMbx {

my $mbx  = shift;
my $conn = shift;
my $type = shift;
my $status;
my $loops;

   #  Select the mailbox. Type is either SELECT (R/W) or EXAMINE (R).

   sendCommand( $conn, "1 $type \"$mbx\"");
   while ( 1 ) {
      $response = readResponse( $conn );
      if ( $response =~ /^1 OK/i ) {
         $status = 1;
         last;
      } elsif ( $response =~ /does not exist/i ) {
         $status = 0;
         last;
      } elsif ( $response =~ /^1 NO|^1 BAD/i ) {
         Log("Unexpected response to SELECT/EXAMINE $mbx command: $response");
         last;
      }
      
      if ( $loops++ > 1000 ) {
         Log("No response to $type command, skipping this mailbox"); 
         last;
      }
   }

   return $status;

}

sub map_mbx_names {

my $mbx_map = shift;
my $srcDelim = shift;
my $dstDelim = shift;

   #  The -M <file> argument causes imapcopy to read the
   #  contents of a file with mappings between source and
   #  destination mailbox names. This permits the user to
   #  to change the name of a mailbox when copying messages.
   #
   #  The lines in the file should be formatted as:
   #       <source mailbox name>: <destination mailbox name>
   #  For example:
   #       Drafts/2008/Save:  Draft_Messages/2008/Save
   #       Action Items: Inbox
   #
   #  Note that if the names contain non-ASCII characters such
   #  as accents or diacritical marks then the Perl module
   #  Unicode::IMAPUtf7 module must be installed.

   return unless $mbx_map_fn;

   unless ( open(MAP, "<$mbx_map_fn") ) {
      Log("Error opening mbx map file $mbx_map_fn: $!");
      exit;
   }
   $use_utf7 = 0;
   while( <MAP> ) {
      chomp;
      s/[\r\n]$//;   # In case we're on Windows
      s/^\s+//;
      next if /^#/;
      next unless $_;
      ($srcmbx,$dstmbx) = split(/\s*:\s*/, $_);

      #  Unless the mailbox name is entirely ASCII we'll have to use
      #  the Modified UTF-7 character set.
      $use_utf7 = 1 unless isAscii( $srcmbx );
      $use_utf7 = 1 unless isAscii( $dstmbx );

      $srcmbx =~ s/\//$srcDelim/g;
      $dstmbx =~ s/\//$dstDelim/g;

      $$mbx_map{"$srcmbx"} = $dstmbx;

   }
   close MAP;

   if ( $use_utf7 ) {
      eval 'use Unicode::IMAPUtf7';
      if ( $@ ) {
         Log("At least one mailbox map contains non-ASCII characters.  This means you");
         Log("have to install the Perl Unicode::IMAPUtf7 module in order to map mailbox ");
         Log("names between the source and destination servers.");
         print "At least one mailbox map contains non-ASCII characters.  This means you\n";
         print "have to install the Perl Unicode::IMAPUtf7 module in order to map mailbox\n";
         print "names between the source and destination servers.\n";
         exit;
      }
   }

   my %temp;
   foreach $srcmbx ( keys %$mbx_map ) {
Log("map has $srcmbx");
      $dstmbx = $$mbx_map{"$srcmbx"};
      Log("Mapping src:$srcmbx to dst:$dstmbx");
      if ( $use_utf7 ){
         #  Encode the name in Modified UTF-7 charset
         $srcmbx = Unicode::IMAPUtf7::imap_utf7_encode( $srcmbx );
         $dstmbx = Unicode::IMAPUtf7::imap_utf7_encode( $dstmbx );
      }
      $temp{"$srcmbx"} = $dstmbx;
   }
   %$mbx_map = %temp;
   %temp = ();

}

sub get_date {

my $days = shift;
my $time = time();
my @months = qw( Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec );

   #  Generate a date in DD-MMM-YYYY format.  The 'days' parameter
   #  indicates how many days to go back from the present date.

   my ($sec,$min,$hr,$mday,$mon,$year,$wday,$yday,$isdst) =
        localtime( $time - $days*86400 );

   $mday = '0' . $mday if length( $mday ) == 1;
   my $month = $months[$mon];
   my $date = $mday . '-' . $month . '-' . ($year+1900);

   return $date;
}

sub get_mbx_prefix {

my $delim  = shift;
my $conn   = shift;
my %prefixes;
my @prefixes;

   #  Not implemented yet.
   #  Try to figure out whether the server has a mailbox prefix
   #  and if so what it is.

   $$delim = "\\." if $$delim eq '.';

   my @mbxs = getMailboxList( $conn );
   my $num_mbxs = $#mbxs + 1;
   foreach $mbx ( @mbxs ) {
      next if uc( $mbx ) eq 'INBOX';
      ($prefix,$rest) = split(/$$delim/, $mbx);
      $prefixes{"$prefix"}++;
   }

   my $num_prefixes = keys %prefixes;
   if ( $num_prefixes == 1 ) {
      while(($$prefix,$count) = each(%prefixes)) {
          push( @prefixes, "$$prefix|$count");
      }
      ($$prefix,$count) = split(/\|/, pop @prefixes);
      $num_mbxs--;   # Because we skipped the INBOX
      if ( $num_mbxs != $count ) {
         # Did not find a prefix 
         $$prefix = '';
      }      

   }

   $$delim =~ s/\\//;
   $$prefix .= $$delim if $$prefix;

   Log("Determined prefix to be $$prefix") if $debug;

   return $$prefix;

}

sub get_mbx_delimiter {

my $conn = shift;
my $delimiter;

   #  Not implemented yet.
   #  Determine the mailbox hierarchy delimiter 

   sendCommand ($conn, "1 LIST \"\" INBOX");
   undef @response;
   while ( 1 ) {
        $response = readResponse ($conn);
        if ( $response =~ /INBOX/i ) {
           my @terms = split(/\s+/, $response );
           $delimiter = $terms[3];
           $delimiter =~ s/"//g;
        }
        last if $response =~ /^1 OK|^1 BAD|^1 NO/;
        last if $response !~ /^\*/;
   } 

   Log("Determined delimiter to be $delimiter") if $debug;
   return $delimiter;
}
   
