; File MSSTER.ASM
; Edit history:
; [2.29] [hlk]
; changed initialization code in telnet.  only clear screen first time 
; we connect.
; [2.29] [jrd]
; Fix handling of mode line, skip asking for space upon returning from
; DOS (a Push command).
; [2.28 jrd]
; Fix capture routine to use full DOS 2.0 path names, shorten pull down
; menu, break lines of Show Macro after escaped codes.
; Joe R. Doupnik 27 Oct 1985 [jrd]
; Added reference to cptsiz (size of capture buffer). 28 Dec 1985
;
; [v2.28]
; Added set mode line {on/off} (From Edgar Butt, U. of Md.)
; Added clear key def routine
; JD 1 May 1985
;

        Public  clscpt, defkey, inicpt, clscpi, telnet
        public  dopar, shokey, prkey, clrdef
        include mssdef.h

datas   segment public 'datas'
        extrn   flags:byte, trans:byte, buff:byte, portval:word
        extrn   cptio:byte

targ    termarg <0,1,80,24,cptchr,2dch,0,scntab,deftab,0,,parnon>
ssp     dw      0               ; Save SP in Telnet.
crlf    db      cr,lf,'$'
tmsg1   db      cr,lf,'[Connecting to host, type $'
tmsg3   db      ' C to return to PC]',cr,lf,cr,lf,cr,lf,'$'
erms22  db      cr,lf,'?No capture file open$' ;[jd]
erms23  db      cr,lf,'?Error writing capture file, suspending capture'
        db      cr,lf,'$'
erms2   db      cr,lf,'?No room in definition buffer, definition ignored'
        db      cr,lf,'$'
erms3   db      cr,lf,'?No room in scan table, definition ignored',cr,lf,'$'
esctl   db      'Control-$'         ; [6]

inthlp  db      cr,lf,'  ?  This message'
        db      cr,lf,'  C  Close the connection            P  Push to DOS'
        db      cr,lf,'  S  Status of the connection        Q  Quit logging'
        db      cr,lf,'  M  Toggle mode line                R  Resume logging'
        db      cr,lf,'  B  Send a break                    0  Send a null'
        db      cr,lf,'  Typing the escape character will send it to the host'
        db      0       ; this short-form obscures less screen area [jrd]

intprm  db      'Command> $'

CAPBUF  DB      cptsiz DUP (?)  ; [jrd]
CAPBP   DW      ?
CAPLFT  dw      ?               ; [jrd]

SCNTLEN EQU     200             ; MAX # OF DEFINITIONS ONE can have
defbsiz equ     400             ; combined length of all definitions...
scntab  dw      scntlen dup (?) ; scan codes redefined
deftab  dw      scntlen dup (?) ; pointer to definition strings
defbuf  db      defbsiz dup (?)
defptr  dw      defbuf          ; pointer starts at beginning
deflen  dw      defbsiz         ; amt of space left in buffer
sttmsg  db      cr,lf,'Type space to continue ...$'
shkmsg  db      cr,lf,'Press key: $'
ocbuf   db      4 dup (?)
datas   ends

code    segment public
        extrn   comnd:near, outchr:near, stat0:near
        extrn   escprt:near, clrbuf:near, term:near
        extrn   cmblnk:near, locate:near, prtchr:near
        extrn   beep:near, puthlp:near
        extrn   serini:near,serrst:near, sendbr:near, showkey:near
        extrn   fpush:near
        assume  cs:code, ds:datas

; the show key command.

shokey  proc    near
        mov     ah,cmcfm                ; confirm with carriage return
        call    comnd
         jmp    r                       ; uh oh...
        mov     dx,offset shkmsg
        mov     ah,prstr
        int     dos                     ; print a prompt for it
        mov     ax,offset targ          ; give it terminal arg block.
        call    showkey                 ; show them the key definition
        push    ax
        push    cx                      ; save results
        mov     dx,offset crlf
        mov     ah,prstr
        int     dos
        pop     cx
        pop     ax
        call    prkey                   ; print the buffer
        mov     dx,offset crlf
        mov     ah,prstr
        int     dos
        jmp     rskp                    ; and return
