title   'tShell (c) 1985 S. Kluger, all rights reserved'
       name    ('tShell')
z80
;
;       prerelease blues:
; start:
;       11/29/85        cold start, drawn up TSHELL.DEF
;       12/01/85        part 1 and 2
;       12/05/85        finished up main code
;       12/08/85        main code bug free
;       12/09/85        first live test, added hook for drive redef
;       12/11/85        completed user area lockout, rewrote TIMECL code
;       12/13/85        completed user 31 exception, added "CNTROL" to
;                       prevent access across network for some fcns,
;                       added terminal config block and access code
;       12/14/85        moved signon message to login program (from usrsom)
;       12/15/85        added printer/print mode setup
;       12/20/85        added return dskast function
;       12/21/85        added set dskast function, added remote lock
;       12/22/85        added system reset date/time function, added TIMECL
;                       suppress code to SCREEN byte
;       12/25/85        fixed AUTUSR bug
;       01/01/86        changed for USRSUP, added fcn 16,17,18,19
;       01/02/86        added sneaky serial # check
;       01/04/86        fixed problem in fcn 15 when date not set
;
; alpha:
; beta:
;       release updates:
;
;
;       serial number/version stuff
;
vers    equ     152h            ; version (1.52)
orig    equ     24
unit    equ     623
shel    equ     1               ; internal serial #
;
       aseg
?orig?  equ     orig            ; set up serial number origin...
?unit?  equ     unit            ; and unit.
       public  ?orig?,?unit?
;
;
;       +-----------------------+
;       | part 1 - data storage |
;       +-----------------------+
;
;
       dseg
;
       include TSHELL.DEF
       include TERMINAL.CFG
;
drvtbl: ds      16*3            ; slave's original DSKAST
flag31: db      0               ; user 31 access flag
srhsav: db      0               ; search drive save
;
fcntbl: dw      xxfc00          ; get parameter block
       dw      xxfc01          ; set parameter block
       dw      xxfc02          ; log off (clear pb and dskast)
       dw      xxfc03          ; send console message
       dw      xxfc04          ; allow/disallow user 31 access
       dw      xxfc05          ; spy on user/attach remote
       dw      xxfc06          ; reset this processor
       dw      xxfc07          ; abort current process
       dw      xxfc08          ; get terminal configuration
       dw      xxfc09          ; set terminal configuration
       dw      xxfc10          ; return dskast
       dw      xxfc11          ; set dskast
       dw      xxfc12          ; lock remote attach
       dw      xxfc13          ; unlock remote attach
       dw      xxfc14          ; return last system reset date/time
       dw      xxfc15          ; set reset date/time
       dw      xxfc16          ; return master node
       dw      xxfc17          ; suspend until date/time
       dw      xxfc18          ; execute program
       dw      xxfc19          ; return tShell serial number
nmbfcn  equ     ($-fcntbl)/2    ; number of functions
;
lrsdt:  dw      0               ; last reset date
lrstm:  dw      0               ;   time
lrsst:  dw      0               ;   tick
locked: db      0               ; locked flag
abcpf:  db      0               ; flag to abort current process
resflg: db      0               ; reset active flag
twxflg: db      0               ; twix active flag
twxbuf: ds      128             ; twix message buffer
execut: db      0               ; execute flag
execp:  dw      execl
execl:  ds      128             ; execute buffer
;
id:     db      '.tShell.'
;
;
;       +-------------------------+
;       | part 2 - initialization |
;       +-------------------------+
;
       common  /?init?/
