#!/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 .
#
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 ";
$COPYRIGHT = "(c) 2002-2020 - Gilles Darold ";
# 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 () {
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 = ) {
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 = ) {
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 = ) {
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 = ) {
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 = ) {
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 = ) {
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 = ) {
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 = ) {
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 = ) {
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 = ) {
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 = ) {
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 = ) {
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 = ) {
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;
}