#!/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; }