PROGRAM SYSMON
LastUpdated... = "Rev: 22:34 02Sep1998 andrew 6 /roi/andrew/BP/SYSTEM.MONITOR"
***
* Copyright (C) 2000, Andrew McLaughlin.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
* or http://www.fsf.org/copyleft/gpl.html
*
*   Enjoy, Andrew McLaughlin - andrew@mclaughlin.orange.ca.us
*** 
* Abstract:
*    This program will scan the system to display a list a resources in
* use.
*
***
* Revision Log
* Proj Who... When.... Why..............................................
*      u2443  01May94  Initial coding.
* 002  andrew 02May97  Enhance to use UniData locking facility.
*      andrew 08May97  Enhance to recognize screen size via "stty -a".
*
***

$INSERT UPCASE.EQUATES

pcperform "hostname" capturing HostName
del HostName<2>
pcperform "whoami" capturing UnixUser                                ;* Get underlying user name
del UnixUser<2>
God = UnixUser eq "root"
God = 1

crt "[SYSTEM.MONITOR v1.2 (c) 1994, Andrew McLaughlin. All rights reserved.]"
crt "Host: ":HostName
sleep 1

OpenErrors = ""
open "LOCK.FILE"     to LockFile      else OpenErrors := " the LOCK.FILE"
open "PORT.CMDS"     to PortCmdsFile  else OpenErrors := " the PORT.CMDS"
open "SYS.LOCK.FILE" to SysLockFile   else OpenErrors := " the SYS.LOCK.FILE"
open "SYS.USER"      to SysUserFile   else OpenErrors := " SYS.USER"
*open "SYSMON.LOG"    to SysMonLogFile else OpenErrors := " the SYSMON.LOG"
open "TERM.CTL"      to TermCtlFile   else OpenErrors := " TERM.CTL"
if OpenErrors then
   stop "Unable to open the following files:":OpenErrors
end

*$INCLUDE FDEF LOCK.FILE.FDEF
*$INCLUDE FDEF SYSMON.LOG.FDEF

*** Link into Manage-2000 common block and TERM.CTL file.
$INCLUDE STANDARD.COMMON.VARIABLES FROM COPY.TOOLS.BP
$INCLUDE STANDARD.COMMON.APP.PROGRAMS FROM COPY.TOOLS.BP
$INCLUDE STANDARD.VARIABLES.END FROM COPY.TOOLS.BP
PGM.NAME='SYSTEM.MONITOR'; FN.NAME ='SYSTEM.MONITOR';PGM.VER.NBR = '6.0C'
if @WHO[5] eq ".MAIN"  or @WHO[6] eq ".TRAIN" then
   CALL IO.OPEN('IO.OPEN.OPTS',PASSWORDS)
end else
   crt "IO.OPEN reference avoided in non ROI account..."
   sleep 1
end
***

dummy       = dummy                                                  ;* To avoid the underutilized warnings
DMY         = DMY                                                    ;* To avoid the underutilized warnings
DUMMY       = DUMMY                                                  ;* To avoid the underutilized warnings
TODAY       = TODAY                                                  ;* To avoid the underutilized warnings
PGM.VER.NBR = PGM.VER.NBR                                            ;* To avoid the underutilized warnings
RPT.TITLE   = RPT.TITLE                                              ;* To avoid the underutilized warnings

FifteenMinutes = iconv("00:15","MT")
ThirtyMinutes = iconv("00:30","MT")
DIM CURRENT.IDS(255)
prompt ""

ReDisplay       = 0
MAT CURRENT.IDS = ''
LOGGING.OUT     = ''
SCREEN.BUFFER   = ''
IF @(0,0) THEN NULL
UserElementSize = 26
PageUser        = 0
PageLock        = 0
PagePrint       = 0
PageSpool       = 0
NewPage = ""
SaveDisplayMode = ""
input Keypress,-1
if Keypress then
   input DisplayMode,1
   DisplayMode = upcase(DisplayMode)
   SaveDisplayMode = if God then "U" else "P"
end else
   DisplayMode     = if God then "U" else "P"
end
InfoMode        = 0
WhoMode         = 0
HostMode        = 0
Esc             = char(27)
loop
   crt @(0,0)
   gosub GetRowsCols
   begin case
      case DisplayMode eq "G" and God
         crt @(-1)
         pcperform "glance"
         DisplayMode = SaveDisplayMode
         ReDisplay = 1
      case DisplayMode eq "S"
         gosub DisplaySpoolers
      case DisplayMode eq "U" and God
         gosub DisplayUsers
      case DisplayMode eq "L" and God
         gosub DisplayLocks
      case DisplayMode eq "P"
         gosub DisplayPrintJobs
      case DisplayMode eq "Q"
      case DisplayMode eq "W"
         DisplayMode = SaveDisplayMode
         WhoMode = not(WhoMode)
         HostMode = 0
      case DisplayMode eq "H" and God
         gosub GetWhoList
         DisplayMode = SaveDisplayMode
         HostMode = not(HostMode)
         WhoMode = 0
      case 1
         Msg = "Invalid character selected: '":DisplayMode:"'. Enter '?' for help.":@SYS.BELL
         gosub StdMsg
         DisplayMode = SaveDisplayMode
   end CASE
   SaveDisplayMode = DisplayMode
   NewPage = ""