shokey  endp

; pass a string pointer in ax, length in cx.
; Prints the string, quoting any unprintables, except crlf.

prkey   proc    near
        mov     si,ax                   ; copy string ptr
        jcxz    prke6                   ; no string, stop here
prke1:  push    cx                      ; save counter
        lodsb                           ; get a byte
        and     al,7fH                  ; consider only low-order 7 bits.
        cmp     al,' '                  ; printable?
        jb      prke2                   ; no, print the hard way
        cmp     al,7fH                  ; maybe a delete?
        jne     prke4                   ; no, can just put into string
prke2:  jcxz    prke3                   ; last char, can't be crlf
        cmp     al,cr                   ; carriage return?
        jne     prke3                   ; no, go on
        cmp     byte ptr [si],lf        ; followed by linefeed?
        jne     prke3
        mov     ah,prstr
        mov     dx,offset crlf
        int     dos                     ; else just print crlf
        inc     si                      ; skip over lf
        pop     cx                      ; careful...
        dec     cx
        push    cx
        jmp     short prke5
prke3:  push    ax                      ; preserve the char
        mov     ah,conout
        mov     dl,'\'
        int     dos                     ; print the quote character
        pop     ax
        call    proct                   ; print the octal byte
        push    ax                      ; break display after this code [jrd]
        push    dx                      ; to keep from going beyond col 80
        mov     ah,prstr
        mov     dx,offset crlf
        int     dos
        mov     ah,conout               ; add two spaces for next line
        mov     dl,' '
        int     dos
        int     dos
        pop     dx
        pop     ax
        jmp     short prke5
prke4:  mov     dl,al                   ; normal char, just print it
        mov     ah,conout
        int     dos
prke5:  pop     cx                      ; restore count
        loop    prke1
prke6:  ret                             ; and return
prkey   endp

; print the byte in al as an octal number
proct   proc    near
        push    si
        push    di
        pushf                           ; save flags...
        mov     ch,3                    ; # of digits to print
        mov     cl,3                    ; shift count
        mov     di,offset ocbuf+2       ; point to end of buffer
        std                             ; set direction to backwards
        mov     dl,al                   ; copy the byte
proc1:  mov     al,dl
        and     al,7                    ; keep low-order byte
        add     al,'0'                  ; make printable
        stosb                           ; drop it off
        shr     dl,cl                   ; shift this digit out
        dec     ch
        jnz     proc1                   ; loop thru all
        mov     cx,3
        cld                             ; forward again
        mov     si,offset ocbuf
        mov     ah,conout               ; console output function
proc2:  lodsb
        mov     dl,al
        int     dos
        loop    proc2                   ; print all digits
        popf
        pop     di
        pop     si
        ret
proct   endp

;       This is the CONNECT command.

TELNET  PROC    NEAR
        mov ah,cmcfm
        call comnd              ; Get a confirm.
         jmp r                  ;  Didn't get a confirm.
        mov ah,prstr            ; Output
        mov dx,offset crlf      ; a crlf.
        int dos
        call domsg              ; Reassure user. [19b]
        mov al,0                ; initial flags
        cmp flags.modflg,0      ; mode line enabled? [jrd]
        jne tel010              ; yes, go on
        or al,modoff            ; no, make sure it stays off

tel010: or al,havtt             ; defaults (!)
        cmp flags.debug,0       ; debug mode?
        jz tel0                 ; no, keep going
        or al,trnctl            ; yes, show control chars
tel0:   cmp flags.wrpflg,0      ; wrap mode?
        jz tel011               ; no, keep going
        or al,lnwrap
tel011: cmp flags.vtflg,0       ; emulation a terminal?
        jz tel1
        or al,emheath           ; say emulating some kind of terminal [jrd]
