       name msxgri
; File MSXGRI.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.
; Grid Compass dependent file for MS-DOS Kermit
;  Use with msugri.asm keyboard translator file.
; Edit history
; 2 March 1991 version 3.10
; Last edit:
; 2 March 1991
; Dec.	7, 1990. Put modem in verbose mode at startup.
;  Change machnm from GRID to GRiD. 
; Nov. 27, 1990. Add call to getbaud in serini.
; Nov. 24, 1990. Remove reference to prserr to make link happy.
; Nov. 21, 1990. Fix so both serial and modem drivers need not be loaded 
;  if they are not used. [jan]
; October 1990. Cosmetic fixes.
; August 1990. Select tek enable/ disable in termtb
; 22 february 1990 Fix up baud setting and and string parsing
; procedurs [jan]
; 23 January 1990. Version 3. Fix up comnd calls. Chance PRTCHR so
; clc for character, stc for no character. clc in OUTPRT. Include
; baud table and portval. Add BAUDST from MSXIBM.ASM. Zap DODISK. [jan]
; 3 February 1989.
; Call "call cmblnk" call call to tekcls so tek screen is cleared
;  even if it's not initialized
;  Take out II in machnm since this also works on 1101 [jan]
; 5 January 1989. Fix up SERINT, SERINI, SERRST, and SENDBR.
; Implement GETMODEM and SERHNG.  Send 'ATE1' to modem in LCLINI. [jan]
; 13 Dec 1988 Move screen clear and terminal type toggling to this file.
;  Do other small cleanups. [jrd]
;
; John Nyenhuis	  Purdue University  School of Electrical Engineering
; West Lafayette IN 47907   (317)494-3524     nyenhuis@ecn.purdue.edu
; November 1988
; Fix up for Tektronix emulation
; User can specify screen size by set term 112x or set term 113x
; Call sbrk to get memory for Tektronix and ascii screen saves
; enable automatic entry into Tektronix emulator
; Most characters are now written to screen through bios rather than with DOS
; keyboard is checked once each 8 read of serial port for added speed
; Xon/Xoff flow control enabled
; vt52 terminal emulation taken out (all it did was to not restore the cursor)
;
; 1 July 1988 Version 2.31
; 12 June 1988 Add error recovery if serial port fails to initialize, reduce
;  serial port buffer to 1000 bytes. [jrd]
; 11 Jan 1988 Add 2.30 features. [jrd]
; 1 Jan 1988 version 2.30
;
; Jim Noble
; Planning Research Corporation
; 1500 Planning Research Drive
; Mail Stop 5S3
; McLean, VA  22102
; May, 1985
; Add global entry point vtstat for use by Status in mssset.
; Added register save/restore in procedure getbaud.
; Joe R. Doupnik 12 March 1986
; Add global procedures ihosts and ihostr to handle host initialization
; when packets are to be sent or received by us,resp. 24 March 1986
; Add global procedure dtrlow (without worker serhng) to force DTR & RTS low
; in support of Kermit command Hangup. Says Not Yet Implemented. [jrd]
; Add global procedure Dumpscr, called by Ter in file msster, to dump screen
;  to a file. Just does a beep for now. 13 April 1986 [jrd]
; In proc Outchr add override of xon from chkxon sending routine.
;  This makes a hand typed Xoff supress the xon flow control character sent
;  automatically as the receiver buffer empties. 20 April 1986 [jrd]


saveregs macro
      push  ax
      push  bx
      push  cx
      push  dx
      push  es
      push  di
      push  si
      push  ds
      pushf
endm

restoreregs  macro
     popf
     pop   ds
     pop   si
     pop   di
     pop   es
     pop   dx
     pop   cx
     pop   bx
     pop   ax
endm

;; below 40 publics are the minimum necessary
       public  baudst,ihostr,bdtab,getbaud,chrout
       public  pcwait,putmod,serrst,trnprs,prtchr
       public  poscur,outchr,dtrlow,vts,puthlp
       public	vtstat,coms,cquery,ctlu,shomodem
       public  portval,getmodem,term,dumpscr,cmblnk
       public  cquit,locate,clearl,machnam,lclini
       public  sendbl,comptab,sendbr,clrmod,cstatus
       public  termtb,serhng,clrbuf,beep, serini
;;additional system dependent publics
	public	klogon,kdos,snull,klogof
	public bigscreen		; bigscreen=1 if it's big [jan]
	public	termtog			; toggle terminal types [jan]
	public	kclrscn, getflgs, setchtab

cmcfm	equ	cmeol		   ; equates to account for 3.0
cmtxt	equ	cmline		   ; names changes in
cmfile	equ	cmword		   ; mssdef.h

baudsiz equ	18		    ; entries in baud table
false	equ	0
true	equ	1
print_out equ	05h			; dos function to print to printer
prtscr	equ	80h			; print screen pressed

gbuflen equ	1000		; max bytes grid internal buffer holds
mntrgh	equ	gbuflen/2	; High point = 1/2 of buffer full.
mntrgl	equ	gbuflen/4	 ; Low point = 1/4 buffer full. [jrd]

CLK_INT equ	1ch*4		; clock interrupt
gserial equ	81h		; grid serial port interrupt
gmodem	equ	82h		; grid modem port interrupt
ginit	equ	0		; function 0 - initialize port
gread	equ	1		; function 1 - read data
gwrite	equ	2		; function 2 - write data
gwcmd	equ	4		; function 4 - write command
grstat	equ	5		; function 5 - read status
gflush	equ	6		; function 6 - buffer flush
ggbaud	equ	7		; function 7 - get baud
gsbaud	equ	8		; function 8 - set baud
gspar	equ	9		; function 9 - set parity
gsdata	equ	10		; function 10 - set data bits
gssbit	equ	11		; function 11 - set stop bits
gbufass equ	12		; function 12 - buffer assign
gcharto equ	13		; function 13 - set character timeout
gcts	equ	19		; function 19 - clear to send timeout
gbrkon	equ	0effH		; function 14 - set break on
gbrkoff equ	0e00H		; function 14 - set break off
scnstrt equ	400h		; starting address of screen area (page 0)
maxscnwrds equ	   256*32	; max number of words in screen memory area
tekonnum equ 18			; enable tek auto entry
tekoffnum  equ 19
ttbig	equ	12		;big screen
ttsmall equ    23		;small screen

data   segment public 'data'
	extrn	flags:byte, trans:byte

	extrn dmpname:byte
	extrn	kbdflg:byte, rxtable:byte
	extrn	tekflg:byte		; used in msggri  [jan]
	extrn	denyflg:word		; controls tek autoentry etc
	extrn	dosnum:word
	extrn	repflg:byte, diskio:byte  ; for replay feature
	extrn	kbdflg:byte  ;	in telnet


; structure for status information table sttab.
stent	struc
sttyp	dw  ?	   ; type (actually routine to call)
msg	dw  ?	   ; message to print
val2	dw  ?	   ; needed value: another message, or tbl addr
tstcel	dw  ?	   ; address of cell to test, in data segment
basval	dw  0	   ; base value, if non-zero
stent	ends

   ; table with datacomm status for the status command
vtstbl stent <srchkw,tekstatustxt,termtb,tekbyte> ; tell tek able/disable
       stent <srchkw,screenstatustxt,termtb,screenbyte> ; tell screen size
   dw 0	   ; end of table



