#!/usr/bin/env perl

# add this to your snmpd.conf file as below
# extend postfixdetailed /etc/snmp/postfixdetailed

# The cache file to use.
my $cache='/var/cache/postfixdetailed';

# the location of pflogsumm
my $pflogsumm='/usr/bin/env pflogsumm';

#totals
#    847   received                 = received
#    852   delivered                = delivered
#      0   forwarded                = forwarded
#      3   deferred  (67  deferrals)= deferred
#      0   bounced                  = bounced
#    593   rejected (41%)           = rejected
#      0   reject warnings          = rejectw
#      0   held                     = held
#      0   discarded (0%)           = discarded

#  16899k  bytes received           = bytesr
#  18009k  bytes delivered          = bytesd
#    415   senders                  = senders
#    266   sending hosts/domains    = sendinghd
#     15   recipients               = recipients
#      9   recipient hosts/domains  = recipienthd

######message deferral detail
#Connection refused  = deferralcr
#Host is down  = deferralhid

########message reject detail
#Client host rejected                                     = chr
#Helo command rejected: need fully-qualified hostname     = hcrnfqh
#Sender address rejected: Domain not found                = sardnf
#Sender address rejected: not owned by user               = sarnobu
#blocked using                                            = bu
#Recipient address rejected: User unknown                 = raruu
#Helo command rejected: Invalid name                      = hcrin
#Sender address rejected: need fully-qualified address    = sarnfqa
#Recipient address rejected: Domain not found             = rardnf
#Recipient address rejected: need fully-qualified address = rarnfqa
#Improper use of SMTP command pipelining                  = iuscp
#Message size exceeds fixed limit                         = msefl
#Server configuration error                               = sce
#Server configuration problem                             = scp
#unknown reject reason                                    = urr

my $old='';

#reads in the old data if it exists
if ( -f $cache ){
	open(my $fh, "<", $cache) or die "Can't open '".$cache."'";
	# if this is over 2048, something is most likely wrong
	read($fh , $old , 2048);
	close($fh);
}

my ( $received,
	 $delivered,
	 $forwarded,
	 $deferred,
	 $bounced,
	 $rejected,
	 $rejectw,
	 $held,
	 $discarded,
	 $bytesr,
	 $bytesd,
	 $senders,
	 $sendinghd,
	 $recipients,
	 $recipienthd,
	 $deferralcr,
	 $deferralhid,
	 $chr,
	 $hcrnfqh,
	 $sardnf,
	 $sarnobu,
	 $bu,
	 $raruu,
	 $hcrin,
	 $sarnfqa,
	 $rardnf,
	 $rarnfqa,
	 $iuscp,
	 $msefl,
	 $sce,
	 $scp,
	 $urr) = split ( /\n/, $old );

if ( ! defined( $received ) ){ $received=0; }
if ( ! defined( $delivered ) ){ $delivered=0; }
if ( ! defined( $forwarded ) ){ $forwarded=0; }
if ( ! defined( $deferred ) ){ $deferred=0; }
if ( ! defined( $bounced ) ){ $bounced=0; }
if ( ! defined( $rejected ) ){ $rejected=0; }
if ( ! defined( $rejectw ) ){ $rejectw=0; }
if ( ! defined( $held ) ){ $held=0; }
if ( ! defined( $discarded ) ){ $discarded=0; }
if ( ! defined( $bytesr ) ){ $bytesr=0; }
if ( ! defined( $bytesd ) ){ $bytesd=0; }
if ( ! defined( $senders ) ){ $senders=0; }
if ( ! defined( $sendinghd ) ){ $sendinghd=0; }
if ( ! defined( $recipients ) ){ $recipients=0; }
if ( ! defined( $recipienthd ) ){ $recipienthd=0; }
if ( ! defined( $deferralcr ) ){ $deferralcr=0; }
if ( ! defined( $deferralhid ) ){ $deferralhid=0; }
if ( ! defined( $chr ) ){ $chr=0; }
if ( ! defined( $hcrnfqh ) ){ $hcrnfqh=0; }
if ( ! defined( $sardnf ) ){ $sardnf=0; }
if ( ! defined( $sarnobu ) ){ $sarnobu=0; }
if ( ! defined( $bu ) ){ $bu=0; }
if ( ! defined( $raruu ) ){ $raruu=0; }
if ( ! defined( $hcrin ) ){ $hcrin=0; }
if ( ! defined( $sarnfqa ) ){ $sarnfqa=0; }
if ( ! defined( $rardnf ) ){ $rardnf=0; }
if ( ! defined( $rarnfqa ) ){ $rarnfqa=0; }
if ( ! defined( $iuscp ) ){ $iuscp=0; }
if ( ! defined( $msefl ) ){ $msefl=0; }
if ( ! defined( $sce ) ){ $sce=0; }
if ( ! defined( $scp ) ){ $scp=0; }
if ( ! defined( $urr ) ){ $urr=0; }

