; Edit history:
;
; [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, cptfcb, inicpt, clscpi, telnet
	public  dopar, shokey, prkey, clrdef
	include msdefs.h

datas 	segment	public 'datas'
	extrn	flags:byte, trans:byte, buff:byte, portval:word

targ	termarg	<0,1,80,24,cptchr,2dch,0,scntab,deftab,0,,parnon>
ssp	dw	0		; Save SP in Telnet.
crlf    db      cr,lf,'$'
tmp	db	?,'$'
temp	dw	0
temp1   dw      ?               ; Temporary storage.
temp2   dw      ?               ; Temporary storage.
tmsg1	db	cr,lf,'[Connecting to host, type $' 
tmsg3	db	' C to return to PC]',cr,lf,cr,lf,cr,lf,'$'
tmsg2	db	cr,lf,'[Back at micro]',cr,lf,'$'
erms22	db	cr,lf,'?No capture file open$' ;[jd]
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'
	db	cr,lf,' S  Status of the connection'
	db	cr,lf,' B  Send a break'
	db	cr,lf,' M  Toggle mode line'
	db	cr,lf,' Q  Quit logging'
	db	cr,lf,' R  Resume logging'
	db	cr,lf,' 0  Send a null'
	db	cr,lf,' P  Push to a new command parser'
	db	cr,lf,' Typing the escape character will send it to the host'
	db	0

intprm	db	'Command>$'

CPTFCB	DB	25H DUP (?)
CAPBUF	DB	200 DUP (?)
CAPBP	DW	?
CAPLFT	DB	?

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	'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			; only consider 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
	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 on?
	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	; vt52 emulation?
	jz tel1
	or al,emheath
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.
	mov flags.modflg,1	; assume mode line is on
	test targ.flgs,modoff	; did someone turn it off?
	jz tem1			; no, go on
	mov flags.modflg,0	; yes, remember it's off
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
	xor targ.flgs,modoff	; toggle mode line
	xor flags.modflg,1	; toggle this one as well
	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
	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,128		; init buffer ptr & chrs left
	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	dx
	mov	ah,setdma
	mov	dx,offset capbuf	; the capture routine buffer
	int	dos
	mov	ah,writef
	mov	dx,offset cptfcb
	int	dos			; write out the block
;*** must be fixed... check error returns, disable capturing,
;*** figure out how to put dma address back
	mov	dx,offset buff
	mov	ah,setdma
	int	dos			; put dma back
	pop	dx
	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	al,caplft
	cmp	al,128			; is buffer empty?
	je	clscp2			; yes, forget this stuff
	call	cptdmp			; dump buffer (preserves registers)
clscp2:	mov	ah,0
	sub	word ptr cptfcb+16,ax	; subtract remaining from low filsize
	sbb	word ptr cptfcb+18,0	; and from high size (with borrow)
	mov	ah,closf
	mov	dx,offset cptfcb
	int	dos			; close up file
	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