tekstatustxt db 'Tek Auto Entry: $'
tekbyte db tekonnum		; tek auto entry code
screenstatustxt db 'Screen Size: $'
screenbyte db ttsmall
prtrdy	db	true	      ; when false, exit connect mode
machnam db	'GRiD_COMPASS$'
msmsg1	db	cr,lf,'  Modem is not ready: DSR is off$'
msmsg2	db	cr,lf,'  Modem is ready:     DSR is on$'
msmsg3	db	cr,lf,'  no Carrier Detect:  CD  is off$'
msmsg4	db	cr,lf,'  Carrier Detect:     CD  is on$'
msmsg5	db	cr,lf,'  no Clear To Send:   CTS is off$'
msmsg6	db	cr,lf,'  Clear To Send:      CTS is on$'
msmsg7	db	cr,lf,'  Modem is not used by the Network$'


mdmhand		db	0		;used by showmodem
mdmstr		db   'ATE1Q0V1S7=25,',cr,lf	 ;init modem string
mdmstrlen	equ   $-mdmstr		;length of modem string

;;new stuff to scan escape sequences from comm port  [jan]
stringtab	dw    tekst1,tekst2	; strings for matching
numstrings	equ   2			; number of strings to match
disptab		dw    toteknoplay,totekplay	  ; dispatch table
tekst1		db    escape,'[?38h',0	;1st string to get into tek mode [jan]
tekst2		db    escape,FF,0	;2nd string to get into tek mode [jan]

stringchekbuff	   db	 16 dup (0)
stringchekcnt	   dw	 0		   ;characters already in buffer
matchsofar	dw    false		; no match yet
match		dw    0
playem		db    false		;don't play back switch characters
; end of data for string scanning


scnwrds		dw    240*20		;words in small screen [jan]
scrsavseg	dw    ?			;segment for screen save [jan]
bigscreen	db    0			;=1 for big [jan]
prevport	db    86		;port number on previous connect
portbusy	db    0			;serial port not yet busy
save_ax		dw    ?			;temp location to save ax
save_ds		dw    ?			;temp location to save ds
curini	db	0			; [gaw@prc]
cursav	db	ESCAPE,'[s','$'		; [gaw@prc]
curres	db	ESCAPE,'[u','$'		; [gaw@prc]
curon	db	ESCAPE,'[3;3z','$'	; [gaw@prc]
curoff	db	ESCAPE,'[3;4z','$'	; [gaw@prc]

erms20	db	cr,lf,'?Warning: System has no disk drives$'
erms40	db	cr,lf,'?Warning: Unrecognized baud rate$'
badbd	db	cr,lf,'Unimplemented baud rate$'
crlf	db	cr,lf,'$'
comphlp db	cr,lf,'1 (SERIAL)  2 (MODEM)$'		; [19b] [gaw@prc]
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,'$'
rdbuf	db	80 dup (?)	; temp buf
noimp	db	cr,lf,'?Not implemented.$'
delstr	db	BS,' ',BS,'$'	; Delete string
clrlin	db	cr,ESCAPE,'[0K','$'
portin	db	0		; has clock int vector been initialized?
xofsnt	db	0		; Say if we sent an XOFF.
xofrcv	db	0		; Say if we received an XOFF.
insrvc	db	false		    ; Say if in service on XON/XOFF interrupt
parmsk	db	?		; parity mask, 0ffh for no parity, 07f with.
flowoff db	?		; flow-off char, Xoff or null (if no flow)
flowon	db	?		; flow-on char, Xon or null
captrtn dw	?		; routine to call for captured output
invseq	db	ESCAPE,'[7m$'	; Reverse video.
nrmseq	db	ESCAPE,'[0m$'	; Normal mode.
ivlseq	db	79 dup (' '),cr,'$'	; Make a line inverse video
tmp	db	?,'$'
temp	dw	0
temp1	dw	?		; Temporary storage.
temp2	dw	?		; Temporary storage.
fncerr	db	cr,lf,'Error on function '
fnctype db	'X with a status return of '
fncstat db	'Y$'
argadr	dw	?		; address of arg blk

; key redefinitions
setktab db	0

setkhlp db	0

; Entries for choosing communications port.

comptab db	2		; number of entries
	mkeyw	'Serial',1
	mkeyw	'Modem',2



setchtab  db   1; set file character-set table
  mkeyw	  'CP437',437


termtb	db	6
	mkeyw	'112x',ttsmall
	mkeyw	'113x',ttbig
	mkeyw	'ANSI',ttgenrc
	mkeyw	'Tek4010',tttek
	mkeyw	'EnableTek',tekonnum
	mkeyw	'DisableTek', tekoffnum
defbaud	 equ 7	     ; defauld baud rate is 1200


port1	prtinfo <defbaud,0,defpar,1,0,defhand,floxon,0>
port2	prtinfo <defbaud,0,defpar,1,0,defhand,floxon,0>


portval dw	port1			; Default is to use port 1

bdtab	db	16			; Baud rate table

	mkeyw	'50',0
	mkeyw	'75',1
	mkeyw	'110',2
	mkeyw	'134',3
	mkeyw	'150',4
	mkeyw	'300',5
	mkeyw	'600',6
	mkeyw	'1200',7
	mkeyw	'1800',8
	mkeyw	'2000',9
	mkeyw	'2400',10
	mkeyw	'3600',11
	mkeyw	'4800',12
	mkeyw	'7200',13
	mkeyw	'9600',14
	mkeyw	'19200',15

modbdtab  db  2			 ; baud entries legal for modem
       mkeyw   '300',5
       mkeyw   '1200',7



; variables for serial interrupt handler

gbuffer db	gbuflen DUP(?)	; large internal buffer for grid [gaw@prc]

source	db	bufsiz DUP(?)	; Buffer for data from port
bufout	dw	0		; buffer removal ptr
count	dw	0		; Number of chars in int buffer
bufin	dw	0		; buffer insertion ptr
telflg	db	0		; Are we acting as a terminal
clreol	db	ESCAPE,'[0K$'
blank	db	ESCAPE,'[2J$'
movcur	db	ESCAPE,'['
colno	db	20 dup (?)
ten	db	10
ourarg	termarg <>
keydelay dw	0		;for periodically checking the keyboard
clkdelay dw	0		;check flow control every 4th tick
serclk	 db	false		;clock interrupt resets-for xon/xoff
charout dd	?		; pointer to direct screen write [jan]

savclko dw	?		; save clock tick interrupt vector offset
savclks dw	?		; save clock tick interrupt vector segment


data   ends

code	segment public 'code'
	extrn	comnd:near, dopar:near, defkey:near
	extrn	sleep:near, msuinit:near, keybd:near
	extrn	tekcls:near
	extrn	tekemu:near	 ; entry point to msggri [jan]
	extrn	sbrk:near		; memory allocator in mssker [jan]
	extrn	srchkw:near, statc:near
	assume	cs:code,ds:data

; local initialization
lclini	proc	near
	mov	dosnum,200h	  ; force dosnum to 2.00 so replay proc works
	mov	prtrdy,true	; port is ready
	push	es		 ;first set up for direct screen writing [jan]
	push	bx		; See page A1 of the GRiD DOS Manual
	mov	ax,0
	mov	es,ax
	les	bx,es:[200h]	; look in Bios for address of charout
	mov	ax,es:[bx+20h]	; offset of charout in ax
	mov	bx,es:[bx+22h]	; seg of charout routine in bx
				; now store addr in a pointer that is used
				; for indirect calls to charout
	mov	word ptr charout,ax
	mov	word ptr charout+2,bx
	pop	bx		; restore the registers
	pop	es
		     ;we're all set up for direct screen write [jan]
	mov	tekflg,0	;tek emulator not initialized [jan]
	mov	portin,0	; serial port not yet initialized
	mov	flags.vtflg,0	; turn off terminal emulation [gaw@prc]
	call	msuinit		; init keyboard translator
	call	scrsavinit	;set up screen memory
