#/usr/local/bin/perl
eval "exec /usr/bin/perl -S $0 $*"
 if $running_under_some_shell;
do verify_perl_version (3001);

# @(#)@ uutraf  1.4 - uutraf.pl
#
# UUCP Traffic Analyzer
#
# Reads /usr/spool/uucp/.Admin/xferstats, and generates a report from
it.
# Also understands Ultrix SYSLOG format.
#
# Created by Johan Vromans <[email protected]>
# Loosely based on an idea by Greg Hackney ([email protected])

# Usage: uutraf [xferstats]

$type = "unknown";

if ( $#ARGV >= 0 ) {
   open (STDIN, $ARGV[0]) || die "Cannot open $ARGV[0]";
   open (IN, $ARGV[0]) || die "Cannot open $ARGV[0]";
   $line = <IN>;
   split (/ /, $line);
   $type = ($_[0] =~ /!/) ? "HDB" : "U";
}
elsif ( -r "/usr/spool/uucp/.Admin/xferstats" ) {
   open (STDIN, "/usr/spool/uucp/.Admin/xferstats");
   $type = "HDB";
}
elsif ( -r "/usr/spool/uucp/SYSLOG" ) {
   open (STDIN, "/usr/spool/uucp/SYSLOG");
   $type = "U";
}
else { die "Sorry, don't know what"; }

if ( $type eq "HDB" ) {
   $pat = "([^!]+)![^(]+\\(([-0-9:/]+)\\).+([<>])-? (\\d+) /
(\\d+)\\.(\\d+) secs";
   $recv = "<";
}
else {
   $pat =
"\\S+\\s+(\\S+)\\s+\\(([-0-9:/]+)\\)\\s+\\(\\d+\\)\\s+(\\w+) (\\d+) b
(\\d+) secs";
   $recv = "received";
}

%hosts = ();            # hosts seen
%bytes_in = ();         # of bytes received from host
%bytes_out = ();        # of bytes sent to host
%secs_in = ();          # of seconds connect for recving
%secs_out = ();         # of seconds connect for sending
%files_in = ();         # of input requests
%files_out = ();        # of output requests

# read info, break the lines and tally

while ( <STDIN> ) {
 if ( /^$pat/o ) {
   print "host $1, date $2, dir $3, bytes $4, secs $5.$6\n";
   $6 = 0 if $type eq "U";
   # gather timestamps
   $last_date = $2;
   $first_date = $last_date unless defined $first_date;

   # initialize new hosts
   unless ( defined $hosts{$1} ) {
     $hosts{$1} = $files_in{$1} = $files_out{$1} =
       $bytes_in{$1} = $bytes_out{$1} =
         $secs_in{$1} = $secs_out{$1} = 0;
   }

   # tally
   if ( $3 eq $recv ) {                # recv
     $bytes_in{$1} += $4;
     $files_in{$1}++;
     $secs_in{$1} += $5 + $6/1000;
   }
   else {                      # xmit
     $bytes_out{$1} += $4;
     $files_out{$1}++;
     $secs_out{$1} += $5 + $6/1000;
   }
 }
 else {
   print STDERR "Possible garbage: $_";
 }
}

@hosts = keys (%hosts);
die "No info found, stopped" if $#hosts < 0;

################ report section ################

$thishost = do gethostname();
$thishost = (defined $thishost) ? "on node $thishost" : "report";

format std_head =
@|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
||||
"UUCP traffic $thishost from $first_date to $last_date"

Remote   -----------K-Bytes----------- -----Hours----- --Avg CPS--
--Files--
Host         Recv      Sent     Total    Recv    Sent  Recv  Sent
Recv Sent


format std_out =
@<<<<<<< @>>>>>>>> @>>>>>>>> @>>>>>>>> @>>>>>> @>>>>>> @>>>> @>>>>
@>>> @>>>
$Zhost,   $Zi_bytes, $Zo_bytes, $Zt_bytes, $Zi_hrs, $Zo_hrs,
$Zi_acps, $Zo_acps, $Zi_count, $Zo_count



$^ = "std_head";
$~ = "std_out";

do print_dashes ();

reset "T";             # reset totals

foreach $host (@hosts) {
 do print_line ($host, $bytes_in{$host}, $bytes_out{$host},
                $secs_in{$host},  $secs_out{$host},
                $files_in{$host}, $files_out{$host});

}

do print_dashes ();
do print_line ("Total", $Ti_bytes, $To_bytes,
              $Ti_secs, $To_secs, $Ti_count, $To_count);

################ that's it ################

sub print_line {
 reset "Z";            # reset print fields
 local ($Zhost,
        $Zi_bytes, $Zo_bytes,
        $Zi_secs, $Zo_secs,
        $Zi_count, $Zo_count) = @_;
 $Ti_bytes += $Zi_bytes;
 $To_bytes += $Zo_bytes;
 $Zt_bytes = $Zi_bytes + $Zo_bytes;
 $Tt_bytes += $Zt_bytes;
 $Zi_acps = ($Zi_secs > 0) ? sprintf ("%.0f", $Zi_bytes/$Zi_secs) :
"0";
 $Zo_acps = ($Zo_secs > 0) ? sprintf ("%.0f", $Zo_bytes/$Zo_secs) :
"0";
 $Zi_bytes = sprintf ("%.1f", $Zi_bytes/1000);
 $Zo_bytes = sprintf ("%.1f", $Zo_bytes/1000);
 $Zt_bytes = sprintf ("%.1f", $Zt_bytes/1000);
 $Zi_hrs = sprintf ("%.2f", $Zi_secs/3600);
 $Zo_hrs = sprintf ("%.2f", $Zo_secs/3600);
 $Ti_secs += $Zi_secs;
 $To_secs += $Zo_secs;
 $Ti_count += $Zi_count;
 $To_count += $Zo_count;
 write;
}

sub print_dashes {
 $Zhost = $Zi_bytes = $Zo_bytes = $Zt_bytes =
   $Zi_hrs = $Zo_hrs = $Zi_acps = $Zo_acps = $Zi_count = $Zo_count =
     "------------";
 write;
 # easy, isn't it?
}

################ missing ################

sub gethostname {
 $ENV{"SHELL"} = "/bin/sh";
 $try = `hostname 2>/dev/null`;
 chop $try;
 return $+ if $try =~ /^[-.\w]+$/;
 $try = `uname -n 2>/dev/null`;
 chop $try;
 return $+ if $try =~ /^[-.\w]+$/;
 $try = `uuname -l 2>/dev/null`;
 chop $try;
 return $+ if $try =~ /^[-.\w]+$/;
 return undef;
}

################ verify perl version ################

# do verify_perl_version ( [ required , [ message ] ] )

sub verify_perl_version {
 local ($version,$patchlevel) = $] =~ /(\d+.\d+).*\nPatch level:
(\d+)/;
 $version = $version * 1000 + $patchlevel;

 # did the caller pass a required version?
 if ( $#_ >= 0 ) {
   local ($req, $msg, @req);
   @req = split (//, $req = shift);
   # if the request is valid - check it
   if ( $#req == 3 && $req > $version ) {
     if ( $#_ >= 0 ) { # user supplied message
       $msg = shift;
     }
     else {
       $msg = "Sorry, this program requires perl " . $req[0] . "." .
$req[1] .
               " patch level " . $req % 100 ." or later.\nStopped";
     }
     die $msg;
   }
 }
 return $version;
}