! Filestore Port killing program (posher AutoChop)
! MDP April'84

begin 

include  "managr:nsdefs.inc"
include  "Inc:Fs.IMP"
include  "Inc:Util.IMP"
include  "managr:ns.inc"

own  string  (31) Sys Time = "",
                  Sys Date = ""

string  (2) fn  Hex 2(integer  xx)

   const  byte  array  Hex Sym (0 : 15) = c 
      '0', '1', '2', '3', '4', '5', '6', '7',
      '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
   string  (2) Frig = To String (Hex Sym ((Xx >> 4) & 15)) . c 
                      To String (Hex Sym (Xx & 15))

   result  = String (Addr (Frig))
end 

routine  Format(string  (255) Line)
   string  (80) This

   cycle 
      if  Length (Line) > 80 start 
         This = Sub String (Line, 1, 80)
         Line = Sub String (Line, 81, Length (Line))
      else 
         This = Line
         Line = ""
      finish 
      Print String (This)
      New Line if  Line # ""
   repeat  until  Line = ""
end 

routine  Announce(string  (80) What, integer  Count)

   Write (Count ,0)
   Space
   Print String (What)
   Print Symbol ('s') if  Count # 1
end 

integer  fn  Day Difference (string  (7) Lower, Upper)

   string  (2) Lo Hrs = Sub String (Lower, 1, 2),
               Lo Min = Sub String (Lower, 4, 5)
   string  (2) Hi Hrs = Sub String (Upper, 1, 2),
               Hi Min = Sub String (Upper, 4, 5)
   integer  Total

   if  Lo Hrs = Hi Hrs start 
      Total = StoI (Hi Min) - StoI (Lo Min)
   else 
      Total = 60 * (S to I (Hi Hrs) - S to I (Lo Hrs))
      Total = Total + (S to I (Hi Min) - S to I (Lo Min))
   finish 
   result  = Total
end 

integer  fn  Time Difference (string  (31) Time Rating)

   string  (15) Day
   string  (7)  Tim

   if  Time Rating -> Day .(" "). Tim start ; finish 
   Tim = Sub String (Tim, 2, Length (Tim)) while  Charno (Tim, 1) = ' '

   if  Sys Date = Day start 
      result  = Day Difference (Tim, Sys Time)
   else 
      result  = 24 * 60 - Day Difference (Sys Time, Tim)
   finish 
end 

integer  fn  Minimum Difference(string  (31) One, Two)

   integer  I One,
            I Two

   Sys Time = Time if  Sys Time = ""
   Sys Date = Date if  Sys Date = ""

   I One = Time Difference (One)
   I Two = Time Difference (Two)

   result  = I One if  I One < I Two
   result  = I Two
end 

record  format  User Fm (string  (6) User Name, Directory,
                         string  (21) Login Time,
                         byte  Uno, Pno, Flags, Location,
                         short  Difference)

routine  Get Unos From FS(record  (User Fm) array  name  Users (1 : *),
    integer  name  Number of Users,
    integer  name  Number of Internal Copies)   ;! -- for Users

   record  (User Fm) name  Element
   string  (19) User, Dir, Login
   string  (19) Read Time, Write Time
   string  (8) Today = Date
   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 

   routine  Read Date (string  (*) name  Dat, integer  name  Sym)

      Dat = To String (Sym)
      Read Rest of (Dat)
      Dat = Dat ." "
      Skip Spaces (Sym)
      Dat = Dat . To String (Sym)
      Read Rest of (Dat)
   end 

   on  9 start 
      -> End Load
   finish 

