	name	msxgen
; File MSXGEN.ASM
	include mssdef.h
;       Copyright (C) 1982,1991, Trustees of Columbia University in the
;       City of New York.  Permission is granted to any individual or
;       institution to use, copy, or redistribute this software as long as
;       it is not sold for profit and this copyright notice is retained.
; Generic MS DOS Kermit module, does i/o via DOS calls.
; Use with file MSUGEN.ASM (Generic keyboard translator)
; Edit history
; 8 Sept 1991 version 3.11
; Last edit 8 Sept 1991
;
; Note: the biggest difficulty using this Generic Kermit is loss of one
; or two incoming characters when the screen must scroll. IBM PC's and
; relatives do this. If possible, replace the DOS screen write with faster
; calls specific to your system. Port i/o is polled through DOS.
 
	public	serini, serrst, clrbuf, outchr, coms, vts, vtstat, dodel
	public	ctlu, cmblnk, locate, lclini, prtchr, baudst, clearl
	public	getbaud, beep, trnprs, pcwait, termtb, trnmod, setnbios
	public	count, xofsnt, puthlp, putmod, clrmod, poscur
	public	sendbr, sendbl, term, machnam, setktab, setkhlp, showkey
	public	ihosts, ihostr, dtrlow, serhng, dumpscr, comptab
	public	chrout, cstatus, cquit, cquery, chang	; kbd action verbs
	public	snull, kdos, klogof, klogon, shomodem, getmodem, mdmhand
	public	portval, bdtab, setchtab, extmacro, vtmacname, vtmaclen
	public	fcsrtype, parmsk, flowon, flowoff, peekcom
	public	sescur, sesdisp

false	equ	0
true	equ	1
instat	equ	6
prtscr	equ	1			; screen printing active
 
data 	segment
	extrn	flags:byte, trans:byte, comand:byte, dmpname:byte
	extrn	npages:word, kbdflg:byte, rxtable:byte, rdbuf:byte
	extrn	prnhand:word, taklev:byte, takadr:word, mcctab:byte
	extrn	param:word, nparam:word
machnam	db	'Generic$'
erms41	db	cr,lf,'?Warning: Cannot open COM port$'
erms50	db	cr,lf,'Error reading from device$'
hnd1	db	cr,lf,'Enter a file handle.  Check your DOS manual if you are '
	db	cr,lf,'not certain what value to supply (generally 3).$'
hnd2	db	'Handle: ',0
hnderr	db	cr,lf,'Warning: Handle not known.'
deverr	db	cr,lf,'Any routine using the communications port will'
	db	cr,lf,'probably not work.$'
hndhlp	db	cr,lf,'A one or two digit file handle $'
devhlp	db	cr,lf,'Name for your systems auxillary port $'
badbd	db	cr,lf,'Unimplemented baud rate$'
noimp	db	cr,lf,'Command not implemented.$'
hngmsg	db	cr,lf,' The phone should have hungup.',cr,lf,'$'
hnghlp	db	cr,lf,' The modem control lines DTR and RTS for the current'
	db	' port are forced low (off)'
	db	cr,lf,' to hangup the phone. Normally, Kermit leaves them'
	db	' high (on) when it exits.'
	db	cr,lf,'$'
msmsg1	db	cr,lf,' Communications port is not ready.$'
msmsg2	db	cr,lf,' Communications port is ready.$'

shkmsg	db	'Not implemented'
shklen	equ	$-shkmsg
setktab	db	0
setkhlp	db	0
anspflg	db	0			; printing active status
vtmacname dw	0			; pointer to selected macro name
vtmaclen dw	0
sescur	dw	0
crlf    db      cr,lf,'$'
delstr  db      BS,BS,'  ',BS,BS,'$'	; Delete string
; If delete code moves cursor then BS over code, BS over bad char, space
; over both to erase from screen, BS twice to restore cursor position. 
argadr	dw	?		; address of arg blk from msster.asm
parmsk	db	0ffh		; 8/7 bit parity mask, for reception
flowoff	db	0		; flow-off char, Xoff or null (if no flow)
flowon	db	0		; flow-on char, Xon or null
captrtn	dw	0		; routine to call for captured output
xofsnt	db	0		; Say if we sent an XOFF
xofrcv	db	0		; Say if we received an XOFF
count	dw	0		; Number of chars in int buffer
fairness dw	0
mdmhand	db	0		; Modem status register, current
prthnd	dw	0		; Port handle
prttab	dw	com1,com2
com1	db	'COM1',0
com2	db	'COM2',0
temp	dw	0
prtstr	db	20 dup(0)	; Name of auxiliary device
 
portmax	equ	4		; number of predefined ports

