#!/usr/bin/perl -w
# Submit tickets to sa-learn
# The user which run this script needs to be the user who handle Anti-Spam
# software and need to have proper rights in RT to access tickets
# (Global rights: SeeQueue, ShowTicket)
# He also needs to be able to access RT files, especially config file.


use strict;
use lib "/appli/rt/rt/local/lib";
use lib "/appli/rt/rt/lib";
use lib "/appli/rt/rt/etc";
use RT;
use RT::Interface::CLI qw( CleanEnv GetCurrentUser );
use RT::Queue;
use RT::Queues;
use RT::Tickets;
use RT::Date;
use MIME::Entity;
use MIME::Body;


my $debug = 0;
my $spam_status = 'spam';
my $ham_status = 'resolved';
my $learn_ham_cmd = '/usr/bin/sa-learn --ham - > /dev/null';
my $learn_spam_cmd = '/usr/bin/sa-learn --spam - > /dev/null';

if ($debug) {
    $learn_ham_cmd = $learn_spam_cmd = '/bin/cat';
}

# Set locales
$ENV{'LANG'} = 'POSIX';
$ENV{'LC_ALL'} = 'POSIX';

# RT CLI initialization
CleanEnv();
RT::LoadConfig();
RT::Init();

# Get the current user all loaded
our $CurrentUser = GetCurrentUser();

unless( $CurrentUser->Id )
{
    print STDERR "No RT user found. Please consult your RT administrator.\n";
    exit 1;
}

# Limit to tickets LastUpdated 2 days ago
my $datelimit = new RT::Date($RT::SystemUser);
$datelimit->SetToNow();
$datelimit->AddDays(-1);

my $spam_count = 0;

# From RT 3.8

sub ContentAsMIME {
    my $self = shift;

    my $entity = new MIME::Entity;
    $entity->head->add( split /:/, $_, 2 )
        foreach SplitHeaders($self);

    use MIME::Body;
    $entity->bodyhandle(
        MIME::Body::Scalar->new( $self->OriginalContent )
    );

    return $entity;
}

sub SplitHeaders {
    my $self = shift;
    my @headers;
    for (split(/\n(?=\w|\z)/,$self->Headers)) {
        push @headers, $_ if ($_ !~ /^RT-Send-Bcc/i);
    }
    return(@headers);
}

sub submit_message ($$) {
    my $message = shift;
    my $type = shift;
    if ($type eq 'ham') {
        open (CMD, "| $learn_ham_cmd ") or die "Can't run $learn_ham_cmd: $!\n";
        print CMD $message;
        close(CMD);
    } elsif ($type eq 'spam') {
        open (CMD, "| $learn_spam_cmd ") or die "Can't run $learn_spam_cmd: $!\n";
        print CMD $message;
        close(CMD);
    } else {
        warn "Unknown type: $type\n";
    }
}

sub get_message ($$) {
    my $ticket = shift;
    my $txn = shift;
    my $entity = new MIME::Entity;
    my $header = 0;
    my $attachments = RT::Attachments->new( $txn->CurrentUser );
    $attachments->Limit( FIELD => 'TransactionId', VALUE => $txn->id );
    $attachments->OrderBy( FIELD => 'Id', ORDER => 'ASC' );
    while ( my $a = $attachments->Next ) {
        if (! $header) {
            $entity->head->add( split /:/, $_, 2 ) foreach SplitHeaders($a);
            $header = 1;
        } else {
            # Skip multipart declaration
            next if (! $a->Content || $a->Content eq '');
            $entity->make_multipart unless $entity->is_multipart;
            $entity->add_part(ContentAsMIME($a));
        }
    }

    return $entity->as_string;

}

# Spams
print "=================SPAM==================\n" if ($debug);
my $queues = new RT::Queues($RT::SystemUser);
$queues->LimitToEnabled();
foreach my $queue (@{$queues->ItemsArrayRef()}) {
    my $tickets = new RT::Tickets($RT::SystemUser);
    $tickets->LimitStatus(VALUE => $spam_status);
    $tickets->LimitQueue(VALUE => $queue->Id);
    $tickets->LimitLastUpdated(OPERATOR => ">",
                               VALUE => $datelimit->ISO );
    while (my $ticket = $tickets->Next) {
        my $txn = $ticket->Transactions->First;
        # Skip web created tickets
        my $msgattr = $txn->Message->First;
        next if (!$msgattr);
        next if (!$msgattr->GetHeader('Received'));

        $spam_count++;

        my $message = get_message($ticket, $txn);
        submit_message($message, 'spam');

    }
}

# Ham
print "==================HAM==================\n" if ($debug);
my $ham_count = 0;
foreach my $queue (@{$queues->ItemsArrayRef()}) {

    # Limit to same count of ham/spam messages
    last if ($ham_count >= $spam_count);

    my $tickets = new RT::Tickets($RT::SystemUser);
    $tickets->LimitStatus(VALUE => $ham_status);
    $tickets->LimitQueue(VALUE => $queue->Id);
    $tickets->LimitLastUpdated(OPERATOR => ">",
                               VALUE => $datelimit->ISO );
    while (my $ticket = $tickets->Next) {
        # Limit to same count of ham/spam messages
        last if ($ham_count >= $spam_count);
        my $txn = $ticket->Transactions->First;
        # Skip web created tickets
        my $msgattr = $txn->Message->First;
        next if (!$msgattr);
        next if (!$msgattr->GetHeader('Received'));

        $ham_count++;

        my $message = get_message($ticket, $txn);
        submit_message($message, 'ham');

    }
}

# vim: expandtab tabstop=4