until DisplayMode eq "Q"
   input Char,1: for 2 else continue
   if Char[1,1] then DisplayMode = upcase(Char)

   begin case
      case DisplayMode eq "I"                                        ;*Info Mode?
         InfoMode = 1
         DisplayMode = SaveDisplayMode
      case DisplayMode eq "?"
         gosub Help
      case num(DisplayMode) and DisplayMode ne ""
         if DisplayMode ge 1 and DisplayMode le 9 then
            NewPage = DisplayMode
         end else
            crt @SYS.BELL:
         end
         DisplayMode = SaveDisplayMode
   end CASE
repeat
crt @(-1)
return


Help:
crt @(-1):
crt "SYSTEM.MONITOR   v1.2      (c) 1994 Andrew McLaughlin. All rights reserved."
crt
crt " Inter-modal commands:"
crt "     ? - Displays this help."
crt "     G - GlancePlus (tm) gateway."
crt "     L - To display current system locks."
crt "     P - To display current system print jobs."
crt "     Q - To exit SYSTEM.MONITOR."
crt "     S - To display current system spoolers."
crt "     U - To display current system users. (The default mode)."
crt
crt " Intra-modal commands:"
crt "     # - Switch to page #. (1 thru 9, where applicable)"
crt "     I - To inspect items that are being displayed. Options:"
crt "         D  - Delete selected item."
crt "         N  - Go to the next item."
crt "         P  - Go to the previoud item."
crt "         Q  - To return to the previous mode."
crt "         V  - Display details about selected item."
crt "         ## - Switch to item ##. (range on screen only, for indexed items)."
crt "     W - Change name column to show Owner name."
crt
crt @(5,ScreenRows-1):space(30):"Press any key to return...":
input Char,1:
DisplayMode = SaveDisplayMode                                        ;* Reset to last display mode
SaveDisplayMode = ""                                                 ;* Force a reset.
return


DisplayUsers:
if NewPage ne "" then
   PageUser = NewPage - 1
   ReDisplay = 1
end
if SaveDisplayMode ne DisplayMode or ReDisplay then
   ReDisplay = 0
   MAT CURRENT.IDS = ""
   GOSUB PAINT.NUMBERS
   GOSUB CALL.FINDIU
   GOSUB UPDATE.SCREEN
   UserNumber  = @UDTNO
   PRINT.DATA = '*':CURRENT.IDS(@UDTNO)
   GOSUB PRINT.TO.SCREEN
   GOSUB FLUSH.TO.SCREEN
end
UserNumber = @UDTNO
PRINT.DATA = ' ':CURRENT.IDS(@UDTNO)
GOSUB PRINT.TO.SCREEN
GOSUB FLUSH.TO.SCREEN
GOSUB CALL.FINDIU
GOSUB UPDATE.SCREEN
UserNumber = @UDTNO
PRINT.DATA = '*':CURRENT.IDS(@UDTNO)
GOSUB PRINT.TO.SCREEN
GOSUB FLUSH.TO.SCREEN
if InfoMode then
   gosub InfoUser
end
return


InfoUser:
ThisUser = 1
Seek = ""
loop
   RelUser = mod(ThisUser-1,MaxUser)
   Col = UserElementSize * int(RelUser / ScreenRows)
   Row = mod(RelUser, ScreenRows)
   crt @(Col,Row):"->":
   gosub InfoInput
until Char eq "Q" do
   crt @(Col,Row):B4.S:ThisUser "'0'R#2 ":AFT.S:
   begin case
      case Char eq "N"
         ThisUser = if ThisUser ge LastUser then LastUser else ThisUser + 1
      case Char eq "P"
         ThisUser = if ThisUser le FirstUser then FirstUser else ThisUser - 1
      case Char eq "D"
         locate ThisUser in NUMS<1> setting Idx else
            crt @SYS.BELL:
            continue
         end
         pcperform "deleteuser ":PIDS<Idx>
         Event = "User logged out: ":CURRENT.IDS(ThisUser)
*         gosub RecordEvent
         crt @(Col+3,Row):"Logged out..." "L#23":
         ReDisplay = 1
      case Char eq "M"
         crt @((ScreenCols-1),BottomOfScreen):"Enter message: ":
         input Message
         execute "message !":ThisUser:" ":Message
         ReDisplay = 1
      case Char eq "?"
         gosub Help
      case num(Char)
         Seek := Char
         if len(Seek) ge 2 then
            ThisUser = Seek + 0
            Seek = ""
         end else
            Tens = ((FirstUser+1) "'0'R#3")[2,1]
            if Seek eq Tens then
               ThisUser = (FirstUser+1)[2]
            end else
               ThisUser = Seek:"0"
            end
            if ThisUser lt (FirstUser+1)[2] then
               ThisUser += (((FirstUser+1) "'0'R#3")[1,1] + 1):"00"
            end else
               ThisUser += ((FirstUser+1) "'0'R#3")[1,1]:"00"
            end
            Seek = (ThisUser "'0'R#3")[1,2]
         end
         if ThisUser gt LastUser+1 then ThisUser = LastUser+1
         if ThisUser lt FirstUser+1 then ThisUser = FirstUser+1
      case 1
         crt @SYS.BELL:
   end CASE