#init current variables
my $receivedC=0;
my $deliveredC=0;
my $forwardedC=0;
my $deferredC=0;
my $bouncedC=0;
my $rejectedC=0;
my $rejectwC=0;
my $heldC=0;
my $discardedC=0;
my $bytesrC=0;
my $bytesdC=0;
my $sendersC=0;
my $sendinghdC=0;
my $recipientsC=0;
my $recipienthdC=0;
my $deferralcrC=0;
my $deferralhidC=0;
my $chrC=0;
my $hcrnfqhC=0;
my $sardnfC=0;
my $sarnobuC=0;
my $buC=0;
my $raruuC=0;
my $hcrinC=0;
my $sarnfqaC=0;
my $rardnfC=0;
my $rarnfqaC=0;
my $iuscpC=0;
my $mseflC=0;
my $sceC=0;
my $scpC=0;
my $urrC=0;

sub newValue{
	my $old=$_[0];
	my $new=$_[1];

	#if new is undefined, just default to 0... this should never happen
	if ( !defined( $new ) ){
		warn('New not defined');
		return 0;
	}

	#sets it to 0 if old is not defined
	if ( !defined( $old ) ){
		warn('Old not defined');
		$old=0;
	}

	#make sure they are both numberic and if not set to zero
	if( $old !~ /^[0123456789]*$/ ){
		warn('Old not numeric');
		$old=0;
	}
	if( $new !~ /^[0123456789]*$/ ){
		warn('New not numeric');
		$new=0;
	}

	#log rotation happened
	if ( $old > $new ){
		return $new;
	};

	return $new - $old;
}


my $output=`$pflogsumm /var/log/maillog`;

#holds client host rejected values till the end when it is compared to the old one
my $chrNew=0;

#holds RBL values till the end when it is compared to the old one
my $buNew=0;

# holds recipient address rejected values till the end when it is compared to the old one
my $raruuNew=0;

#holds the current values for checking later
my $current='';

