#!/local/bin/perl

%service = ( 0, "unspec",
	     1, "Active",
	     2, "Passive",
	     3, "Client",
	     4, "Server",
	     5, "Broadcast",
	     6, "Control",
	     7, "Private" );
%nc = ();
@ignpat = ();
$noname = 0;
$verbose = 0;
$retries = 5;
$lastkey = 0;

sub timedelta {
  local($tm, $days, $h, $m, $s);

  $tm = @_[$[];
  $days = 0;
  $days = sprintf("%dd+", $days) if $days = int($tm / (60*60*24));
  $days = "" unless $days;
  $tm = $tm % (60*60*24);
  $h  = int($tm / (60*60));
  $tm = $tm % (60*60);
  $m  = int($tm / 60);
  $s  = $tm % 60;

  return sprintf("%s%02d:%02d:%02d", $days, $h, $m, $s);
}

sub listentry {
  local($host, $mode) = split("$;" , @_[$[]);
  local($count, $version, $firsttime) = split("$;" , $_[$[+1]);
  local($name);

  if (grep($host =~ m/$_/, @ignpat))
    {
      print "ignored $host ...\n" if $verbose;
      return;
    }

  return if ! $count;

  if (defined($nc{$host}))
    {
      $name = $nc{$host};
    }
  else
    {
      if ($noname)
	{
	  $nc{$host} = $name = $host;
	}
      else
	{
	  $name = (gethostbyaddr(pack("C4", split(/\./, $host)), 2))[$[];
	  $nc{$host} = $name = $host if ! defined($name);
	}
    }

  printf ($fmt, ($lastkey eq $host) ? "" : $name, $service{$mode}, $count, $version, &timedelta($firsttime), $firsttime / $count);

  if (@_[$[+2])
    {
      $hostcnt++ if $lastkey ne $host;
      $packcnt += $count;
      $maxtime = $firsttime if $firsttime > $maxtime;
    }

  $lastkey = $host;
}

while ($ARGV[$[] =~ /^-[nvid]$/)
  {
    if ($ARGV[$[] eq "-i")
      {
	shift;
	push(@ignpat, shift) unless ! defined($ARGV[$[]);
      }
    elsif ($ARGV[$[] eq "-d")
      {
	shift;
	$dir = shift unless ! defined($ARGV[$[]);
      }
    elsif ($ARGV[$[] eq "-n")
      {
	shift;
	$noname = 1;
      }
    elsif ($ARGV[$[] eq "-v")
      {
	shift;
	$verbose = 1;
      }
  }

$dir     = "/tmp" unless defined($dir);
$gone     = 60*60*48;
$fmt = "%48s %10s %7d %7d %13s %14.3f\n";
$sfmt = "%48s %10s %7s %7s %13s %14s\n";
@lbl = ("Host", "Mode", "Count", "Version", "Time active", "Packetinterval");

if (!defined($ARGV[$[]))
  {
    $hostname = `hostname`;
    chop($hostname);
    unshift(@ARGV, $hostname);
  }

foreach $hostname (@ARGV)
  {
    $dbmfile = $dir . "/monlstats-" . $hostname;
    $monl = "xntpdc -c 'hostnames no' -c monl $hostname | tail +3 |";
    $hostcnt = 0;
    $packcnt = 0;
    $maxtime = 0;
    %Seen = ();
    %New = ();
    %Old = ();

    print "Monitor Status of $hostname\n\n";

    $cnt = $retries;
    do
      {
	open(MONL, $monl) || die("$monl failed $!");
	@monlout = <MONL>;
	close(MONL);
      } while (! @monlout && $cnt--);

    if (! @monlout)
      {
	print "not available.\n";
	next;
      }

    dbmopen(Clients, $dbmfile, 0644) || die("dbmopen(.., $dbmfile, ...): $!");

    foreach (@monlout)
    {
      chop;
      split;
      ($host, $count, $mode, $version, $lasttime, $firsttime) = (@_[$[, $[+2 .. $[+6]);
      
      $Seen{$host, $mode} = 1;

      if (!defined($Clients{$host, $mode}))
	{
	  if ($lasttime <= $gone)
	    {
	      ## got a new one
	      $Clients{$host, $mode} = $New{$host, $mode} = join("$;", $count, $version, $firsttime, $lasttime);
	    }
	}
      else
	{
	  ## throw out the old ones
	  if ($lasttime > $gone)
	    {
	      $Old{$host, $mode} = $Clients{$host, $mode};
	      delete $Clients{$host, $mode};
	    }
	  else
	    {
	      $Clients{$host, $mode} = join("$;", $count, $version, $firsttime, $lasttime);
	    }
	}
    }

    grep(($Seen{$_} || ($Old{$_} = delete $Clients{$_})), keys(%Clients));

    if (grep(($tmp = $_ , !grep($tmp =~ m/$_/, @ignpat)), keys(%New)))
      {
	print "New customers\n";
	print "-------------\n";
	printf $sfmt, @lbl;
	grep( &listentry($_, $New{$_}, 1), sort(keys(%New)) );
	print "\n";
      }

  
    if (grep((!defined($New{$_}) && ($tmp = $_, !grep($tmp =~ m/$_/, @ignpat))), keys(%Clients)))
      {
	print "Current customers\n";
	print "-----------------\n";
	printf $sfmt, @lbl;
	grep( defined($New{$_}) || &listentry($_, $Clients{$_}, 1) , sort(keys(%Clients)) );
	print "\n";
      }

    if (grep(($tmp = $_, !grep($tmp =~ m/$_/, @ignpat)), keys(%Old)))
      {
	print "Discarded customers\n";
	print "-------------------\n";
	printf $sfmt, @lbl;
	grep( &listentry($_, $Old{$_}, 0) , sort(keys(%Old)) );
	print "\n";
      }

    dbmclose(Clients);

    print "\nSummary:\n";
    print "--------\n";
    printf("Elapsed time: %13s\n", &timedelta($maxtime));
    printf("       Hosts: %13d\n", $hostcnt);
    printf("     Packets: %13d\n", $packcnt);
    printf("        Rate: %13.2f\n", $packcnt / $maxtime) if $maxtime;
    print "\n";
  }