port1	prtinfo	<0FFFH,0,defpar,1,0,defhand,floxon>
port2	prtinfo	<0FFFH,0,defpar,1,0,defhand,floxon>
port3 	prtinfo	<0FFFH,0,defpar,1,0,defhand,floxon>
port4	prtinfo	<0FFFH,0,defpar,1,0,defhand,floxon>
	rept	portmax-4
	prtinfo	<0FFFH,0,defpar,1,0,defhand,floxon>
	endm
portval	dw	port1			; Default is to use port 1

; Entries for choosing communications port
comptab	db	6			; Number of options
	mkeyw	'1',1
	mkeyw	'2',2
	mkeyw	'COM1',1
	mkeyw	'COM2',2
	mkeyw	'Device',3
	mkeyw	'File-handle',4
 
setchtab db	1			; Set File Character-Set table
	mkeyw	'CP437',437		; hardware default Code Page

bdtab	db	0			; baud rate table, number of entries

ourarg	termarg	<>

termtb	db	tttypes			; entries for Status, not Set
	mkeyw	'Heath-19',ttheath
	mkeyw	'none',ttgenrc
	mkeyw	'Tek4014',tttek
	mkeyw	'VT102',ttvt100		
	mkeyw	'VT52',ttvt52

oldsp	dw	0			; offset to longjmp to for i/o failure
endconptr	dw	offset endcon,seg endcon	; FAR pointer
vtmacroptr	dw	offset vtmacro,seg vtmacro	; FAR pointer
data	ends

code1	segment
; Control text cursor. AL = 0 for off, 1 for on (nominally underline)
fcsrtype proc	far
	ret				; can't do this from DOS
fcsrtype endp
code1	ends

code	segment
	extrn	comnd:near, dopar:near, atoi:near, prompt:near
	extrn	msuinit:near, keybd:near, pntchr:near, pntflsh:near
	extrn	dec2di:near
	assume	cs:code, ds:data, es:nothing

; Clear the input buffer. This throws away all the characters in the
; serial interrupt buffer.  This is particularly important when
; talking to servers, since NAKs can accumulate in the buffer.
; Do nothing since we are not interrupt driven.  Returns normally.
 
CLRBUF	PROC	NEAR
	cmp	prthnd,0		; got a port handle yet?
	jne	clrbu1			; ne = yes
	ret				; else just return
clrbu1:	call	prtchr			; read from comms port
	jnc	clrbu1			; nc = char available
	ret				; no data
CLRBUF	ENDP
 
; Clear to the end of the current line.  Returns normally.
 
CLEARL	PROC	NEAR
	push	ax
	push	dx
	mov	ah,prstr
	mov	dx,offset crlf
	int	dos
	pop	dx
	pop	ax
	ret
CLEARL	ENDP

shomodem proc	near
	mov	ah,cmeol		; get a confirm
	call	comnd
	jc	shmodx			; c = no confirm
	cmp	prthnd,0		; got a handle yet?
	jne	shmod0			; ne = yes, just go on
	call	opnprt			; else 'open' the port
shmod0:	mov	dx,offset msmsg1	; say port is not ready
	mov	bx,prthnd
	mov	al,7			; output status command
	mov	ah,ioctl		; ask DOS to look for us
	int	dos
	jc	shmod1			; c = call failed, device not ready
	or	al,al
	jz	shmod1			; z = not ready
	mov	dx,offset msmsg2	; say port is ready
shmod1:	mov	ah,prstr
	int	dos
	clc
shmodx:	ret
shomodem endp

getmodem proc near
	mov	al,0
	clc
	ret
getmodem endp

; Put the char in AH to the serial port.  This assumes the port has been
; initialized. Returns carry clear if success, else carry set if the
; character cannot be written.
 
OUTCHR	PROC	NEAR
	push	cx		; save regs
	or	ah,ah		; sending a null?
	jz	outch2		; z = yes
	xor	cx,cx		; clear counter
	cmp	ah,flowoff	; sending xoff?
	jne	outch1		; ne = no
	mov	xofsnt,false	; supress xon from chkxon buffer routine
outch1:	cmp	xofrcv,true	; are we being held?
	jne	outch2		; ne = no, it's OK to go on
	loop	outch1		; held, try for a while
	mov	xofrcv,false	; timed out, force it off and fall thru
outch2:	push	dx		; save register
	mov	al,ah		; parity routine works on AL
	call	dopar		; set parity appropriately
	mov	byte ptr temp,al ; put data there
	cmp	prthnd,0	; got a handle yet?
	jne	outch3		; ne = yes
	call	opnprt		; else 'open' the port
outch3:	push	bx
	mov	bx,prthnd	; port handle
	mov	cx,1		; one byte to write
	mov	dx,offset temp	; place where data will be found
	mov	ah,write2	; write to file/device
	int	dos
	pop	bx
	pop	dx
	pop	cx
	clc
	ret
OUTCHR	ENDP 

; This routine blanks the screen.  Returns normally.
 