;
usrin@::
       ld      de,tshpr
       call    crproc##        ; create rsp
       ld      a,(autusr##)    ; get autusr byte
       and     80h             ; see if default logon privileged
       jr      nz,.nsru.       ;   do not patch SRUFCN
       ld      a,0c3h          ; patch SRUFCN
       ld      (srufcn##+12),a
       ld      hl,sruint
       ld      (srufcn##+13),hl
nsru.:  ld      hl,timecl       ; patch timecl
       ld      (cmdint##+12),hl
       ld      de,drvtbl       ; move the dskast
       ld      hl,dskast##
       ld      bc,16*3
       ldir
       ld      a,(srhdrv##)    ; get and save search drive
       ld      (srhsav),a
       ld      hl,(conast##+1) ; get console entry point
       ld      (consol),hl     ; store it here
       ld      hl,conint       ; get intercept address
       ld      (conast##+1),hl ; redirect console
       ld      a,nmbfcn
       ld      hl,id
       ret
;
;       +------------------------+
;       | part 3 - mainline code |
;       +------------------------+
;
       cseg
;
usrfc@::
       push    hl
       push    de
       push    bc
       call    xxfc15
       pop     bc
       pop     de
       pop     hl
       ld      a,l             ; get function number
       cp      nmbfcn+1        ; in range?
       jr      c,..uok.        ;   yes, process fcn
       ld      a,0ffh
       ret
;
.uok.:  ld      h,0             ; hl=function #
       add     hl,hl
       push    de              ; save de
       ld      de,fcntbl
       add     hl,de           ; hl points to fcn address
       pop     de
       ld      a,(hl)
       inc     hl
       ld      h,(hl)
       ld      l,a
       jp      (hl)            ; execute function
;
;       +----------------------------------+
;       | function 0 - get parameter block |
;       +----------------------------------+
;
xxfc00: ld      d,b             ; move destination (dma)
       ld      e,c
       ld      hl,LCLID        ; point to source
gspb:   ld      bc,128
       ldir
       xor     a               ; set ok flag
       ret
;
;       +----------------------------------+
;       | function 1 - set parameter block |
;       |         and log user on          |
;       +----------------------------------+
;
xxfc01: call    cntrol          ; see if authorized
       ret     nz
       ld      a,(LCLLGD)      ; get logged flag
       or      a               ; logged?
       ret     nz              ;   yes, barf
       dec     a               ; make a=ff
       ld      (LCLLGD),a      ; set logged true
       ld      h,b             ; move source (dma)
       ld      l,c
       ld      de,LCLID
       call    gspb            ; wrap up
       ld      a,(LCLDPR)      ; get default printer/queue
       ld      (queptr##),a    ; reset it
       ld      a,(LCLDPM)      ; get default print mode
       ld      (prtmod##),a    ; reset it
       ld      a,(LCLSHD)      ; get defined search drive
       ld      (srhdrv##),a    ; set new search drive
       call    redef           ; effect drive redefinition
       ld      b,8             ; 16 drives to process twice
       ld      hl,dskast##     ; patch target
       ld      a,(LCLDRA+1)    ; get access for A..H
       call    ..sds.          ; patch
       ld      b,8             ; the next 8
       ld      a,(LCLDRA)      ; access for J..P
       call    ..sds.
       xor     a               ; set ok flag
       ret
;
.sds.:  rra                     ; drive bit into carry
       jr      c,.sdx.         ; skip if allowed
       ld      (hl),0ffh       ;   else patch to offline
sdx.:   inc     hl
       inc     hl
       inc     hl              ; point to next drive
       djnz    ..sds.          ; repeat until 8 drives done
       ret
;
;       +----------------------+
;       | function 2 - log off |
;       +----------------------+
;
xxfc02: call    cntrol          ; authorization check
       ret     nz
       ld      hl,LCLID        ; clear pb
       ld      b,128
.lof.:  ld      (hl),0
       inc     hl
       djnz    ..lof.
       ld      hl,drvtbl       ; restore dskast
       ld      de,dskast##
       ld      bc,16*3
       ldir
       xor     a
       ld      (flag31),a      ; set 31 access flag off
       ld      a,(srhsav)      ; reset search drive
       ld      (srhdrv##),a
       ret
;
;       +-----------------------------------+
;       | function 3 - send console message |
;       +-----------------------------------+
;
xxfc03: ld      h,b
       ld      l,c
       ld      de,twxbuf
       ld      bc,128
       ldir
       ld      a,0ffh
       ld      (twxflg),a
       ret
;
;       +-----------------------------+
;       | function 4 - user 31 access |
;       +-----------------------------+
;
xxfc04: call    cntrol          ; authorized?
       ret     nz
       ld      hl,flag31       ; point to access flag
       ld      a,(hl)          ; get it to a
       cpl                     ; complement (toggle) it
       ld      (hl),a          ; save it
       ret                     ; a returns status
;
;       +--------------------------+
;       | function 5 - spy on user |
;       +--------------------------+
;
xxfc05: xor     a                       ; not implemented
       ret
;
;       +----------------------------+
;       | function 6 - reset station |
;       +----------------------------+
;
xxfc06: ld      a,0ffh
       ld      (resflg),a              ; set reset flag
       ret
;
;       +------------------------------------+
;       | function 7 - abort current process |
;       +------------------------------------+
;
xxfc07: ld      a,0ffh          ; set abort flag, so that the guy...
       ld      (abcpf),a       ; ...gets blown off at next console I/O
       ret
;
;       +-----------------------------------------+
;       | function 8 - get terminal configuration |
;       +-----------------------------------------+
;
xxfc08: call    cntrol          ; allowed?
       ret     nz              ; no, return undone
       ld      d,b             ; move destination
       ld      e,c             ;   into bc
       ld      hl,TCFBLK       ; source to hl
gspb:   jp      gspb            ; move
;
;       +-----------------------------------------+
;       | function 9 - set terminal configuration |
;       +-----------------------------------------+
;
xxfc09: call    cntrol          ; allowed?
       ret     nz              ; no, return undone
       ld      h,b             ; move source
       ld      l,c             ;   into hl
       ld      de,TCFBLK       ; set up destination
       jr      .gspb           ; move it
;
;       +-----------------------------+
;       | function 10 - return dskast |
;       +-----------------------------+
;
xxfc10: call    cntrol          ; local call?
       ret     nz              ;   no, barf
       ld      d,b             ; move destingation
       ld      e,c
       ld      hl,dskast##
       jr      .gspb
;
;       +--------------------------+
;       | function 11 - set dskast |
;       +--------------------------+
;
xxfc11: call    cntrol          ; local call?
       ret     nz              ;   no, ignore
       ld      a,(LCLLV)       ; get access byte
       and     3               ; mask priv level
       sub     2               ; see if full
       ret     nz              ;   no, ignore
       ld      h,b             ; move source
       ld      l,c
       ld      de,dskast##
       ld      bc,16*3
       ldir
       xor     a               ; return ok
       ret
;
;       +----------------------------------+
;       | function 12 - lock remote attach |
;       +----------------------------------+
;
xxfc12: ld      a,(locked)      ; get locked flag
       inc     a               ; test it
       ret     z               ; return if locked
       ld      a,0ffh
lunl.:  ld      (locked),a      ; lock
       ret
;
;       +------------------------------------+
;       | function 13 - unlock remote attach |
;       +------------------------------------+
;
xxfc13: xor     a
       jr      .lunl.
;
;       +---------------------------------------------+
;       | function 14 - return last system reset time |
;       +---------------------------------------------+
;
xxfc14: ld      hl,(lrsdt)              ; get last reset date
       ld      de,(lrstm)              ;   hours and minutes
       ld      bc,(lrsst)              ;   seconds and tick count
       ret
;
;       +-----------------------------------+
;       | function 15 - set reset date/time |
;       +-----------------------------------+
;
xxfc15: ld      c,10
       call    otntry##
       ld      a,0ffh
       bit     7,h
       ret     nz                      ; invalid date/time
       ld      (lrsdt),hl
       ld      (lrstm),de
       ld      (lrsst),bc
       ld      a,0c9h
       ld      (xxfc15),a              ; inhibit re-entry
       ret
;
;       +----------------------------------+
;       | function 16 - return master node |
;       +----------------------------------+
;
xxfc16: ld      hl,(defdid##)
       ret
;
;       +-----------------------------+
;       | function 17 - suspend until |
;       +-----------------------------+
;
xxfc17: push    iy
       push    bc                      ; save pointer to dma buffer
       ld      c,10
       call    otntry##                ; get date and time
       pop     iy                      ; pointer into IY
       ld      a,l
       cp      (iy)
       jr      nz,.17.n                ; skip if negative compare
       ld      a,h
       cp      (iy+1)
       jr      nz,.17.n
       ld      a,e
       cp      (iy+2)
       jr      nz,.17.n
       ld      a,d
       cp      (iy+3)
17.n:   push    iy
       pop     bc
       pop     iy
       ret     z                       ; return if done
       push    bc
       ld      c,2
       ld      de,60                   ; else wait a second
       call    otntry##
       pop     bc
       jr      xxfc17
;
;       +------------------------------------+
;       | function 18 - execute command line |
;       +------------------------------------+
;
xxfc18: ld      h,b
       ld      l,c
       ld      de,execl
       ld      a,(hl)
       or      a
       ret     z
       call    gspb
       ld      hl,execl
       ld      (execp),hl
       ld      a,1
       ld      (execut),a
       ret
;
;       +------------------------------------+
;       | function 19 - return serial number |
;       +------------------------------------+
;
xxfc19: ld      hl,shel         ; return serial #
       ld      de,vers         ; and version #
       ld      bc,unit
       ld      a,orig
       ret
;
;
;       +---------------------------+
;       | part 4 - resident process |
;       +---------------------------+
;
;
tshpr:  ld      c,12
       call    otntry##
       ld      hl,unit
       or      a
       sbc     hl,de
       jr      nz,.crash
       ld      c,2                     ; do it once a second
       ld      de,60
       call    otntry##
       ld      a,(resflg)              ; get reset flag
       inc     a
       jr      nz,.tshnr               ; skip if no reset
       ld      c,2
       ld      de,240                  ; delay 4 seconds
       call    otntry##
       call    xreset##                ; call external reset
crash:  di
       halt
;
tshnr:  ld      a,(twxflg)              ; get twix flag
       inc     a
       call    z,sndtwx                ; send twix if there
       jp      tshpr                   ; and loop
;
sndtwx: ld      hl,twxbuf               ; point to buffer
       ld      a,(hl)                  ; get length
       or      a                       ; empty?
       ret     z                       ; yes, return
       ld      b,a
       inc     hl
.stwx:  push    bc
       push    hl
       ld      a,(conast##)
       ld      d,a
       ld      e,2
       ld      c,(hl)
       call    condra##
       pop     hl
       pop     bc
       inc     hl
       djnz    ..stwx
;
;
;       +-------------------------+
;       | part 5 - intercept code |
;       +-------------------------+
;
; 1. set user number intercept
;
sruint: call    chkusr          ; check user access
       ret     nc              ; ignore if restricted
       ld      (ix+40h),a      ;   else store user number
       ret
;
; 2. prompt display intercept
;
timecl: ld      a,(clblen##+9)
       or      a               ;if prompt inhibit...
       jr      nz,skip         ;...then don't display time
       ld      a,(LCLSCM)      ; get screen byte
       bit     6,a             ; see if TIMECL disabled
       jr      nz,skip         ;   skip if disabled
       ld      c,10
       call    otntry##        ; get time
       ld      a,d             ; get hours
       call    bytout
       ld      (timst+1),hl
       ld      a,e             ; get minutes
       call    bytout
       ld      (timst+4),hl
       ld      c,12
       call    ocntry##
       ld      a,d
       add     a,'A'
       ld      (sta),a
       ld      a,e
       call    bytout
       ld      (net),hl
       call    dms##
timst:  db      '[00:00 '
sta:    db      'A'
net:    db      '00] ',80h
skip:   ld      a,(ix+40h)
       ret
;
bytout: ld      l,'0'-1
.l:     inc     l
       sub     10
       jr      nc,..l
       add     a,'0'+10
       ld      h,a
       ret
;
; 3. console I/O intercept
;
conint: ld      a,(abcpf)       ; get abort flag
       inc     a
       jr      nz,.nabrt       ; don't abort
       ld      (abcpf),a
       call    dms##           ; let the sucker know
       0dh,0ah,0ah,7
       '[OPERATOR TERMINATED]',0dh,0ah,80h
       jp      errxit##        ; trash him
;
nabrt:  ld      a,(execut)
       or      a
       jr      z,.nexec
       call    .exab                   ; abort whatever we're doing
       ld      a,e
       cp      2
       jr      nc,.nexec
       ld      hl,(execp)
       inc     hl
       or      a
       jr      nz,.exns
       ld      a,(execl)
       or      a
       ret     z
       ld      c,(hl)
       ld      a,0ffh
       ret
;
exns:   ld      a,(execl)
       dec     a
       ld      (execl),a
       jp      m,doexe
       ld      (execp),hl
       ld      a,(hl)
       ret
;
doexe:  xor     a
       ld      (execut),a
nexec:  jp      0               ; patched later
consol  equ     $-2

;
exab:   ld      a,0c9h
       ld      (.exab),a
       jp      errxit##
;
;       +------------------------------+
;       | part 6 - utility subroutines |
;       +------------------------------+
;
;
; 1. check user
;    input:  A = desired user area
;    output: C = allowed or NC = restricted
;            no registers altered
;
chkusr: and     1fh                     ; make 0..1f
       push    hl
       ld      hl,LCLLGD
       bit     7,(hl)
       pop     hl
       scf
       ccf
       ret     z               ; exit if unlogged
       cp      31              ; user 31 requested?
       jr      nz,n.31.        ;   no, continue normally
       push    hl
       ld      hl,flag31       ; point to user 31 access flag
       inc     (hl)
       dec     (hl)
       pop     hl              ; Z if flag off
       jr      z,n.31.         ; check if maybe authorized anyway
       scf
       ret                     ; say yes
;
n.31.:  push    bc
       push    hl
       ld      c,a             ; save requested user area
       ld      a,(LCLLV)       ; get his access level
       and     3               ; mask acl
       cp      2               ; check if full access
       ld      a,c
       scf                     ; preset true
       jr      z,.n.res        ; skip if authorized
       cp      8               ; over 7?
       ld      hl,LCLUSA
       jr      c,..ck..
       cp      16              ; over 15?
       inc     hl
       jr      c,..ck..
       cp      24              ; over 23
       inc     hl
       jr      c,..ck..
       inc     hl
.ck..:  and     7               ; make 0..7
       ld      b,a             ; into counter
       inc     b               ; iterate at least once
       ld      a,(hl)          ; get access bits
.ckl.:  rra                     ; move bits around
       djnz    ..ckl.          ;   until right one is in CY
       ld      a,c             ; get user area back
n.res:  pop     hl              ; restore hl
       pop     bc              ; restore bc
       ret
;
; 2. dskast patch for drive re-definition
;    no input, output, all regs used
;    NOTE: for testing, redef is allowed for A:
;
redef:
       ret                     ; later

;
; 3. check for authorization.
;    a call here verifies that DE=FFFF
;
cntrol: inc     de
       ld      a,d
       or      e
       ld      a,0ffh          ; set false
       ret



       end
               ; check if maybe authorized anyway
       scf
       ret                     ; say yes
;
n.31.:  push    bc
       push