;	 call	 serini		 ; initialize serial port
	ret
lclini	endp

;scrsavinit sets up memory block for saving tektronix and
; alpha screens two pages of screen memory are requested
; first page is for alpha, second is for tektronix

scrsavinit   proc   near	   ;set up memory block to save	 [jan]
	push	ax
	push	cx
	push	es
	push	di
	mov	ax,maxscnwrds*4+100	; want 4*maxscnwrds bytes
	call	sbrk			; ax will have the segment
	mov	scrsavseg,ax		; put it in our data segment
	xor	ax,ax			; ax=0--clear screen buffer
	mov	di,ax			; di=0
	mov	cx,2*maxscnwrds+6	; number of words to be 0
	mov	es,scrsavseg		; es points to memory segment
	rep	stosw			; zero memory location [jrd]
	pop	di
	pop	es
	pop	cx
	pop	ax
	ret
scrsavinit endp


; Clear the input buffer before sending a packet.

CLRBUF	PROC	NEAR
	cmp	 repflg,0	 ; doing replay?
	je	 clrb0		 ; e => no replay
	ret			; don't clear if replaying
clrb0:
	push	 ax		 ;need to save for CROSHAIR in msggri
	cli
	mov	ax,offset source
	mov	bufin,ax
	mov	bufout,ax
	mov	count,0
	sti
clrb1:	call	prtchr			; get a character
	jnc	clrb1			; until there aren't any more
	pop	ax
	clc
	ret
CLRBUF	ENDP

; Common routine to clear to end-of-line

CLEARL	PROC	NEAR
	mov dx,offset clreol
	mov ah,prstr
	int dos
	ret
CLEARL	ENDP


; SHOW MODEM, displays current status of lines DSR, CD, and CTS.
; Uses byte mdmhand, the modem line status register. [jrd]
shomodem proc	near
	mov	ah,cmcfm		; get a confirm
	call	comnd
	jnc	shomod0
	ret				 ; get out if error
shomod0:
	mov	dx,offset msmsg7	; no modem status for network
	call	getmodem		; get modem status
	mov	mdmhand,al
	mov	ah,prstr
	mov	dx,offset msmsg1	; modem ready msg
	test	mdmhand,20h		; is DSR asserted?
	jz	shomd1			; z = no
	mov	dx,offset msmsg2	; say not asserted
shomd1: int	dos
	mov	dx,offset msmsg3	; CD asserted msg
	test	mdmhand,80h		; CD asserted?
	jz	shomd2			; z = no
	mov	dx,offset msmsg4	; say not asserted
shomd2: int	dos
	mov	dx,offset msmsg5	; CTS asserted msg
	test	mdmhand,40h		; CTS asserted?
	jz	shomd3			; z = no
	mov	dx,offset msmsg6	; say not asserted
shomd3: mov	ah,prstr
	int	dos
	stc
	ret		       ; carry set upon failure
shomodem endp

; Get modem status and set global byte mdmhand. Preserve all registers.
; status in al ; ax not preserved   [jan]

getmodem proc near
	push	 bx		    ;need to save everybody
	push	 cx
	push	 dx
	pushf
	mov	 ah,5		    ;grid status call
	call	 grdfnc
	mov	 al,ah		   ;ah contains status if no error
	popf
	pop	 dx
	pop	 cx
	pop	 bx
	clc			   ; carry clear upon success
	ret
getmodem endp


; Do a grid function call to the correct com port and return

GRDFNC	PROC	NEAR
	or	portbusy,1	 ;so we know port is busy
	push	es		; save es reg
	push	ds		; then mov ds to es
	pop	es
	push	ax		; save function call and value in al
	add	ah,"0"		; make function code printable
	mov	fnctype,ah	; and save in error message
	pop	ax		; restore ax
	cmp	flags.comflg,1	; serial port or modem? [gaw@prc]
	jne	grdfnc1		; if modem, do other int [gaw@prc]
	int	gserial		; else do serial port function call [gaw@prc]
	jmp	short grdfnc2	; skip other int [gaw@prc]
grdfnc1:int	gmodem		; do modem port function call [gaw@prc]
grdfnc2:jnc	grdfnc3		; skip error msg if carry not set
	add	al,"0"		; make error code printable
	mov	fncstat,al	; and put in error message
	mov	ah,prstr
	push	dx
	mov	dx,offset fncerr ; Give an error message
	int	dos
	pop	dx
grdfnc3:pop	es		; restore es
	and	portbusy,0feH	; clear bit 0
	ret
GRDFNC	ENDP



; Set the baud rate for the current port, based on the value
; in the portinfo structure.  Returns carry clear.

BAUDST	PROC	NEAR
	saveregs
	mov	dx,offset bdtab		; baud rate table for serial
	mov	si,portval
	mov	ax, offset port2	; structure for modem
	cmp	ax,si			; using the modem
	jne	baudst1			; ne= > yes, using modem
	mov	dx, offset modbdtab
baudst1:xor	bx,bx			; help is the table itself
	mov	ah,cmkey		; get keyword
	call	comnd
	jc	baudst2			; c = failure
	push	bx			; save result
	mov	ah,cmeol		; get confirmation
	call	comnd
	pop	bx
	jc	baudst2			; c = failure
	mov	si,portval		; get address of baud structure
	mov	ax,[si].baud		; remember original value
	mov	[si].baud,bx		; set the baud rate
	call	dobaud			; use common code
	clc
baudst2:restoreregs 
	ret
BAUDST	ENDP

; Set the baud rate for the current port, based on the value
; in the portinfo structure.  Returns normally.
; illegal rate not checked; baudst does this

DOBAUD	PROC	NEAR
	saveregs
	mov	bx,portval
	mov	ax,[bx].baud	; ax has baud rate from bdtab
	mov	ah,gsbaud	; set up to set the port baudrate
	call	grdfnc		; do a grid function call to a com port
	restoreregs
	ret
DOBAUD	ENDP

; Send a break out the current serial port.  Returns normally.
sendbr	proc	near
	push	ax
	mov	ax,250		;250 milliseconds long
	call	sendbrt		;do a timed break
	pop	ax		;restore ax
	ret
sendbr	endp

; Send a long break out the current serial port.  Returns normally.
sendbl	proc	near
	push	ax
	mov	ax,1400		;1400 milliseconds long
	call	sendbrt		;do a timed break
	pop	ax		;restore ax
	ret
sendbl	endp

;send timed break.  ax has length in milliseconds.
sendbrt proc	near
	mov	portbusy,2	; port is occupied
	push	cx		; save cx
	push	ax		; save length of break
	mov	ax,gbrkon	; setup to do break on [gaw@prc]
	call	grdfnc		; do break on
	pop	ax		; get time to delay
	call	pcwait		; wait awhile
	mov	ax,gbrkoff	; setup to do break off [gaw@prc]
	call	grdfnc		; do break off
	mov	ax,50
	call	pcwait		; wait awhile
	pop	cx		; restore
	mov    portbusy,0	; port no longer busy
	clc
	ret			; And return
