! Process killing program
! 1. allows users to delete their own processes which are stuck
! 2. allows priviliged users to delete anyone...
!
! MDP Feb'84    JHB Dec '85
! 
! Command sent to filestore :
! 
! Form : ]<uno><selector>,<uno/xno/pno of victim>
! *** Where selector = 1 for kill UNO
! ***                = 2 for kill XNO
! ***                = 3 for kill PORT

%include "Inc:Util.Imp"
%include "Inc:Fs.Imp"
%include "inc:fsutil.imp"
%include "managr:nsdefs.inc"
%include "managr:ns.inc"
!*** useful:whodat stuff
!The following routine etc. came from USEFUL:WHODAT/WHODAT2 and has been
!chopped down to minimise dependencies.

%record %format User Fm (%string (6) User Name, Directory,
                         %byte Uno, Pno, Flags, Location)

%routine Get Unos From FS(%record (User Fm) %array %name Users (1 : *),
    %integer %name Number of Users)

   %record (User Fm) %name Element
   %string (19) User, Dir
   %integer Id, Sym, Flag, Uno, Pno
   %integer nl flag = 0
   %integer tptr,tlen,taddr

   %routine Read Sym (%integer %name sym)

      %signal 9 %if tptr = taddr+tlen
      sym = byteinteger(tptr)
      tptr = tptr+1
   %end
         
   %routine Skip Symbol
      %integer sym

      read sym (sym)
   %end

   %integer %fn Hex Sym (%integer Sym)

      %result = Sym - '0' %if '0' <= Sym <= '9'
      %result = Sym - 'A' + 10
   %end

   %routine Read Rest of (%string (19) %name What)

      %integer Sym

      %cycle
         Read Sym (Sym)
         nl flag = 1 %and Sym = ' ' %if sym = nl
         %exit %if Sym = ' '
         What = What . To String (Sym)
      %repeat
   %end

   %routine Skip Spaces (%integer %name Sym)

      Sym = ' '
      Read Sym (Sym) %while Sym = ' '
   %end

   %on 9 %start
      -> End Load
   %finish

   Number of Users = 0
   Connect File ("$:UNOS",0,taddr,tlen)
   tptr = taddr
   
   Read Sym (Sym) %until Sym = Nl      ;! skip ANON

! 6  -2           pub     pub  ---login------  -----read-----  -----write----
   %cycle
      Flag = 0
      Skip Symbol                      ;! leading space

      ! -- Uno

      Read Sym (Sym)
      Read Sym (Uno)
      %if Sym # ' ' %then Uno = 10 * (Sym - '0') + (Uno - '0') %c
                    %else Uno = Uno - '0'

      ! -- 2 Spaces

      Skip Symbol
      Skip Symbol

      ! -- Port Number

      Read Sym (Sym)
      %if Sym = '-' %start
         Read Sym (Sym) %until Sym = Nl
         %continue
      %finish

      Read Sym (Pno)
      %if Sym # ' ' %then Pno = 10 * (Sym - '0') + (Pno - '0') %c
                    %else Pno = Pno - '0'

      ! -- 2 Spaces

      Skip Symbol
      Skip Symbol

      ! -- Terminal Address

      Read Sym (Sym)
      Read Sym (Id)
      Id = 16 * Hex Sym (Sym) + Hex Sym (Id)

      ! -- 3 Spaces

      Skip Symbol %for Sym = 1, 1, 3      ;! skip upto spaces before user name

      ! -- Username

      Skip Spaces (Sym)
      User = To String (Sym)
      Read Rest of (User)

      %if Charno (User, Length (User)) = '!' %start
         Flag = 1
         Length (User) = Length (User) - 1
      %finish

      Skip Spaces (Sym)
      Dir = To String (Sym)
      Read Rest of (Dir)
      %if nl flag = 0 %start
         Read Sym (Sym) %until Sym = Nl
      %finish

      Number of Users    =  Number of Users + 1
      Element            == Users (Number of Users)
      Element_Uno        =  Uno
      Element_Pno        =  Pno
      Element_User Name  =  User
      Element_Directory  =  Dir
      Element_Location   =  Id
      Element_Flags      =  Flag
   %repeat