repeat
crt @(Col,Row):ThisUser "'0'R#2 ":
InfoMode = 0
mat CURRENT.IDS = ""
return



DisplayLocks:
if NewPage ne "" then
   PageLock = NewPage - 1
   ReDisplay = 1
end
if SaveDisplayMode ne DisplayMode or ReDisplay then
   ReDisplay = 0
   crt @(-1)
   crt @(0,0):B4.S:"SYSTEM.MONITOR         Current System Locks     Page ":PageLock+1:AFT.S:
   PL = @(5,2):B4.S:"FileName-RecordName" "'.'L#25 "
   PL := "Port" "R#4 "
   PL := "Function" "'.'L#15 "
   PL := "User......" "R#10 "
   PL := "Since":AFT.S
   PL := @(5,BottomOfScreen-1):(if WhoMode then "Who" else ""):(if HostMode then "Host" else "")
   crt PL:
end
execute "LIST.READU ALL" capturing LockList
del LockList<1>                                                                                                                     ;*[002]
LockCount = dcount(LockList,@FM)                                                                                                    ;*[002]
Locks = B4.S
if LockCount lt 1 then
   Locks := "No"
end else
   Locks := @SYSTEM.RETURN.CODE
end
if LockCount eq 1 then
   Locks := " Lock"
end else
   Locks := " Locks"
end
Locks := AFT.S
Now = date():time() "'0'R#5"
IdxLock = 0
MoreLocks = LockList ne ""
SortedLockList = ""
loop while MoreLocks
   LockItem = ""
      remove LockItem from LockList setting MoreLocks
   Sys = 0
   LockPid = trim(LockItem[1,3])
   LockTime = iconv((LockItem[20])[1,8],"MT")
   LockDate = iconv(LockItem[12],"D")
   LockItem = trimf(LockItem[14,len(LockItem)])                                                                                     ;*[002]
   idx = index(LockItem,"tty",1)                                                                                                    ;*[002]
   LockUser = LockItem[1,idx-1]                                                                                                     ;*[002]
   LockItem = LockItem[idx+5,len(LockItem)]
   idx = index(LockItem,"73807361",1)
   if not(idx) then idx = index(LockItem,"73807363",1)
   LockFileName = trim(LockItem[1,idx-9])
   LockItem = trim(LockItem[idx+8,len(LockItem)])
   LockRecordName = field(LockItem," ",1)
   Then = LockDate:LockTime "'0'R#5"
   Old = (abs(Now - Then) ge FifteenMinutes)
   if LockFileName matches "'../TERMINALS'..." then
      LockFileName = field(LockFileName,'/',3,1)
   end
   if LockFileName matches "'/roi/'..." then
      LockFileName = LockFileName[6,99]
   end
   if LockFileName matches "'/usr/ud33/bin/sch'..." then
      LockFileName = "Spool Lock"
   end
   if LockFileName then
      PL = B4.D:(LockFileName:"-":LockRecordName) "L#25 "
   end else
      PL = B4.D:"" "L#25 "
   end
   PL := LockPid "R#4 "
   SysUserKey = LockUser
   begin case
      case WhoMode and LockItem ne ""
         readv SysUserName from SysUserFile, upcase(SysUserKey), 1 else SysUserName = "Unknown User"
         PL := trim(SysUserName) "L#15 "
      case HostMode and LockItem ne ""
         UserNo = LockPid
         PL := Hosts<UserNo> "L#15 "
      case 1
         readv Command from TermCtlFile, LockPid, 21 else Command = "Unknown"
         if Command eq "FN.NAME" or Command eq "VARIOUS.FNS" then    ;*Multi-function program?
            readv Command from PortCmdsFile, LockPid "'0'R#3", 1 else Command = "Unknown"
            Command = field(trim(Command)," ",1,1):" +"
         end
         PL := Command "L#15 "
   END CASE
   PL := SysUserKey "L#10 "
   if Old then PL := B4.S
   if LockDate lt DATE() then
      PL := oconv(LockDate,"D0-MD")
   end else
      PL := oconv(LockTime,"MT")
   end
   if Old then PL := AFT.S
   PL := AFT.D
   PL = trimb(PL)
   iLockTime = iconv(LockTime,"MT")
   locate iLockTime in SortedLockList<1,1> by "AR" setting Idx else null
   ins iLockTime before SortedLockList<1,Idx>
   ins PL        before SortedLockList<2,Idx>
repeat
for i = 3 to MaxLock
   crt @(5,i):SortedLockList<2,i+(MaxLock*PageLock)>:@(-4):
next i
Msg = Locks
gosub StdMsg
crt @(55,0):timedate()
if InfoMode then
   gosub InfoLocks
end
return


InfoLocks:
ThisLock = 1
crt @(0,1):"(Info Mode)":
loop
   crt @(2,ThisLock + 2):"->":@(75,0):
   gosub InfoInput
until Char eq "Q" do
   crt @(2,ThisLock + 2):"  ":
   begin case
      case Char eq "N"
         ThisLock = if ThisLock ge MaxLock then 1 else ThisLock + 1
      case Char eq "P"
         ThisLock = if ThisLock le 1 then MaxLock else ThisLock - 1
      case Char eq "D"