sendbrt	 endp


; Send char in ah out the serial port. Checks flow control.
; clc if success
OUTCHR	PROC	NEAR
	push	cx
	push	bx
	cmp	portin,0	; port initialized?
	jne	outchr0		; ne=> not initialized
	call	serini		; initialize port
outchr0:
	mov	bx,portval
	cmp	[bx].floflg,0	; Are we doing flow control
	pop	bx
	je	outch2		; No, just continue
	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		; 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:
	mov	al,ah		  ; parity routine expects character in al
	call	dopar		  ; do the parity [jan ]
	mov	byte ptr temp,al ; put character in buffer
	push	di		; Save register
	mov	cx,1		; set up to write one char to a grid port
	mov	di,offset temp
	mov	ah,gwrite
	call	grdfnc		; go write a character
	pop	di		; restore saved registers
	pop	cx
	 clc
	 ret			 ; clc means success
OUTCHR	ENDP

; This routine blanks the screen.

CMBLNK	PROC	NEAR
	push	ax
	push	dx
	mov	ah,prstr
	mov	dx,offset blank
	int	dos
	pop	dx
	pop	ax
	clc			 ; stay in connect mode
	ret
CMBLNK	ENDP

LOCATE	PROC	NEAR
	mov	dx,0		; Go to top left corner of screen.
	jmp	poscur		; callret...
LOCATE	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
	push	ax		; save some regs
	push	bx
	push	cx
	push	dx
	mov	ah,ggbaud	; set up to get port baud rate
	call	grdfnc		; and go get it
	mov	al,ah		; mov baudrate into al
	mov	ah,0		; and zero upper part of ax
	mov	bx,portval
	mov	[bx].baud,ax	; Set baud rate
	pop	dx		; restore regs
	pop	cx
	pop	bx
	pop	ax
	clc			    ; msxibm does this
	ret
GETBAUD ENDP

; Returns with char in al, # of chars in buffer in dx and carry clear.
; Carry set means no character available.
PRTCHR	PROC	NEAR
	cmp	repflg,0		; doing replay?
	je	prtch0a			; e => not doing replay
	jmp	getrepchr		; get replay character if in replay
prtch0a: cmp	portin,0		; port not initialized
	 jne	 prtch0b		; 0=> not initialized
	 call	serini
prtch0b:
	cmp	serclk,true	; should we check flow control? [jan][jrd]
	jne	prtch0		;ne = no
	call	flowchek	;checkout flow control
prtch0: push	si
	cmp	count,0		; any characters?
	jne	prtch2		; ne = yes, get from buffer
prtch1:
	push	di
	push	bx
	push	cx
	mov	cx,bufsiz	; set up to read from grid port buffer
	mov	di,offset source
	mov	ah,gread
	call	grdfnc
	pop	cx		; restore saved registers
	pop	bx
	pop	di

	mov	count,ax	; reset count
	or	ax,ax
	jz	prtch4		; still no chars
	mov	bufout,offset source ; this is output ptr
prtch2:
	dec	count
	mov	dx,count	; return count in dx
	mov	si,bufout
	cld
	lodsb			; get character
	mov	bufout,si	; update ptr
	pop	si
	clc			; clc means a character
	ret
prtch4:	pop	si
	stc		      ; stc means no characters
	ret
PRTCHR	ENDP

;FLOWCHEK --Check to see if we need to do flow control
;this gets called in connect mode each 4 ticks of the clock
;both SERINT and PRTCHR call this. SERINT will not call FLOWCHEK
;if the port is busy
;
;
FLOWCHEK   PROC	  NEAR
       or      portbusy,2	      ;bit 1 set if in flowchek

;    code below largely taken from old SERINT
       push    ax
       push    bx
       push    cx
       push    dx
       push    di
       cld
       mov     bx,portval
       cmp     [bx].floflg,0   ; Doing flow control?
       je      intdone		; No, just leave.
       mov     ah,grstat       ; get the buffer count
       call    grdfnc
       cmp     xofsnt,true     ; Have we sent an XOFF?
       je      flowchek1	; Yes.
       cmp     cx,mntrgh       ; Past the high trigger point?
       jbe     intdone	       ; No, we're within our limit
       mov     ah,flowoff      ; Get the XOFF
       or      ah,ah	       ; null (no flow control)?
       jz      intdone	       ; z = yes, do nothing
       mov     byte ptr temp,ah ; put character in buffer
       mov     cx,1	       ; set up to write one char to a grid port
       mov     di,offset temp
       mov     ah,gwrite
       call    grdfnc	       ; go write a character
       mov     xofsnt,true     ; Remember we sent it
       jmp     intdone

flowchek1:
       cmp     cx,mntrgl       ; below the low trigger point?
       ja      intdone	       ; no, don't send XON
       mov     ah,flowon       ; get the XON
       or      ah,ah	       ; null?
       jz      intdone	       ; z = yes, do nothing
       mov     byte ptr temp,ah ; put character in buffer
       mov     cx,1	       ; set up to write one char to a grid port
       mov     di,offset temp
       mov     ah,gwrite
       call    grdfnc	       ; go write a character
       mov     xofsnt,false    ; remember we sent it
intdone:pop	di
	pop	dx
	pop	cx
	pop	bx
	pop	ax
	mov	serclk,false
	mov	portbusy,0	;port no longer busy
	ret
FLOWCHEK 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)
	 nop			; outchr can do skip return
	 nop
	 nop
