#!/usr/bin/perl

# Imap Interface to SpamAssassin Learn (Power Version)     v0.02
# ----------------------------------------------------     -----
#
# Note - unless you want to do all sorts of complex stuff, you probably
#        want the normal version of this script, imap-sa-learn.pl
#        
# Connects to an imap server, and filters the messages from the INBOX
# and SpamTrap (unless otherwise told) through sa-learn. Allows you to
# save the emails into several different places, and other snazy things
#
#  usage:
#    power-imap-sa-learn.pl <-hamfolder HAM> <-spamfolder SPAM>
#
#  Other options:
#    -username nnnn	username for the server
#    -password nnnn	password for the server
#    -server nnnn	server to connect to
#
#    -skips nnn		skips over the first nnn messages in the folder(s)
#    -logmail		save the email into an mbox file using formail
#    -logmaildir nnn	dir to write into, default is ~/mail
#
#    -deletespam	after learning from a spam message, delete it
#    -delete-spam	(as above)
#    -dangerous-delete-ham	after learning from a ham (real email),
#    				delete it. Most people don't want this...
#    -dangerous-delete-all	after learning from any message, delete
#    				it, spam or ham
#
#
# Uses Mail::IMAPClient and SpamAssassin (sa-learn)
#
# Needs a version of SpamAssassin with the Bayesian filtering support,
# i.e. 2.50 or later
#
#      Nick Burch <nick@tirian.magd.ox.ac.uk>
#           25/06/2003

use Mail::IMAPClient;

# Define our default server and credentials here
# These can be overridden on the command line
#
#  ** fix me **    your details go below
my $username = 'john.smith';
my $password = 'bitter';
my $server = 'my.imap.provider.invalid';

# Define where to find messages
my $defspamfolder = 'SpamTrap';
my $defhamfolder = 'INBOX';
my $deletespam = 0;
my $deleteham = 0;
my $default = 1;

my $log = 0;
my $logdir = $ENV{'HOME'}."/mail";

my $skips = 0;

my @spams;
my @hams;

while(my $arg = shift) {
   if($arg eq "-spamfolder") {
     my $spam = shift;
     push @spams,$spam;
     print "Using spam folder $spam\n";
     $default = 0;
   }
   if($arg eq "-hamfolder") {
     my $ham = shift;
     push @hams,$ham;
     print "Using normal (ham) folder $ham\n";
     $default = 0;
   }
   if($arg eq "-username") {
     $username eq shift;
   }
   if($arg eq "-password") {
     $password eq shift;
   }
   if($arg eq "-server") {
     $server eq shift;
   }
   if($arg eq "-deletespam" || $arg eq "-deletespams" || $arg eq "-delete-spam" || $arg eq "-delete-spams") {
     $deletespam = 1;
   }
   if($arg eq "-dangerous-delete-ham" || $arg eq "-dangerous-delete-hams") {
     $deleteham = 1;
   }
   if($arg eq "-dangerous-delete-all") {
     $deletespam = 1;
     $deleteham = 1;
   }
   if($arg eq "-logmaildir" || $arg eq "-logmail-dir") {
     $logdir = shift;
     $log = 1;
   }
   if($arg eq "-logmail") {
     $log = 1;
   }
   if($arg eq "-skips" || $arg eq "-skip") {
     $skips = shift;
   }
   if($arg eq "-?" || $arg eq "-h") {
     print "Usage:\n";
     print "  imap-sa-learn.pl [-spamfolder f]* [-hamfolder f]*\n\n";
     print "with no argumnets, uses default folders\n";
     print "(a few other options exist, see the header of the program)\n";
     exit;
   }
}

if($default) {
   push @hams,$defhamfolder;
   push @spams,$defspamfolder;
}

my %folders;
$folders{'spam'} = \@spams;
$folders{'ham'} = \@hams;


# Normal (1), Debugging (2), or silent(0)?
my $debug = 1;
if($debug == 2) {
	print "About to connect to $server as $username\n";
}

# Connect to the IMAP server in peek (i.e. don't set read flag) mode
my $imap = Mail::IMAPClient->new(Server   => $server,
				 User     => $username,
				 Password => $password,
				 Peek     => 1);

# Check we were able to connect to the server
unless($imap) {
	if($@) { die($@."\n"); }
	else { die("Unable to connect to $server, with an unknown error\n"); }
}
if($debug == 2) {
	print "Connected to server, looking for emails\n";
}


# Process our folders
foreach my $type(keys %folders) {
   foreach my $folder (@{$folders{$type}}) {
      print "\nLooking in $type folder $folder\n";

      # Pick the folder
      $imap->select($folder);

      # Enable peek mode
      $imap->Peek(1);

      # Fetch messages
      my @mails = ($imap->seen(),$imap->unseen);

      my $count = 0;

      foreach my $id (@mails) {
         $count++;
         if($count < $skips) { next; }

         print " Learning on $type message $id\n";
         my $mail = $imap->message_string($id);
         open SA, "| sa-learn --no-rebuild --$type --single";
         print SA $mail;
         close SA;

         if($log) {
            print "Logging $type message $id\n";
            open LOG, "| formail -ds >> ".$logdir."/".$type;
            print LOG $mail;
            close LOG;
         }

         if($type eq "spam" && $deletespam) {
            # If you want to move the message rather than deleting it,
            # uncomment the line below, change the folder, but _don't_
            # remove the delete line!
            #$imap->append('TrashBin', $mail );

            print "Deleting Spam Message $id\n";
            $imap->delete_message($id);
         }
         if($type eq "ham" && $deleteham) {
            print "Deleting Ham (normal email) Message $id\n";
            $imap->delete_message($id);
         }
      }
      if($deleteham || $deletespam) {
         # Only expunge now, rather than on every message
         $imap->expunge();
      }
   }
}

print "Now rebuilding the Baysean filters\n";
`sa-learn --rebuild`;

$imap->close;
exit;
