#!/usr/bin/perl # # yasma.pl # (Yet Another Sendmail Log Analyzer) # # Copyright (c) 2006 by Peter_Siegrist(SystemLoesungen) (PSS@ZweierNet.ch) # # All Rights reserved. # 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. # # 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. # require 5.006_001; use strict; use subs qw(lprint); use locale; use POSIX qw(locale_h); use CGI qw(:all); $| = 1; # flush eval { use Geo::IP::PurePerl; }; use File::Basename; use IO::Handle; use Getopt::Std; use vars qw($opt_f $opt_c $opt_u); use lib "./lib"; use Parse::Syslog::Mail; # modified version of Parse::Syslog::Mail my $VERSION = "V0.96"; #-- sub TRUE { 1; } sub FALSE { 0; } getopt('fc'); #>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>># my $conf_file = $opt_c || "yasma.conf"; my $geoip_dbase = ""; #- Hide user-part from mailaddresses ? my $HIDE_USERS = FALSE; #- print $OUT each message packet. !!long long list!! my $DEBUG = FALSE; #- Number of lines to show: #- of Top Sender Report my $max_top_snt = 20; #- of Top Recipients Report my $max_top_rcv = 20; #- of Top Senders Size Report my $max_top_siz = 20; #- of Top Recipient Size Report my $max_top_riz = 20; #- of Top Deferrer Report my $max_top_def = 25; #- of Top Rejects Report my $max_top_rej = 25; #- of Top Supposed Spammers Report my $max_top_ssp = 25; #- of Top Staus Messages my $max_top_sts = 25; #- of Top Relay Hosts my $max_top_rel = 25; #- of Top Mailer my $max_top_mlr = 25; #- of Top Mailer Hosts my $max_top_hst = 25; #>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>># my %hash_bas = (); my %hash_def = (); my %hash_rej = (); my %hash_snt = (); my %hash_rcv = (); my %hash_ssp = (); my %hash_sts = (); my %hash_rel = (); my %hash_mlr = (); my %hash_hst = (); my %top_rsize = (); my %top_ssize = (); my %top_sender = (); my %top_recv = (); my %hash_present = (); my $t1 = time(); my $t2 = 0; my $out_file; my $msg_total = 0; my $msg_outbound = 0; my $msg_inbound = 0; my $msg_relay = 0; my $msg_deferred = 0; my $msg_rejected = 0; my $msg_size = 0; my $msg_in_size = 0; my $msg_out_size = 0; my $msg_relay_size = 0; &read_config; #-- cmd line opts $out_file = $opt_f if $opt_f; $HIDE_USERS = TRUE if $opt_u; #-- output direction my $OUT = *STDOUT; $out_file && do { open($OUT, ">$out_file") or die "Cannot open $out_file: $!\n"; select $OUT; $| = 1; }; #-- Read maillog foreach my $infile ( map { glob($_) } @ARGV ) { if ( ! -f $infile ) { print STDERR "File: '$infile' don't exist. Skipping ...\n"; next; } my $log_year = ""; print STDERR "Processing $infile\n"; $log_year = substr( $1, 0, 4) if $infile =~ /[_\.\-](\d{8})[_\.\-]/; if ($infile =~ /(\.Z$|\.gz$)/) { open( INZ, "zcat $infile |" ) or die "err: INZ: $!\n"; $infile = IO::Handle->new_from_fd( fileno(INZ), "r" ) or die "err-io-handle: $!\n"; } my $maillog; if ( $log_year != "" ) { $maillog = new Parse::Syslog::Mail $infile, allow_future => 1, year=>$log_year or die $!; } else { $maillog = new Parse::Syslog::Mail $infile, allow_future => 1 or die $!; } while(my $log = $maillog->next) { if ( $$log{'timestamp'} ) { $t1 = $$log{'timestamp'} if $$log{'timestamp'} < $t1; $t2 = $$log{'timestamp'} if $$log{'timestamp'} > $t2; } if ( $$log{status} ) { (exists $$log{host}) && ($hash_hst{$$log{host}}{count} +=1); (exists $$log{mailer}) && ($hash_mlr{$$log{mailer}}{count} +=1); (exists $$log{program}) && ($hash_bas{program}{$$log{program}}{count} +=1); (exists $$log{relay}) && ($hash_rel{$$log{relay}}{count} +=1); CASE: { $$log{status} =~ /Deferred\: (.*)/i && do { my $txt = $1; $hash_def{$$log{id}}{count} +=1; $hash_def{$$log{id}}{timestamp} = localtime($$log{timestamp}); $hash_def{$$log{id}}{status} = $txt; my $to = $$log{to}; $to =~ s/^.+(?=\@)(.*)/$1/ if $HIDE_USERS; $to =~ s/\//; $to =~ s/^\\\\//; $to = "<>" if $to eq ""; $hash_def{$$log{id}}{to} = lc($to); my $ctladdr = lc($$log{ctladdr}); $ctladdr =~ s/^.+(?=\@)(.*)/$1/ if $HIDE_USERS; $ctladdr =~ s/\//; $ctladdr =~ s/^\\\\//; $ctladdr = "<>" if $ctladdr eq ""; $hash_def{$$log{id}}{ctladdr} = $ctladdr; $hash_sts{'Deferred'}{count} +=1; last CASE; }; $$log{status} =~ /sender notify\: (.*)/i && do { my $txt = $1; last CASE if not exists $hash_def{$$log{id}}; my $id = $$log{id}; $hash_def{$id}{notify} = "sender notify:" . $txt; $hash_sts{'Sender notify'}{count} +=1; last CASE; }; $$log{status} =~ /^reject/i && do { $$log{reject} =~ s/\b[a-z0-9\.\-_\+]+(\@[a-z0-9\.\-_\+]+)\b/$1/gi if $HIDE_USERS; $hash_rej{$$log{reject}}{count} +=1; $hash_rej{$$log{reject}}{timestamp} = localtime($$log{timestamp}); $hash_rej{$$log{reject}}{relay} = lc($$log{relay}); if ( exists $$log{reject} ) { $$log{reject} =~ /(\d{3})\s+(\d\.\d\.\d)\s+(.*)$/; my $smtprc = $1; my $dsn = $2; my $dsn_text = $3; $dsn_text =~ s/(?:\w*)\s*\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}(.*)/$1/g; # dsn $dsn_text =~ s/\//g; $dsn_text =~ s/\b[a-z0-9\.\-_\+]+\@[a-z0-9\.\-_\+]+\b//gi; $dsn_text =~ s/^\s+//; # leading sp $dsn_text =~ s/\s{2,}/ /; # dbl sp $dsn_text =~ s/\.{2,}//g; # some n-dots $dsn_text =~ s/^\s+(.*)/$1/; # leading sp $dsn_text =~ s/\[\]//g; # empty [] $dsn_text =~ s/(.*\s+)[^A-Za-z0-9]+(\s+.*)/$1$2/; # alles ausser $dsn_text =~ s/\s{2,}/ /; # dbl sp #-- suit to std messages $dsn_text =~ s/.*(Domain name required for sender address).*/$1/; $dsn_text =~ s/.*(Domain of sender address\s).*(does not resolve).*/$1$2/; $dsn_text =~ s/.*(Domain of sender address\s).*(does not exist).*/$1$2/; $dsn_text =~ s/.*(Fix reverse DNS Details.*)/$1/; #-- if ( exists $$log{arg2} ) { $$log{arg2} =~ s/\//; $$log{arg2} = lc($$log{arg2}); $hash_ssp{$dsn_text}{$$log{arg2}}{count} += 1; $hash_ssp{$dsn_text}{count} += 1; $hash_ssp{$dsn_text}{dsn} = $dsn; } elsif ( exists $$log{arg1} ) { $$log{arg1} =~ s/\//; $$log{arg1} = lc($$log{arg1}); $hash_ssp{$dsn_text}{$$log{arg1}}{count} += 1; $hash_ssp{$dsn_text}{count} += 1; $hash_ssp{$dsn_text}{dsn} = $dsn; } } $hash_sts{'Reject'}{count} +=1; last CASE; }; $$log{status} =~ /^Sent/i && do { last CASE if !exists $hash_present{$$log{id}}; # kein from $hash_snt{$$log{id}}{count} +=1; $hash_snt{$$log{id}}{timestamp} = localtime($$log{timestamp}); $hash_snt{$$log{id}}{from} = lc($hash_present{$$log{id}}{from}); $hash_snt{$$log{id}}{size} = $hash_present{$$log{id}}{size}; $hash_snt{$$log{id}}{in_size} = $hash_present{$$log{id}}{size} if $$log{mailer} =~ /local/i; #-- vorab prog-mailer als inbound !!!!!!!!!! $hash_snt{$$log{id}}{in_size} = $hash_present{$$log{id}}{size} if $$log{mailer} =~ /prog/i; $hash_snt{$$log{id}}{out_size} = $hash_present{$$log{id}}{size} if $$log{mailer} =~ /esmtp/i; $hash_snt{$$log{id}}{relay_size} = $hash_present{$$log{id}}{size} if $$log{mailer} =~ /relay/i;; $hash_snt{$$log{id}}{mailer} = $$log{mailer}; my $to = $$log{to}; $to =~ s/^.+(?=\@)(.*)/$1/ if $HIDE_USERS; $to =~ s/\//; $to =~ s/^\\\\//; $to = "<>" if $to eq ""; $hash_snt{$$log{id}}{to} = lc($to); $hash_sts{'Sent'}{count} +=1; last CASE; }; #-- Defualt do { my $ls = $$log{status}; $ls =~ s/^[A-Za-z_0-9]+\d{4}:\s//; $ls =~ s/\//g; my ($status) = $ls; # =~ /^(\w+)+\:.*/; $status =~ s/\b[a-z0-9\.\-_\+]+(\@[a-z0-9\.\-_\+]+)\b/$1/gi if $HIDE_USERS; $hash_sts{$status}{count} +=1; last CASE; }; } } else { next if not exists $$log{from} or $$log{from} eq ""; #next if not exists $$log{daemon} or $$log{daemon} !~ /MTA/i; my $from = $$log{from}; $from =~ s/^.+(?=\@)(.*)/$1/ if $HIDE_USERS; $from =~ s/\//; $from = "<>" if $from eq ""; $hash_present{$$log{id}}{from} = $from; if ( $$log{daemon} =~ /MTA/i ) { $hash_present{$$log{id}}{size} = $$log{size}; } } } close INZ; } my $estim_day = ""; my $estim_std = ""; my $estim_min = ""; $estim_day = qq(    (estimated)) if (($t2 - $t1) < 86400); $estim_std = qq(    (estimated)) if (($t2 - $t1) < 3600 ); $estim_min = qq(    (estimated)) if (($t2 - $t1) < 60 ); my $std_period = round2(($t2 - $t1) / 3600); my $day_period = round2($std_period / 24); my ($a1,$a2,$a3,$a4,$a5) = (localtime($t1))[3,4,5,2,1]; my ($e1,$e2,$e3,$e4,$e5) = (localtime($t2))[3,4,5,2,1]; $a3 += 1900; $e3 += 1900; $a2 +=1; $e2 +=1; foreach my $key ( sort { $hash_def{$b}{count} <=> $hash_def{$a}{count} || $a cmp $b } keys %hash_def) { $msg_total += $hash_def{$key}{count}; $msg_deferred += $hash_def{$key}{count}; if ( $hash_def{$key}{mailer} =~ /local|esmtp|relay/i ) { $hash_def{$hash_snt{$key}{from}} +=1; $hash_def{$hash_snt{$key}{to}} +=1; } foreach my $key1 ( keys %{ $hash_def{$key} }) { lprint "Deferred: $key = $key1: $hash_def{$key}{$key1}\n"; } lprint "-------\n"; } foreach my $key ( sort { $hash_rej{$b}{count} <=> $hash_rej{$a}{count} || $a cmp $b } keys %hash_rej) { $msg_total += $hash_rej{$key}{count}; $msg_rejected += $hash_rej{$key}{count}; foreach my $key1 (keys %{ $hash_rej{$key} }) { lprint "Rejected: $key = $key1: $hash_rej{$key}{$key1}\n"; } lprint "-------\n"; } foreach my $key ( sort { $hash_snt{$b}{count} <=> $hash_snt{$a}{count} || $a cmp $b } keys %hash_snt) { $msg_total += $hash_snt{$key}{count}; $msg_size += $hash_snt{$key}{size}; $msg_in_size += $hash_snt{$key}{in_size}; $msg_out_size += $hash_snt{$key}{out_size}; $msg_relay_size += $hash_snt{$key}{relay_size}; $msg_inbound += $hash_snt{$key}{count} if $hash_snt{$key}{mailer} =~ /local/i; $msg_outbound += $hash_snt{$key}{count} if $hash_snt{$key}{mailer} =~ /esmtp/i; $msg_relay += $hash_snt{$key}{count} if $hash_snt{$key}{mailer} =~ /relay/i; if ( $hash_snt{$key}{mailer} =~ /local|esmtp|relay/i ) { $top_sender{$hash_snt{$key}{from}} +=1; $top_recv{$hash_snt{$key}{to}} +=1; $top_rsize{$hash_snt{$key}{to}} += int($hash_snt{$key}{size}/1024); $top_ssize{$hash_snt{$key}{from}} += int($hash_snt{$key}{size}/1024); } foreach my $key1 (keys %{ $hash_snt{$key} }) { lprint "Sent: $key = $key1: $hash_snt{$key}{$key1}\n"; }lprint "-------\n"; } $msg_size = int($msg_size/1024); $msg_in_size = int($msg_in_size/1024); $msg_out_size = int($msg_out_size/1024); $msg_relay_size = int($msg_relay_size/1024); #-- CGI Part ------------------------- #-- Locale Settings my $LOCALE = "de_DE.ISO8859-1"; setlocale(LC_CTYPE, "$LOCALE"); my $Q = new CGI; &menu1; exit; { end_script: print $OUT $Q->end_html; exit; } #-- SUBS sub lprint { $DEBUG && print $OUT shift() . "
"; } sub menu1 { #-- Styles my $STYLE_1 =<<"EOF_STYLE_1"; A{ color: red; font-family: Avantgarde, Verdana, Arial; font-variant: small-caps; letter-spacing: 0.2em; font-style: normal; font-weight: bold; text-decoration: none; } HTML { font-size: 10px; color: #F3F0E0; font-family: Verdana, Arial, Helvetica, sans-serif; font-style: normal; font-variant: normal; text-decoration: none; background-color: #707070; } .hr { color:#F3F0E0; background-color:; border:1px solid #F3F0E0; height: 0pt; } .m0 { border-width: 1px; border-style: solid; border-color: #F3F0E0; border-spacing: 2px; empty-cells:hide; padding: 0px; white-space:pre; font: bold 14px Verdana; color: #F3F0E0; margin: 0px; background-color: #808080; } .m0 table { border-width: 1px; border-style: solid; border-color: #F3F0E0; border-spacing: 1px; empty-cells:hide; padding: 0px; white-space:pre; font: bold 14px Verdana; color: #F3F0E0; margin: 0px; background-color: #808080; } .m0 td { border-width: 0px; border-style: solid; border-color: #F3F0E0; border-spacing: 0px; padding: 3px; white-space:pre; font: bold 14px Verdana; color: #F3F0E0; margin: 0px; background-color: #404040; } .m0 th { border-spacing: 1px; font: normal 16px Avantgarde, Verdana, Arial; font-variant:small-caps; letter-spacing:0.2em; padding: 5px; white-space:pre; color: #F3F0E0; margin: 0px; background-color: #808080; } .m0 tr { border: 0px; margin: 0px; padding: 0px; background-color: #808080; } .m1 { border-width: 1px; border-style: solid; border-color: #F3F0E0; border-spacing: 2px; empty-cells:hide; padding: 1px; white-space:pre; font: bold 12px Verdana; color: #F3F0E0; margin: 0px; background-color: #808080; } .m1 table { border-width: 1px; border-style: solid; border-color: #F3F0E0; border-spacing: 1px; empty-cells:hide; padding: 1px; white-space:pre; font: bold 12px Verdana; color: #F3F0E0; margin: 0px; background-color: #808080; } .m1 td { border-width: 0px; border-style: solid; border-color: #F3F0E0; border-spacing: 0px; padding: 3px; white-space:pre; font: bold 12px Verdana; color: #F3F0E0; margin: 0px; background-color: #404040; } .m1 th { border-spacing: 1px; padding: 5px; white-space:pre; font: normal 16px Avantgarde, Verdana, Arial; font-variant:small-caps; letter-spacing:0.2em; color: #F3F0E0; margin: 0px; background-color: #808080; } .m1 tr { border: 0px; margin: 0px; padding: 0px; background-color: #808080; } .trline { border: 0px; margin: 0px; padding: 0px; background-color: #808080; height: 2px; font-size: 2px; } #graph1 { background-color: #404040; height: 100%; border: 0px; table-layout:auto; padding: 0px; margin: 3px; border-collapse:collapse; vertical-align:middle; } #graph1 tr { background-color: #404040; height: 50px; border: 0px; padding: 0px; } #graph1 td { border: 0px; margin: px; padding: 0px; text-align: left; } #graph1 .go { border-width: 1px 1px 0px 1px; border-style: solid; border-color: black; padding: 2px; padding-left: 0px; } #graph1 .gm { border-width: 0px 1px 0px 1px; border-style: solid; border-color: black; padding: 2px; padding-left: 0px; } #graph1 .gu { border-width: 0px 1px 1px 1px; border-style: solid; border-color: black; padding: 2px; padding-left: 0px; } div.pc { border: 0px; width: 100%; margin: 0px; padding: 0px; float: left; background: transparent; vertical-align: middle; } div.pc > div { background-color: red; height: 20px; vertical-align: middle; text-align: right; border-width: 1px 1px 1px 1px; border-style: solid; border-color: black; } EOF_STYLE_1 my $p_title = "Yasma - Sendmail Logfile Analyzer"; #print $OUT $Q->header( -type => 'text/html' ); print $OUT $Q->start_html( -title => "$p_title", -head => [ meta( { -http_equiv => 'Content-Type', -content => 'text/html; charset=iso-8859-1'}), meta( { -http_equiv => 'content-language', -content => 'de'}) ], -author => "sigi-at-ZweierNet-dot-ch", -style => {-code => "$STYLE_1"} ); print $OUT qq(