*         IdxLock = ThisLock + (MaxLock * PageLock)
*         Sys = 0
*         LockKey = LockKeys<IdxLock>
*         read LockRec from LockFile, LockKey else
*            Sys = 1
*            read LockRec from SysLockFile, LockKey else
*               LockRec = ""
*               LockRec<LOCK$FUNCTION.NAME> = "Lock No Longer Set"
*            end
*         end
*         FunctionName = LockRec<LOCK$FUNCTION.NAME>
*         PortNo = LockRec<LOCK$PORT>
*         UserId = LockRec<LOCK$USER.ID>
*         if Sys then
*            delete SysLockFile, LockKey
*            LockKey := " [Sys]"
*         end else
*            delete LockFile, LockKey
*         end
*         Event = "Lock released: ":LockKey:" ":PortNo:" ":FunctionName:" ":UserId
**         gosub RecordEvent
*         crt @(5,ThisLock+2):"Cleared..." "L#25":
         crt @(5,BottomOfScreen):"Delete locks not available.":
      case Char eq "?"
         gosub Help
      case 1
         crt @SYS.BELL:
   end CASE
repeat
crt @(2,ThisLock + 2):"  ":@(0,(BottomOfScreen)):@(-4):@(0,1):space(11):
InfoMode = 0
return


DisplayPrintJobs:
if NewPage ne "" then
   PagePrint = NewPage - 1
   ReDisplay = 1
end
if SaveDisplayMode ne DisplayMode or ReDisplay then
   ReDisplay = 0
   crt @(-1)
   BS = @(0,0):B4.S:"SYSTEM.MONITOR           Current Print Jobs     Page ":PagePrint+1:AFT.S
   BS := @(5,2):B4.S:"Job ID" "'.'L#25 "
   BS := "User." "L#5 "
   BS := "When" "'.'L#12 "
   BS := "Size" "'.'L#13 "
   BS := "Device":AFT.S
   crt BS:
end
RedisplayData = BS
Msg = B4.T:"Scanning lpr print jobs...":AFT.T
gosub StdMsg
pcperform "lpstat -i -o" capturing PrintJobs
swap "(standard input)" with "StdIn" in PrintJobs
pcperform "ls -l /tmp/PRT*" capturing SpoolJobs
Msg = B4.T:"Scanning for sprint print jobs...":AFT.T
gosub StdMsg
gosub BuildSprintJobs
if index(SpoolJobs,"not found",1) then
   SpoolJobs = ""
end
TotalPrintJobs = dcount(PrintJobs,@FM) / 2
if TotalPrintJobs lt 0 then TotalPrintJobs = 0
TotalPrintJobs += dcount(SpoolJobs,@FM)
TotalPrintJobs += dcount(SprintJobs,@FM)
if TotalPrintJobs then
   Msg = B4.T:TotalPrintJobs:" job":(if TotalPrintJobs eq 1 then "" else "s"):AFT.T
end else
   Msg = B4.T:"No jobs":AFT.T
end
gosub StdMsg
MorePrintJobs = PrintJobs ne "" or SpoolJobs ne "" or SprintJobs ne ""
SavePrintJobs = ""
Phase = 1
IdxPrint = 0
PrintJobId = ""
PrintJob = ""
PrintUser  = ""
PrintTime  = ""
PrintSize  = ""
PrintDevice = ""
for i = 3 to MaxPrint
   loop while MorePrintJobs
      begin case
         case Phase eq 1
            remove PrintJob from PrintJobs setting MorePrintJobs
            if PrintJob[1,1] matches char(9):@VM:" " then
               AddInfo = PrintJob
               PrintJob = SavePrintJob
            end else
               SavePrintJob = PrintJob
               remove AddInfo from PrintJobs setting MorePrintJobs
            end
            PrintJob = trim(PrintJob)
            LastItem = dcount(PrintJob," ")
            if LastItem lt 9 then LastItem = 9
            PrintDevice = field(PrintJob," ",LastItem-1,2)
            PrintJob = field(PrintJob," ",1,7)
            PrintJob = trim(PrintJob:" ":AddInfo)
            if not(MorePrintJobs) then
               Phase += 1
               MorePrintJobs = SpoolJobs ne "" or SprintJobs ne ""
               if PrintJob eq "" then
                  if not(MorePrintJobs) then
                     exit                                            ;* Nothing left to do...
                  end else
                     continue                                        ;* There must not have been any print jobs...
                  end
               end
            end
            PrintJobId = field(PrintJob," ",1)
            PrintUser = field(PrintJob," ",2)
            PrintTime = field(PrintJob," ",5,3)
            convert " " to @FM in PrintJob
            locate "bytes" in PrintJob<1> setting Idx then
               PrintSize = PrintJob<Idx-1>
            end else
               PrintSize = 0
            end
            locate "copies" in PrintJob<1> setting Idx then
               PrintDevice := " ":PrintJob<Idx-1>:" copies"
            end

         case Phase eq 2
            remove PrintJob from SprintJobs setting MorePrintJobs
            PrintJob = convert(" ",@FM,PrintJob)
            PrintJobId = PrintJob<1>
            PrintUser = PrintJob<2>
            PrintDevice = PrintJob<3>
            PrintSize = PrintJob<4>
            PrintTime = oconv(PrintJob<5>,"D2-DMD"):" ":OCONV(PrintJob<6>,"MTH")
            if not(MorePrintJobs) then Phase += 1

         case Phase eq 3
            remove PrintJob from SpoolJobs setting MorePrintJobs
            PrintJob = trim(PrintJob)
            PrintJobId = field(PrintJob," ",9)
            PrintUser = field(PrintJob," ",3)
            PrintTime = field(PrintJob," ",6,3)
            PrintSize = field(PrintJob," ",5)
            PrintDevice = "Spooling"
            if not(MorePrintJobs) then Phase += 1

      end CASE
      if not(God) and (PrintUser ne UnixUser) then continue
      IdxPrint += 1
      if IdxPrint gt (MaxPrint * PagePrint) then exit
   repeat
   PL = @(5,i)
   if PrintJob ne "" then
      PL := B4.D
      SavePrintJobs<-1> = PrintJobId
      PL := PrintJobId "L#25 "
      PL := PrintUser[1,5] "R#5 "
      PL := PrintTime "R#12 "
      Suffix = ""
      if PrintSize gt 1024 and num(PrintSize) then
         PrintSize = PrintSize / 1024
         Suffix = "K"
         if PrintSize gt 1024 then
            PrintSize = PrintSize / 1024
            Suffix = "M"
         end
      end
      if Suffix ne "" then
         PL := PrintSize "R2#10":" ":Suffix:"B"
      end else
         if PrintSize ne "" then
            PL := PrintSize "R#10":" B "
         end
      end
      PL := " ":PrintDevice :AFT.D
   end
   crt trimb(PL): @(-4):
   RedisplayData := trimb(PL):@(-4)
