#!/afs/athena/contrib/perl5/p -w

use strict;
use FileHandle;
use lib '/u1/project/stats';
use Finger;
use SelectLoop;

open(PID, "> /u1/project/stats/f-stats.pid") || die "can't open pidfile";
print PID "$$\n";
close(PID);

use vars qw( $SL @host @user @ltime @unadulterated );

$Finger::ConnectTimeout = 5;
# $SelectLoop::Debug=1;
# $Finger::Debug=1;

sub uniq {	# (c) center for advanced cheating studies =)
  keys %{{map(($_, ''), @_)}};
}

sub user {
  my ($i, $data) = @_;
  $data || return undef;
  ($data =~ /^No one logged on/) && return '';
  ($data =~ /^Login\s/)
    || do { warn "$host[$i]: UNKNOWN format ($data)"; return undef };
  $data =~ s/\r\n/\n/g;

  my ($format, @lines) = split(/\n+/, $data);
  my (@users) = uniq( map( (split /\s/, $_, 2)[0], @lines ) );
  print STDERR "ignoring some ($#users) users on $host[$i]\n" if $#users;
  $users[0];
}

sub digest {
  my ($i) = @_;
  my ($who) = user(@_);
  my ($time);

  return unless defined $who;

  if (defined $user[$i]) {
    return if ($user[$i] eq $who);
    print STDERR "login change \@$host[$i]: $user[$i] -> $who\n";
    $time = time;
    if ($user[$i] && $unadulterated[$i]) {
      print $time - $ltime[$i], "\n";
      print STDERR "lt: $user[$i]\@$host[$i]\n";
    }
    $unadulterated[$i] = 1;
  } else {
    print STDERR "initial login \@$host[$i]: $who\n";    
    $time = time;
  }

  $user[$i] = $who;
  $ltime[$i] = $time;
}

######## main program starts here

STDOUT->autoflush(1);
STDERR->autoflush(1);

@ARGV || print STDERR "No args, reading stdin...\n";

$SL = new SelectLoop
  ('handler' => sub { digest ($_[1], $_) if ($_[0] eq 'EOF');  (1) } );

my $i;

HOST:
while (<>) {
  s/^\s+//;   s/\s+$//;
  next HOST if /^\s*\#/;
  push(@host, $_);
}
close ARGV;

while (1) {  
  my $start = time;

  foreach $i (0..$#host) {
    $SL->add( Finger::query("\@$host[$i]"), $i );
    $SL->do_select;
  }

  $SL->timeout(undef);	# might as well block now
  $SL->do_select while $SL->entries;

  my $wait = $start+60 - time;
  if ($wait > 0) {
    print STDERR "waiting: $wait s\n";
    sleep($wait);
  }
}