ihosts1:call	clrbuf		; clear out interrupt buffer
	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 = none
	jz	ihostr1		; z = null
	call	outchr		; send it (release Host's output queue)
	 nop			; outchr can do skip return
	 nop
	 nop
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,cmtxt	; 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
	jnc	dtrlow1	      
	ret			; get out if error
dtrlow1:
	call	serhng		; drop DTR and RTS
	mov	ah,prstr	; give a nice message
	mov	dx,offset hngmsg
	int	dos
	clc
	ret			; clear carry for success
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	PROC	NEAR		     ;[jan]
	or	  portbusy,2	     ;port is occupied
	mov	  ax,150
	call	  pcwait	     ;wait for next tick of clock
	cmp	  flags.comflg,1     ;serial(1) or modem(<>1)
	jne	  serhngm	     ;jne means we are using modem
	mov	  ax,01000H	     ;turn off rts with function 16
	call	  grdfnc
	mov	  ax,100
	call	  pcwait	     ;wait 100 mx
	mov	  ax,01100H	     ;turn off dtr with function 17
	call	  grdfnc
	mov	  ax,500	     ;wait 1/2 second
	call	  pcwait
	mov	  ax,010ffH	     ;turn on rts with function 16
	call	  grdfnc
	mov	  ax,100
	call	  pcwait
	mov	  ax,011ffH	     ;turn on dtr with function 17
	call	  grdfnc
	jmp	  serhng1
serhngm:			     ;hang up modem
	mov	  ah,ginit
	call	  grdfnc	     ;hangup and initialize modem
	mov	  ax,500
	call	  pcwait	     ;let relay settle down
	mov	  prevport,86	     ;fake so serini will initialize
	call	  serini	     ;this reinitialzes modem
serhng1:mov	  ax,300	     ;wait to let things settle
	call	  pcwait
	mov	  portbusy,0	     ;port is no longer occupied
	clc			     ; success
	ret
SERHNG	ENDP

MODEMSTR    PROC   NEAR	      ;send initializing string to modem [jan]
	  cmp	   flags.comflg,2    ; using modem
	  je	   modemstr0a	     ; yes
	  ret			     ; get out if serial
modemstr0a:
	  push	   ax		     ;save ax
	  mov	   ax,200
	  call	   pcwait	     ;delay 200 ms before doing something
	  push	   es		     ;save es and di
	  push	   di
	  push	   ds
	  pop	   es		     ;es now points to our data segment
	  mov	   di,offset mdmstr  ;string to send to modem
	  mov	   cx,mdmstrlen	     ;length of the string
modemstr0: push	    cx		      ;save cx
	  cmp	   byte ptr es:[di],','	      ;delay 0.5 second on comma
	  jne	   modemstr2
	  mov	   ax,500	     ;delay for the comma
	  call	   pcwait
	  jmp	   modemstr3	     ;onto next character
modemstr2:
	  mov	   ax,50	     ;send out port
	  call	   pcwait	     ;50 ms between characters
	  mov	    cx,1	     ;1 byte at a time
	  mov	    ah,2	     ;grid write call
	  call	    grdfnc	     ;write it to modem
modemstr3: inc	     di		     ;point to next byte
	  pop	    cx		     ;get the count
	  loop	    modemstr0	     ;do the next byte if cx<>0
	  pop	  di		     ;restore di and es
	  pop	  es
	  pop	  ax
	  ret
MODEMSTR   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


; Position the cursor according to contents of DX.

POSCUR	PROC	NEAR
	push	ax			; save regs
	push	dx
	push	es
	push	di
	mov	ax,ds
	mov	es,ax			; address data segment!!!
	cld
	mov	di,offset colno
	mov	al,dh			; row
	inc	al			; adjust offset from 1 instead of 0
	mov	ah,0			; zero up half of reg containing number
	call	nout
	mov	al,';'
	stosb
	mov	al,dl			; column
	inc	al			; adjust offset from 1 instead of 0
	mov	ah,0			; zero up half of reg containing number
	call	nout
	mov	al,'H'
	stosb
	mov	al,'$'
	stosb
	mov	dx,offset movcur
	mov	ah,prstr
	int	dos			; print the sequence
	pop	di
	pop	es
	pop	dx
	pop	ax
	ret
POSCUR	ENDP

; put the number in ax into the buffer pointed to by di.  Di is updated
nout	proc	near
	push	dx			; save registers
	push	bx
	push	ax
	cld
	mov	dx,0			; high order is always 0
	mov	bx,10
	div	bx			; divide to get digit
	push	dx			; save remainder digit
	or	ax,ax			; test quotient
	jz	nout1			; zero, no more of number
	call	nout			; else call for rest of number
nout1:	pop	ax			; get digit back
	add	al,'0'			; make printable
	stosb				; drop it off
	pop	ax			; restore all registers
	pop	bx
	pop	dx
	ret
nout	endp


; Write a line in inverse video 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,26 * 100H	; line 26
	call	poscur
	mov	dx,offset invseq ; put into inverse video
	mov	ah,prstr
	int	dos
	pop	dx
	int	dos
	mov	dx,offset nrmseq ; normal videw
	int	dos
	ret			; and return
putmod	endp

; Clear the mode line written by putmod.  Returns normally.
clrmod	proc	near
	mov	dx,26 * 100H
	call	poscur
	call	clearl
	ret
clrmod	endp

; Put a help message one the screen in reverse video.  Pass
; the message in AX, terminated by a null.  Returns normally.
; The message is put wherever the cursor currently is located.
puthlp	proc	near
	push ax
	mov ah,prstr		; Leave some room before the message
	mov dx,offset crlf
	int dos
	pop si			; Put message address here
puth0:	mov ah,prstr
	mov dx,offset invseq	; Put into reverse video
	int dos
	mov ah,prstr
	mov dx,offset ivlseq	; Make line inverse video
	int dos
	cld
puth1:	lodsb
	cmp al,0		; Terminated with a null
	je puth2
	mov dl,al
	mov ah,conout
	int dos
	cmp al,lf		; Line feed?
	je puth0		; Yes, clear the next line
	jmp puth1		; Else, just keep on writing
puth2:	mov dx,offset crlf
	mov ah,prstr
	int dos
	mov dx,offset nrmseq	; Normal video
	int dos
	clc
	ret
puthlp	endp

; Perform a delete.

DODEL	PROC	NEAR
	push	ax
	push	dx
	mov	ah,prstr
	mov	dx,offset delstr	; Erase character
	int	dos
	pop	dx
	pop	ax
	ret
DODEL	ENDP

; Perform a Control-U.

CTLU	PROC	NEAR
	push	ax
	push	dx
	mov	ah,prstr
	mov	dx,offset clrlin
	int	dos
	pop	dx
	pop	ax
	ret
CTLU	ENDP
 ;;	  set the current port
COMS	PROC	NEAR
	mov	dx,offset comptab
	xor	bx,bx		; help is the table itself
	mov	ah,cmkey
	call	comnd
	jnc	coms00
	ret			; get out if error
coms00:	push	bx
	mov	ah,cmcfm
	call	comnd		; Get a confirm.
	jc	comx		; carry set = failure
	pop	bx
	mov	flags.comflg,bl	; Set the comm port flag
	cmp	flags.comflg,1	; Using Com 1?
	jne	coms0		; ne = no
	mov	portval,offset port1
	clc			; carry clear for success
	ret
coms0:	mov	portval,offset port2
	clc			; carry clear for success
	ret
comx:	pop bx
	stc			; carry set for failure
	ret
COMS	ENDP

; Set heath emulation on/off.

VTS	PROC	NEAR
      mov     dx,offset termtb
      mov     bx,0
      mov     ah,cmkey
      call    comnd
      jnc     vts0
      ret	       ; get out if error
vts0:
      push    bx
      mov     ah,cmcfm
      call    comnd		; Get a confirm
       jc      vt0		 ; carry => didn't get a confirm
      pop     bx
      cmp     bl,ttbig	       ; using big screen?
      jne     vt1	      ;ne means its not big
      mov     bigscreen,1     ; so we know screen is big
      mov     screenbyte, bl  ; for status
      mov     scnwrds, 256*32  ; words in big screen
      mov     tekflg,0	       ; tek needs reinitialization
      clc
      ret
vt1:  cmp     bl,ttsmall       ;ne means its not small
      jne     vt1a
      mov     tekflg,0	       ; tek needs reinitialization
      mov     scnwrds, 240*20	  ;words in small screen
      mov     bigscreen,0	;screen is not big, i.e. it's small
      mov    screenbyte, bl    ; for status
      clc
      ret
vt1a: cmp	bl,tekonnum	; enable tek?
      jne	vt1b		; ne = no, don't enable
      and	denyflg,not tekxflg ; clear tekx bit
      mov	tekbyte,bl	; for status display
	clc
	ret
vt1b:	cmp	bl,tekoffnum	; disable tek
	jne	vt2		; ne => don't disable
	or	denyflg,tekxflg	; set tek deny bit
	mov	tekbyte,bl	; for status display
	clc
	ret


vt2:	mov	flags.vtflg,bl	; Set the Tektronix emulation flag [jan]
	mov	tekflg,0	; need to re-initialize tek emulator [jan]
	clc			; carry clear for success
vt3:	ret
vt0:	pop	bx
	stc			; carry set for failure
	ret
VTS	ENDP



VTSTAT	PROC	NEAR	; For Status display [jrd]
    mov bx, offset vtstbl    ; table of things to show
    jmp statc		     ; common status code
;;;  ret	     ; no emulator status to display
VTSTAT	ENDP

termtog proc  near		; toggle terminal type [jan]
	call	savescr		; save present screen
	xor	flags.vtflg,tttek ;toggle terminal type
	mov	tekflg,0	; we need to re-initialize tek emulator
	call	restscr		; restore the previous screen
	clc			; do not exit Connect mode [jrd]
	ret
termtog endp

kclrscn proc	near		; clear screen in text or Tek mode [jrd]
	cmp	flags.vtflg,tttek ; doing Tek emulation?
	jne	kclrsc1		; ne = no
	call	cmblnk		; blank for good measure [jan]
	call	tekcls		; blank and some more
	clc			; stay in Connect mode
	ret
kclrsc1:call	cmblnk		; blank screen
	clc			; stay in Connect mode
	ret
kclrscn 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	; [jrd]
	clc
	ret
DUMPSCR ENDP



; show the definition of a key.	 The terminal argument block (which contains
; the address and length of the definition tables) is passed in ax.
; Returns a string to print in AX, length of same in CX.
; Returns normally.
showkey proc	near
	ret			; and return
showkey endp


;  Common initialization for using serial port.

SERINI	PROC	NEAR

	mov	portbusy,2	;port is occupied-don't check flow
	mov	clkdelay,0	; restart flow check clock
	push	es
	cmp	portin,0	; Did we initialize interrupt already?
	je	serin0		; No, skip exit
	jmp	serin1		; Yes, so just leave
serin0:
	cli			; Disable interrupts
	cld			; Do increments in string operations
	 xor	ax,ax		;ax=0
	 mov	es,ax		;es=0
	 mov	bx,CLK_INT	;clock vector
	 mov	ax,es:[bx]	;get offset
	 mov	savclko,ax	;save clock int offset
	 mov	ax,es:[bx+2]	;get segment
	 mov	savclks,ax	;save clock int segment

	mov	ax,offset serint
	mov	es:[bx],ax	; and load with offset of serint
	mov	ax,cs
	mov	es:[bx+2],ax	; and load with code segement address
				;clk vector now reset
	mov	portin,1	; Remember interrupt has been initialized
	sti			; turn interrupts back on
serin1: call	getbaud		; get existing baud rate
	call	dobaud		; and reset it

	push	bx
	mov	bx,portval		; get port
	mov	parmsk,0ffh		; parity mask, assume parity is None
	cmp	[bx].parflg,parnon	; is it None?
	je	serin2			; e = yes
	mov	parmsk,07fh		; no, pass lower 7 bits as data
serin2: mov	bx,[bx].flowc		; get flow control chars
	mov	flowoff,bl		; xoff or null
	mov	flowon,bh		; xon or null
	pop	bx


	mov	ah,flags.comflg	   ;get new com port
	cmp	ah,prevport	   ;port changed?
	je	serin3		   ;no change so don't reinitialize
	mov	prevport,ah	   ;remember we have changed
	xor	ax,ax
	mov	ah,gspar	; parity = none
	call	grdfnc
	mov	al,1		; stopbit = 1
	mov	ah,gssbit
	call	grdfnc
	mov	al,8		; data bits = 8
	mov	ah,gsdata
	call	grdfnc
	mov	dx,1		; timeout on char read wait = 1ms
	mov	ah,gcharto
	call	grdfnc
	call	modemstr	; init modem if on
	cmp	flags.comflg,1	; Using Com 1?
	jne	skipcts		; Nope.
	mov	dx,0		; timeout on cts = 0
	mov	ah,gcts
	call	grdfnc
skipcts:mov	ax,ds		; point to large buffer
	mov	es,ax
	mov	di,offset gbuffer
	mov	cx,gbuflen
	mov	ah,gbufass
	call	grdfnc
	mov	ah,gflush	; flush grid input buffer
	call	grdfnc
;;	  call	  clrbuf		  ; Clear input buffer
serin3: pop	es
	mov	portbusy,0		;now able to do flow checking
	clc				; carry clear for success
	ret
SERINI	ENDP


SERRST	PROC	NEAR		; reset the clock interrupt vector
	cmp	portin,0	; Did we initialize interrupt already?
	je	serrst0		; No, skip resetting clock vector
	cli			; Disable interrupts

	push	es		; restore vector of clock tick int at 1CH
	xor	ax,ax		; point to segment part of vector
	mov	es,ax		; es=0
	mov	bx,CLK_INT	; clock interrupt =1ch*4
	mov	ax,savclko	; replace with original value
	mov	es:[bx],ax	; restore offset
	mov	ax,savclks
	mov	es:[bx+2],ax	; restore segment
	pop	es		; and clean up stack
	mov	portin,0	; Remember interrupt has been reset.
	sti			; turn interrupts back on

serrst0:
	ret			; All done
SERRST	ENDP


; Comm port interrupt service routine to prevent grid buffer overflow
; Calls flowchek which sends Xoff if necessary if activated
;flow control is checked every 4 clock ticks, about 80 ms
; Modified by [jan] with helpful suggestions from [jrd]
SERINT	PROC	FAR
       push   ax		;all registers must be saved by SERINT
       push   ds		;here, we put some words on the stack
       mov    ax,data	       ;first we let the clock interrupt get called
       mov    ds,ax		;then (maybe) come back to check flow control
       pop    save_ds		;save ds
       pop    save_ax		;save ax
       pushf			;save since they're changed by and instr.
       inc    clkdelay		;just do flow control check
       mov    ax,clkdelay	;once each 4 ticks of the clock
       and    ax,3		;for improved performance
       jnz    serint0		;nz means don't check this tick
       popf
       pushf			;restore flags and return to stack
       mov    ax,cs		;put segment of return address on stack
       push   ax		;clock will return here
       mov    ax,offset serint1 ;offset of return address
       push   ax		;is placed on stack
       pushf			;this will come off
serint0:popf			;remove extra flags from stack

       mov    ax,savclks	;put address of clock routine
       push   ax		;on top of stack
       mov    ax,savclko
       push   ax
       mov    ax,save_ax	;restore ax and ds
       mov    ds,save_ds
       ret			;go to the clock routine
				;we come back at serint1
				;once each 4 ticks
;;Clock interrupt returns here if (clkdelay and 3)=0


serint1:			;;  entry point after clock routine
       push ax
       push bx
       push cx
       push dx
       push ds
	 mov	 ax,data
	 mov	 ds,ax
	 mov	 serclk,true	 ;check out flow control at least once/4 tick
	cmp	insrvc,true	 ; are we already doing interrupt service?
	je	retint		 ; yes, then skip service until this one done
	mov	insrvc,true	 ; nope, set in service flag
	cmp    portbusy,0	 ;is serial port available?
	jne	serint5		  ;don't stack calls
				;grdfnc is non-reentrant
	sti			; flag set enable interrupts
	call  flowchek		;do flow control checking
	  mov	serclk,false	  ;don't check until next tick
serint5:  mov	  insrvc,false	  ; set in service flag to false
retint:	pop ds
       pop dx
       pop cx
       pop bx
       pop ax
       iret		      ;iret since we have to remove flags
SERINT	ENDP
; Generate a short beep.



BEEP	PROC	NEAR
	mov dl,bell
	mov ah,conout
	int dos
	ret
BEEP	ENDP


;check string to see if we need to do something special

stringchek  proc  near
       cmp   stringchekcnt,0	 ; nobody in yet?
       jne   stringchek1	 ; ne => already have characters
       cmp   al,escape		 ; is this escape?
       je    stringchek1	 ; it is escape, so go and process
       cmp   al,escape+80h	 ; in case parity is odd
       je    stringchek1	 ; process the escape
       stc			 ; display the character
       ret			 ; return quickly if nothing to do
stringchek1:			 ; here is escape already in
       saveregs
       and     al,07fh		 ;strip high bit
       mov     bx,stringchekcnt
       mov     stringchekbuff[bx],al  ;put character in buffer
       inc     stringchekcnt	      ;one more character in buffer
       call    stringtest	 ; does the string in stringchekbuff match?
       cmp	match,0		 ; 0 means no match
       je      stringchek2
       mov     si,match		   ; here means we have a match
       shl     si,1		   ; multiply by 2
       dec     si
       dec     si		   ; 1=0, 2=1 etc
       call    disptab[si]	   ; call appropriate function
       call    stringbuffplay	      ; play back the buffer
       clc			   ; don't display
       jmp     stringchek3	   ; return and don't display character
stringchek2:
	 clc			  ; don not display
	 cmp   matchsofar,true	  ; do we have a match so far
	 je    stringchek3	     ; e=true , get out
	 mov   playem,true
	 call  stringbuffplay	       ; clean out the buffer
	 clc			   ; don't display character
stringchek3:
	 restoreregs
	 ret
stringchek   endp

;test to see if input string is a match to toggle terminal  [jan]


; stringtab gives addresses of 0 terminated strings
; teststring in stringchekbuff
;numstrings is the number to checked
; matchsofar will have be true if there is a possilbe match
; match will be non-zero 1, 2, 3 indicating number of match if a match
; if no match yet, match will be 0
; severaal registers get destroyed
stringtest proc near
	mov	matchsofar, false	  ; assume no match
	mov	match,0			; no match
	xor	si,si			; pointer to string tab
	dec	si
	dec	si			; step back 1 item
	mov	cx,0			; cx points to number of string
strtst1:
	inc	cx			; strings number
	cmp	cx,numstrings		; done parsing table?
	ja	strtst5			; we're done, get out of here
	mov	di, offset stringchekbuff
	inc	si
	inc	si			; point to next item
	mov	bx,stringtab[si]	; offset of string
strtst2:
	mov	al,[di]			; stringchekbuff in al
	mov	ah,[bx]			; string element to test in ah
	cmp	al,0			; end of stringchekbuff
	jne	strtst2a		; ne=> not at end of buffer
	mov	matchsofar,true		; we have a match so far
	jmp	strtst5			; return to caller
strtst2a:
	cmp	ah,0			; at end of string?
	je	strtst1			; failure, go to next string
	cmp	ah,al			; match?
	jne	strtst1			; no match, on to next string
					; here if match
	mov	ah,[bx+1]		; next byte from string
	cmp	ah,0			; are we done with string?
	je	strtst3			; e => yes, a match
	inc	bx			; next element in string
	inc	di			; next character in stringchekbuff
	jmp	strtst2			; check next item in string
strtst3:				; here if we have a match
	 mov	match,cx		;
	 mov	matchsofar,true		;
strtst5:
	ret
stringtest endp



;play back characters in string buffer ..called by stringchek
stringbuffplay proc near
      xor      bx,bx	      ;bx=0
      mov      cx,stringchekcnt
stringbuffplay1:
      mov      al,stringchekbuff[bx]
      cmp      playem,true    ;playback characters?
      jne      stringbuffplay2	 ;ne = no don't play back
      push     bx	      ; save index
      push     cx	      ; save count
      call     outtty	      ; print the character
      pop      cx	      ; restore count
      pop      bx	      ; restore index
stringbuffplay2:
     mov      stringchekbuff[bx],0  ;set to 0
     inc      bx	      ;point to next character
     loop     stringbuffplay1	 ;repeat until buffer is empty
     mov      stringchekcnt,0	 ;now no characters in buffer
     ret
stringbuffplay endp

ignoretek proc near	       ; ignore this escape sequence in tek mode
    mov playem,false
    cmp flags.vtflg,tttek      ; are in in tek emulation
    je	ignoretek1	       ; e=yes do not play back
    mov playem,true
ignoretek1:
     ret
ignoretek endp

ignoreall proc near   ; always ignore this escape sequence
     mov playem,false
     call beep
     ret
ignoreall endp

totekplay proc near	       ; turn on tektronix
      mov playem,true	       ; play back characters
      jmp totek
totekplay endp

toteknoplay proc near
     mov playem,false
     jmp  totek
toteknoplay endp


totek proc near		   ; turn on tektronix
       test    denyflg,tekxflg	 ;tek auto entry enabled?
       jz     totek1
       mov playem,true		; play back characters
       ret
totek1:

   cmp	flags.vtflg,tttek	; already doing tek
   je	totek2
   call termtog			; toggle to tektronix
totek2:
    ret
totek endp


; put the character in al to the screen, do capture and printing,
; does translation for Set Input command.
; Adapted from msyibm.asm [jrd]
outtty	proc	near
	cmp	flags.vtflg,tttek	; doing tektronix emulation?
	jne	outtty1			; ne= not doing tek emulation
	jmp	tekemu			; do tekemu and return
outtty1:cmp	repflg,0		; replaying?
	je	outtty2			; e=> no replay
  ;	 mov	 ah,conout		 ; dostty screen mode
  ;	 mov	 dl,al			 ; write without intervention.
  ;	 int	 dos			 ; else let dos display char
  ;	 ret				 ; get out
outtty2:

	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 [jrd]
	mov	bx,offset rxtable	; address of translate table [jrd]
	xlatb				; new char is in al
	pop	bx
outnp7:
	   test ourarg.flgs, capt	; capture flag on?
	jz	outnoc			; no, forget this part
	push	ax			; save char
	call	captrtn			; give it captured character
	pop	ax			; restore character and keep going
outnoc: test	ourarg.flgs,prtscr	; should we be printing?
	jz	outnop			; no, keep going
	push	ax
	mov	ah,print_out		; write to system printer device
	mov	dl,al
	int	dos
	pop	ax
	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	outnp5			; 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)? [jrd]
	;jne	 outnp5			 ; ne = no
       ; jmp	 beep			 ; use short beep, avoid char loss.