Yasma - Yet Another Sendmail Logfile Analyzer); print $OUT qq(

Free Yasma $VERSION Designed by PSS

); print $OUT qq(

Report Generated at ); print $OUT scalar localtime(); print $OUT qq(


); &print_totals; &print_avg; &print_tops; print $OUT qq(


Free Yasma $VERSION Designed by PSS


); goto end_script; } sub print_totals { print $OUT qq(); print $OUT qq(! : print $OUT qq! ($std_period hours)!; print $OUT qq(); print $OUT qq(); print $OUT qq(); print $OUT qq(); print $OUT qq(); print $OUT qq(); print $OUT qq(); print $OUT qq(); print $OUT qq(); print $OUT qq(); print $OUT qq(); print $OUT qq(); print $OUT qq(
Overview of Period ); printf("%d.%d.%d %02d:%02d - %d.%d.%d %02d:%02d", $a1,$a2,$a3,$a4,$a5, $e1,$e2,$e3,$e4,$e5); $std_period > 24 ? print $OUT qq! ($day_period days)
Overall Processed Messages$msg_total); &make_chart; print $OUT qq(
Total Delivered Messages); print $OUT $msg_outbound + $msg_inbound; print $OUT qq(
     Outbound$msg_outbound
     Inbound$msg_inbound
     Relay (of it)$msg_relay
Total Waste Messages); print $OUT ($msg_rejected + $msg_deferred); print $OUT qq(
     Deferred Messages$msg_deferred
     Rejected Messages$msg_rejected
Ratio Delivered : Waste Messages
); print $OUT round(eval { (($msg_outbound + $msg_inbound) * 100) / $msg_total } or 0); print $OUT qq( % : ); print $OUT round(eval { (($msg_rejected + $msg_deferred) * 100) / $msg_total } or 0); print $OUT qq( %
Total Size of Delivered Messages); print $OUT fmt_kb($msg_size); print $OUT qq( Kb
     Outbound); print $OUT fmt_kb($msg_out_size); print $OUT qq( Kb
     Inbound); print $OUT fmt_kb($msg_in_size); print $OUT qq( Kb
); } sub print_tops { print $OUT qq(



); print $OUT qq(); print $OUT qq(); foreach my $adr( sort { $top_sender{$b} <=> $top_sender{$a} || $a cmp $b } keys %top_sender ) { print $OUT qq(); last if $max_top_snt-- == 1; } print $OUT qq(
Top Envelope Sender
$top_sender{$adr}$adr
); print $OUT qq(


); print $OUT qq(); print $OUT qq(); foreach my $adr( sort { $top_recv{$b} <=> $top_recv{$a} || $a cmp $b } keys %top_recv ) { print $OUT qq(); last if $max_top_rcv-- == 1; } print $OUT qq(
Top Envelope Recipients
$top_recv{$adr}$adr
); print $OUT qq(


); print $OUT qq(); print $OUT qq(); foreach my $adr( sort { $top_ssize{$b} <=> $top_ssize{$a} || $a cmp $b } keys %top_ssize ) { print $OUT qq(); last if $max_top_siz-- == 1; } print $OUT qq(
Top Senders Message Size (in Kbyte)
); print $OUT fmt_kb($top_ssize{$adr}); print $OUT qq($adr
); print $OUT qq(



); print $OUT qq(); print $OUT qq(); foreach my $adr( sort { $top_rsize{$b} <=> $top_rsize{$a} || $a cmp $b } keys %top_rsize ) { print $OUT qq(); last if $max_top_riz-- == 1; } print $OUT qq(
Top Recipients Message Size (in Kbyte)
); print $OUT fmt_kb($top_rsize{$adr}); print $OUT qq($adr
); print $OUT qq(



); print $OUT qq(); print $OUT qq(); foreach my $key ( sort { $hash_def{$b}{count} <=> $hash_def{$a}{count} || $a cmp $b } keys %hash_def) { if ( exists $hash_def{$key}{notify} ) { print $OUT qq(); } else { print $OUT qq(); } last if $max_top_def-- == 1; } print $OUT qq(
Top Deferrer
$hash_def{$key}{count}

$hash_def{$key}{ctladdr}
     To: $hash_def{$key}{to}
     Reason: $hash_def{$key}{status}
          ==> Solved with: $hash_def{$key}{notify}
$hash_def{$key}{count}

$hash_def{$key}{ctladdr}
     To: $hash_def{$key}{to}
     Reason: $hash_def{$key}{status}
); print $OUT qq(


); print $OUT qq(); print $OUT qq(); foreach my $key ( sort { $hash_rej{$b}{count} <=> $hash_rej{$a}{count} || $a cmp $b } keys %hash_rej) { print $OUT qq(); last if $max_top_rej-- == 1; } print $OUT qq(
Top Rejects
$hash_rej{$key}{count}
$key
     Relay: $hash_rej{$key}{relay}
); my $GI; $geoip_dbase && ( $GI = Geo::IP::PurePerl->open($geoip_dbase) ); print $OUT qq(


); print $OUT qq(); print $OUT qq(); my $stmp = $max_top_ssp; foreach my $key1 ( sort { $hash_ssp{$b}{count} <=> $hash_ssp{$a}{count} || $a cmp $b } keys %hash_ssp ) { my $scnt = $stmp; my $fk = "($hash_ssp{$key1}{dsn}) $key1"; my $fkc = $hash_ssp{$key1}{count}; my %tmph = (); foreach my $x ( keys %{ $hash_ssp{$key1} } ) { next if $x eq "count" or $x eq "dsn"; $tmph{$x} = "$hash_ssp{$key1}{$x}{count}"; } foreach my $key ( sort { $tmph{$b} <=> $tmph{$a} || $a cmp $b } keys %tmph ) { my $land = ""; if ($key =~ /\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/ ) { $geoip_dbase && ($land = $GI->country_code_by_addr($key)); } my $keyl = $key; if ($keyl =~ s/.+\@(.*)/$1/ ) { $geoip_dbase && ($land = $GI->country_code_by_name($keyl)); } my $keyu = $key; $keyu =~ s/\b[a-z0-9\.\-_\+]+(\@[a-z0-9\.\-_\+]+)\b/$1/gi if $HIDE_USERS; print $OUT qq(); $fk = " "; $fkc = " "; last if $scnt-- == 1; } last if $max_top_ssp-- == 1; } print $OUT qq(
Top DSN Messages and Supposed Spammers/Abused Addresses
$fkc$fk$tmph{$key} $keyu    ); $geoip_dbase && (print $OUT qq([$land])); print $OUT qq(
); print $OUT qq(


); print $OUT qq(); print $OUT qq(); foreach my $key( sort { $hash_sts{$b}{count} <=> $hash_sts{$a}{count} || $a cmp $b } keys %hash_sts ) { print $OUT qq(); last if $max_top_sts-- == 1; } print $OUT qq(
Top Status Messages
$hash_sts{$key}{count}$key
); print $OUT qq(


); print $OUT qq(); print $OUT qq(); foreach my $key( sort { $hash_rel{$b}{count} <=> $hash_rel{$a}{count} || $a cmp $b } keys %hash_rel ) { print $OUT qq(); last if $max_top_rel-- == 1; } print $OUT qq(
Top Relay Hosts
$hash_rel{$key}{count}$key
); print $OUT qq(


); print $OUT qq(); print $OUT qq(); foreach my $key( sort { $hash_mlr{$b}{count} <=> $hash_mlr{$a}{count} || $a cmp $b } keys %hash_mlr ) { print $OUT qq(); last if $max_top_mlr-- == 1; } print $OUT qq(
Top Mailer
$hash_mlr{$key}{count}$key
); print $OUT qq(


); print $OUT qq(); print $OUT qq(); foreach my $key( sort { $hash_hst{$b}{count} <=> $hash_hst{$a}{count} || $a cmp $b } keys %hash_hst ) { print $OUT qq(); last if $max_top_hst-- == 1; } print $OUT qq(
Top Mailer Hosts Processed
$hash_hst{$key}{count}$key
); } sub print_avg { print $OUT qq(


); print $OUT qq(); print $OUT qq(! : print $OUT qq! ($std_period hours)!; print $OUT qq(); print $OUT qq(); print $OUT qq(); print $OUT qq(); print $OUT qq(); print $OUT qq(); print $OUT qq(); print $OUT qq(); print $OUT qq(); print $OUT qq(); print $OUT qq(); print $OUT qq(); print $OUT qq(); print $OUT qq(); print $OUT qq(); print $OUT qq(); print $OUT qq(); print $OUT qq(); print $OUT qq(); print $OUT qq(); print $OUT qq(); print $OUT qq(); print $OUT qq(
Averages of Period ); printf("%d.%d.%d %02d:%02d - %d.%d.%d %02d:%02d", $a1,$a2,$a3,$a4,$a5, $e1,$e2,$e3,$e4,$e5); $std_period > 24 ? print $OUT qq! ($day_period days)
Overall Processed/Day $estim_day); print $OUT round2(eval { $msg_total / ($std_period / 24) } or 0 ); print $OUT qq(Total Delivered/Day $estim_day); print $OUT round2(eval {($msg_outbound + $msg_inbound) / ($std_period / 24) } or 0); print $OUT qq(
Overall Processed/Hour $estim_std); print $OUT round2(eval { $msg_total / $std_period } or 0); print $OUT qq(Total Delivered/Hour $estim_std); print $OUT round2(eval {($msg_outbound + $msg_inbound) / $std_period } or 0); print $OUT qq(
Overall Processed/Min $estim_min); print $OUT round2(eval { $msg_total / ($std_period * 60) } or 0 ); print $OUT qq(Total Delivered/Min $estim_min); print $OUT round2(eval {($msg_outbound + $msg_inbound) / ($std_period * 60) } or 0); print $OUT qq(
Inbound Delivered/Day $estim_day); print $OUT round2(eval {$msg_inbound / ($std_period /24) } or 0 ); print $OUT qq(Outbound Delivered/Day $estim_day); print $OUT round2(eval {$msg_outbound / ($std_period /24) } or 0); print $OUT qq(
Inbound Delivered/Hour $estim_std); print $OUT round2(eval {$msg_inbound / $std_period } or 0 ); print $OUT qq(Outbound Delivered/Hour $estim_std); print $OUT round2(eval {$msg_outbound / $std_period } or 0); print $OUT qq(
Inbound Delivered/Min $estim_min); print $OUT round2(eval {$msg_inbound / ($std_period * 60) } or 0 ); print $OUT qq(Outbound Delivered/Min $estim_min); print $OUT round2(eval {$msg_outbound / ($std_period * 60) } or 0); print $OUT qq(
Rejected Messages/Day $estim_day); print $OUT round2(eval {$msg_rejected / ($std_period /24) } or 0 ); print $OUT qq(Deferred Messages/Day $estim_day); print $OUT round2(eval {$msg_deferred / ($std_period /24) } or 0); print $OUT qq(
Rejected Messages/Hour $estim_std); print $OUT round2(eval {$msg_rejected / $std_period } or 0); print $OUT qq(Deferred Messages/Hour $estim_std); print $OUT round2(eval {$msg_deferred / $std_period } or 0); print $OUT qq(
Rejected Messages/Min $estim_min); print $OUT round2(eval {$msg_rejected / ($std_period * 60) } or 0 ); print $OUT qq(Deferred Messages/Min $estim_min); print $OUT round2(eval {$msg_deferred / ($std_period * 60) } or 0); print $OUT qq(
Average Size of Delivered Messages); print $OUT fmt_kb(round(eval {$msg_size / ($msg_outbound + $msg_inbound) } or 0)); print $OUT qq( Kb ); #print $OUT round2($msg_deferred / ($std_period /24)); print $OUT qq(
Average Size of Inbound Messages); print $OUT fmt_kb(round(eval {$msg_in_size / $msg_inbound } or 0)); print $OUT qq( KbAverage Size of Outbound Messages); print $OUT fmt_kb(round(eval {$msg_out_size / $msg_outbound } or 0)); print $OUT qq( Kb
); } sub make_chart { # 400x250 my $max = 0; $msg_deferred > $max && ($max = $msg_deferred); $msg_rejected > $max && ($max = $msg_rejected); $msg_inbound > $max && ($max = $msg_inbound); $msg_outbound > $max && ($max = $msg_outbound); my $wde = round(eval { ($msg_deferred * 100) / $max } or 0); my $wre = round(eval { ($msg_rejected * 100) / $max } or 0); my $wib = round(eval { ($msg_inbound * 100) / $max } or 0); my $wob = round(eval { ($msg_outbound * 100) / $max } or 0); print $OUT <<"EOFHTML";
Deferred
$msg_deferred
Rejected
$msg_rejected
Inbound
$msg_inbound
Outbound
$msg_outbound
EOFHTML return; } sub round { return int( shift() + .5); } sub round2 { return int( shift() * 100 + .5) / 100; } sub fmt_kb { my $x = shift; $x =~ s/(\d{1,3})(?=(\d{3})+$)/$1'/g; return $x; } sub read_config { open( CONF, "$conf_file" ) or die "Configfile '$conf_file' Error: $!\n"; while ( my $line = ) { next if $line =~ /^(#|\s+)/; CS: { $line =~ /^HIDE_USERS\s*=\s*(.*)/i && do { $HIDE_USERS = TRUE if $1 =~ m/true/i; last CS; }; $line =~ /^DEBUG\s*=\s*(.*)/i && do { $DEBUG = TRUE if $1 =~ m/true/i; last CS; }; $line =~ /^out_file\s*=\s*(.*)/i && do { $out_file = $1 if $1; last CS; }; $line =~ /^geoip_dbase\s*=\s*(.*)/i && do { $geoip_dbase = $1 if $1; last CS; }; $line =~ /^max_top_snt\s*=\s*(.*)/i && do { $max_top_snt = $1; last CS; }; $line =~ /^max_top_rcv\s*=\s*(.*)/i && do { $max_top_rcv = $1; last CS; }; $line =~ /^max_top_siz\s*=\s*(.*)/i && do { $max_top_siz = $1; last CS; }; $line =~ /^max_top_riz\s*=\s*(.*)/i && do { $max_top_riz = $1; last CS; }; $line =~ /^max_top_def\s*=\s*(.*)/i && do { $max_top_def = $1; last CS; }; $line =~ /^max_top_rej\s*=\s*(.*)/i && do { $max_top_rej = $1; last CS; }; $line =~ /^max_top_ssp\s*=\s*(.*)/i && do { $max_top_ssp = $1; last CS; }; $line =~ /^max_top_sts\s*=\s*(.*)/i && do { $max_top_sts = $1; last CS; }; $line =~ /^max_top_rel\s*=\s*(.*)/i && do { $max_top_rel = $1; last CS; }; $line =~ /^max_top_mlr\s*=\s*(.*)/i && do { $max_top_mlr = $1; last CS; }; $line =~ /^max_top_hst\s*=\s*(.*)/i && do { $max_top_hst = $1; last CS; }; } } close CONF; }