[alt.sources] sendmail syslog summarizer

tchrist@convex.com (Tom Christiansen) (08/31/89)

This is in response to article <848@radig.UUCP> by 
peter@radig.UUCP (Peter Radig) in comp.mail.sendmail
and comp.sources.wanted, who wanted: 

>is there any public domain accounting package for the sendmail kit?
>I need it for charging my users against their outgoing mail.

I whipped together a quick perl script to do this.  I call it ssl.  It
will summarize both incoming and outgoing mail by user according to
bytes transferred and also according to message count.  It has some
remedial address parsing to try to determine the person's mbox part of
the address, This is the first crude attempt, but it works.  Things yet
to do include:

	write a man page
	merge some of the common To: and From: code
	    by using multi-dimensional arrays
	add sorting options
	add more intelligence to address parsing

--tom

#!/usr/local/bin/perl
#
# summarize sendmail syslog
#
# flags mean:
#
#	-o	outbound mail only
#	-i	inbound  mail only
#	-t	suppress printing of totals
#	-e 	print strange lines to stderr
#	-m	reduce to local mbox is possible

($program = $0) =~ s%.*/%%;


while ($ARGV[0] =~ /^-/) {
    $ARGV[0] =~ s/^-//; 
    foreach $flag ( split (//,$ARGV[0]) ) {
	if ( 'oitem' !~ /$flag/ ) {
	    printf stderr "unknown flag: %s\n", $flag;
	    die "usage: $program [-oitem] [syslog_file ...]\n";
	} 
	die "$0: '$flag' flag already set\n" if ($flags{$flag}++);
    } 
    shift;
}

if ( !$flags{'o'} && !$flags{'i'} && !$flags{'t'}) {
    $flags{'o'}++;
    $flags{'i'}++;
} 

do hash_passwd() if $flags{'m'};

while (<>) {
    if (/: [A-Z][A-Z](\d+): from=(.*), size=(\d+)/) {
	next unless $flags{'t'} || $flags{'o'};
	($id, $user, $size) = ($1, $2, $3);
	$user =~ s/.*<(.*)>/$1/;

	if ($flags{'m'}) {
	    $ouser = $user;
	    $user = do strip($user);
	    $user = $ouser if ! $known{$user};
	}

	$from_user_size{$user} += $size;
	$id_size{$id} = $size;
	$from_user_count{$user}++;
	$total_from++;
    } elsif (/: [A-Z][A-Z](\d+): to=(.*), delay=/) {
	next unless $flags{'t'} || $flags{'i'};
	$id = $1;
	for (split(/,/, $2)) {
	    s/.*<(.*)>/$1/;
	    $to = $flags{'m'} ? do strip($_) : $_;
	    printf "adding %d bytes to %s from %s\n",
		$id_size{$id},$to,$id; 
	    if (!$to) {
		die "to no one: $_\n";

	    } 
	    $to_user_size{$to} += $id_size{$id};
	    $to_user_count{$to}++;
	    $total_to++;
	} 
    } else {
	study;
	next if /message-id/;
	next if /locked/;
	next if /alias database (auto|)rebuilt/;
	#next if /aliases/;
	next if /rebuilding alias database/;
	print stderr if $flags{'e'};
	$errors++;
    } 
} 

printf stderr "Error lines: %d\n", $errors if $errors && ($flags{'e'}) && !($flags{'t'});


if ($flags{'i'}) {
    printf "To: %d\n", $total_to unless $flags{'t'};;
    foreach $user ( keys(to_user_size) ) {
	printf "%4d message%s %7d bytes %s\n",
	    $to_user_count{$user}, 
	    $to_user_count{$user} != 1 ? "s" : " ",
	    $to_user_size{$user}, 
	    $user;
    } 
}


if ($flags{'o'}) {
    printf "From: %d\n", $total_from unless $flags{'t'};;
    foreach $user ( keys(from_user_size) ) {
	printf "%4d message%s %7d bytes %s\n",
	    $from_user_count{$user}, 
	    $from_user_count{$user} != 1 ? "s" : " ",
	    $from_user_size{$user}, 
	    $user;
    } 
}

sub strip {
    $_ = @_;
    
    s/@.*//;
    s/.*!//;
    s/\s*\(.*\)//;
    tr/A-Z/a-z/;

    return $_;
} 

sub hash_passwd {
    chop($yp = `/bin/domainname`) if -x '/bin/domainname';
    $passwd = $yp ? 'ypcat passwd |' : '/etc/passwd';
    open passwd || die "$program: can't open $passwd: $!\n";
    while (<passwd>) {
	/^(\w+):[^:]+:(\d+):.*/;
	($who,$uid) = ($1, $2);
	$uid = 'zero' if ! $uid;  # kludge for uid 0
	$known{$who} = $uid;
    } 
    close passwd;
} 

    Tom Christiansen                       {uunet,uiucdcs,sun}!convex!tchrist 
    Convex Computer Corporation                            tchrist@convex.COM
		 "EMACS belongs in <sys/errno.h>: Editor too big!"