next i
crt @(55,0):timedate():
if InfoMode then
   gosub InfoPrintJobs
end
return


InfoPrintJobs:
ThisPrintJob = 1
PL = @(0,1):"(Info mode)"
RedisplayData := PL
crt PL:
NewDest = convert(",",@FM,getptr(0))                                 ;* Get current printer settings
Idx = index(NewDest,"DEST",1)
if Idx then
   NewDest = field(NewDest<dcount(NewDest[1,Idx],@FM)>," ",2,1)
end else
   NewDest = "F0"
end
loop
   crt @(2,ThisPrintJob + 2):"->":@(75,0):
   gosub InfoInput
until Char eq "Q" do
   crt @(2,ThisPrintJob + 2):"  ":
   begin case
      case Char eq "M"                                               ;* Move a print job to another queue
         PrintJobId = SavePrintJobs<ThisPrintJob>
         if PrintJobId[1,5] eq "/tmp/" then
            Msg = "Spooling print jobs cannot be moved.":@SYS.BELL
            gosub StdMsg
            continue
         end
         Msg = "Enter printer name to move to (END): "
         gosub StdMsg
         input @(43,(BottomOfScreen)):NewDest:
         NewDest = upcase(NewDest)
         if NewDest matches "":@VM:"END" then
            Msg = "Nothing done."
            gosub StdMsg
            continue
         end
         pcperform "lpalt ":PrintJobId:" -d":NewDest capturing Move
         Msg = trim(convert(@FM," ",Move))
         gosub StdMsg
      case Char eq "N"
         if SavePrintJobs<ThisPrintJob> ne "" then
            ThisPrintJob = if ThisPrintJob ge MaxPrint then 1 else ThisPrintJob + 1
         end else
            ThisPrintJob = 1
         end
      case Char eq "P"
         if SavePrintJobs<ThisPrintJob> ne "" then
            ThisPrintJob = if ThisPrintJob le 1 then MaxPrint else ThisPrintJob - 1
         end else
            ThisPrintJob = dcount(SavePrintJobs,@FM)
         end
      case Char eq "R"                                               ;* Release a print job to another queue
         PrintJobId = SavePrintJobs<ThisPrintJob>
         if PrintJobId[1,5] eq "/tmp/" then
            Msg = "Spooling print jobs cannot be released.":@SYS.BELL
            gosub StdMsg
            continue
         end
         Msg = "Enter printer name to release to (END): "
         gosub StdMsg
         input @(45,(BottomOfScreen)):NewDest:
         NewDest = upcase(NewDest)
         if NewDest matches "":@VM:"END" then
            Msg = "Nothing done."
            gosub StdMsg
            continue
         end
         Path = "/usr/spool/lp/request/":field(PrintJobId,"-",1,1)
         Path := "/dA":field(PrintJobId,"-",2,1) "'0'R#4":HostName
         pcperform "lp -d":NewDest:" ":Path capturing Release
         Msg = trim(convert(@FM," ",Release))
         gosub StdMsg
      case Char eq "D"
         PrintJobId = SavePrintJobs<ThisPrintJob>
         if PrintJobId[1,5] eq "/tmp/" then
            pcperform "rm /tmp/":field(PrintJobId,"/",3) capturing Cancel
            Event = "Spooling job deleted: /tmp/":field(PrintJobId,"/",3)
         end else
