sendmailanalyzer/sa_cache

5454 lines
182 KiB
Perl
Executable file
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env perl
#
# SendmailAnalyzer: maillog parser and statistics reports tool for Sendmail
# Copyright (C) 2002-2020 Gilles Darold
#
# This program 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 3 of the License, or
# any later version.
#
# This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
#
use vars qw($VERSION $AUTHOR $COPYRIGHT);
use strict;
no strict qw/refs/;
use CGI;
use Benchmark;
use Getopt::Long;
use POSIX qw / strftime :sys_wait_h /;
use Time::Local 'timelocal_nocheck';
$VERSION = '9.4';
$AUTHOR = "Gilles Darold <gilles\@darold.net>";
$COPYRIGHT = "(c) 2002-2020 - Gilles Darold <gilles\@darold.net>";
# Configuration storage hash
my %CONFIG = ();
# Other configuration directives
my $CONFIG_FILE = "/usr/local/sendmailanalyzer/sendmailanalyzer.conf";
my $DEF_CONF = $CONFIG_FILE;
my $CACHE_DATE = '';
my $HOST = '';
my $HELP = '';
my $DAYCACHE = 0;
my $PID_FILE = 'sa_cache.pid';
# Die on kill -2, -3 or -15
$SIG{'INT'} = $SIG{'QUIT'} = $SIG{'TERM'} = 'terminate';
our %ANTISPAM_NAME = (
'spamdmilter' => 'Spamd-Milter',
'jchkmail' => 'J-ChkMail',
'dnsbl' => 'RBL Check',
'spamassassin' => 'SpamAssassin',
'amavis' => 'Amavis',
'mimedefang' => 'MIMEDefang',
'dnsblmilter' => 'DNSBL-Milter',
'spamd' => 'Spamd',
'policydweight' => 'Policyd-weight',
);
# Collect command line arguments
GetOptions (
'config|c=s' => \$CONFIG_FILE,
'date|d=s' => \$CACHE_DATE,
'syslog|s=s' => \$HOST,
'help|h' => \$HELP,
'actual-day-only|a' => \$DAYCACHE,
);
&usage() if ($HELP);
if ($CACHE_DATE && ($CACHE_DATE !~ /^\d{4}\/\d{2}$/)) {
&usage();
}
sub usage
{
print "Usage: sa_cache [-s hostname] [-c conf_file] [-d yyyy/mm]\n\n";
print "This script generate cache statistics for past months and year until now.\n";
print "Using the --actual-day-only will compute statstics for the current day only\n";
print " -c | --config file => Path to sendmailanalyzer configuration file.\n";
print " Default: $CONFIG_FILE\n";
print " -d | --date \"yyyy/mm\" => year/month cache to proceed. Default is all month/year.\n";
print " -h | --help => Show this message.\n";
print " -s | --syslog hostname => syslog name of the host to proceed. Default all.\n\n";
print " -a | --actual-day-only => Proceed only the current day, this option replace the old\n";
print " and obsolete day_cache script. You still have to run it often like each five minutes.\n\n";
exit 0;
}
# Global variable to store temporary parsed data
my $t0 = new Benchmark;
# Read configuration file
&read_config($CONFIG_FILE);
# Check if output dir exist
if (!-d $CONFIG{OUT_DIR}) {
die "FATAL: Output directory $CONFIG{OUT_DIR} should exists !\n";
}
my $cgi = new CGI;
# Add global caching
push(@{$CONFIG{DOMAIN_REPORT}}, '');
# Check if we have a SQL-host configured for virtual domains
if ( $CONFIG{VIRTUAL_DOMAIN_DB} && $CONFIG{VIRTUAL_DOMAIN_DB_QUERY} ) {
eval("use DBI;");
my $dbh = DBI->connect(
$CONFIG{VIRTUAL_DOMAIN_DB},
$CONFIG{VIRTUAL_DOMAIN_DB_USER},
$CONFIG{VIRTUAL_DOMAIN_DB_PASS},
) or die "Couldn't connect to database: " . DBI->errstr;
# Get all virtual domains and stores them in $CONFIG{LOCAL_DOMAIN} array
my $sth = $dbh->prepare( $CONFIG{VIRTUAL_DOMAIN_DB_QUERY} );
$sth->execute();
while (my @row = $sth->fetchrow_array) {
push(@{ $CONFIG{LOCAL_DOMAIN} }, $row[0]);
}
$sth->finish();
$dbh->disconnect() if (defined $dbh);
}
my $UNIQID = 0;
if (-e "$CONFIG{PID_DIR}/$PID_FILE") {
logerror("pid file $CONFIG{PID_DIR}/$PID_FILE exists, maybe sa_cache is already running.\n");
exit 0;
} else {
if (not open(OUT, ">$CONFIG{PID_DIR}/$PID_FILE")) {
logerror("Can't create pid file $CONFIG{PID_DIR}/$PID_FILE\n");
exit 0;
} else {
print OUT "$$";
close(OUT);
}
}
# Try to find syslog hosts
if (not opendir(DIR, "$CONFIG{OUT_DIR}/")) {
logerror("Can't open directory $CONFIG{OUT_DIR}: $!\n");
return;
}
my @sysloghost = grep { !/^(data|lang|[\.]+)$/ && -d "$CONFIG{OUT_DIR}/$_" } readdir(DIR);
closedir(DIR);
foreach my $h (@sysloghost) {
next if ($HOST && ($h ne $HOST));
$UNIQID = 0;
# Dump daily statistics
&cache_stat($cgi, $h);
}
# Show total run time
my $t1 = new Benchmark;
my $td = timediff($t1, $t0);
print "Cache generation took:",timestr($td),"\n";
unlink("$CONFIG{PID_DIR}/$PID_FILE");
exit 0;
#-------------------------------- ROUTINES ------------------------------------
####
# Routine used to log sendmailanalyzer errors or send emails alert if requested
####
sub logerror
{
my $str = shift;
print STDERR "ERROR: $str\n";
}
####
# Read configuration file
####
sub read_config
{
my $file = shift;
if (!-e $file) {
$file = '/etc/sendmailanalyzer.conf';
}
if (!-e $file) {
die "FATAL: Configuration file $file doesn't exists !\n";
} else {
if (not open(IN, $file)) {
die "FATAL: Can't read configuration file $file: $!\n";
} else {
while (<IN>) {
chomp;
s/#.*//;
s/^[\s\t]+//;
s/[\s\t]$//;
if ($_ ne '') {
my ($var, $val) = split(/[\s\t]+/, $_, 2);
if ($var =~ /DOMAIN_USER/i) {
my ($usr, @doms) = split(/[\t,;\s]+/, $val);
push(@{$CONFIG{DOMAIN_USER}{$usr}}, @doms);
} elsif ($var =~ /DOMAIN_HOST_REPORT/i) {
my ($hst, @doms) = split(/[\t,;\s]/, $val);
push(@{$CONFIG{DOMAIN_HOST_REPORT}{$hst}}, @doms);
} elsif ($var =~ /DOMAIN_REPORT/i) {
push(@{$CONFIG{DOMAIN_REPORT}}, split(/[\t,;\s]/, $val));
} elsif ($var =~ /LOCAL_DOMAIN/i) {
if (-e $val) {
if (open(my $in, '<', $val)) {
@{$CONFIG{LOCAL_DOMAIN}} = <$in>;
chomp(@{$CONFIG{LOCAL_DOMAIN}});
close($in);
} else {
&logerror("LOCAL_DOMAIN file $val can not be read, $!");
}
} else {
push(@{$CONFIG{LOCAL_DOMAIN}}, split(/[\t,;\s]/, $val));
}
} elsif ($var =~ /LOCAL_HOST_DOMAIN/i) {
my ($hst, @doms) = split(/[\t,;\s]/, $val);
if ($#doms == 0 && -e $doms[0]) {
if (open(my $in, '<', $doms[0])) {
@{$CONFIG{LOCAL_HOST_DOMAIN}{$hst}} = <$in>;
chomp(@{$CONFIG{LOCAL_HOST_DOMAIN}{$hst}});
close($in);
} else {
&logerror("LOCAL_DOMAIN file $doms[0] can not be read, $!");
}
} else {
push(@{$CONFIG{LOCAL_HOST_DOMAIN}{$hst}}, @doms);
}
} else {
$CONFIG{$var} = $val if (!defined $CONFIG{$var} && ($val ne ''));
}
}
}
close(IN);
}
}
# Set default values
$CONFIG{OUT_DIR} ||= '/var/www/htdocs/sendmailanalyzer';
$CONFIG{TOP} ||= 25;
$CONFIG{MAIL_HUB} ||= '';
$CONFIG{MAIL_GW} ||= '';
$CONFIG{PID_DIR} ||= $CONFIG{PID_FILE};
$CONFIG{LANG} ||= 'lang/en_US';
if (!exists $CONFIG{SPAM_DETAIL}) {
$CONFIG{SPAM_DETAIL} = 1;
}
$CONFIG{WEEKLY_FREE_SPACE} ||= 0;
}
our %topsender = ();
our %toprcpt = ();
our %topspam = ();
our %topvirus = ();
our %topdsn = ();
our %topreject = ();
our %toperr = ();
our %topmaxrcpt = ();
our %topmaxsize = ();
our %delivery = ();
our %messaging = ();
our %spam = ();
our %dsn = ();
our %virus = ();
our %reject = ();
our %err = ();
our %GLOBAL_STATUS = ();
our %topspamdetail = ();
our %auth = ();
our %topauth = ();
our %postgrey = ();
our %toppostgrey = ();
our %starttls = ();
our %spf_dkim = ();
####
# Cache statistic for the given date
####
sub cache_stat
{
my ($q, $hostname) = @_;
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
$mon++;
$year += 1900;
my $currentday = $year . sprintf("%02d",$mon) . sprintf("%02d",$mday);
my $currentmonth = $year . sprintf("%02d",$mon);
# Lookup years directories for a given host
opendir(DIR, "$CONFIG{OUT_DIR}/$hostname") || die "can't opendir $CONFIG{OUT_DIR}/$hostname: $!";
my @ydirs = grep { /^\d+$/ && -d "$CONFIG{OUT_DIR}/$hostname/$_" } readdir(DIR);
closedir DIR;
foreach my $y (sort {$a <=> $b } @ydirs) {
next if ($DAYCACHE && ($y ne $year));
print "Checking directory: $CONFIG{OUT_DIR}/$hostname/$y\n" if ($CONFIG{DEBUG});
# Lookup months directories for the current host/year
opendir(DIR, "$CONFIG{OUT_DIR}/$hostname/$y") || die "can't opendir $CONFIG{OUT_DIR}/$hostname/$y: $!";
my @mdirs = grep { /^\d+$/ && -d "$CONFIG{OUT_DIR}/$hostname/$y/$_" } readdir(DIR);
closedir DIR;
foreach my $m (sort {$a <=> $b } @mdirs) {
next if ($DAYCACHE && ("$y$m" ne $currentmonth));
next if ($CACHE_DATE && ($CACHE_DATE ne "$y/$m"));
print "\t$CONFIG{OUT_DIR}/$hostname/$y/$m\n" if ($CONFIG{DEBUG});
# Lookup days directories for the current host/year/month
opendir(DIR, "$CONFIG{OUT_DIR}/$hostname/$y/$m") || die "can't opendir $CONFIG{OUT_DIR}/$hostname/$y/$m: $!";
my @ddirs = grep { /^\d+$/ && -d "$CONFIG{OUT_DIR}/$hostname/$y/$m/$_" } readdir(DIR);
closedir DIR;
foreach my $d (sort {$a <=> $b } @ddirs) {
last if (!$DAYCACHE && ("$y$m$d" eq "$currentday"));
next if ($DAYCACHE && ("$y$m$d" ne "$currentday"));
print "\t\t$CONFIG{OUT_DIR}/$hostname/$y/$m/$d\n" if ($CONFIG{DEBUG});
&do_hour_cache($hostname,$y,$m,$d,$currentday, $hour);
foreach my $DOMAIN (@{$CONFIG{DOMAIN_REPORT}}) {
&do_day_cache($hostname,$DOMAIN,$y,$m,$d,$currentday);
}
foreach my $DOMAIN (@{$CONFIG{DOMAIN_HOST_REPORT}{$hostname}}) {
&do_day_cache($hostname,$DOMAIN,$y,$m,$d,$currentday);
}
}
foreach my $DOMAIN (@{$CONFIG{DOMAIN_REPORT}}) {
&do_month_cache($hostname,$DOMAIN,$y,$m,$currentmonth);
}
foreach my $DOMAIN (@{$CONFIG{DOMAIN_HOST_REPORT}{$hostname}}) {
&do_month_cache($hostname,$DOMAIN,$y,$m,$currentmonth);
}
}
# Build years cache
foreach my $DOMAIN (@{$CONFIG{DOMAIN_REPORT}}) {
&do_year_cache($hostname,$DOMAIN,$y,$year);
}
foreach my $DOMAIN (@{$CONFIG{DOMAIN_HOST_REPORT}{$hostname}}) {
&do_year_cache($hostname,$DOMAIN,$y,$year);
}
# Build weeks cache
my $curweek = POSIX::strftime("%W", gmtime time);
foreach my $week ("00" .. "53") {
last if ( ($y eq $year) && ($week > $curweek));
foreach my $DOMAIN (@{$CONFIG{DOMAIN_REPORT}}) {
&do_week_cache($hostname,$DOMAIN,$y,$year,$week,$curweek);
}
foreach my $DOMAIN (@{$CONFIG{DOMAIN_HOST_REPORT}{$hostname}}) {
&do_week_cache($hostname,$DOMAIN,$y,$year,$week,$curweek);
}
}
}
}
####
# Get week number
####
sub get_week_number
{
my ($year, $month, $day) = @_;
# Check if the date is valide first
my $datefmt = POSIX::strftime("%F", 1, 1, 1, $day, $month - 1, $year - 1900);
if ($datefmt ne "$year-$month-$day") {
return -1;
}
my $weekNumber = POSIX::strftime("%W", 1, 1, 1, $day, $month - 1, $year - 1900);
return $weekNumber;
}
####
# Hour cache statistics
####
sub do_hour_cache
{
my ($hostname, $year, $month, $day, $curday, $curhour) = @_;
# Do not proceed the current day this is the work of day_cache option
return if (!$DAYCACHE && ("$year$month$day" eq "$curday"));
my @data = ();
# Remove the file flag and all cache files generated by day_cache option
if (!$DAYCACHE) {
if (-e "$CONFIG{OUT_DIR}/$hostname/$year/$month/$day/flag") {
unlink("$CONFIG{OUT_DIR}/$hostname/$year/$month/$day/flag");
`rm -f $CONFIG{OUT_DIR}/$hostname/$year/$month/$day/*cache.pm*`;
}
return if (-e "$CONFIG{OUT_DIR}/$hostname/$year/$month/$day/cache.pm");
} else {
# remove cache file for the current hour and previous one for the current day
`rm -f $CONFIG{OUT_DIR}/$hostname/$year/$month/$day/${curhour}cache.pm*`;
$curhour--;
if ($curhour >= 0) {
$curhour = sprintf("%02d",$curhour);
`rm -f $CONFIG{OUT_DIR}/$hostname/$year/$month/$day/${curhour}cache.pm*`;
}
`rm -f $CONFIG{OUT_DIR}/$hostname/$year/$month/$day/cache.pm*`;
}
print "Reading hourly statistics from $CONFIG{OUT_DIR}/$hostname/$year/$month/$day/\n" if ($CONFIG{DEBUG});
my $begin = "00";
my $end = "23";
if ($DAYCACHE) {
$end = sprintf("%02d", $curhour+1);
}
foreach my $hour ("$begin" .. "$end") {
next if (-e "$CONFIG{OUT_DIR}/$hostname/$year/$month/$day/${hour}cache.pm");
my %localstat = ();
my %localglobstat = ();
my %sourceid = ();
my $file = "$CONFIG{OUT_DIR}/$hostname/$year/$month/$day/dsn.dat";
if (open(IN, $file)) {
my @done = ();
while (my $l = <IN>) {
chomp($l);
# Format: Hour:Id:SourceId:Status
@data = split(/:/, $l, 4);
$data[0] =~ /^(\d{2})/;
next if ($1 ne $hour);
$localstat{$data[1]}{idx_dsn} = "$1";
$localstat{$data[1]}{hour} = $data[0] if (!exists $localstat{$data[1]}{hour});
$localstat{$data[1]}{srcid} = $data[2];
$localstat{$data[1]}{dsnstatus} = $data[3];
$sourceid{$data[2]} = $data[1];
}
close(IN);
}
$file = "$CONFIG{OUT_DIR}/$hostname/$year/$month/$day/senders.dat";
if (open(IN, $file)) {
while (my $l = <IN>) {
chomp($l);
# Format: Hour:Id:Sender:Size:Nrcpts:Relay:Subject
@data = split(/:/, $l);
$data[0] =~ /^(\d{2})/;
next if ($1 ne $hour);
$data[5] = &clean_relay($data[5]);
$localstat{$data[1]}{idx_sender} = "$1";
$localstat{$data[1]}{hour} = $data[0];
$data[2] ||= '<>';
$localstat{$data[1]}{sender} = $data[2];
$localstat{$data[1]}{size} = $data[3];
$localstat{$data[1]}{nrcpt} = $data[4];
$localstat{$data[1]}{sender_relay} = $data[5];
if (exists $sourceid{$data[1]}) {
$localstat{TOPDSN}{$sourceid{$data[1]}}{sender} = $data[2];
$localstat{TOPDSN}{$sourceid{$data[1]}}{sender_relay} = $data[5];
}
for (my $i = 6; $i <= $#data; $i++) {
$localstat{$data[1]}{subject} .= ($i > 6) ? ':' : '';
$localstat{$data[1]}{subject} .= $data[$i];
}
}
close(IN);
}
$file = "$CONFIG{OUT_DIR}/$hostname/$year/$month/$day/recipient.dat";
if (open(IN, $file)) {
while (my $l = <IN>) {
chomp($l);
# Format: Hour:Id:recipient:Relay:Status
@data = split(/:/, $l);
$data[0] =~ /^(\d{2})/;
next if ($1 ne $hour);
$data[3] = &clean_relay($data[3]);
$localstat{$data[1]}{idx_rcpt} = "$1";
push(@{$localstat{$data[1]}{rcpt}}, $data[2]);
push(@{$localstat{$data[1]}{hour}}, $data[0]);
push(@{$localstat{$data[1]}{rcpt_relay}}, $data[3]);
push(@{$localstat{$data[1]}{status}}, $data[4]);
if (exists $sourceid{$data[1]} && ($data[4] ne 'Sent')) {
push(@{$localstat{TOPDSN}{$sourceid{$data[1]}}{rcpt}}, $data[2]);
}
}
close(IN);
}
%sourceid = ();
$file = "$CONFIG{OUT_DIR}/$hostname/$year/$month/$day/rejected.dat";
if (open(IN, $file)) {
while (my $l = <IN>) {
chomp($l);
# Format: Hour:Id:Rule:Relay:Arg1:Status
@data = split(/:/, $l);
$data[0] =~ /^(\d{2})/;
next if ($1 ne $hour);
$data[3] = &clean_relay($data[3]);
$localstat{$data[1]}{idx_reject} = "$1";
$localstat{$data[1]}{rule} = $data[2];
$localstat{$data[1]}{hour} = $data[0] if (!exists $localstat{$data[1]}{hour});
$localstat{$data[1]}{sender_relay} = $data[3] if (!$localstat{$data[1]}{sender_relay});
if ($#data > 4) {
if ($data[2] eq 'check_relay') {
$localstat{$data[1]}{sender_relay} = $data[4];
} elsif ($data[2] eq 'check_rcpt') {
push(@{$localstat{$data[1]}{chck_rcpt}}, $data[4]);
} elsif ($data[5] eq 'postscreen reject' && $data[4] ne '') {
$data[5] .= " (score: $data[4])";
} else {
# $data[2] eq 'check_mail' or POSTFIX
$localstat{$data[1]}{sender} = $data[4];
}
push(@{$localstat{$data[1]}{chck_status}}, $data[5]);
} else {
push(@{$localstat{$data[1]}{chck_status}}, $data[4]);
}
}
close(IN);
}
$file = "$CONFIG{OUT_DIR}/$hostname/$year/$month/$day/spam.dat";
if (open(IN, $file)) {
while (my $l = <IN>) {
chomp($l);
# Format: Hour:Id:From:To:Spam
@data = split(/:/, $l, 5);
$data[0] =~ /^(\d{2})/;
next if ($1 ne $hour);
$localstat{$data[1]}{idx_spam} = "$1";
$localstat{$data[1]}{hour} = $data[0] if (!exists $localstat{$data[1]}{hour});
$localstat{$data[1]}{sender} = $data[2] if (!exists $localstat{$data[1]}{sender});
foreach my $a (split(/,/, $data[3])) {
if (!grep(/^$a$/i, @{$localstat{$data[1]}{rcpt}})) {
push(@{$localstat{$data[1]}{rcpt}}, $a);
}
}
$localstat{$data[1]}{spam} = $data[4];
}
close(IN);
}
$file = "$CONFIG{OUT_DIR}/$hostname/$year/$month/$day/virus.dat";
if (open(IN, $file)) {
my @done = ();
while (my $l = <IN>) {
chomp($l);
# Format: Hour:Id:file:virus
@data = split(/:/, $l, 4);
$data[0] =~ /^(\d{2})/;
next if ($1 ne $hour);
$localstat{$data[1]}{idx_virus} = "$1";
$localstat{$data[1]}{hour} = $data[0] if (!exists $localstat{$data[1]}{hour});
$localstat{$data[1]}{file} = $data[2];
$localstat{$data[1]}{virus} = $data[3];
}
close(IN);
}
$file = "$CONFIG{OUT_DIR}/$hostname/$year/$month/$day/syserr.dat";
if (open(IN, $file)) {
while (my $l = <IN>) {
chomp($l);
# Format: Hour:Id:Message
@data = split(/:/, $l);
$data[0] =~ /^(\d{2})/;
next if ($1 ne $hour);
$localstat{$data[1]}{idx_syserr} = "$1";
$localstat{$data[1]}{hour} = $data[0] if (!exists $localstat{$data[1]}{hour});
shift(@data);
my $id = shift(@data);
$localstat{$id}{error} = join(':', @data);
}
close(IN);
}
$file = "$CONFIG{OUT_DIR}/$hostname/$year/$month/$day/other.dat";
if (open(IN, $file)) {
while (my $l = <IN>) {
chomp($l);
# Format: Hour:Message
@data = split(/:/, $l);
my $hms = shift(@data);
$hms =~ /^(\d{2})/;
next if ($1 ne $hour);
next if (&clear_postfix(join(':', @data)));
$localstat{$UNIQID}{idx_other} = "$1";
$localstat{$UNIQID}{hour} = $hms;
$localstat{$UNIQID}{error} = join(':', @data);
$UNIQID++;
}
close(IN);
}
$file = "$CONFIG{OUT_DIR}/$hostname/$year/$month/$day/starttls.dat";
if (open(IN, $file)) {
while (my $l = <IN>) {
chomp($l);
# Format: Hour:FAIL=count;NO=count,OK=count
@data = split(/:/, $l, 2);
my $hms = shift(@data);
$hms =~ /^(\d{2})/;
next if ($1 ne $hour);
my %verify = split(/[=;]/, $data[0]);
foreach my $v (keys %verify) {
$localstat{STARTTLS}{$v} += $verify{$v};
}
}
close(IN);
}
$file = "$CONFIG{OUT_DIR}/$hostname/$year/$month/$day/postgrey.dat";
if (open(IN, $file)) {
while (my $l = <IN>) {
chomp($l);
# Format: Hour:Id:Relay:From:To:Action:Reason
@data = split(/:/, $l);
$data[0] =~ /^(\d{2})/;
next if ($1 ne $hour);
$data[2] = &clean_relay($data[2]);
$localstat{$data[1]}{idx_postgrey} = "$1";
$localstat{$data[1]}{hour} = $data[0] if (!exists $localstat{$data[1]}{hour});
$localstat{$data[1]}{sender_relay} = $data[2];
$localstat{$data[1]}{sender} = $data[3];
push(@{$localstat{$data[1]}{rcpt}}, $data[4]);
$localstat{$data[1]}{action} = $data[5];
$localstat{$data[1]}{reason} = $data[6];
}
close(IN);
}
$file = "$CONFIG{OUT_DIR}/$hostname/$year/$month/$day/spf_dkim.dat";
if (open(IN, $file)) {
while (my $l = <IN>) {
chomp($l);
# Format: Hour:Id:Type:Rule:Domain:Status
@data = split(/:/, $l);
$data[0] =~ /^(\d{2})/;
next if ($1 ne $hour);
if ($data[2] eq 'spf') {
$localstat{$data[1]}{$data[2]}{$data[3]}{hour} = $data[0] if (!exists $localstat{$data[1]}{$data[2]}{$data[3]}{hour});
#$localstat{$data[1]}{$data[2]}{$data[3]}{domain}{$data[4]}++;
$localstat{$data[1]}{$data[2]}{$data[3]}{status}{$data[5]}++;
} elsif ($data[2] eq 'dkim') {
$localstat{$data[1]}{$data[2]}{hour} = $data[0] if (!exists $localstat{$data[1]}{$data[2]}{hour});
#$localstat{$data[1]}{$data[2]}{domain}{$data[4]}++;
$localstat{$data[1]}{$data[2]}{status}{$data[5]}++;
}
}
close(IN);
}
for my $typ (sort keys %ANTISPAM_NAME) {
$file = "$CONFIG{OUT_DIR}/$hostname/$year/$month/$day/$typ.dat";
if (open(IN, $file)) {
while (my $l = <IN>) {
chomp($l);
# Format: Hour:Id:type:score:cache:autolearn:spam
@data = split(/:/, $l, 7);
$data[0] =~ /^(\d{2})/;
next if ($1 ne $hour);
$localstat{$data[1]}{idx_spamd} = "$1";
$localstat{$data[1]}{hour} = $data[0] if (!exists $localstat{$data[1]}{hour});
$localstat{$data[1]}{spamtype} = $data[2];
$localstat{$data[1]}{score} = $data[3];
$localstat{$data[1]}{cache} = $data[4];
$localstat{$data[1]}{autolearn} = $data[5];
$localstat{$data[1]}{spamdetail} = $data[6];
}
close(IN);
}
}
$file = "$CONFIG{OUT_DIR}/$hostname/$year/$month/$day/auth.dat";
if (open(IN, $file)) {
while (my $l = <IN>) {
chomp($l);
# Format: Hour:Id:Relay:Mech:Type
@data = split(/:/, $l);
$data[0] =~ /^(\d{2})(\d{2})/;
next if ($1 ne $hour);
$data[2] = &clean_relay($data[2]);
push(@{$localstat{$data[1]}{idx_auth}}, "$1");
push(@{$localstat{$data[1]}{auth_hour}}, $data[0]);
push(@{$localstat{$data[1]}{auth_relay}}, $data[2]);
push(@{$localstat{$data[1]}{auth_mech}}, $data[3]);
push(@{$localstat{$data[1]}{auth_type}}, $data[4]);
}
close(IN);
}
foreach my $DOMAIN (@{$CONFIG{DOMAIN_REPORT}}) {
$file = "$CONFIG{OUT_DIR}/$hostname/$year/$month/$day/${hour}cache.pm\U$DOMAIN\E";
print "Writing cache file: $file\n" if ($CONFIG{DEBUG});
&clean_globals();
&compute_top_stats($file, $DOMAIN, \%localstat);
&compute_global_stats($file, $DOMAIN, \%localstat, '00', '60', 'Minutes of the hour', $hostname);
}
foreach my $DOMAIN (@{$CONFIG{DOMAIN_HOST_REPORT}{$hostname}}) {
$file = "$CONFIG{OUT_DIR}/$hostname/$year/$month/$day/${hour}cache.pm\U$DOMAIN\E";
print "Writing cache file: $file\n" if ($CONFIG{DEBUG});
&clean_globals();
&compute_top_stats($file, $DOMAIN, \%localstat);
&compute_global_stats($file, $DOMAIN, \%localstat, '00', '60', 'Minutes of the hour', $hostname);
}
}
}
sub clean_globals
{
%topsender = ();
%toprcpt = ();
%topspam = ();
%topvirus = ();
%topdsn = ();
%topreject = ();
%toperr = ();
%topmaxrcpt = ();
%topmaxsize = ();
%topspamdetail = ();
%topauth = ();
%toppostgrey = ();
%delivery = ();
%messaging = ();
%spam = ();
%virus = ();
%reject = ();
%err = ();
%dsn = ();
%auth = ();
%postgrey = ();
%starttls = ();
%GLOBAL_STATUS = ();
}
sub compute_top_stats
{
my ($file, $DOMAIN, $STATS) = @_;
if (open(OUT, ">$file")) {
foreach my $id (keys %$STATS) {
next if (($id eq 'TOPDSN') || ($id eq 'STARTTLS'));
next if ($DOMAIN && ($STATS->{$id}{sender} !~ /$DOMAIN/) && !grep(/$DOMAIN/, @{$STATS->{$id}{rcpt}}));
if ($STATS->{$id}{nrcpt} > $CONFIG{MAX_RCPT}) {
push(@{$topmaxrcpt{$STATS->{$id}{nrcpt}}{sender}}, $STATS->{$id}{sender});
push(@{$topmaxrcpt{$STATS->{$id}{nrcpt}}{sa_id}}, $id);
}
if ($STATS->{$id}{sender} && grep(/Sent/, @{$STATS->{$id}{status}})) {
my $sender = $STATS->{$id}{sender};
$topsender{email}{$sender}++;
my $dom = $sender || '';
$dom =~ s/^.*\@//;
$topsender{domain}{$dom}++;
$topsender{relay}{$STATS->{$id}{sender_relay}}++;
}
if ($STATS->{$id}{size} && $STATS->{$id}{nrcpt}) {
if ($STATS->{$id}{size} > $CONFIG{MAX_SIZE}) {
$topmaxsize{$id}{sender} = $STATS->{$id}{sender};
$topmaxsize{$id}{size} = $STATS->{$id}{size};
$topmaxsize{$id}{nrcpt} = $STATS->{$id}{nrcpt};
}
}
for (my $i = 0; $i <= $#{$STATS->{$id}{status}}; $i++) {
if ($STATS->{$id}{status}[$i] eq 'Sent') {
$toprcpt{email}{$STATS->{$id}{rcpt}[$i]}++;
my $dom = $STATS->{$id}{rcpt}[$i] || '<>';
$dom =~ s/^.*\@//;
$toprcpt{domain}{$dom}++;
$toprcpt{relay}{$STATS->{$id}{rcpt_relay}[$i]}++;
}
}
if (exists $STATS->{$id}{dsnstatus}) {
$topdsn{sender}{$STATS->{TOPDSN}{$id}{sender}}++;
$topdsn{relay}{$STATS->{TOPDSN}{$id}{sender_relay}}++;
$topdsn{dsnstatus}->{$STATS->{$id}{dsnstatus}}++;
for (my $i = 0; $i <= $#{$STATS->{TOPDSN}{$id}{rcpt}}; $i++) {
$topdsn{rcpt}{$STATS->{TOPDSN}{$id}{rcpt}[$i]}++;
}
}
if (exists $STATS->{$id}{spam}) {
$topspam{sender}{$STATS->{$id}{sender}}++;
my $dom = $STATS->{$id}{sender} || '<>';
$dom =~ s/^.*\@//;
$topspam{domain}{$dom}++;
$topspam{sender_relay}{$STATS->{$id}{sender_relay}}++;
$topspam{rule}{$STATS->{$id}{spam}}++;
for (my $i = 0; $i <= $#{$STATS->{$id}{rcpt}}; $i++) {
$topspam{rcpt}{$STATS->{$id}{rcpt}[$i]}++;
}
}
if (exists $STATS->{$id}{virus}) {
$topvirus{sender}{$STATS->{$id}{sender}}++;
$topvirus{relay}{$STATS->{$id}{sender_relay}}++;
$topvirus{file}{$STATS->{$id}{file}}++;
$topvirus{virus}{$STATS->{$id}{virus}}++;
for (my $i = 0; $i <= $#{$STATS->{$id}{status}}; $i++) {
$topvirus{rcpt}{$STATS->{$id}{rcpt}[$i]}++;
}
}
if (exists $STATS->{$id}{rule}) {
$topreject{sender}{$STATS->{$id}{sender}}++;
my $dom = $STATS->{$id}{sender} || '<>';
$dom =~ s/^.*\@//;
$topreject{domain}{$dom}++;
$topreject{relay}{$STATS->{$id}{sender_relay}}++;
$topreject{rule}{$STATS->{$id}{rule}}++;
for (my $i = 0; $i <= $#{$STATS->{$id}{chck_status}}; $i++) {
next if ($STATS->{$id}{chck_status}[$i] =~ /Queued/);
$topreject{chck_status}{$STATS->{$id}{chck_status}[$i]}++;
}
}
if (exists $STATS->{$id}{error}) {
$toperr{$STATS->{$id}{error}}++;
}
if (exists $STATS->{$id}{reason}) {
$toppostgrey{sender}{$STATS->{$id}{sender}}++;
$toppostgrey{sender_relay}{$STATS->{$id}{sender_relay}}++;
$STATS->{$id}{sender} =~ s/^.*\@//;
$STATS->{$id}{sender} ||= 'Unknown';
$toppostgrey{domain}{$STATS->{$id}{sender}}++;
for (my $i = 0; $i <= $#{$STATS->{$id}{rcpt}}; $i++) {
$toppostgrey{rcpt}{$STATS->{$id}{rcpt}[$i]}++;
}
$toppostgrey{reason}{$STATS->{$id}{reason}}++;
}
if (exists $STATS->{$id}{spamtype} && grep(/^$STATS->{$id}{spamtype}$/, keys %ANTISPAM_NAME)) {
$topspamdetail{$STATS->{$id}{spamtype}}{score}{$STATS->{$id}{score}}++ if ($STATS->{$id}{score});
$topspamdetail{$STATS->{$id}{spamtype}}{rule}{$STATS->{$id}{spamdetail}}++;
$topspamdetail{$STATS->{$id}{spamtype}}{cache}{$STATS->{$id}{cache}}++ if ($STATS->{$id}{cache});
$topspamdetail{$STATS->{$id}{spamtype}}{autolearn}{$STATS->{$id}{autolearn}}++ if ($STATS->{$id}{autolearn});
}
if (exists $STATS->{$id}{auth_relay}) {
$topauth{authid}{$id} += ($#{$STATS->{$id}{auth_relay}} + 1);
for (my $i = 0; $i <= $#{$STATS->{$id}{auth_relay}}; $i++) {
$topauth{relay}{$STATS->{$id}{auth_relay}[$i]}++;
$topauth{mech}{$STATS->{$id}{auth_mech}[$i]}++;
}
}
}
# Top SMTP Auth statistics
my $top = 0;
print OUT "\%::topauth = (\n";
print OUT "'relay' => {";
foreach my $d (sort { $topauth{relay}{$b} <=> $topauth{relay}{$a} } keys %{$topauth{relay}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$topauth{relay}{$d}',";
$top++;
}
print OUT "},\n";
delete $topauth{relay};
$top = 0;
print OUT "'mech' => {";
foreach my $d (sort { $topauth{mech}{$b} <=> $topauth{mech}{$a} } keys %{$topauth{mech}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$topauth{mech}{$d}',";
$top++;
}
print OUT "},\n";
delete $topauth{mech};
$top = 0;
print OUT "'authid' => {";
foreach my $d (sort { $topauth{authid}{$b} <=> $topauth{authid}{$a} } keys %{$topauth{authid}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$topauth{authid}{$d}',";
$top++;
}
print OUT "},\n";
print OUT ");\n\n";
%topauth = ();
# Top sender statistics
$top = 0;
print OUT "\%::topsender = (\n";
print OUT "'domain' => {";
foreach my $d (sort { $topsender{domain}{$b} <=> $topsender{domain}{$a} } keys %{$topsender{domain}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$topsender{domain}{$d}',";
$top++;
}
print OUT "},\n";
delete $topsender{domain};
$top = 0;
print OUT "'relay' => {";
foreach my $d (sort { $topsender{relay}{$b} <=> $topsender{relay}{$a} } keys %{$topsender{relay}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$topsender{relay}{$d}',";
$top++;
}
print OUT "},\n";
delete $topsender{relay};
$top = 0;
print OUT "'email' => {";
foreach my $d (sort { $topsender{email}{$b} <=> $topsender{email}{$a} } keys %{$topsender{email}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$topsender{email}{$d}',";
$top++;
}
print OUT "},\n";
print OUT ");\n\n";
%topsender = ();
# Top recipient statistics
$top = 0;
print OUT "\%::toprcpt = (\n";
print OUT "'domain' => {";
foreach my $d (sort { $toprcpt{domain}{$b} <=> $toprcpt{domain}{$a} } keys %{$toprcpt{domain}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$toprcpt{domain}{$d}',";
$top++;
}
print OUT "},\n";
delete $toprcpt{domain};
$top = 0;
print OUT "'relay' => {";
foreach my $d (sort { $toprcpt{relay}{$b} <=> $toprcpt{relay}{$a} } keys %{$toprcpt{relay}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$toprcpt{relay}{$d}',";
$top++;
}
print OUT "},\n";
delete $toprcpt{relay};
$top = 0;
print OUT "'email' => {";
foreach my $d (sort { $toprcpt{email}{$b} <=> $toprcpt{email}{$a} } keys %{$toprcpt{email}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$toprcpt{email}{$d}',";
$top++;
}
print OUT "},\n";
print OUT ");\n\n";
%toprcpt = ();
# Top rejection statistics
$top = 0;
print OUT "\%::topreject = (\n";
print OUT "'rule' => {";
foreach my $d (sort { $topreject{rule}{$b} <=> $topreject{rule}{$a} } keys %{$topreject{rule}}) {
last if ($top == $CONFIG{TOP});
my $c = $topreject{rule}{$d};
$d =~ s/'/\\'/g;
print OUT "'$d' => '$c',";
$top++;
}
print OUT "},\n";
delete $topreject{rule};
$top = 0;
print OUT "'domain' => {";
foreach my $d (sort { $topreject{domain}{$b} <=> $topreject{domain}{$a} } keys %{$topreject{domain}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$topreject{domain}{$d}',";
$top++;
}
print OUT "},\n";
delete $topreject{domain};
$top = 0;
print OUT "'relay' => {";
foreach my $d (sort { $topreject{relay}{$b} <=> $topreject{relay}{$a} } keys %{$topreject{relay}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$topreject{relay}{$d}',";
$top++;
}
print OUT "},\n";
delete $topreject{relay};
$top = 0;
print OUT "'chck_status' => {";
foreach my $d (sort { $topreject{chck_status}{$b} <=> $topreject{chck_status}{$a} } keys %{$topreject{chck_status}}) {
last if ($top == $CONFIG{TOP});
my $c = $topreject{chck_status}{$d};
$d =~ s/'/\\'/g;
print OUT "'$d' => '$c',";
$top++;
}
print OUT "},\n";
delete $topreject{chck_status};
$top = 0;
print OUT "'sender' => {";
foreach my $d (sort { $topreject{sender}{$b} <=> $topreject{sender}{$a} } keys %{$topreject{sender}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$topreject{sender}{$d}',";
$top++;
}
print OUT "},\n";
print OUT ");\n\n";
%topreject = ();
# Top virus statistics
$top = 0;
print OUT "\%::topvirus = (\n";
print OUT "'virus' => {";
foreach my $d (sort { $topvirus{virus}{$b} <=> $topvirus{virus}{$a} } keys %{$topvirus{virus}}) {
last if ($top == $CONFIG{TOP});
my $c = $topvirus{virus}{$d};
$d =~ s/'/\\'/g;
print OUT "'$d' => '$c',";
$top++;
}
print OUT "},\n";
delete $topvirus{virus};
$top = 0;
print OUT "'sender' => {";
foreach my $d (sort { $topvirus{sender}{$b} <=> $topvirus{sender}{$a} } keys %{$topvirus{sender}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$topvirus{sender}{$d}',";
$top++;
}
print OUT "},\n";
delete $topvirus{sender};
$top = 0;
print OUT "'relay' => {";
foreach my $d (sort { $topvirus{relay}{$b} <=> $topvirus{relay}{$a} } keys %{$topvirus{relay}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$topvirus{relay}{$d}',";
$top++;
}
print OUT "},\n";
delete $topvirus{relay};
$top = 0;
print OUT "'file' => {";
foreach my $d (sort { $topvirus{file}{$b} <=> $topvirus{file}{$a} } keys %{$topvirus{file}}) {
last if ($top == $CONFIG{TOP});
my $c = $topvirus{file}{$d};
$d =~ s/'/\\'/g;
print OUT "'$d' => '$c',";
$top++;
}
print OUT "},\n";
delete $topvirus{file};
$top = 0;
print OUT "'rcpt' => {";
foreach my $d (sort { $topvirus{rcpt}{$b} <=> $topvirus{rcpt}{$a} } keys %{$topvirus{rcpt}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$topvirus{rcpt}{$d}',";
$top++;
}
print OUT "},\n";
print OUT ");\n\n";
%topvirus = ();
# Top dsn statistics
$top = 0;
print OUT "\%::topdsn = (\n";
print OUT "'dsnstatus' => {";
foreach my $d (sort { $topdsn{dsnstatus}{$b} <=> $topdsn{dsnstatus}{$a} } keys %{$topdsn{dsnstatus}}) {
last if ($top == $CONFIG{TOP});
my $c = $topdsn{dsnstatus}{$d};
$d =~ s/'/\\'/g;
print OUT "'$d' => '$c',";
$top++;
}
print OUT "},\n";
delete $topdsn{dsnstatus};
$top = 0;
print OUT "'sender' => {";
foreach my $d (sort { $topdsn{sender}{$b} <=> $topdsn{sender}{$a} } keys %{$topdsn{sender}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$topdsn{sender}{$d}',";
$top++;
}
print OUT "},\n";
delete $topdsn{sender};
$top = 0;
print OUT "'relay' => {";
foreach my $d (sort { $topdsn{relay}{$b} <=> $topdsn{relay}{$a} } keys %{$topdsn{relay}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$topdsn{relay}{$d}',";
$top++;
}
print OUT "},\n";
delete $topdsn{relay};
$top = 0;
print OUT "'rcpt' => {";
foreach my $d (sort { $topdsn{rcpt}{$b} <=> $topdsn{rcpt}{$a} } keys %{$topdsn{rcpt}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$topdsn{rcpt}{$d}',";
$top++;
}
print OUT "},\n";
delete $topdsn{rcpt};
$top = 0;
print OUT ");\n\n";
%topdsn = ();
print OUT "\%::topmaxrcpt = (\n";
foreach my $nb (sort { $b <=> $a } keys %topmaxrcpt) {
print OUT "'$nb' => { 'sender' => [(";
for (my $i = 0; $i <= $#{$topmaxrcpt{$nb}{sender}}; $i++) {
print OUT "'$topmaxrcpt{$nb}{sender}[$i]',";
}
print OUT ")],";
print OUT "'sa_id' => [(";
for (my $i = 0; $i <= $#{$topmaxrcpt{$nb}{sa_id}}; $i++) {
print OUT "'$topmaxrcpt{$nb}{sa_id}[$i]',";
}
print OUT ")],";
print OUT "},";
}
print OUT ");\n\n";
print OUT "\%::topmaxsize = (\n";
foreach my $id (sort { $b <=> $a } keys %topmaxsize) {
print OUT "'$id' => { ";
print OUT "'sender' => '$topmaxsize{$id}{sender}',";
print OUT "'size' => '$topmaxsize{$id}{size}',";
print OUT "'nrcpt' => '$topmaxsize{$id}{nrcpt}'";
print OUT "},\n";
}
print OUT ");\n\n";
# Top spam statistics
$top = 0;
print OUT "\%::topspam = (\n";
print OUT "'rule' => {";
foreach my $d (sort { $topspam{rule}{$b} <=> $topspam{rule}{$a} } keys %{$topspam{rule}}) {
last if ($top == $CONFIG{TOP});
my $c = $topspam{rule}{$d};
$d =~ s/'/\\'/g;
print OUT "'$d' => '$c',";
$top++;
}
print OUT "},";
delete $topspam{rule};
$top = 0;
print OUT "'domain' => {";
foreach my $d (sort { $topspam{domain}{$b} <=> $topspam{domain}{$a} } keys %{$topspam{domain}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$topspam{domain}{$d}',";
$top++;
}
print OUT "},";
delete $topspam{domain};
$top = 0;
print OUT "'sender_relay' => {";
foreach my $d (sort { $topspam{sender_relay}{$b} <=> $topspam{sender_relay}{$a} } keys %{$topspam{sender_relay}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$topspam{sender_relay}{$d}',";
$top++;
}
print OUT "},";
delete $topspam{sender_relay};
$top = 0;
print OUT "'sender' => {";
foreach my $d (sort { $topspam{sender}{$b} <=> $topspam{sender}{$a} } keys %{$topspam{sender}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$topspam{sender}{$d}',";
$top++;
}
print OUT "},";
delete $topspam{sender};
$top = 0;
print OUT "'rcpt' => {";
foreach my $d (sort { $topspam{rcpt}{$b} <=> $topspam{rcpt}{$a} } keys %{$topspam{rcpt}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$topspam{rcpt}{$d}',";
$top++;
}
print OUT "},";
print OUT ");\n\n";
%topspam = ();
# Top spam detail statistics
$top = 0;
print OUT "\%::topspamdetail = (\n";
foreach my $t (sort keys %topspamdetail) {
print OUT "'$t' => {";
print OUT "'rule' => {";
foreach my $d (sort { $topspamdetail{$t}{rule}{$b} <=> $topspamdetail{$t}{rule}{$a} } keys %{$topspamdetail{$t}{rule}}) {
last if ($top == $CONFIG{TOP});
my $c = $topspamdetail{$t}{rule}{$d};
$d =~ s/'/\\'/g;
print OUT "'$d' => '$c',";
$top++;
}
print OUT "},";
delete $topspamdetail{$t}{rule};
$top = 0;
print OUT "'score' => {";
foreach my $d (sort { $topspamdetail{$t}{score}{$b} <=> $topspamdetail{$t}{score}{$a} } keys %{$topspamdetail{$t}{score}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$topspamdetail{$t}{score}{$d}',";
$top++;
}
print OUT "},";
delete $topspamdetail{$t}{score};
$top = 0;
print OUT "'cache' => {";
foreach my $d (sort { $topspamdetail{$t}{cache}{$b} <=> $topspamdetail{$t}{cache}{$a} } keys %{$topspamdetail{$t}{cache}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$topspamdetail{$t}{cache}{$d}',";
$top++;
}
print OUT "},";
delete $topspamdetail{$t}{cache};
$top = 0;
print OUT "'autolearn' => {";
foreach my $d (sort { $topspamdetail{$t}{autolearn}{$b} <=> $topspamdetail{$t}{autolearn}{$a} } keys %{$topspamdetail{$t}{autolearn}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$topspamdetail{$t}{autolearn}{$d}',";
$top++;
}
print OUT "},";
delete $topspamdetail{$t}{autolearn};
$top = 0;
print OUT "},";
}
print OUT ");\n\n";
%topspamdetail = ();
# Top system message statistics
$top = 0;
print OUT "\%::toperr = (\n";
foreach my $m ( keys %toperr) {
my $c = $toperr{$m};
$m =~ s/'/\\'/gs;
print OUT "'$m' => '$c',\n";
}
print OUT ");\n\n";
%toperr = ();
# Top postgrey statistics
$top = 0;
print OUT "\%::toppostgrey = (\n";
print OUT "'sender' => {";
foreach my $d (sort { $toppostgrey{sender}{$b} <=> $toppostgrey{sender}{$a} } keys %{$toppostgrey{sender}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$toppostgrey{sender}{$d}',";
$top++;
}
print OUT "},\n";
delete $toppostgrey{sender};
$top = 0;
print OUT "'sender_relay' => {";
foreach my $d (sort { $toppostgrey{sender_relay}{$b} <=> $toppostgrey{sender_relay}{$a} } keys %{$toppostgrey{sender_relay}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$toppostgrey{sender_relay}{$d}',";
$top++;
}
print OUT "},\n";
delete $toppostgrey{sender_relay};
$top = 0;
print OUT "'domain' => {";
foreach my $d (sort { $toppostgrey{domain}{$b} <=> $toppostgrey{domain}{$a} } keys %{$toppostgrey{domain}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$toppostgrey{domain}{$d}',";
$top++;
}
print OUT "},\n";
delete $toppostgrey{domain};
$top = 0;
print OUT "'reason' => {";
foreach my $d (sort { $toppostgrey{reason}{$b} <=> $toppostgrey{reason}{$a} } keys %{$toppostgrey{reason}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$toppostgrey{reason}{$d}',";
$top++;
}
print OUT "},\n";
delete $toppostgrey{reason};
$top = 0;
print OUT "'rcpt' => {";
foreach my $d (sort { $toppostgrey{rcpt}{$b} <=> $toppostgrey{rcpt}{$a} } keys %{$toppostgrey{rcpt}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$toppostgrey{rcpt}{$d}',";
$top++;
}
print OUT "},\n";
print OUT ");\n\n";
%toppostgrey = ();
close(OUT);
} else {
&logerror("can't write cache file $file: $!");
}
}
sub get_minute_range
{
my $val = shift;
for (my $i = 5; $i <= 60; $i += 5) {
return $i if ( ($val < $i) && ($val >= ($i - 5)) );
}
return $val;
}
sub compute_global_stats
{
my ($file, $DOMAIN, $STATS, $begin, $end, $x_label, $hostname) = @_;
my %PERIOD_STAT = ();
foreach my $id (keys %$STATS) {
next if (($id eq 'TOPDSN') || ($id eq 'STARTTLS'));
next if ($DOMAIN && ($STATS->{$id}{sender} !~ /$DOMAIN/) && !grep(/$DOMAIN/, @{$STATS->{$id}{rcpt}}));
if (exists $STATS->{$id}{dsnstatus}) {
next if ($DOMAIN && ($STATS->{$STATS->{$id}{srcid}}{sender} !~ /$DOMAIN/) && !grep(/$DOMAIN/, @{$STATS->{$id}{rcpt}}));
$PERIOD_STAT{dsn}{"$STATS->{$id}{idx_dsn}"}++;
if (($end > 31) && ($STATS->{$id}{hour} =~ /^\d\d(\d\d)/)) {
my $m = &get_minute_range($1);
$PERIOD_STAT{count_dsn}{$m}++;
}
for (my $i = 0; $i <= $#{$STATS->{$id}{status}}; $i++) {
if ($STATS->{$id}{status}[$i] eq 'Sent') {
my $direction = &set_direction($STATS->{$id}{sender_relay}, $STATS->{$id}{rcpt_relay}[$i], $hostname);
$direction =~ s/^Ext_/Int_/; # DSN are always sent by localhost
$dsn{$direction}++;
if ($direction =~ /_Int/) {
$dsn{local_outbound}++;
} else {
$dsn{outbound}++;
}
} else {
$dsn{error}++;
}
}
} elsif (exists $STATS->{$id}{nrcpt}) {
if ($STATS->{$id}{sender_relay} eq 'localhost') {
$messaging{local_inbound}++;
$messaging{local_inbound_bytes} += $STATS->{$id}{size} || 0;
} elsif (exists $STATS->{$id}{sender_relay}) {
$messaging{inbound}++;
$messaging{inbound_bytes} += $STATS->{$id}{size} || 0;
}
$PERIOD_STAT{flow}{"$STATS->{$id}{idx_sender}"}{inbound}++;
$PERIOD_STAT{flow}{"$STATS->{$id}{idx_sender}"}{inbound_bytes} += $STATS->{$id}{size};
if (($end > 31) && ($STATS->{$id}{hour} =~ /^\d\d(\d\d)/)) {
my $m = &get_minute_range($1);
$PERIOD_STAT{count}{$m}++;
$PERIOD_STAT{count_bytes}{$m} += $STATS->{$id}{size} || 0;
}
}
if (exists $STATS->{$id}{status}) {
for (my $i = 0; $i <= $#{$STATS->{$id}{status}}; $i++) {
$GLOBAL_STATUS{"$STATS->{$id}{status}[$i]"}++;
$GLOBAL_STATUS{"$STATS->{$id}{status}[$i]" . '_bytes'} += $STATS->{$id}{size};
if ($STATS->{$id}{status}[$i] eq 'Sent') {
$PERIOD_STAT{flow}{"$STATS->{$id}{idx_rcpt}"}{outbound}++;
$PERIOD_STAT{flow}{"$STATS->{$id}{idx_rcpt}"}{outbound_bytes} += $STATS->{$id}{size};
$messaging{nbsender}{"$STATS->{$id}{sender}"} = '';
$messaging{nbrcpt}{"$STATS->{$id}{rcpt}[$i]"} = '';
$delivery{'total'}++;
my $direction = &set_direction($STATS->{$id}{sender_relay}, $STATS->{$id}{rcpt_relay}[$i], $hostname);
$delivery{$direction}++;
$direction .= '_bytes';
$delivery{$direction} += $STATS->{$id}{size};
if ($direction =~ /_Int/) {
$messaging{local_outbound}++;
$messaging{local_outbound_bytes} += $STATS->{$id}{size} || 0;
} else {
$messaging{outbound}++;
$messaging{outbound_bytes} += $STATS->{$id}{size} || 0;
}
if (($end > 31) && ($STATS->{$id}{hour}[$i] =~ /^\d\d(\d\d)/)) {
my $m = &get_minute_range($1);
$PERIOD_STAT{count1}{$m}++;
$PERIOD_STAT{count1_bytes}{$m} += $STATS->{$id}{size} || 0;
}
}
}
}
if (exists $STATS->{$id}{spam}) {
$PERIOD_STAT{spam}{"$STATS->{$id}{idx_spam}"}++;
$GLOBAL_STATUS{Spam}++;
$GLOBAL_STATUS{Spam_bytes} += $STATS->{$id}{size};
if ($STATS->{$id}{sender_relay} =~ /localhost/) {
$spam{local_inbound}++;
$spam{local_inbound_bytes} += $STATS->{$id}{size};
} elsif ($CONFIG{MAIL_HUB} && $STATS->{$id}{sender_relay} =~ /$CONFIG{MAIL_HUB}/) {
$spam{local_inbound}++;
$spam{local_inbound_bytes} += $STATS->{$id}{size};
} else {
$spam{inbound}++;
$spam{inbound_bytes} += $STATS->{$id}{size} || 0;
}
if (($end > 31) && ($STATS->{$id}{hour} =~ /^\d\d(\d\d)/)) {
my $m = &get_minute_range($1);
$PERIOD_STAT{count_spam}{$m}++;
}
for (my $i = 0; $i <= $#{$STATS->{$id}{status}}; $i++) {
if ($STATS->{$id}{status}[$i] eq 'Sent') {
my $direction = &set_direction($STATS->{$id}{sender_relay}, $STATS->{$id}{rcpt_relay}[$i], $hostname);
$spam{$direction}++;
$direction .= '_bytes';
$spam{$direction} += $STATS->{$id}{size};
if ($direction =~ /_Int/) {
$spam{local_outbound}++;
$spam{local_outbound_bytes} += $STATS->{$id}{size} || 0;
} else {
$spam{outbound}++;
$spam{outbound_bytes} += $STATS->{$id}{size} || 0;
}
}
}
}
if (exists $STATS->{$id}{virus}) {
$PERIOD_STAT{virus}{"$STATS->{$id}{idx_virus}"}++;
$GLOBAL_STATUS{Virus}++;
$GLOBAL_STATUS{Virus_bytes} += $STATS->{$id}{size};
if ($STATS->{$id}{sender_relay} =~ /localhost/) {
$virus{local_inbound}++;
$virus{local_inbound_bytes} += $STATS->{$id}{size};
} elsif ($CONFIG{MAIL_HUB} && $STATS->{$id}{sender_relay} =~ /$CONFIG{MAIL_HUB}/) {
$virus{local_inbound}++;
$virus{local_inbound_bytes} += $STATS->{$id}{size};
} else {
$virus{inbound}++;
$virus{inbound_bytes} += $STATS->{$id}{size} || 0;
}
if (($end > 31) && ($STATS->{$id}{hour} =~ /^\d\d(\d\d)/)) {
my $m = &get_minute_range($1);
$PERIOD_STAT{count_virus}{$m}++;
}
for (my $i = 0; $i <= $#{$STATS->{$id}{status}}; $i++) {
if ($STATS->{$id}{status}[$i] eq 'Sent') {
my $direction = &set_direction($STATS->{$id}{sender_relay}, $STATS->{$id}{rcpt_relay}[$i], $hostname);
$virus{$direction}++;
$direction .= '_bytes';
$virus{$direction} += $STATS->{$id}{size};
if ($direction =~ /_Int/) {
$virus{local_outbound}++;
$virus{local_outbound_bytes} += $STATS->{$id}{size} || 0;
} else {
$virus{outbound}++;
$virus{outbound_bytes} += $STATS->{$id}{size} || 0;
}
}
}
}
if (exists $STATS->{$id}{rule}) {
$PERIOD_STAT{reject}{"$STATS->{$id}{idx_reject}"}++;
$GLOBAL_STATUS{Rejected}++;
$GLOBAL_STATUS{Rejected_bytes} += $STATS->{$id}{size};
if ($STATS->{$id}{sender_relay} =~ /localhost/) {
$reject{local_inbound}++;
$reject{local_inbound_bytes} += $STATS->{$id}{size};
} elsif ($CONFIG{MAIL_HUB} && $STATS->{$id}{sender_relay} =~ /$CONFIG{MAIL_HUB}/) {
$reject{local_inbound}++;
$reject{local_inbound_bytes} += $STATS->{$id}{size};
} else {
$reject{inbound}++;
$reject{inbound_bytes} += $STATS->{$id}{size};
}
}
if (exists $STATS->{$id}{error}) {
$GLOBAL_STATUS{SysErr}++;
$GLOBAL_STATUS{SysErr_bytes} += $STATS->{$id}{size};
if ($STATS->{$id}{sender_relay} =~ /localhost/) {
$err{local_inbound}++;
$err{local_inbound_bytes} += $STATS->{$id}{size};
} elsif ($CONFIG{MAIL_HUB} && $STATS->{$id}{sender_relay} =~ /$CONFIG{MAIL_HUB}/) {
$err{local_inbound}++;
$err{local_inbound_bytes} += $STATS->{$id}{size};
} else {
$err{inbound}++;
$err{inbound_bytes} += $STATS->{$id}{size};
}
}
if (!$DOMAIN && exists $STATS->{$id}{auth_relay}) {
for (my $i = 0; $i <= $#{$STATS->{$id}{auth_relay}}; $i++) {
$PERIOD_STAT{auth}{$STATS->{$id}{auth_type}[$i]}{"$STATS->{$id}{idx_auth}[$i]"}++;
$auth{$STATS->{$id}{auth_type}[$i]}{$STATS->{$id}{auth_mech}[$i]}++;
if (($end > 31) && ($STATS->{$id}{auth_hour}[$i] =~ /^\d\d(\d\d)/)) {
my $m = &get_minute_range($1);
$PERIOD_STAT{count_auth}{$STATS->{$id}{auth_type}[$i]}{$m}++;
}
}
}
if (exists $STATS->{$id}{reason}) {
$postgrey{reason}{$STATS->{$id}{reason}}++;
}
if (exists $STATS->{$id}{spf}) {
foreach my $r (keys %{ $STATS->{$id}{spf} }) {
#foreach my $k (keys %{ $STATS->{$id}{spf}{$r}{domain} }) {
# $spf_dkim{spf}{$r}{domain}{$k} += $STATS->{$id}{spf}{$r}{domain}{$k};
#}
foreach my $k (keys %{ $STATS->{$id}{spf}{$r}{status} }) {
$spf_dkim{spf}{$r}{status}{$k} += $STATS->{$id}{spf}{$r}{status}{$k};
}
}
}
if (exists $STATS->{$id}{dkim}) {
foreach my $k (keys %{ $STATS->{$id}{dkim}{status} }) {
$spf_dkim{dkim}{status}{$k} += $STATS->{$id}{dkim}{status}{$k};
}
#foreach my $k (keys %{ $STATS->{$id}{dkim}{domain} }) {
# $spf_dkim{dkim}{domain}{$k} += $STATS->{$id}{dkim}{domain}{$k};
#}
}
}
# Top STARTTLS stats
foreach my $v (keys %{$STATS->{'STARTTLS'}}) {
$starttls{$v} = $STATS->{'STARTTLS'}{$v};
}
# Messaging aggregation
$messaging{total_inbound} = $messaging{inbound} + $messaging{local_inbound};
$messaging{total_inbound_bytes} = $messaging{inbound_bytes} + $messaging{local_inbound_bytes};
$messaging{total_outbound} = $messaging{outbound} + $messaging{local_outbound};
$messaging{total_outbound_bytes} = $messaging{outbound_bytes} + $messaging{local_outbound_bytes};
# Messaging flows
my $lbls = '';
# Per five minutes stats
if ($end > 31) {
for (my $i = 5; $i <= 60; $i += 5) {
my $t = sprintf("%02d", $i);
$lbls .= "$t:";
$messaging{values} .= ($PERIOD_STAT{count}{$i} || 0) . ':';
$messaging{values1}.= ($PERIOD_STAT{count1}{$i} || 0) . ':';
$messaging{values_bytes} .= ($PERIOD_STAT{count_bytes}{$i} || 0) . ':';
$messaging{values1_bytes} .= ($PERIOD_STAT{count1_bytes}{$i} || 0) . ':';
$spam{values} .= ($PERIOD_STAT{count_spam}{$i} || 0) . ':';
$virus{values} .= ($PERIOD_STAT{count_virus}{$i} || 0) . ':';
$dsn{values} .= ($PERIOD_STAT{count_dsn}{$i} || 0) . ':';
foreach my $type (keys %{$PERIOD_STAT{auth}}) {
$auth{$type}{values} .= ($PERIOD_STAT{count_auth}{$type}{$i} || 0) . ':';
}
}
} else {
foreach my $t ("$begin" .. "$end") {
$lbls .= "$t:";
$messaging{values} .= ($PERIOD_STAT{flow}{"$t"}{inbound} || 0) . ':';
$messaging{values1}.= ($PERIOD_STAT{flow}{"$t"}{outbound} || 0) . ':';
$messaging{values_bytes} .= ($PERIOD_STAT{flow}{"$t"}{inbound_bytes} || 0) . ':';
$messaging{values1_bytes} .= ($PERIOD_STAT{flow}{"$t"}{outbound_bytes} || 0) . ':';
$spam{values} .= ($PERIOD_STAT{spam}{"$t"} || 0) . ':';
$virus{values} .= ($PERIOD_STAT{virus}{"$t"} || 0) . ':';
$dsn{values} .= ($PERIOD_STAT{dsn}{"$t"} || 0) . ':';
foreach my $type (keys %{$PERIOD_STAT{auth}}) {
$auth{$type}{values} .= ($PERIOD_STAT{auth}{$type}{"$t"} || 0) . ':';
}
}
}
$lbls =~ s/:$//;
$messaging{values} =~ s/:$//;
$messaging{values1} =~ s/:$//;
$messaging{values_bytes} =~ s/:$//;
$messaging{values1_bytes} =~ s/:$//;
$spam{values} =~ s/:$//;
$virus{values} =~ s/:$//;
$dsn{values} =~ s/:$//;
foreach my $type (keys %auth) {
$auth{$type}{values} =~ s/:$//;
}
$err{total_inbound} = $err{inbound} + $err{local_inbound};
$err{total_inbound_bytes} = $err{inbound_bytes} + $err{local_inbound_bytes};
$spam{total_inbound} = $spam{inbound} + $spam{local_inbound};
$spam{total_inbound_bytes} = $spam{inbound_bytes} + $spam{local_inbound_bytes};
$spam{total_outbound} = $spam{outbound} + $spam{local_outbound};
$spam{total_outbound_bytes} = $spam{outbound_bytes} + $spam{local_outbound_bytes};
$reject{total_inbound} = $reject{inbound} + $reject{local_inbound};
$reject{total_inbound_bytes} = $reject{inbound_bytes} + $reject{local_inbound_bytes};
$virus{total_inbound} = $virus{inbound} + $virus{local_inbound};
$virus{total_inbound_bytes} = $virus{inbound_bytes} + $virus{local_inbound_bytes};
$virus{total_outbound} = $virus{outbound} + $virus{local_outbound};
$virus{total_outbound_bytes} = $virus{outbound_bytes} + $virus{local_outbound_bytes};
$dsn{total_outbound} = $dsn{outbound} + $dsn{local_outbound};
my $nbsender = scalar keys %{$messaging{nbsender}};
my $nbrcpt = scalar keys %{$messaging{nbrcpt}};
delete $messaging{nbsender};
delete $messaging{nbrcpt};
if (open(OUT, ">>$file")) {
print OUT "\%::auth = (\n";
foreach my $type (keys %auth) {
print OUT "'$type' => {";
print OUT "'values' => '$auth{$type}{values}',";
print OUT "'lbls' => '$lbls',";
print OUT "'x_label' => '$x_label',";
foreach my $mech (keys %{$auth{$type}}) {
next if ($mech eq 'values');
print OUT "'$mech' => '$auth{$type}{$mech}',";
}
print OUT "},\n";
}
print OUT ");\n\n";
%auth = ();
print OUT "\%::messaging = (\n";
print OUT "'inbound' => '$messaging{inbound}',\n";
print OUT "'inbound_bytes' => '$messaging{inbound_bytes}',\n";
print OUT "'local_inbound' => '$messaging{local_inbound}',\n";
print OUT "'local_inbound_bytes' => '$messaging{local_inbound_bytes}',\n";
print OUT "'total_inbound' => '$messaging{total_inbound}',\n";
print OUT "'total_inbound_bytes' => '$messaging{total_inbound_bytes}',\n";
print OUT "'outbound' => '$messaging{outbound}',\n";
print OUT "'outbound_bytes' => '$messaging{outbound_bytes}',\n";
print OUT "'local_outbound' => '$messaging{local_outbound}',\n";
print OUT "'local_outbound_bytes' => '$messaging{local_outbound_bytes}',\n";
print OUT "'total_outbound' => '$messaging{total_outbound}',\n";
print OUT "'total_outbound_bytes' => '$messaging{total_outbound_bytes}',\n";
print OUT "'lbls' => '$lbls',\n";
print OUT "'x_label' => '$x_label',\n";
print OUT "'values' => '$messaging{values}',\n";
print OUT "'values1' => '$messaging{values1}',\n";
print OUT "'values_bytes' => '$messaging{values_bytes}',\n";
print OUT "'values1_bytes' => '$messaging{values1_bytes}',\n";
print OUT "'nbsender' => '$nbsender',\n";
print OUT "'nbrcpt' => '$nbrcpt',\n";
print OUT ");\n\n";
%messaging = ();
# Spamming flows + Spam delivery flows + Rejection flows
print OUT "\%::spam = (\n";
print OUT "'inbound' => '$spam{inbound}',\n";
print OUT "'inbound_bytes' => '$spam{inbound_bytes}',\n";
print OUT "'local_inbound' => '$spam{local_inbound}',\n";
print OUT "'local_inbound_bytes' => '$spam{local_inbound_bytes}',\n";
print OUT "'total_inbound' => '$spam{total_inbound}',\n";
print OUT "'total_inbound_bytes' => '$spam{total_inbound_bytes}',\n";
print OUT "'outbound' => '$spam{outbound}',\n";
print OUT "'outbound_bytes' => '$spam{outbound_bytes}',\n";
print OUT "'local_outbound' => '$spam{local_outbound}',\n";
print OUT "'local_outbound_bytes' => '$spam{local_outbound_bytes}',\n";
print OUT "'total_outbound' => '$spam{total_outbound}',\n";
print OUT "'total_outbound_bytes' => '$spam{total_outbound_bytes}',\n";
print OUT "'lbls' => '$lbls',\n";
print OUT "'x_label' => '$x_label',\n";
print OUT "'values' => '$spam{values}',\n";
print OUT "'Ext_Int' => '$spam{Ext_Int}',\n";
print OUT "'Int_Int' => '$spam{Int_Int}',\n";
print OUT "'Int_Ext' => '$spam{Int_Ext}',\n";
print OUT "'Ext_Ext' => '$spam{Ext_Ext}',\n";
print OUT "'Ext_Int_bytes' => '$spam{Ext_Int_bytes}',\n";
print OUT "'Int_Int_bytes' => '$spam{Int_Int_bytes}',\n";
print OUT "'Int_Ext_bytes' => '$spam{Int_Ext_bytes}',\n";
print OUT "'Ext_Ext_bytes' => '$spam{Ext_Ext_bytes}',\n";
print OUT ");\n\n";
%spam = ();
print OUT "\%::reject = (\n";
print OUT "'inbound' => '$reject{inbound}',\n";
print OUT "'inbound_bytes' => '$reject{inbound_bytes}',\n";
print OUT "'local_inbound' => '$reject{local_inbound}',\n";
print OUT "'local_inbound_bytes' => '$reject{local_inbound_bytes}',\n";
print OUT "'total_inbound' => '$reject{total_inbound}',\n";
print OUT "'total_inbound_bytes' => '$reject{total_inbound_bytes}',\n";
print OUT ");\n\n";
%reject = ();
print OUT "\%::postgrey = (\n";
print OUT "'reason' => {";
foreach my $k (keys %{$postgrey{reason}}) {
print OUT "\t'$k' => '$postgrey{reason}{$k}',";
}
print OUT "},\n";
print OUT ");\n\n";
%postgrey = ();
print OUT "\%::spf_dkim = (\n";
print OUT "'spf' => {\n";
foreach my $r (keys %{$spf_dkim{spf}}) {
print OUT "\t'$r' => {\n";
foreach my $s (keys %{$spf_dkim{spf}{$r}}) {
print OUT "\t\t'$s' => { ";
foreach my $v (keys %{$spf_dkim{spf}{$r}{$s}}) {
print OUT "'$v' => '$spf_dkim{spf}{$r}{$s}{$v}',";
}
print OUT " },\n";
}
print OUT "\t},\n";
}
print OUT "},\n";
print OUT "'dkim' => {\n";
foreach my $r (keys %{$spf_dkim{dkim}}) {
print OUT "\t'$r' => {\n";
foreach my $s (keys %{$spf_dkim{dkim}{$r}}) {
print OUT "\t\t'$s' => '$spf_dkim{dkim}{$r}{$s}',\n";
}
print OUT "\t},\n";
}
print OUT "},\n";
print OUT ");\n\n";
%spf_dkim = ();
# Viruses flows / Viruses delivery flows / syserr flows
print OUT "\%::virus = (\n";
print OUT "'inbound' => '$virus{inbound}',\n";
print OUT "'inbound_bytes' => '$virus{inbound_bytes}',\n";
print OUT "'local_inbound' => '$virus{local_inbound}',\n";
print OUT "'local_inbound_bytes' => '$virus{local_inbound_bytes}',\n";
print OUT "'total_inbound' => '$virus{total_inbound}',\n";
print OUT "'total_inbound_bytes' => '$virus{total_inbound_bytes}',\n";
print OUT "'outbound' => '$virus{outbound}',\n";
print OUT "'outbound_bytes' => '$virus{outbound_bytes}',\n";
print OUT "'local_outbound' => '$virus{local_outbound}',\n";
print OUT "'local_outbound_bytes' => '$virus{local_outbound_bytes}',\n";
print OUT "'total_outbound' => '$virus{total_outbound}',\n";
print OUT "'total_outbound_bytes' => '$virus{total_outbound_bytes}',\n";
print OUT "'lbls' => '$lbls',\n";
print OUT "'x_label' => '$x_label',\n";
print OUT "'values' => '$virus{values}',\n";
print OUT "'Ext_Int' => '$virus{Ext_Int}',\n";
print OUT "'Int_Int' => '$virus{Int_Int}',\n";
print OUT "'Int_Ext' => '$virus{Int_Ext}',\n";
print OUT "'Ext_Ext' => '$virus{Ext_Ext}',\n";
print OUT "'Ext_Int_bytes' => '$virus{Ext_Int_bytes}',\n";
print OUT "'Int_Int_bytes' => '$virus{Int_Int_bytes}',\n";
print OUT "'Int_Ext_bytes' => '$virus{Int_Ext_bytes}',\n";
print OUT "'Ext_Ext_bytes' => '$virus{Ext_Ext_bytes}',\n";
print OUT ");\n\n";
%virus = ();
print OUT "\%::err = (\n";
print OUT "'inbound' => '$err{inbound}',\n";
print OUT "'inbound_bytes' => '$err{inbound_bytes}',\n";
print OUT "'local_inbound' => '$err{local_inbound}',\n";
print OUT "'local_inbound_bytes' => '$err{local_inbound_bytes}',\n";
print OUT "'total_inbound' => '$err{total_inbound}',\n";
print OUT "'total_inbound_bytes' => '$err{total_inbound_bytes}',\n";
print OUT ");\n\n";
%err = ();
print OUT "\%::GLOBAL_STATUS = (\n";
foreach my $s (sort {$GLOBAL_STATUS{$b} <=> $GLOBAL_STATUS{$a}} keys %GLOBAL_STATUS) {
next if ($s =~ /_bytes/);
my $slbl = $s;
$slbl =~ s/'/\\'/g;
print OUT "'$slbl' => '$GLOBAL_STATUS{$s}',\n";
print OUT "'$slbl", "_bytes' => '", $GLOBAL_STATUS{$s . '_bytes'}, "',\n";
}
print OUT ");\n\n";
my $elbls = 'Ext -> Int:Ext -> Ext:Int -> Int:Int -> Ext';
print OUT "\%::delivery = (\n";
print OUT "'lbls' => '$elbls',\n";
print OUT "'x_label' => '$x_label',\n";
print OUT "'Ext_Int' => '$delivery{Ext_Int}',\n";
print OUT "'Int_Int' => '$delivery{Int_Int}',\n";
print OUT "'Int_Ext' => '$delivery{Int_Ext}',\n";
print OUT "'Ext_Ext' => '$delivery{Ext_Ext}',\n";
print OUT "'Ext_Int_bytes' => '$delivery{Ext_Int_bytes}',\n";
print OUT "'Int_Int_bytes' => '$delivery{Int_Int_bytes}',\n";
print OUT "'Int_Ext_bytes' => '$delivery{Int_Ext_bytes}',\n";
print OUT "'Ext_Ext_bytes' => '$delivery{Ext_Ext_bytes}',\n";
print OUT ");\n\n";
# DSN
$dsn{total_outbound} = ($dsn{local_outbound}+$dsn{outbound}) || 0;
print OUT "\%::dsn = (\n";
print OUT "'outbound' => '$dsn{outbound}',\n";
print OUT "'local_outbound' => '$dsn{local_outbound}',\n";
print OUT "'error' => '$dsn{error}',\n";
print OUT "'total_outbound' => '$dsn{total_outbound}',\n";
print OUT "'lbls' => '$lbls',\n";
print OUT "'x_label' => '$x_label',\n";
print OUT "'values' => '$dsn{values}',\n";
print OUT "'Ext_Int' => '$dsn{Ext_Int}',\n";
print OUT "'Int_Int' => '$dsn{Int_Int}',\n";
print OUT "'Int_Ext' => '$dsn{Int_Ext}',\n";
print OUT "'Ext_Ext' => '$dsn{Ext_Ext}',\n";
print OUT ");\n\n";
%dsn = ();
print OUT "\%::starttls = (\n";
foreach my $k (keys %starttls) {
my $slbl = $k;
$slbl =~ s/'/\\'/g;
print OUT "\t'$slbl' => '$starttls{$k}',";
}
print OUT ");\n\n";
%starttls = ();
close(OUT);
} else {
&logerror("can't write cache file $file: $!");
}
}
sub free_space
{
my $path = shift;
my @days = @_;
return if ( !$CONFIG{FREE_SPACE} || (lc($CONFIG{FREE_SPACE}) eq 'none') );
if ( (lc($CONFIG{FREE_SPACE}) eq 'archive') && !-e "$path/history.tar.gz") {
print "Backuping monthly data files into $path/history.tar.gz\n" if ($CONFIG{DEBUG});
my @found = `find $path -name "*.dat" 2>/dev/null`;
if ($#found >= 0) {
`tar czf $path/history.tar.gz \`find $path -name "*.dat"\` 2>/dev/null`;
if ($? != 0) {
print STDERR "ERROR: can't create archive $path/history.tar.gz, reason: $!\n";
}
}
}
if (-e "$path/history.tar.gz" || (lc($CONFIG{FREE_SPACE}) eq 'delete')) {
opendir(DIR, "$path") || die "can't opendir $path: $!";
my @ddirs = grep { /^\d+$/ && -d "$path/$_" } readdir(DIR);
closedir DIR;
foreach my $d (@ddirs) {
my @files = `ls $path/$d/*.dat 2>/dev/null`;
if ($#files >= 0) {
print "Removing monthly data file $path/$d/*.dat\n" if ($CONFIG{DEBUG});
`rm -f $path/$d/*.dat`;
}
}
}
}
sub free_space_week
{
my ($path, @days) = @_;
return if ( !$CONFIG{FREE_SPACE} || (lc($CONFIG{FREE_SPACE}) eq 'none') );
if ( (lc($CONFIG{FREE_SPACE}) eq 'archive') && !-e "$path/history.tar.gz") {
print "Backuping weekly data files into $path/history.tar.gz\n" if ($CONFIG{DEBUG});
my @found = ();
foreach my $d (@days) {
push(@found, `find $d -name "*.dat" 2>/dev/null`);
}
if ($#found >= 0) {
chomp(@found);
my $files = join(" ", @found);
`tar czf $path/history.tar.gz $files 2>/dev/null`;
if ($? != 0) {
print STDERR "ERROR: can't create archive $path/history.tar.gz, reason: $!\n";
}
}
}
if (-e "$path/history.tar.gz" || (lc($CONFIG{FREE_SPACE}) eq 'delete')) {
foreach my $d (@days) {
my @files = `ls $d/*.dat 2>/dev/null`;
if ($#files >= 0) {
print "Removing weekly data files $d/*.dat\n" if ($CONFIG{DEBUG});
`rm -f $d/*.dat`;
}
}
}
}
####
# Day cache statistics
####
sub do_day_cache
{
my ($hostname, $DOMAIN, $year, $month, $day, $curday) = @_;
if (-e "$CONFIG{OUT_DIR}/$hostname/$year/$month/$day/cache.pm\U$DOMAIN\E" && ("$year$month$day" < $curday)) {
return;
}
print "Reading daily statistics from $CONFIG{OUT_DIR}/$hostname/$year/$month/$day\n" if ($CONFIG{DEBUG});
my %localtopsender = ();
my %localtoprcpt = ();
my %localtopspam = ();
my %localtopvirus = ();
my %localtopdsn = ();
my %localtopreject = ();
my %localtoperr = ();
my %localdelivery = ();
my %localmessaging = ();
my %localspam = ();
my %localvirus = ();
my %localdsn = ();
my %localreject = ();
my %localerr = ();
my %localGLOBAL_STATUS = ();
my %localtopspamdetail = ();
my %localauth = ();
my %localtopauth = ();
my %localpostgrey = ();
my %localtoppostgrey = ();
my %localstarttls = ();
my %localspf_dkim = ();
my $lbls = '';
my %authval = ();
foreach my $hour ("00" .. "23") {
$lbls .= "$hour:";
if (!-e "$CONFIG{OUT_DIR}/$hostname/$year/$month/$day/${hour}cache.pm\U$DOMAIN\E") {
$localmessaging{values} .= '0:';
$localmessaging{values1} .= '0:';
$localmessaging{values_bytes} .= '0:';
$localmessaging{values1_bytes} .= '0:';
$localspam{values} .= '0:';
$localvirus{values} .= '0:';
$localdsn{values} .= '0:';
$localmessaging{nbsender} .= '0:';
$localmessaging{nbrcpt} .= '0:';
next;
} else {
&clean_globals();
my $file = "$CONFIG{OUT_DIR}/$hostname/$year/$month/$day/${hour}cache.pm\U$DOMAIN\E";
print "Loading cache statistics from $file\n" if ($CONFIG{DEBUG});
do "$file";
foreach my $k (keys %messaging) {
if (!grep(/^$k$/, 'lbls','x_label','values','values1','values_bytes','values1_bytes','nbsender','nbrcpt')) {
$localmessaging{$k} += $messaging{$k};
}
}
$localmessaging{values} .= ($messaging{total_inbound} || 0) . ':';
$localmessaging{values1} .= ($messaging{total_outbound} || 0) . ':';
$localmessaging{values_bytes} .= ($messaging{total_inbound_bytes} || 0) . ':';
$localmessaging{values1_bytes} .= ($messaging{total_outbound_bytes} || 0) . ':';
my $tmp = 0;
foreach (split(/:/, $messaging{nbsender})) {
$tmp += $_;
}
$localmessaging{nbsender} .= $tmp . ':';
$tmp = 0;
foreach (split(/:/, $messaging{nbrcpt})) {
$tmp += $_;
}
$localmessaging{nbrcpt} .= $tmp . ':';
%messaging = ();
foreach my $t (keys %auth) {
foreach my $m (keys %{$auth{$t}}) {
if (!grep(/^$m$/, 'lbls','x_label','values')) {
$localauth{$t}{$m} += $auth{$t}{$m};
$localauth{$t}{values}{"$hour"} += $auth{$t}{$m};
}
}
}
%auth = ();
foreach my $k (keys %spam) {
if (!grep(/^$k$/, 'lbls','x_label','values')) {
$localspam{$k} += $spam{$k};
}
}
$localspam{values} .= ($spam{total_inbound} || 0) . ':';
%spam = ();
foreach my $k (keys %reject) {
if (!grep(/^$k$/, 'lbls','x_label','values')) {
$localreject{$k} += $reject{$k};
}
}
%reject = ();
foreach my $k (keys %{$postgrey{reason}}) {
$localpostgrey{reason}{$k} += $postgrey{reason}{$k};
}
%postgrey = ();
foreach my $r (keys %{$spf_dkim{spf}}) {
foreach my $k (keys %{$spf_dkim{spf}{$r}{status}}) {
$localspf_dkim{spf}{$r}{status}{$k} += $spf_dkim{spf}{$r}{status}{$k};
}
foreach my $k (keys %{$spf_dkim{spf}{$r}{domain}}) {
$localspf_dkim{spf}{$r}{domain}{$k} += $spf_dkim{spf}{$r}{domain}{$k};
}
}
foreach my $r (keys %{$spf_dkim{dkim}{status}}) {
$localspf_dkim{dkim}{status}{$r} += $spf_dkim{dkim}{status}{$r};
}
%spf_dkim = ();
foreach my $k (keys %virus) {
if (!grep(/^$k$/, 'lbls','x_label','values')) {
$localvirus{$k} += $virus{$k};
}
}
$localvirus{values} .= ($virus{total_inbound} || 0) . ':';
%virus = ();
foreach my $k (keys %dsn) {
if (!grep(/^$k$/, 'lbls','x_label','values')) {
$localdsn{$k} += $dsn{$k};
}
}
$localdsn{values} .= ($dsn{total_outbound} || 0) . ':';
%dsn = ();
foreach my $k (keys %err) {
if (!grep(/^$k$/, 'lbls','x_label','values')) {
$localerr{$k} += $err{$k};
}
}
%err = ();
foreach my $k (keys %GLOBAL_STATUS) {
$localGLOBAL_STATUS{$k} += $GLOBAL_STATUS{$k};
}
%GLOBAL_STATUS = ();
foreach my $k (keys %delivery) {
if (!grep(/^$k$/, 'lbls','x_label')) {
$localdelivery{$k} += $delivery{$k};
}
}
foreach my $k (keys %topsender) {
foreach my $d (keys %{$topsender{$k}}) {
$localtopsender{$k}{$d} += $topsender{$k}{$d} || 0;
}
}
%topsender = ();
foreach my $k (keys %toprcpt) {
foreach my $d (keys %{$toprcpt{$k}}) {
$localtoprcpt{$k}{$d} += $toprcpt{$k}{$d} || 0;
}
}
%toprcpt = ();
foreach my $k (keys %topreject) {
foreach my $d (keys %{$topreject{$k}}) {
$localtopreject{$k}{$d} += $topreject{$k}{$d} || 0;
}
}
%topreject = ();
foreach my $k (keys %topvirus) {
foreach my $d (keys %{$topvirus{$k}}) {
$localtopvirus{$k}{$d} += $topvirus{$k}{$d} || 0;
}
}
%topvirus = ();
foreach my $k (keys %topdsn) {
foreach my $d (keys %{$topdsn{$k}}) {
$localtopdsn{$k}{$d} += $topdsn{$k}{$d} || 0;
}
}
%topdsn = ();
foreach my $k (keys %topspam) {
foreach my $d (keys %{$topspam{$k}}) {
$localtopspam{$k}{$d} += $topspam{$k}{$d} || 0;
}
}
%topspam = ();
foreach my $k (keys %toperr) {
$localtoperr{$k} += $toperr{$k} || 0;
}
%toperr = ();
foreach my $k (keys %toppostgrey) {
foreach my $d (keys %{$toppostgrey{$k}}) {
$localtoppostgrey{$k}{$d} += $toppostgrey{$k}{$d} || 0;
}
}
%toppostgrey = ();
foreach my $t (keys %topspamdetail) {
foreach my $k (keys %{$topspamdetail{$t}}) {
foreach my $d (keys %{$topspamdetail{$t}{$k}}) {
$localtopspamdetail{$t}{$k}{$d} += $topspamdetail{$t}{$k}{$d} || 0;
}
}
}
%topspamdetail = ();
foreach my $k (keys %topauth) {
foreach my $d (keys %{$topauth{$k}}) {
$localtopauth{$k}{$d} += $topauth{$k}{$d} || 0;
}
}
%topauth = ();
foreach my $t (keys %localauth) {
$authval{$t} .= ($localauth{$t}{values}{"$hour"} || 0) . ':';
}
foreach my $k (keys %starttls) {
$localstarttls{$k} += $starttls{$k};
}
%starttls = ();
}
}
foreach my $t (keys %localauth) {
delete $localauth{$t}{values};
$localauth{$t}{values} = $authval{$t};
$localauth{$t}{lbls} =~ s/:$//;
$localauth{$t}{values} =~ s/:$//;
}
$lbls =~ s/:$//;
$localmessaging{values} =~ s/:$//;
$localmessaging{values1} =~ s/:$//;
$localmessaging{values_bytes} =~ s/:$//;
$localmessaging{values1_bytes} =~ s/:$//;
$localspam{values} =~ s/:$//;
$localvirus{values} =~ s/:$//;
$localdsn{values} =~ s/:$//;
$localmessaging{nbrcpt} =~ s/:$//;
$localmessaging{nbsender} =~ s/:$//;
my $file = "$CONFIG{OUT_DIR}/$hostname/$year/$month/$day/cache.pm\U$DOMAIN\E";
print "Writing cache file: $file\n" if ($CONFIG{DEBUG});
if (open(OUT, ">$file")) {
print OUT "\%::auth = (\n";
foreach my $type (keys %localauth) {
print OUT "'$type' => {";
print OUT "'values' => '$localauth{$type}{values}',";
print OUT "'lbls' => '$lbls',";
print OUT "'x_label' => 'Day of the month',";
foreach my $mech (keys %{$localauth{$type}}) {
next if (grep(/^$mech$/,'lbls','x_label','values'));
print OUT "'$mech' => '$localauth{$type}{$mech}',";
}
print OUT "},\n";
}
print OUT ");\n\n";
%localauth = ();
print OUT "\%::messaging = (\n";
print OUT "'inbound' => '$localmessaging{inbound}',\n";
print OUT "'inbound_bytes' => '$localmessaging{inbound_bytes}',\n";
print OUT "'local_inbound' => '$localmessaging{local_inbound}',\n";
print OUT "'local_inbound_bytes' => '$localmessaging{local_inbound_bytes}',\n";
print OUT "'total_inbound' => '$localmessaging{total_inbound}',\n";
print OUT "'total_inbound_bytes' => '$localmessaging{total_inbound_bytes}',\n";
print OUT "'outbound' => '$localmessaging{outbound}',\n";
print OUT "'outbound_bytes' => '$localmessaging{outbound_bytes}',\n";
print OUT "'local_outbound' => '$localmessaging{local_outbound}',\n";
print OUT "'local_outbound_bytes' => '$localmessaging{local_outbound_bytes}',\n";
print OUT "'total_outbound' => '$localmessaging{total_outbound}',\n";
print OUT "'total_outbound_bytes' => '$localmessaging{total_outbound_bytes}',\n";
print OUT "'lbls' => '$lbls',\n";
print OUT "'x_label' => 'Day of the month',\n";
print OUT "'values' => '$localmessaging{values}',\n";
print OUT "'values1' => '$localmessaging{values1}',\n";
print OUT "'values_bytes' => '$localmessaging{values_bytes}',\n";
print OUT "'values1_bytes' => '$localmessaging{values1_bytes}',\n";
print OUT "'nbsender' => '$localmessaging{nbsender}',\n";
print OUT "'nbrcpt' => '$localmessaging{nbrcpt}',\n";
print OUT ");\n\n";
%localmessaging = ();
print OUT "\%::spam = (\n";
print OUT "'inbound' => '$localspam{inbound}',\n";
print OUT "'inbound_bytes' => '$localspam{inbound_bytes}',\n";
print OUT "'local_inbound' => '$localspam{local_inbound}',\n";
print OUT "'local_inbound_bytes' => '$localspam{local_inbound_bytes}',\n";
print OUT "'total_inbound' => '$localspam{total_inbound}',\n";
print OUT "'total_inbound_bytes' => '$localspam{total_inbound_bytes}',\n";
print OUT "'outbound' => '$localspam{outbound}',\n";
print OUT "'outbound_bytes' => '$localspam{outbound_bytes}',\n";
print OUT "'local_outbound' => '$localspam{local_outbound}',\n";
print OUT "'local_outbound_bytes' => '$localspam{local_outbound_bytes}',\n";
print OUT "'total_outbound' => '$localspam{total_outbound}',\n";
print OUT "'total_outbound_bytes' => '$localspam{total_outbound_bytes}',\n";
print OUT "'lbls' => '$lbls',\n";
print OUT "'x_label' => 'Day of the month',\n";
print OUT "'values' => '$localspam{values}',\n";
print OUT "'Ext_Int' => '$localspam{Ext_Int}',\n";
print OUT "'Int_Int' => '$localspam{Int_Int}',\n";
print OUT "'Int_Ext' => '$localspam{Int_Ext}',\n";
print OUT "'Ext_Ext' => '$localspam{Ext_Ext}',\n";
print OUT "'Ext_Int_bytes' => '$localspam{Ext_Int_bytes}',\n";
print OUT "'Int_Int_bytes' => '$localspam{Int_Int_bytes}',\n";
print OUT "'Int_Ext_bytes' => '$localspam{Int_Ext_bytes}',\n";
print OUT "'Ext_Ext_bytes' => '$localspam{Ext_Ext_bytes}',\n";
print OUT ");\n\n";
%localspam = ();
print OUT "\%::reject = (\n";
print OUT "'inbound' => '$localreject{inbound}',\n";
print OUT "'inbound_bytes' => '$localreject{inbound_bytes}',\n";
print OUT "'local_inbound' => '$localreject{local_inbound}',\n";
print OUT "'local_inbound_bytes' => '$localreject{local_inbound_bytes}',\n";
print OUT "'total_inbound' => '$localreject{total_inbound}',\n";
print OUT "'total_inbound_bytes' => '$localreject{total_inbound_bytes}',\n";
print OUT ");\n\n";
%localreject = ();
print OUT "\%::postgrey = (\n";
print OUT "'reason' => {";
foreach my $k (keys %{$localpostgrey{reason}}) {
print OUT "\t'$k' => '$localpostgrey{reason}{$k}',";
}
print OUT "},\n";
print OUT ");\n\n";
%localpostgrey = ();
print OUT "\%::spf_dkim = (\n";
print OUT "'spf' => {\n";
foreach my $r (keys %{$localspf_dkim{spf}}) {
print OUT "\t'$r' => {\n";
foreach my $s (keys %{$localspf_dkim{spf}{$r}}) {
print OUT "\t\t'$s' => { ";
foreach my $v (keys %{$localspf_dkim{spf}{$r}{$s}}) {
print OUT "'$v' => '$localspf_dkim{spf}{$r}{$s}{$v}',";
}
print OUT " },\n";
}
print OUT "\t},\n";
}
print OUT "},\n";
print OUT "'dkim' => {\n";
foreach my $r (keys %{$localspf_dkim{dkim}}) {
print OUT "\t'$r' => {\n";
foreach my $s (keys %{$localspf_dkim{dkim}{$r}}) {
print OUT "\t\t'$s' => '$localspf_dkim{dkim}{$r}{$s}',\n";
}
print OUT "\t},\n";
}
print OUT "},\n";
print OUT ");\n\n";
%localspf_dkim = ();
print OUT "\%::virus = (\n";
print OUT "'inbound' => '$localvirus{inbound}',\n";
print OUT "'inbound_bytes' => '$localvirus{inbound_bytes}',\n";
print OUT "'local_inbound' => '$localvirus{local_inbound}',\n";
print OUT "'local_inbound_bytes' => '$localvirus{local_inbound_bytes}',\n";
print OUT "'total_inbound' => '$localvirus{total_inbound}',\n";
print OUT "'total_inbound_bytes' => '$localvirus{total_inbound_bytes}',\n";
print OUT "'outbound' => '$localvirus{outbound}',\n";
print OUT "'outbound_bytes' => '$localvirus{outbound_bytes}',\n";
print OUT "'local_outbound' => '$localvirus{local_outbound}',\n";
print OUT "'local_outbound_bytes' => '$localvirus{local_outbound_bytes}',\n";
print OUT "'total_outbound' => '$localvirus{total_outbound}',\n";
print OUT "'total_outbound_bytes' => '$localvirus{total_outbound_bytes}',\n";
print OUT "'lbls' => '$lbls',\n";
print OUT "'x_label' => 'Day of the month',\n";
print OUT "'values' => '$localvirus{values}',\n";
print OUT "'Ext_Int' => '$localvirus{Ext_Int}',\n";
print OUT "'Int_Int' => '$localvirus{Int_Int}',\n";
print OUT "'Int_Ext' => '$localvirus{Int_Ext}',\n";
print OUT "'Ext_Ext' => '$localvirus{Ext_Ext}',\n";
print OUT "'Ext_Int_bytes' => '$localvirus{Ext_Int_bytes}',\n";
print OUT "'Int_Int_bytes' => '$localvirus{Int_Int_bytes}',\n";
print OUT "'Int_Ext_bytes' => '$localvirus{Int_Ext_bytes}',\n";
print OUT "'Ext_Ext_bytes' => '$localvirus{Ext_Ext_bytes}',\n";
print OUT ");\n\n";
%localvirus = ();
print OUT "\%::dsn = (\n";
print OUT "'outbound' => '$localdsn{outbound}',\n";
print OUT "'local_outbound' => '$localdsn{local_outbound}',\n";
print OUT "'total_outbound' => '$localdsn{total_outbound}',\n";
print OUT "'error' => '$localdsn{error}',\n";
print OUT "'lbls' => '$lbls',\n";
print OUT "'x_label' => 'Day of the month',\n";
print OUT "'values' => '$localdsn{values}',\n";
print OUT "'Ext_Int' => '$localdsn{Ext_Int}',\n";
print OUT "'Int_Int' => '$localdsn{Int_Int}',\n";
print OUT "'Int_Ext' => '$localdsn{Int_Ext}',\n";
print OUT "'Ext_Ext' => '$localdsn{Ext_Ext}',\n";
print OUT ");\n\n";
%localdsn = ();
print OUT "\%::err = (\n";
print OUT "'inbound' => '$localerr{inbound}',\n";
print OUT "'inbound_bytes' => '$localerr{inbound_bytes}',\n";
print OUT "'local_inbound' => '$localerr{local_inbound}',\n";
print OUT "'local_inbound_bytes' => '$localerr{local_inbound_bytes}',\n";
print OUT "'total_inbound' => '$localerr{total_inbound}',\n";
print OUT "'total_inbound_bytes' => '$localerr{total_inbound_bytes}',\n";
print OUT ");\n\n";
%localerr = ();
print OUT "\%::GLOBAL_STATUS = (\n";
foreach my $k (keys %localGLOBAL_STATUS) {
my $slbl = $k;
$slbl =~ s/'/\\'/g;
print OUT "'$slbl' => '$localGLOBAL_STATUS{$k}',\n";
}
print OUT ");\n\n";
%localGLOBAL_STATUS = ();
print OUT "\%::starttls = (\n";
foreach my $v (sort keys %localstarttls) {
my $slbl = $v;
$slbl =~ s/'/\\'/g;
print OUT "'$slbl' => '$localstarttls{$v}',\n";
}
print OUT ");\n\n";
%localstarttls = ();
my $elbls = 'Ext -> Int:Ext -> Ext:Int -> Int:Int -> Ext';
print OUT "\%::delivery = (\n";
print OUT "'lbls' => '$elbls',\n";
print OUT "'x_label' => 'Day of the month',\n";
print OUT "'Ext_Int' => '$localdelivery{Ext_Int}',\n";
print OUT "'Int_Int' => '$localdelivery{Int_Int}',\n";
print OUT "'Int_Ext' => '$localdelivery{Int_Ext}',\n";
print OUT "'Ext_Ext' => '$localdelivery{Ext_Ext}',\n";
print OUT "'Ext_Int_bytes' => '$localdelivery{Ext_Int_bytes}',\n";
print OUT "'Int_Int_bytes' => '$localdelivery{Int_Int_bytes}',\n";
print OUT "'Int_Ext_bytes' => '$localdelivery{Int_Ext_bytes}',\n";
print OUT "'Ext_Ext_bytes' => '$localdelivery{Ext_Ext_bytes}',\n";
print OUT ");\n\n";
%localdelivery = ();
# Top SMTP Auth statistics
my $top = 0;
print OUT "\%::topauth = (\n";
print OUT "'relay' => {";
foreach my $d (sort { $localtopauth{relay}{$b} <=> $localtopauth{relay}{$a} } keys %{$localtopauth{relay}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopauth{relay}{$d}',";
$top++;
}
print OUT "},\n";
delete $localtopauth{relay};
$top = 0;
print OUT "'mech' => {";
foreach my $d (sort { $localtopauth{mech}{$b} <=> $localtopauth{mech}{$a} } keys %{$localtopauth{mech}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopauth{mech}{$d}',";
$top++;
}
print OUT "},\n";
delete $localtopauth{mech};
$top = 0;
print OUT "'authid' => {";
foreach my $d (sort { $localtopauth{authid}{$b} <=> $localtopauth{authid}{$a} } keys %{$localtopauth{authid}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopauth{authid}{$d}',";
$top++;
}
print OUT "},\n";
print OUT ");\n\n";
%localtopauth = ();
# Top sender statistics
$top = 0;
print OUT "\%::topsender = (\n";
print OUT "'domain' => {";
foreach my $d (sort { $localtopsender{domain}{$b} <=> $localtopsender{domain}{$a} } keys %{$localtopsender{domain}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopsender{domain}{$d}',";
$top++;
}
print OUT "},\n";
delete $localtopsender{domain};
$top = 0;
print OUT "'relay' => {";
foreach my $d (sort { $localtopsender{relay}{$b} <=> $localtopsender{relay}{$a} } keys %{$localtopsender{relay}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopsender{relay}{$d}',";
$top++;
}
print OUT "},\n";
delete $localtopsender{relay};
$top = 0;
print OUT "'email' => {";
foreach my $d (sort { $localtopsender{email}{$b} <=> $localtopsender{email}{$a} } keys %{$localtopsender{email}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopsender{email}{$d}',";
$top++;
}
print OUT "},\n";
print OUT ");\n\n";
%localtopsender = ();
# Top recipient statistics
$top = 0;
print OUT "\%::toprcpt = (\n";
print OUT "'domain' => {";
foreach my $d (sort { $localtoprcpt{domain}{$b} <=> $localtoprcpt{domain}{$a} } keys %{$localtoprcpt{domain}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtoprcpt{domain}{$d}',";
$top++;
}
print OUT "},\n";
delete $localtoprcpt{domain};
$top = 0;
print OUT "'relay' => {";
foreach my $d (sort { $localtoprcpt{relay}{$b} <=> $localtoprcpt{relay}{$a} } keys %{$localtoprcpt{relay}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtoprcpt{relay}{$d}',";
$top++;
}
print OUT "},\n";
delete $localtoprcpt{relay};
$top = 0;
print OUT "'email' => {";
foreach my $d (sort { $localtoprcpt{email}{$b} <=> $localtoprcpt{email}{$a} } keys %{$localtoprcpt{email}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtoprcpt{email}{$d}',";
$top++;
}
print OUT "},\n";
print OUT ");\n\n";
%localtoprcpt = ();
# Top rejection statistics
$top = 0;
print OUT "\%::topreject = (\n";
print OUT "'rule' => {";
foreach my $d (sort { $localtopreject{rule}{$b} <=> $localtopreject{rule}{$a} } keys %{$localtopreject{rule}}) {
last if ($top == $CONFIG{TOP});
my $c = $localtopreject{rule}{$d};
$d =~ s/'/\\'/g;
print OUT "'$d' => '$c',";
$top++;
}
print OUT "},\n";
delete $localtopreject{rule};
$top = 0;
print OUT "'domain' => {";
foreach my $d (sort { $localtopreject{domain}{$b} <=> $localtopreject{domain}{$a} } keys %{$localtopreject{domain}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopreject{domain}{$d}',";
$top++;
}
print OUT "},\n";
delete $localtopreject{domain};
$top = 0;
print OUT "'relay' => {";
foreach my $d (sort { $localtopreject{relay}{$b} <=> $localtopreject{relay}{$a} } keys %{$localtopreject{relay}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopreject{relay}{$d}',";
$top++;
}
print OUT "},\n";
delete $localtopreject{relay};
$top = 0;
print OUT "'chck_status' => {";
foreach my $d (sort { $localtopreject{chck_status}{$b} <=> $localtopreject{chck_status}{$a} } keys %{$localtopreject{chck_status}}) {
last if ($top == $CONFIG{TOP});
my $c = $localtopreject{chck_status}{$d};
$d =~ s/'/\\'/g;
print OUT "'$d' => '$c',";
$top++;
}
print OUT "},\n";
delete $localtopreject{chck_status};
$top = 0;
print OUT "'sender' => {";
foreach my $d (sort { $localtopreject{sender}{$b} <=> $localtopreject{sender}{$a} } keys %{$localtopreject{sender}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopreject{sender}{$d}',";
$top++;
}
print OUT "},\n";
print OUT ");\n\n";
%localtopreject = ();
# Top virus statistics
$top = 0;
print OUT "\%::topvirus = (\n";
print OUT "'virus' => {";
foreach my $d (sort { $localtopvirus{virus}{$b} <=> $localtopvirus{virus}{$a} } keys %{$localtopvirus{virus}}) {
last if ($top == $CONFIG{TOP});
my $c = $localtopvirus{virus}{$d};
$d =~ s/'/\\'/g;
print OUT "'$d' => '$c',";
$top++;
}
print OUT "},\n";
delete $localtopvirus{virus};
$top = 0;
print OUT "'sender' => {";
foreach my $d (sort { $localtopvirus{sender}{$b} <=> $localtopvirus{sender}{$a} } keys %{$localtopvirus{sender}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopvirus{sender}{$d}',";
$top++;
}
print OUT "},\n";
delete $localtopvirus{sender};
$top = 0;
print OUT "'relay' => {";
foreach my $d (sort { $localtopvirus{relay}{$b} <=> $localtopvirus{relay}{$a} } keys %{$localtopvirus{relay}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopvirus{relay}{$d}',";
$top++;
}
print OUT "},\n";
delete $localtopvirus{relay};
$top = 0;
print OUT "'file' => {";
foreach my $d (sort { $localtopvirus{file}{$b} <=> $localtopvirus{file}{$a} } keys %{$localtopvirus{file}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopvirus{file}{$d}',";
$top++;
}
print OUT "},\n";
delete $localtopvirus{file};
$top = 0;
print OUT "'rcpt' => {";
foreach my $d (sort { $localtopvirus{rcpt}{$b} <=> $localtopvirus{rcpt}{$a} } keys %{$localtopvirus{rcpt}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopvirus{rcpt}{$d}',";
$top++;
}
print OUT "},\n";
print OUT ");\n\n";
%localtopvirus = ();
# Top dsn statistics
$top = 0;
print OUT "\%::topdsn = (\n";
print OUT "'dsnstatus' => {";
foreach my $d (sort { $localtopdsn{dsnstatus}{$b} <=> $localtopdsn{dsnstatus}{$a} } keys %{$localtopdsn{dsnstatus}}) {
last if ($top == $CONFIG{TOP});
my $c = $localtopdsn{dsnstatus}{$d};
$d =~ s/'/\\'/g;
print OUT "'$d' => '$c',";
$top++;
}
print OUT "},\n";
delete $localtopdsn{dsnstatus};
$top = 0;
print OUT "'sender' => {";
foreach my $d (sort { $localtopdsn{sender}{$b} <=> $localtopdsn{sender}{$a} } keys %{$localtopdsn{sender}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopdsn{sender}{$d}',";
$top++;
}
print OUT "},\n";
delete $localtopdsn{sender};
$top = 0;
print OUT "'relay' => {";
foreach my $d (sort { $localtopdsn{relay}{$b} <=> $localtopdsn{relay}{$a} } keys %{$localtopdsn{relay}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopdsn{relay}{$d}',";
$top++;
}
print OUT "},\n";
delete $localtopdsn{relay};
$top = 0;
print OUT "'rcpt' => {";
foreach my $d (sort { $localtopdsn{rcpt}{$b} <=> $localtopdsn{rcpt}{$a} } keys %{$localtopdsn{rcpt}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopdsn{rcpt}{$d}',";
$top++;
}
print OUT "},\n";
print OUT ");\n\n";
%localtopdsn = ();
# Top spam statistics
$top = 0;
print OUT "\%::topspam = (\n";
print OUT "'rule' => {";
foreach my $d (sort { $localtopspam{rule}{$b} <=> $localtopspam{rule}{$a} } keys %{$localtopspam{rule}}) {
last if ($top == $CONFIG{TOP});
my $c = $localtopspam{rule}{$d};
$d =~ s/'/\\'/g;
print OUT "'$d' => '$c',";
$top++;
}
print OUT "},";
delete $localtopspam{rule};
$top = 0;
print OUT "'domain' => {";
foreach my $d (sort { $localtopspam{domain}{$b} <=> $localtopspam{domain}{$a} } keys %{$localtopspam{domain}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopspam{domain}{$d}',";
$top++;
}
print OUT "},";
delete $localtopspam{domain};
$top = 0;
print OUT "'sender_relay' => {";
foreach my $d (sort { $localtopspam{sender_relay}{$b} <=> $localtopspam{sender_relay}{$a} } keys %{$localtopspam{sender_relay}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopspam{sender_relay}{$d}',";
$top++;
}
print OUT "},";
delete $localtopspam{sender_relay};
$top = 0;
print OUT "'sender' => {";
foreach my $d (sort { $localtopspam{sender}{$b} <=> $localtopspam{sender}{$a} } keys %{$localtopspam{sender}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopspam{sender}{$d}',";
$top++;
}
print OUT "},";
delete $localtopspam{sender};
$top = 0;
print OUT "'rcpt' => {";
foreach my $d (sort { $localtopspam{rcpt}{$b} <=> $localtopspam{rcpt}{$a} } keys %{$localtopspam{rcpt}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopspam{rcpt}{$d}',";
$top++;
}
print OUT "},";
print OUT ");\n\n";
%localtopspam = ();
# Top system message statistics
$top = 0;
print OUT "\%::toperr = (\n";
foreach my $m (sort { $localtopspam{$b} <=> $localtopspam{$a} } keys %localtoperr) {
my $c = $localtoperr{$m};
$m =~ s/'/\\'/g;
print OUT "'$m' => $c,\n";
}
print OUT ");\n";
%localtoperr = ();
# Top postgrey statistics
$top = 0;
print OUT "\%::toppostgrey = (\n";
print OUT "'sender' => {";
foreach my $d (sort { $localtoppostgrey{sender}{$b} <=> $localtoppostgrey{sender}{$a} } keys %{$localtoppostgrey{sender}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtoppostgrey{sender}{$d}',";
$top++;
}
print OUT "},\n";
delete $localtoppostgrey{sender};
$top = 0;
print OUT "'sender_relay' => {";
foreach my $d (sort { $localtoppostgrey{sender_relay}{$b} <=> $localtoppostgrey{sender_relay}{$a} } keys %{$localtoppostgrey{sender_relay}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtoppostgrey{sender_relay}{$d}',";
$top++;
}
print OUT "},\n";
delete $localtoppostgrey{sender_relay};
$top= 0;
print OUT "'domain' => {";
foreach my $d (sort { $localtoppostgrey{domain}{$b} <=> $localtoppostgrey{domain}{$a} } keys %{$localtoppostgrey{domain}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtoppostgrey{domain}{$d}',";
$top++;
}
print OUT "},\n";
delete $localtoppostgrey{domain};
$top= 0;
print OUT "'reason' => {";
foreach my $d (sort { $localtoppostgrey{reason}{$b} <=> $localtoppostgrey{reason}{$a} } keys %{$localtoppostgrey{reason}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtoppostgrey{reason}{$d}',";
$top++;
}
print OUT "},\n";
delete $localtoppostgrey{reason};
$top= 0;
print OUT "'rcpt' => {";
foreach my $d (sort { $localtoppostgrey{rcpt}{$b} <=> $localtoppostgrey{rcpt}{$a} } keys %{$localtoppostgrey{rcpt}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtoppostgrey{rcpt}{$d}',";
$top++;
}
print OUT "},\n";
print OUT ");\n\n";
%localtoppostgrey = ();
# Top spam detail statistics
$top = 0;
print OUT "\%::topspamdetail = (\n";
foreach my $t (sort keys %localtopspamdetail) {
print OUT "'$t' => {";
print OUT "'rule' => {";
foreach my $d (sort { $localtopspamdetail{$t}{rule}{$b} <=> $localtopspamdetail{$t}{rule}{$a} } keys %{$localtopspamdetail{$t}{rule}}) {
last if ($top == $CONFIG{TOP});
my $c = $localtopspamdetail{$t}{rule}{$d};
$d =~ s/'/\\'/g;
print OUT "'$d' => '$c',";
$top++;
}
print OUT "},";
delete $localtopspamdetail{$t}{rule};
$top = 0;
print OUT "'score' => {";
foreach my $d (sort { $localtopspamdetail{$t}{score}{$b} <=> $localtopspamdetail{$t}{score}{$a} } keys %{$localtopspamdetail{$t}{score}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopspamdetail{$t}{score}{$d}',";
$top++;
}
print OUT "},";
delete $localtopspamdetail{$t}{score};
$top = 0;
print OUT "'cache' => {";
foreach my $d (sort { $localtopspamdetail{$t}{cache}{$b} <=> $localtopspamdetail{$t}{cache}{$a} } keys %{$localtopspamdetail{$t}{cache}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopspamdetail{$t}{cache}{$d}',";
$top++;
}
print OUT "},";
delete $localtopspamdetail{$t}{cache};
$top = 0;
print OUT "'autolearn' => {";
foreach my $d (sort { $localtopspamdetail{$t}{autolearn}{$b} <=> $localtopspamdetail{$t}{autolearn}{$a} } keys %{$localtopspamdetail{$t}{autolearn}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopspamdetail{$t}{autolearn}{$d}',";
$top++;
}
print OUT "},";
delete $localtopspamdetail{$t}{autolearn};
$top = 0;
print OUT "},";
}
print OUT ");\n";
close(OUT);
} else {
&logerror("can't write cache file $file: $!");
}
}
####
# Month cache statistics
####
sub do_month_cache
{
my ($hostname, $DOMAIN, $year, $month, $curmonth) = @_;
if (!$DOMAIN && -e "$CONFIG{OUT_DIR}/$hostname/$year/$month/cache.pm" && ("$year$month" < $curmonth)) {
# reduce disk space storage by deleting or archiving data file
if (!$CONFIG{WEEKLY_FREE_SPACE}) {
&free_space("$CONFIG{OUT_DIR}/$hostname/$year/$month");
return;
}
}
if (-e "$CONFIG{OUT_DIR}/$hostname/$year/$month/cache.pm\U$DOMAIN\E" && ("$year$month" < $curmonth)) {
return;
}
print "Reading statistics from $CONFIG{OUT_DIR}/$hostname/$year/$month\n" if ($CONFIG{DEBUG});
my %localtopsender = ();
my %localtoprcpt = ();
my %localtopspam = ();
my %localtopvirus = ();
my %localtopdsn = ();
my %localtopreject = ();
my %localtoperr = ();
my %localdelivery = ();
my %localmessaging = ();
my %localspam = ();
my %localvirus = ();
my %localdsn = ();
my %localreject = ();
my %localerr = ();
my %localGLOBAL_STATUS = ();
my %localtopspamdetail = ();
my %localauth = ();
my %localtopauth = ();
my %localpostgrey = ();
my %localtoppostgrey = ();
my %localstarttls = ();
my %localspf_dkim = ();
my $lbls = '';
foreach my $day ("01" .. "31") {
$lbls .= "$day:";
if (!-e "$CONFIG{OUT_DIR}/$hostname/$year/$month/$day/cache.pm\U$DOMAIN\E") {
$localmessaging{values} .= '0:';
$localmessaging{values1} .= '0:';
$localmessaging{values_bytes} .= '0:';
$localmessaging{values1_bytes} .= '0:';
$localspam{values} .= '0:';
$localvirus{values} .= '0:';
$localdsn{values} .= '0:';
$localmessaging{nbsender} .= '0:';
$localmessaging{nbrcpt} .= '0:';
next;
} else {
&clean_globals();
my $file = "$CONFIG{OUT_DIR}/$hostname/$year/$month/$day/cache.pm\U$DOMAIN\E";
print "Loading cache statistics from $file\n" if ($CONFIG{DEBUG});
do "$file";
foreach my $k (keys %messaging) {
if (!grep(/^$k$/, 'lbls','x_label','values','values1','values_bytes','values1_bytes','nbsender','nbrcpt')) {
$localmessaging{$k} += $messaging{$k};
}
}
$localmessaging{values} .= ($messaging{total_inbound} || 0) . ':';
$localmessaging{values1} .= ($messaging{total_outbound} || 0) . ':';
$localmessaging{values_bytes} .= ($messaging{total_inbound_bytes} || 0) . ':';
$localmessaging{values1_bytes} .= ($messaging{total_outbound_bytes} || 0) . ':';
my $tmp = 0;
foreach (split(/:/, $messaging{nbsender})) {
$tmp += $_;
}
$localmessaging{nbsender} .= $tmp . ':';
$tmp = 0;
foreach (split(/:/, $messaging{nbrcpt})) {
$tmp += $_;
}
$localmessaging{nbrcpt} .= $tmp . ':';
%messaging = ();
foreach my $t (keys %auth) {
foreach my $m (keys %{$auth{$t}}) {
if (!grep(/^$m$/, 'lbls','x_label','values')) {
$localauth{$t}{$m} += $auth{$t}{$m};
$localauth{$t}{values}{"$day"} += $auth{$t}{$m};
}
}
}
%auth = ();
foreach my $k (keys %spam) {
if (!grep(/^$k$/, 'lbls','x_label','values')) {
$localspam{$k} += $spam{$k};
}
}
$localspam{values} .= ($spam{total_inbound} || 0) . ':';
%spam = ();
foreach my $k (keys %reject) {
if (!grep(/^$k$/, 'lbls','x_label','values')) {
$localreject{$k} += $reject{$k};
}
}
%reject = ();
foreach my $k (keys %{$postgrey{reason}}) {
$localpostgrey{reason}{$k} += $postgrey{reason}{$k};
}
%postgrey = ();
foreach my $r (keys %{$spf_dkim{spf}}) {
foreach my $k (keys %{$spf_dkim{spf}{$r}{status}}) {
$localspf_dkim{spf}{$r}{status}{$k} += $spf_dkim{spf}{$r}{status}{$k};
}
foreach my $k (keys %{$spf_dkim{spf}{$r}{domain}}) {
$localspf_dkim{spf}{$r}{domain}{$k} += $spf_dkim{spf}{$r}{domain}{$k};
}
}
foreach my $r (keys %{$spf_dkim{dkim}{status}}) {
$localspf_dkim{dkim}{status}{$r} += $spf_dkim{dkim}{status}{$r};
}
%spf_dkim = ();
foreach my $k (keys %virus) {
if (!grep(/^$k$/, 'lbls','x_label','values')) {
$localvirus{$k} += $virus{$k};
}
}
$localvirus{values} .= ($virus{total_inbound} || 0) . ':';
%virus = ();
foreach my $k (keys %dsn) {
if (!grep(/^$k$/, 'lbls','x_label','values')) {
$localdsn{$k} += $dsn{$k};
}
}
$localdsn{values} .= ($dsn{total_outbound} || 0) . ':';
%dsn = ();
foreach my $k (keys %err) {
if (!grep(/^$k$/, 'lbls','x_label','values')) {
$localerr{$k} += $err{$k};
}
}
%err = ();
foreach my $k (keys %GLOBAL_STATUS) {
$localGLOBAL_STATUS{$k} += $GLOBAL_STATUS{$k};
}
%GLOBAL_STATUS = ();
foreach my $k (keys %delivery) {
if (!grep(/^$k$/, 'lbls','x_label')) {
$localdelivery{$k} += $delivery{$k};
}
}
foreach my $k (keys %topsender) {
foreach my $d (keys %{$topsender{$k}}) {
$localtopsender{$k}{$d} += $topsender{$k}{$d} || 0;
}
}
%topsender = ();
foreach my $k (keys %toprcpt) {
foreach my $d (keys %{$toprcpt{$k}}) {
$localtoprcpt{$k}{$d} += $toprcpt{$k}{$d} || 0;
}
}
%toprcpt = ();
foreach my $k (keys %topreject) {
foreach my $d (keys %{$topreject{$k}}) {
$localtopreject{$k}{$d} += $topreject{$k}{$d} || 0;
}
}
%topreject = ();
foreach my $k (keys %topvirus) {
foreach my $d (keys %{$topvirus{$k}}) {
$localtopvirus{$k}{$d} += $topvirus{$k}{$d} || 0;
}
}
%topvirus = ();
foreach my $k (keys %topdsn) {
foreach my $d (keys %{$topdsn{$k}}) {
$localtopdsn{$k}{$d} += $topdsn{$k}{$d} || 0;
}
}
%topdsn = ();
foreach my $k (keys %topspam) {
foreach my $d (keys %{$topspam{$k}}) {
$localtopspam{$k}{$d} += $topspam{$k}{$d} || 0;
}
}
%topspam = ();
foreach my $k (keys %toperr) {
$localtoperr{$k} += $toperr{$k} || 0;
}
%toperr = ();
foreach my $k (keys %toppostgrey) {
foreach my $d (keys %{$toppostgrey{$k}}) {
$localtoppostgrey{$k}{$d} += $toppostgrey{$k}{$d} || 0;
}
}
%toppostgrey = ();
foreach my $t (keys %topspamdetail) {
foreach my $k (keys %{$topspamdetail{$t}}) {
foreach my $d (keys %{$topspamdetail{$t}{$k}}) {
$localtopspamdetail{$t}{$k}{$d} += $topspamdetail{$t}{$k}{$d} || 0;
}
}
}
%topspamdetail = ();
foreach my $k (keys %topauth) {
foreach my $d (keys %{$topauth{$k}}) {
$localtopauth{$k}{$d} += $topauth{$k}{$d} || 0;
}
}
%topauth = ();
foreach my $k (keys %starttls) {
$localstarttls{$k} += $starttls{$k};
}
%starttls = ();
}
}
my %authval = ();
foreach my $day ("01" .. "31") {
foreach my $t (keys %localauth) {
$authval{$t} .= ($localauth{$t}{values}{"$day"} || 0) . ':';
}
}
foreach my $t (keys %localauth) {
delete $localauth{$t}{values};
$localauth{$t}{values} = $authval{$t};
$localauth{$t}{lbls} =~ s/:$//;
$localauth{$t}{values} =~ s/:$//;
}
$lbls =~ s/:$//;
$localmessaging{values} =~ s/:$//;
$localmessaging{values1} =~ s/:$//;
$localmessaging{values_bytes} =~ s/:$//;
$localmessaging{values1_bytes} =~ s/:$//;
$localspam{values} =~ s/:$//;
$localvirus{values} =~ s/:$//;
$localdsn{values} =~ s/:$//;
$localmessaging{nbrcpt} =~ s/:$//;
$localmessaging{nbsender} =~ s/:$//;
my $file = "$CONFIG{OUT_DIR}/$hostname/$year/$month/cache.pm\U$DOMAIN\E";
print "Writing cache file: $file\n" if ($CONFIG{DEBUG});
if (open(OUT, ">$file")) {
print OUT "\%::auth = (\n";
foreach my $type (keys %localauth) {
print OUT "'$type' => {";
print OUT "'values' => '$localauth{$type}{values}',";
print OUT "'lbls' => '$lbls',";
print OUT "'x_label' => 'Month of the year',";
foreach my $mech (keys %{$localauth{$type}}) {
next if (grep(/^$mech$/,'lbls','x_label','values'));
print OUT "'$mech' => '$localauth{$type}{$mech}',";
}
print OUT "},\n";
}
print OUT ");\n\n";
%localauth = ();
print OUT "\%::messaging = (\n";
print OUT "'inbound' => '$localmessaging{inbound}',\n";
print OUT "'inbound_bytes' => '$localmessaging{inbound_bytes}',\n";
print OUT "'local_inbound' => '$localmessaging{local_inbound}',\n";
print OUT "'local_inbound_bytes' => '$localmessaging{local_inbound_bytes}',\n";
print OUT "'total_inbound' => '$localmessaging{total_inbound}',\n";
print OUT "'total_inbound_bytes' => '$localmessaging{total_inbound_bytes}',\n";
print OUT "'outbound' => '$localmessaging{outbound}',\n";
print OUT "'outbound_bytes' => '$localmessaging{outbound_bytes}',\n";
print OUT "'local_outbound' => '$localmessaging{local_outbound}',\n";
print OUT "'local_outbound_bytes' => '$localmessaging{local_outbound_bytes}',\n";
print OUT "'total_outbound' => '$localmessaging{total_outbound}',\n";
print OUT "'total_outbound_bytes' => '$localmessaging{total_outbound_bytes}',\n";
print OUT "'lbls' => '$lbls',\n";
print OUT "'x_label' => 'Month of the year',\n";
print OUT "'values' => '$localmessaging{values}',\n";
print OUT "'values1' => '$localmessaging{values1}',\n";
print OUT "'values_bytes' => '$localmessaging{values_bytes}',\n";
print OUT "'values1_bytes' => '$localmessaging{values1_bytes}',\n";
print OUT "'nbsender' => '$localmessaging{nbsender}',\n";
print OUT "'nbrcpt' => '$localmessaging{nbrcpt}',\n";
print OUT ");\n\n";
%localmessaging = ();
print OUT "\%::spam = (\n";
print OUT "'inbound' => '$localspam{inbound}',\n";
print OUT "'inbound_bytes' => '$localspam{inbound_bytes}',\n";
print OUT "'local_inbound' => '$localspam{local_inbound}',\n";
print OUT "'local_inbound_bytes' => '$localspam{local_inbound_bytes}',\n";
print OUT "'total_inbound' => '$localspam{total_inbound}',\n";
print OUT "'total_inbound_bytes' => '$localspam{total_inbound_bytes}',\n";
print OUT "'outbound' => '$localspam{outbound}',\n";
print OUT "'outbound_bytes' => '$localspam{outbound_bytes}',\n";
print OUT "'local_outbound' => '$localspam{local_outbound}',\n";
print OUT "'local_outbound_bytes' => '$localspam{local_outbound_bytes}',\n";
print OUT "'total_outbound' => '$localspam{total_outbound}',\n";
print OUT "'total_outbound_bytes' => '$localspam{total_outbound_bytes}',\n";
print OUT "'lbls' => '$lbls',\n";
print OUT "'x_label' => 'Month of the year',\n";
print OUT "'values' => '$localspam{values}',\n";
print OUT "'Ext_Int' => '$localspam{Ext_Int}',\n";
print OUT "'Int_Int' => '$localspam{Int_Int}',\n";
print OUT "'Int_Ext' => '$localspam{Int_Ext}',\n";
print OUT "'Ext_Ext' => '$localspam{Ext_Ext}',\n";
print OUT "'Ext_Int_bytes' => '$localspam{Ext_Int_bytes}',\n";
print OUT "'Int_Int_bytes' => '$localspam{Int_Int_bytes}',\n";
print OUT "'Int_Ext_bytes' => '$localspam{Int_Ext_bytes}',\n";
print OUT "'Ext_Ext_bytes' => '$localspam{Ext_Ext_bytes}',\n";
print OUT ");\n\n";
%localspam = ();
print OUT "\%::reject = (\n";
print OUT "'inbound' => '$localreject{inbound}',\n";
print OUT "'inbound_bytes' => '$localreject{inbound_bytes}',\n";
print OUT "'local_inbound' => '$localreject{local_inbound}',\n";
print OUT "'local_inbound_bytes' => '$localreject{local_inbound_bytes}',\n";
print OUT "'total_inbound' => '$localreject{total_inbound}',\n";
print OUT "'total_inbound_bytes' => '$localreject{total_inbound_bytes}',\n";
print OUT ");\n\n";
%localreject = ();
print OUT "\%::postgrey = (\n";
print OUT "'reason' => {";
foreach my $k (keys %{$localpostgrey{reason}}) {
print OUT "\t'$k' => '$localpostgrey{reason}{$k}',";
}
print OUT "},\n";
print OUT ");\n\n";
%localpostgrey = ();
print OUT "\%::spf_dkim = (\n";
print OUT "'spf' => {\n";
foreach my $r (keys %{$localspf_dkim{spf}}) {
print OUT "\t'$r' => {\n";
foreach my $s (keys %{$localspf_dkim{spf}{$r}}) {
print OUT "\t\t'$s' => { ";
foreach my $v (keys %{$localspf_dkim{spf}{$r}{$s}}) {
print OUT "'$v' => '$localspf_dkim{spf}{$r}{$s}{$v}',";
}
print OUT " },\n";
}
print OUT "\t},\n";
}
print OUT "},\n";
print OUT "'dkim' => {\n";
foreach my $r (keys %{$localspf_dkim{dkim}}) {
print OUT "\t'$r' => {\n";
foreach my $s (keys %{$localspf_dkim{dkim}{$r}}) {
print OUT "\t\t'$s' => '$localspf_dkim{dkim}{$r}{$s}',\n";
}
print OUT "\t},\n";
}
print OUT "},\n";
print OUT ");\n\n";
%localspf_dkim = ();
print OUT "\%::virus = (\n";
print OUT "'inbound' => '$localvirus{inbound}',\n";
print OUT "'inbound_bytes' => '$localvirus{inbound_bytes}',\n";
print OUT "'local_inbound' => '$localvirus{local_inbound}',\n";
print OUT "'local_inbound_bytes' => '$localvirus{local_inbound_bytes}',\n";
print OUT "'total_inbound' => '$localvirus{total_inbound}',\n";
print OUT "'total_inbound_bytes' => '$localvirus{total_inbound_bytes}',\n";
print OUT "'outbound' => '$localvirus{outbound}',\n";
print OUT "'outbound_bytes' => '$localvirus{outbound_bytes}',\n";
print OUT "'local_outbound' => '$localvirus{local_outbound}',\n";
print OUT "'local_outbound_bytes' => '$localvirus{local_outbound_bytes}',\n";
print OUT "'total_outbound' => '$localvirus{total_outbound}',\n";
print OUT "'total_outbound_bytes' => '$localvirus{total_outbound_bytes}',\n";
print OUT "'lbls' => '$lbls',\n";
print OUT "'x_label' => 'Month of the year',\n";
print OUT "'values' => '$localvirus{values}',\n";
print OUT "'Ext_Int' => '$localvirus{Ext_Int}',\n";
print OUT "'Int_Int' => '$localvirus{Int_Int}',\n";
print OUT "'Int_Ext' => '$localvirus{Int_Ext}',\n";
print OUT "'Ext_Ext' => '$localvirus{Ext_Ext}',\n";
print OUT "'Ext_Int_bytes' => '$localvirus{Ext_Int_bytes}',\n";
print OUT "'Int_Int_bytes' => '$localvirus{Int_Int_bytes}',\n";
print OUT "'Int_Ext_bytes' => '$localvirus{Int_Ext_bytes}',\n";
print OUT "'Ext_Ext_bytes' => '$localvirus{Ext_Ext_bytes}',\n";
print OUT ");\n\n";
%localvirus = ();
print OUT "\%::dsn = (\n";
print OUT "'outbound' => '$localdsn{outbound}',\n";
print OUT "'local_outbound' => '$localdsn{local_outbound}',\n";
print OUT "'total_outbound' => '$localdsn{total_outbound}',\n";
print OUT "'error' => '$localdsn{error}',\n";
print OUT "'lbls' => '$lbls',\n";
print OUT "'x_label' => 'Month of the year',\n";
print OUT "'values' => '$localdsn{values}',\n";
print OUT "'Ext_Int' => '$localdsn{Ext_Int}',\n";
print OUT "'Int_Int' => '$localdsn{Int_Int}',\n";
print OUT "'Int_Ext' => '$localdsn{Int_Ext}',\n";
print OUT "'Ext_Ext' => '$localdsn{Ext_Ext}',\n";
print OUT ");\n\n";
%localdsn = ();
print OUT "\%::err = (\n";
print OUT "'inbound' => '$localerr{inbound}',\n";
print OUT "'inbound_bytes' => '$localerr{inbound_bytes}',\n";
print OUT "'local_inbound' => '$localerr{local_inbound}',\n";
print OUT "'local_inbound_bytes' => '$localerr{local_inbound_bytes}',\n";
print OUT "'total_inbound' => '$localerr{total_inbound}',\n";
print OUT "'total_inbound_bytes' => '$localerr{total_inbound_bytes}',\n";
print OUT ");\n\n";
%localerr = ();
print OUT "\%::GLOBAL_STATUS = (\n";
foreach my $k (keys %localGLOBAL_STATUS) {
my $slbl = $k;
$slbl =~ s/'/\\'/g;
print OUT "'$slbl' => '$localGLOBAL_STATUS{$k}',\n";
}
print OUT ");\n\n";
%localGLOBAL_STATUS = ();
print OUT "\%::starttls = (\n";
foreach my $v (sort keys %localstarttls) {
my $slbl = $v;
$slbl =~ s/'/\\'/g;
print OUT "'$slbl' => '$localstarttls{$v}',\n";
}
print OUT ");\n\n";
%localstarttls = ();
my $elbls = 'Ext -> Int:Ext -> Ext:Int -> Int:Int -> Ext';
print OUT "\%::delivery = (\n";
print OUT "'lbls' => '$elbls',\n";
print OUT "'x_label' => 'Month of the year',\n";
print OUT "'Ext_Int' => '$localdelivery{Ext_Int}',\n";
print OUT "'Int_Int' => '$localdelivery{Int_Int}',\n";
print OUT "'Int_Ext' => '$localdelivery{Int_Ext}',\n";
print OUT "'Ext_Ext' => '$localdelivery{Ext_Ext}',\n";
print OUT "'Ext_Int_bytes' => '$localdelivery{Ext_Int_bytes}',\n";
print OUT "'Int_Int_bytes' => '$localdelivery{Int_Int_bytes}',\n";
print OUT "'Int_Ext_bytes' => '$localdelivery{Int_Ext_bytes}',\n";
print OUT "'Ext_Ext_bytes' => '$localdelivery{Ext_Ext_bytes}',\n";
print OUT ");\n\n";
%localdelivery = ();
# Top SMTP Auth statistics
my $top = 0;
print OUT "\%::topauth = (\n";
print OUT "'relay' => {";
foreach my $d (sort { $localtopauth{relay}{$b} <=> $localtopauth{relay}{$a} } keys %{$localtopauth{relay}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopauth{relay}{$d}',";
$top++;
}
print OUT "},\n";
delete $localtopauth{relay};
$top = 0;
print OUT "'mech' => {";
foreach my $d (sort { $localtopauth{mech}{$b} <=> $localtopauth{mech}{$a} } keys %{$localtopauth{mech}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopauth{mech}{$d}',";
$top++;
}
print OUT "},\n";
delete $localtopauth{mech};
$top = 0;
print OUT "'authid' => {";
foreach my $d (sort { $localtopauth{authid}{$b} <=> $localtopauth{authid}{$a} } keys %{$localtopauth{authid}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopauth{authid}{$d}',";
$top++;
}
print OUT "},\n";
print OUT ");\n\n";
%localtopauth = ();
# Top sender statistics
$top = 0;
print OUT "\%::topsender = (\n";
print OUT "'domain' => {";
foreach my $d (sort { $localtopsender{domain}{$b} <=> $localtopsender{domain}{$a} } keys %{$localtopsender{domain}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopsender{domain}{$d}',";
$top++;
}
print OUT "},\n";
delete $localtopsender{domain};
$top = 0;
print OUT "'relay' => {";
foreach my $d (sort { $localtopsender{relay}{$b} <=> $localtopsender{relay}{$a} } keys %{$localtopsender{relay}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopsender{relay}{$d}',";
$top++;
}
print OUT "},\n";
delete $localtopsender{relay};
$top = 0;
print OUT "'email' => {";
foreach my $d (sort { $localtopsender{email}{$b} <=> $localtopsender{email}{$a} } keys %{$localtopsender{email}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopsender{email}{$d}',";
$top++;
}
print OUT "},\n";
print OUT ");\n\n";
%localtopsender = ();
# Top recipient statistics
$top = 0;
print OUT "\%::toprcpt = (\n";
print OUT "'domain' => {";
foreach my $d (sort { $localtoprcpt{domain}{$b} <=> $localtoprcpt{domain}{$a} } keys %{$localtoprcpt{domain}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtoprcpt{domain}{$d}',";
$top++;
}
print OUT "},\n";
delete $localtoprcpt{domain};
$top = 0;
print OUT "'relay' => {";
foreach my $d (sort { $localtoprcpt{relay}{$b} <=> $localtoprcpt{relay}{$a} } keys %{$localtoprcpt{relay}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtoprcpt{relay}{$d}',";
$top++;
}
print OUT "},\n";
delete $localtoprcpt{relay};
$top = 0;
print OUT "'email' => {";
foreach my $d (sort { $localtoprcpt{email}{$b} <=> $localtoprcpt{email}{$a} } keys %{$localtoprcpt{email}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtoprcpt{email}{$d}',";
$top++;
}
print OUT "},\n";
print OUT ");\n\n";
%localtoprcpt = ();
# Top rejection statistics
$top = 0;
print OUT "\%::topreject = (\n";
print OUT "'rule' => {";
foreach my $d (sort { $localtopreject{rule}{$b} <=> $localtopreject{rule}{$a} } keys %{$localtopreject{rule}}) {
last if ($top == $CONFIG{TOP});
my $c = $localtopreject{rule}{$d};
$d =~ s/'/\\'/g;
print OUT "'$d' => '$c',";
$top++;
}
print OUT "},\n";
delete $localtopreject{rule};
$top = 0;
print OUT "'domain' => {";
foreach my $d (sort { $localtopreject{domain}{$b} <=> $localtopreject{domain}{$a} } keys %{$localtopreject{domain}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopreject{domain}{$d}',";
$top++;
}
print OUT "},\n";
delete $localtopreject{domain};
$top = 0;
print OUT "'relay' => {";
foreach my $d (sort { $localtopreject{relay}{$b} <=> $localtopreject{relay}{$a} } keys %{$localtopreject{relay}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopreject{relay}{$d}',";
$top++;
}
print OUT "},\n";
delete $localtopreject{relay};
$top = 0;
print OUT "'chck_status' => {";
foreach my $d (sort { $localtopreject{chck_status}{$b} <=> $localtopreject{chck_status}{$a} } keys %{$localtopreject{chck_status}}) {
last if ($top == $CONFIG{TOP});
my $c = $localtopreject{chck_status}{$d};
$d =~ s/'/\\'/g;
print OUT "'$d' => '$c',";
$top++;
}
print OUT "},\n";
delete $localtopreject{chck_status};
$top = 0;
print OUT "'sender' => {";
foreach my $d (sort { $localtopreject{sender}{$b} <=> $localtopreject{sender}{$a} } keys %{$localtopreject{sender}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopreject{sender}{$d}',";
$top++;
}
print OUT "},\n";
print OUT ");\n\n";
%localtopreject = ();
# Top virus statistics
$top = 0;
print OUT "\%::topvirus = (\n";
print OUT "'virus' => {";
foreach my $d (sort { $localtopvirus{virus}{$b} <=> $localtopvirus{virus}{$a} } keys %{$localtopvirus{virus}}) {
last if ($top == $CONFIG{TOP});
my $c = $localtopvirus{virus}{$d};
$d =~ s/'/\\'/g;
print OUT "'$d' => '$c',";
$top++;
}
print OUT "},\n";
delete $localtopvirus{virus};
$top = 0;
print OUT "'sender' => {";
foreach my $d (sort { $localtopvirus{sender}{$b} <=> $localtopvirus{sender}{$a} } keys %{$localtopvirus{sender}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopvirus{sender}{$d}',";
$top++;
}
print OUT "},\n";
delete $localtopvirus{sender};
$top = 0;
print OUT "'relay' => {";
foreach my $d (sort { $localtopvirus{relay}{$b} <=> $localtopvirus{relay}{$a} } keys %{$localtopvirus{relay}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopvirus{relay}{$d}',";
$top++;
}
print OUT "},\n";
delete $localtopvirus{relay};
$top = 0;
print OUT "'file' => {";
foreach my $d (sort { $localtopvirus{file}{$b} <=> $localtopvirus{file}{$a} } keys %{$localtopvirus{file}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopvirus{file}{$d}',";
$top++;
}
print OUT "},\n";
delete $localtopvirus{file};
$top = 0;
print OUT "'rcpt' => {";
foreach my $d (sort { $localtopvirus{rcpt}{$b} <=> $localtopvirus{rcpt}{$a} } keys %{$localtopvirus{rcpt}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopvirus{rcpt}{$d}',";
$top++;
}
print OUT "},\n";
print OUT ");\n\n";
%localtopvirus = ();
# Top dsn statistics
$top = 0;
print OUT "\%::topdsn = (\n";
print OUT "'dsnstatus' => {";
foreach my $d (sort { $localtopdsn{dsnstatus}{$b} <=> $localtopdsn{dsnstatus}{$a} } keys %{$localtopdsn{dsnstatus}}) {
last if ($top == $CONFIG{TOP});
my $c = $localtopdsn{dsnstatus}{$d};
$d =~ s/'/\\'/g;
print OUT "'$d' => '$c',";
$top++;
}
print OUT "},\n";
delete $localtopdsn{dsnstatus};
$top = 0;
print OUT "'sender' => {";
foreach my $d (sort { $localtopdsn{sender}{$b} <=> $localtopdsn{sender}{$a} } keys %{$localtopdsn{sender}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopdsn{sender}{$d}',";
$top++;
}
print OUT "},\n";
delete $localtopdsn{sender};
$top = 0;
print OUT "'relay' => {";
foreach my $d (sort { $localtopdsn{relay}{$b} <=> $localtopdsn{relay}{$a} } keys %{$localtopdsn{relay}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopdsn{relay}{$d}',";
$top++;
}
print OUT "},\n";
delete $localtopdsn{relay};
$top = 0;
print OUT "'rcpt' => {";
foreach my $d (sort { $localtopdsn{rcpt}{$b} <=> $localtopdsn{rcpt}{$a} } keys %{$localtopdsn{rcpt}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopdsn{rcpt}{$d}',";
$top++;
}
print OUT "},\n";
print OUT ");\n\n";
%localtopdsn = ();
# Top spam statistics
$top = 0;
print OUT "\%::topspam = (\n";
print OUT "'rule' => {";
foreach my $d (sort { $localtopspam{rule}{$b} <=> $localtopspam{rule}{$a} } keys %{$localtopspam{rule}}) {
last if ($top == $CONFIG{TOP});
my $c = $localtopspam{rule}{$d};
$d =~ s/'/\\'/g;
print OUT "'$d' => '$c',";
$top++;
}
print OUT "},";
delete $localtopspam{rule};
$top = 0;
print OUT "'domain' => {";
foreach my $d (sort { $localtopspam{domain}{$b} <=> $localtopspam{domain}{$a} } keys %{$localtopspam{domain}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopspam{domain}{$d}',";
$top++;
}
print OUT "},";
delete $localtopspam{domain};
$top = 0;
print OUT "'sender_relay' => {";
foreach my $d (sort { $localtopspam{sender_relay}{$b} <=> $localtopspam{sender_relay}{$a} } keys %{$localtopspam{sender_relay}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopspam{sender_relay}{$d}',";
$top++;
}
print OUT "},";
delete $localtopspam{sender_relay};
$top = 0;
print OUT "'sender' => {";
foreach my $d (sort { $localtopspam{sender}{$b} <=> $localtopspam{sender}{$a} } keys %{$localtopspam{sender}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopspam{sender}{$d}',";
$top++;
}
print OUT "},";
delete $localtopspam{sender};
$top = 0;
print OUT "'rcpt' => {";
foreach my $d (sort { $localtopspam{rcpt}{$b} <=> $localtopspam{rcpt}{$a} } keys %{$localtopspam{rcpt}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopspam{rcpt}{$d}',";
$top++;
}
print OUT "},";
print OUT ");\n\n";
%localtopspam = ();
# Top system message statistics
$top = 0;
print OUT "\%::toperr = (\n";
foreach my $m (sort { $localtopspam{$b} <=> $localtopspam{$a} } keys %localtoperr) {
my $c = $localtoperr{$m};
$m =~ s/'/\\'/g;
print OUT "'$m' => $c,\n";
}
print OUT ");\n";
%localtoperr = ();
# Top postgrey statistics
$top = 0;
print OUT "\%::toppostgrey = (\n";
print OUT "'sender' => {";
foreach my $d (sort { $localtoppostgrey{sender}{$b} <=> $localtoppostgrey{sender}{$a} } keys %{$localtoppostgrey{sender}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtoppostgrey{sender}{$d}',";
$top++;
}
print OUT "},\n";
delete $localtoppostgrey{sender};
$top = 0;
print OUT "'sender_relay' => {";
foreach my $d (sort { $localtoppostgrey{sender_relay}{$b} <=> $localtoppostgrey{sender_relay}{$a} } keys %{$localtoppostgrey{sender_relay}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtoppostgrey{sender_relay}{$d}',";
$top++;
}
print OUT "},\n";
delete $localtoppostgrey{sender_relay};
$top = 0;
print OUT "'domain' => {";
foreach my $d (sort { $localtoppostgrey{domain}{$b} <=> $localtoppostgrey{domain}{$a} } keys %{$localtoppostgrey{domain}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtoppostgrey{domain}{$d}',";
$top++;
}
print OUT "},\n";
delete $localtoppostgrey{domain};
$top = 0;
print OUT "'reason' => {";
foreach my $d (sort { $localtoppostgrey{reason}{$b} <=> $localtoppostgrey{reason}{$a} } keys %{$localtoppostgrey{reason}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtoppostgrey{reason}{$d}',";
$top++;
}
print OUT "},\n";
delete $localtoppostgrey{reason};
$top = 0;
print OUT "'rcpt' => {";
foreach my $d (sort { $localtoppostgrey{rcpt}{$b} <=> $localtoppostgrey{rcpt}{$a} } keys %{$localtoppostgrey{rcpt}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtoppostgrey{rcpt}{$d}',";
$top++;
}
print OUT "},\n";
print OUT ");\n\n";
%localtoppostgrey = ();
# Top spam detail statistics
$top = 0;
print OUT "\%::topspamdetail = (\n";
foreach my $t (sort keys %localtopspamdetail) {
print OUT "'$t' => {";
print OUT "'rule' => {";
foreach my $d (sort { $localtopspamdetail{$t}{rule}{$b} <=> $localtopspamdetail{$t}{rule}{$a} } keys %{$localtopspamdetail{$t}{rule}}) {
last if ($top == $CONFIG{TOP});
my $c = $localtopspamdetail{$t}{rule}{$d};
$d =~ s/'/\\'/g;
print OUT "'$d' => '$c',";
$top++;
}
print OUT "},";
delete $localtopspamdetail{$t}{rule};
$top = 0;
print OUT "'score' => {";
foreach my $d (sort { $localtopspamdetail{$t}{score}{$b} <=> $localtopspamdetail{$t}{score}{$a} } keys %{$localtopspamdetail{$t}{score}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopspamdetail{$t}{score}{$d}',";
$top++;
}
print OUT "},";
delete $localtopspamdetail{$t}{score};
$top = 0;
print OUT "'cache' => {";
foreach my $d (sort { $localtopspamdetail{$t}{cache}{$b} <=> $localtopspamdetail{$t}{cache}{$a} } keys %{$localtopspamdetail{$t}{cache}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopspamdetail{$t}{cache}{$d}',";
$top++;
}
print OUT "},";
delete $localtopspamdetail{$t}{cache};
$top = 0;
print OUT "'autolearn' => {";
foreach my $d (sort { $localtopspamdetail{$t}{autolearn}{$b} <=> $localtopspamdetail{$t}{autolearn}{$a} } keys %{$localtopspamdetail{$t}{autolearn}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopspamdetail{$t}{autolearn}{$d}',";
$top++;
}
print OUT "},";
delete $localtopspamdetail{$t}{autolearn};
$top = 0;
print OUT "},";
}
print OUT ");\n";
close(OUT);
} else {
&logerror("can't write cache file $file: $!");
}
}
####
# Year cache statistics
####
sub do_year_cache
{
my ($hostname, $DOMAIN, $year, $curyear) = @_;
if (-e "$CONFIG{OUT_DIR}/$hostname/$year/cache.pm\U$DOMAIN\E" && ($year < $curyear)) {
return;
}
print "Reading statistics from $CONFIG{OUT_DIR}/$hostname/$year/\n" if ($CONFIG{DEBUG});
my %localtopsender = ();
my %localtoprcpt = ();
my %localtopspam = ();
my %localtopvirus = ();
my %localtopdsn = ();
my %localtopreject = ();
my %localtoperr = ();
my %localdelivery = ();
my %localmessaging = ();
my %localspam = ();
my %localvirus = ();
my %localdsn = ();
my %localreject = ();
my %localerr = ();
my %localGLOBAL_STATUS = ();
my %localtopspamdetail = ();
my %localauth = ();
my %localtopauth = ();
my %localpostgrey = ();
my %localtoppostgrey = ();
my %localstarttls = ();
my %localspf_dkim = ();
my $lbls = '';
foreach my $month ("01" .. "12") {
$lbls .= "$month:";
if (!-e "$CONFIG{OUT_DIR}/$hostname/$year/$month/cache.pm\U$DOMAIN\E") {
$localmessaging{values} .= '0:';
$localmessaging{values1} .= '0:';
$localmessaging{values_bytes} .= '0:';
$localmessaging{values1_bytes} .= '0:';
$localspam{values} .= '0:';
$localvirus{values} .= '0:';
$localdsn{values} .= '0:';
$localmessaging{nbsender} .= '0:';
$localmessaging{nbrcpt} .= '0:';
next;
} else {
&clean_globals();
my $file = "$CONFIG{OUT_DIR}/$hostname/$year/$month/cache.pm\U$DOMAIN\E";
print "Loading cache statistics from $file\n" if ($CONFIG{DEBUG});
do "$file";
foreach my $k (keys %messaging) {
if (!grep(/^$k$/, 'lbls','x_label','values','values1','values_bytes','values1_bytes','nbsender','nbrcpt')) {
$localmessaging{$k} += $messaging{$k};
}
}
$localmessaging{values} .= ($messaging{inbound} || 0) . ':';
$localmessaging{values1} .= ($messaging{outbound} || 0) . ':';
$localmessaging{values_bytes} .= ($messaging{inbound_bytes} || 0) . ':';
$localmessaging{values1_bytes} .= ($messaging{outbound_bytes} || 0) . ':';
my $tmp = 0;
foreach (split(/:/, $messaging{nbsender})) {
$tmp += $_;
}
$localmessaging{nbsender} .= $tmp . ':';
$tmp = 0;
foreach (split(/:/, $messaging{nbrcpt})) {
$tmp += $_;
}
$localmessaging{nbrcpt} .= $tmp . ':';
%messaging = ();
foreach my $t (keys %auth) {
foreach my $m (keys %{$auth{$t}}) {
if (!grep(/^$m$/, 'lbls','x_label','values')) {
$localauth{$t}{$m} += $auth{$t}{$m};
$localauth{$t}{values}{"$month"} += $auth{$t}{$m};
}
}
}
%auth = ();
foreach my $k (keys %spam) {
if (!grep(/^$k$/, 'lbls','x_label','values')) {
$localspam{$k} += $spam{$k};
}
}
$localspam{values} .= ($spam{inbound} || 0) . ':';
%spam = ();
foreach my $k (keys %reject) {
if (!grep(/^$k$/, 'lbls','x_label','values')) {
$localreject{$k} += $reject{$k};
}
}
%reject = ();
foreach my $k (keys %{$postgrey{reason}}) {
$localpostgrey{reason}{$k} += $postgrey{reason}{$k};
}
%postgrey = ();
foreach my $r (keys %{$spf_dkim{spf}}) {
foreach my $k (keys %{$spf_dkim{spf}{$r}{status}}) {
$localspf_dkim{spf}{$r}{status}{$k} += $spf_dkim{spf}{$r}{status}{$k};
}
foreach my $k (keys %{$spf_dkim{spf}{$r}{domain}}) {
$localspf_dkim{spf}{$r}{domain}{$k} += $spf_dkim{spf}{$r}{domain}{$k};
}
}
foreach my $r (keys %{$spf_dkim{dkim}{status}}) {
$localspf_dkim{dkim}{status}{$r} += $spf_dkim{dkim}{status}{$r};
}
%spf_dkim = ();
foreach my $k (keys %virus) {
if (!grep(/^$k$/, 'lbls','x_label','values')) {
$localvirus{$k} += $virus{$k};
}
}
$localvirus{values} .= ($virus{inbound} || 0) . ':';
%virus = ();
foreach my $k (keys %dsn) {
if (!grep(/^$k$/, 'lbls','x_label','values')) {
$localdsn{$k} += $dsn{$k};
}
}
$localdsn{values} .= ($dsn{outbound} || 0) . ':';
%dsn = ();
foreach my $k (keys %err) {
if (!grep(/^$k$/, 'lbls','x_label','values')) {
$localerr{$k} += $err{$k};
}
}
%err = ();
foreach my $k (keys %GLOBAL_STATUS) {
$localGLOBAL_STATUS{$k} += $GLOBAL_STATUS{$k};
}
%GLOBAL_STATUS = ();
foreach my $k (keys %delivery) {
if (!grep(/^$k$/, 'lbls','x_label')) {
$localdelivery{$k} += $delivery{$k};
}
}
foreach my $k (keys %topsender) {
foreach my $d (keys %{$topsender{$k}}) {
$localtopsender{$k}{$d} += $topsender{$k}{$d} || 0;
}
}
%topsender = ();
foreach my $k (keys %toprcpt) {
foreach my $d (keys %{$toprcpt{$k}}) {
$localtoprcpt{$k}{$d} += $toprcpt{$k}{$d} || 0;
}
}
%toprcpt = ();
foreach my $k (keys %topreject) {
foreach my $d (keys %{$topreject{$k}}) {
$localtopreject{$k}{$d} += $topreject{$k}{$d} || 0;
}
}
%topreject = ();
foreach my $k (keys %topvirus) {
foreach my $d (keys %{$topvirus{$k}}) {
$localtopvirus{$k}{$d} += $topvirus{$k}{$d} || 0;
}
}
%topvirus = ();
foreach my $k (keys %topdsn) {
foreach my $d (keys %{$topdsn{$k}}) {
$localtopdsn{$k}{$d} += $topdsn{$k}{$d} || 0;
}
}
%topdsn = ();
foreach my $k (keys %topspam) {
foreach my $d (keys %{$topspam{$k}}) {
$localtopspam{$k}{$d} += $topspam{$k}{$d} || 0;
}
}
%topspam = ();
foreach my $k (keys %toperr) {
$localtoperr{$k} += $toperr{$k} || 0;
}
%toperr = ();
foreach my $k (keys %toppostgrey) {
foreach my $d (keys %{$toppostgrey{$k}}) {
$localtoppostgrey{$k}{$d} += $toppostgrey{$k}{$d} || 0;
}
}
%toppostgrey = ();
foreach my $t (keys %topspamdetail) {
foreach my $k (keys %{$topspamdetail{$t}}) {
foreach my $d (keys %{$topspamdetail{$t}{$k}}) {
$localtopspamdetail{$t}{$k}{$d} += $topspamdetail{$t}{$k}{$d} || 0;
}
}
}
%topspamdetail = ();
foreach my $k (keys %topauth) {
foreach my $d (keys %{$topauth{$k}}) {
$localtopauth{$k}{$d} += $topauth{$k}{$d} || 0;
}
}
%topauth = ();
foreach my $k (keys %starttls) {
$localstarttls{$k} += $starttls{$k};
}
%starttls = ();
}
}
my %authval = ();
foreach my $month ("01" .. "12") {
foreach my $t (keys %localauth) {
$authval{$t} .= ($localauth{$t}{values}{"$month"} || 0) . ':';
}
}
foreach my $t (keys %localauth) {
delete $localauth{$t}{values};
$localauth{$t}{values} = $authval{$t};
$localauth{$t}{lbls} =~ s/:$//;
$localauth{$t}{values} =~ s/:$//;
}
$lbls =~ s/:$//;
$localmessaging{values} =~ s/:$//;
$localmessaging{values1} =~ s/:$//;
$localmessaging{values_bytes} =~ s/:$//;
$localmessaging{values1_bytes} =~ s/:$//;
$localspam{values} =~ s/:$//;
$localvirus{values} =~ s/:$//;
$localdsn{values} =~ s/:$//;
$localmessaging{nbsender} =~ s/:$//;
$localmessaging{nbrcpt} =~ s/:$//;
my $file = "$CONFIG{OUT_DIR}/$hostname/$year/cache.pm\U$DOMAIN\E";
print "Writing cache file: $file\n" if ($CONFIG{DEBUG});
if (open(OUT, ">$file")) {
print OUT "\%::auth = (\n";
foreach my $type (keys %localauth) {
print OUT "'$type' => {\n";
print OUT "\t'values' => '$localauth{$type}{values}',\n";
print OUT "\t'lbls' => '$lbls',\n";
print OUT "\t'x_label' => 'Month of the year',\n";
foreach my $mech (keys %{$localauth{$type}}) {
next if (grep(/^$mech$/,'lbls','x_label','values'));
print OUT "\t'$mech' => '$localauth{$type}{$mech}',\n";
}
print OUT "\t},\n";
}
print OUT ");\n\n";
%localauth = ();
print OUT "\%::messaging = (\n";
print OUT "'inbound' => '$localmessaging{inbound}',\n";
print OUT "'inbound_bytes' => '$localmessaging{inbound_bytes}',\n";
print OUT "'local_inbound' => '$localmessaging{local_inbound}',\n";
print OUT "'local_inbound_bytes' => '$localmessaging{local_inbound_bytes}',\n";
print OUT "'total_inbound' => '$localmessaging{total_inbound}',\n";
print OUT "'total_inbound_bytes' => '$localmessaging{total_inbound_bytes}',\n";
print OUT "'outbound' => '$localmessaging{outbound}',\n";
print OUT "'outbound_bytes' => '$localmessaging{outbound_bytes}',\n";
print OUT "'local_outbound' => '$localmessaging{local_outbound}',\n";
print OUT "'local_outbound_bytes' => '$localmessaging{local_outbound_bytes}',\n";
print OUT "'total_outbound' => '$localmessaging{total_outbound}',\n";
print OUT "'total_outbound_bytes' => '$localmessaging{total_outbound_bytes}',\n";
print OUT "'lbls' => '$lbls',\n";
print OUT "'x_label' => 'Month of the year',\n";
print OUT "'values' => '$localmessaging{values}',\n";
print OUT "'values1' => '$localmessaging{values1}',\n";
print OUT "'values_bytes' => '$localmessaging{values_bytes}',\n";
print OUT "'values1_bytes' => '$localmessaging{values1_bytes}',\n";
print OUT "'nbsender' => '$localmessaging{nbsender}',\n";
print OUT "'nbrcpt' => '$localmessaging{nbrcpt}',\n";
print OUT ");\n\n";
%localmessaging = ();
print OUT "\%::spam = (\n";
print OUT "'inbound' => '$localspam{inbound}',\n";
print OUT "'inbound_bytes' => '$localspam{inbound_bytes}',\n";
print OUT "'local_inbound' => '$localspam{local_inbound}',\n";
print OUT "'local_inbound_bytes' => '$localspam{local_inbound_bytes}',\n";
print OUT "'total_inbound' => '$localspam{total_inbound}',\n";
print OUT "'total_inbound_bytes' => '$localspam{total_inbound_bytes}',\n";
print OUT "'outbound' => '$localspam{outbound}',\n";
print OUT "'outbound_bytes' => '$localspam{outbound_bytes}',\n";
print OUT "'local_outbound' => '$localspam{local_outbound}',\n";
print OUT "'local_outbound_bytes' => '$localspam{local_outbound_bytes}',\n";
print OUT "'total_outbound' => '$localspam{total_outbound}',\n";
print OUT "'total_outbound_bytes' => '$localspam{total_outbound_bytes}',\n";
print OUT "'lbls' => '$lbls',\n";
print OUT "'x_label' => 'Month of the year',\n";
print OUT "'values' => '$localspam{values}',\n";
print OUT "'Ext_Int' => '$localspam{Ext_Int}',\n";
print OUT "'Int_Int' => '$localspam{Int_Int}',\n";
print OUT "'Int_Ext' => '$localspam{Int_Ext}',\n";
print OUT "'Ext_Ext' => '$localspam{Ext_Ext}',\n";
print OUT "'Ext_Int_bytes' => '$localspam{Ext_Int_bytes}',\n";
print OUT "'Int_Int_bytes' => '$localspam{Int_Int_bytes}',\n";
print OUT "'Int_Ext_bytes' => '$localspam{Int_Ext_bytes}',\n";
print OUT "'Ext_Ext_bytes' => '$localspam{Ext_Ext_bytes}',\n";
print OUT ");\n\n";
%localspam = ();
print OUT "\%::reject = (\n";
print OUT "'inbound' => '$localreject{inbound}',\n";
print OUT "'inbound_bytes' => '$localreject{inbound_bytes}',\n";
print OUT "'local_inbound' => '$localreject{local_inbound}',\n";
print OUT "'local_inbound_bytes' => '$localreject{local_inbound_bytes}',\n";
print OUT "'total_inbound' => '$localreject{total_inbound}',\n";
print OUT "'total_inbound_bytes' => '$localreject{total_inbound_bytes}',\n";
print OUT ");\n\n";
%localreject = ();
print OUT "\%::postgrey = (\n";
print OUT "'reason' => {";
foreach my $k (keys %{$localpostgrey{reason}}) {
print OUT "\t'$k' => '$localpostgrey{reason}{$k}',";
}
print OUT "},\n";
print OUT ");\n\n";
%localpostgrey = ();
print OUT "\%::spf_dkim = (\n";
print OUT "'spf' => {\n";
foreach my $r (keys %{$localspf_dkim{spf}}) {
print OUT "\t'$r' => {\n";
foreach my $s (keys %{$localspf_dkim{spf}{$r}}) {
print OUT "\t\t'$s' => { ";
foreach my $v (keys %{$localspf_dkim{spf}{$r}{$s}}) {
print OUT "'$v' => '$localspf_dkim{spf}{$r}{$s}{$v}',";
}
print OUT " },\n";
}
print OUT "\t},\n";
}
print OUT "},\n";
print OUT "'dkim' => {\n";
foreach my $r (keys %{$localspf_dkim{dkim}}) {
print OUT "\t'$r' => {\n";
foreach my $s (keys %{$localspf_dkim{dkim}{$r}}) {
print OUT "\t\t'$s' => '$localspf_dkim{dkim}{$r}{$s}',\n";
}
print OUT "\t},\n";
}
print OUT "},\n";
print OUT ");\n\n";
%localspf_dkim = ();
print OUT "\%::virus = (\n";
print OUT "'inbound' => '$localvirus{inbound}',\n";
print OUT "'inbound_bytes' => '$localvirus{inbound_bytes}',\n";
print OUT "'local_inbound' => '$localvirus{local_inbound}',\n";
print OUT "'local_inbound_bytes' => '$localvirus{local_inbound_bytes}',\n";
print OUT "'total_inbound' => '$localvirus{total_inbound}',\n";
print OUT "'total_inbound_bytes' => '$localvirus{total_inbound_bytes}',\n";
print OUT "'outbound' => '$localvirus{outbound}',\n";
print OUT "'outbound_bytes' => '$localvirus{outbound_bytes}',\n";
print OUT "'local_outbound' => '$localvirus{local_outbound}',\n";
print OUT "'local_outbound_bytes' => '$localvirus{local_outbound_bytes}',\n";
print OUT "'total_outbound' => '$localvirus{total_outbound}',\n";
print OUT "'total_outbound_bytes' => '$localvirus{total_outbound_bytes}',\n";
print OUT "'lbls' => '$lbls',\n";
print OUT "'x_label' => 'Month of the year',\n";
print OUT "'values' => '$localvirus{values}',\n";
print OUT "'Ext_Int' => '$localvirus{Ext_Int}',\n";
print OUT "'Int_Int' => '$localvirus{Int_Int}',\n";
print OUT "'Int_Ext' => '$localvirus{Int_Ext}',\n";
print OUT "'Ext_Ext' => '$localvirus{Ext_Ext}',\n";
print OUT "'Ext_Int_bytes' => '$localvirus{Ext_Int_bytes}',\n";
print OUT "'Int_Int_bytes' => '$localvirus{Int_Int_bytes}',\n";
print OUT "'Int_Ext_bytes' => '$localvirus{Int_Ext_bytes}',\n";
print OUT "'Ext_Ext_bytes' => '$localvirus{Ext_Ext_bytes}',\n";
print OUT ");\n\n";
%localvirus = ();
print OUT "\%::dsn = (\n";
print OUT "'outbound' => '$localdsn{outbound}',\n";
print OUT "'local_outbound' => '$localdsn{local_outbound}',\n";
print OUT "'total_outbound' => '$localdsn{total_outbound}',\n";
print OUT "'error' => '$localdsn{error}',\n";
print OUT "'lbls' => '$lbls',\n";
print OUT "'x_label' => 'Month of the year',\n";
print OUT "'values' => '$localdsn{values}',\n";
print OUT "'Ext_Int' => '$localdsn{Ext_Int}',\n";
print OUT "'Int_Int' => '$localdsn{Int_Int}',\n";
print OUT "'Int_Ext' => '$localdsn{Int_Ext}',\n";
print OUT "'Ext_Ext' => '$localdsn{Ext_Ext}',\n";
print OUT ");\n\n";
%localdsn = ();
print OUT "\%::err = (\n";
print OUT "'inbound' => '$localerr{inbound}',\n";
print OUT "'inbound_bytes' => '$localerr{inbound_bytes}',\n";
print OUT "'local_inbound' => '$localerr{local_inbound}',\n";
print OUT "'local_inbound_bytes' => '$localerr{local_inbound_bytes}',\n";
print OUT "'total_inbound' => '$localerr{total_inbound}',\n";
print OUT "'total_inbound_bytes' => '$localerr{total_inbound_bytes}',\n";
print OUT ");\n\n";
%localerr = ();
print OUT "\%::GLOBAL_STATUS = (\n";
foreach my $k (keys %localGLOBAL_STATUS) {
my $slbl = $k;
$slbl =~ s/'/\\'/g;
print OUT "'$k' => '$localGLOBAL_STATUS{$k}',\n";
}
print OUT ");\n\n";
%localGLOBAL_STATUS = ();
print OUT "\%::starttls = (\n";
foreach my $v (sort keys %localstarttls) {
my $slbl = $v;
$slbl =~ s/'/\\'/g;
print OUT "'$slbl' => '$localstarttls{$v}',\n";
}
print OUT ");\n\n";
%localstarttls = ();
my $elbls = 'Ext -> Int:Ext -> Ext:Int -> Int:Int -> Ext';
print OUT "\%::delivery = (\n";
print OUT "'lbls' => '$elbls',\n";
print OUT "'x_label' => 'Month of the year',\n";
print OUT "'Ext_Int' => '$localdelivery{Ext_Int}',\n";
print OUT "'Int_Int' => '$localdelivery{Int_Int}',\n";
print OUT "'Int_Ext' => '$localdelivery{Int_Ext}',\n";
print OUT "'Ext_Ext' => '$localdelivery{Ext_Ext}',\n";
print OUT "'Ext_Int_bytes' => '$localdelivery{Ext_Int_bytes}',\n";
print OUT "'Int_Int_bytes' => '$localdelivery{Int_Int_bytes}',\n";
print OUT "'Int_Ext_bytes' => '$localdelivery{Int_Ext_bytes}',\n";
print OUT "'Ext_Ext_bytes' => '$localdelivery{Ext_Ext_bytes}',\n";
print OUT ");\n\n";
%localdelivery = ();
# Top SMTP Auth statistics
my $top = 0;
print OUT "\%::topauth = (\n";
print OUT "'relay' => {";
foreach my $d (sort { $localtopauth{relay}{$b} <=> $localtopauth{relay}{$a} } keys %{$localtopauth{relay}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopauth{relay}{$d}',";
$top++;
}
print OUT "},\n";
delete $localtopauth{relay};
$top = 0;
print OUT "'mech' => {";
foreach my $d (sort { $localtopauth{mech}{$b} <=> $localtopauth{mech}{$a} } keys %{$localtopauth{mech}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopauth{mech}{$d}',";
$top++;
}
print OUT "},\n";
delete $localtopauth{mech};
$top = 0;
print OUT "'authid' => {";
foreach my $d (sort { $localtopauth{authid}{$b} <=> $localtopauth{authid}{$a} } keys %{$localtopauth{authid}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopauth{authid}{$d}',";
$top++;
}
print OUT "},\n";
print OUT ");\n\n";
%localtopauth = ();
# Top sender statistics
$top = 0;
print OUT "\%::topsender = (\n";
print OUT "'domain' => {";
foreach my $d (sort { $localtopsender{domain}{$b} <=> $localtopsender{domain}{$a} } keys %{$localtopsender{domain}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopsender{domain}{$d}',";
$top++;
}
print OUT "},\n";
delete $localtopsender{domain};
$top = 0;
print OUT "'relay' => {";
foreach my $d (sort { $localtopsender{relay}{$b} <=> $localtopsender{relay}{$a} } keys %{$localtopsender{relay}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopsender{relay}{$d}',";
$top++;
}
print OUT "},\n";
delete $localtopsender{relay};
$top = 0;
print OUT "'email' => {";
foreach my $d (sort { $localtopsender{email}{$b} <=> $localtopsender{email}{$a} } keys %{$localtopsender{email}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopsender{email}{$d}',";
$top++;
}
print OUT "},\n";
print OUT ");\n\n";
%localtopsender = ();
# Top recipient statistics
$top = 0;
print OUT "\%::toprcpt = (\n";
print OUT "'domain' => {";
foreach my $d (sort { $localtoprcpt{domain}{$b} <=> $localtoprcpt{domain}{$a} } keys %{$localtoprcpt{domain}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtoprcpt{domain}{$d}',";
$top++;
}
print OUT "},\n";
delete $localtoprcpt{domain};
$top = 0;
print OUT "'relay' => {";
foreach my $d (sort { $localtoprcpt{relay}{$b} <=> $localtoprcpt{relay}{$a} } keys %{$localtoprcpt{relay}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtoprcpt{relay}{$d}',";
$top++;
}
print OUT "},\n";
delete $localtoprcpt{relay};
$top = 0;
print OUT "'email' => {";
foreach my $d (sort { $localtoprcpt{email}{$b} <=> $localtoprcpt{email}{$a} } keys %{$localtoprcpt{email}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtoprcpt{email}{$d}',";
$top++;
}
print OUT "},\n";
print OUT ");\n\n";
%localtoprcpt = ();
# Top rejection statistics
$top = 0;
print OUT "\%::topreject = (\n";
print OUT "'rule' => {";
foreach my $d (sort { $localtopreject{rule}{$b} <=> $localtopreject{rule}{$a} } keys %{$localtopreject{rule}}) {
last if ($top == $CONFIG{TOP});
my $c = $localtopreject{rule}{$d};
$d =~ s/'/\\'/g;
print OUT "'$d' => '$c',";
$top++;
}
print OUT "},\n";
delete $localtopreject{rule};
$top = 0;
print OUT "'domain' => {";
foreach my $d (sort { $localtopreject{domain}{$b} <=> $localtopreject{domain}{$a} } keys %{$localtopreject{domain}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopreject{domain}{$d}',";
$top++;
}
print OUT "},\n";
delete $localtopreject{domain};
$top = 0;
print OUT "'relay' => {";
foreach my $d (sort { $localtopreject{relay}{$b} <=> $localtopreject{relay}{$a} } keys %{$localtopreject{relay}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopreject{relay}{$d}',";
$top++;
}
print OUT "},\n";
delete $localtopreject{relay};
$top = 0;
print OUT "'chck_status' => {";
foreach my $d (sort { $localtopreject{chck_status}{$b} <=> $localtopreject{chck_status}{$a} } keys %{$localtopreject{chck_status}}) {
last if ($top == $CONFIG{TOP});
my $c = $localtopreject{chck_status}{$d};
$d =~ s/'/\\'/g;
print OUT "'$d' => '$c',";
$top++;
}
print OUT "},\n";
delete $localtopreject{chck_status};
$top = 0;
print OUT "'sender' => {";
foreach my $d (sort { $localtopreject{sender}{$b} <=> $localtopreject{sender}{$a} } keys %{$localtopreject{sender}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopreject{sender}{$d}',";
$top++;
}
print OUT "},\n";
print OUT ");\n\n";
%localtopreject = ();
# Top virus statistics
$top = 0;
print OUT "\%::topvirus = (\n";
print OUT "'virus' => {";
foreach my $d (sort { $localtopvirus{virus}{$b} <=> $localtopvirus{virus}{$a} } keys %{$localtopvirus{virus}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopvirus{virus}{$d}',";
$top++;
}
print OUT "},\n";
delete $localtopvirus{virus};
$top = 0;
print OUT "'sender' => {";
foreach my $d (sort { $localtopvirus{sender}{$b} <=> $localtopvirus{sender}{$a} } keys %{$localtopvirus{sender}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopvirus{sender}{$d}',";
$top++;
}
print OUT "},\n";
delete $localtopvirus{sender};
$top = 0;
print OUT "'relay' => {";
foreach my $d (sort { $localtopvirus{relay}{$b} <=> $localtopvirus{relay}{$a} } keys %{$localtopvirus{relay}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopvirus{relay}{$d}',";
$top++;
}
print OUT "},\n";
delete $localtopvirus{relay};
$top = 0;
print OUT "'file' => {";
foreach my $d (sort { $localtopvirus{file}{$b} <=> $localtopvirus{file}{$a} } keys %{$localtopvirus{file}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopvirus{file}{$d}',";
$top++;
}
print OUT "},\n";
delete $localtopvirus{file};
$top = 0;
print OUT "'rcpt' => {";
foreach my $d (sort { $localtopvirus{rcpt}{$b} <=> $localtopvirus{rcpt}{$a} } keys %{$localtopvirus{rcpt}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopvirus{rcpt}{$d}',";
$top++;
}
print OUT "},\n";
print OUT ");\n\n";
%localtopvirus = ();
# Top dsn statistics
$top = 0;
print OUT "\%::topdsn = (\n";
print OUT "'dsnstatus' => {";
foreach my $d (sort { $localtopdsn{dsnstatus}{$b} <=> $localtopdsn{dsnstatus}{$a} } keys %{$localtopdsn{dsnstatus}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopdsn{dsnstatus}{$d}',";
$top++;
}
print OUT "},\n";
delete $localtopdsn{dsnstatus};
$top = 0;
print OUT "'sender' => {";
foreach my $d (sort { $localtopdsn{sender}{$b} <=> $localtopdsn{sender}{$a} } keys %{$localtopdsn{sender}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopdsn{sender}{$d}',";
$top++;
}
print OUT "},\n";
delete $localtopdsn{sender};
$top = 0;
print OUT "'relay' => {";
foreach my $d (sort { $localtopdsn{relay}{$b} <=> $localtopdsn{relay}{$a} } keys %{$localtopdsn{relay}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopdsn{relay}{$d}',";
$top++;
}
print OUT "},\n";
delete $localtopdsn{relay};
$top = 0;
print OUT "'rcpt' => {";
foreach my $d (sort { $localtopdsn{rcpt}{$b} <=> $localtopdsn{rcpt}{$a} } keys %{$localtopdsn{rcpt}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopdsn{rcpt}{$d}',";
$top++;
}
print OUT "},\n";
print OUT ");\n\n";
%localtopdsn = ();
# Top spam statistics
$top = 0;
print OUT "\%::topspam = (\n";
print OUT "'rule' => {";
foreach my $d (sort { $localtopspam{rule}{$b} <=> $localtopspam{rule}{$a} } keys %{$localtopspam{rule}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopspam{rule}{$d}',";
$top++;
}
print OUT "},";
delete $localtopspam{rule};
$top = 0;
print OUT "'domain' => {";
foreach my $d (sort { $localtopspam{domain}{$b} <=> $localtopspam{domain}{$a} } keys %{$localtopspam{domain}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopspam{domain}{$d}',";
$top++;
}
print OUT "},";
delete $localtopspam{domain};
$top = 0;
print OUT "'sender_relay' => {";
foreach my $d (sort { $localtopspam{sender_relay}{$b} <=> $localtopspam{sender_relay}{$a} } keys %{$localtopspam{sender_relay}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopspam{sender_relay}{$d}',";
$top++;
}
print OUT "},";
delete $localtopspam{sender_relay};
$top = 0;
print OUT "'sender' => {";
foreach my $d (sort { $localtopspam{sender}{$b} <=> $localtopspam{sender}{$a} } keys %{$localtopspam{sender}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopspam{sender}{$d}',";
$top++;
}
print OUT "},";
delete $localtopspam{sender};
$top = 0;
print OUT "'rcpt' => {";
foreach my $d (sort { $localtopspam{rcpt}{$b} <=> $localtopspam{rcpt}{$a} } keys %{$localtopspam{rcpt}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopspam{rcpt}{$d}',";
$top++;
}
print OUT "},";
print OUT ");\n\n";
%localtopspam = ();
# Top system message statistics
$top = 0;
print OUT "\%::toperr = (\n";
foreach my $m ( keys %localtoperr) {
my $c = $localtoperr{$m};
$m =~ s/'/\\'/g;
print OUT "'$m' => '$c',\n";
}
print OUT ");\n";
%toperr = ();
# Top postgrey statistics
$top = 0;
print OUT "\%::toppostgrey = (\n";
print OUT "'sender' => {";
foreach my $d (sort { $localtoppostgrey{sender}{$b} <=> $localtoppostgrey{sender}{$a} } keys %{$localtoppostgrey{sender}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtoppostgrey{sender}{$d}',";
$top++;
}
print OUT "},\n";
delete $localtoppostgrey{sender};
$top = 0;
print OUT "'sender_relay' => {";
foreach my $d (sort { $localtoppostgrey{sender_relay}{$b} <=> $localtoppostgrey{sender_relay}{$a} } keys %{$localtoppostgrey{sender_relay}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtoppostgrey{sender_relay}{$d}',";
$top++;
}
print OUT "},\n";
delete $localtoppostgrey{sender_relay};
$top = 0;
print OUT "'domain' => {";
foreach my $d (sort { $localtoppostgrey{domain}{$b} <=> $localtoppostgrey{domain}{$a} } keys %{$localtoppostgrey{domain}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtoppostgrey{domain}{$d}',";
$top++;
}
print OUT "},\n";
delete $localtoppostgrey{domain};
$top = 0;
print OUT "'reason' => {";
foreach my $d (sort { $localtoppostgrey{reason}{$b} <=> $localtoppostgrey{reason}{$a} } keys %{$localtoppostgrey{reason}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtoppostgrey{reason}{$d}',";
$top++;
}
print OUT "},\n";
delete $localtoppostgrey{reason};
$top = 0;
print OUT "'rcpt' => {";
foreach my $d (sort { $localtoppostgrey{rcpt}{$b} <=> $localtoppostgrey{rcpt}{$a} } keys %{$localtoppostgrey{rcpt}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtoppostgrey{rcpt}{$d}',";
$top++;
}
print OUT "},\n";
print OUT ");\n\n";
%localtoppostgrey = ();
# Top spam detail statistics
$top = 0;
print OUT "\%::topspamdetail = (\n";
foreach my $t (sort keys %localtopspamdetail) {
print OUT "'$t' => {";
print OUT "'rule' => {";
foreach my $d (sort { $localtopspamdetail{$t}{rule}{$b} <=> $localtopspamdetail{$t}{rule}{$a} } keys %{$localtopspamdetail{$t}{rule}}) {
last if ($top == $CONFIG{TOP});
my $c = $localtopspamdetail{$t}{rule}{$d};
$d =~ s/'/\\'/g;
print OUT "'$d' => '$c',";
$top++;
}
print OUT "},";
delete $localtopspamdetail{$t}{rule};
$top = 0;
print OUT "'score' => {";
foreach my $d (sort { $localtopspamdetail{$t}{score}{$b} <=> $localtopspamdetail{$t}{score}{$a} } keys %{$localtopspamdetail{$t}{score}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopspamdetail{$t}{score}{$d}',";
$top++;
}
print OUT "},";
delete $localtopspamdetail{$t}{score};
$top = 0;
print OUT "'cache' => {";
foreach my $d (sort { $localtopspamdetail{$t}{cache}{$b} <=> $localtopspamdetail{$t}{cache}{$a} } keys %{$localtopspamdetail{$t}{cache}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopspamdetail{$t}{cache}{$d}',";
$top++;
}
print OUT "},";
delete $localtopspamdetail{$t}{cache};
$top = 0;
print OUT "'autolearn' => {";
foreach my $d (sort { $localtopspamdetail{$t}{autolearn}{$b} <=> $localtopspamdetail{$t}{autolearn}{$a} } keys %{$localtopspamdetail{$t}{autolearn}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopspamdetail{$t}{autolearn}{$d}',";
$top++;
}
print OUT "},";
delete $localtopspamdetail{$t}{autolearn};
$top = 0;
print OUT "},";
}
print OUT ");\n\n";
close(OUT);
} else {
&logerror("can't write cache file $file: $!");
}
}
sub set_direction
{
my ($sender_relay, $recipient_relay, $hostname) = @_;
# By default all mail are considered issued from local computer.
my $direction = 'Int_';
###### Check for sender origine
if ($sender_relay) {
# This host is a gateway and it forward mails to an internal hub or outside
if (!$CONFIG{MAIL_GW} && $CONFIG{MAIL_HUB}) {
if (!grep($sender_relay =~ /$_/i, split(/[\s\t,;]/, $CONFIG{MAIL_HUB}))) {
# if message doesn't come from localhost or user defined loca relay it comes from outside
if (exists $CONFIG{LOCAL_HOST_DOMAIN}{$hostname} && ($#{$CONFIG{LOCAL_HOST_DOMAIN}{$hostname}} > -1) ) {
$direction = 'Ext_' if (!grep($sender_relay =~ /\b$_$/, 'localhost', @{$CONFIG{LOCAL_HOST_DOMAIN}{$hostname}}));
} elsif (exists $CONFIG{LOCAL_DOMAIN} && ($#{$CONFIG{LOCAL_DOMAIN}} > -1)) {
$direction = 'Ext_' if (!grep($sender_relay =~ /\b$_$/, 'localhost', @{$CONFIG{LOCAL_DOMAIN}}));
}
}
# This host received all messages from a gateway
} elsif ($CONFIG{MAIL_GW} && !$CONFIG{MAIL_HUB}) {
# If sender relay is the gateway, it comes from outside
$direction = 'Ext_' if (grep($sender_relay =~ /$_/i, split(/[\s\t,;]/, $CONFIG{MAIL_GW}) ));
# This host is a hub, it received all messages from a gateway and forward them to other host
} elsif ($CONFIG{MAIL_GW} && $CONFIG{MAIL_HUB}) {
# If sender relay is the gateway, it comes from outside
$direction = 'Ext_' if (grep($sender_relay =~ /$_/i, split(/[\s\t,;]/, $CONFIG{MAIL_GW})));
} else {
# if message doesn't come from localhost or user defined loca relay it comes from outside
if (exists $CONFIG{LOCAL_HOST_DOMAIN}{$hostname} && ($#{$CONFIG{LOCAL_HOST_DOMAIN}{$hostname}} > -1) ) {
$direction = 'Ext_' if (!grep($sender_relay =~ /\b$_$/, 'localhost', @{$CONFIG{LOCAL_HOST_DOMAIN}{$hostname}}));
} elsif (exists $CONFIG{LOCAL_DOMAIN} && ($#{$CONFIG{LOCAL_DOMAIN}} > -1)) {
$direction = 'Ext_' if (!grep($sender_relay =~ /\b$_$/, 'localhost', @{$CONFIG{LOCAL_DOMAIN}}));
}
}
} else {
$direction = 'Unk_';
}
###### Now check for destination
if ($recipient_relay) {
# If the recipient relay is localhost, it should be distributed internally
if ($recipient_relay eq 'localhost') {
$direction .= 'Int';
# If this host is a mail gateway and the recipient relay match one of
# our destination hub lets say it should be distributed internally
} elsif ($CONFIG{MAIL_HUB} && (grep($recipient_relay =~ /$_/, split(/[\s\t,;]/, $CONFIG{MAIL_HUB}) )) ) {
$direction .= 'Int';
# If the recipient relay match any of our local domain
# lets say the mail should be distributed internally
} elsif (exists $CONFIG{LOCAL_HOST_DOMAIN}{$hostname} && ($#{$CONFIG{LOCAL_HOST_DOMAIN}{$hostname}} > -1) ){
if (grep($recipient_relay =~ /\b$_$/i, @{$CONFIG{LOCAL_HOST_DOMAIN}{$hostname}})) {
$direction .= 'Int';
} else {
$direction .= 'Ext';
}
} elsif (exists $CONFIG{LOCAL_DOMAIN} && ($#{$CONFIG{LOCAL_DOMAIN}} > -1)) {
if (grep($recipient_relay =~ /\b$_$/i, @{$CONFIG{LOCAL_DOMAIN}})) {
$direction .= 'Int';
} else {
$direction .= 'Ext';
}
# Finally his only way is to go outside
} else {
$direction .= 'Ext';
}
} else {
$direction .= 'Unk';
}
return $direction;
}
####
# Die cleanly on signal
####
sub terminate
{
&dprint("Received terminating signal.");
unlink("$CONFIG{PID_DIR}/$PID_FILE");
exit 0;
}
sub clear_postfix
{
my $str = shift;
# POSTFIX: Skip connect/disconnect message
if ($str =~ m#^(DIS)?CONNECT #i) {
return 1;
# POSTFIX temporary blacklist/whitelist messsage
} elsif ($str =~ m#^(PASS OLD|PASS NEW|WHITELISTED|BLACKLISTED)#i) {
return 1;
# POSTFIX pregreet test
} elsif ($str =~ m#^(PREGREET|HANGUP)#i) {
return 1;
# POSTFIX dnsbl message
} elsif ($str =~ m#^DNSBL rank#i) {
return 1;
# POSTFIX dnsbl message ???
} elsif ($str =~ m#addr \d+\.\d+\.\d+\.\d+ listed#i) {
return 1;
# POSTFIX postscreen error message: COMMAND (PIPELINING|COUNT LIMIT|TIME LIMIT)???
} elsif ($str =~ m#^COMMAND #i) {
return 1;
}
return 0;
}
####
# Weekly cache statistics
####
sub do_week_cache
{
my ($hostname, $DOMAIN, $year, $curyear, $week, $curweek) = @_;
if (!$DOMAIN && -e "$CONFIG{OUT_DIR}/$hostname/$year/weeks/$week/cache.pm" && ("$year$week" < "$curyear$curweek")) {
if ($CONFIG{WEEKLY_FREE_SPACE}) {
my @days = &get_week_boundaries($year, $week);
map { s/^/$CONFIG{OUT_DIR}\/$hostname\//; } @days;
# reduce disk space storage by deleting or archiving data file
&free_space_week("$CONFIG{OUT_DIR}/$hostname/$year/weeks/$week", @days);
return;
}
}
# This cache have been already build
if (-e "$CONFIG{OUT_DIR}/$hostname/$year/weeks/$week/cache.pm\U$DOMAIN\E" && ("$year$week" < "$curyear$curweek")) {
return;
}
print "Reading statistics from $CONFIG{OUT_DIR}/$hostname/$year/weeks/$week\n" if ($CONFIG{DEBUG});
my %localtopsender = ();
my %localtoprcpt = ();
my %localtopspam = ();
my %localtopvirus = ();
my %localtopdsn = ();
my %localtopreject = ();
my %localtoperr = ();
my %localdelivery = ();
my %localmessaging = ();
my %localspam = ();
my %localvirus = ();
my %localdsn = ();
my %localreject = ();
my %localerr = ();
my %localGLOBAL_STATUS = ();
my %localtopspamdetail = ();
my %localauth = ();
my %localtopauth = ();
my %localpostgrey = ();
my %localtoppostgrey = ();
my %localstarttls = ();
my %localspf_dkim = ();
my $lbls = '';
my %authval = ();
&clean_globals();
my @days = &get_week_boundaries($year, $week);
foreach my $path (@days) {
$path =~ /\/(\d+)$/;
my $day = "$1";
$lbls .= "$day:";
if (!-e "$CONFIG{OUT_DIR}/$hostname/$path/cache.pm\U$DOMAIN\E") {
$localmessaging{values} .= '0:';
$localmessaging{values1} .= '0:';
$localmessaging{values_bytes} .= '0:';
$localmessaging{values1_bytes} .= '0:';
$localspam{values} .= '0:';
$localvirus{values} .= '0:';
$localdsn{values} .= '0:';
$localmessaging{nbsender} .= '0:';
$localmessaging{nbrcpt} .= '0:';
next;
} else {
my $file = "$CONFIG{OUT_DIR}/$hostname/$path/cache.pm\U$DOMAIN\E";
print "Loading cache statistics from $file\n" if ($CONFIG{DEBUG});
do "$file";
foreach my $k (keys %messaging) {
if (!grep(/^$k$/, 'lbls','x_label','values','values1','values_bytes','values1_bytes','nbsender','nbrcpt')) {
$localmessaging{$k} += $messaging{$k};
}
}
$localmessaging{values} .= ($messaging{total_inbound} || 0) . ':';
$localmessaging{values1} .= ($messaging{total_outbound} || 0) . ':';
$localmessaging{values_bytes} .= ($messaging{total_inbound_bytes} || 0) . ':';
$localmessaging{values1_bytes} .= ($messaging{total_outbound_bytes} || 0) . ':';
my $tmp = 0;
foreach (split(/:/, $messaging{nbsender})) {
$tmp += $_;
}
$localmessaging{nbsender} .= $tmp . ':';
$tmp = 0;
foreach (split(/:/, $messaging{nbrcpt})) {
$tmp += $_;
}
$localmessaging{nbrcpt} .= $tmp . ':';
%messaging = ();
foreach my $t (keys %auth) {
foreach my $m (keys %{$auth{$t}}) {
if (!grep(/^$m$/, 'lbls','x_label','values')) {
$localauth{$t}{$m} += $auth{$t}{$m};
$localauth{$t}{values}{"$day"} += $auth{$t}{$m};
}
}
}
%auth = ();
foreach my $k (keys %spam) {
if (!grep(/^$k$/, 'lbls','x_label','values')) {
$localspam{$k} += $spam{$k};
}
}
$localspam{values} .= ($spam{total_inbound} || 0) . ':';
%spam = ();
foreach my $k (keys %reject) {
if (!grep(/^$k$/, 'lbls','x_label','values')) {
$localreject{$k} += $reject{$k};
}
}
%reject = ();
foreach my $k (keys %{$postgrey{reason}}) {
$localpostgrey{reason}{$k} += $postgrey{reason}{$k};
}
%postgrey = ();
foreach my $r (keys %{$spf_dkim{spf}}) {
foreach my $k (keys %{$spf_dkim{spf}{$r}{status}}) {
$localspf_dkim{spf}{$r}{status}{$k} += $spf_dkim{spf}{$r}{status}{$k};
}
foreach my $k (keys %{$spf_dkim{spf}{$r}{domain}}) {
$localspf_dkim{spf}{$r}{domain}{$k} += $spf_dkim{spf}{$r}{domain}{$k};
}
}
foreach my $r (keys %{$spf_dkim{dkim}{status}}) {
$localspf_dkim{dkim}{status}{$r} += $spf_dkim{dkim}{status}{$r};
}
%spf_dkim = ();
foreach my $k (keys %virus) {
if (!grep(/^$k$/, 'lbls','x_label','values')) {
$localvirus{$k} += $virus{$k};
}
}
$localvirus{values} .= ($virus{total_inbound} || 0) . ':';
%virus = ();
foreach my $k (keys %dsn) {
if (!grep(/^$k$/, 'lbls','x_label','values')) {
$localdsn{$k} += $dsn{$k};
}
}
$localdsn{values} .= ($dsn{total_outbound} || 0) . ':';
%dsn = ();
foreach my $k (keys %err) {
if (!grep(/^$k$/, 'lbls','x_label','values')) {
$localerr{$k} += $err{$k};
}
}
%err = ();
foreach my $k (keys %GLOBAL_STATUS) {
$localGLOBAL_STATUS{$k} += $GLOBAL_STATUS{$k};
}
%GLOBAL_STATUS = ();
foreach my $k (keys %starttls) {
$localstarttls{$k} += $starttls{$k};
}
%starttls = ();
foreach my $k (keys %delivery) {
if (!grep(/^$k$/, 'lbls','x_label')) {
$localdelivery{$k} += $delivery{$k};
}
}
foreach my $k (keys %topsender) {
foreach my $d (keys %{$topsender{$k}}) {
$localtopsender{$k}{$d} += $topsender{$k}{$d} || 0;
}
}
%topsender = ();
foreach my $k (keys %toprcpt) {
foreach my $d (keys %{$toprcpt{$k}}) {
$localtoprcpt{$k}{$d} += $toprcpt{$k}{$d} || 0;
}
}
%toprcpt = ();
foreach my $k (keys %topreject) {
foreach my $d (keys %{$topreject{$k}}) {
$localtopreject{$k}{$d} += $topreject{$k}{$d} || 0;
}
}
%topreject = ();
foreach my $k (keys %toppostgrey) {
foreach my $d (keys %{$toppostgrey{$k}}) {
$localtoppostgrey{$k}{$d} += $toppostgrey{$k}{$d} || 0;
}
}
%toppostgrey = ();
foreach my $k (keys %topvirus) {
foreach my $d (keys %{$topvirus{$k}}) {
$localtopvirus{$k}{$d} += $topvirus{$k}{$d} || 0;
}
}
%topvirus = ();
foreach my $k (keys %topdsn) {
foreach my $d (keys %{$topdsn{$k}}) {
$localtopdsn{$k}{$d} += $topdsn{$k}{$d} || 0;
}
}
%topdsn = ();
foreach my $k (keys %topspam) {
foreach my $d (keys %{$topspam{$k}}) {
$localtopspam{$k}{$d} += $topspam{$k}{$d} || 0;
}
}
%topspam = ();
foreach my $k (keys %toperr) {
$localtoperr{$k} += $toperr{$k} || 0;
}
%toperr = ();
foreach my $t (keys %topspamdetail) {
foreach my $k (keys %{$topspamdetail{$t}}) {
foreach my $d (keys %{$topspamdetail{$t}{$k}}) {
$localtopspamdetail{$t}{$k}{$d} += $topspamdetail{$t}{$k}{$d} || 0;
}
}
}
%topspamdetail = ();
foreach my $k (keys %topauth) {
foreach my $d (keys %{$topauth{$k}}) {
$localtopauth{$k}{$d} += $topauth{$k}{$d} || 0;
}
}
%topauth = ();
}
foreach my $t (keys %localauth) {
$authval{$t} .= ($localauth{$t}{values}{"$day"} || 0) . ':';
}
}
foreach my $t (keys %localauth) {
delete $localauth{$t}{values};
$localauth{$t}{values} = $authval{$t};
$localauth{$t}{lbls} =~ s/:$//;
$localauth{$t}{values} =~ s/:$//;
}
$lbls =~ s/:$//;
$localmessaging{values} =~ s/:$//;
$localmessaging{values1} =~ s/:$//;
$localmessaging{values_bytes} =~ s/:$//;
$localmessaging{values1_bytes} =~ s/:$//;
$localspam{values} =~ s/:$//;
$localvirus{values} =~ s/:$//;
$localdsn{values} =~ s/:$//;
$localmessaging{nbrcpt} =~ s/:$//;
$localmessaging{nbsender} =~ s/:$//;
# Create weeks directory if they do not exist yet
if (!-d "$CONFIG{OUT_DIR}/$hostname/$year/weeks") {
&create_directory("$hostname/$year/weeks");
}
if (!-d "$CONFIG{OUT_DIR}/$hostname/$year/weeks/$week") {
&create_directory("$hostname/$year/weeks/$week");
}
my $file = "$CONFIG{OUT_DIR}/$hostname/$year/weeks/$week/cache.pm\U$DOMAIN\E";
print "Writing cache file: $file\n" if ($CONFIG{DEBUG});
if (open(OUT, ">$file")) {
print OUT "\%::auth = (\n";
foreach my $type (keys %localauth) {
print OUT "'$type' => {";
print OUT "'values' => '$localauth{$type}{values}',";
print OUT "'lbls' => '$lbls',";
print OUT "'x_label' => 'Days of the week',";
foreach my $mech (keys %{$localauth{$type}}) {
next if (grep(/^$mech$/,'lbls','x_label','values'));
print OUT "'$mech' => '$localauth{$type}{$mech}',";
}
print OUT "},\n";
}
print OUT ");\n\n";
%localauth = ();
print OUT "\%::messaging = (\n";
print OUT "'inbound' => '$localmessaging{inbound}',\n";
print OUT "'inbound_bytes' => '$localmessaging{inbound_bytes}',\n";
print OUT "'local_inbound' => '$localmessaging{local_inbound}',\n";
print OUT "'local_inbound_bytes' => '$localmessaging{local_inbound_bytes}',\n";
print OUT "'total_inbound' => '$localmessaging{total_inbound}',\n";
print OUT "'total_inbound_bytes' => '$localmessaging{total_inbound_bytes}',\n";
print OUT "'outbound' => '$localmessaging{outbound}',\n";
print OUT "'outbound_bytes' => '$localmessaging{outbound_bytes}',\n";
print OUT "'local_outbound' => '$localmessaging{local_outbound}',\n";
print OUT "'local_outbound_bytes' => '$localmessaging{local_outbound_bytes}',\n";
print OUT "'total_outbound' => '$localmessaging{total_outbound}',\n";
print OUT "'total_outbound_bytes' => '$localmessaging{total_outbound_bytes}',\n";
print OUT "'lbls' => '$lbls',\n";
print OUT "'x_label' => 'Days of the week',\n";
print OUT "'values' => '$localmessaging{values}',\n";
print OUT "'values1' => '$localmessaging{values1}',\n";
print OUT "'values_bytes' => '$localmessaging{values_bytes}',\n";
print OUT "'values1_bytes' => '$localmessaging{values1_bytes}',\n";
print OUT "'nbsender' => '$localmessaging{nbsender}',\n";
print OUT "'nbrcpt' => '$localmessaging{nbrcpt}',\n";
print OUT ");\n\n";
%localmessaging = ();
print OUT "\%::spam = (\n";
print OUT "'inbound' => '$localspam{inbound}',\n";
print OUT "'inbound_bytes' => '$localspam{inbound_bytes}',\n";
print OUT "'local_inbound' => '$localspam{local_inbound}',\n";
print OUT "'local_inbound_bytes' => '$localspam{local_inbound_bytes}',\n";
print OUT "'total_inbound' => '$localspam{total_inbound}',\n";
print OUT "'total_inbound_bytes' => '$localspam{total_inbound_bytes}',\n";
print OUT "'outbound' => '$localspam{outbound}',\n";
print OUT "'outbound_bytes' => '$localspam{outbound_bytes}',\n";
print OUT "'local_outbound' => '$localspam{local_outbound}',\n";
print OUT "'local_outbound_bytes' => '$localspam{local_outbound_bytes}',\n";
print OUT "'total_outbound' => '$localspam{total_outbound}',\n";
print OUT "'total_outbound_bytes' => '$localspam{total_outbound_bytes}',\n";
print OUT "'lbls' => '$lbls',\n";
print OUT "'x_label' => 'Days of the week',\n";
print OUT "'values' => '$localspam{values}',\n";
print OUT "'Ext_Int' => '$localspam{Ext_Int}',\n";
print OUT "'Int_Int' => '$localspam{Int_Int}',\n";
print OUT "'Int_Ext' => '$localspam{Int_Ext}',\n";
print OUT "'Ext_Ext' => '$localspam{Ext_Ext}',\n";
print OUT "'Ext_Int_bytes' => '$localspam{Ext_Int_bytes}',\n";
print OUT "'Int_Int_bytes' => '$localspam{Int_Int_bytes}',\n";
print OUT "'Int_Ext_bytes' => '$localspam{Int_Ext_bytes}',\n";
print OUT "'Ext_Ext_bytes' => '$localspam{Ext_Ext_bytes}',\n";
print OUT ");\n\n";
%localspam = ();
print OUT "\%::reject = (\n";
print OUT "'inbound' => '$localreject{inbound}',\n";
print OUT "'inbound_bytes' => '$localreject{inbound_bytes}',\n";
print OUT "'local_inbound' => '$localreject{local_inbound}',\n";
print OUT "'local_inbound_bytes' => '$localreject{local_inbound_bytes}',\n";
print OUT "'total_inbound' => '$localreject{total_inbound}',\n";
print OUT "'total_inbound_bytes' => '$localreject{total_inbound_bytes}',\n";
print OUT ");\n\n";
%localreject = ();
print OUT "\%::postgrey = (\n";
print OUT "'reason' => {";
foreach my $k (keys %{$localpostgrey{reason}}) {
print OUT "\t'$k' => '$localpostgrey{reason}{$k}',";
}
print OUT "},\n";
print OUT ");\n\n";
%localpostgrey = ();
print OUT "\%::spf_dkim = (\n";
print OUT "'spf' => {\n";
foreach my $r (keys %{$localspf_dkim{spf}}) {
print OUT "\t'$r' => {\n";
foreach my $s (keys %{$localspf_dkim{spf}{$r}}) {
print OUT "\t\t'$s' => { ";
foreach my $v (keys %{$localspf_dkim{spf}{$r}{$s}}) {
print OUT "'$v' => '$localspf_dkim{spf}{$r}{$s}{$v}',";
}
print OUT " },\n";
}
print OUT "\t},\n";
}
print OUT "},\n";
print OUT "'dkim' => {\n";
foreach my $r (keys %{$localspf_dkim{dkim}}) {
print OUT "\t'$r' => {\n";
foreach my $s (keys %{$localspf_dkim{dkim}{$r}}) {
print OUT "\t\t'$s' => '$localspf_dkim{dkim}{$r}{$s}',\n";
}
print OUT "\t},\n";
}
print OUT "},\n";
print OUT ");\n\n";
%localspf_dkim = ();
print OUT "\%::virus = (\n";
print OUT "'inbound' => '$localvirus{inbound}',\n";
print OUT "'inbound_bytes' => '$localvirus{inbound_bytes}',\n";
print OUT "'local_inbound' => '$localvirus{local_inbound}',\n";
print OUT "'local_inbound_bytes' => '$localvirus{local_inbound_bytes}',\n";
print OUT "'total_inbound' => '$localvirus{total_inbound}',\n";
print OUT "'total_inbound_bytes' => '$localvirus{total_inbound_bytes}',\n";
print OUT "'outbound' => '$localvirus{outbound}',\n";
print OUT "'outbound_bytes' => '$localvirus{outbound_bytes}',\n";
print OUT "'local_outbound' => '$localvirus{local_outbound}',\n";
print OUT "'local_outbound_bytes' => '$localvirus{local_outbound_bytes}',\n";
print OUT "'total_outbound' => '$localvirus{total_outbound}',\n";
print OUT "'total_outbound_bytes' => '$localvirus{total_outbound_bytes}',\n";
print OUT "'lbls' => '$lbls',\n";
print OUT "'x_label' => 'Days of the week',\n";
print OUT "'values' => '$localvirus{values}',\n";
print OUT "'Ext_Int' => '$localvirus{Ext_Int}',\n";
print OUT "'Int_Int' => '$localvirus{Int_Int}',\n";
print OUT "'Int_Ext' => '$localvirus{Int_Ext}',\n";
print OUT "'Ext_Ext' => '$localvirus{Ext_Ext}',\n";
print OUT "'Ext_Int_bytes' => '$localvirus{Ext_Int_bytes}',\n";
print OUT "'Int_Int_bytes' => '$localvirus{Int_Int_bytes}',\n";
print OUT "'Int_Ext_bytes' => '$localvirus{Int_Ext_bytes}',\n";
print OUT "'Ext_Ext_bytes' => '$localvirus{Ext_Ext_bytes}',\n";
print OUT ");\n\n";
%localvirus = ();
print OUT "\%::dsn = (\n";
print OUT "'outbound' => '$localdsn{outbound}',\n";
print OUT "'local_outbound' => '$localdsn{local_outbound}',\n";
print OUT "'total_outbound' => '$localdsn{total_outbound}',\n";
print OUT "'error' => '$localdsn{error}',\n";
print OUT "'lbls' => '$lbls',\n";
print OUT "'x_label' => 'Days of the week',\n";
print OUT "'values' => '$localdsn{values}',\n";
print OUT "'Ext_Int' => '$localdsn{Ext_Int}',\n";
print OUT "'Int_Int' => '$localdsn{Int_Int}',\n";
print OUT "'Int_Ext' => '$localdsn{Int_Ext}',\n";
print OUT "'Ext_Ext' => '$localdsn{Ext_Ext}',\n";
print OUT ");\n\n";
%localdsn = ();
print OUT "\%::err = (\n";
print OUT "'inbound' => '$localerr{inbound}',\n";
print OUT "'inbound_bytes' => '$localerr{inbound_bytes}',\n";
print OUT "'local_inbound' => '$localerr{local_inbound}',\n";
print OUT "'local_inbound_bytes' => '$localerr{local_inbound_bytes}',\n";
print OUT "'total_inbound' => '$localerr{total_inbound}',\n";
print OUT "'total_inbound_bytes' => '$localerr{total_inbound_bytes}',\n";
print OUT ");\n\n";
%localerr = ();
print OUT "\%::GLOBAL_STATUS = (\n";
foreach my $k (keys %localGLOBAL_STATUS) {
my $slbl = $k;
$slbl =~ s/'/\\'/g;
print OUT "'$slbl' => '$localGLOBAL_STATUS{$k}',\n";
}
print OUT ");\n\n";
%localGLOBAL_STATUS = ();
print OUT "\%::starttls = (\n";
foreach my $k (keys %localstarttls) {
my $slbl = $k;
$slbl =~ s/'/\\'/g;
print OUT "'$slbl' => '$localstarttls{$k}',\n";
}
print OUT ");\n\n";
%localstarttls = ();
my $elbls = 'Ext -> Int:Ext -> Ext:Int -> Int:Int -> Ext';
print OUT "\%::delivery = (\n";
print OUT "'lbls' => '$elbls',\n";
print OUT "'x_label' => 'Days of the week',\n";
print OUT "'Ext_Int' => '$localdelivery{Ext_Int}',\n";
print OUT "'Int_Int' => '$localdelivery{Int_Int}',\n";
print OUT "'Int_Ext' => '$localdelivery{Int_Ext}',\n";
print OUT "'Ext_Ext' => '$localdelivery{Ext_Ext}',\n";
print OUT "'Ext_Int_bytes' => '$localdelivery{Ext_Int_bytes}',\n";
print OUT "'Int_Int_bytes' => '$localdelivery{Int_Int_bytes}',\n";
print OUT "'Int_Ext_bytes' => '$localdelivery{Int_Ext_bytes}',\n";
print OUT "'Ext_Ext_bytes' => '$localdelivery{Ext_Ext_bytes}',\n";
print OUT ");\n\n";
%localdelivery = ();
# Top SMTP Auth statistics
my $top = 0;
print OUT "\%::topauth = (\n";
print OUT "'relay' => {";
foreach my $d (sort { $localtopauth{relay}{$b} <=> $localtopauth{relay}{$a} } keys %{$localtopauth{relay}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopauth{relay}{$d}',";
$top++;
}
print OUT "},\n";
delete $localtopauth{relay};
$top = 0;
print OUT "'mech' => {";
foreach my $d (sort { $localtopauth{mech}{$b} <=> $localtopauth{mech}{$a} } keys %{$localtopauth{mech}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopauth{mech}{$d}',";
$top++;
}
print OUT "},\n";
delete $localtopauth{mech};
$top = 0;
print OUT "'authid' => {";
foreach my $d (sort { $localtopauth{authid}{$b} <=> $localtopauth{authid}{$a} } keys %{$localtopauth{authid}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopauth{authid}{$d}',";
$top++;
}
print OUT "},\n";
print OUT ");\n\n";
%localtopauth = ();
# Top sender statistics
$top = 0;
print OUT "\%::topsender = (\n";
print OUT "'domain' => {";
foreach my $d (sort { $localtopsender{domain}{$b} <=> $localtopsender{domain}{$a} } keys %{$localtopsender{domain}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopsender{domain}{$d}',";
$top++;
}
print OUT "},\n";
delete $localtopsender{domain};
$top = 0;
print OUT "'relay' => {";
foreach my $d (sort { $localtopsender{relay}{$b} <=> $localtopsender{relay}{$a} } keys %{$localtopsender{relay}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopsender{relay}{$d}',";
$top++;
}
print OUT "},\n";
delete $localtopsender{relay};
$top = 0;
print OUT "'email' => {";
foreach my $d (sort { $localtopsender{email}{$b} <=> $localtopsender{email}{$a} } keys %{$localtopsender{email}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopsender{email}{$d}',";
$top++;
}
print OUT "},\n";
print OUT ");\n\n";
%localtopsender = ();
# Top recipient statistics
$top = 0;
print OUT "\%::toprcpt = (\n";
print OUT "'domain' => {";
foreach my $d (sort { $localtoprcpt{domain}{$b} <=> $localtoprcpt{domain}{$a} } keys %{$localtoprcpt{domain}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtoprcpt{domain}{$d}',";
$top++;
}
print OUT "},\n";
delete $localtoprcpt{domain};
$top = 0;
print OUT "'relay' => {";
foreach my $d (sort { $localtoprcpt{relay}{$b} <=> $localtoprcpt{relay}{$a} } keys %{$localtoprcpt{relay}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtoprcpt{relay}{$d}',";
$top++;
}
print OUT "},\n";
delete $localtoprcpt{relay};
$top = 0;
print OUT "'email' => {";
foreach my $d (sort { $localtoprcpt{email}{$b} <=> $localtoprcpt{email}{$a} } keys %{$localtoprcpt{email}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtoprcpt{email}{$d}',";
$top++;
}
print OUT "},\n";
print OUT ");\n\n";
%localtoprcpt = ();
# Top rejection statistics
$top = 0;
print OUT "\%::topreject = (\n";
print OUT "'rule' => {";
foreach my $d (sort { $localtopreject{rule}{$b} <=> $localtopreject{rule}{$a} } keys %{$localtopreject{rule}}) {
last if ($top == $CONFIG{TOP});
my $c = $localtopreject{rule}{$d};
$d =~ s/'/\\'/g;
print OUT "'$d' => '$c',";
$top++;
}
print OUT "},\n";
delete $localtopreject{rule};
$top = 0;
print OUT "'domain' => {";
foreach my $d (sort { $localtopreject{domain}{$b} <=> $localtopreject{domain}{$a} } keys %{$localtopreject{domain}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopreject{domain}{$d}',";
$top++;
}
print OUT "},\n";
delete $localtopreject{domain};
$top = 0;
print OUT "'relay' => {";
foreach my $d (sort { $localtopreject{relay}{$b} <=> $localtopreject{relay}{$a} } keys %{$localtopreject{relay}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopreject{relay}{$d}',";
$top++;
}
print OUT "},\n";
delete $localtopreject{relay};
$top = 0;
print OUT "'chck_status' => {";
foreach my $d (sort { $localtopreject{chck_status}{$b} <=> $localtopreject{chck_status}{$a} } keys %{$localtopreject{chck_status}}) {
last if ($top == $CONFIG{TOP});
my $c = $localtopreject{chck_status}{$d};
$d =~ s/'/\\'/g;
print OUT "'$d' => '$c',";
$top++;
}
print OUT "},\n";
delete $localtopreject{chck_status};
$top = 0;
print OUT "'sender' => {";
foreach my $d (sort { $localtopreject{sender}{$b} <=> $localtopreject{sender}{$a} } keys %{$localtopreject{sender}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopreject{sender}{$d}',";
$top++;
}
print OUT "},\n";
print OUT ");\n\n";
%localtopreject = ();
# Top postgrey statistics
$top = 0;
print OUT "\%::toppostgrey = (\n";
print OUT "'sender' => {";
foreach my $d (sort { $localtoppostgrey{sender}{$b} <=> $localtoppostgrey{sender}{$a} } keys %{$localtoppostgrey{sender}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtoppostgrey{sender}{$d}',";
$top++;
}
print OUT "},\n";
delete $localtoppostgrey{sender};
$top = 0;
print OUT "'sender_relay' => {";
foreach my $d (sort { $localtoppostgrey{sender_relay}{$b} <=> $localtoppostgrey{sender_relay}{$a} } keys %{$localtoppostgrey{sender_relay}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtoppostgrey{sender_relay}{$d}',";
$top++;
}
print OUT "},\n";
delete $localtoppostgrey{sender_relay};
$top= 0;
print OUT "'domain' => {";
foreach my $d (sort { $localtoppostgrey{domain}{$b} <=> $localtoppostgrey{domain}{$a} } keys %{$localtoppostgrey{domain}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtoppostgrey{domain}{$d}',";
$top++;
}
print OUT "},\n";
delete $localtoppostgrey{domain};
$top= 0;
print OUT "'reason' => {";
foreach my $d (sort { $localtoppostgrey{reason}{$b} <=> $localtoppostgrey{reason}{$a} } keys %{$localtoppostgrey{reason}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtoppostgrey{reason}{$d}',";
$top++;
}
print OUT "},\n";
delete $localtoppostgrey{reason};
$top= 0;
print OUT "'rcpt' => {";
foreach my $d (sort { $localtoppostgrey{rcpt}{$b} <=> $localtoppostgrey{rcpt}{$a} } keys %{$localtoppostgrey{rcpt}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtoppostgrey{rcpt}{$d}',";
$top++;
}
print OUT "},\n";
print OUT ");\n\n";
%localtoppostgrey = ();
# Top virus statistics
$top = 0;
print OUT "\%::topvirus = (\n";
print OUT "'virus' => {";
foreach my $d (sort { $localtopvirus{virus}{$b} <=> $localtopvirus{virus}{$a} } keys %{$localtopvirus{virus}}) {
last if ($top == $CONFIG{TOP});
my $c = $localtopvirus{virus}{$d};
$d =~ s/'/\\'/g;
print OUT "'$d' => '$c',";
$top++;
}
print OUT "},\n";
delete $localtopvirus{virus};
$top = 0;
print OUT "'sender' => {";
foreach my $d (sort { $localtopvirus{sender}{$b} <=> $localtopvirus{sender}{$a} } keys %{$localtopvirus{sender}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopvirus{sender}{$d}',";
$top++;
}
print OUT "},\n";
delete $localtopvirus{sender};
$top = 0;
print OUT "'relay' => {";
foreach my $d (sort { $localtopvirus{relay}{$b} <=> $localtopvirus{relay}{$a} } keys %{$localtopvirus{relay}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopvirus{relay}{$d}',";
$top++;
}
print OUT "},\n";
delete $localtopvirus{relay};
$top = 0;
print OUT "'file' => {";
foreach my $d (sort { $localtopvirus{file}{$b} <=> $localtopvirus{file}{$a} } keys %{$localtopvirus{file}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopvirus{file}{$d}',";
$top++;
}
print OUT "},\n";
delete $localtopvirus{file};
$top = 0;
print OUT "'rcpt' => {";
foreach my $d (sort { $localtopvirus{rcpt}{$b} <=> $localtopvirus{rcpt}{$a} } keys %{$localtopvirus{rcpt}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopvirus{rcpt}{$d}',";
$top++;
}
print OUT "},\n";
print OUT ");\n\n";
%localtopvirus = ();
# Top dsn statistics
$top = 0;
print OUT "\%::topdsn = (\n";
print OUT "'dsnstatus' => {";
foreach my $d (sort { $localtopdsn{dsnstatus}{$b} <=> $localtopdsn{dsnstatus}{$a} } keys %{$localtopdsn{dsnstatus}}) {
last if ($top == $CONFIG{TOP});
my $c = $localtopdsn{dsnstatus}{$d};
$d =~ s/'/\\'/g;
print OUT "'$d' => '$c',";
$top++;
}
print OUT "},\n";
delete $localtopdsn{dsnstatus};
$top = 0;
print OUT "'sender' => {";
foreach my $d (sort { $localtopdsn{sender}{$b} <=> $localtopdsn{sender}{$a} } keys %{$localtopdsn{sender}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopdsn{sender}{$d}',";
$top++;
}
print OUT "},\n";
delete $localtopdsn{sender};
$top = 0;
print OUT "'relay' => {";
foreach my $d (sort { $localtopdsn{relay}{$b} <=> $localtopdsn{relay}{$a} } keys %{$localtopdsn{relay}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopdsn{relay}{$d}',";
$top++;
}
print OUT "},\n";
delete $localtopdsn{relay};
$top = 0;
print OUT "'rcpt' => {";
foreach my $d (sort { $localtopdsn{rcpt}{$b} <=> $localtopdsn{rcpt}{$a} } keys %{$localtopdsn{rcpt}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopdsn{rcpt}{$d}',";
$top++;
}
print OUT "},\n";
print OUT ");\n\n";
%localtopdsn = ();
# Top spam statistics
$top = 0;
print OUT "\%::topspam = (\n";
print OUT "'rule' => {";
foreach my $d (sort { $localtopspam{rule}{$b} <=> $localtopspam{rule}{$a} } keys %{$localtopspam{rule}}) {
last if ($top == $CONFIG{TOP});
my $c = $localtopspam{rule}{$d};
$d =~ s/'/\\'/g;
print OUT "'$d' => '$c',";
$top++;
}
print OUT "},";
delete $localtopspam{rule};
$top = 0;
print OUT "'domain' => {";
foreach my $d (sort { $localtopspam{domain}{$b} <=> $localtopspam{domain}{$a} } keys %{$localtopspam{domain}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopspam{domain}{$d}',";
$top++;
}
print OUT "},";
delete $localtopspam{domain};
$top = 0;
print OUT "'sender_relay' => {";
foreach my $d (sort { $localtopspam{sender_relay}{$b} <=> $localtopspam{sender_relay}{$a} } keys %{$localtopspam{sender_relay}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopspam{sender_relay}{$d}',";
$top++;
}
print OUT "},";
delete $localtopspam{sender_relay};
$top = 0;
print OUT "'sender' => {";
foreach my $d (sort { $localtopspam{sender}{$b} <=> $localtopspam{sender}{$a} } keys %{$localtopspam{sender}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopspam{sender}{$d}',";
$top++;
}
print OUT "},";
delete $localtopspam{sender};
$top = 0;
print OUT "'rcpt' => {";
foreach my $d (sort { $localtopspam{rcpt}{$b} <=> $localtopspam{rcpt}{$a} } keys %{$localtopspam{rcpt}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopspam{rcpt}{$d}',";
$top++;
}
print OUT "},";
print OUT ");\n\n";
%localtopspam = ();
# Top system message statistics
$top = 0;
print OUT "\%::toperr = (\n";
foreach my $m (sort { $localtopspam{$b} <=> $localtopspam{$a} } keys %localtoperr) {
my $c = $localtoperr{$m};
$m =~ s/'/\\'/g;
print OUT "'$m' => $c,\n";
}
print OUT ");\n";
%localtoperr = ();
# Top spam detail statistics
$top = 0;
print OUT "\%::topspamdetail = (\n";
foreach my $t (sort keys %localtopspamdetail) {
print OUT "'$t' => {";
print OUT "'rule' => {";
foreach my $d (sort { $localtopspamdetail{$t}{rule}{$b} <=> $localtopspamdetail{$t}{rule}{$a} } keys %{$localtopspamdetail{$t}{rule}}) {
last if ($top == $CONFIG{TOP});
my $c = $localtopspamdetail{$t}{rule}{$d};
$d =~ s/'/\\'/g;
print OUT "'$d' => '$c',";
$top++;
}
print OUT "},";
delete $localtopspamdetail{$t}{rule};
$top = 0;
print OUT "'score' => {";
foreach my $d (sort { $localtopspamdetail{$t}{score}{$b} <=> $localtopspamdetail{$t}{score}{$a} } keys %{$localtopspamdetail{$t}{score}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopspamdetail{$t}{score}{$d}',";
$top++;
}
print OUT "},";
delete $localtopspamdetail{$t}{score};
$top = 0;
print OUT "'cache' => {";
foreach my $d (sort { $localtopspamdetail{$t}{cache}{$b} <=> $localtopspamdetail{$t}{cache}{$a} } keys %{$localtopspamdetail{$t}{cache}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopspamdetail{$t}{cache}{$d}',";
$top++;
}
print OUT "},";
delete $localtopspamdetail{$t}{cache};
$top = 0;
print OUT "'autolearn' => {";
foreach my $d (sort { $localtopspamdetail{$t}{autolearn}{$b} <=> $localtopspamdetail{$t}{autolearn}{$a} } keys %{$localtopspamdetail{$t}{autolearn}}) {
last if ($top == $CONFIG{TOP});
print OUT "'$d' => '$localtopspamdetail{$t}{autolearn}{$d}',";
$top++;
}
print OUT "},";
delete $localtopspamdetail{$t}{autolearn};
$top = 0;
print OUT "},";
}
print OUT ");\n";
close(OUT);
} else {
&logerror("can't write cache file $file: $!");
}
}
####
# Create output directory tree
####
sub create_directory
{
my $dest = shift;
my $curdir = '';
foreach my $d (split(/\//, $dest)) {
$curdir .= $d . '/';
if (!-d "$CONFIG{OUT_DIR}/$curdir") {
if (not mkdir("$CONFIG{OUT_DIR}/$curdir")) {
&logerror("Can't create directory $CONFIG{OUT_DIR}/$curdir: $!");
&logerror("Data will be lost.");
return 0;
}
}
}
return 1;
}
####
# Get all days of a week
####
sub get_week_boundaries
{
my ($year, $week) = @_;
my @days = ();
my $wn = 0;
for my $m ('01' .. '12') {
for my $d ('01' .. '31') {
$wn = &get_week_number($year,$m,$d);
next if ($wn == -1);
push(@days, "$year/$m/$d") if ($wn == $week);
}
}
return @days;
}
####
# Get the week day of a date
####
sub get_day_of_week
{
my ($year, $month, $day) = @_;
# %u The day of the week as a decimal, range 1 to 7, Monday being 1.
# %w The day of the week as a decimal, range 0 to 6, Sunday being 0.
#my $weekDay = POSIX::strftime("%u", gmtime timelocal_nocheck(0,0,0,$day,--$month,$year));
my $weekDay = POSIX::strftime("%u", 1,1,1,$day,--$month,$year-1900);
return $weekDay;
}
####
# Fix relay not sanityzed in sendmailanalyzer script
####
sub clean_relay
{
my $relay = shift;
if ( $relay =~ s/\(([a-fA-F0-9\.\:]+)\)// ) {
$relay = $1;
}
$relay =~ s/:/_/g; # fix ipv6 to remove data field separator
return $relay;
}