CMBLNK	PROC	NEAR
	push	ax			; save some registers
	push	dx
	mov	ah,prstr
	mov	dx,offset crlf		; carriage return plus line feed
	pop	dx
	pop	ax 
	ret
CMBLNK	 ENDP
 
; Homes the cursor.  Returns normally.
 
LOCATE  PROC	NEAR
	mov	dx,0			; Go to top left corner of screen
	jmp	poscur
LOCATE  ENDP
 
; Write a line at the bottom of the screen
; the line is passed in dx, terminated by a $.  Returns normally.
putmod	proc	near
	push	dx		; preserve message
	mov	dx,1800h	; now address line 24
	call	poscur
	pop	dx		; get message back
	mov	ah,prstr
	int	dos		; write it out
	ret			; and return
putmod	endp
 
; clear the mode line written by putmod.  Returns normally.
clrmod	proc	near
	mov	dx,1800h
	call	poscur		; Go to bottom row
	call	clearl		; Clear to end of line
	ret
clrmod	endp
 
; Put a help message on the screen.  
; Pass the message in ax, terminated by a null.  Returns normally.
puthlp	proc	near
	push	dx		; save regs
	push	si
	push	ax		; preserve this
	mov 	ah,prstr
	mov 	dx,offset crlf
	int 	dos
	pop	si		; point to string again
	cld
puthl3:	lodsb			; get a byte
	cmp	al,0		; end of string?
	je	puthl4		; yes, stop
	mov 	dl,al
	mov	ah,dconio
	int	dos		; else write to screen
	jmp	puthl3		; and keep going
puthl4:	mov 	ah,prstr
	mov 	dx,offset crlf
	int 	dos
	pop	si
	pop	dx
	ret
puthlp	endp
 
; Set the baud rate for the current port, based on the value
; in the portinfo structure.  Returns normally.
 
BAUDST	PROC	NEAR
	mov	ah,prstr
	mov	dx,offset noimp		; Say it's not implemented
	int	dos
	push	bx			; save reg
	mov	bx,portval
	mov	[bx].baud,0FFFFH	; So it's not a recognized value
	pop	bx
	ret
BAUDST	ENDP
 
; Get the current baud rate from the serial card and set it
; in the portinfo structure for the current port.  Returns normally.
; This is used during initialization.
 
GETBAUD	PROC	NEAR
	stc
	ret				; Can't do this
GETBAUD	ENDP

; Use for DOS 2.0 and above.  Check the port status.  If no data, return
; carry set; else read a char into AL and return carry clear.
; Note added by [jrd]: The test for char-at-input-port is int 21h function
; 44h (ioctl) sub function 6 (get input status). On many systems an FFH will
; be reported (meaning Ready) even though no char is available; the Ready
; indication is misleading. In such cases the system will wait for a char
; and will appear to be hung. A preferrable method is to use the ROM Bios
; call int 14H function 3 (get port status) and if the lsb of the returned
; 8 bits in AH is 1 then a char is availble at the port; this assumes that
; the machine emulates this ROM Bios operation.
; Lastly, if the current code is used and the system hangs then reboot
; and say  ECHO Hello >COM1  before running Kermit; this should make MSDOS
; truely aware of the port's actual status. Dark grey magic. Good luck! [jrd]
PRTCHR	PROC    NEAR
	push	bx
	push	cx
	cmp	prthnd,0	; got a handle yet?
	jne	prtch0		; ne = yes
	call	opnprt		; else 'open' the port
prtch0:	call	chkxon
	mov	bx,prthnd
	mov	al,instat	; input status command
	mov	ah,ioctl	; see note above
	int	dos
	jc	prtch4		; c = call failed, device not ready
	or	al,al
	jz	prtch4		; not ready
	mov	bx,prthnd	; the file handle
	mov	ah,readf2	; read file/device
	mov	cx,1		; want just one character
	mov	dx,offset rdbuf	; where to store it
	int	dos
	jnc	prtch1		; nc = no error
	cmp	al,5		; Error condition
	je	prt3x
	cmp	al,6		; Error condition
	je	prt3x
	jmp	prtch4		; else report no char present
prtch1:	mov	dx,ax		; needed to obey rules
	or	ax,ax		; reading from end of file?
	jz	prtch4		; z = yes
	mov	al,rdbuf	; recover char
prtch3:	pop	cx
	pop	bx
	clc
	ret			; return success (char is in al)
prt3x:	mov	ah,prstr
	mov	dx,offset erms50
	int	dos
prtch4:	pop	cx
	pop	bx
	stc			; no chars
	ret
PRTCHR  ENDP
 
; Examine incoming communications stream for a packet SOP character.
; Return CX= count of bytes starting at the SOP character (includes SOP)
; and carry clear. Return CX = 0 and carry set if SOP is not present.
; Destroys AL.
peekcom proc far
	xor	cx,cx			; return count of zero
	stc				; say no data
	ret