tel1:   mov bx,portval
        cmp [bx].ecoflg,0       ; echoing?
        jz tel2
        or al,lclecho
tel2:   mov targ.flgs,al        ; store flags
        mov ah,flags.comflg
        mov targ.prt,ah         ; Port 1 or 2
        mov ah,trans.escchr
        mov targ.escc,ah
        mov ah,[bx].parflg
        mov targ.parity,ah
        mov ax,[bx].baud
        mov targ.baudb,al
        mov ah,flags.capflg
        and ah,capt
        or targ.flgs,ah
        call serini             ; init serial port
tem:    mov ax,offset targ      ; Point to terminal arguments
        call term
        or targ.flgs,scrsam     ; assume screen is the same.
tem1:   mov flags.wrpflg,0      ; assume not wrap mode
        test targ.flgs,lnwrap   ; in wrap mode?
        jz tem2                 ; no, continue
        mov flags.wrpflg,1
tem2:
intchr: mov ah,dconio           ; Direct console I/O.
        mov dl,0FFH             ; Input.
        int dos                 ; Get a char.
        jz intchr               ; no char, keep looking
        mov ah,al
        jz intchr               ; If so, go until we get a char.
        cmp ah,' '              ; space - ignore it
        je tem
        mov bh,ah               ; Save the actual char.
        and ah,not ('a'-'A')    ; Convert to upper case.
        or ah,40H               ; convert ctl-char to actual char.
        cmp ah,'C'              ; Is it close?
        jne intch1
        call serrst             ; reset serial port
        jmp rskp                ; and return
intch1: cmp ah,'S'              ; Is it status?
        jnz intch2
        call stat0              ; If so, call stat0.
        call puthlp             ; put help on screen
        mov dx,offset sttmsg
        mov ah,prstr
        int dos
intch1a:mov ah,coninq           ; console input, no echo
        int dos
        cmp al,' '              ; space?
        jne intch1a
        and targ.flgs,not scrsam ; remember screen changed.
        jmp tem
intch2: cmp ah,'B'              ; Send a break? [20g]
        jne intch3              ; No. [20g]
        call sendbr             ; Yes, so send a break. [20g]
        jmp tem                 ; And return.  [20g]
intch3: cmp ah,'M'              ; mode line?
        jne intch4
        cmp flags.modflg,1      ; mode line enabled? [jrd]
        jne intch3a             ; ne = no, leave it alone
        xor targ.flgs,modoff    ; enabled, toggle its state. [jrd]
intch3a:jmp tem                 ; and reconnect
intch4: cmp bh,'?'              ; Is it help?
        jne intch5              ; If not, go to the next check.
        mov ax,offset inthlp    ; If so, get the address of the help message.
        call puthlp             ; write help msg
        mov dx,offset intprm
        mov ah,prstr            ; Print it.
        int dos
        and targ.flgs,not scrsam ; remember screen changed
        jmp intchr              ; Get another char.
intch5: cmp bh,trans.escchr     ; Is it the escape char?
        jne intch7              ; If not, go send a beep to the user.
intch6: mov ah,al
        call outchr
        nop
        nop
        nop
        jmp tem                 ; Return, we are done here.
intch7: cmp ah,'Q'              ; maybe want to stop logging?
        jne intch8
        test targ.flgs,capt     ; not capturing, can't do this
        jz intc11
        and targ.flgs,not capt ; stop capturing
        jmp tem                 ; and resume
intch8: cmp ah,'R'              ; maybe resume?
        jne intch9              ; no, keep going
        cmp flags.capflg,0      ; can we capture?
        jz intc11               ; no, forget it
        test targ.flgs,capt     ; already capturing?
        jnz intc11              ; yes, can't toggle back on then
        or targ.flgs,capt       ; else turn flag on
        jmp tem                 ; and resume
intch9: cmp bh,'0'              ; perhaps want a null (note original chr in bh)
        jne intc10
        mov ah,0
        call outchr
        nop
        nop
        nop
        jmp tem