my @outputA=split( /\n/, $output );
my $int=0;
while ( defined( $outputA[$int] ) ){
	my $line=$outputA[$int];

	$line=~s/^ *//;
	$line=~s/ +/ /g;
	$line=~s/\)$//;

	my $handled=0;
	
	#received line
	if ( ( $line =~ /[0123456789] received$/ ) && ( ! $handled ) ){
		$line=~s/ .*//;
		$receivedC=$line;
		$received=newValue( $received, $line );
		$handled=1;
	}

	#delivered line
	if ( ( $line =~ /[0123456789] delivered$/ ) && ( ! $handled ) ){
		$line=~s/ .*//;
		$deliveredC=$line;
		$delivered=newValue( $delivered, $line );
		$handled=1;
	}

	#forward line
	if ( ( $line =~ /[0123456789] forwarded$/ ) && ( ! $handled ) ){
		$line=~s/ .*//;
		$forwardedC=$line;
		$forwarded=newValue( $forwarded, $line );
		$handled=1;
	}

	#defereed line
	if ( ( $line =~ /[0123456789] deferred \(/ ) && ( ! $handled ) ){
		$line=~s/ .*//;
		$deferredC=$line;
		$deferred=newValue( $deferred, $line );
		$handled=1;
	}

	#bounced line
	if ( ( $line =~ /[0123456789] bounced$/ ) && ( ! $handled ) ){
		$line=~s/ .*//;
		$bouncedC=$line;
		$bounced=newValue( $bounced, $line );
		$handled=1;
	}

	#rejected line
	if ( ( $line =~ /[0123456789] rejected \(/ ) && ( ! $handled ) ){
		$line=~s/ .*//;
		$rejectedC=$line;
		$rejected=newValue( $rejected, $line );
		$handled=1;
	}

	#reject warning line
	if ( ( $line =~ /[0123456789] reject warnings/ ) && ( ! $handled ) ){
		$line=~s/ .*//;
		$rejectwC=$line;
		$rejectw=newValue( $rejectw, $line );
		$handled=1;
	}

	#held line
	if ( ( $line =~ /[0123456789] held$/ ) && ( ! $handled ) ){
		$line=~s/ .*//;
		$heldC=$line;
		$held=newValue( $held, $line );
		$handled=1;
	}

	#discarded line
	if ( ( $line =~ /[0123456789] discarded \(/ ) && ( ! $handled ) ){
		$line=~s/ .*//;
		$discardedC=$line;
		$discarded=newValue( $discarded, $line );
		$handled=1;
	}

	#bytes received line
	if ( ( $line =~ /[0123456789kM] bytes received$/ ) && ( ! $handled ) ){
		$line=~s/ .*//;
		$line=~s/k/000/;
		$line=~s/M/000000/;
		$bytesrC=$line;
		$bytesr=newValue( $bytesr, $line );
		$handled=1;
	}

	#bytes delivered line
	if ( ( $line =~ /[0123456789kM] bytes delivered$/ ) && ( ! $handled ) ){
		$line=~s/ .*//;
		$line=~s/k/000/;
		$line=~s/M/000000/;
		$bytesdC=$line;
		$bytesd=newValue( $bytesd, $line );
		$handled=1;
	}

	#senders line
	if ( ( $line =~ /[0123456789] senders$/ ) && ( ! $handled ) ){
		$line=~s/ .*//;
		$sendersC=$line;
		$senders=newValue( $senders, $line );
		$handled=1;
	}

	#sendering hosts/domains line
	if ( ( $line =~ /[0123456789] sending hosts\/domains$/ ) && ( ! $handled ) ){
		$line=~s/ .*//;
		$sendinghdC=$line;
		$sendinghd=newValue( $sendinghd, $line );
		$handled=1;
	}

	#recipients line
	if ( ( $line =~ /[0123456789] recipients$/ ) && ( ! $handled ) ){
		$line=~s/ .*//;
		$recipientsC=$line;
		$recipients=newValue( $recipients, $line );
		$handled=1;
	}

	#recipients line
	if ( ( $line =~ /[0123456789] recipient hosts\/domains$/ ) && ( ! $handled ) ){
		$line=~s/ .*//;
		$recipienthdC=$line;
		$recipienthd=newValue( $recipienthd, $line );
		$handled=1;
	}

	# deferrals connectios refused
	if ( ( $line =~ /[0123456789] 25\: Connection refused$/ ) && ( ! $handled ) ){
		$line=~s/ .*//;
		$deferralcrC=$line;
		$deferralcr=newValue( $deferralcr, $line );
		$handled=1;
	}

	# deferrals Host is down
	if ( ( $line =~ /Host is down$/ ) && ( ! $handled ) ){
		$line=~s/ .*//;
		$deferralhidC=$line;
		$deferralhid=newValue( $deferralhid, $line );
		$handled=1;
	}

	# Client host rejected
	if ( ( $line =~ /Client host rejected/ ) && ( ! $handled ) ){
		$line=~s/.*\: //g;
		$chrNew=$chrNew + $line;
		$handled=1;
	}
	
	#Helo command rejected: need fully-qualified hostname
	if ( ( $line =~ /Helo command rejected\: need fully\-qualified hostname/ ) && ( ! $handled ) ){
		$line=~s/.*\: //g;
		$hcrnfqhC=$line;
		$hcrnfqh=newValue( $hcrnfqh, $line );
		$handled=1;
	}

	#Sender address rejected: Domain not found
	if ( ( $line =~ /Sender address rejected\: Domain not found/ ) && ( ! $handled ) ){
		$line=~s/.*\: //g;
		$sardnfC=$line;
		$sardnf=newValue( $sardnf, $line );
		$handled=1;
	}

	#Sender address rejected: not owned by user
	if ( ( $line =~ /Sender address rejected\: not owned by user/ ) && ( ! $handled ) ){
		$line=~s/.*\: //g;
		$sarnobuC=$line;
		$sarnobu=newValue( $sarnobu, $line );
		$handled=1;
	}

	#blocked using
	# These lines are RBLs so there will be more than one.
	# Use $buNew to add them all up.
	if ( ( $line =~ /blocked using/ ) && ( ! $handled ) ){
		$line=~s/.*\: //g;
		$buNew=$buNew + $line;
		$handled=1;
	}

	#Recipient address rejected: User unknown
	if ( ( $line =~ /Recipient address rejected\: User unknown/ ) && ( ! $handled ) ){
		$line=~s/.*\: //g;
		$raruuNew=$raruuNew + $line;
		$handled=1;
	}

	#Helo command rejected: Invalid name
	if ( ( $line =~ /Helo command rejected\: Invalid name/ ) && ( ! $handled ) ){
		$line=~s/.*\: //g;
		$hcrinC=$line;
		$hcrin=newValue( $hcrin, $line );
	}
	
	#Sender address rejected: need fully-qualified address
	if ( ( $line =~ /Sender address rejected\: need fully-qualified address/ ) && ( ! $handled ) ){
		$line=~s/.*\: //g;
		$sarnfqaC=$line;
		$sarnfqa=newValue( $sarnfqa, $line );
	}

	#Recipient address rejected: Domain not found
	if ( ( $line =~ /Recipient address rejected\: Domain not found/ ) && ( ! $handled ) ){
		$line=~s/.*\: //g;
		$rardnfC=$line;
		$rardnf=newValue( $rardnf, $line );
	}

	#Improper use of SMTP command pipelining
	if ( ( $line =~ /Improper use of SMTP command pipelining/ ) && ( ! $handled ) ){
		$line=~s/.*\: //g;
		$iuoscpC=$line;
		$iuoscp=newValue( $iuoscp, $line );
	}

	#Message size exceeds fixed limit
	if ( ( $line =~ /Message size exceeds fixed limit/ ) && ( ! $handled ) ){
		$line=~s/.*\: //g;
		$mseflC=$line;
		$msefl=newValue( $msefl, $line );
	}

	#Server configuration error
	if ( ( $line =~ /Server configuration error/ ) && ( ! $handled ) ){
		$line=~s/.*\: //g;
		$sceC=$line;
		$sce=newValue( $sce, $line );
	}

	#Server configuration problem
	if ( ( $line =~ /Server configuration problem/ ) && ( ! $handled ) ){
		$line=~s/.*\: //g;
		$scpC=$line;
		$scp=newValue( $scp, $line );
	}
	
	#unknown reject reason
	if ( ( $line =~ /unknown reject reason/ ) && ( ! $handled ) ){
		$line=~s/.*\: //g;
		$urrC=$line;
		$urr=newValue( $urr, $line );
	}
	$int++;
}

# final client host rejected total
$chr=newValue( $chr, $chrNew );

# final RBL total
$bu=newValue( $bu, $buNew );

# final recipient address rejected total
$raruu=newValue( $raruu, $raruuNew );

my $data=$received."\n".
	$delivered."\n".
	$forwarded."\n".
	$deferred."\n".
	$bounced."\n".
	$rejected."\n".
	$rejectw."\n".
	$held."\n".
	$discarded."\n".
	$bytesr."\n".
	$bytesd."\n".
	$senders."\n".
	$sendinghd."\n".
	$recipients."\n".
	$recipienthd."\n".
	$deferralcr."\n".
	$deferralhid."\n".
	$chr."\n".
	$hcrnfqh."\n".
	$sardnf."\n".
	$sarnobu."\n".
	$bu."\n".
	$raruu."\n".
	$hcrin."\n".
	$sarnfqa."\n".
	$rardnf."\n".
	$rarnfqa."\n".
	$iuscp."\n".
	$sce."\n".
	$scp."\n".
	$urr."\n";
	$msefl."\n".

print $data;

my $current=$receivedC."\n".
	$deliveredC."\n".
	$forwardedC."\n".
	$deferredC."\n".
	$bouncedC."\n".
	$rejectedC."\n".
	$rejectwC."\n".
	$heldC."\n".
	$discardedC."\n".
	$bytesrC."\n".
	$bytesdC."\n".
	$sendersC."\n".
	$sendinghdC."\n".
	$recipientsC."\n".
	$recipienthdC."\n".
	$deferralcrC."\n".
	$deferralhidC."\n".
	$chrNew."\n".
	$hcrnfqhC."\n".
	$sardnfC."\n".
	$sarnobuC."\n".
	$buNew."\n".
	$raruuNew."\n".
	$hcrinC."\n".
	$sarnfqaC."\n".
	$rardnfC."\n".
	$rarnfqaC."\n".
	$iuscpC."\n".
	$mseflC."\n".
	$sceC."\n".
	$scpC."\n".
	$urrC."\n";

open(my $fh, ">", $cache) or die "Can't open '".$cache."'";
print $fh $current;
close($fh);
