#!/usr/bin/perl -T BEGIN { use CGI::Carp qw(fatalsToBrowser carpout); } $ENV{PATH} = "/usr/sbin"; use strict; #use warnings; use CGI; use CGI::Carp qw(fatalsToBrowser carpout); use AnyDBM_File; use Fcntl; use List::Util qw(first); my %queue_to_user; my $tie_status = tie(%queue_to_user, 'AnyDBM_File', "/var/www/data/queue.db", O_CREAT | O_RDWR,0666) or die "Couldn't tie! ($!)"; $|++; my $q = new CGI; # print out to browser mode (somewhat useful) if ( $ENV{PATH_INFO} ) { my ($qid) = ( $ENV{PATH_INFO} =~ m,/(\w{14}), ); open( QF, "<", "/var/spool/mqueue/hf$qid" ) or die "Couldn't open /var/spool/mqueue/hf$qid for reading ($!)\n"; open( DF, "<", "/var/spool/mqueue/df$qid" ) or die "Couldn't open /var/spool/mqueue/df$qid for reading ($!)\n"; print $q->header( -type => 'text/plain' ); $/ = undef; print , ; exit 0; } # all else, we're in html mode print $q->header( -type => 'text/html' ); # checks to see if we're in admin mode or not my $admin = 0; if ($ENV{REMOTE_USER} eq "warewolf" ) { # && defined($q->param("noadmin")) && $q->param("noadmin") eq "1") { $admin++; } print STDERR "admin mode = $admin\n"; # set real to effective uid $< = $>; my $clearing = 0; if ( $q->param("op") ) { if ( $q->param("op") eq "clear") { # {{{ # clean slate mode, delete all messages owned by $ENV{REMOTE_USER} $clearing = 1; } # }}} elsif ( $q->param("op") eq "delete" ) { # {{{ # we're deleting messsages now my ($qid) = ( $q->param("qid") =~ m/(\w{14})/ ); unlink("/var/spool/mqueue/hf$qid") or die "Couldn't delete /var/spool/mqueue/hf$qid ($!)"; unlink("/var/spool/mqueue/df$qid") or die "Couldn't delete /var/spool/mqueue/df$qid ($!)"; print "Deleted $qid
\n"; } # }}} elsif ( $q->param("op") eq "run" ) { # {{{ # we're telling sendmail to run a particular message in the quarantine queue so it gets delivered to somebody's mailbox my ($qid) = ( $q->param("qid") =~ m/(\w{14})/ ); open( SENDMAIL, "-|", "sendmail -v -qQ -qf -qI$qid" ); print "
\n";
    # XXX 
    # XXX NO sanitation of sendmail's output
    # XXX 
    while () {
      my ($out) = ( $_ =~ m/(.+)/ );
      print $out;
    } 
    print "