intc10: cmp ah,'P'              ; maybe want to push?
        jne intc11              ; no, go on
        call fpush              ; try pushing
         nop
         nop
         nop                    ; isn't this silly?
;;;     mov dx,offset sttmsg    ; don't wait for space [jrd]
;;;     mov ah,prstr
;;;     int dos
;;;     jmp intch1a             ; wait for space
intc11: call beep
        jmp tem
TELNET  ENDP
; Reassure user about connection to the host.  Tell him what escape
; sequence to use to return and the communications port and baud
; rate being used.   [19b]

DOMSG   PROC    NEAR
        mov ah,prstr
        mov dx,offset tmsg1
        int dos
        call escprt
        mov ah,prstr
        mov dx,offset tmsg3
        int dos
        ret
DOMSG   ENDP


; Set parity for character in Register AL.

dopar:  push bx
        mov bx,portval
        cmp [bx].parflg,parnon  ; No parity?                    [10 start]
        je parret               ; Just return
        cmp [bx].parflg,parevn  ; Even parity?
        jne dopar0
        and al,07FH             ; Strip parity.
        jpe parret              ; Already even, leave it.
        or al,080H              ; Make it even parity.
        jmp parret
dopar0: cmp [bx].parflg,parmrk  ; Mark parity?
        jne dopar1
        or al,080H              ; Turn on the parity bit.
        jmp parret
dopar1: cmp [bx].parflg,parodd  ; Odd parity?
        jne dopar2
        and al,07FH             ; Strip parity.
        jpo parret              ; Already odd, leave it.
        or al,080H              ; Make it odd parity.
        jmp parret
dopar2: and al,07FH             ; Space parity - turn off parity bit.
parret: pop bx
        ret                                     ; [10 end]

inicpt  proc    near
        mov     capbp,offset capbuf
        mov     caplft,cptsiz           ; init buffer ptr & chrs left. [jrd]
        ret                             ; and return
inicpt  endp


cptchr  proc    near                    ; capture routine, char in al
        push    di
        mov     di,capbp
        mov     byte ptr [di],al
        inc     di
        mov     capbp,di                ; restore pointer
        pop     di
        dec     caplft                  ; decrement chars remaining
        jnz     cptch1                  ; more room, forget this part
        call    cptdmp                  ; dump the info
        call    inicpt                  ; re-init ptrs.
cptch1: ret                             ; and return
cptchr  endp

cptdmp  proc    near                    ; empty the capture buffer
        push    ax
        push    bx                      ; [jrd]
        push    cx                      ; [jrd]
        push    dx
        mov     dx,offset capbuf        ; the capture routine buffer
        mov     bx,cptio.handle         ; get file handle [jrd]
        mov     cx,cptsiz               ; original buffer size [jrd]
        sub     cx,caplft               ; minus number remaining [jrd]
        mov     ah,write2               ; write with filehandle [jrd]
        int     dos                     ; write out the block
        jnc     cptdm1                  ; carry set means error
        and     targ.flgs,not capt      ; so please stop capturing
        mov     dx,offset erms23        ; tell user the bad news
        mov     ah,prstr
        int     dos
cptdm1: pop     dx
        pop     cx                      ; [jrd]
        pop     bx                      ; [jrd]
        pop     ax
        ret

cptdmp  endp

clscpt  proc    near
        test    flags.capflg,0FFH       ; doing capture
        jnz     clscp1                  ; yes, go ahead
        mov     dx,offset erms22
        mov     ah,prstr
        int     dos
        jmp     rskp
clscp1: mov     ah,cmcfm
        call    comnd
         jmp    r
clscpi: mov     al,'Z'-64               ; control-z for eof...
        call    cptchr                  ; output to file
        mov     ax,caplft
        cmp     ax,cptsiz               ; is buffer empty?
        je      clscp2                  ; yes, forget this stuff
        call    cptdmp                  ; dump buffer (preserves registers)