outnop1:
outnp5:
	call	charout			;tell grid bios to write character[jan]
;	 mov	 ah,conout		 ; dostty screen mode
;	 mov	 dl,al			 ; write without intervention.
;	 int	 dos			 ; else let dos display char
outnp6: ret				; and return
outtty	endp

; send the character in al out to the serial port
; handle echoing also...
outprt	proc	near
;	 test	 flags,lclecho		 ; echoing?
	 test  ourarg.flgs,lclecho	; echoing?
	jz	outpr1			; no, forget it
	push	ax			; save char
	call	outtty			; print it
	pop	ax			; restore
outpr1: mov	ah,al			; this is where outchr expects it
	call	outchr			; output to the port
	 nop
	 nop
	 nop				; skip returns
	ret
outprt	endp

; Get a char from the serial port manager
; returns with carry on if a character is available
portchr proc	near
	call	prtchr			; character at port?
	    jnc	  portc1		 ; nc => character at port
portc0: clc				; no carry -> no character
	ret				; and return
portc1: and	al,parmsk		; apply 8/7 bit parity mask
	stc				; have a character
	ret				; and return
portchr endp


argini	proc	near			; read passed arguments
	mov	bx,argadr		; base of argument block
	mov	ax,[bx].captr
	mov	captrtn,ax		; buffer capture routine
	mov	parmsk,0ffh		; parity mask, assume parity = None
	cmp	[bx].parity,parnon	; is parity None?
	je	argin2			; e = yes, keep all 8 bits
	mov	parmsk,07fh		; else keep lower 7 bits
