(* [CSC60]NTV:<SYS-SOURCES>SNIFF.PAS.8, 15-May-86 17:05:43, Edit by FORDYCE *)
(* 3(2) Added compile-time option to not include IDLE command availability *)
(*       and to default to no idle time                                    *)

(* <FORDYCE.WORK>SNIFF.PAS.15, 15-Nov-84 14:15:03, Edit by FORDYCE  *)
(* 3(1) Added "IDLE n" option, where only jobs idle for longer than *)
(*       n minutes will be logged out.                              *)

(*$V:300000002B*)

(* <FORDYCE.WORK>SNIFF.PAS.5, 18-Sep-84 13:27:06, Edit by FORDYCE     *)
(* 3(0) Converted kludgey logic to using Rutgers' CMINIR, and related *)
(*       routines                                                     *)
(*      Rewrite ASK_TTY and YESNO routines to use COMND jsys          *)

(* <FORDYCE.WORK>SNIFF.PAS.2, 18-Sep-84 10:05:57, Edit by FORDYCE *)
(* 2(1) Added 'DET' option - functions similarly to 'ALL' option, *)
(*       except that only detached jobs are 'sniffed'.            *)
(*      Removed extraneous INCLUDE statements                     *)

(* <STALL.1>SNIFF.PAS.2 22-Sep-81 10:32:38, Edit by FORDYCE *)
               (* Added 'NIL' option - see edit history below *)

PROGRAM SNIFF ;

(* * * * * * * * * * * * * * * * * * * * * * * * * * *)
(*                                                   *)
(* Written by   David Fordyce           20-Feb-81    *)
(*              Texas Instruments, Inc.              *)
(*              Computer Science Laboratory          *)
(*              Central Research Laboratories        *)
(*              P.O. Box 226015 ; M/S 238            *)
(*              Dallas, Texas 75266                  *)
(*              (214) 995-0375                       *)
(*                                                   *)
(* Edit History:                                     *) 
(*                                                   *)
(* 11-May-81    by  David Fordyce                    *)
(*              Prevent the user from logging-out or *)
(*              attaching to a batch job             *)
(*                                                   *)
(* 22-Sept-81   by  David Fordyce                    *)
(*              Add the 'nil' option to only display *)
(*              other jobs (if any) without asking   *)
(*              the user what he wants to do.  This  *)
(*              feature complements the EXEC's       *)
(*              prompting you with one of your       *)
(*              detached jobs, allowing you to enter *)
(*              a job # or 'NEW-JOB'.                *)
(* * * * * * * * * * * * * * * * * * * * * * * * * * *)

Include 'pas:extern.pas' ;

{ *** Set USEIDLE <>0 if you have the IDLE jsys installed *** }
Const
  UseIdle = 0;

Type
 STRING = PACKED ARRAY[1..80] of CHAR ;
 STR    = ARRAY[1..6] of CHAR ;
 ST     = PACKED ARRAY[1..3] of CHAR ;
 ALFA   = PACKED ARRAY[1..10] of CHAR ;

Var
 Emode  : Cmmodes ;

 I:INTEGER ;
 Jobnum:ARRAY[1..128] of INTEGER ;   (* Job number *)
 Trmnum:ARRAY[1..128] of INTEGER ;   (* Job's terminal number *)
                                     (* -1 means DETached *)
 Usrnum:ARRAY[1..128] of INTEGER ;   (* Job's user number *)
 Cdrnum:ARRAY[1..128] of INTEGER ;   (* Job's connected directory
				         number *)
 Subsys:ARRAY[1..128] of ALFA ;      (* Subsystem name *)
 Pgmnam:ARRAY[1..128] of ALFA ;      (* Program name *)
 IdlTim:ARRAY[1..128] of INTEGER ;   (* Job idle time *)

Jbinfo:PACKED RECORD                 (* Argument block for GETJI *)
 Jijno:INTEGER ;		     (* Job number *)
 Jitno:INTEGER ;		     (* Job's terminal number *)
 Jiuno:INTEGER ;		     (* Job's user number *)
 Jidno:INTEGER ;		     (* Job's connected
				        directory number *)
 Jisnm:INTEGER ;		     (* Subsystem name (sixbit ) *)
 Jipnm:INTEGER ;		     (* Program name (sixbit) *)
 Jirt :INTEGER ;                     (* Run time *)
 Jicpj:INTEGER ;                     (* Controlling PTY job number, or -1
                                        if no PTY *)
 Jirtl:INTEGER ;                     (* Run time limit *)
 Jibat:INTEGER ;                     (* -1 if controlled by batch *)
 END ;

Myuser:INTEGER ;
Mydrno:INTEGER ;
Myjbno:INTEGER ;
Myterm:INTEGER ;

Jobcnt:INTEGER ;

Frmarg:ALFA ;

RscnP:  BOOLEAN ;
Showonly:BOOLEAN ;

Text:ST ;

Xwd:PACKED RECORD CASE BOOLEAN OF
         TRUE:(full:INTEGER) ;
         FALSE:(lh:0..777777B;rh:0..777777B)
         END ;

Comtable:TABLE ;

Cmdtab  :TABLE ;
 Cmdopt :INTEGER ;

YNtab   :TABLE ;

IdlDef, IdlLim : INTEGER ;  (* For sniffing IDLE jobs *)


PROCEDURE CMDINI ;

BEGIN

 Comtable := Tbmak(1) ;
 Tbadd(Comtable,1,'sniff',0) ;

 Cmdtab := tbmak(4) ;
 Tbadd(Cmdtab,1,'all',0) ;
 Tbadd(Cmdtab,2,'detached',0) ;
 if UseIdle <> 0
  then
   Tbadd(Cmdtab,3,'idle',0) ;
 Tbadd(Cmdtab,4,'nil',0) ;

 YNtab := Tbmak(2) ;
 Tbadd(YNtab,0,'no',0) ;
 Tbadd(YNtab,1,'yes',0) ;

END ;


PROCEDURE DO_IT ;

Var I,ret:INTEGER ;
    
BEGIN

FOR I := 1 to 128 DO
  IF Jobnum[I] <> 0
   THEN
    begin
    If IdlLim = 0
     Then
      IF (Jobnum[I] <> Myjbno)
       Then
        Jsys(lgout,1,ret;Jobnum[I]) ;
    If IdlLim <> 0
     Then
      If (Jobnum[I] <> Myjbno) AND (IdlTim[I] >= IdlLim)
       Then
        Jsys(lgout,1,ret;Jobnum[I]) ;
    end ;

END ;


PROCEDURE DO_DET ;

Var I,ret:INTEGER ;
    
BEGIN

FOR I := 1 to 128 DO
  IF Jobnum[I] <> 0
   THEN
    IF (Jobnum[I] <> Myjbno) and (Trmnum[I] = -1)
     THEN
      Begin
       Jsys(lgout,1,ret;Jobnum[I]) ;
       WRITELN(tty,' [Job # ',Jobnum[I]:2,' running ',Pgmnam[I]:7,' (Det) Logged Out]') ;
      End ;

END ;


PROCEDURE SUICIDE ;

Var Lgojfn, LgoHandle, ret : INTEGER ;

BEGIN

 Reset(output,'sys:ljob.exe') ;
 Lgojfn := Curjfn(output) ;
 Close(output) ;
 Jsys(cfork,2,ret;200000000000B,0;LgoHandle) ;  (* CFORK *)
 IF ret = 1 THEN WRITE(tty,' CFORK Failed ') ;
 Jsys(gget,1,ret;LgoHandle:Lgojfn) ; (* GET *)
 Jsys(sfrkv;LgoHandle,0) ; (* SFRKV *)

END ;


PROCEDURE GET_DATA ;

VAR I,J,K,ret,result1 : INTEGER ;
    IdlRet : INTEGER ;

BEGIN

WITH Jbinfo DO
  FOR I := 1 to 128 DO
   BEGIN
    ret := 0 ;                          (* Zero out return indicator *)
    if UseIdle <> 0
     then
      Jsys(Idle,-1,Idlret;I;IdlTim[I])  (* Get idle time in milliseconds *)
     else
      IdlTim[I] := 0 ;                  (* default to no idle time *)
    Jsys(getji,-2,ret;I,-10:Jbinfo,0) ;
    (* get information for job specified by I *)
    IF ret > 2 
     THEN Jobnum[I] := 0                (* either a bad return from getji *)
    ELSE	    
     IF Myuser <> Jiuno  
      THEN Jobnum[I] := 0               (* or the job in question does not *)
         	                        (*  belong to this logged in user *)
     ELSE
      IF Jibat <> -1                    (* only let the user know of non-batch
                                           jobs *)
       THEN
       BEGIN 
        Jobnum[I] := Jijno ;
        Trmnum[I] := Jitno ;
        Usrnum[I] := Jiuno ;
        Cdrnum[I] := Jidno ;
        K := Jisnm ;
        FROM6(K,Frmarg) ;	
        Subsys[I] := Frmarg ;
        K := Jipnm ;
        FROM6(K,Frmarg) ;       
        Pgmnam[I] := Frmarg ;
        Jobcnt := Jobcnt + 1 
       END ; (* begin (if) *)
   END ; (* begin (for) *)
END ; (* procedure *)


PROCEDURE MY_DATA ;

VAR ret : INTEGER ;

BEGIN
 Jsys(gjinf,1,ret;;Myuser,Mydrno,Myjbno,Myterm) ;
END ;


PROCEDURE TELL_TTY ;

VAR I, Ret :INTEGER ;

BEGIN
WRITELN(tty,' You have the following jobs: ') ;

FOR I := 1 TO 128 DO
 IF Jobnum[I] <> 0
  THEN
   IF Trmnum[I] = -1
    THEN
     WRITELN(tty,'  Job # ',Jobnum[I]:2,' running ',Pgmnam[I]:7,' (detached)') 
    ELSE
     BEGIN
      IF Trmnum[I] = Myterm
       THEN
        WRITELN(tty,'  Job # ',Jobnum[I]:2,' running ',Pgmnam[I]:7,' (current job)') 
       ELSE
        BEGIN
        WRITE(tty,'  Job # ',Jobnum[I]:2,' running ',Pgmnam[I]:7,' (on TTY');
        Jsys(Nout,1,Ret;101B,Trmnum[I],8) ;
	WRITELN(tty,':)') ;
        END ;
     END ;

END ;


FUNCTION YESNO:BOOLEAN ;

var ans : integer ;

BEGIN

ans := cmkey(yntab) ;
cmcfm ;

case ans of
 0 : yesno := false ;
 1 : yesno := true ;
 end ;

END ;


PROCEDURE ASK_TTY ;

VAR I,Bp,ret,result1 : INTEGER ;
    Prmpt            : STRING ;


BEGIN                          (* 1 *)
 I := 1 ;                      (* initialize loop counter *)
 loop
 exit if Jobcnt = 1 ;          (* only let the user attach to one *)
                               (*  job to refrain from pestering  *)
                               (*  the user with more questions   *)

 IF Jobnum[I] <> 0
  THEN
   IF Jobnum[I] <> Myjbno
    THEN
     BEGIN   (* see what user wants to do *)
      Jsys(Sout;-1:Prmpt,-1:' Do you want to attach to job # ',32,0;BP) ;
      Jsys(Nout,1,Ret;BP,Jobnum[I],10;BP) ;
      Jsys(Sout;BP,-1:' ? ',3,0;BP) ;
      Jsys(Bout;BP,chr(00)) ;
      Cmini(Prmpt) ;
      IF Yesno
       THEN 
        BEGIN  (* do attach *)
         WRITELN(tty,' [Job # ',Myjbno:2,' logged out]') ;         
         Jsys(atach,1,ret;Jobnum[I],Myuser,0,0;result1) ;
         Jsys(Lgout,1,Ret;-1) ;
         Jobnum[Myjbno] := 0 ;
         Myjbno := Jobnum[I] ;
         Jobcnt := Jobcnt - 1 ;
        END   (* do attach *)
      ELSE
       BEGIN  (* ask about logout *)
        Jsys(Sout;-1:Prmpt,-1:' Do you want to log out job # ',30,0;BP) ;
        Jsys(Nout,1,Ret;BP,Jobnum[I],10;BP) ;
        Jsys(Sout;BP,-1:' ? ',3,0;BP) ;
        Jsys(Bout;BP,chr(00)) ;
        Cmini(Prmpt) ;
        IF Yesno
         THEN
          BEGIN   (* do logout *)
 	  Jsys(lgout,1,ret;Jobnum[I]) ;
           IF ret = 1 THEN WRITELN(tty,' [Job # ',Jobnum[I]:2,' not logged out]') ;
           IF ret = 2 THEN WRITELN(tty,' [Job # ',Jobnum[I]:2,' logged out]') ;
           Jobcnt := Jobcnt - 1 ;
          END   (* do logout *)
        ELSE
	 Jobcnt := Jobcnt - 1 ;
      END ;   (* ask about logout *)
     END ;  (* see what user wants to do *)

IF I = 128
 THEN
  I := 1 
 ELSE
  I := I + 1 
end   (* loop *)
END ; (* 1 *)


BEGIN                     (* 1 *)
reset(tty,'',true,0,0,5); (* map lower case, handle data errors *) 

Showonly := FALSE ;       (* unless otherwise noted, ask user what job he
                             wants to attach to *)
Jobcnt := 0 ;             (* initialize count of the number of this *)
			  (*  user's jobs *)
IdlDef := 0 ;             (* No idle time by default *)
IdlLim := Idldef ;

CMDINI ;		  (* Initialize TBLUK tables *)

MY_DATA ;
GET_DATA ;

  Cminir('') ;
  Emode := Cmmode ;
  IF Emode = Rescan
   THEN
    Cmdopt := Cmkey(Cmdtab)
   ELSE
    Cmdopt := 0 ;

CASE Cmdopt OF
 0 : Jfcl ; (* No Rescan Command *)
 1 : begin (* ALL *)
      Cmcfm ;
      DO_IT ;
      Jobcnt := 0 ;          (* reset this counter to indicate that all
                              *  of the other jobs have already been
                              *  disposed of *)
     end ;
 2 : begin (* DETACHED *)
      Cmcfm ;
      DO_DET ;
      Jobcnt := 0 ;          (* reset this counter to indicate that all
                              *  of the other jobs have already been
                              *  disposed of *)
     end ;
 3 : begin
      IdlLim := Cmnum ;
      Cmcfm ;
      IdlLim := IdlLim * 60 * 1000 ;   (* need value in milliseconds *)
      DO_IT ;                (* use same code as "ALL", except for idle time *)
      Jobcnt := 0 ;
     end;
 4 : begin (* NIL *)
      Cmcfm ;
      Showonly := TRUE ;    (* set this so that other jobs for this
                             *  user will be listed, but the user
                             *  won't be asked any questions *)
     end ;
 END ; (* case *)

IF Jobcnt > 1
 THEN 
  BEGIN      (* 2 *)
   TELL_TTY ;
   IF NOT Showonly
    THEN   
     ASK_TTY 
  END ;      (* 2 *)

END.   (* 1 *)