clscp2: mov     ah,close2               ; DOS 2.0 close [jrd]
        push    bx                      ; [jrd]
        mov     bx,cptio.handle         ; file handle [jrd]
        int     dos                     ; close up file
        pop     bx                      ; [jrd]
        mov     flags.capflg,0          ; no longer capturing...
        jmp     rskp                    ; and return
clscpt  endp

; enter with ax/scan code to define, si/ pointer to definition, cx/ length
; of definition.  Defines it in definition table.
defkey  proc    near
        cmp     deflen,cx
        jg      defk0           ; room in buffer, continue
        mov     dx,offset erms2
        call    tmsg
        ret
defk0:  push    ax              ; save scan code
        mov     ax,ds
        mov     es,ax           ; address data segment
        mov     di,defptr       ; this is where the def gets built
        inc     di              ; leave a byte for length
defk1:  lodsb                   ; get a byte from the source
        cmp     al,'\'          ; escape?
        jne     defk2           ; no, just deposit him
        dec     cx              ; count available is one less
        call    trnesc          ; translate the escape sequence
        inc     cx              ; account for '\' (loop will decrement again).
defk2:  stosb                   ; drop off character
        loop    defk1           ; and keep going while we have more
        mov     ax,di           ; get ptr to end
        dec     ax              ; back up pointer to end
        mov     si,defptr       ; pick up old ptr value
        sub     ax,si           ; this is actual length used
        sub     deflen,ax       ; account for the space
        mov     byte ptr [si],al ; fill in length of entry
        mov     defptr,di       ; this is next free byte
; definition address is in si
        pop     ax              ; recover scan code
        mov     cx,targ.klen    ; length of scan table
        jcxz    defk4           ; not there, just go add it
        mov     di,offset scntab ; the scan code table
        repne   scasw           ; look for this one
        jne     defk4           ; not defined already
        sub     di,offset scntab + 2 ; compute index into table
        mov     deftab[di],si   ; fill in address
        ret                     ; and return
defk4:  mov     di,targ.klen    ; get length again
        inc     di
        cmp     di,scntlen
        ja      defk5           ;** ignore def if over size
        mov     targ.klen,di    ; update length
        shl     di,1            ; double for word index
        mov     scntab[di-2],ax ; put scan code into table
        mov     deftab[di-2],si ; and fill in definition
        ret                     ; that's it
defk5:  mov     dx,offset erms3
        call    tmsg
        ret
defkey  endp

; enter with si/ source pointer, cx/ count
; converts an escape sequence, updates all pointers
trnesc  proc    near
        push    bx
        push    dx              ; preserve these
        mov     al,0            ; this is current accumulation
        jcxz    trnes2          ; empty string, forget it
        mov     bl,3            ; this is max # of digits to use
        mov     bh,8            ; this is radix
trnes1: mov     dl,[si]
        cmp     dl,'0'
        jb      trnes2          ; out of range, stop here
        cmp     dl,'7'
        ja      trnes2
        inc     si              ; accept character
        sub     dl,'0'          ; convert to binary
        mul     bh              ; shift accumulation
        add     al,dl           ; add to accumulation
        dec     bl              ; decrement digit counter
        loopnz  trnes1          ; and keep trying
trnes2: pop     dx
        pop     bx
        ret                     ; and return
trnesc  endp

; clear all def's
clrdef  proc    near
        mov     targ.klen,0     ; no defn's
        mov     defptr,offset defbuf ; pointer starts at beginning
        mov     deflen,defbsiz  ; amt of space left in buffer
        ret
clrdef  endp

; print a $-message in dx
tmsg    proc    near
        mov     ah,prstr
        int     dos
        ret
tmsg    endp

; Jumping to this location is like retskp.  It assumes the instruction
;   after the call is a jmp addr.

RSKP    PROC    NEAR
        pop bp
        add bp,3
        push bp
        ret
RSKP    ENDP

; Jumping here is the same as a ret.

R       PROC    NEAR
        ret
R       ENDP

code    ends
        end



