#!/usr/bin/perl

use Getopt::Std;
use SOAP::Lite;

my $default_threshold = 150;
my $do_suspend = 0;
my $do_report = 0;
my $verbose = 0;
my $exempt = 0;
my $exceptions = "/data01/zenadmin/zen-findspammer-exceptions.txt";
my $logfile;
my $threshold;
my $report;
my $report_exists=0;

my $email="/bin/mail -s";
my $title=`hostname`;
chomp ($title);
$title.=" Autosuspend (Webmail Spam)";
my $report_to="netops\@zeninternet.co.uk,supportsecondline\@staff.zeninternet.co.uk";


###############################

getopts('rsvf:t:');

if ($opt_f)
{
 $logfile = $ARGV[0];
}
else
{
 $logfile = "/var/log/exim_mainlog";
}

if ($opt_t)
{
 $threshold = $opt_t;
}
else
{
 $threshold = $default_threshold;
}

$verbose = 1 if ($opt_v);
$do_suspend = 1 if ($opt_s);
$do_report = 1 if ($opt_r);
 
####################################

my %dodgydomains;
my %junkids;
my %except;
 
if ( -f $exceptions) {
	open (EXCEPTIONS, $exceptions) or die "Err: can't open exceptions file $exceptions\n";
	while (my $ln = <EXCEPTIONS>) {
		chomp($ln);
		$except{$ln}++;
		$exempt++;
	}
}

if ($verbose) {
	print "\n================== Overview ====================\n";
	print "Checking $logfile for webmail and asmtp spammers\n";
	if ($exempt) {
		print "Found $exempt entries in $exceptions\n";
	}
	print "\tMAX RCPTS option is set to $threshold\n";
	print "\t  SUSPEND option is set to $do_suspend\n";
	print "\t   REPORT option is set to $do_report\n";
}

if ($do_suspend)
{
	$report = "\nThe following accounts were suspended:\n";
}
else
{
	$report = "\nThe following accounts could be suspended (use '-s' flag to enable suspensions):\n";
}

if ($verbose) { 
	print "\n============= Suspicious Accounts ==============\n";
}

open(LOGFILE, $logfile) or die "Err: can't open logfile $logfile\n";
while(<LOGFILE>)
{
	if (/U=cpanel P=local/ && /<=/)
	{
		my ($start, $rcpts) = split(/from .*@.* for /, $_, 2);
		my ($date,$time,$msgid,$fullsite,$subject) = (split(/ /, $start, 10))[0,1,2,8,9];
		$subject =~ s/^T=//;
		my @rcpts = (split(/ /, $rcpts));
		my $norcpts = $#rcpts + 1;
		my $site = (split(/@/, $fullsite))[1];

		if ($norcpts > $threshold)
		{
			print "HORDE: $date $time $msgid\tRcpts: $norcpts\tSite: $site Subject: $subject\n" if $verbose;
			$dodgydomains{$site} += $norcpts;
			$junkids{$site}{$msgid}++;
		}
	}
	elsif (/P=esmtpa A=fixed_login:/ && /<=/)
	{
		my $ln = $_;
		my ($start, $rcpts) = split(/from .*@.* for /, $_, 2);
		my ($substart,$other) = split(/ <= /, $start, 2);
		my ($date,$time,$msgid) = (split(/ /, $substart, 3))[0,1,2];
		my ($asmtp,$subject) = (split(/ .=/, $other, 8))[4,6];

		my @rcpts = (split(/ /, $rcpts));
		my $norcpts = $#rcpts + 1;
		my $user = (split(/:/, $asmtp))[1];
		my $site;

		#print "LN: $ln\n";
		#print "START = $start\n";
		#print "SUBSTART = $substart\n";
		#print "OTHER = $other\n";
		#print "BITS: Date:$date:Time:$time:MsgID:$msgid:ASMTP:$asmtp:SUBJECT:$subject:\n";

		if ($user =~ /@/) { 
			$site = (split(/@/, $user))[1];
		}
		elsif ($user =~ /\+/) {
		#	print "1. user = $user, site = $site\n";
			$site = (split(/\+/, $user))[1];
		#	print "2. user = $user, site = $site\n";
		}
		else { 
			$site = $user;
		}
		#print "3. user = $user, site = $site\n";

		if ($site !~ /\./) {
			# we have a straight up username and need to append myzen
			$site .= ".myzen.co.uk";
		#	print "4. site = $site\n";
		}

		#print "5. $msgid asmtp = $asmtp\n";
		#print "6. $msgid user = $user\n";
		#print "7. $msgid site = $site\n";
		#print "8. $msgid rcpts = $norcpts\n";

		if ($norcpts > $threshold)
		{
			if ($except{$site}) {
				# we won't ban this one
				print "ASMTP (EXEMPT): $date $time $msgid\tRcpts: $norcpts\tSite: $site Subject: $subject\n" if $verbose;
			}
			else {
				print "ASMTP: $date $time $msgid\tRcpts: $norcpts\tSite: $site Subject: $subject\n" if $verbose;
				$dodgydomains{$site} += $norcpts;
				$junkids{$site}{$msgid}++;
			}
		}
	}
}
close(LOGFILE);

if ($verbose) { 
	$report .= "\n=============== Actions Taken ==================\n"; 
}

foreach my $domain (keys %dodgydomains)
{
	my $msgscleaned = 0;

	unless (/82\.71\.204/)
	{
		#print "site: $domain total recipients: $dodgydomains{$domain}\n";
		if ($do_suspend)
		{
			my $suspend_return = suspend_domain($domain);
			if ($suspend_return =~ /^OK:/)
			{
				foreach my $msgid (keys %{$junkids{$domain}})
				{
					$msgscleaned++;
					if ($verbose)
					{
						$report .= `/usr/sbin/exim -Mrm $msgid`;
					}
					else
					{
						`/usr/sbin/exim -Mrm $msgid 2>&1 > /dev/null`;
					}
				}
				$report .= "SUSPENDED Site: $domain (Rcpts: $dodgydomains{$domain}, Msgs removed: $msgscleaned)\n";
				$report_exists++;
			}
			elsif ($suspend_return =~ / Account is already suspended/)
			{
				$report .= "ALREADY SUSPENDED Site: $domain (Rcpts: $dodgydomains{$domain}, Msgs removed: $msgscleaned)\n" if $verbose;
				$report_exists++ if $verbose;
			}
			else
			{
				$report .= "SUSPEND FAILED Site: $domain (Rcpts: $dodgydomains{$domain}, Msgs removed: $msgscleaned)\n";
				$report_exists++;
			}
		}
		else
		{
			$report .= "NOT SUSPENDED Site: $domain (Rcpts: $dodgydomains{$domain}, Msgs removed: $msgscleaned)\n" if (!$do_suspend);
			$report_exists++ if (!$do_suspend);
		}
	}
}

if (($do_report || $verbose) && $report_exists)
{
	print "$report\n";
	system("echo '$report' | $email '$title' $report_to");
}

sub suspend_domain($)
{
	my $dodgy_domain = shift;

	my $return_string = SOAP::Lite
		-> uri('http://127.0.0.1:8/CPanelManagement/')
		-> proxy('http://127.0.0.1:8/')
		-> suspendDomain($dodgy_domain)
		-> result;

	return($return_string);
}