argin2: call	serini			; initialize port if necessary
	ret				; that's it
argini	endp

getflgs	 proc  near
	 mov al,ourarg.flgs	       ;supply flags for msggri [jan]
	 ret
getflgs	 endp

term	proc	near
	mov	argadr,ax		; save argument ptr
	push	es
	mov	si,ax			; this is source
	mov	di,offset ourarg	; place to store arguments
	push	ds
	pop	es			; address destination segment
	mov	cx,size termarg
	cld
	rep	movsb			; copy into our arg blk
	pop	es
	call	argini			; init options from arg address
	cmp	curini,0		; have we been in here before[gaw@prc]
	je	term1			; if not skip restoring cursor[gaw@prc]
	call	restscr			; restore screen

term1:	cmp	prtrdy,false		; ready to read port
	je	term5			; get out
	call	portchr			; read char from serial port
	jnc	term3			; nc = no char, go on
	cmp	flags.vtflg,tttek	; doing tek emulation?
	je	term1a			; e=yes, already doing tek
	call	stringchek		; ESC FF will turn on tek [jan]
	jnc	term3
term1a: call	outtty			; display and capture char [jrd]

term3:	inc	keydelay		; just check keyboard once
	mov	ax,keydelay		; each eight reads of the port
	and	ax,7			; should speed things up
	jnz	term1			; at higher baud rates [jan]
	call	keybd			; call keyboard xlator, send results
	jnc	term1			; nc = stay in Connect mode