{ Print String ("In Get FS Unos..."); New Line
   Sys Time = Time
   Sys Date = Date

   Number of Users = 0
   Number of Internal Copies = 0
   Connect File ("$:UNOS",0,taddr,tlen)
{ Print String ("File connected at addr = "); PHex (taddr)
{ Print String (" to of len = "); PHex (TLen); New Line
   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 
         Number of Internal Copies = Number of Internal Copies + 1
         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)

      Skip Spaces (Sym)
      Login = To String (Sym)
      Read Rest of (Login)
      Skip Spaces (Sym)
      if  Login # Today then  Login = Login . " " . To String (Sym) c 
                        else  Login = To String (Sym)
      Read Rest of (Login)

      Skip Spaces (Sym)
      Read Date (Read Time, Sym)

      Skip Spaces (Sym)
      Read Date (Write Time, Sym)
      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
{ Print String ("Read user '".User."'");New Line
      Element_Directory  =  Dir
      Element_Login Time =  Login
      if  00<=id<=255 then  element_location=id else  c 
      Element_Location   =  255
      Element_Flags      =  Flag
      Element_Difference =  Minimum Difference (Read Time, Write Time)
   repeat 

End Load:
{ Print String ("Leaving Get FS Unos..."); New Line
   Sys Time = ""
   Sys Date = ""
end 

constant  string  (6) Free Location = "*Free*"

constant  integer  Vax Station 1 = 16_03,
                   Vax Station 2 = 16_72

record  format  Port Fm (string  (2) Local,
                         integer  Remote Id,
                         string  (2) Remote P,
                         integer  Difference)

record  (Port Fm) array  Ports (1:48)
integer  Number of Ports = 0
record  (User Fm) array  Users (1 : 48)
integer  Number of Users = 0

byte  integer  Local S  = L Dte,
               Local P  = L Sap,
               Remote S = R Dte,
               Remote P = R Sap,
               Host     = R Dte

routine  Chop
   byte  Four = 12

   Ether Write (FS Port, Four, 1)
   cycle 
   repeat  until  Ack&1 << FS Port # 0
end 

routine  Alias (integer  FS Station, FS Port No, APM Station, APM Port No)

   Ethc = 15
   T Wait
   Ethc = 7
   T Wait
   Ethd = APM Station
   T Wait
   Fsport = APM Port No
   Ether Open (FS Port, FS Station << 8 + FS Port No)
end 

string  (31) fn  Sleep State (integer  Minutes)
   const  string  (31) array  Comments (0:7) = c 
      "",             "beginning to yawn ",
      "drowsing ",    "dropping off ",
      "asleep ",      "snoring gently ",
      "fast asleep ", "dead to the world "

   Minutes = Minutes // 10
   Minutes = 0 if  Minutes < 0         ;! ???
   Minutes = 7 if  Minutes > 7
   result  = Comments (Minutes)
end 

Routine  Get Table From FS

   string  (80) Line
   string  (19) Read Time, Write Time
   string  (2) Loc P, Rem P, Temp I
   integer  Rem I
   record  (Port Fm) name  Port

   integer  fn  Hex Char (integer  Sym)

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

   on  9 start 
      -> End Load
   finish 

   Number of Ports = 0
   Open Input (1, "$:Ports")
   Select Input (1)

   cycle 
      Read Line (Line)

      Loc P = Sub String (Line, 2, 3)
      Temp I = Sub String (Line, 6, 7)
      Rem I = Hex Char (Charno (Temp I, 2))
      Rem I = 16 * Hex Char (Charno (Temp I, 1)) + Rem I if  Charno (Temp I, 1) # ' '
      Rem P = Sub String (Line, 9, 10)

      Read Time = Sub String (Line, 13, 26)
      Write Time = Sub String (Line, 29, 42)

      Number of Ports = Number of Ports + 1
      Port == Ports (Number of Ports)

      Port_Local      = Loc P
      Port_Remote Id  = Rem I
      Port_Remote P   = Rem P
      Port_Difference = 1{Minimum Difference (Read Time, Write Time)
   repeat 

End Load:
   Close Input
   Select Input (0)
end 

   record  (Port Fm) name  Port
   record  (User Fm) name  User
   string  (255) Temp Res, Res, Parm = CLI Param
   string  (7) Whos Using, S Pno
   record  (ns lfm) data
   integer  Number of Dead = 0
   integer  Pno, Uno, Len, Nic
   integer  P L, P R, Sym, i, j, xno

   Get Table From Fs
   Get Unos From Fs (Users, Number of Users, Nic)
   xno = open ns db

   for  Pno = 1,1, Number of Ports cycle 
      Port == Ports (Pno)
      Res = ""
      Res = Port_Local ." ".Hex2 (Port_Remote Id)." ".Port_Remote P." : "

      Whos using = Free Location

      for  Uno = 1, 1, Number of Users cycle 
         User == Users (Uno)
         if  User_Pno < 10 then  SPno = I To S (User_Pno, 1) c 
                           else  SPno = I To S (User_Pno, 0)

         if  Port_Local = S Pno start 
            Whos Using = User_User Name
            exit 
         finish 
      repeat 

      Whos Using = " " . Whos Using while  Length (Whos Using) < 6
      Res = Res . Whos Using . " " . Sleep State (Port_Difference)

      i = read ns db(xno, port_remote id!long, addr(data))
      if  i>=0 start 
         if  data_inon = 'I' start 
            res=res."   In "
         elseif  data_inon = 'O'
            res=res."   On "
         elseif  data_inon = 'A'
            res=res."   At "
         finish 

         res=res."the " if  data_room = 'T'

         for  j=31,-1,1 cycle ; exit  if  data_lname(j) > ' '; repeat 
         for  i=1,1,j cycle ; res=res.tostring(data_lname(i)); repeat 
         res=res."'s room" if  data_room = 'R'
      else 
        res=res."On a mythical machine "
      finish 

      Res = Res . " " while  Length (Res) < 74
      Res = Res . ":"
{      Print String (Res); newline
      Prompt (Res)
      Sym  = Test Symbol until  Sym = -1
      Read Symbol (Sym) until  Sym!' ' = 'n' or  Sym!' ' = 'y' or  Sym = Nl

      if  Sym ! ' ' = 'y' start 
         if  Whos Using # Free Location start 
            Prompt ("That terminal is occupied, Are you sure : ")
            P L  = Test Symbol until  P L = -1
            Read Symbol (Pl) until  Pl!' ' = 'n' or  Pl!' ' = 'y' or  Pl = Nl
         else 
            P L = 'y'
         finish 

         if  P L! ' ' = 'y' start 
            P L = S To I (Port_Local)
            P R = S To I (Port_Remote P)
            Alias (Host, P L, Port_Remote Id, P R)
            Chop
            Alias (Remote S, Remote P, Local S, Local P)
            Number of Dead = Number of Dead + 1
            Number of Users = Number of Users - 1 if  Whos Using # Free Location
         finish 
      finish 
       
      Read Symbol (Sym) while  Sym # Nl
   repeat 

   close ns db(xno)

   Announce ("port", Number of Ports)
   Print String (" allocated with ")
   Announce ("port", Number of Dead)
   Print String (" killed and ")
   Write (Number of Users, 0)
   Print String (" now left in use.")
   New Line
end  of  program