; CP4TT.ASM
;	KERMIT - (Celtic for "FREE")
;
;	This is the CP/M-80 implementation of the Columbia University
;	KERMIT file transfer protocol.
;
;	Version 4.0
;
;	Copyright June 1981,1982,1983,1984,1985
;	Columbia University
;
; Originally written by Bill Catchings of the Columbia University Center for
; Computing Activities, 612 W. 115th St., New York, NY 10025.
;
; Contributions by Frank da Cruz, Daphne Tzoar, Bernie Eiben,
; Bruce Tanner, Nick Bush, Greg Small, Kimmo Laaksonen, Jeff Damens, and many
; others. 
;
;	This file contains the code for the TRANSMIT and CONNECT commands,
;	which communicate with a host which is not running KERMIT.
;
; revision history:
; edit 4: 13-Jan-85 by Vanya J.Cooper Pima Commun. College Tel: 602-884-6809
;
;pcc002	28-Dec-84	modules:cp4tt,cp4utl
;	Add connect mode <esc>P command to toggle printer on
;	and off.  Conflicts with "official" recommended commands
;	in protocol manual, but I don't think CP/M will ever get
;	a PUSH command.
;
;pcc003-pcc005	2-Jan-85	vjc	modules:cp4mit,cp4tt,cp4utl
;	These edits must all be installed together and change the way
;	logging is handled.  The log file spec is moved to a separate
;	fcb, and not opened until an actual CONNECT command is given.
;	This takes care of a NASTY bug that if you used any other file
;	command between the LOG and CONNECT, the log file would get
;	written over the last file used.  This also allows logging to
;	be "permanently" enabled until an CLOSE (new command) for all
;	CONNECT sessions, like most other kermits do.  If a log file
;	already exists, it will be appended to.  Also add two new
;	CONNECT mode commands <esc>Q to suspend logging and <esc>R to
;	resume.  <esc>R means something else during TRANSMIT, but
;	logging is never on then, so there shouldn't be any conflict.
;	I also changed the write code, so that it can handle one more
;	character after the XOFF is send to stop the host.  This allows
;	a little "slop" for systems that don't stop immediately (such
;	as TOPS10), but it didn't help much.
;
;pcc008	2-Jan-85	vjc	modules:cp4def,cp4tt,cp4utl
;	Keyboard input during CONNECT mode can get locked out if
;	there is enough input from the modem port to keep prtchr
;	busy.  This can happen for example, if the printer is running
;	at the same speed as the modem line, leaving you helpless to
;	turn it off or abort the host.  Add a fairness count, so that
;	at least every prfair characters we look at console input.
;
;pcc012	4-Jan-85	vjc	modules:cp4mit,cp4tt,cp4utl
;	Use the big buffer for the log file.  Move the log file back
;	into the common fcb and only save the drive, name, and
;	extension between connects.  Add new routines to cp4utl to
;	create or append to an existing file, and to conditionally
;	advance buffers only if in memory.  Remove edit pcc003 that
;	allows one more character after the xoff, since it didn't
;	really work very well and does not fit in well with the way
;	the buffer advancing routines are set up.  If someone still
;	thinks this would be useful, it could be put back in with a
;	little more work.
;	
;	While testing this edit, I also noticed another bug that
;	the command parsing routines do not limit or check the
;	length of command lines or file specs, trashing what ever
;	comes after them.  Currently because of where the fcb and
;	command buffer are located, this does not usually cause a
;	problem, but could if an extremely long line was typed in,
;	or in the future multiple fcbs defined elsewhere in memory
;	were used.  Maybe this should be put on the bug list
;	somewhere.
;
; edit 3: July 27, 1984
;	Allow assembly with LASM: to CP4TT is linked by CP4PKT, and links
;	to CP4CPM; remove exclamation points so as not to confuse LASM.
;	Add Toad Hall TACtrap to TRANSMIT command (TAC intercept character
;	is only doubled if it's data; when typed by the user, they're not
;	automatically doubled)
;
; edit 2: June 7, 1984
;	formatting and documentation; add module version number; make sure
;	console is selected when leaving intchr.
;
; edit 1: May, 1984
;	extracted from CPMBASE.M80 version 3.9; modifications are described
;	in the accompanying .UPD file.

