#!/usr/bin/perl -w

# Copyright (C) 2009-2016 Daniel Berteaud <daniel@firewall-services.com>

# This file is part of smeserver-zabbix-agent package.

# This script is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.

# This script is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.

# You should have received a copy of the GNU General Public License
# along with Foobar; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

# This script parse qpsmtpd logs (which must be sent to STDIN), and count the number
# of emails rejected by each plugins, and those accepted. You need to logterse plugin enabled

my $what = $ARGV[0] || '';

# This is the list of plugins we can get stats for
# you can set the regex used to identify a line in the logs
my %denied = (
  dnsbl               => qr{dnsbl\s+90},
  rhsbl               => qr{rhsbl\s+90},
  uribl               => qr{uribl\s+90},
  clamav              => qr{virus::clam(av|dscan)\s+90},
  check_earlytalker   => qr{(check_)?earlytalker\s+90},
  check_basicheaders  => qr{(check_basic)?headers\s+90},
  check_goodrcptto    => qr{(check_)?goodrcptto\s+90},
  check_spamhelo      => qr{(check_)?spamhelo\s+90},
  fcrdns              => qr{fcrdns\s+90},
  karma               => qr{karma\s+90},
  spf                 => qr{sender_permitted_from\s+90},
  tls_failed          => qr{tls\s+90},
  resolvable_fromhost => qr{(require_)?resolvable_fromhost}
);

my @others = qw(total_denied spam_denied other_denied spam_queued queued total);
my %cnt;
foreach (keys %denied, @others){
    $cnt{$_} = 0;
}

while (<STDIN>) {
    my $line = $_;

    # We only want logterse lines like
    #    @400000004994ad092afa867c 18386 logging::logterse plugin:
    # The format can slightly change depending on qpsmtpd version
    next unless $line =~ m/^\@[0-9a-f]{24} \d+( \((queue|deny)\))? logging::logterse/;

    # Lets count all the message which have been denied 'msg denied before queued'
    if ($line =~ m/msg denied before queued/){
        $cnt{total_denied}++;
        # Now try to find the plugin responsible for the deny
        foreach (keys %denied){
            if ($line =~ m/$denied{$_}/){
                $cnt{$_}++;
            }
        }
        next;
    }

    # Rejected by spamassassin because spam score is too high
    elsif ($line =~ m/spam score exceeded threshold/){
        $cnt{spam_denied}++;
        next;
    }

    # Tagged as spam, but kept accepted
    elsif ($line =~ m/queued\s+<.*>\s+Yes,\s+(score|hits)=/){
        $cnt{spam_queued}++;
        next;
    }

    # Queued, not tagged as spam, those are the clean emails
    elsif ($line =~ m/queued\s+<.*>\s+No,\s+(score|hits)=/){
        $cnt{queued}++;
        next;
    }
}

# Now lets count other_denied, which is total_denied minus
# all the known plugins denied
$cnt{other_denied} = $cnt{total_denied};
foreach (keys %denied){
    $cnt{total} = $cnt{total} + $cnt{$_};
    $cnt{other_denied} = $cnt{other_denied} - $cnt{$_};
}
foreach (@others){
    $cnt{total} = $cnt{total} + $cnt{$_} if ($_ !~ /total/);
}

# The print argument prints all on stdout
if ($what eq "print"){
    foreach (keys %denied,@others){
        print "$_: $cnt{$_}\n";
    }
}

# If the arg is a known plugin, prints only its value
elsif (defined $cnt{$what}){
    print "$cnt{$what}\n";
}

# Else, print an error
else{
    print "supported items are: ";
    foreach (keys %denied, @others){
        print "$_ ";
    }
    print "\n";
    exit 1;
}
exit 0;
