#!/usr/bin/perl
#
#	Mofigications:
#
#		25.12.1998, Jochen Wiedmann
#			Mails werden nicht mehrfach weitergeleitet;
#			zu diesem Zweck wird ein eigener Header
#			X-Mail2Group eingefuehrt.
#
use strict;
require 5.004;


require Mail::Internet;
require Mail::Util;
require Getopt::Long;
require Time::Local;
require DBI;
require Data::Dumper;
require Symbol;


my $PREFS_FILE = '/home/httpd/html/admin/var/prefs';
my $SPOOL_DIR  = '/var/spool/mail';
my $DBI_DSN    = 'DBI:mysql:user';
my $DBI_USER   = 'nobody';
#my $DBI_PASS   = '';
my $DBI_PASS   = 'my_name_is_nobody';
my $WWW_USER   = 'nobody';
#my $LOCAL_MAILS = '\@euwid\.de\b';
my $LOCAL_MAILS = '';

my %MONTHS = (
    'jan' => 0,
    'feb' => 1,
    'mar' => 2,
    'apr' => 3,
    'may' => 4,
    'jun' => 5,
    'jul' => 6,
    'aug' => 7,
    'sep' => 8,
    'oct' => 9,
    'nov' => 10,
    'dec' => 11
    );


my $options = {
    'dsn' => $DBI_DSN,
    'user' => $DBI_USER,
    'password' => $DBI_PASS,
    'verbose' => 0,
    'debug' => 0
};

Getopt::Long::GetOptions($options, 'dsn=s', 'user=s', 'password=s',
			 'verbose', 'debug');
my $debug = $options->{'debug'};
if ($debug) {
    $options->{'verbose'} = 1;
}
my $verbose = $options->{'verbose'};

my $config = do $PREFS_FILE
    || die "Error while reading prefs file $PREFS_FILE: $@";


if (!$config->{'mail2group'}->{'active'}) { exit 0 }
if (!$config->{'mail2group'}->{'weekend'}) {
    my($sec, $min, $hour, $mday, $mon, $year, $wday) = localtime(time());
    if ($wday == 0  ||  $wday == 6) { exit 0 }
}
my $cache = $config->{'mail2group'}->{'cache'} or {};
foreach my $var (keys %$cache) {
    $cache->{$var} = 0;
}


my $dbh = DBI->connect($options->{'dsn'}, $options->{'user'},
		       $options->{'password'}, { 'RaiseError' => 1 });
END { $dbh->disconnect() if $dbh; undef $dbh }

my $sth = $dbh->prepare("SELECT * FROM USERS");
$sth->execute();
while (my $ref = $sth->fetchrow_hashref()) {
    my $user = $ref->{'USER'};
    my $forward = $ref->{'CUSTOM'};
    if (!$forward) {
	print "Ignoring user $user.\n" if $verbose;
	next;
    }
    my $folder = "$SPOOL_DIR/$user";
    if (! -f $folder  ||  -z _) {
	print "Empty folder of user $user.\n" if ($verbose);
	next;
    }
    my @mails = eval { Mail::Util::read_mbox("$SPOOL_DIR/$user") };
    if ($@) {
	print STDERR "Error while reading folder $folder: $@\n";
	next;
    }
    my $i = 0;
    foreach my $mail (@mails) {
	++$i;
	my $msg = Mail::Internet->new($mail, 'MailFrom' => 'KEEP');
	my $head = $msg->head();
	if ($head->get("X-Mail2Group")) {
	    print "Ignoring mail $i of user $user: Mail2Group header found.\n"
		if ($verbose);
	    next;
	}
	my $local;
	if ($LOCAL_MAILS) {
	    foreach my $address ($head->get("reply-to"),
				 $head->get("from")) {
		if ($address =~ /$LOCAL_MAILS/oi) {
		    $local = $address;
		    last;
		}
	    }
	    if ($local) {
		print "Ignoring mail $i of user $user: Local sender $local.\n"
		    if ($verbose);
		next;
	    }
	}
	my $id = $head->get("Message-Id");
	if (!defined($id)) {
	    print "Ignoring mail $i of user $user: Missing message-id.\n"
		if ($verbose);
	    next;
	}
	if ($id =~ /<(.*?)>/) {
	    $id = $1;
	}
	$id .= ",$user";
	if (exists($cache->{$id})) {
	    print "Ignoring mail $i of user $user (Cache, $id)\n"
		if ($verbose);
	    $cache->{$id} = 1;
	    next;
	}
	if ($msg) {
	    my $received = $msg->head()->get("Received");
	    my $time;
	    if ($received =~ /(\d+)\s+(\S+)\s+(\d+)\s+(\d+)\:(\d+)\:(\d+)/s) {
		my $mday = $1;
		my $mon = $2;
		my $year = $3;
		my $hour = $4;
		my $min = $5;
		my $sec = $6;
		if (exists($MONTHS{lc $mon})) {
		    $mon = $MONTHS{lc $mon};
		} else {
		    print STDERR ("Cannot parse received header from mail $i"
				  , " of user $user\n");
		    next;
		}
		$year -= 1900 if ($year > 99);
		$time = Time::Local::timelocal($sec, $min, $hour, $mday, $mon,
					       $year);
	    }
	    if ($time + $config->{'mail2group'}->{'delay'} * 24 * 60 * 60
		> time()) {
		printf("Ignoring mail $i ($id) of user $user: $received\n")
		    if ($verbose);
		next;
	    }
	    printf("Forwarding mail $i ($id) of user $user to $forward.\n")
		if ($verbose);
	    $cache->{$id} = 1;
	    if ($debug) {
		next;
	    }
	    $head->add('X-Forwarder', "mail2group ($user)");
	    $head->add('X-Mail2Group', "$user => $forward");
	    $msg->smtpsend('Host' => '127.0.0.1',
			   map { s/^\s+//; s/\s+$//; ('Bcc' => $_) }
			       split(/,/, $forward));
	}
    }
}


my @keys = grep { !$cache->{$_} } keys %$cache;
foreach my $key (@keys) {
    if ($verbose) {
	printf("Deleting ID $key from cache.\n");
    }
    delete $cache->{$key};
}


$config->{'mail2group'}->{'cache'} = $cache;
my $dump = Data::Dumper->new([$config], ['PREFS']);
$dump->Indent(1);
my $str = $dump->Dump();
my $fh = Symbol::gensym();
if ($verbose) {
    print("Saving data:\n$str\n");
}
if (!$debug) {
    if (!open($fh, ">$PREFS_FILE")  ||  !(print $fh $str)  ||
	!close($fh)) {
	die "Couldn't save data: $!";
    }
    my($login, $pass, $uid, $gid) = getpwnam($WWW_USER);
    chown $uid, $gid, $PREFS_FILE;
}