ttver:	db	'CP4TT.ASM  (4)  13-Jan-85$'

;	This is the TRANSMIT command.  It attempts to send a file, even
;	though there is no KERMIT on the other side.
;	here from: kermit

xmit:	mvi	a,cmofi		;Parse an input file spec (non-wild).
	lxi	d,fcb		;Give the address for the FCB.
	call	comnd
	 jmp	kermit		;Give up on bad parse.
	call	cfmcmd
	call	getfil		;Open file.
	cpi	0FFH		;Succeed?
	jnz	xmit1
	lxi	d,erms15
	call	prtstr		;Display error msg.
	jmp	kermit

xmit1:	lxi	d,inms19	;Output start message.
	call	prtstr
	call	escpr		;Print the escape character.
	lxi	d,inms20	;Output 2nd part.
	call	prtstr
	call	escpr		;Print the escape character.
	lxi	d,inms21	;Print the rest.
	call	prtstr
	mvi	a,1		;Start file I/O.
	sta	fileio
	xra	a		;Clear XOFF flag.
	sta	xofflg
	; fall through into xnext...
;
;	assemble another line from the disk file.
;	here from: previous page, rexmit

xnext:	call	prtchr		; Copy characters from comm line to console
	mvi	c,consta	;  until user types anything on the console.
	call	bdos
	ora	a
	jz	xnext		; nothing at console yet.
	lda	eoflag		;EOF encountered?
	ora	a
	jnz	xend		;Yes, finish.
	xra	a		;Reset line buffer counter.
	mov	c,a
	sta	cmaflg		;Reset carriage return flag.
	lxi	d,cmdbuf	;Use comnd buffer as line buffer.
	lhld	bufpnt		; Get current buffer pointer.
	lda	chrcnt		; Get current byte count
	mov	b,a		;  in B
xmit30:	dcr	b		; Assume there's a character there
	jp	xmit2		; If there was, proceed.
	call	inbuf		; There wasn't.  Try for another buffer.
	 jmp	xmit38		; End of file.
	lhld	bufpnt		; Got another buffer.  Get new pointer in HL
	lda	chrcnt		;  and new byte count
	mov	b,a		;  in B
xmit2:	mov	a,m		;Get a character from disk buffer.
	inx	h
	ani	7FH		;Mask 7 bits.
	jz	xmit30		;Skip nulls.
	cpi	cr		;Carriage return?
	jz	xmit32
	cpi	subt		;CTRL-Z (substitute)?
	jz	xmit37
	cpi	lf		;Line feed?
	jz	xmit39
	stax	d		;Save to buffer.
	inx	d
	lda	cmaflg		;Carriage return seen?
	ora	a
	jnz	xmit31		;Yes, don't count this character.
	inr	c		;Count it.
xmit31:	jmp	xmit30		;Loop for next input byte.

; Carriage return seen.  Start discarding characters until we see a line-feed.
xmit32:	sta	cmaflg		;Mark return seen.
	jmp	xmit30		;And continue.

; Control-Z seen. Force end of file, and send the current line.
xmit37:	sta	eoflag		;Mark EOF for next line.
	; fall through...
; End of File encountered. eoflag has already been set; just send current line.
xmit38:
	; fall through...
; Linefeed seen. send the current line.
xmit39:	shld	bufpnt		;Save next buffer pointer.
	mov	a,b		;Save count of remaining characters.
	sta	chrcnt
	mov	a,c		;Save line length.
	sta	filcnt
	; fall through into rexmit...
;

;	transmit the buffered line.
;	here from: previous page, intchr

