#!/usr/bin/perl -w

# spam-stats.pl
# count and classify reject: lines in postfix mail logs
# Copyright Craig Sanders <cas@taz.net.au> 2001
# Maby changes by Marco d'Itri <md@linux.it> 2002
# This script is licensed under the terms of the GNU General Public License.

use strict;

my (%count, %header, %body, %host);
my $total = 0;

while (<STDIN>) {
	next unless /postfix\/.* reject: /;
	# we don't care about local problems like quota
	next if /Insufficient system storage;/;
	next if /Message size exceeds fixed limit/;
	next if /Etrn command rejected/;
	chomp;

	s/^.*?reject: //;

	if    (/^header .+>: (.+?)$/) { $count{'header checks'}++; $header{$1}++; }
	elsif (/^body .+>: (.+?)$/)   { $count{'body checks'}++;   $body{$1}++;  }

	elsif (/^\S+ from \S+: \d{3} Improper use of SMTP command pipelining/)
		{ $count{'Bad pipelining'}++ }

	elsif (s/^\S+ from \S+: \d{3} Service unavailable;( Client host)? \S+ //) {
		if (/^blocked using (\S+)[,;]/) { 
			$count{"DNSBL $1"}++;
		} elsif (/^access denied/i) { 
			#s/reject: [^:]+: [^:]+: //;
			#s/:.*//; 
			$count{"Local access rule: $_"}++; # XXX
		} else {
			warn "NOT COUNTED:\n$_\n";
		}
	}

	elsif (s/^.+?: \d{3} <.+?>: //) {

	   if (/^Relay access denied/) { $count{'Relay access denied'}++ } 
	elsif (/^Helo command rejected/) { $count{'Bad HELO'}++ } 
	elsif (/^Client host rejected: (.+);/) {
		$count{'Client host rejected'}++; $host{$1}++; }
	elsif (/^Sender address rejected: need fully-qualified address/) {
		$count{'Need FQDN address'}++ }
	elsif (/^Sender address rejected: Domain not found/i) {
		$count{'Sender Domain not found'}++ }  
	elsif (/^Sender address rejected/) { $count{'Sender address rejected'}++ }
	elsif (/^Recipient address rejected: Domain not found/) {
		$count{'Recipient Domain not found'}++ }
	elsif (/^Recipient address rejected: need fully-qualified address/) {
		$count{'Need FQDN address (recipient)'}++ } 
	elsif (/^Recipient address rejected/) {
		$count{'Recipient address rejected'}++ } 
	elsif (/^User unknown/) { $count{'User unknown'}++ } 
	else { $count{'Other'}++; warn "UNKNOWN\n$_\n"; }

	} else {
		$count{'Other'}++;
		warn "UNKNOWN\n$_\n";
	}

}

foreach (reverse sort { $count{$a} <=> $count{$b} } keys %count) {
	printf("%7i\t%s\n", $count{$_}, $_);
	$total += $count{$_};
}

printf "\n%7i\tTOTAL\n", $total;

print "\nRejected headers:\n" if keys %header;
foreach (reverse sort { $header{$a} <=> $header{$b} } keys %header) {
	printf("%7i\t%s\n", $header{$_}, $_);
}

print "\nRejected bodies\n" if keys %body;
foreach (reverse sort { $body{$a} <=> $body{$b} } keys %body) {
	printf("%7i\t%s\n", $body{$_}, $_);
}

print "\nRejected hosts\n" if keys %host;
foreach (reverse sort { $host{$a} <=> $host{$b} } keys %host) {
	printf("%7i\t%s\n", $host{$_}, $_);
}

exit 0;

