#!/usr/bin/perl
# vi:ts=4
#
# gen_mail_report - generate a report from the summarization statistics
# gathered by "extract_mail_stats"
# - run by the 'report_mail_stats' script
#
#
# See "Usage" part below for list of flags.
#
#
# Matt Covey, MetaWire, Inc., June, July 1997
# initially from ideas by Tom Christiansen <tchrist@convex.com> ("ssl"),
# and Paul O'Neill, Coastal Imaging Lab, Oregon State University,
# 18 jun 90
#
#
# Typical output:
#
#
# Tue, May 17 8438 msgs arrived, delivered to 7108 addresses [50.147 Mbytes]
# 11949 errors
# 6 msgs / minute (ave) [min 4, max 7]
#
# From To Domain % Bytes
# ------- -------- -------------------------------------- --- ---------
# <- 158 4910 -> test.com.............................. 32% 36.629 M
# <- 504 4 -> yahoo.com............................. 3% 578 K
# <- 58 446 -> genius.com............................ 3% 2.293 M
# 389 -> cyberagenz.com........................ 2% 2.373 M
# 321 -> [ignored]............................. 2% 1.249 M
# <- 314 <blank 'from'>........................ 2% 1.890 M
# <- 4 281 -> transware.com......................... 1.406 M
# <- 221 6 -> hotmail.com........................... 288 K
# <- 126 msn.com............................... 181 K
# 90 -> mac.com............................... 1.462 M
# <- 74 4 -> comcast.net........................... 3.834 M
# <- 70 funtimedate.com....................... 80 K [list shortened
# <- 1 cinemateka.ru......................... 388 K after this line]
# <- 5655 69 -> 3423 domains with < 15 msgs, 2%, 300K. 36% 20.564 M
# ------- -------- -------------------------------------- --- ---------
#
#
# ------------------------------------------------------------------------------|
# 411| * |
# 390| * * |
# 369| * * * * * * * |
# 349| * * * * * * * * * * * * * * |
# 328| * * * * * * * * * * * * * * * * * * * |
# 308| * * * * * * * * * * * * * * * * * * * * * |
# 287| * * * * * * * * * * * * * * * * * * * * * * * |
# 267| * * * * * * * * * * * * * * * * * * * * * * * |
# 246| * * * * * * * * * * * * * * * * * * * * * * * |
# 226| * * * * * * * * * * * * * * * * * * * * * * * * |
# 205| * * * * * * * * * * * * * * * * * * * * * * * * |
# 184| * * * * * * * * * * * * * * * * * * * * * * * * |
# 164| * * * * * * * * * * * * * * * * * * * * * * * * |
# 143| * * * * * * * * * * * * * * * * * * * * * * * * |
# 123| * * * * * * * * * * * * * * * * * * * * * * * * |
# 102| * * * * * * * * * * * * * * * * * * * * * * * * |
# 82| * * * * * * * * * * * * * * * * * * * * * * * * |
# 61| * * * * * * * * * * * * * * * * * * * * * * * * |
# 41| * * * * * * * * * * * * * * * * * * * * * * * * |
# 20| * * * * * * * * * * * * * * * * * * * * * * * * |
# ------------------------------------------------------------------------------|
# hour: 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
# ------------------------------------------------------------------------------|
#
require '/usr/local/etc/syswatch/bin/sw_common.pl';
do set_common_vars();
#
# Defaults:
#
# report if...
$TheThresholdMsgs = 0; # has this many msgs, else goes in "others" category
$UseNMsgThreshold = 0; # off
$TheThresholdPercent = 0; # or has this much percent of total to/from msgs
$UsePercentThreshold = 0; # off
$TheThresholdKBytes = 0; # or has this many Kbytes
$UseKBytesThreshold = 0; # off
$ReportStrangeLines = 1; # on
$ReportDeferrals = 1; # on
$ReportTotals = 1; # on
$ReportBytes = 1; # on
$ReportDetails = 1; # on
$ReportHourly = 0; # off
$ReportAveragePer = 1; # off
$IsSeparateDefersTable = 0; # off
$ChangeUserToDomain = 1; # on
$TopLevelDomainsOnly = 0; # off
#
# User/domain aliases, ones to ignore, etc
#
$TheIgnoreFile = "$SW_CONFIG/mailusers.ignore";
$TheUserAliasesFile = "$SW_CONFIG/mailusers.aliases";
$TheDomainAliasesFile = "$SW_CONFIG/maildomains.aliases";
#
# Display related details:
#
$MIN_PERCENT_TO_PRINT_PERCENT_NUMBER = 2; # otherwise don't print anything
$MAX_USER_NAME_COL_WIDTH = 38;
$N_LINES_OF_GRAPH_DATA = 20;
#
# Some log entries can be: "... from=<>, size=..."
# Use this string as a placeholder.
#
$NO_FROM_USER = '<blank \'from\'>';
$NO_TO_USER = '<blank \'to\'>';
#
# Main part of program:
#
do handle_args ();
do hash_passwd () if $ReduceToLocalMailbox;
do read_ignore_users ( $TheIgnoreFile ) if( -e $TheIgnoreFile );
do read_user_aliases ( $TheUserAliasesFile ) if( -e $TheUserAliasesFile );
do read_domain_aliases( $TheDomainAliasesFile ) if( -e $TheDomainAliasesFile );
while( $ARGV[0] )
{
$NDays++;
do read_stats( $ARGV[ 0 ] );
shift;
}
do output_stats();
exit( 0 );
#
# -- end --
#
#
# handle_args
#
# Parse the args and set out internal flags
#
sub handle_args
{
while( $ARGV[ 0 ] =~ /^-/ )
{
if( &is_arg( '-threshold' ) || &is_arg( '-t' ) )
{
$n = int( $ARGV[ 0 ] );
$last_chr = substr( $ARGV[ 0 ], length( $ARGV[ 0 ] - 1 ) );
if( $last_chr eq '%' )
{
$TheThresholdPercent = $n;
$UsePercentThreshold = 1;
}
elsif( $last_chr eq 'K' )
{
$TheThresholdKBytes = $n;
$UseKBytesThreshold = 1;
}
elsif( $last_chr eq 'M' )
{
$TheThresholdKBytes = $n * 1024;
$UseKBytesThreshold = 1;
}
else
{
$TheThresholdMsgs = $n;
$UseNMsgThreshold = 1;
}
shift ARGV;
next;
}
if( &is_arg( '-all' ) )
{
$TheThresholdKBytes = 0;
$UseKBytesThreshold = 0;
$TheThresholdPercent = 0;
$UsePercentThreshold = 0;
$TheThresholdMsgs = 0;
$UseNMsgThreshold = 0;
next;
}
$ChangeUserToDomain = 0, next if( &is_arg( '-Users' ) );
$ChangeUserToDomain = 1, next if( &is_arg( '-Domains' ) );
$TopLevelDomainsOnly = 1, next if( &is_arg( '-topleveldomains' ) );
$ReportDetails = 0, next if( &is_arg( '-nodetails' ) );
$ReportTotals = 0, next if( &is_arg( '-nototals' ) );
$ReportBytes = 0, next if( &is_arg( '-nobytes' ) );
$ReportDeferrals = 0, next if( &is_arg( '-nodefers' ) );
$ReportHourly = 1, next if( &is_arg( '-hourly' ) );
$ReportAveragePer = 1, next if( &is_arg( '-avePer' ) );
$ReportStrangeLines = 1, next if( &is_arg( '-e' ) );
$ReduceToLocalMailbox= 1, next if( &is_arg( '-m' ) );
$Debug = 1, next if( &is_arg( '-d' ) );
$Debug = 2, next if( &is_arg( '-d2' ) );
$TheTimeSpanLabel = $ARGV[ 0 ], shift ARGV, next if( &is_arg( '-periodLabel' ) );
print stderr "unknown arg: $ARGV[ 0 ]\n";
print "Usage: $program [flags] counts_file+
flags=
-Domains reduce addresses to domains (jj\@A.B.co.jp -> B.co.jp)
-topleveldomains reduce addresses to top level domains (jj\@A.B.co.jp -> co.jp)
-Users use full address (jj\@A.B.co.jp)
-threshold <num> min number of msgs needed to report addr
xx% min percent of msgs needed to report addr
xxK min KBytes of msgs needed to report addr
xxM min MBytes of msgs needed to report addr
-t same as -threshold
-all show all addresses (don't use thresholds)
-hourly print a graph of hourly received times
-nototals suppress printing of totals
-nodetails suppress printing of details
-nodefers suppress printing of deferral counts
-nobytes suppress printing of byte counts
-avePer print average msgs per day, etc
-periodLabel use this as the time period label (ex: 'Tue, Jul 1')
-d turn on debug mode
-d2 turn even more debugging on
-m reduce to local mbox is possible
-e print strange lines to stderr
";
exit -1;
}
# print "Debug mode\n" if( $Debug );
}
sub mk_threshold_label
{
local ( $n_lbl ) = @_;
local ( $type_lbl ) = 'domain';
$type_lbl = 'user' if( ! $ChangeUserToDomain );
$type_lbl = $type_lbl . 's' if( int( $n_lbl ) != 1 );
local ( $lbl ) = "$n_lbl $type_lbl with <";
local ( $sep ) = ' ';
if( $TheThresholdMsgs > 1 )
{
$lbl = $lbl . "$sep$TheThresholdMsgs msgs";
$sep = ', ';
}
if( $TheThresholdPercent >= 1 )
{
$lbl = $lbl . "$sep$TheThresholdPercent%";
$sep = ', ';
}
if( $TheThresholdKBytes >= 1 )
{
local ( $unit ) = 'K';
local ( $n ) = $TheThresholdKBytes;
if( $TheThresholdKBytes >= 1000 )
{
$n = int( $TheThresholdKBytes / 1000 );
$unit = 'M';
}
$lbl = $lbl . "$sep${n}$unit";
$sep = ', ';
}
# $lbl = $lbl . " <<";
return $lbl;
}
#
# read_ignore_users
#
# Read the file containing users to not print info about
#
sub read_ignore_users
{
local ( $fn ) = @_;
open( IUF, $fn ) || die "Can't open ignore file $fn";
while( <IUF> )
{
next if( /^#/ );
next if( /^$/ );
chop( $_ );
$TheIgnoreUsers{ $_ } = 1;
print "Ignoring user $_\n" if( $Debug > 1 );
}
print "\n" if( $Debug > 1 );
close( IUF );
}
#
# read_user_aliases
#
# Read the file containing aliases for users
#
sub read_user_aliases
{
local ( $fn ) = @_;
local ( $contains, $called );
open( IUF, $fn ) || die "Can't open alias file $fn";
while( <IUF> )
{
next if( /^#/ );
next if( /^$/ );
chop( $_ );
($contains, $called) = split;
$TheUserAliases{ $contains } = $called;
print "Aliasing: users containing '$contains' -> $called\n" if( $Debug > 1 );
}
print "\n" if( $Debug > 1 );
close( IUF );
@TheUserAliasKeys = keys( TheUserAliases );
}
#
# read_domain_aliases
#
sub read_domain_aliases
{
local ( $fn ) = @_;
local ( $contains, $called );
open( IUF, $fn ) || die "Can't open alias file $fn";
while( <IUF> )
{
next if( /^#/ );
next if( /^$/ );
chop( $_ );
($contains, $called) = split;
$TheDomainAliases{ $contains } = $called;
print "Aliasing: users containing '$contains' -> $called\n" if( $Debug > 1 );
}
print "\n" if( $Debug > 1 );
close( IUF );
@TheDomainAliasKeys = keys( TheDomainAliases );
}
#
# read_stats
#
sub read_stats
{
local ( $fn ) = @_;
local ( $user, $n_to, $n_from, $bytes_to, $bytes_from, $n, $ndeferrals );
open( LD, $fn ) || die "Can't open $fn";
while( <LD> )
{
next if( /^#/ );
next if( /^$/ );
$NMsgsFrom += $1, next if( /^MsgsFrom (\d+)/ );
$NMsgsTo += $1, next if( /^MsgsTo (\d+)/ );
$NErrors += $1, next if( /^Error lines (\d+)/ );
$NDeferrals += $1, next if( /^Deferred (\d+)/ );
$NBlocked += $1, next if( /^Blocked (\d+)/ );
$NBlockedExpired += $1, next if( /^BlockedExpired (\d+)/ );
$NUnblocked += $1, next if( /^Unblocked (\d+)/ );
#
# Hourly 0 5 2 10 1 ...
#
if( /^Hourly (.*)/ )
{
local ( @hrs ) = split( /\t/, $1 );
local ( $hr );
foreach $hr (00..23)
{
$Hourly{ $hr } += $hrs[ int( $hr ) ];
}
next;
}
#
# A regular "user" line:
#
($user, $n_to, $n_from, $bytes_to, $bytes_from, $ndeferrals) = split( /\t/ );
#
# Check for replacing this user with an alias
#
$user = &chk_for_alias( $user );
#
# Only want to deal with domains?
#
# matt@kamson.com -> kamson.com
#
$user = &extract_domain( $user ) if( $ChangeUserToDomain );
$to_user_count { $user } += $n_to;
$from_user_count{ $user } += $n_from;
$to_user_size { $user } += $bytes_to;
$from_user_size { $user } += $bytes_from;
$deferrals { $user } += $ndeferrals;
$total_to += $n_to;
$total_from += $n_from;
$total_to_size += $bytes_to;
$total_from_size += $bytes_from;
$total_msgs_deferred += $ndeferrals;
}
close( LD );
}
#
# extract_domain
#
# Given a mail address matt@mail.metawire.com
# return the domain part: metawire.com
#
# NOTE that if a name has several parts, we just
# remove the top-most:
#
# matt@mail.northca.metawire.com
# return northca.metawire.com
#
sub extract_domain
{
local ( $addr ) = @_;
local ( $usr, $host_or_domain ) = split( '@', $addr, 2 );
#
# Check for invalid addresses, like:
#
# @angstrom.metawire.com:anjyo@hrl.hitachi.co.jp
#
# Which would have split into:
#
# $usr = '' -- nothing
# $host_or_domain = angstrom.metawire.com:anjyo@hrl.hitachi.co.jp
#
local ( $n ) = 0;
while( $host_or_domain =~ /.*\@(.*)/ )
{
#
# Split into: angstrom.metawire.com:anjyo hrl.hitachi.co.jp
#
print "domain: bad addr: $addr\n" if( $Debug && $n++ == 0 );
$host_or_domain = $1;
}
#
# No domain part ? Then rtn addr
#
return $addr if( ! $host_or_domain );
local ( $mach, $domain ) = split( '\.', $host_or_domain, 2 );
#
# Must be "apple.com", not "lists.apple.com" ?
#
if( $TopLevelDomainsOnly && $domain =~ /.*\.(.*\..*)$/ )
{
return $1 if( $1 );
}
#
# $domain is at least "abc.com"? Then can rtn that.
#
return $domain if( $domain && $domain =~ /.*\..*/ );
#
# $host_or_domain is a good looking "abc.com"?
#
return $host_or_domain if( $host_or_domain =~ /.*\..*/ );
#
# Doesn't fit the normal pattern, so just rtn the whole thing
#
return $addr;
}
#
# chk_for_alias
#
sub chk_for_alias
{
local ( $usr ) = @_;
local ( $a );
foreach $a (@TheUserAliasKeys)
{
return $TheUserAliases{ $a } if( $usr =~ /$a/ );
}
if( $ChangeUserToDomain )
{
foreach $a (@TheDomainAliasKeys)
{
return $TheDomainAliases{ $a } if( $usr =~ /$a/ );
}
}
return $usr;
}
#
# output_stats
#
sub output_stats
{
local ( $user, $n, $max_user_name );
$max_user_name = 10;
#
# Merge both together
#
@loop = keys( to_user_count );
foreach $user (@loop)
{
$both_count{ $user } = $to_user_count{ $user };
$n = length( $user );
$max_user_name = $n if( $n > $max_user_name );
}
@loop = keys( from_user_count );
foreach $user (@loop)
{
$both_count{ $user } += $from_user_count{ $user };
$n = length( $user );
$max_user_name = $n if( $n > $max_user_name );
}
local ( $below_thresh ) = &mk_threshold_label( "5####" );
$n = length( $below_thresh );
$max_user_name = $n if( $n > $max_user_name );
$max_user_name = $MAX_USER_NAME_COL_WIDTH if( $max_user_name > $MAX_USER_NAME_COL_WIDTH );
do print_totals() if( $ReportTotals );
do print_details( $max_user_name ) if( $ReportDetails );
# do print_defers() if( $IsSeparateDefersTable );
do print_hourly_graph() if( $ReportHourly );
}
#
# Mon, Jul 7 116 msgs arrived, delivered to 117 addresses [379 Kbytes]
# 167 errors
# 12 msgs deferred a total of 174 times
# 33 blocked
# 5 msgs / hour (ave) [min 0, max 30]
#
sub print_totals
{
local ( $tspan ) = $TheTimeSpanLabel;
local ( $indent ) = &pad_col( '', length( $TheTimeSpanLabel ), ' ' );
#
# Is "Jun 30..Jul 6, 1997" ? Since this makes the whole
# first line too long, just split into:
#
# Jun 30 ..
# Jul 6, 1997 1034 msgs arrived, delivered to 1255 addresses
#
if( $tspan =~ /(.*)\.\.(.*)/ )
{
$tspan = "$1 ..\n$2 ";
$indent = length( $2 ) + 1;
$indent = substr( ' ', 0, $indent );
}
printf "$tspan %5d msgs arrived", $NMsgsFrom;
printf ", delivered to %d addresses", $NMsgsTo if( $NMsgsFrom != $NMsgsTo );
# print " ($total_to w/ to, $total_from w/ from)" if( $total_to != $total_from );
if( $ReportBytes )
{
local ( $n ) = $total_to_size;
$n = $total_from_size if( $total_from_size > $n );
local ( $kb ) = &KMbytes( $n, 'no spaces' );
print " [${kb}bytes]";
}
print "\n";
printf "$indent %5d errors\n", $NErrors if( $NErrors && $ReportStrangeLines );
if( $NDeferrals )
{
printf "$indent %5d msgs deferred", $total_msgs_deferred;
printf " a total of %d times", $NDeferrals if( $NDeferrals != $total_msgs_deferred );
print "\n";
}
if( $NBlocked )
{
printf "$indent %5d blocked", $NBlocked;
printf ", %d expired", $NBlockedExpired if( $NBlockedExpired );
print "\n"
}
elsif( $NBlockedExpired )
{
printf "$indent %5d blocked msgs expired\n", $NBlockedExpired if( $NBlockedExpired );
}
printf "$indent %5d unblocked\n", $NUnblocked if( $NUnblocked );
if( $ReportAveragePer )
{
# local ( $indent2 ) = substr( $indent, 0, length( $indent) - 5 ); # len( "(ave)" )
local ( $nmsgs ) = $NMsgsFrom;
$nmsgs = $NMsgsTo if( $NMsgsTo > $nmsgs );
local ( $n, $ave_msgs_unit ) = &calc_msgs_per_min_hr( $nmsgs, 24 );
local ( $plural ) = '';
$plural = 's' if( $n > 1 );
printf "$indent %5d msg$plural / $ave_msgs_unit (ave)", $n;
local ( $min_val ) = 999999;
local ( $max_val ) = 0;
local ( $hr );
foreach $hr (00..23)
{
$min_val = $Hourly{ $hr } if( $Hourly{ $hr } < $min_val );
$max_val = $Hourly{ $hr } if( $Hourly{ $hr } > $max_val );
}
($n, $unit) = &calc_msgs_per_min_hr( $min_val, 1 );
print " [min $n, ";
($n, $unit) = &calc_msgs_per_min_hr( $max_val, 1, $unit );
print "max $n";
print ", per $unit" if( $unit ne $ave_msgs_unit );
print "]";
printf "; %d msgs / day", int( $nmsgs / $NDays ) if( $NDays > 1 );
print "\n";
}
print "\n";
}
sub calc_msgs_per_min_hr
{
local ( $nmsgs, $n_hours, $use_unit ) = @_;
local ( $n, $unit );
if( $use_unit eq '' || $use_unit eq 'minute' )
{
$n = int( ($nmsgs / ($NDays * $n_hours * 60)) + 0.5 );
$unit = 'minute';
}
if( $n == 0 || $use_unit eq 'hour' )
{
$n = int( ($nmsgs / ($NDays * $n_hours)) + 0.5 );
$unit = 'hour';
}
return ($n, $unit);
}
sub print_details
{
local ( $max_user_name ) = @_;
local ( $below_threshold, $n, $user );
#
# From To Domain % Bytes Defers
# ----- ----- -------------------------------------------- --- --------- ------
#
&print_table_header();
&print_table_header( '-' );
#
# Total up the "ignored" user count/sizes
#
local ( $n_ignored_to, $n_ignored_from, $sz_ignored_to, $sz_ignored_from, $n_defers_ignored );
@loop = keys( both_count );
foreach $user (sort bothsort @loop)
{
if( $TheIgnoreUsers{ $user } )
{
$n_ignored_to += $to_user_count { $user };
$n_ignored_from += $from_user_count{ $user };
$sz_ignored_to += $to_user_size { $user };
$sz_ignored_from += $from_user_size { $user };
$n_defers_ignored += $deferrals { $user };
}
}
if( $n_ignored_to || $n_ignored_from )
{
$user = "[ignored]";
$to_user_count { $user } = $n_ignored_to;
$from_user_count{ $user } = $n_ignored_from;
$to_user_size { $user } = $sz_ignored_to;
$from_user_size { $user } = $sz_ignored_from;
$deferrals { $user } = $n_defers_ignored;
$both_count { $user } = $n_ignored_to + $n_ignored_from;
}
#
# print all the lines
#
@loop = keys( both_count );
foreach $user (sort bothsort @loop)
{
&pr_user_line( $user, $max_user_name ) if( ! $TheIgnoreUsers{ $user } );
}
local ( $thres ) = &mk_threshold_label( "$NBelowThresholdUsers" );
&pr_user_line( $thres, $max_user_name, $NBelowThresholdTo, $NBelowThresholdFrom,
$SzBelowThresholdTo, $SzBelowThresholdFrom,
$NBelowThresholdDefers )
if( $NBelowThresholdTo || $NBelowThresholdFrom || $NBelowThresholdDefers );
#
# And the bottom "------ ----- -----------------" line
#
&print_table_header( '-' ) if( $ReportTotals );
print "\n"; # a blank separator line
}
#
# From To Domain % Bytes Defers
# ------- -------- ----------------------------- --- --------- ------
#
sub print_table_header
{
local ( $underline ) = @_;
&pr_tbl_hdr_text( " From", $underline, ' ' );
&pr_tbl_hdr_text( " To ", $underline );
local ( $who_lbl ) = 'Email address';
$who_lbl = 'Domain' if( $ChangeUserToDomain );
&pr_tbl_hdr_text( $who_lbl . &pad_col( $who_lbl, $max_user_name, ' ' ), $underline );
&pr_tbl_hdr_text( " %", $underline );
&pr_tbl_hdr_text( " Bytes", $underline ) if( $ReportBytes );
&pr_tbl_hdr_text( "Defer", $underline ) if( $ReportDeferrals && $NDeferrals
&& ! $IsSeparateDefersTable );
print "\n";
}
sub pr_tbl_hdr_text
{
local ( $lbl, $underline, $ending_sep ) = @_;
$ending_sep = ' ' if( ! $ending_sep );
print &pad_col( '', length( $lbl ), '-' ) if( $underline );
print $lbl if( ! $underline );
print $ending_sep;
}
# From To Domain % Bytes Defers
# ------- -------- ----------------------------- --- --------- ------
# <- 82 145 -> cyberstudios.com............. 13% 546 K
# <- 34 103 -> metawire.com................. 8% 499 K 1
# <- 1 131 -> ffcnet.com................... 7% 445 K
# <- 71 bungi.com.................... 4% 300 K
# <- 25 39 -> endeavorla.com............... 3% 185 K
# <- 31 30 -> aol.com...................... 3% 375 K
# <- 50 watchdroid 6100.............. 2% 10 K
# 11 -> sierracanyon-pvt-k12-ca-us... 12
# <- 3 6 -> edgela.com................... 2.119 M
# <- 4 2 -> uu.net....................... 13 K 1
# <- 2 1 -> rotterdam.nl................. 2 K 1
# <- 1 1 -> msn.com...................... 4 K 1
# <- 457 332 -> 223 domains with < 2%, 300K.. 46% 3.768 M
# ------- -------- ----------------------------- --- --------- ------
#
sub pr_user_line
{
local ( $user,
$max_user_name,
$n_to,
$n_from,
$sz_to,
$sz_from,
$n_defers ) = @_;
if( $n_to == 0 && $n_from == 0 && $n_defers == 0 )
{
$n_to = $to_user_count { $user };
$n_from = $from_user_count{ $user };
$sz_to = $to_user_size { $user };
$sz_from = $from_user_size { $user };
$n_defers = $deferrals { $user };
}
local ( $perc ) = do percent_of( $n_to + $n_from, $NMsgsFrom + $NMsgsTo );
#
# Check against thresholds - are there enough msgs/
# % of msgs/bytes to report this individual, or so
# few we'll just lump them in with the "others" group?
#
if( ($UseNMsgThreshold && $n_to + $n_from >= $TheThresholdMsgs)
|| ($UseKBytesThreshold && $sz_to + $sz_from >= ($TheThresholdKBytes * 1024))
|| ($UsePercentThreshold && $perc >= $TheThresholdPercent)
|| $n_defers != 0
|| (! $UseNMsgThreshold && ! $UseKBytesThreshold && ! $UsePercentThreshold) )
{
# is above threshold
}
else # is below threshold, so lump into the "others" category
{
$NBelowThresholdTo += $n_to;
$NBelowThresholdFrom += $n_from;
$SzBelowThresholdTo += $sz_to;
$SzBelowThresholdFrom += $sz_from;
$NBelowThresholdDefers += $n_defers;
$NBelowThresholdUsers++;
return;
}
#
# From
#
print " " if( $n_from == 0 );
printf "<-%5d", $n_from if( $n_from != 0 );
#
# To
#
print " " if( $n_to == 0 );
printf " %5d ->", $n_to if( $n_to != 0 );
#
# Domain/Email addr
#
if( length( $user ) > $max_user_name )
{
$user = substr( $user, 0, $max_user_name - 1 ) . '+';
}
print " $user" . &pad_col( $user, $max_user_name, '.' );
#
# %
#
print " " if( $perc < $MIN_PERCENT_TO_PRINT_PERCENT_NUMBER );
printf " %2d%% ", $perc if( $perc >= $MIN_PERCENT_TO_PRINT_PERCENT_NUMBER );
#
# bytes
#
if( $ReportBytes )
{
# print " ";
$n = $sz_to + $sz_from;
print " " if( $n == 0 );
print &KMbytes( $n ) if( $n != 0 );
# print " " if( $sz_to == 0 );
# printf "%4d", $sz_to if( $sz_to != 0 );
# print " " if( $sz_from == 0 );
# printf "%4d", $sz_from if( $sz_from != 0 );
}
#
# Defers
#
if( $ReportDeferrals && $NDeferrals && ! $IsSeparateDefersTable )
{
print " " if( $n_defers == 0 );
printf " %4d", $n_defers if( $n_defers != 0 );
}
print "\n";
}
#
# print_hourly_graph()
#
# Print a nice bar chart of the hourly info
#
sub print_hourly_graph
{
local ( $hr, $max_val, $line );
$max_val = 0;
foreach $hr (00..23)
{
$max_val = $Hourly{ $hr } if( $Hourly{ $hr } > $max_val );
}
$max_val = $N_LINES_OF_GRAPH_DATA if( $max_val < $N_LINES_OF_GRAPH_DATA );
local ( $rs_scaling ) = $max_val / $N_LINES_OF_GRAPH_DATA;
local ( $percent_scaling ) = 100 / $N_LINES_OF_GRAPH_DATA;
print "\n\n";
print "-"x78;
print "|\n";
for($line=$N_LINES_OF_GRAPH_DATA; $line > -3; $line--)
{
next if( $line == 0 );
if( $line == -1 )
{
print "-"x78;
print "|\n";
next;
}
local ( $value_for_this_line ) = $line * $rs_scaling;
local ( $percent_for_this_line ) = $line * $percent_scaling;
printf ("%4d| ", int( $value_for_this_line ) ) if( $line > -1 );
print "hour: " if ( $line == -2 );
foreach $hr (0..23)
{
if( $line == -2 )
{
local ( $start ) = $hr;
$start = "0$hr" if( $hr < 10 );
print "$start ";
next;
}
$ind = "$host $hr";
if( ($line == 1 && $Hourly{ $hr } > 0)
|| ($Hourly{ $hr } >= $value_for_this_line) )
{
print " * ";
}
else
{
print " ";
}
}
print "|\n";
}
print "-"x78;
print "|\n";
}
#
# percent_of()
#
# Return how much $part is a percent of the $total
#
sub percent_of
{
local ( $part, $total ) = @_;
local ( $percent );
if( $part == 0 || $total == 0 )
{
$percent = 0;
}
elsif( $part == $total )
{
$percent = 100;
}
elsif( $part > $total )
{
$percent = 100;
}
else
{
$percent = int( ($part * 100) / $total );
$percent = 1 if( $percent == 0 );
}
return $percent;
}
sub tosort
{
($to_user_count { $b } - $to_user_count{ $a }) * 10000000 + $to_user_size { $b } - $to_user_size { $a };
}
sub fromsort
{
($from_user_count{ $b } - $from_user_count{ $a }) * 10000000 + $from_user_size{ $b } - $from_user_size{ $a };
}
sub bothsort
{
# ($both_count{ $b } - $both_count{ $a });
# (($both_count { $b } - $both_count { $a }) * 10000000) + ($a - $b);
if( $both_count{ $b } == $both_count{ $a } )
{
($b le $a);
}
else
{
(($both_count{ $b } - $both_count{ $a }) * 100000);
}
}
#
# pr_pad()
#
# Pad out this many chrs
# //print( "-"x78 );
#
sub pr_pad
{
local ( $wid,
$lbl,
$chr ) = @_;
local ( $len ) = 0;
if( $lbl )
{
$len = length( $lbl );
print $lbl;
}
$chr = ' ' if( ! $chr );
foreach ($len..$wid)
{
print $chr;
}
}
#
# KMbytes()
#
# return a string for this many bytes:
#
# 10 K
# 3 K
# 854 K
# 4.1 M
# 13.5 M
# 384.2 M
#
sub KMbytes
{
local ( $n, $suppress_spaces ) = @_;
local ( $i );
$n = int( ( int( $n ) + 1023) / 1024);
# 10 K
# 3 K
# 854 K
#
if( $n < 1000 )
{
if( $suppress_spaces )
{
$i = "$n";
}
else
{
$i = " $n";
$i = " $i" if( $n < 100 );
$i = " $i" if( $n < 10 );
}
return "$i K";
}
#
# 4.123 M
# 13.123 M
# 384.123 M
#
local ( $xx, $dd, $sd );
$xx = int( $n / 1000 );
$dd = int( ($n - ($xx * 1000)) );
$sd = "$dd";
$sd = "${sd}0" if( $dd < 100 );
$sd = "${sd}0" if( $dd < 10 );
$i = "$xx.$sd";
# $i = "$i.000" if( int( $n ) == $n );
if( ! $suppress_spaces )
{
$i = " $i" if( $xx < 100 );
$i = " $i" if( $xx < 10 );
}
return "$i M";
}
sub strip
{
local($foo) = shift(@_);
#print "$foo\n";
$foo =~ s/@.*//;
$foo =~ s/.*!//;
$foo =~ s/\s*\(.*\)//;
$foo =~ tr/A-Z/a-z/;
return $foo;
}
sub hash_passwd
{
chop( $yp = `/bin/domainname` ) if -x '/bin/domainname';
$passwd = $yp ? 'ypcat passwd |' : '/etc/passwd';
open( PASSWD, $passwd ) || die "$program: can't open $passwd: $!\n";
while( <PASSWD> )
{
/^(\w+):[^:]+:(\d+):.*/;
($who,$uid) = ($1, $2);
# $uid = 'zero' if ! $uid; # kludge for uid 0
$uid = 'zero' if( $uid == 0 && $who );
# $uid = 'zero' if defined($uid);
$known{$who} = $uid;
#print "$who $uid $known{$who}\n";
}
close PASSWD;
#print "SPECIEALLLL -- $known{''}\n";
}
|