* Note: This command is being executed in the background because it
* is such a pig. Do not remove the & at the end.
            pcperform "cancel ":PrintJobId:" &" capturing Cancel
            Event = "Spooled job deleted: ":PrintJobId
         end
*         gosub RecordEvent
         Msg = convert(@FM," ",Cancel)[1,74]
         gosub StdMsg
         crt @(5,ThisPrintJob+2):"Deleted..." "L#25":
      case Char eq "V"                                               ;* View job
         PrintJobId = SavePrintJobs<ThisPrintJob>
         if PrintJobId[1,5] eq "/tmp/" then
            Path = "/tmp"
            PrintJobId = field(PrintJobId,"/",3)
         end else
            Path = "/usr/spool/lp/request/":field(PrintJobId,"-",1,1)
            osread dummy from Path:"/.remotesending" then
               PrintJobId = "dfA":field(PrintJobId,"-",2,1) "'0'R#3":HostName
            end else
               PrintJobId = "dA":field(PrintJobId,"-",2,1) "'0'R#4":HostName
            end
         end
         VocRec = ""
         VocRec<1> = "DIR"
         VocRec<2> = Path
         write VocRec to VOC, "SYSMON.PTR"
         openseq "SYSMON.PTR",PrintJobId readonly to PrintFile else
            Msg = "Unable to open ":Path:"/":PrintJobId:"."
            gosub StdMsg
            continue
         end
         crt @(-1)
         Mode = "I"
         Line = ""
         Params = ""
         WorkRec = ""
         Answer = ""
         loop
            call SCROLL.INQ(Mode, Line[1,ScreenCols], "", 0, 0, Answer, Params, WorkRec, 0)
            if Answer eq "END" then exit
            if Answer eq "TOP" then exit
            if Mode eq "F" then exit
            readseq Line from PrintFile else Mode = "F"
            swap char(12) with "<FF>" in Line
            swap char(27) with "<ESC>" in Line
            if Mode eq "I" then Mode = "N"
         repeat
         crt @(-1)
         crt RedisplayData
      case Char eq "?"
         gosub Help
      case 1
         crt @SYS.BELL:
   end CASE
repeat
crt @(2,ThisPrintJob + 2):"  ":@(0,(BottomOfScreen)):@(-4):@(0,1):space(11):
InfoMode = 0
return


DisplaySpoolers:
if SaveDisplayMode ne DisplayMode or ReDisplay then
   ReDisplay = 0
   crt @(-1)
   BS = @(0,0):B4.S:"SYSTEM.MONITOR           Current Spoolers":AFT.S
   BS := @(5,2):B4.S:"Device" "'.'L#15 "
   BS := "Sts" "'.'L#3":AFT.S
   BS := @(30,2):B4.S:"Device" "'.'L#15 "
   BS := "Sts" "'.'L#3":AFT.S
   BS := @(55,2):B4.S:"Device" "'.'L#15 "
   BS := "Sts" "'.'L#3":AFT.S
   crt BS:
end
PageSpool = PageSpool                                                ;* To avoid the underutilized warning.
RedisplayData = BS
pcperform "lpstat -p|grep printer|sort" capturing Spoolers
MoreSpoolers = Spoolers ne ""
SaveSpoolers = ""
InitRow = 3
Row = 3
Col = 5
SaveSpoolers = ""
SaveEnableds = ""
loop while MoreSpoolers
   remove Spooler from Spoolers setting MoreSpoolers
   if field(Spooler," ",1) ne "printer" then continue
   PrinterName = field(Spooler," ",2,1)
   Enabled = index(Spooler,"enabled",1) ne 0
   PL = @(Col,Row)
   Row += 1
   if Row gt (ScreenRows - 2) then
      Row = InitRow
      Col += 25
   end
   PL := B4.D
   SaveSpoolers<-1> = PrinterName
   SaveEnableds<-1> = Enabled
   PL := PrinterName "L#15 "
   PL := if Enabled then "On" else "Off"
   PL := AFT.D
   crt trimb(PL):
   RedisplayData := trimb(PL)
repeat
crt @(55,0):timedate():
if InfoMode then
   gosub InfoSpoolers
end
return


InfoSpoolers:
ThisSpooler = 1
LastSpooler = dcount(SaveSpoolers,@FM)
PL = @(0,1):"(Info mode)"
RedisplayData := PL
crt PL:
PL = @(5,(BottomOfScreen)):"Press <SPACE> to toggle spooler mode..."
RedisplayData := PL
crt PL:
loop
   Col = (int((ThisSpooler - 1) / MaxSpool) * 25) + 2
   Row = mod(ThisSpooler - 1 , MaxSpool) + 1
   crt @(Col,Row + 2):"->":@(75,0):
   gosub InfoInput
until Char eq "Q" do
   crt @(Col,Row + 2):"  ":
   begin case
      case Char eq "N"
         ThisSpooler = if ThisSpooler ge LastSpooler then 1 else ThisSpooler + 1
      case Char eq "P"
         ThisSpooler = if ThisSpooler le 1 then LastSpooler else ThisSpooler - 1
      case Char eq " "                                               ;* Toggle enabled/disable
         Spooler = SaveSpoolers<ThisSpooler>
         if SaveEnableds<ThisSpooler> then
            pcperform "disable ":Spooler capturing Result
            Event = "Spooler ":Spooler:" disabled."
            SaveEnableds<ThisSpooler> = 0
         end else
            pcperform "enable ":Spooler capturing Result
            Event = "Spooler ":Spooler:" enabled."
            SaveEnableds<ThisSpooler> = 1
         end
         Msg = convert(@FM," ",Result)[1,74]
         gosub StdMsg
         crt @(Col+19,Row+2):(if SaveEnableds<ThisSpooler> then "On " else "Off"):