peekcom endp

; Local routine to see if we have to transmit an xon
chkxon	proc	near
	push	bx
	mov	bx,portval
	cmp	[bx].floflg,0	; doing flow control?
	je	chkxo1		; no, skip all this
	cmp	xofsnt,false	; have we sent an xoff?
	je	chkxo1		; no, forget it
	mov	ax,[bx].flowc	; ah gets xon
	call	outchr		; send it
	mov	xofsnt,false	; remember we've sent the xon
chkxo1:	pop	bx		; restore register
	ret			; and return
chkxon	endp

; IHOSTS - Initialize the host by sending XON, or equivalent, and enter the
; cycle of clear input buffer, wait 1 second, test if buffer empty then exit
; else repeat cycle. Requires that the port be initialized before hand.
; Ihosts is used by the local send-file routine just after initializing
; the serial port.
; 22 March 1986 [jrd]

IHOSTS	PROC	NEAR
	push	ax		; save the registers
	push	bx
	push	cx
	push	dx
	mov	bx,portval	; port indicator
	mov	ax,[bx].flowc	; put Go-ahead flow control char in ah
	or	ah,ah		; don't send null if flow = none
	jz	ihosts1		; z = null
	call	outchr		; send it (release Host's output queue)
ihosts1:call	clrbuf		; clear out interrupt buffer
	call	prtchr		; check for char at port
	jnc	ihosts1		; nc=have a char in al, repeat wait/read cycle
	pop	dx    		; empty buffer. we are done here
	pop	cx
	pop	bx
	pop	ax
	ret
IHOSTS	ENDP

; IHOSTR - initialize the remote host for our reception of a file by
; sending the flow-on character (XON typically) to release any held
; data. Called by receive-file code just after initializing the serial
; port.		22 March 1986 [jrd]
IHOSTR	PROC	NEAR
	push	ax		; save regs
	push	bx
	push	cx
	mov	bx,portval	; port indicator
	mov	ax,[bx].flowc	; put Go-ahead flow control char in ah
	or	ah,ah		; don't send null if flow = null
	jz	ihostr1		; z = null
	call	outchr		; send it (release Host's output queue)
ihostr1:pop	cx
	pop	bx
	pop	ax
	ret
IHOSTR	ENDP

DTRLOW	PROC	NEAR		; Global proc to Hangup the Phone by making
				; DTR and RTS low
	mov	ah,cmline	; allow text to be able to display help
	mov	bx,offset rdbuf		; dummy buffer
	mov	dx,offset hnghlp	; help message
	call	comnd			; get a confirm
	jc	dtrlowx
; not yet imp.	call serhng		; drop DTR and RTS
	mov	ah,prstr		; give a nice message
; not yet imp.	mov dx,offset hngmsg
	mov	dx,offset noimp		; for now
	int	dos
	clc
dtrlowx:ret
DTRLOW	ENDP
 
; Hang up the Phone. Similar to SERRST except it just forces DTR and RTS low
; to terminate the connection. 29 March 1986 [jrd]
; Calling this twice without intervening calls to serini should be harmless.
; Returns normally.
; SERHNG is Not Yet Implemented.

SERHNG	PROC NEAR
	clc
	ret
SERHNG	ENDP

; Wait for the # of milliseconds in ax, for non-IBM compatibles.
; Based on 4.77 Mhz 8088 processor speeds.
; Thanks to Bernie Eiben for this one.
pcwait	proc	near
	mov	cx,240		; inner loop counter for 1 millisecond
pcwai1:	sub	cx,1		; inner loop takes 20 clock cycles
	jnz	pcwai1
	dec	ax		; outer loop counter
	jnz	pcwait		; wait another millisecond
	ret
pcwait	endp


; Send a break out the current serial port.  Returns normally.
SENDBR	PROC	NEAR			; Normal Break
	clc
	ret
SENDBR	ENDP
SENDBL	PROC	NEAR			; Long Break
	clc
	ret
SENDBL	ENDP
 
; Position the cursor according to contents of DX:
; DH contains row, DL contains column.  Returns normally.
POSCUR	PROC	NEAR
	clc
	ret
POSCUR	ENDP
 
; Delete a character from the terminal.  This works by printing
; backspaces and spaces.  Returns normally.
 
DODEL	PROC	NEAR
	mov	ah,prstr
	mov	dx,offset delstr	; Erase character
	int	dos			
	ret
DODEL	ENDP
 
; Move the cursor to the left margin, then clear to end of line.
; Returns normally.
 
CTLU	PROC	NEAR
	push	ax
	push	cx
	push	dx
	mov	ah,conout
	mov	dl,cr			; cursor to left margin
	int	dos
	mov	cx,79
	mov	dl,' '			; send 79 spaces to clear line
ctlu1:	int	dos
	loop	ctlu1
	mov	dl,cr			; cursor to left margin again
	int	dos
	pop	dx
	pop	cx
	pop	ax
	ret
CTLU	ENDP
 
; Set the current port.  
 
COMS	PROC	NEAR
	mov	dx,offset comptab	; the table to examine
	xor	bx,bx			; use keywords as help
	mov	ah,cmkey		; parse keyword from comptab
	call	comnd
	jc	comsx			; c = no match
	cmp	bl,3			; set device name?
	je	coms3			; e = yes, go get name
	jbe	coms1a			; be = 1 or 2
	jmp	coms4			; a = pick up file handle
coms1a:	push	bx
	mov	ah,cmeol
	call	comnd
	pop	bx
	jc	comsx			; failure
	mov	flags.comflg,bl		; set the comm port flag
	cmp	bl,1			; using Com 1?
	jne	coms2			; ne = no
	mov	portval,offset port1
	ret
coms2:	cmp	flags.comflg,2		; using Com2?
	jne	coms3			; ne = no
	mov	portval,offset port2
	clc
comsx:	ret
coms3:	mov	ah,cmword		; parse string, returns asciiz string
	mov	dx,offset prtstr	; put name here
	mov	bx,offset devhlp	; help message if question mark
	call	comnd
	jc	comsx			; c = error
	mov	ah,cmeol
	call	comnd
	jc	comsx
	mov	dx,offset prtstr	; point to string
	mov	ah,open2		; open port as a file
	mov	al,2			; for reading and writing
	int	dos
	jc	coms31			; c = failure
	mov	portval,offset port3	; port info structure
	mov	flags.comflg,3		; set port ident
	jmp	short coms32		; success
coms31:	mov	ah,prstr
	mov	dx,offset erms41
	int	dos
	mov	dx,offset deverr
	int	dos
	clc
	ret
coms32:	mov	prthnd,ax		; save handle
	mov	ah,ioctl
	mov	al,00h			; get device info
	xor	dx,dx
	mov	bx,prthnd		; port's handle
	int	dos
	jc	coms41			; c = error
	or	dl,20h			; set binary mode in device info
	mov	dh,0
	mov	ah,ioctl		
	mov	al,01h			; set device info
	int	dos
	jc	coms41			; c = error
	ret
coms4:	mov	ah,cmword
	mov	dx,offset rdbuf		; where to put input
	mov	bx,offset hndhlp	; in case user wants help
	call	comnd
	jc	coms42
	push	ax
	mov	ah,cmeol
	call	comnd
	pop	ax
	jc	coms42			; failure
	mov	si,offset rdbuf
	call	atoi			; convert to real number in ax
	jc	coms42			; c = failure
	mov	portval,offset port4	; port info structure
	mov	flags.comflg,4		; set port ident
	jmp	coms32			; go complete processing
coms41:	mov	ah,prstr		; else, issue a warning
	mov	dx,offset hnderr
	int	dos
	clc
coms42:	ret
COMS	ENDP
 
; Set heath emulation on/off.
 
VTS	PROC	NEAR
	jmp	notimp			; not implemented
VTS	ENDP


VTSTAT	PROC	NEAR			; for Status display
	ret				; no emulator status to display
VTSTAT	ENDP 

; Save the screen to a buffer and then append buffer to a disk file. [jrd]
; Default filename is Kermit.scn; actual file can be a device too. Filename
; is determined by mssset and is passed as pointer dmpname.

DUMPSCR	PROC	NEAR	; Dumps screen contents to a file. Just Beeps here
	call	beep
	clc
	ret
DUMPSCR	ENDP
 
notimp:	mov	ah,prstr
	mov	dx,offset noimp
	int	dos
	stc
	ret
 
; Initialize variables to values used by the generic MS DOS version.
 
lclini:	mov	flags.vtflg,0		; don't do terminal emulation
	mov	prthnd,0		; no handle yet
	mov	flags.remflg,dserial 	; set serial display mode
;;	call	opnprt			; get file handle for comm port
	call	msuinit			; declare keyboard translator present
	ret
 
; Get a file handle for the communications port.  Use DOS call to get the
; next available handle.  If it fails, ask user what value to use (there
; should be a predefined handle for the port, generally 3).  The open
; will fail if the system uses names other than "COM1" or "COM2".
opnprt:	mov	al,flags.comflg
	dec	al			; com1 is 1, com2 is 2, etc
	xor	ah,ah
	push	si
	mov	si,ax
	shl	si,1			; double index
	mov	dx,prttab[si]		; table of port names
	pop	si
	mov	ah,open2		; open file/device
	mov	al,2			; for reading/writing
	int	dos
	jnc	opnpr2			; nc = no error so far
	mov	ah,prstr		; It didn't like the string
	mov	dx,offset erms41
	int	dos
	mov	dx,offset hnd1
	int	dos
	mov	dx,offset hnd2		; ask user for the handle
	call	prompt					   
	mov	ah,cmline
	mov	bx,offset rdbuf		; where to put input
	mov	dx,offset hndhlp	; in case user wants help
	call	comnd
	jc	opnpr1			; c = error
	mov	si,offset rdbuf
	xchg	ah,al			; count to ah
	call	atoi			; convert to real number
	jc	opnpr1			; c = error
	mov	prthnd,ax		; value returned in AX
	clc				; carry clear for success
opnpr1:	ret
opnpr2:	mov	prthnd,ax		; call succeeded
	mov	ah,ioctl
	mov	al,00h			; get device info
	xor	dx,dx
	mov	bx,prthnd		; port's handle
	int	dos
	or	dl,20h			; set binary mode in device info
	mov	dh,0
	mov	ah,ioctl
	mov	al,1			; set device info
	int	dos
	clc
	ret				; carry clear for success
 
showkey:mov	ax,offset shkmsg
	mov	cx,shklen
	ret
	
; Initialization for using serial port.  Returns normally.
; Attempts to put port device in binary mode. [jrd]
SERINI	PROC	NEAR
	cmp	prthnd,0		; got a handle yet?
	jne	serin0			; ne = yes, just go on
	push	bx
	call	opnprt			; else 'open' the port
	pop	bx
	jc	serin2			; c = failure
serin0:	push	bx
	mov	bx,portval		; get port
	mov	parmsk,0ffh		; parity mask, assume parity is None
	cmp	[bx].parflg,parnon	; is it None?
	je	serin1			; e = yes
	mov	parmsk,07fh		; no, pass lower 7 bits as data
serin1:	mov	bx,[bx].flowc		; get flow control chars
	mov	flowoff,bl		; xoff or null
	mov	flowon,bh		; xon or null
	pop	bx
	clc				; carry clear for success
serin2:	ret
SERINI	ENDP
 
; Reset the serial port.  This is the opposite of serini.  Calling
; this twice without intervening calls to serini should be harmless.
; Returns normally.
 
SERRST	PROC	NEAR
	clc
	ret
SERRST	ENDP
 
; Produce a short beep.  The PC DOS bell is long enough to cause a loss
; of data at the port.  Returns normally.
 
BEEP	PROC	NEAR
	mov	dl,bell
	mov	ah,dconio
	int	dos
	clc
	ret
BEEP	ENDP 
 
; Dumb terminal emulator.  Doesn't work too well above 1200 baud (and
; even at 1200 baud you sometimes lose the first one or two characters
; on a line). Does capture (logging), local echo, debug display, tests
; for printer/logging device not ready. Uses keyboard translator
; 20 March 1987 [jrd]. 
term	proc	near
	mov	argadr,ax		; save argument ptr
	mov	si,ax			; this is source
	mov	oldsp,sp		; remember stack for i/o failure,
	mov	di,offset ourarg	; place to store arguments
	mov	ax,ds
	mov	es,ax			; address destination segment
	mov	cx,size termarg
	cld
	rep	movsb			; copy into our arg blk
	mov	ax,ourarg.captr
	mov	captrtn,ax		; buffer capture routine
	mov	parmsk,0ffh		; parity mask, assume parity = None
	cmp	ourarg.parity,parnon	; is parity None?
	je	term1			; e = yes, keep all 8 bits
	mov	parmsk,07fh		; else keep lower 7 bits

term1:	call	portchr		       ; get char from port, apply parity mask
	jnc	short term3		; nc = char
term2:	mov	fairness,0		; say kbd was examined
	call	keybd			; call keyboard translator in msu
	jnc	term1			; nc = no char or have processed it
	call	pntflsh			; flush printer buffer
	stc
	ret				; carry set = quit connect mode
term3:	and	al,parmsk		; apply 8/7 bit parity mask
	call	outtty			; print on terminal
	inc	fairness		; say read port but not kbd, again
	cmp	fairness,200		; this many port reads before kbd?
	jb	term1			; b = no, read port again
	call	pntflsh			; flush printer buffer
	jmp	short term2		; yes, let user have a chance too
quit:	ret
term	endp

; keyboard translator action routines, system dependent, called from msugen.
; These are invoked by a jump instruction. Return carry clear for normal
; processing, return carry set exit Connect mode (kbdflg has transfer char).

chrout: call	outprt			; put char in al to serial port
	clc				; stay in Connect mode
	ret

trnprs:	push	ax			; toggle Copy screen to printer
	test	anspflg,prtscr		; should we be printing?
	jnz	trnpr2			; nz = yes, its on and going off
	mov	ah,ioctl
	mov	al,7			; get output status of printer
	push	bx
	mov	bx,prnhand		; file handle for system printer
	int	dos
	pop	bx
	jc	trnpr1			; c = printer not ready
	cmp	al,0ffh			; Ready status?
	je	trnpr2			; e = Ready	
trnpr1:	call	beep			; Not Ready, complain
	jmp	short trnpr3		; and ignore request
trnpr2:	xor	anspflg,prtscr		; toggle print flag
trnpr3:	pop	ax
	clc
	ret

; toggle Connect mode status line
trnmod	proc	near
	ret
trnmod	endp

klogon	proc	near			; resume logging (if any)
	test	flags.capflg,logses	; session logging enabled?
	jz	klogn			; z = no, forget it
	or	ourarg.flgs,capt	; turn on capture flag
klogn:	clc
	ret
klogon	endp

klogof	proc	near			; suspend logging (if any)
	and	ourarg.flgs,not capt	; stop capturing
klogo:	clc
	ret
klogof	endp

snull:	mov	ah,0			; send a null
	call	outchr			; send without echo or logging
	clc
	ret

kdos:	mov	al,'P'			; Push to DOS
	jmp	short cmdcom
cstatus:mov	al,'S'			; these commands exit Connect mode
	jmp	short cmdcom
cquit:	mov	al,'C'
	jmp	short cmdcom
cquery:	mov	al,'?'
	jmp	short cmdcom
chang:	mov	al,'H'			; Hangup, drop DTR & RTS
;;;	jmp	short cmdcom
cmdcom:	mov	kbdflg,al		; pass char to msster.asm via kbdflg
	stc				; say exit Connect mode
	ret
					;; end of action routines

; put the character in al to the screen, do capture and printing,
; does translation for Set Input command.
; Adapted from msyibm.asm
outtty	proc	near
	test	flags.remflg,d8bit	; keep 8 bits for displays?
	jnz	outnp8			; nz = yes, 8 bits if possible
	and	al,7fh			; remove high bit
outnp8:	cmp	rxtable+256,0		; is translation off?
	je	outnp7			; e = yes, off
	push	bx			; Translate incoming char
	mov	bx,offset rxtable	; address of translate table
	xlatb				; new char is in al
	pop	bx
outnp7:	test	ourarg.flgs,capt	; capturing output? Can be shut off
	jz	outnoc			; no, forget this part
	call	captrtn			; give it captured character
outnoc:	test	anspflg,prtscr		; should we be printing?
	jz	outnop			; no, keep going
	call	pntchr			; queue char for printer
	jnc	outnop			; nc = successful print
	push	ax
	call	beep			; else make a noise and
	call	trnprs			;  turn off printing
	pop	ax
outnop:	cmp	flags.vtflg,0		; emulating a terminal?
	jnz	outnop1			; nz = yup, go do something smart
	test	ourarg.flgs,trnctl	; debug? if so use dos tty mode
	jz	outnp4			; z = no
	mov	ah,conout
	cmp	al,7fh			; Ascii Del char or greater?
	jb	outnp1			; b = no
	je	outnp0			; e = Del char
	push	ax			; save the char
	mov	dl,7eh			; output a tilde for 8th bit
	int	dos
	pop	ax			; restore char
	and	al,7fh			; strip high bit
outnp0:	cmp	al,7fh			; is char now a DEL?
	jne	outnp1			; ne = no
	and	al,3fH			; strip next highest bit (Del --> '?')
	jmp	outnp2			; send, preceded by caret
outnp1:	cmp	al,' '			; control char?
	jae	outnp3			; ae = no
	add	al,'A'-1		; make visible
outnp2:	push	ax			; save char
	mov	dl,5eh			; caret
	int	dos			; display it
	pop	ax			; recover the non-printable char
outnp3:	mov	dl,al
	int	dos
	ret
outnp4:	cmp	al,bell			; bell (Control G)?
	jne	outnp5			; ne = no
	jmp	beep			; use short beep, avoid char loss
outnop1:
outnp5:	test	flags.remflg,d8bit	; keep 8 bits for displays?
	jnz	outnp9			; nz = yes, 8 bits if possible
	and	al,7fh			; remove high bit
outnp9:	mov	ah,conout		; dostty screen mode
	mov	dl,al			; write without intervention
	int	dos			; else let dos display char
	ret				; and return
outtty	endp


; send the character in al out to the serial port; handle echoing.
; Can send an 8 bit char while displaying only 7 bits locally.
outprt	proc	near
	test	ourarg.flgs,lclecho	; echoing?
	jz	outpr1			; z = no, forget it
	push	ax			; save char
	call	outtty			; print it
	pop	ax			; restore
outpr1:	mov	ah,al			; outchr expects char in ah
	jmp	outchr			; output to the port
outprt	endp

; Get a char from the serial port manager, return it in al
; returns with carry clear if a character is available, else carry set
portchr	proc	near
	call	prtchr			; character at port?
	jnc	portc1			; nc = yes
portc0:	stc				; carry -> no character
	ret
portc1:	and	al,parmsk		; apply 8/7 bit parity mask
	or	al,al			; catch nulls
	jz	portc0			; z = null, ignore it
	cmp	al,del			; catch dels
	je	portc0			; e = del, ignore it
portc2:	clc				; have a character, in AL
	ret
portchr	endp

; Invoked by keyboard translator when an unknown keyboard verb is used as
; a string definition, such as {\ktest}. Enter with vtmacname pointing to
; uppercased verb name, asciiz, and vtmaclen set to its length.
extmacro proc	near
	call	dword ptr vtmacroptr	; FAR pointer
	ret
extmacro endp

fdec2di	proc	far
	call	dec2di
	ret
fdec2di	endp
code	ends

code1	segment
	assume	cs:code1


;
; Reference	Macro structure for	db	number of entries (mac names)
;  is file	 table mcctab	   |->	dw	length of macroname
;  mssset.asm		each entry |-> 	db	'macroname'
;  where these			   |->	dw	segment:0 of definition string
;  are stored.					  (offset part is always 0)	
;		Definition string in 	db	length of <string with null>
;		 buffer macbuf	  	db	'string with trailing null'
;
vtmacro	proc	far			; common code for external macro
	push	bx
	push	cx
	push	si
	push	di
	push	es
	mov	ax,ds
	mov	es,ax
	mov	di,offset rdbuf+2	; macro def buffer starts here
	mov	si,vtmacname		; pointer to macro name
	mov	cx,vtmaclen		; length of macro name<sp/null>text
	mov	[di-2],cx		; counted string field
	cld
	rep	movsb			; copy to rdbuf
	mov	byte ptr [di],0		; null terminator
	mov	si,offset rdbuf+2	; look for name-text separator
	mov	cx,vtmaclen
vtmac1:	lodsb
	cmp	al,' '			; space separator?
	je	vtmac1a			; e = yes, stop here
	or	al,al			; null terminator?
	jz	vtmac1a			; e = yes, stop here
	loop	vtmac1
	inc	si			; to do null length correctly
vtmac1a:sub	si,offset rdbuf+2+1	; compute length of macro name
	mov	cx,si
	mov	vtmaclen,cx		; save a macro name length
					; check for existence of macro
	mov	bx,offset mcctab	; table of macro names
	mov	cl,[bx]			; number of names in table
	xor	ch,ch
	jcxz	vtmacx			; z = empty table, do nothing
	inc	bx			; point to length of first name
vtmac2:	mov	ax,[bx]			; length of this name
	cmp	ax,vtmaclen		; length same as desired keyword?
	jne	vtmac3			; ne = no, search again
	mov	si,bx
	add	si,2			; point at first char of name
	push	cx			; save name counter
	push	di			; save reg
	mov	cx,vtmaclen		; length of name
	mov	di,vtmacname		; point at desired macro name
	push	es			; save reg
	push	ds
	pop	es			; make es use data segment
	cld
	repe	cmpsb			; match strings
	pop	es			; need current si below
	pop	cx
	pop	di			; recover saved regs
	je	vtmac4			; e = matched
vtmac3:	add	bx,ax			; step to next name, add name length
	add	bx,4			; + count and def word ptr
	loop	vtmac2			; try next name
vtmacx:	pop	es
	pop	di
	pop	si			; no macro, return to Connect mode
	pop	cx
	pop	bx
	ret

vtmac4:	cmp	taklev,maxtak		; room in Take level?
	jge	vtmacx			; ge = no, exit with no action
	inc	taklev			; increment take level
	add	takadr,size takinfo	; make a new Take entry/macro
	mov	bx,takadr		; point to current macro structure
	mov	ax,ds			; segment of rdbuf
	mov	[bx].takbuf,ax		; segment of definition string struc
	mov	cx,word ptr rdbuf	; length of count + string
	mov	[bx].takcnt,cx		; number of chars in definition
	mov	[bx].takargc,0		; our argument count
	mov	[bx].takptr,offset rdbuf+2 ; where to read next command char
	mov	[bx].taktyp,0ffh	; flag as a macro
	pop	es
	pop	di
	pop	si
	pop	cx
	pop	bx
	jmp	dword ptr endconptr	; exit Connect mode
vtmacro	endp
code1	ends

code	segment
	assume	cs:code

; Error recovery routine used when outchr reports unable to send character
;  or when vtmacro requests exiting Connect mode.
; Exit Connect mode cleanly, despite layers of intermediate calls.
endcon	proc	near
	mov	kbdflg,'C'		; report 'C' to TERM's caller
	mov	sp,oldsp		; recover startup stack pointer
					; TERM caller's return address is now
					; on the top of stack. A longjmp.
	jmp	quit			; exit Connect mode cleanly
endcon	endp

; Service SET NETBIOS-NAME name   command at Kermit prompt level
setnbios proc	near
	ret
setnbios endp
sesdisp	proc	near
	ret
sesdisp	endp

code	ends 
	end