End Load:
%end

!*** end of whodat stuff ***


! "High-density" hex.  Usually just "normal" hex, except that
! the high order hexit isn't forced to be modulo 16, and the
! sequence goes ...8, 9, :, ;, .... rather than the more
! normal ...8, 9, A, B, ....

%string(2)%fn hdx2(%integer i)
   ! two hexit version
   %result = tostring(i >> 4 + '0') . tostring(i & 15 + '0')
%end

%begin

   %record (User Fm) %array Users (1 : 50)
   %record (User Fm) %name Me, User

   %string (80) I Am = CLI Param
   %integer Number of Users = 0
   %integer Index, Ptr 1, Ptr 2, This Person
   %integer xno

   %routine Try to Kill User (%record (User Fm) %name User)

      %string (80) Line
      %integer I

      %on 3, 4, 9 %start
         ! Print String ("Event : ")
         ! Write (Event_Event,2);Write (Event_Sub, 3)
         ! Write (Event_Extra, 3); Space
         Print String (Event_Message)
         New Line
         %return
      %finish

      %cycle
         Print String (User_User Name)
         printstring(" (uno")
         Write (User_Uno, 2)
         printstring(") on port ")
         PHex 2 (User_Pno)
         printstring(" from ")
         PHex 2 (User_Location)
         Print String (" (")
         printstring(fs lname(user_location))
         printstring(") ")

         Print String (" (you)") %if User_User Name = I Am %c
                                %and User_Uno       = UserNo %c
                                %and User_Location  = Ether Station
         Space
         Read Line (Line)
         %return %if Line = ""
         toupper(Line)
         %return %if 'K' # Charno (Line, 1) # 'Y'
         %if Me_Flags # 0 %and User_User Name # I Am %start
            Print Line ("Privileged users type 'KILL' or 'YES' to kill other processes")%c
               %and %continue %if "KILL" # Line # "YES"
         %finish
         Line = "1," . Hdx2 (User_Uno)
         I = FComm (']'<<8 + UserNo + '0', Line)
         %exit
      %repeat
   %end
   
   I Am = Current User
   %if I Am = "" %start
      Print String ("SUICIDE can only be used when logged on, you aren't.")
      New Line
      %stop
   %finish

   Get Unos from FS (Users, Number of Users)

   This Person = 0

   %for Index = 1,1,Number of Users %cycle
      User == Users (Index)
      %if User_Uno = UserNo %start
         %if This Person # 0 %start
            Print Line ("There is more than one of 'YOU' logged onto this terminal, will take")
            Print Line ("the first one as 'YOU'.")
            %exit
         %else
            This Person = Index
         %finish
      %finish
   %repeat

   %if This Person = 0 %start
      Print line ("This Person = 0 : Catastrophic Error...Tell 'USEFUL'")
      %stop
   %finish

   Me == Users (This Person)
   %if Me_Uno # UserNo %start
      Print line ("Me_Uno # UserNo, Tell USEFUL.....")
      %stop
   %finish

   %if Me_Flags = 0 %start                          ;! non privileged
      Ptr 1 = 1
      Ptr 2 = 1                                     ;! so remove dross
      %while Ptr 1 <= Number of Users %cycle
         User == Users (Ptr 1)
         %if User_User Name = I Am %start
            Users (Ptr 2) = User
            Ptr 2 = Ptr 2 + 1
         %finish
         Ptr 1 = Ptr 1 + 1
      %repeat

      Number of Users = Ptr 2 - 1
   %finish

   xno=open ns db
   %for Index = 1,1,Number of Users %cycle
      Try to Kill User (Users (Index))
   %repeat
   close ns db(xno)
%end %of %program