*         gosub RecordEvent
      case Char eq "V"
         pcperform "lpstat -P":SaveSpoolers<ThisSpooler> capturing Status
         crt @(5,(BottomOfScreen)):B4.D:trim(Status<1>):AFT.D:@(-4):
      case Char eq "?"
         gosub Help
      case 1
         crt @SYS.BELL:
   end CASE
repeat
crt @(Col,Row + 2):"  ":@(0,(BottomOfScreen)):@(-4):@(0,1):space(11):
InfoMode = 0
return


CALL.FINDIU:
pcperform "listuser " capturing ListUsers
del ListUsers<1>
del ListUsers<1>
del ListUsers<1>
del ListUsers<1>
del ListUsers<1>
del ListUsers<1>
MoreListUsers = ListUsers ne ""
NUM.INFO.USERS = dcount(ListUsers,@FM)
NUMS = ""
IDS = ""
PIDS = ""
loop while MoreListUsers
   remove ListUser from ListUsers setting MoreListUsers
   ListUser = convert(" ",@FM,trim(ListUser))
   NUM = ListUser<1>
   if NUM eq "" then continue
   NUMS<-1> = NUM
   readv SysUserKey from TermCtlFile, NUM, 37 else SysUserKey = "u????"
   SysUserKey = downcase(SysUserKey)
   if len(SysUserKey) lt 5 then
      ID  = SysUserKey "R#5 "
   end else
      ID = SysUserKey:" "
   end
   begin case
      case WhoMode
         readv SysUserName from SysUserFile, upcase(SysUserKey), 1 else SysUserName = "Unknown"
         ID := trim(field(SysUserName,"/",1,1))
      case HostMode
         ID := Hosts<NUM>
      case 1
         readv Command from TermCtlFile, NUM, 21 else Command = "Unknown"
         if Command eq "FN.NAME" or Command eq "VARIOUS.FNS" then    ;*Multi-function program?
            readv Command from PortCmdsFile, NUM "'0'R#3", 1 else Command = "Unknown"
            Command = field(trim(Command)," ",1,1):" +"
         end
         ID := Command
   END CASE
   IDS<-1> = ID
   PIDS<-1> = ListUser<2>
repeat
return

UPDATE.SCREEN:
MORE.LOGOUTS = LOGGING.OUT NE ""
LOOP WHILE MORE.LOGOUTS
   REMOVE LOGOUT FROM LOGGING.OUT SETTING MORE.LOGOUTS
   UserNumber = LOGOUT
   PRINT.DATA = space(23)
   GOSUB PRINT.TO.SCREEN
REPEAT
LOGGING.OUT = ''
LAST = NUM.INFO.USERS - 1
LAST.USER.NUM = 1
gosub GetWhoList
FOR INX = 0 TO LAST
   USER.NUM    = NUMS<INX + 1>
   USER.ID     = IDS<INX + 1>
   IF USER.NUM - LAST.USER.NUM GT 1 THEN
      FOR J = LAST.USER.NUM + 1 TO USER.NUM - 1
         IF CURRENT.IDS(J) NE '' THEN
            STRING = CURRENT.IDS(J)
            GOSUB LOP.ID
            UserNumber = J
            PRINT.DATA = B4.S:STRING:AFT.S
            GOSUB PRINT.TO.SCREEN
            CURRENT.IDS(J) = ''
            LOGGING.OUT<-1> = J
         END
      NEXT J
   END
   IF USER.ID NE CURRENT.IDS(USER.NUM) THEN
      STRING = USER.ID
      GOSUB LOP.ID
      UserNumber = USER.NUM
      PRINT.DATA = ' ':STRING:' '
      GOSUB PRINT.TO.SCREEN
      CURRENT.IDS(USER.NUM) = USER.ID
   END
   LAST.USER.NUM = USER.NUM
NEXT
GOSUB FLUSH.TO.SCREEN
return

PAINT.NUMBERS:
crt @(-1)
PRINT.LINE = ""
FirstUser = PageUser * MaxUser
LastUser = FirstUser + MaxUser - 1
FOR I = FirstUser TO LastUser
   RelUser = mod(I,MaxUser)
   COL = INT(RelUser / ScreenRows) * UserElementSize
   ROW = MOD(RelUser,ScreenRows)
   PRINT.LINE := @(COL,ROW):B4.S:FMT(I + 1,"'0'R#2"):AFT.S
NEXT I
crt PRINT.LINE:
return

PRINT.TO.SCREEN:
SHORT = UserNumber - 1
if SHORT lt FirstUser then return
if SHORT gt LastUser then return
COL = (INT(SHORT / ScreenRows) * UserElementSize) + 2
ROW = MOD(SHORT,ScreenRows)
if Idles<UserNumber> le ThirtyMinutes then
   SCREEN.BUFFER := @(COL,ROW):B4.D:PRINT.DATA:AFT.D