"; } # }}} } # carry on as usual # start finding quarantined messages opendir( QUEUE, "/var/spool/mqueue" ) or die "Couldn't opendir /var/spool/mqueue ($!)"; # hf = quarantined messages my @queue_ids = grep { m/hf(\w{14})$/; $_ = $1 } readdir QUEUE; # this is a quick lookup table # that maps email addresses to local unix account names my %email_to_localuser; print "Click here to refresh this page.
\n"; print "
Press to clear all mail from the queue.
\n"; print "\n"; QID: foreach my $qid (@queue_ids) { open( QF, "<", "/var/spool/mqueue/hf$qid" ) or die "Couldn't open /var/spool/mqueue/hf$qid for reading! ($!)"; my $info; while () { $_ =~ m/^q"?(.+)"?$/ && do { $info->{quarantine} = $1; next }; $_ =~ m/^T(\d+)$/ && do { $info->{epoch} = $1; next }; $_ =~ m/^S<(.+)\>$/ && do { $info->{sender} = $1; next }; $_ =~ m/^rRFC822; (.+)$/ && do { $info->{recipient} = $1; last }; } $info->{size} = ( stat QF )[7]; $info->{epoch} = scalar localtime( $info->{epoch} ); close QF; # don't skip messages # ..... when our email -> local user (unix name) cache gets a hit # ..... when we're an admin # ..... when our Queue ID -> local user (unix name) cache gets a hit if ( defined( $email_to_localuser{ $info->{recipient} } ) or defined( $queue_to_user{$qid} ) ) { print STDERR "email to localuser for $info->{recipient} is $email_to_localuser{$info->{recipient}}\n"; next QID unless ( $ENV{REMOTE_USER} eq $email_to_localuser{ $info->{recipient} } or $admin or $queue_to_user{$qid} eq $ENV{REMOTE_USER} ); } # figure out if a message is to be delivered locally or not # XXX actually this wasn't implimented XXX my $local = 0; do { # if either cache $email_to_localuser or $queue_to_user is empty, figure out who it goes to #open( SENDMAIL, "-|", "sendmail -bv $info->{recipient}" ); # noisy open( SENDMAIL, "-|", "sendmail -OLogLevel=0 -bv $info->{recipient}" ); # quiet # REMOTE # # warewolf@xabean.com:/var/www/ssl-bin$ sudo sendmail -OLogLevel=0 -bv s2288@mail2000.com.tw # s2288@mail2000.com.tw... deliverable: mailer esmtp, host mail2000.com.tw., user s2288@mail2000.com.tw # # LOCAL # # warewolf@xabean.com:/var/www/ssl-bin$ sudo sendmail -OLogLevel=0 -bv wa4usb@wa4usb.us # wa4usb@wa4usb.us... deliverable: mailer local, user dharman while () { # XXX local or not delivery detection XXX if ($_ !~ m/\Qmailer esmtp, host\E/) { $local++ }; my ($found) = ($_ =~ m/\Qlocal, user $ENV{REMOTE_USER}\E/); # skip unless it's for the logged in remote user, or we're god next QID unless ( $found or $admin ); # stick it in our cache (unless we're an admin, otherwise it'd be a false cache) $email_to_localuser{ $info->{recipient} } = $ENV{REMOTE_USER} unless ($admin); if ($found) { # stick it in our cache (unless we're an admin, otherwise it'd be a false cache) $queue_to_user{$qid} = $ENV{REMOTE_USER} unless ($admin); } if (! $local) { # non local mail, lets nuke it from the queue # map { unlink("/var/spool/mqueue/$_$qid") } qw(qf df hf) ; } } # end while () { } unless ( defined( $email_to_localuser{ $info->{recipient} } ) or defined( $queue_to_user{$qid} ) ); my $style; if (! defined($queue_to_user{$qid})) { $style = $admin ? ' style="background-color: #ccc;"' : ""; } else { $style = ( $admin && $ENV{REMOTE_USER} ne $queue_to_user{$qid}) ? ' style="background-color: #ccc;"' : ""; } if ($clearing) { unlink("/var/spool/mqueue/hf$qid") or die "Couldn't delete /var/spool/mqueue/hf$qid ($!)"; unlink("/var/spool/mqueue/df$qid") or die "Couldn't delete /var/spool/mqueue/df$qid ($!)"; print "\n"; print "\n"; print "\n"; print "\n"; } else { print "\n"; print "\n"; print "\n"; } } print "
Q IDSizeQ TimeSender/Recipient
DELETED
$info->{size}$info->{epoch}$info->{sender}
$info->{quarantine}
$info->{recipient}
$qid
\n"; print "
\n"; if ($q->param("noadmin")) { print "\n"; } $info->{sender} = $info->{sender} || ""; print " |
\n"; print "
$info->{size}$info->{epoch}$info->{sender}
$info->{quarantine}
$info->{recipient}
\n"; # size maintenance of cache foreach my $id ( keys %queue_to_user ) { delete $queue_to_user{$id} unless first { defined( $queue_to_user{$_} ) } @queue_ids; } undef $tie_status; untie %queue_to_user; # vim: ft=perl foldmethod=marker commentstring=#\ %s bg=dark