term5:					; [gaw@prc]
	call	savescr			; save screen [gaw@prc]
	cmp	prtrdy,true		; need to set kbdflg if wierd exit
	je	term6
	mov	kbdflg,'C'		; so we exit connect mode
	mov	prtrdy,true
term6:	ret
term	endp


getrepchr proc	near	      ; get replay character for file
      mov    ah,readf2	      ; read from replay file
      mov    bx,diskio.handle
      mov    cx,1	      ; read 1 character
      mov    dx,offset rdbuf  ; to this buffer
      int    dos
      jc     getrepchr1	      ; c => failure
      cmp    ax,cx	      ; read the byte?
      jne    getrepchr1
      mov    al,rdbuf	      ; al has character
      clc		      ; character available in al
      clc
      ret


getrepchr1:
      call   beep	     ; announce file is done
      call   beep
      call   getkey	     ; wait for a key to be pressed
      mov    prtrdy,false    ; so we exit connect mode
      stc
      ret		     ; no character available
getrepchr    endp

repchrout  proc	 near		; process key in al  while replaying
	and   al,7fh		; strip parity
repchrout1:
	cmp   al,'C'-40h	; Control C?(to exit playback mode)
	je    repchrout3	; e=> yes, return failure
	cmp   al,XOFF		; user wants to stop?
	jne   repchrout2	; ne => ok to continue
	call  getkey		; wait and get a key
	jmp   repchrout1	; now process this key
repchrout2:
	clc			; return success
	ret
repchrout3:
	mov   prtrdy,false	; exit terminal
	stc			; exit connect mode
	ret
repchrout  endp

getkey	proc   near	      ; wait for a key to be typed
       mov    ah,7
       int    dos
       ret
getkey	endp

savescr proc near
	push	es			; move ds base address to es
	push	di
	push	ax
	push	dx
	xor	ax,ax
	mov	di,maxscnwrds*2	      ;tek page by default
	cmp    flags.vtflg,tttek
	je    savsc1
	mov    di,0		     ;point to 1st page for text
	mov	ah,prstr		; send '<esc>[s' to ansi.sys[gaw@prc]
	mov	dx,offset cursav	; [gaw@prc]
	int	dos			; [gaw@prc]
	mov	byte ptr curini,1	; now we've saved the cursor[gaw@prc]
	mov	dx,offset curoff	; turn off cursor
	mov	ah,prstr
	int	dos


savsc1: mov    ax,scrsavseg
	mov    es,ax			;es points to screen save segment
	mov	si,scnstrt		; point to screen memory area
	mov	cx,scnwrds		; setup word count
	push	ds
	xor	ax,ax			; point to base page with ds
	mov	ds,ax
	cld
	rep	movsw			; transfer image to save area
	pop	ds			; restore registers and return
	mov	dx,offset curon		; turn on cursor
	mov	ah,prstr
	int	dos
	pop	dx
	pop	ax
	pop	di
	pop	es
	ret
savescr endp

restscr proc near
	mov	dx,offset curoff	; turn off cursor
	mov	ah,prstr
	int	dos
	mov	dx,offset blank		; clear screen to get rid of cursor
	mov	ah,prstr
	int	dos
	push	es			; point to base page with es
	xor	ax,ax			; restore screen
	mov	es,ax
	xor	ax,ax
	mov	si,ax		       ;si=0 by default
	cmp	flags.vtflg,tttek
	jne	ressc1			;ne means not tek
	mov	si,maxscnwrds*2		 ;point to second page if tek


ressc1: mov	di,scnstrt		; point to screen memory area
	mov	cx,scnwrds		; setup word count
	mov	ax,scrsavseg
	push	ds
	mov	ds,ax			 ;ds points to screen save area
	cld
	rep	movsw			; transfer image to screen
	pop	ds
	pop	es
	cmp	flags.vtflg,0		; are we in emulation mode[gaw@prc]
	jne	ressc2			 ; to skip restoring cursor[gaw@prc]
	mov	ah,prstr		; send '<esc>[u' to ansi.sys[gaw@prc]
	mov	dx,offset curres	; [gaw@prc]
	int	dos			; [gaw@prc]
	mov	dx,offset curon		; turn on cursor
	mov	ah,prstr
	int	dos
ressc2: ret
restscr endp


;  msu calls this to send keystroke in al out the port
chrout	proc  near
	cmp	repflg,0		; in replay mode?
	je	chrout1			; e=> not doing replay
	jmp	repchrout	      ; display the replay character
chrout1:call	outprt		       ; put char in al to serial port
	clc				; stay in Connect mode
	ret
chrout	endp


trnprs: push	ax			; toggle Copy screen to printer
	test	ourarg.flgs,prtscr	; are we currently 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,4			; 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	trnpr3			; and ignore request
trnpr2: xor	ourarg.flgs,prtscr	; flip the flag
trnpr3: pop	ax
	clc
	ret


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
	push	bx			; tell kermit we resume logging
	mov	bx, offset argadr
	or	[bx].flgs, capt
	pop	bx
klogn:	clc
	ret
klogon	endp

klogof	proc	near			; suspend logging (if any)
	and	ourarg.flgs, not capt
	push	bx
	mov	bx, offset argadr
	and	[bx].flgs, not capt    ; turn off kermit's capture flag
	pop	bx
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
cmdcom: mov	kbdflg,al		; pass char to msster.asm via kbdflg
	stc				; say exit Connect mode
	ret

code	ends
	end
