#/usr/local/bin/perl 

# process command line var settings
$idle = -1;
$dot = 60;
$colon = 10;
($me = $0) =~ s%.*/%%;
sub another { print stderr "Interrupted!\n"; exit 1;} 
$SIG{'INT'} = 'another';

eval '$'.$1.'$2;' while $ARGV[0] =~ /^([A-Za-z_]+=)(.*)/ && shift;

# parse switches
while ($ARGV[0] =~ /^-/) {      
    $ARGV[0] =~ /^-a/ && ($all++,shift,next);
    $ARGV[0] =~ /^-d/ && ($debug++,shift,next);
    $ARGV[0] =~ /^-n/ && ($idle = 0,shift,next);
    $ARGV[0] =~ /^-w/ && ($window++,shift,next);
    $ARGV[0] =~ /^-l/ && ($long++,shift,next);
    $ARGV[0] =~ /^-b/ && ($broadcast++,shift,next);
    $ARGV[0] =~ /^-m/ && ($multicast++,shift,next);
    $ARGV[0] =~ /^-s/ && ($slumber++,shift,next);
    $ARGV[0] =~ /^-i/ && (shift,$idle=$ARGV[0],shift,next);
    last;
}

$hosts && $multicast++;

if ($idle =~ /[:h]/) {
        $hours = $minutes = 0;
        ($hours = $idle)   =~ s/[:h].*$//;
        ($minutes = $idle) =~ s/.*[:h]//;
        $idle = $hours * 60 + $minutes;
        if ($debug) { print "you said $idle m idle\n"; }
} elsif ($idle < 0) {
    $idle = $dot;
} 

$sleep = 60 unless $sleep;
$idle = 999E10 if $all;

if ( $ARGV[0] =~ /^-/ ) {
    select (stderr);
    printf "usage: %s [vars] [-b | -m] [-a] [-n] [-l] [-w] [-s] [target ...]\n",
			$me;
    printf "\t-b to broadcast to the ruserd\n";
    printf "\t-m to multicast to the ruserd\n";
    printf "\t-a for ALL, even very idle people\n";
    printf "\t-n for people active NOW short idles\n";
    printf "\t-l for LONG listing\n";
    printf "\t-w to dynamically compute WINDOW size\n";
    printf "\t-s to sleep and repeat until all targets found\n";
    printf "\tvars \$idle ($idle) and \$sleep ($sleep) can be set with var=value\n";
    printf "\t     as can \$hosts, \$dot ($dot), and \$colon ($colon)\n";
    exit 1;
}

# compute width according to window size

$ENV{"TERMCAP"} =~ /:co#(\d+):/ && ($cols = int($1/25));

if ( $window ) {
    open(win,"(stty all > /dev/tty ) 2>&1 |") || die "can't run stty";
    while (<win>) {
        chop; split;
        $cols = int($_[7]/ 25);
        last;
    } 
    close win;
}

$cols = 3 unless $cols;

if ($multicast && !$hosts) {
    $machines = '/usr/adm/MACHINES';
    open machines || die "$me: can't open $machines: $!\n";
    open(saveout, ">&stdout"); # much cheaper than invoking sh
    close(stdout);

    while (<machines>) {
	next if /norpc/;
	chop;
	s/\s.*//;
	if (do ping($_)) { # no sh here!
	    #print stderr $_, " ok\n";
	    push(@hosts,$_); 
	} else {
	    #printf stderr "%s is down!\n", $_;
	} 
    } 
    open(stdout, ">&saveout");
    close machines;
    close saveout;
    $debug && print "hosts are: ", join(' ',@hosts),"\n";
} 

restart:

$count = $#ARGV + 1;

$PIPE = "/usr/ucb/rwho";
if ($broadcast || $multicast) {
    $PIPE = "/usr/ucb/rusers -l ";
    $multicast && $PIPE .= $hosts ? $hosts : join(' ',@hosts);
}
$PIPE .= "|sort|";
$debug && printf "PIPE is %s", $PIPE;
open PIPE || die "$me: can't popen \"$PIPE\": $!\n";

PIPEline: while (<PIPE>) {
    s/-ex0//;
    $matched = 0;
    if ( $count ) {
        matchcheck: for ( $i = 0; $i < $count; $i++ ) {
            $str = $ARGV[$i];
            $matched = /$str/;
            if ( $matched ) {
                if ($debug) { printf "YES: `%s' MATCH <%s>\n", $str, $_ ; }
                last matchcheck; # break
            } else { 
                if ($debug) { printf "NO: `%s' DIDN'T <%s>\n", $str, $_ ; }
            }
        }
        if ( ! $matched ) {
            next PIPEline;
        }
    }

    $_[5] = "";
    split; 

    $myidle = 0;
    if ( $_[5] =~ /^[:0-9]*$/  ) {
        $hours = $minutes = 0;
        if ( $_[5] =~ /[0-9]:/ ) {
            $hours = $_[5];
            $hours =~ s/:.*$//;
        }
        $minutes = $_[5];
        $minutes =~ s/^.*://;
        $myidle = $hours * 60 + $minutes;
    } 

    next PIPEline if $myidle > $idle;

    $found{$str}++ if ($slumber);

    if ( $long ) {
        print;
    } else {
        if ($debug) { printf "%s@%s is %d\n", $_[0],$_[1],$myidle; }
        if ($myidle < $dot && $myidle > $colon) {
            $_[1] =~ s/:/./;
        }  elsif ($myidle > $dot) {
            $_[1] =~ s/:/ /;
        } 
        push(users,sprintf("%-9s%15s", $_[0], $_[1]));
    }
}
exit if $long && ! $slumber;

$rows = int(($#users+$cols) / $cols);

# { printf "found %d matches\n", $#users+1; }
# { printf "rows are %s, cols are %s\n", $rows, $cols; }

if ($slumber && $restarted && $#users >= $[) {
	printf "\n%s: bingo! at %s%c\n", $me, `date`, 7;
} 

for ($elt = 0; $elt < $rows * $cols; $elt++) {
    $targ =  ($elt%$cols) * $rows + int(($elt/$cols));
    printf "%s ", $targ < ($#users+1) ? $users[$targ] : "";
    #if ($debug) { #printf "%d ", $targ < ($#users+1) ? $targ : -1; }
    
    print "\n" if (($elt+1) % $cols) == 0;
}

print "\n" if ($elt+1) % $cols == 0;

close PIPE;

if ($slumber) {
	@nargv = ();
	@users = ();
	for ($i = 0; $i < $count; $i++) {
		! $found{$ARGV[$i]} && push(@nargv,$ARGV[$i]); 
	} 
	@ARGV = @nargv;

	if ($#ARGV >= $[) {
	    exit if ($forked++ == 0 && fork);
	    sleep $sleep;
	    $restarted = 1;
	    ($whoami = `who am i`) =~ s/.*!([^ ]*).*/$1/;
	    exit if $whoami != $ENV{"USER"};
	    goto restart;
	}
} 


sub ping {
    local($host) = @_;

    if (fork) {
	wait;
	exit if $? & 0xff; # interrupted  
	return $? == 0;
    }  else {
	exec 'pong', $host, 1;
    } 
} 