rexmit:	lda	filcnt		;Set up line length.
	sta	cmccnt
	lxi	h,cmdbuf	;Set up line buffer pointer.
	shld	cmcptr
xmit40:	call	prtchr		;Receive comm. line & display.
	lda	xofflg		;XOFF received?
	ora	a
	jnz	xmit40		;Yes, wait for XON
	lda	cmccnt		;Any characters left?
	dcr	a
	jm	xmit49		;No, next state.
	sta	cmccnt
	call	selmdm		; select modem for outmdm
	lhld	cmcptr		;Get the character to be sent
	mov	a,m
	inx	h		;Bump to next character.
	shld	cmcptr
	call	setpar		;Set parity (if any).
	mov	e,a		;Save character (with parity)
	call	outmdm		;Output it to the comm. line.
; TAC trap: If this character is the TAC intercept character, and the TAC
; trap is enabled, we have to output it twice.  If the TAC trap is enabled,
; tacflg contains the intercept character.  (The current character cannot
; be NUL, so we don't have to worry about doubling nulls in the message)
	lda	tacflg		; get current intercept character, or zero.
	cmp	m		; compare against current data character.
	jnz	xmit41		; if different, do nothing.
	call	setpar		; match. set appropriate parity,
	mov	e,a		;  put it in the right register,
	call	outmdm		;  and output it a second time.
xmit41:
	lda	ecoflg		;Local echo?
	ora	a
	jz	xmit40		;No, continue.
	mov	a,e		;Get the character.
	ani	7FH		;Mask out parity.
	mov	e,a		;Display on console.
	call	selcon
	call	outcon
	jmp	xmit40		;Continue.

xmit49:	xra	a		;Reset last character seen.
	sta	lstchr
xmit50:	call	prtchr		;Receive comm. line & display.
	call	conchr		;Read keyboard & send.
	 jmp	xendc		;CLOSE connection.
	lda	lstchr		;Check last keyboard character.
	cpi	cr		;Carriage return?
	jz	xnext		;Yes, prepare to send next line.
	jmp	xmit50		;Continue, until carriage return.
;
;	clean up.
;   xend - end of file reached. close file, go to connect mode.
;	here from: xnext.
;   xendc - user wants out. close file, go to command mode.
;	here from: rexmit.

xend:	call	xmtoff		;Close file, etc.
	lxi	d,inms22	;Tell we're done with transmission
	jmp	telnt1		;Branch to CONNECT command.

xendc:	call	xmtoff		;Close file, etc.
	jmp	kermit		;Back to command loop.

xmtoff:	mvi	c,closf		;Close file.
	lxi	d,fcb
	call	bdos
	xra	a		;Terminate file I/O.
	sta	fileio
	ret
;
;   telnet - the CONNECT command.
;	here from: kermit
;   telnt1 - entry to connect mode from TRANSMIT command
;	here from: xend

telnet:	call	cfmcmd
	lxi	d,infms7	;Output start of message
; enter here from TRANSMIT command.
telnt1:	call	prtstr
	call	escpr		;Print the escape char.
	lxi	d,infms8	;Output some more of the message
	call	prtstr
	call	escpr		;Print the escape char again.
	lxi	d,inms8a	;Print the remainder of the message
	call	prtstr
	call	syscon		;do system-dependent stuff
	lda	logflg		;[pcc005] Want a log?
	ora	a		;[pcc005]
	cnz	logopn		;[pcc005] Open if so

chrlup:	call	prtchr		;See if char at port (send to console).
	call	conchr		;See if char at console (send to port).
	 jmp	kermit		;requested to end session - go to command loop.
	jmp	chrlup		;Go do it again.
;
;
;	prtchr - copy characters from comm line to console
;	returns: nonskip, console selected.
;	called by: xnext, rexmit, telnet
;

prtchr:	call	selmdm		; select modem port
	call	inpmdm		; try to get a character from it
	ora	a		; test character
	jnz	prtch0		; if non-zero, process it.
	sta	prtcnt		;[pcc008] zero out prt fairness count
	call	selcon		; select console
	ret			; return.

prtch0: ani	7FH		; drop parity bit.
	jz	prtchr		; ignore null (filler)
	cpi	del		; ignore delete, too
	jz	prtchr
	cpi	xon		;Is it an XON?
	jz	prtxon		;yes
	cpi	xoff		;Is it an XOFF?
	jz	prtxof		;yes
	mov	e,a		;Set the char aside.
	lda	vtflg		;Get the VT52 emulation flag.
	cpi	1		;Is the flag set?
	jnz	prtch1		;If not, don't do this stuff.
	lda	escflg		;Get the escape flag.
	ora	a		;Are we working on an escape sequence?
	jz	prtch2		;If not, continue.
	call	vt52		;If so, work on it some more
	jmp	prtchr		;try for more characters.

prtch2:	mov	a,e		;normal text.
	cpi	esc		;Is the char an escape?
	jnz	prtch1		;If not skip on.
	mvi	a,1
	sta	escflg		;Set the escape flag: escape seen.
	jmp	prtchr		;Get another char...

prtch1:	call	sysflt		; ok to print this character (in E)?
	ora	a
	jz	prtchr		; no, skip it.
	lda	logflg		;Get the log flag.
	cpi	81H		;[pcc003] Are we logging
	cz	logit		;[pcc003] Do so if needed
	call	selcon		; select console
	lda	prnflg		;Get Print parallel flag
	ora	a
	cnz	outlpt		; output to printer if flag set
	call	outcon		; output to console.
	lxi	h,prtcnt	;[pcc008] point to prt fairness count
	inr	m		;[pcc008] bump
	mov	a,m		;[pcc008] get it in a
	cpi	prfair+1	;[pcc008] time to be fair?
	jm	prtchr		;[pcc008] no, go around again.
	mvi	m,0		;[pcc008] reset count
	ret			;[pcc008] and return

; I don't think we want to print xon/xoff - this should be
; flow control only across the link between us and the host.
; (besides, IBM host xon's don't make sense to most micros)
; remember xon/xoff state in xofflg (zero = xon, non-zero = xoff)
prtxon:	xra	a		;Yes, reset XOFF flag
prtxof:	sta	xofflg
	jmp	prtchr		; look for another character
;;[pcc005] Log file routines

;[pcc005]
;    logopn - open the log file
;	Open the log file and append to it if it already exists
;	or create one if not.

logopn:	lxi	h,lognam	;[pcc012] copy name
	lxi	d,fcb		;[pcc012] to fcb
	lxi	b,12		;[pcc012] 12 bytes
	call	mover		;[pcc012] copy it
	call	appfil		;[pcc012] open file for appending
	jmp	logerr		;[pcc012] error
	lxi	h,logflg	;[pcc005] point to log flag
	mvi	a,80H		;[pcc005] file open flag
	ora	m		;[pcc005] or in contents of logflg
	mov	m,a		;[pcc005] and store back
	lxi	d,inms28	;[pcc005] assume logging is on
	cpi	81H		;[pcc005] check
	jz	prtstr		;[pcc005] print msg if true
	lxi	d,inms27	;[pcc005] no, must be suspended
	jmp	prtstr		;[pcc005] print and return

;
;	logit - output character in E to log file.
;	we assume the host recognizes xon/xoff. (we probably shouldn't)
;	modem port is selected.
;	preserves de
;	called by: prtchr

logit:	lxi	h,chrcnt	;[pcc012] point to buffer count
	dcr	m		;[pcc012] and decrement
	jp	logit1		;[pcc012] continue if ok
	push	d		;[pcc012] save de
	call	outadv		;[pcc012] advance buffer if in memory
	call	logwrt		;[pcc012] sigh, time to write to disk
	pop	d		;[pcc012] restore de
	lda	logflg		;[pcc012] get logging flag
	ora	a		;[pcc012] Did we quit because of an error
	rz			;[pcc012] return now if so
logit1:	lhld	bufpnt		;[pcc012] get buffer pointer
	mov	m,e		;Store the char.
	inx	h
	shld	bufpnt
	ret			;[pcc012] and return

;[pcc012]
;  logwrt - write to log file with XON/XOFF since it may take a while.

logwrt:	mvi	a,xoff		;^S to stop the host while we write the buffer.
	call	setpar		; set correct parity...
	mov	e,a
	call	outmdm		; output it.
	call	outbuf		;[pcc012] output the buffer and advance
	call	logerr		;[pcc005] quit if error
	mvi	a,xon		;^Q to restart the host
	call	setpar		; set appropriate parity
	mov	e,a
	call	outmdm		; send it.
	ret			;[pcc012]

;[pcc005]
;	logcls - Close the log file and reset the flag

logcls:	lxi	d,infms6	;[pcc005] Tell user we are closing file.
	call	prtstr		;[pcc005]
	call	clofil		;[pcc012] and do it
	jmp	logerr		;[pcc005] jump if error
	lxi	h,logflg	;[pcc005] point to flag
	mov	a,m		;[pcc005] get it
	ani	7FH		;[pcc005] clear the open bit
	mov	m,a		;[pcc005] and store back
	ret			;[pcc005]

;[pcc005]
;    logerr - here on a variety of logging errors
;	just close the file and disable logging
;	called from logopn,logptr,logcls

logerr:	lxi	d,erms22	;[pcc005] Error message
	call	prtstr		;[pcc005] print it
	mvi	c,closf		;[pcc005] Close the file.
	lxi	d,fcb		;[pcc012]
	call	bdos		;[pcc005] 
	xra	a		;[pcc005] clear logflg
	sta	logflg		;[pcc005] so don't try again
	ret			;[pcc005]
;
;
;	VT52 emulation.
;	called by: prtchr
;	A/ contents of escflg (guaranteed non-zero)
;	E/ current character
;	modem is selected.
;
vt52:	cpi	1		; first character after escape?
	jnz	vt52y		; no, must be doing cursor positioning.
;
;	E contains the character that followed the escape.
;	valid characters are:
;	A - cursor up
;	B - cursor down
;	C - cursor right
;	D - cursor left
;	F - enter graphics mode (hard to do on a non-vt52)
;	G - exit graphics mode
;	H - home
;	I - reverse linefeed
;	J - erase to end of screen
;	K - erase to end of line
;	Y - cursor positioning leadin
;	Z - identify terminal as VT52
;	[ - enter hold-screen mode (not supported)
;	\ - exit hold-screen mode (not supported)
;	> - enter alternate-keypad mode? (not supported)
;	= - exit alternate-keypad mode? (not supported)
;
;	Invalid sequences are handled as the VT52 does - the escape and
;	the following character are swallowed, never to be seen again.
;	For <esc>E, the translation table may contain just '$' (no action),
;	or may be used as clear-and-home, as in the Heath/Zenith H19.
;
	mov	a,e		; get the second character of the sequence.
	cpi	'Y'		; if cursor lead-in handle it.
	jnz	vt52a		; if not, go on.
	mvi	a,2		; state = 2: row follows.
	sta	escflg		; update the flag.
	ret			; back for another character

vt52a:	cpi	'Z'		; VT52 ID query?
	jz	vt52id		; yes. claim to be one.
	cpi	'A'		;Less than an 'A'?
	jm	vtig		;Yes - ignore.
	cpi	'K'+1		;Greater than 'K'?
	jp	vtig		;Yes - ignore.
	sui	'A'		;Else make into index.
	rlc			;Multiply by four.
	rlc			;(Shift left twice.)
	lhld	pttab		;Load base addr of table.
	mov	e,a		;Move a into de pair.
	mvi	d,00H		;Zero out high byte.
	dad	d		;Double add index+offset.
	xchg			;Exchange de with hl.
	call	selcon		; select console
	call	prtstr		;and syscall.
vtig:				;Ignore escape sequence.
	xra	a		;Reset the ol' escape flag.
	sta	escflg
	ret			;Return home.

; here for <esc>Z.  Tell the host we're a VT52. (Sure we are...)
vt52id:	mvi	a,esc		; response is escape...
	call	setpar		; (need correct parity)
	mov	e,a
	call	outmdm		; (console already selected)
	mvi	a,'/'		; ... slash ...
	call	setpar		; (with parity)
	mov	e,a
	call	outmdm
	mvi	a,'K'		; ... K.
	call	setpar
	mov	e,a
	call	outmdm
	jmp	vtig		; clear escape-sequence flag and return.

; here when escflg isn't 0 or 1 - processing cursor positioning sequence.
vt52y:	cpi	2		; looking for row? (y-coordinate)
	jnz	vt52x		; no, must be column.
	mov	a,e		; yes. get coordinate
	sui	(' '-1)		; convert from ascii (1 = top line)
	sta	vtyval		; store for later
	mvi	a,3		; advance to next state (x coord)
	sta	escflg		; store it
	ret			; try for another character

; here when escflag isn't 0, 1, or 2 - it must be 3. (right?)
; E holds the last character of the cursor positioning sequence.
vt52x:	xra	a		; end of escape sequence, reset state.
	sta	escflg
	mov	a,e		; get column (' ' is left margin)
	sui	(' '-1)		; make left margin be one
	mov	c,a		; stash column in c
	lda	vtyval		; get row number
	mov	b,a		;  in b
	call	selcon		; select console
	call	csrpos		; call system-dependent cursor positioner
	ret			; all through.
;
;
;	conchr - copy character from console to comm line, processing
;	(kermit's) escape sequences.
;	Enter and exit with console selected.
;	nonskip return: transparent mode terminated.
;	skip return:	still in transparent mode.
;	called by: rexmit, telnet

conchr:	call	inpcon		;Try to get a character from the console
	ani	07FH		;Keep only 7 bits
	jz	rskp		;Null means nothing there.
	mov	e,a		;Move the char for comparison.
	sta	lstchr		;Save it
	lda	escchr		;Get the escape char.
	cmp	e		;Is it an escape char?
	jz	intchr		;If so go process it.
	call	selmdm		; select the modem
	mov	a,e		;Get the char.
	call	setpar		;Set parity (if any).
	mov	e,a		;Restore it.
	call	outmdm		;Output the char to the port.
	call	selcon		; reselect console
	lda	ecoflg		;Get the echo flag.
	ora	a		;Is it turned on?
	jz	rskp		;If not we're done here.
	mov	a,e		;Get the char.
	ani	7FH		;Turn off the parity bit.
	mov	e,a
	call	outcon		; echo the character.
	jmp	rskp		; use skip return
;
;	transparent escape character has been typed. dispatch on second
;	character. (console is still selected)
;	here from: conchr

intchr: call	inpcon		; get another character from the console
	ora	a		; zero means no character available yet.
	jz	intchr		; If so, loop until we get a char.
	mov	b,a		;Save the actual char.
	cpi	ctrlc		;is it Control-C?
	jz	contc		;yes
	ani	137O		;Convert to upper case.
	cpi	'C'		;Is it close?
	jnz	intch0		;If not proceed.
contc:	lxi	d,infms9	;Say we are back.
	call	prtstr
	call	syscls		; call system-dependent close routine
	lda	logflg		;Get the log flag.
	ora	a		;[pcc005] Check if open
	cm	logcls		;[pcc005] Close if needed
	ret

;Here if not a 'C' or '^C'

intch0: cpi	'S'		;Is it status?
	jnz	inch01		;If not, proceed.
	call	stat01		;Print out the status stuff.
	call	prcrlf		;[pcc011] add a crlf
	jmp	rskp		;return from conchr

inch01:	cpi	'R'-100O	;Control-R?
	jz	inch02		;Yes
	cpi	'R'		;(plain) R?
	jnz	inch03		;No
inch02:	lda	fileio		;TRANSMIT in progress?
	ora	a
	jz	inch03		;No,ignore
	pop	b		;Remove return address (non-local goto)
	jmp	rexmit		;Retransmit line

inch03:	mov	a,b		;Get the char.
	cpi	'?'		;Is it a help request?
	jnz	intch1		;If not, go to the next check.
	lda	fileio		;TRANSMIT in progress?
	ora	a
	jz	inch3a		;[pcc003] No
	lxi	d,xmthlp	;Tell about R too
	call	prtstr
inch3a:	lda	logflg		;[pcc003] Logging flag
	ora	a		;[pcc003] see if active
	jp	inch04		;[pcc005] jump if no file open
	lxi	d,loghlp	;[pcc003] yes, tell about R AND Q
	call	prtstr		;[pcc003]
inch04:	lxi	d,inthlp	;If so, get the address of the help message.
	call	prtstr
	call	sysinh		; print system-dependent help message
	lxi	d,inhlp1	; Tell about doubling the escape character
	call	prtstr
	call	escpr		;Print escape character
	lxi	d,inhlp2	;Print the rest
	call	prtstr
	jmp	intchr		;Get another char.

intch1: mov	a,b		;Get the character.
	cpi	'0'		;Is it '0', to send a null?
	jnz	intch3		;No.
	xra	a		;Yes, send an ASCII zero.
	call	setpar		; with the correct parity
	mov	e,a
	call	selmdm		; (to the modem...)
	call	outmdm
	call	selcon		; return with console selected
	jmp	rskp

intch3:	lda	escchr		;Get the escape char.
	cmp	b		;Is it the escape char?
	jnz	intch4		;[pcc002] jump if not
	mov	a,b		;Get the char.
	call	setpar
	mov	e,a		;Restore it.
	call	selmdm
	call	outmdm		;Output it.
	call	selcon		;We promised console would be selected...
	jmp	rskp		;Return, we are done here.
intch4:	mov	a,b		;[pcc002] get it again
	ani	137o		;[pcc002] in upper case
	cpi	'P'		;[pcc002] toggle printer?
	jnz	intch5		;[pcc003] nope
	lda	prnflg		;[pcc002] get printer flag
	xri	01h		;[pcc002] complement it
	sta	prnflg		;[pcc002] and put back
	jmp	rskp		;[pcc002]
intch5:	lda	logflg		;[pcc003] get log flag
	ora	a		;[pcc003] See if open
	jp	intch7		;[pcc003] no, skip R and Q
	mov	a,b		;[pcc003] get back chr
	ani	137o		;[pcc003] make upper case
	cpi	'R'		;[pcc003] Is it R
	jnz	intch6		;[pcc003] Jump if not
	mvi	a,81H		;[pcc003] set flag for logging
	sta	logflg		;[pcc003] put it back
	lxi	d,inms28	;[pcc003] message
	call	prtstr		;[pcc003]
	jmp	rskp		;[pcc003] done
intch6:	cpi	'Q'		;[pcc003] Quit logging?
	jnz	intch7		;[pcc003] no
	mvi	a,82H		;[pcc003] flag for open, but suspended
	sta	logflg		;[pcc003] store away
	lxi	d,inms27	;[pcc003] keep them informed
	call	prtstr		;[pcc003]
	jmp	rskp		;[pcc003]
intch7:				;[pcc003]

intchz:	mov	a,b		; not recognized. get saved copy back.
	call	sysint		; interpret system-dependent sequences
	 jmp	rskp		;  done. return (from conchr).
	mvi	e,'G'-100O	;Otherwise send a beep.
	call	outcon		; to the console.
	jmp	rskp
;
IF lasm
	LINK	CP4CPM
ENDIF;lasm