end else
   SCREEN.BUFFER := @(COL,ROW):B4.S:PRINT.DATA:AFT.S
end
return

FLUSH.TO.SCREEN:
crt SCREEN.BUFFER:@(0,0)
SCREEN.BUFFER = ''
return

LOP.ID:
STRING = STRING "L#22"
return


*RecordEvent:
*readvu SysMonLogKey from SYS.CTL, "NEXT.SYSMON.LOG.NBR", 2 ELSE SysMonLogKey = 1
*SysMonLogRec             = ""
*SysMonLogRec<SML$DATE>   = DATE()
*SysMonLogRec<SML$TIME>   = TIME()
*SysMonLogRec<SML$USERID> = @LOGNAME
*SysMonLogRec<SML$EVENT>  = Event
*write SysMonLogRec to SysMonLogFile, SysMonLogKey
*writev SysMonLogKey+1 to SYS.CTL, "NEXT.SYSMON.LOG.NBR", 2
*return


GetWhoList:
pcperform "who -u|sort" capturing WhoLists
WhoLists     = trim(WhoLists)
MoreWhoLists = WhoLists ne ""
Devices      = ""
Idles        = ""                                                    ;* Idle time array associated with PIDS
Hosts        = ""
loop while MoreWhoLists
   remove WhoItem from WhoLists setting MoreWhoLists
   convert " " to @FM in WhoItem
   Device = WhoItem<2>
   Idle   = WhoItem<6>
   if Idle eq "." then
      Idle = 0
   end else
      Idle = iconv(Idle,"MT")
   end
   PID    = WhoItem<7>
   Host   = WhoItem<8>
   locate PID in PIDS<1> setting Idx else continue
   Idx = NUMS<Idx>                                                   ;* Resolve User Number
   Devices<Idx> = Device
   Idles<Idx>   = Idle
   Hosts<Idx>   = Host
repeat
Devices = Devices
return


GetRowsCols:
pcperform "stty -a" capturing Stty
Stty           = Stty<2>
ScreenRows     = trim(field(field(Stty,";",1),"=",2))
ScreenCols     = trim(field(field(Stty,";",2),"=",2))
if ScreenCols  = 0 then ScreenCols = 80
if ScreenRows  = 0 then ScreenRows = 24
MaxUser        = ScreenRows * int(ScreenCols / UserElementSize)
FirstUser      = PageUser * MaxUser
LastUser       = FirstUser + MaxUser - 1
MaxLock        = ScreenRows - 4
MaxPrint       = ScreenRows - 4
MaxSpool       = ScreenRows - 4
BottomOfScreen = ScreenRows - 1
return


InfoInput:
* Try and generically handle an escape sequence for arrow keys...
input Char,1:
Char = upcase(Char)
begin case
   case Char eq "E"
      input BufSize,-1
      input Flush,BufSize
      if Flush eq "ND" then Char = "Q"
   case Char eq Esc
      input Char,2:
      begin case
         case Char[1] eq "A"; Char = "P"                             ;* vt100
         case Char[1] eq "B"; Char = "N"                             ;* vt100
      end CASE
   case Char eq char(26); Char = "P"                                 ;* Wyse-50
   case Char eq char(10); Char = "N"                                 ;* Wyse-50
end CASE
return


BuildSprintJobs:
SprintTable = ""
pcperform "sqlist" capturing Sqlist
MoreSqlist = Sqlist ne ""
loop while MoreSqlist
   remove Job from Sqlist setting MoreSqlist
   Job = convert(" ",@FM,trim(Job))
   JobId = Job<1>
   locate JobId in SprintTable<1,1> by "AR" setting Idx else
      ins JobId  before SprintTable<1,Idx>
      ins Job<2> before SprintTable<2,Idx>                           ;* User
      ins Job<8> before SprintTable<3,Idx>                           ;* Device
      ins ""     before SprintTable<4,Idx>
      ins ""     before SprintTable<5,Idx>
      ins ""     before SprintTable<6,Idx>
   end
repeat

pcperform \ls -l /usr/ud33/bin/sch/sprint/spd | grep "SP"\ capturing SprintList
MoreSprintList = SprintList ne ""
loop while MoreSprintList
   remove Job from SprintList setting MoreSprintList
   Job = convert(" ",@FM,trim(Job))
   JobId = Job[8] + 0
   locate JobId in SprintTable<1,1> by "AR" setting Idx then
      SprintTable<4,Idx> = Job<5>                                    ;* Size
      SprintTable<5,Idx> = iconv(Job<6>:" ":Job<7>,"D")              ;* Date
      SprintTable<6,Idx> = iconv(Job<8>,"MT")                        ;* Time
   end
repeat
SprintJobs = ""
for i = 1 to dcount(SprintTable<1>,@VM)
   SprintJobs<-1> = "SP":SprintTable<1,i> "'0'R#8":" ":SprintTable<2,i>:" ":SprintTable<3,i>:" ":SprintTable<4,i>:" ":SprintTable<5,i>:" ":SprintTable<6,i>
next i
return


StdMsg:
crt @(5,(BottomOfScreen)):Msg:@(-4):
return


END
