1 | addr.domain.com [1.2.3.4] a.user@domain.com | addr2.domain2.com [5.6.7.8] a2.user2@domain2.com |
my $reached_table = 0;
my($count,$sender);
while (<$fh>) {
unless ($reached_table) {
last if (/No relayed messages/);
$reached_table = 1 if (/^\s*\d/ || />\d+);
next unless $reached_table;
}
if (/>(\d+)<.td>(.*?) ?<.td> | (.*?)) {
update_relayed($1,$2,$3);
}
elsif (/^\s*(\d+)\s+(.*?)\s*$/) {
($count,$sender) = ($1,$2);
}
elsif (/=>\s+(.*?)\s*$/) {
update_relayed($count,$sender,$1);
}
else {
last; #Finished the table ?
}
}
}
elsif (/Top (.*?) by (message count|volume)/) {
#Top 50 sending hosts by message count
#-------------------------------------
#
# 48 1468KB local
# Could also have average values for HTML output.
# 48 1468KB 30KB local
my($category,$by_count_or_volume) = ($1,$2);
#As we show 2 views of each table (by count and by volume),
#most (but not all) entries will appear in both tables.
#Set up a hash to record which entries we have already seen
#and one to record which ones we are seeing for the first time.
if ($by_count_or_volume =~ /count/) {
undef %league_table_value_entered;
undef %league_table_value_was_zero;
undef %table_order;
}
#As this section processes multiple different table categories,
#set up pointers to the hashes to be updated.
my($messages_href,$addresses_href,$data_href,$data_gigs_href);
if ($category =~ /local sender/) {
$messages_href = \%received_count_user;
$addresses_href = undef;
$data_href = \%received_data_user;
$data_gigs_href = \%received_data_gigs_user;
}
elsif ($category =~ /sending (\S+?)s?\b/) {
#Top 50 sending (host|domain|email|edomain)s
#Top sending (host|domain|email|edomain)
$messages_href = \%{$received_count{"\u$1"}};
$data_href = \%{$received_data{"\u$1"}};
$data_gigs_href = \%{$received_data_gigs{"\u$1"}};
}
elsif ($category =~ /local destination/) {
$messages_href = \%delivered_messages_user;
$addresses_href = \%delivered_addresses_user;
$data_href = \%delivered_data_user;
$data_gigs_href = \%delivered_data_gigs_user;
}
elsif ($category =~ /local domain destination/) {
$messages_href = \%delivered_messages_local_domain;
$addresses_href = \%delivered_addresses_local_domain;
$data_href = \%delivered_data_local_domain;
$data_gigs_href = \%delivered_data_gigs_local_domain;
}
elsif ($category =~ /(\S+) destination/) {
#Top 50 (host|domain|email|edomain) destinations
#Top (host|domain|email|edomain) destination
$messages_href = \%{$delivered_messages{"\u$1"}};
$addresses_href = \%{$delivered_addresses{"\u$1"}};
$data_href = \%{$delivered_data{"\u$1"}};
$data_gigs_href = \%{$delivered_data_gigs{"\u$1"}};
}
elsif ($category =~ /temporarily rejected ips/) {
$messages_href = \%temporarily_rejected_count_by_ip;
}
elsif ($category =~ /rejected ips/) {
$messages_href = \%rejected_count_by_ip;
}
elsif ($category =~ /non-rejected spamming ips/) {
$messages_href = \%spam_count_by_ip;
}
elsif ($category =~ /mail temporary rejection reasons/) {
$messages_href = \%temporarily_rejected_count_by_reason;
}
elsif ($category =~ /mail rejection reasons/) {
$messages_href = \%rejected_count_by_reason;
}
my $reached_table = 0;
my $row_re;
while (<$fh>) {
# Watch out for empty tables.
goto PARSE_OLD_REPORT_LINE if (// or (/^\s*[a-zA-Z]/ && !/^\s*Messages/));
$_ = html2txt($_); #Convert general HTML markup to text.
# Messages Addresses Bytes Average
if (/^\s*Messages/) {
my $pattern = '^\s*(\d+)';
$pattern .= (/Addresses/) ? '\s+(\d+)' : '()';
$pattern .= (/Bytes/) ? '\s+([\dKMGB]+)' : '()';
$pattern .= (/Average/) ? '\s+[\dKMGB]+' : '';
$pattern .= '\s+(.*?)\s*$';
$row_re = qr/$pattern/;
$reached_table = 1;
next;
}
next unless $reached_table;
my($messages, $addresses, $rounded_volume, $entry);
if (/$row_re/) {
($messages, $addresses, $rounded_volume, $entry) = ($1, $2, $3, $4);
}
else {
#Else we have finished the table and we may need to do some
#kludging to retain the order of the entries.
if ($by_count_or_volume =~ /volume/) {
#Add a few bytes to appropriate entries to preserve the order.
foreach $rounded_volume (keys %table_order) {
#For each rounded volume, we want to create a list which has things
#ordered from the volume table at the front, and additional things
#from the count table ordered at the back.
@{$table_order{$rounded_volume}{volume}} = () unless defined $table_order{$rounded_volume}{volume};
@{$table_order{$rounded_volume}{'message count'}} = () unless defined $table_order{$rounded_volume}{'message count'};
my(@order,%mark);
map {$mark{$_} = 1} @{$table_order{$rounded_volume}{volume}};
@order = @{$table_order{$rounded_volume}{volume}};
map {push(@order,$_)} grep(!$mark{$_},@{$table_order{$rounded_volume}{'message count'}});
my $bonus_bytes = $#order;
$bonus_bytes = 511 if ($bonus_bytes > 511); #Don't go over the half-K boundary!
while (@order and ($bonus_bytes > 0)) {
my $entry = shift(@order);
if ($league_table_value_was_zero{$entry}) {
$$data_href{$entry} += $bonus_bytes;
print STDERR "$category by $by_count_or_volume: added $bonus_bytes bonus bytes to $entry\n" if $debug;
}
$bonus_bytes--;
}
}
}
last;
}
# Store a new table entry.
# Add the entry into the %table_order hash if it has a rounded
# volume (KB/MB/GB).
push(@{$table_order{$rounded_volume}{$by_count_or_volume}},$entry) if ($rounded_volume =~ /\D/);
unless ($league_table_value_entered{$entry}) {
$league_table_value_entered{$entry} = 1;
unless ($$messages_href{$entry}) {
$$messages_href{$entry} = 0;
$$addresses_href{$entry} = 0;
$$data_href{$entry} = 0;
$$data_gigs_href{$entry} = 0;
$league_table_value_was_zero{$entry} = 1;
}
$$messages_href{$entry} += $messages;
# When adding the addresses, be aware that we could be merging
# an old report which does not include addresses. In this case,
# we add the messages instead.
$$addresses_href{$entry} += ($addresses) ? $addresses : $messages;
#Add the rounded value to the data and data_gigs hashes.
un_round($rounded_volume,\$$data_href{$entry},\$$data_gigs_href{$entry}) if $rounded_volume;
print STDERR "$category by $by_count_or_volume: added $messages,$rounded_volume to $entry\n" if $debug;
}
}
}
elsif (/List of errors/) {
#List of errors
#--------------
#
# 1 07904931641@one2one.net R=external T=smtp: SMTP error
# from remote mailer after RCPT TO:<07904931641@one2one.net>:
# host mail.one2one.net [193.133.192.24]: 550 User unknown
#
#1 - ally.dufc@dunbar.org.uk R=external T=smtp: SMTP error from remote mailer after RCPT TO:: host mail.dunbar.org.uk [216.167.89.88]: 550 Unknown local part ally.dufc in
my $reached_table = 0;
my($count,$error,$blanks);
while (<$fh>) {
$reached_table = 1 if (/^( *|)(\d+)/);
next unless $reached_table;
s/^(\d+) -/$1/; #Convert an HTML line to a text line.
$_ = html2txt($_); #Convert general HTML markup to text.
if (/\t\s*(.*)/) {
$error .= ' ' . $1; #Join a multiline error.
}
elsif (/^\s*(\d+)\s+(.*)/) {
if ($error) {
#Finished with a previous multiline error so save it.
$errors_count{$error} = 0 unless $errors_count{$error};
$errors_count{$error} += $count;
}
($count,$error) = ($1,$2);
}
elsif (/Errors encountered/) {
if ($error) {
#Finished the section, so save our stored last error.
$errors_count{$error} = 0 unless $errors_count{$error};
$errors_count{$error} += $count;
}
last;
}
}
}
}
}
#######################################################################
# parse_histogram($fh, \@delivered_interval_count);
# Parse a histogram into the provided array of counters.
#######################################################################
sub parse_histogram {
my($fh, $counters_aref) = @_;
# Messages received per hour (each dot is 2 messages)
#---------------------------------------------------
#
#00-01 106 .....................................................
#01-02 103 ...................................................
my $reached_table = 0;
while (<$fh>) {
$reached_table = 1 if (/^00/);
next unless $reached_table;
print STDERR "Parsing $_" if $debug;
if (/^(\d+):(\d+)\s+(\d+)/) { #hh:mm start time format ?
$$counters_aref[($1*60 + $2)/$hist_interval] += $3 if $hist_opt;
}
elsif (/^(\d+)-(\d+)\s+(\d+)/) { #hh-hh start-end time format ?
$$counters_aref[($1*60)/$hist_interval] += $3 if $hist_opt;
}
else { #Finished the table ?
last;
}
}
}
#######################################################################
# update_relayed();
#
# update_relayed($count,$sender,$recipient);
#
# Adds an entry into the %relayed hash. Currently only used when
# merging reports.
#######################################################################
sub update_relayed {
my($count,$sender,$recipient) = @_;
#When generating the key, put in the 'H=' and 'A=' which can be used
#in searches.
my $key = "H=$sender => H=$recipient";
$key =~ s/ ([^=\s]+\@\S+|<>)/ A=$1/g;
if (!defined $relay_pattern || $key !~ /$relay_pattern/o) {
$relayed{$key} = 0 if !defined $relayed{$key};
$relayed{$key} += $count;
}
else {
$relayed_unshown += $count;
}
}
#######################################################################
# add_to_totals();
#
# add_to_totals(\%totals,\@keys,$values);
#
# Given a line of space separated values, add them into the provided hash using @keys
# as the hash keys.
#
# If the value contains a '%', then the value is set rather than added. Otherwise, we
# convert the value to bytes and gigs. The gigs get added to I-gigs.
#######################################################################
sub add_to_totals {
my($totals_href,$keys_aref,$values) = @_;
my(@values) = split(/\s+/,$values);
for(my $i = 0; $i < @values && $i < @$keys_aref; ++$i) {
my $key = $keys_aref->[$i];
if ($values[$i] =~ /%/) {
$$totals_href{$key} = $values[$i];
}
else {
$$totals_href{$key} = 0 unless ($$totals_href{$key});
$$totals_href{"$key-gigs"} = 0 unless ($$totals_href{"$key-gigs"});
un_round($values[$i], \$$totals_href{$key}, \$$totals_href{"$key-gigs"});
print STDERR "Added $values[$i] to $key - $$totals_href{$key} , " . $$totals_href{"$key-gigs"} . "GB.\n" if $debug;
}
}
}
#######################################################################
# line_to_hash();
#
# line_to_hash(\%hash,\@keys,$line);
#
# Given a line of space separated values, set them into the provided hash
# using @keys as the hash keys.
#######################################################################
sub line_to_hash {
my($href,$keys_aref,$values) = @_;
my(@values) = split(/\s+/,$values);
for(my $i = 0; $i < @values && $i < @$keys_aref; ++$i) {
$$href{$keys_aref->[$i]} = $values[$i];
}
}
#######################################################################
# get_report_total();
#
# $total = get_report_total(\%hash,$key);
#
# If %hash contains values split into Units and Gigs, we calculate and return
#
# $hash{$key} + 1024*1024*1024 * $hash{"${key}-gigs"}
#######################################################################
sub get_report_total {
no integer;
my($hash_ref,$key) = @_;
if ($$hash_ref{"${key}-gigs"}) {
return $$hash_ref{$key} + $gig * $$hash_ref{"${key}-gigs"};
}
return $$hash_ref{$key} || 0;
}
#######################################################################
# html2txt();
#
# $text_line = html2txt($html_line);
#
# Convert a line from html to text. Currently we just convert HTML tags to spaces
# and convert >, <, and tags back.
#######################################################################
sub html2txt {
($_) = @_;
# Convert HTML tags to spacing. Note that the reports may contain and
# words, so explicitly specify the HTML tags we will remove
# (the ones used by this program). If someone is careless enough to have their
# Userid the same as an HTML tag, there's not much we can do about it.
s/<\/?(html|head|title|body|h\d|ul|li|a\s+|table|tr|td|th|pre|hr|p|br)\b.*?>/ /g;
s/\<\;/\/og; #Convert '>' to '>'.
s/\ \;/ /og; #Convert ' ' to ' '.
return($_);
}
#######################################################################
# get_next_arg();
#
# $arg = get_next_arg();
#
# Because eximstats arguments are often passed as variables,
# we can't rely on shell parsing to deal with quotes. This
# subroutine returns $ARGV[1] and does a shift. If $ARGV[1]
# starts with a quote (' or "), and doesn't end in one, then
# we append the next argument to it and shift again. We repeat
# until we've got all of the argument.
#
# This isn't perfect as all white space gets reduced to one space,
# but it's as good as we can get! If it's essential that spacing
# be preserved precisely, then you get that by not using shell
# variables.
#######################################################################
sub get_next_arg {
my $arg = '';
my $matched_pattern = 0;
while ($ARGV[1]) {
$arg .= ' ' if $arg;
$arg .= $ARGV[1]; shift(@ARGV);
if ($arg !~ /^['"]/) {
$matched_pattern = 1;
last;
}
if ($arg =~ s/^(['"])(.*)\1$/$2/) {
$matched_pattern = 1;
last;
}
}
die "Mismatched argument quotes - <$arg>.\n" unless $matched_pattern;
return $arg;
}
#######################################################################
# set_worksheet_line($ws_global, $startrow, $startcol, \@content, $format);
#
# set values to a sequence of cells in a row.
#
#######################################################################
sub set_worksheet_line {
my ($worksheet, $row, $col, $content, $format) = @_;
foreach my $token (@$content)
{
$worksheet->write($row, $col++, $token, $format );
}
}
#######################################################################
# @rcpt_times = parse_time_list($string);
#
# Parse a comma separated list of time values in seconds given by
# the user and fill an array.
#
# Return a default list if $string is undefined.
# Return () if $string eq '0'.
#######################################################################
sub parse_time_list {
my($string) = @_;
if (! defined $string) {
return(60, 5*60, 15*60, 30*60, 60*60, 3*60*60, 6*60*60, 12*60*60, 24*60*60);
}
my(@times) = split(/,/, $string);
foreach my $q (@times) { $q = eval($q) + 0 }
@times = sort { $a <=> $b } @times;
@times = () if ($#times == 0 && $times[0] == 0);
return(@times);
}
#######################################################################
# initialise_rcpt_times($protocol);
# Initialise an array of rcpt_times to 0 for the specified protocol.
#######################################################################
sub initialise_rcpt_times {
my($protocol) = @_;
for (my $i = 0; $i <= $#rcpt_times; ++$i) {
$rcpt_times_bin{$protocol}[$i] = 0;
}
$rcpt_times_overflow{$protocol} = 0;
}
##################################################
# Main Program #
##################################################
$last_timestamp = '';
$last_date = '';
$show_errors = 1;
$show_relay = 1;
$show_transport = 1;
$topcount = 50;
$local_league_table = 1;
$include_remote_users = 0;
$include_original_destination = 0;
$hist_opt = 1;
$volume_rounding = 1;
$localtime_offset = calculate_localtime_offset(); # PH/FANF
$charts = 0;
$charts_option_specified = 0;
$chartrel = ".";
$chartdir = ".";
@queue_times = parse_time_list();
@rcpt_times = ();
@delivery_times = ();
$last_offset = '';
$offset_seconds = 0;
$row=1;
$col=0;
$col_hist=0;
$run_hist=0;
my(%output_files); # What output files have been specified?
# Decode options
while (@ARGV > 0 && substr($ARGV[0], 0, 1) eq '-') {
if ($ARGV[0] =~ /^\-h(\d+)$/) { $hist_opt = $1 }
elsif ($ARGV[0] =~ /^\-ne$/) { $show_errors = 0 }
elsif ($ARGV[0] =~ /^\-nr(.?)(.*)\1$/) {
if ($1 eq "") { $show_relay = 0 } else { $relay_pattern = $2 }
}
elsif ($ARGV[0] =~ /^\-q([,\d\+\-\*\/]+)$/) { @queue_times = parse_time_list($1) }
elsif ($ARGV[0] =~ /^-nt$/) { $show_transport = 0 }
elsif ($ARGV[0] =~ /^\-nt(.?)(.*)\1$/)
{
if ($1 eq "") { $show_transport = 0 } else { $transport_pattern = $2 }
}
elsif ($ARGV[0] =~ /^-t(\d+)$/) { $topcount = $1 }
elsif ($ARGV[0] =~ /^-tnl$/) { $local_league_table = 0 }
elsif ($ARGV[0] =~ /^-txt=?(\S*)$/) { $txt_fh = get_filehandle($1,\%output_files) }
elsif ($ARGV[0] =~ /^-html=?(\S*)$/) { $htm_fh = get_filehandle($1,\%output_files) }
elsif ($ARGV[0] =~ /^-xls=?(\S*)$/) {
if ($HAVE_Spreadsheet_WriteExcel) {
$xls_fh = get_filehandle($1,\%output_files);
}
else {
warn "WARNING: CPAN Module Spreadsheet::WriteExcel not installed. Obtain from www.cpan.org\n";
}
}
elsif ($ARGV[0] =~ /^-merge$/) { $merge_reports = 1 }
elsif ($ARGV[0] =~ /^-charts$/) {
$charts = 1;
warn "WARNING: CPAN Module GD::Graph::pie not installed. Obtain from www.cpan.org\n" unless $HAVE_GD_Graph_pie;
warn "WARNING: CPAN Module GD::Graph::linespoints not installed. Obtain from www.cpan.org\n" unless $HAVE_GD_Graph_linespoints;
}
elsif ($ARGV[0] =~ /^-chartdir$/) { $chartdir = $ARGV[1]; shift; $charts_option_specified = 1; }
elsif ($ARGV[0] =~ /^-chartrel$/) { $chartrel = $ARGV[1]; shift; $charts_option_specified = 1; }
elsif ($ARGV[0] =~ /^-include_original_destination$/) { $include_original_destination = 1 }
elsif ($ARGV[0] =~ /^-cache$/) { } #Not currently used.
elsif ($ARGV[0] =~ /^-byhost$/) { $do_sender{Host} = 1 }
elsif ($ARGV[0] =~ /^-bydomain$/) { $do_sender{Domain} = 1 }
elsif ($ARGV[0] =~ /^-byemail$/) { $do_sender{Email} = 1 }
elsif ($ARGV[0] =~ /^-byemaildomain$/) { $do_sender{Edomain} = 1 }
elsif ($ARGV[0] =~ /^-byedomain$/) { $do_sender{Edomain} = 1 }
elsif ($ARGV[0] =~ /^-bylocaldomain$/) { $do_local_domain = 1 }
elsif ($ARGV[0] =~ /^-emptyok$/) { $emptyOK = 1 }
elsif ($ARGV[0] =~ /^-nvr$/) { $volume_rounding = 0 }
elsif ($ARGV[0] =~ /^-show_rt([,\d\+\-\*\/]+)?$/) { @rcpt_times = parse_time_list($1) }
elsif ($ARGV[0] =~ /^-show_dt([,\d\+\-\*\/]+)?$/) { @delivery_times = parse_time_list($1) }
elsif ($ARGV[0] =~ /^-d$/) { $debug = 1 }
elsif ($ARGV[0] =~ /^--?h(elp)?$/){ help() }
elsif ($ARGV[0] =~ /^-t_remote_users$/) { $include_remote_users = 1 }
elsif ($ARGV[0] =~ /^-pattern$/)
{
push(@user_descriptions,get_next_arg());
push(@user_patterns,get_next_arg());
}
elsif ($ARGV[0] =~ /^-utc$/)
{
# We don't need this value if the log is in UTC.
$localtime_offset = undef;
}
else
{
print STDERR "Eximstats: Unknown or malformed option $ARGV[0]\n";
help();
}
shift;
}
# keep old default behaviour
if (! ($xls_fh or $htm_fh or $txt_fh)) {
$txt_fh = \*STDOUT;
}
# Check that all the charts options are specified.
warn "-charts option not specified. Use -help for help.\n" if ($charts_option_specified && ! $charts);
# Default to display tables by sending Host.
$do_sender{Host} = 1 unless ($do_sender{Domain} || $do_sender{Email} || $do_sender{Edomain});
# prepare xls Excel Workbook
if (defined $xls_fh) {
# Create a new Excel workbook
$workbook = Spreadsheet::WriteExcel->new($xls_fh);
# Add worksheets
$ws_global = $workbook->addworksheet('Exim Statistik');
# show $ws_global as initial sheet
$ws_global->set_first_sheet();
$ws_global->activate();
if ($show_relay) {
$ws_relayed = $workbook->addworksheet('Relayed Messages');
$ws_relayed->set_column(1, 2, 80);
}
if ($show_errors) {
$ws_errors = $workbook->addworksheet('Errors');
}
# set column widths
$ws_global->set_column(0, 2, 20); # Columns B-D width set to 30
$ws_global->set_column(3, 3, 15); # Columns B-D width set to 30
$ws_global->set_column(4, 4, 25); # Columns B-D width set to 30
# Define Formats
$f_default = $workbook->add_format();
$f_header1 = $workbook->add_format();
$f_header1->set_bold();
#$f_header1->set_color('red');
$f_header1->set_size('15');
$f_header1->set_valign();
# $f_header1->set_align('center');
# $ws_global->write($row++, 2, "Testing Headers 1", $f_header1);
$f_header2 = $workbook->add_format();
$f_header2->set_bold();
$f_header2->set_size('12');
$f_header2->set_valign();
# $ws_global->write($row++, 2, "Testing Headers 2", $f_header2);
# Create another header2 for use in merged cells.
$f_header2_m = $workbook->add_format();
$f_header2_m->set_bold();
$f_header2_m->set_size('8');
$f_header2_m->set_valign();
$f_header2_m->set_align('center');
$f_percent = $workbook->add_format();
$f_percent->set_num_format('0.0%');
$f_headertab = $workbook->add_format();
$f_headertab->set_bold();
$f_headertab->set_valign();
# $ws_global->write($row++, 2, "Testing Headers tab", $f_headertab);
}
# Initialise the queue/delivery/rcpt time counters.
for (my $i = 0; $i <= $#queue_times; $i++) {
$qt_all_bin[$i] = 0;
$qt_remote_bin[$i] = 0;
}
for (my $i = 0; $i <= $#delivery_times; $i++) {
$dt_all_bin[$i] = 0;
$dt_remote_bin[$i] = 0;
}
initialise_rcpt_times('all');
# Compute the number of slots for the histogram
if ($hist_opt > 0)
{
if ($hist_opt > 60 || 60 % $hist_opt != 0)
{
print STDERR "Eximstats: -h must specify a factor of 60\n";
exit 1;
}
$hist_interval = 60/$hist_opt; #Interval in minutes.
$hist_number = (24*60)/$hist_interval; #Number of intervals per day.
@received_interval_count = (0) x $hist_number;
@delivered_interval_count = (0) x $hist_number;
my $user_pattern_index = 0;
for (my $user_pattern_index = 0; $user_pattern_index <= $#user_patterns; ++$user_pattern_index) {
@{$user_pattern_interval_count[$user_pattern_index]} = (0) x $hist_number;
}
@dt_all_bin = (0) x $hist_number;
@dt_remote_bin = (0) x $hist_number;
}
#$queue_unknown = 0;
$total_received_data = 0;
$total_received_data_gigs = 0;
$total_received_count = 0;
$total_delivered_data = 0;
$total_delivered_data_gigs = 0;
$total_delivered_messages = 0;
$total_delivered_addresses = 0;
$qt_all_overflow = 0;
$qt_remote_overflow = 0;
$dt_all_overflow = 0;
$dt_remote_overflow = 0;
$delayed_count = 0;
$relayed_unshown = 0;
$message_errors = 0;
$begin = "9999-99-99 99:99:99";
$end = "0000-00-00 00:00:00";
my($section,$type);
foreach $section ('Received','Delivered','Temp Rejects', 'Rejects','Ham','Spam') {
foreach $type ('Volume','Messages','Delayed','Failed','Hosts','Domains','Emails','Edomains') {
$report_totals{$section}{$type} = 0;
}
}
# Generate our parser.
my $parser = generate_parser();
if (@ARGV) {
# Scan the input files and collect the data
foreach my $file (@ARGV) {
if ($file =~ /\.gz/) {
unless (open(FILE,"gunzip -c $file |")) {
print STDERR "Failed to gunzip -c $file: $!";
next;
}
}
elsif ($file =~ /\.Z/) {
unless (open(FILE,"uncompress -c $file |")) {
print STDERR "Failed to uncompress -c $file: $!";
next;
}
}
else {
unless (open(FILE,$file)) {
print STDERR "Failed to read $file: $!";
next;
}
}
#Now parse the filehandle, updating the global variables.
parse($parser,\*FILE);
close FILE;
}
}
else {
#No files provided. Parse STDIN, updating the global variables.
parse($parser,\*STDIN);
}
if ($begin eq "9999-99-99 99:99:99" && ! $emptyOK) {
print STDERR "**** No valid log lines read\n";
exit 1;
}
# Output our results.
print_header();
print_grandtotals();
# Print counts of user specified patterns if required.
print_user_patterns() if @user_patterns;
# Print rejection reasons.
# print_rejects();
# Print totals by transport if required.
print_transport() if $show_transport;
# Print the deliveries per interval as a histogram, unless configured not to.
# First find the maximum in one interval and scale accordingly.
if ($hist_opt > 0) {
print_histogram("Messages received", 'message', @received_interval_count);
print_histogram("Deliveries", 'delivery', @delivered_interval_count);
}
# Print times on queue if required.
if ($#queue_times >= 0) {
print_duration_table("Time spent on the queue", "all messages", \@queue_times, \@qt_all_bin,$qt_all_overflow);
print_duration_table("Time spent on the queue", "messages with at least one remote delivery", \@queue_times, \@qt_remote_bin,$qt_remote_overflow);
}
# Print delivery times if required.
if ($#delivery_times >= 0) {
print_duration_table("Delivery times", "all messages", \@delivery_times, \@dt_all_bin,$dt_all_overflow);
print_duration_table("Delivery times", "messages with at least one remote delivery", \@delivery_times, \@dt_remote_bin,$dt_remote_overflow);
}
# Print rcpt times if required.
if ($#rcpt_times >= 0) {
foreach my $protocol ('all', grep(!/^all$/, sort keys %rcpt_times_bin)) {
print_duration_table("Receipt times", "$protocol messages", \@rcpt_times, $rcpt_times_bin{$protocol}, $rcpt_times_overflow{$protocol});
}
}
# Print relay information if required.
print_relay() if $show_relay;
# Print the league tables, if topcount isn't zero.
if ($topcount > 0) {
my($ws_rej, $ws_top50, $ws_rej_row, $ws_top50_row, $ws_temp_rej, $ws_temp_rej_row);
$ws_rej_row = $ws_temp_rej_row = $ws_top50_row = 0;
if ($xls_fh) {
$ws_top50 = $workbook->addworksheet('Deliveries');
$ws_rej = $workbook->addworksheet('Rejections') if (%rejected_count_by_reason || %rejected_count_by_ip || %spam_count_by_ip);
$ws_temp_rej = $workbook->addworksheet('Temporary Rejections') if (%temporarily_rejected_count_by_reason || %temporarily_rejected_count_by_ip);
}
print_league_table("mail rejection reason", \%rejected_count_by_reason, undef, undef, undef, $ws_rej, \$ws_rej_row) if %rejected_count_by_reason;
print_league_table("mail temporary rejection reason", \%temporarily_rejected_count_by_reason, undef, undef, undef, $ws_temp_rej, \$ws_temp_rej_row) if %temporarily_rejected_count_by_reason;
foreach ('Host','Domain','Email','Edomain') {
next unless $do_sender{$_};
print_league_table("sending \l$_", $received_count{$_}, undef, $received_data{$_},$received_data_gigs{$_}, $ws_top50, \$ws_top50_row);
}
print_league_table("local sender", \%received_count_user, undef,
\%received_data_user,\%received_data_gigs_user, $ws_top50, \$ws_top50_row) if (($local_league_table || $include_remote_users) && %received_count_user);
foreach ('Host','Domain','Email','Edomain') {
next unless $do_sender{$_};
print_league_table("\l$_ destination", $delivered_messages{$_}, $delivered_addresses{$_}, $delivered_data{$_},$delivered_data_gigs{$_}, $ws_top50, \$ws_top50_row);
}
print_league_table("local destination", \%delivered_messages_user, \%delivered_addresses_user, \%delivered_data_user,\%delivered_data_gigs_user, $ws_top50, \$ws_top50_row) if (($local_league_table || $include_remote_users) && %delivered_messages_user);
print_league_table("local domain destination", \%delivered_messages_local_domain, \%delivered_addresses_local_domain, \%delivered_data_local_domain,\%delivered_data_gigs_local_domain, $ws_top50, \$ws_top50_row) if (($local_league_table || $include_remote_users) && %delivered_messages_local_domain);
print_league_table("rejected ip", \%rejected_count_by_ip, undef, undef, undef, $ws_rej, \$ws_rej_row) if %rejected_count_by_ip;
print_league_table("temporarily rejected ip", \%temporarily_rejected_count_by_ip, undef, undef, undef, $ws_rej, \$ws_rej_row) if %temporarily_rejected_count_by_ip;
print_league_table("non-rejected spamming ip", \%spam_count_by_ip, undef, undef, undef, $ws_rej, \$ws_rej_row) if %spam_count_by_ip;
}
# Print the error statistics if required.
print_errors() if $show_errors;
print $htm_fh "\n\n" if $htm_fh;
$txt_fh->close if $txt_fh && ref $txt_fh;
$htm_fh->close if $htm_fh;
if ($xls_fh) {
# close Excel Workbook
$ws_global->set_first_sheet();
# FIXME: whyever - activate does not work :-/
$ws_global->activate();
$workbook->close();
}
# End of eximstats
|