; CPSPK1.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
;       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 (system-independent) routines that implement
;       the KERMIT protocol, and the commands that use them:
;       RECEIVE, SEND, FINISH, and LOGOUT.
;
; revision history:
;
;edit 23, 16-Jan-1991 by MF. The bug of (22) was not fixed (although
;	the error described needed to be corrected). Really fixed the bug this:
;	time. changed "lda 'E'" after "ptch9b" to "mvi a,'E'" -- Zilog
;	mnemonic thinking must've addled my brain!
;edit 22, 14-Jan-1991 by MF. Fix bug in the code which sends an "E" packet
;	to the remote Kermit on encountering "disk full" so that
;	uncontrollified <CR><LF> is not copied to the packet data area (and
;	hence sent to the remote Kermit). This should fix a bug reported
;	by Russell Lang of Monash University in Australia wherein a PC
;	running Kermit in Server mode complained of invalid characters when
;	receiving the "disk full" error packet from CP/M Kermit.
;edit 21 of 3-Jan-1991 by MF. Reverse part of edit 20 which flushes comm
;	input at EOF send: the problem of multiple copies of packets being
;	sent when a stream of files being sent is partially interrupted with
;	^X has been fixed by modifying "inchr" in CPSPK2.ASM.
;edit 20, 2-Jan-1991 by MF. Tightened up code just after "sdata1" and around
;	"sdat14". Added code to flush comm input after user has typed ^X
;	or ^Z to interrupt file sends so that duplicate packets are not
;	sent after the interrupt character (especially ^X) has been typed.
;edit 19, 14-Dec-1990 by MF.  Place "<<>>" around "F" and "X" packets coming
;	as replies to REMOTE commands a la VMS Bliss Kermit.
;	Also type each character of "X" or "F" packet explicitly in case
;	dollar-signs are part of the filename (as in VMS Bliss Kermit
;	when a REMOTE TYPE is given and SET FILE NAMING FULL is in effect).
;	Expanded code is at label rfil3f.
;edit 18, 27-Nov-1990 by MF. Fix bug introduced with edit 17 which resulted
;	in "E" packet being sent twice when receiving file(s) and disk-full
;	occurred. Sorry about that, folks!
;edit 17, 27-Nov-1990 by MF. When receiving files, make the decision as to
;	whether to delete a partially-received file on a "disk full"
;	condition subject to the setting of the SET INCOMPLETE-FILES
;	switch in conformity with the behavior of MSDOS Kermit.
;	An "E" packet is still sent to the remote Kermit. Also try to close
;	any incomplete file whether deleting it or not (labels rdat16 and
;	rdat3a). If keeping incomplete files, try to write outstanding
;	buffers to disk, giving an error if the disk is full.
;edit 16, 23-Nov-1990 by MF. When receiving, cause the file being written
;	to disk to **always** be deleted and an "E" packet to be sent when a
;	"disk full" condition is encountered (per suggestion of
;	RJL@MONU1.CC.MONASH.EDU.AU).
;edit 15, 15-Nov-1990 by MF.  Changed code for the Receive Complete state
;	to always go into RECEIVE if AUTORECEIVE is on.  This will happen
;	most of the time anyway as most mainframe Kermits issue a prompt
;	after a single SEND command (wild-carded or not), thus guaranteeing
;	that the modem status check of Kermit-80 ver. 4.09 would **always**
;	have characters ready for input (the mainframe Kermit's prompt),
;	defeating the status check and the Console input check (originally
;	intended to drop the user out of the loop if he/she typed a key with
;	no comm input present).  Eliminate "any key" message there also.
;	the user can drop out by hitting ^C.
;	Of course, none of the foregoing applies if the Receive Complete
;	state occurs as the result of a "Get" command where Autoreceive
;	is meaningless and we just drop back to Kermit command-level.
;edit 14, 1-Oct-1990 by MF.  Added code to send an "I" packet before an
;	"R" packet in GET command.
;	Modified routine "sinit" to ignore "E" packets when sending an
;	"i" packet (per KPROTO.DOC).
;edit 13, 14-Sep-1990 by MF.  Added code to implement SET FILE COLLISION
;	and SET INCOMPLETE commands.
;edit 12, 9-Sep-1990 by MF.  Added code to prevent packet counts
;	from being displayed during Remote commands.  Fixed
;	AUTORECEIVE 	code, file colision Rename algorithm and eliminated
;	multiple display of initial messages during GET/RECEIVE.
; edit 11, 28 July, 1987 by OBSchou.  Commented out capas etc support
;	(Long packets etc) as this is not worth the effort coding... but
;	I have left what WAS done for any enthusiast.  Also set in a few
;	to NOT write to screen if SET TERMINAL QUIET set.  Hopefully speeds
;	up transfers on systems taking forever to update screens.
;
; edit 10, 8 April, 1987 by OBSchou.  Tarted up all sorts of bits n bobs
;	to cope with all the new aditions for Kermit-80 V 4.09
;	Look for the [10] for most cahnges.  spar and rpar largely replaced
;
; edit 9, March 30th by OBSchou.  Set bits for automatically receiving
;	another file if a remote sender sends files in seperate sessions.
;	The code simply checks the serial line, and if there is some
;	activity, assume its another SEND INIT packet.  As there is no
;	simple way to go to receive with the control-a, just ignore the
;	packet.  Causes one retry on the sender, but so what.  Really 
;	should make it a server gizzmo.
;
; edit 8: January 28, 1987 by OBSchou
;	Two major issues: firstly split CPSPKT.ASM into CPSPK(1 2).ASM
;	making it far easier to handle this file.
;	Second, some mode to the GET routines to correctly print the file
;	name instead of the fireworks.  Trouble was with GET <file> <file>
;	and RECEIVE <file>.  However, new bugs discovered...
;
; edit 7: August 11, 1986    Godfrey N. Nix [gnn] Nottingham University
;       To ignore echoed packets (ie send 'S' receive 'S' before 'A');
;       To allow character other than SOH for packet header (see also
;                       updates to CP4MIT and CP4UTL for other code needed);
;       To permit SEND and RECEIVE to specify a host filename which
;                       is of a different structure to that of CP/M.
;
; edit 6a: [OBSchou] 7 March, 1985.
;       Edited file with additions from MJ Carter.  He writes:
;       25th September 1985, M J Carter [majoc], Nottingham University
;       Code in gofil() amended, for exactly the same reasons to the 
;       alteration to cmifil() in cpscmd.asm.  If there is any deep
;       reason why gofil() has to be used instead of a call to comnd(cmofil), 
;       I can't see it.  The bug (on a British Micro Mimi 803) caused 
;       gofil() to overwrite existing files in GET and RECEIVE, even 
;       with file warning SET ON.
;
;edir 6: November 22, 1984
;       Change SEND's 'Unable to find file' error exit from calling
;       error3 to calling prtstr instead.  I don't know about you, but
;       I greatly dislike having messages dumped into pre-existing
;       junk on the screen where I have to spend lots of time hunting
;       for them.  [Hal Hostetler]
;
; edit 5: September 9, 1984
;       Call flsmdm in init to flush old input when starting transfers.
;       Select console before returning from inpkt.
;       Replace inline code with calls to makfil/clofil to set up for
;       multisector buffering on output.
;       Remove superfluous call to clrlin in error3.
;
; edit 4: August 21, 1984 (CJC)
;       Fix comment in inpkt: packet is terminated by NUL on return, not CR.
;       If debugging, display the outgoing packet before putting the EOL
;       character on, so the dumped packet doesn't get overwritten.
;
; edit 3: July 27, 1984
;       add link directive for LASM.  CP4PKT is linked by CP4MIT, and links
;       to CP4TT.  Add Toad Hall TACtrap to permit operations through a TAC.
;
; edit 2: June 8, 1984
;       formatting and documentation; remove some unused labels; move setpar
;       to cp4mit.m80; add module version string; make all arithmetic on
;       'pktnum' modulo 64; apply defaults correctly for missing parameters
;       in send-init packet (and corresponding ack).
;
; edit 1: May, 1984
;       extracted from CPMBASE.M80 version 3.9; modifications are described
;       in the accompanying .UPD file.
;
pk1ver:	db	'CPSPK1.ASM (23) 16-Jan-1991$'	; name, edit number, date

;       GET command   [gnn]
;       here from: kermit

read:	mvi	a,0ffh		;[obs 8] we are doing a get
	sta	getrxflg	;[obs 8] so set flag
	lxi	d,remdat	;Where to put the text (if any.)
	mvi	a,cmtxt
	call	comnd		;Get either some text or a confirm.
	jmp	kermt3		; Didn't get anything.
	ora	a		;Get any chars?
	jz	kermt3		;[gnn] GET must have a filename
	sta	rdl		;Store the number of chars.
	xchg			;Get pointer into HL.
	mvi	m,'$'		;Put in a dollar sign for printing.
	call	init		;Clear the line and initialize the buffers.
	lda	quietd		; quiet display?
	ana	a
	jz	read01		;[MF]No, go ahead and position cursor
	call	prcrlf		;[MF]Yes, keep from overwriting the prompt
	jmp	read00		;[MF]and write filename
read01:	call	scrfln		;Position cursor [MF]
read00:	lxi	d,remdat	;Print the file name, in either case
	call	prtstr
	jmp	read0a		;[gnn] go get local name if any


; enter here for RECEIVE command  [gnn]
read0:	mvi	a,0		;[gnn]
	sta	rdl		;[gnn][MF] flag entry as receive, not get
	sta	getrxflg	;[obs 8] doing a receive, so reset flag
	call	init		;clear line, initialise buffers
read0a:	lxi	d,remnam	;[gnn] save local name here
	mvi	a,cmtxt		;[gnn]
	call	comnd		;[gnn] read second filename if present
	jmp	kermt3		;[gnn]  error exit
	sta	remlen		;[gnn] save length of name, may be zero
	sta	getrxflg	;[obs 8] May also be receive <fnam> so 
				;[obs 8]pretend get for printing filename
	lda	rdl		;[gnn] look at first name
	ora	a		;[gnn] receive or get?
	jz	read1		;[gnn] receive

	mvi	a,'I'		;[MF]Set state to send "I" packet
	sta	state		;[MF]...

;       jmp     read12		;[obs] [gnn] does not want this

read1:	;call   init		;Clear the line and initialize the buffers.
read12:	xra	a
	sta	czseen		;Clear the ^X/^Z flag initially.
	lxi	h,0
	shld	numpkt		;Set the number of packets to zero.
	shld	numrtr		;Set the number of retries to zero.
	sta	pktnum		;Set the packet number to zero.
	sta	numtry		;Set the number of tries to zero.
	lda	quietd		; quiet display?
	ana	a
	jnz	read13		; yes, so dont write...
	call	scrnrt		;Position cursor
	lxi	h,0
	call	nout		;Write the number of retries.
read13:	lda	rdl		;[MF]Get or receive?
	ora	a		;[MF]...
	jnz	read2		;[MF]Get, don't reset state
	mvi	a,'R'
	sta	state		;Set the state to receive initiate.
	;...
;
;RECEIVE state table switcher.

read2:	lda	quietd		; noisy display?
	ana	a
	jnz	read21		; no, a quiet one
	lda	remtxt		;[MF] In Remote command?
	ora	a
	jnz	read21		;[MF] Yes, don't write to screen
	call	scrnp		;Position cursor
	lhld	numpkt
	call	nout		;Write the current packet number.
read21:	lda	state		;Get the state.
	cpi	'D'		;Are we in the DATA receive state?
	jnz	read22
	call	rdata
	jmp	read2

read22:	cpi	'X'		; F packet but not an F packet?
	jnz	read3		; nope, so try next one
	call	rfile		; 'get' the filename (but dont open it)
	jmp	read2

read3:	cpi	'F'		;Are we in the FILE receive state?
	jnz	read4
	call	rfile		;Call receive file.
	jmp	read2

read4:	cpi	'R'		;Are we in the Receive-Initiate state?
	jnz	read5
	call	rinit
	lda	state		;[jd] get new state
	cpi	'F'		;[jd] went into receive state?
	jnz	read2		;[jd] no
	lxi	d,inms24	;[jd] yes, get receiving... message
	call	finmes		;[jd] go print it
	jmp	read2

read5:	cpi	'C'		;Are we in the Receive-Complete state?
	jnz	read6
	lxi	d,infms3	;Put in "Complete" message.
	lda	czseen		;Or was it interrupted?
	ora	a		; .  .  .
	jz	read5a		;No.
	xra	a		;Yes, clear flag.
	sta	czseen		; ...
	lxi	d,inms13	;Issue "interrupted" message.
read5a:	lda	remtxt		;[MF] Doing a Remote command?
	ora	a
	cz	finmes		;Print completion message in right place if not
;
	lda	rdl		;[MF]Receive or Get?
	ora	a		;[MF]...
	jnz	kermit		;[MF]Get, Autoreceive means nothing.
	lda	autorc		; see if we want autoreceives
	ana	a
	jz	kermit		;[MF]No autoreceives, so drop out
	lxi	d,autmes	;[MF]Yes, tell the user what we're doing
	call	prtstr		;[MF]...
	jmp	read1		;[MF]Try another Receive (we get one
				;[MF]retry from the sender as the ^A is lost)

read6:	cpi	'Y'		;[MF]Simple ack (from remote command)?
	jz	kermit		;[MF]Yes

	cpi	'I'		;[MF]Exchanging parameters via info packet?
	jnz	read7		;[MF]No
	call	sinit		;[MF]Yes, send the packet
	lda	state		;[MF]Now see what happened
	cpi	'X'		;[MF]Did we exchange parameters successfully?
	jz	read6a		;[MF]Yes, go send the filespec
	cpi	'A'		;[MF]No, are we in abort state?
	jnz	read2		;[MF]No, try again
	jmp	kermit		;[MF]Yes, it's a real disaster, we must stop
read6a:	lda	rdl		;[MF]Get length of filespec
	sta	argblk+1	;[MF]as length of packet
	mov	c,a		;[MF]We must copy the filespec
	mvi	b,0		;[MF]...
	lxi	h,remdat	;[MF]from the temporary buffer
	lxi	d,data		;[MF]to the packet data area
	call	mover		;[MF]Do it.
; for GET we must send the name of the file we want [gnn]

	mvi	a,'1'		;Start with single character checksum
	sta	curchk		;Save the type
	xra	a		;Start a packet zero.
	sta	argblk
	mvi	a,'R'		;Receive init packet.
	call	spack		;Send the packet.
	jmp	kermt3		; Die!
	xra	a
	sta	czseen		;Clear the ^X/^Z flag initially.
	lxi	h,0
	shld	numpkt		;Set the number of packets to zero.
	sta	pktnum		;Set the packet number to zero.
	sta	numtry		;Set the number of tries to zero.
	mvi	a,'R'		;[MF]Set state to Receive-Initiate
	sta	state		;[MF]...
	jmp	read21		;[MF]and go around again
				;[MF]without retyping packet-number

read7:	cpi	'A'		;Are we in the Receive-"Abort" state?
	jnz	read8
read8:	lxi	d,infms4	;Anything else is equivalent to "abort".
	call	finmes
	jmp	kermit
;
;       Receive routines

;       Receive init
;       called by: read

rinit:	lda	numtry		;Get the number of tries.
	cpi	imxtry		;Have we reached the maximum number of tries?
	jm	rinit2
	lxi	d,ermes4
	call	error3		;Move cursor and print an error message.
	jmp	abort		;Change the state to abort.

rinit2:	inr	a		;Increment it.
	sta	numtry		;Save the updated number of tries.
	mvi	a,'1'		;Reset block check type to single character
	sta	curchk		;Store as current type for initialization
	call	rpack		;Get a packet.
	jmp	nak		; Trashed packet: nak, retry.
	cpi	'S'		;Is it a send initiate packet?
	jnz	rinit3		;If not see if its an error.
rini2a:	lda	numtry		;Get the number of tries.
	sta	oldtry		;Save it.
	xra	a
	sta	numtry		;Reset the number of tries.
	lda	argblk		;Returned packet number.  (Synchronize them.)
	call	countp
	lda	argblk+1	;Get the number of arguments received.
	lxi	h,data		;Get a pointer to the data.
	call	spar		;Get the data into the proper variables.
	lxi	h,data		;Get a pointer to our data block.
	call	rpar		;Set up the receive parameters.
	sta	argblk+1	;Store the returned number of arguments.
	mvi	a,'Y'		;Acknowledge packet.
	call	spack		;Send the packet.
	jmp	abort		; Failed, abort.
	lda	inichk		;Now switch to agreed upon check-type
	sta	curchk		;For all future packets
	mvi	a,'F'		;Set the state to file send.
	sta	state
	ret

rinit3:	cpi	'E'		;Is it an error packet.
	jnz	nak0		;If not NAK whatever it is.
	call	error
	jmp	abort
;
;       Receive file
;       called by: read

rfile:	lda	numtry		;Get the number of tries.
	cpi	maxtry		;Have we reached the maximum number of tries?
	jm	rfile1
	lxi	d,ermes5
	call	error3		;Move cursor and print an error message.
	jmp	abort		;Change the state to abort.

rfile1:	inr	a		;Increment it.
	sta	numtry		;Save the updated number of tries.
	call	rpack		;Get a packet.
	jmp	nak		; Trashed packet: nak, retry.
	cpi	'S'		;Is it a send initiate packet?
	jnz	rfile2		; No, try next type.
	lda	oldtry		;Get the number of tries.
	cpi	imxtry		;Have we reached the maximum number of tries?
	jm	rfil12		;If not proceed.
	lxi	d,ermes4
	call	error3		;Move cursor and print an error message.
	jmp	abort		;Change the state to abort.

rfil12:	inr	a		;Increment it.
	sta	oldtry		;Save the updated number of tries.
	lda	pktnum		;Get the present packet number.
	dcr	a		;Decrement
	ani	3FH		; modulo 64
	mov	b,a
	lda	argblk		;Get the packet's number
	cmp	b		;Is the packet's number one less than now?
	jnz	nak0		;No, NAK and try again.
	call	updrtr		;Update the retry count.
	xra	a
	sta	numtry		;Reset the number of tries.
	lxi	h,data		;Get a pointer to our data block.
	call	rpar		;Set up the parameter information.
	sta	argblk+1	;Save the number of arguments.
	mvi	a,'Y'		;Acknowledge packet.
	call	spack		;Send the packet.
	jmp	abort		; Failed, abort.
	ret

rfile2:	cpi	'Z'		;Is it an EOF packet?
	jnz	rfile3		; No, try next type.
	lda	oldtry		;Get the number of tries.
	cpi	maxtry		;Have we reached the maximum number of tries?
	jm	rfil21		;If not proceed.
	lxi	d,ermes6
	call	error3		;Move cursor and print an error message.
	jmp	abort		;Change the state to abort.

rfil21:	call	tryagn
	ret

rfile3:	cpi	'F'		;Start of file?
	jnz	rfil3b
	mov	c,a		;[MF]Save packet type
	lda	remtxt		;[MF]Doing a remote server command?
	ora	a		;[MF]...
	mov	a,c		;[MF]Restore packet type
	jnz	rfil3d		;[MF]If yes, same as x packet
	call	compp
	jnz	nak0		;No, NAK it and try again.
	call	countp
	mov	c,a		;[MF]
	lda	remtxt		;[MF]Doing a remote command?
	ora	a		;[MF]...
	mov	a,c		;[MF]
	jnz	rfil3a		;[MF]Yes, don't open a file
	call	gofil		;Get a file to write to, and init output buffer.
	jmp	abort
rfil3a:	lda	numtry		;Get the number of tries.
	sta	oldtry		;Save it.
	call	ackp
	mvi	a,'D'		;Set the state to data receive.
	sta	state
	lda	czseen		;Check if we punted a file
	cpi	'Z'		;and didn't want any more
	rz			;If that was the request, keep telling other end
	xra	a		;Otherwise, clear flag (^X is only for one file)
	sta	czseen		;And store the flag back
	ret

rfil3b:	cpi	'X'		;Start of 'file?' , but not a file?
	jnz	rfile4
rfil3d:	call	compp
	jnz	nak0		;No, NAK it and try again.
	call	countp

	call	selcon		;[MF]Select Console
	lda	argblk+1	; get length
	ora	a		;[MF]Anything to write?
	jz	rfil3e		;[MF]No
	push	psw		;[MF]Yes, save character count
	mvi	e,'<'		;[MF]Write "<<" as in VMSKermit
	push	d		;[MF]...
	call	outcon		;[MF]...
	pop	d		;[MF]...
	call	outcon		;[MF]...
	pop	psw		;[MF]Restore character count
	lxi	h,data		; lets write the filename (?) to display
rfil3f:	push	psw		;[MF]Save loop counter
	mov	e,m		;[MF]Get character to write
	inx	h		;[MF]and increment character pointer
	push	h		;[MF]Save the pointer
	call	outcon		;[MF]Write character to display
	pop	h		;[MF]Restore pointer
	pop	psw		;[MF]and loop counter
	dcr	a		;[MF]Decrement the counter
	jnz	rfil3f		;[MF]Display entire filename
	mvi	e,'>'		;[MF]Put in ">>" as in VMSKermit
	push	d		;[MF]...
	call	outcon		;[MF]...
	pop	d		;[MF]...
	call	outcon		;[MF]...
	call	prcrlf		;[MF]New line
rfil3e:	lda	numtry		;Get the number of tries.
	sta	oldtry		;Save it.
	call	ackp
	mvi	a,'D'		; expecting a D packet
	sta	state
	lda	czseen		;Check if we punted a file
	cpi	'Z'		;and didn't want any more
	rz			;If that was the request, keep telling other end
	xra	a		;Otherwise, clear flag (^X is only for one file)
	sta	czseen		;And store the flag back
	ret

rfile4:	cpi	'B'		;End of transmission.
	jnz	rfile5
	call	compp
	jnz	nak0		;No, NAK it and try again.
	xra	a		;No data.  (Packet number already in argblk).
	sta	argblk+1
	mvi	a,'Y'		;Acknowledge packet.
	call	spack		;Send the packet.
	jmp	abort
	mvi	a,'C'		;Set the state to complete.
	sta	state
	ret

rfile5:	cpi	'E'		;Is it an error packet.
	jnz	abort
	call	error
	jmp	abort
;
;       Receive data
;       called by: read

rdata:	lda	numtry		;Get the number of tries.
	cpi	maxtry		;Have we reached the maximum number of tries?
	jm	rdata1
	lxi	d,erms10
	call	error3		;Display error message.
rdat16:	lda	remtxt		;[MF]Is a Remote command in progress?
	ora	a		;[MF]...
	jnz	abort		;[MF]Yes, don't worry about file disposition
	lda	incflg		;[MF]Are we keeping incomplete files?
	ora	a		;[MF]...
	jnz	rdat17		;[MF]Yes
	lxi	d,fcb		;[MF]No, close the file, ignoring errors
	push	d		;[MF]while protecting the pointer
	mvi	c,closf		;[MF]...
	call	bdos		;[MF]...
	pop	d		;[MF]Now delete the file, ignoring errors
	mvi	c,delf		;[MF]...
	call	bdos		;[MF]...
	jmp	abort		;Change the state to abort.
rdat17:	call	clofil		;[MF]Try to close the file, writing
				;[MF]outstanding buffers to disk
	jmp	rdat37		;[MF]We can't, the disk is full
	jmp	abort		;[MF]Change the state to "abort"

rdata1:	inr	a		;Increment it.
	sta	numtry		;Save the updated number of tries.
	call	rpack		;Get a packet.
	jmp	nak		; Trashed packet: nak, retry.
	cpi	'D'		;Is it a data packet?
	jnz	rdata2		; No, try next type.
	call	compp		;check for correct packet number (zero flag = ok)
	jz	rdat14		;its correct
	lda	oldtry		;Get the number of tries.
	cpi	maxtry		;Have we reached the maximum number of tries?
	jm	rdat12		;If not proceed.
	lxi	d,erms10
	call	error3		;Display err msg.
	jmp	rdat16		;[MF]Change the state to abort.

rdat12:	call	tryagn
	ret

rdat14:	call	countp
	lda	numtry		;Get the number of tries.
	sta	oldtry		;Save it.
	lda	argblk+1	;Get the length of the data.
	call	ptchr
	jmp	rdat3b		;[MF] Unable to write out chars;abort.
	xra	a
	sta	numtry		;Reset the number of tries.
	sta	argblk+1	;No data.  (Packet number still in argblk.)
	mov	c,a		;Assume no data
	lda	czseen		;Check if control-X typed
	ora	a		; .  .  .
	jz	rdat15		;Zero if not typed
	mov	c,a		;Get the type of character typed
	mvi	a,1		;One data character
	sta	argblk+1	;Save the count
	mov	a,c		;Get the possible data character
	sta	data		;Store in data area
rdat15:	mvi	a,'Y'		;Acknowledge packet.
	call	spack		;Send the packet.
	jmp	rdat16		;[MF]
	ret

rdata2:	cpi	'F'		;Start of file?
	jnz	rdata3		; No, try next type.
	lda	oldtry		;Get the number of tries.
	cpi	maxtry		;Have we reached the maximum number of tries?
	jm	rdat21		;If not proceed.
	lxi	d,ermes5
	call	error3		;Display err msg.
	jmp	rdat16		;[MF]Change the state to abort.

rdat21:	call	tryagn
	ret

rdata3:	cpi	'Z'		;Is it a EOF packet?
	jnz	rdata4		;Try and see if its an error.
	call	compp
	jnz	nak0		;No, NAK it and try again.
	call	countp
	lda	argblk+1	;Get the data length
	cpi	1		;Have one item?
	jnz	rdat33		;If not, ignore data
	lda	data		;Yes, get the character
	cpi	'D'		;Is it a 'D' for discard?
	jz	rdat36		;If so, punt file
rdat33:	lda	remtxt		;[MF]Writing text to disk?
	ora	a		;[MF]...
	  jnz	rdat38		;[MF]No, don't close file
	call	clofil		;Finish off the file.
	jmp	rdat37		; Give up if the disk is full.
rdat38:	xra	a		;Since we kept the file,
	sta	czseen		;don't say it was discarded.
	lda	numtry		;Get the number of tries. [MF]
	sta	oldtry		;Save it. [MF]
	call	ackp		;[MF]
	jmp	rdat39		;[MF]and get ready to get more files
rdat36:	lda	numtry		;Get the number of tries.
	sta	oldtry		;Save it.
	call	ackp
	lda	remtxt		;[MF]Is a Remote command in progress?
	ora	a		;[MF]...
	jnz	rdat39		;[MF]Yes, don't worry about file disposition
	lda	dscflg		;[MF]Is the file being punted because
	ora	a		;[MF]of a collision?
	jnz	rdat39		;[MF]Yes, don't delete the existing file
	lda	incflg		;[MF]No, are we keeping incomplete files?
	ora	a		;[MF]...
	jnz	rdat3a		;[MF]Yes
	lxi	d,fcb		;[MF]No, close the file,
	mvi	c,closf		;[MF]ignoring errors
	push	d		;[MF]...
	call	bdos		;[MF]...
	pop	d		;[MF]Now delete the file,
	mvi	c,delf		;[MF]ignoring errors
	call	bdos		;[MF]...
	jmp	rdat39		;[MF]and continue
rdat3a:	call	clofil		;[MF]Try to close the file, writing
				;[MF]outstanding buffers to disk
	jmp	rdat37		;[MF]Can't, disk is full
rdat39:	mvi	a,'F'
	sta	state
	ret

rdat37:	call	ptchr9		; Send "?Disk full" on the error line [MF]
				; and to the remote Kermit [MF]
rdat3b:	lda	remtxt		;[MF]Doing a Remote command?
	ora	a		;[MF]...
	jnz	abort		;[MF]Yes, just abort
	lxi	d,fcb		;[MF]Close the file, ignoring errors
	push	d		;[MF]Protect fcb pointer
	mvi	c,closf		;[MF]...
	call	bdos		;[MF]...
	pop	d		;[MF]Restore pointer
	lda	incflg		;[MF]Are we keeping incomplete files?
	ora	a		;[MF]...
	jnz	abort		;[MF]Yes, just abort transfer
	mvi	c,delf		;[MF]No, delete the file, ignoring errors
	call	bdos		;[MF]...
	jmp	abort		;[MF] abort transfer

rdata4:	cpi	'E'		;Is it an error packet.
	jnz	rdat16		;[MF]
	call	error
	jmp	rdat16		;[MF]
;
;       SEND command
;       here from: kermit

send:	mvi	a,cmifi		;Parse an input file spec.
	lxi	d,fcb		;Give the address for the FCB.
	call	comnd
	jmp	kermit		; Give up on bad parse.
;       section to get remote filename [gnn]
	lxi	d,remnam	;[gnn] where to put filename
	mvi	a,cmtxt		;[gnn] 
	call	comnd		;[gnn] get the text to end of the line
	jmp	kermt3		;[gnn] failure in reading buffer
	sta	remlen		;[gnn] save length (may be zero)
;
	xra	a
	sta	mfflg1		; clear flags...
	sta	mfflg2
	sta	mfflg3		;[gnn]
	sta	fcbcnt		;[gnn] clear fcbcount
	lxi	h,fcb0		;[gnn] and fcb pointer
	shld	xfcbptr
;
	call	mfname		;handle (multi) files
	jnc	send14		;got a valid file-name
	lxi	d,erms15
	call	prtstr		;Display error msg. ([hh] where it's visible)
	jmp	kermit

send14:	call	init		;Clear the line and initialize the buffers.
	xra	a
	sta	pktnum		;Set the packet number to zero.
	sta	numtry		;Set the number of tries to zero.
	sta	wrn8		;[jd] we haven't sent the 8-bit-lost warning
	lxi	h,0
	shld	numpkt		;Set the number of packets to zero.
	shld	numrtr		;Set the number of retries to zero.
	lda	quietd		; a quiet display?
	ana	a
	jnz	send15		; yup, dont write
	call	scrnrt		;Position cursor
	lxi	h,0
	call	nout		;Write the number of retries.
send15:	mvi	a,'1'		;Reset to use single character checksum
	sta	curchk		;For startup
	mvi	a,'S'
	sta	state		;Set the state to receive initiate.
	;...
;
;SEND state table switcher

send2:	lda	quietd		; a quiet display?
	ana	a
	jnz	send21		; yes, so dont write
	call	scrnp		;Position cursor
	lhld	numpkt
	call	nout		;Write the packet number.
send21:	lda	state		;Get the state.
	cpi	'D'		;Are we in the data send state?
	jnz	send3
	call	sdata
	jmp	send2

send3:	cpi	'F'		;Are we in the file send state?
	jnz	send4
	call	sfile		;Call send file.
	jmp	send2

send4:	cpi	'Z'		;Are we in the EOF state?
	jnz	send5
	call	seof
	jmp	send2

send5:	cpi	'S'		;Are we in the send initiate state?
	jnz	send6
	call	sinit
	lda	state		;[jd] get state back
	cpi	'F'		;[jd] into file send state yet?
	jnz	send2		;[jd] no
	lxi	d,inms23	;[jd] yes, print sending...
	call	finmes		;[jd] 
	jmp	send2

send6:	cpi	'B'		;Are we in the eot state?
	jnz	send7
	call	seot
	jmp	send2

send7:	cpi	'C'		;Are we in the send complete state?
	jnz	send8		;No...
	lxi	d,infms3	;Yes, write "Complete" message.
	lda	czseen		;Or was it interrupted?
	ora	a		; .  .  .
	jz	send7a		;No.
	lxi	d,inms13	;Yes, then say "Interrupted" instead.
send7a:	call	finmes
	jmp	kermit

send8:	cpi	'A'		;Are we in the send "abort" state?
	jnz	send9
	lxi	d,infms4	;Print  message.
	call	finmes
	jmp	kermit

send9:	lxi	d,infms4	;Anything else is equivalent to "abort".
	call	finmes
	jmp	kermit
;
;       Send routines

;       Send initiate
;       called by: send

sinit:	lda	numtry		;Get the number of tries.
	cpi	imxtry		;Have we reached the maximum number of tries?
	jm	sinit2
	lxi	d,erms14
	call	error3		;Display ermsg
	jmp	abort		;Change the state to abort.

sinit2:	inr	a		;Increment it.
	sta	numtry		;Save the updated number of tries.
	mvi	a,'1'		;Reset to use single character checksum
	sta	curchk		;For startup
	lda	chktyp		;Get our desired block check type
	sta	inichk		;Store so we tell other end
	lxi	h,data		;Get a pointer to our data block.
	call	rpar		;Set up the parameter information.
	sta	argblk+1	;Save the number of arguments.
	lda	numpkt		;Get the packet number.
	sta	argblk
	lda	state		; load state (I or S)

	call	spack		;Send the packet.
	jmp	abort		; Failed, abort.
	call	rpack		;Get a packet.
	jmp	r		; Trashed packet don't change state, retry.
	cpi	'Y'		;ACK?
	jnz	sinit3		;If not try next.
	call	compp		;compare packets. If ok, zero flag set
	rnz			;If not try again.
	call	countp		;increment packet number modulo 64
	lda	argblk+1	;Get the number of pieces of data.
	lxi	h,data		;Pointer to the data.
	call	spar		;Read in the data. (decode what they want)
	lda	numtry		;Get the number of tries.
	sta	oldtry		;Save it.
	xra	a
	sta	numtry		;Reset the number of tries.
	lda	state		; se if S or I state
	cpi	'I'		; I state, so set X as next state
	jnz	sinita
sinitb:	mvi	a,'X'
	sta	state
	ret

sinita:	lda	inichk		;Get the agreed upon block check type
	sta	curchk		;Store as type to use for packets now
	mvi	a,'F'		;Set the state to file send. (Assumed)
	sta	state
	call	getfil		;Open the file.
	ret			; assume success; mfname thinks the file exists.

sinit3:	cpi	'N'		;NAK?
	jnz	sinit4		;If not see if its an error.
	call	updrtr		;Update the number of retries.
	lda	pktnum		;Get the present packet number.
	inr	a		;Increment
	ani	3FH		; modulo 64
	mov	b,a
	lda	argblk		;Get the packet's number.
	cmp	b		;Is the packet's number one more than now?
	rnz			;If not assume its for this packet, go again.
	xra	a
	sta	numtry		;Reset number of tries.
	mvi	a,'F'		;Set the state to file send.
	sta	state
	ret

sinit4:	cpi	'E'		;Is it an error packet.
	jnz	abort
	lda	state		;[MF]Get state
	cpi	'I'		;[MF]If an "I" packet was sent,
	jz	sinitb		;[MF]Ignore the error, pretend success
	call	error		;[MF]else display the error info
	jmp	abort		;[MF]and abort
;
;       Send file header
;       called by: send
;[5a] Question [majoc]: Why could not the filename
;     parsing have been done by comnd, like all the rest?

sfile:	lda	numtry		;Get the number of tries.
	cpi	maxtry		;Have we reached the maximum number of tries?
	jm	sfile1
	lxi	d,erms14
	call	error3
	jmp	abort		;Change the state to abort.

sfile1:	inr	a		;Increment it.
	sta	numtry		;Save the updated number of tries.
	xra	a		;Clear A
	sta	czseen		;No control-Z or X seen
	lxi	h,data		;Get a pointer to our data block.
	shld	datptr		;Save it.
; use remote name if given, else use local name [gnn]
	lda	remlen		;[gnn] anything given?
	ora	a		;[gnn] 
	jnz	sfile4		;[gnn] use remote name

	lxi	h,fcb+1		;Pointer to the file name in the FCB.
	shld	fcbptr		;Save position in FCB.
	mvi	b,0		;No chars yet.
	mvi	c,0
sfil11:	mov	a,b
	cpi	8H		;Is this the ninth char?
	jnz	sfil12		;If not proceed.
	mvi	a,'.'		;Get a dot.
	lhld	datptr
	mov	m,a		;Put the char in the data packet.
	inx	h
	shld	datptr		;Save position in data packet.
	inr	c
sfil12:	inr	b		;Increment the count.
	mov	a,b
	cpi	0CH		;Twelve? 
	jp	sfil13
	lhld	fcbptr
	mov	a,m
	ani	7fH		;Turn off CP/M 2 or 3's high bits.
	inx	h
	shld	fcbptr		;Save position in FCB.
	cpi	'!'		;Is it a good character?
	jm	sfil11		;If not get the next.
	lhld	datptr
	mov	m,a		;Put the char in the data packet.
	inx	h
	shld	datptr		;Save position in data packet.
	inr	c
	jmp	sfil11		;Get another.

sfil13:	mov	a,c		;Number of char in file name.
	sta	argblk+1
	lhld	datptr
	mvi	a,'$'
	mov	m,a		;Put in a dollar sign for printing.
	lda	quietd		; a quiet display
	ana	a
	jnz	sfi13a		; yes, dont write
	call	scrfln		;Position cursor
sfi13a:	lxi	d,data		;Print the file name though, in either case
	call	prtstr
	lda	pktnum		;Get the packet number.
	sta	argblk
	mvi	a,'F'		;File header packet.
	call	spack		;Send the packet.
	jmp	abort		; Failed, abort.
	call	rpack		;Get a packet.
	jmp	r		; Trashed packet don't change state, retry.
	cpi	'Y'		;ACK?
	jnz	sfile2		;If not try next.
	call	compp
	rnz			;If not hold out for the right one.
sfil14:	call	countp
	lda	numtry		;Get the number of tries.
	sta	oldtry		;Save it.
	xra	a
	sta	numtry		;Reset the number of tries.
	sta	bytes		;[10] clear the "bytes transferred" counter
	sta	bytes+1		;[10]
	sta	bytes+2		;[10]
	sta	bytes+3		;[10]
	call	gtchr		;Fill the first data packet
	jmp	sfil16		;Error go see if its EOF.
;                              	;Got the chars, proceed.
	sta	size		;Save the size of the data gotten.
	mvi	a,'D'		;Set the state to data send.
	sta	state
	ret

sfil16:	cpi	0FFH		;Is it EOF?
	jnz	abort		;If not give up.
	mvi	a,'Z'		;Set the state to EOF.
	sta	state
	ret

sfile2:	cpi	'N'		;NAK?
	jnz	sfile3		;Try if error packet.
	call	updrtr		;Update the number of retries.
	lda	pktnum		;Get the present packet number.
	inr	a		;Increment
	ani	3FH		; modulo 64
	mov	b,a
	lda	argblk		;Get the packet's number.
	cmp	b		;Is the packet's number one more than now?
	rnz			;If not go try again.
	jmp	sfil14		;Just as good as a ACK;go to the ACK code.

sfile3:	cpi	'E'		;Is it an error packet.
	jnz	abort
	call	error
	jmp	abort

; copy remote name into packet to send [gnn]
sfile4:	xchg			;[gnn] keep pointer to packet
	lxi	h,remnam	;[gnn] set pointer to name
	mov	c,a		;[gnn] keep count of length
	mov	b,a		;[gnn] and set as loop counter
sfil41:	mov	a,m		;[gnn] get a character
	stax	d		;[gnn] copy it to packet
	inx	h		;[gnn] 
	inx	d		;[gnn] move pointers
	dcr	b		;[gnn] 
	mov	a,b		;[gnn] 
	ora	a		;[gnn] done them all?
	jnz	sfil41		;[gnn] repeat until done
	xchg			;[gnn] get final position
	shld	datptr		;[gnn] and save it
	jmp	sfil13		;[gnn] now go and send packet

;
;       Send data
;       called by: send

sdata:	lda	numtry		;Get the number of tries.
	cpi	maxtry		;Have we reached the maximum number of tries?
	jm	sdata1
	lxi	d,erms14
	call	error3
	jmp	abort		;Change the state to abort.

sdata1:	inr	a		;Increment it.
	sta	numtry		;Save the updated number of tries.
	lxi	h, data		;Get a pointer to our data block.
	shld	datptr		;Save it.
	lxi	h,filbuf	;Pointer to chars to be sent.
	shld	cbfptr		;Save position in char buffer.
	mvi	b,1		;First char.
sdat11:	lhld	cbfptr
	mov	a,m
	inx	h
	shld	cbfptr		;Save position in char buffer.
	mov	c,a		;[jd] preserve character temporarily
	lda	quot8		;[jd] doing eighth-bit quoting?
	ora	a		;[jd] 
	mov	a,c		;[jd] restore char
	jnz	sdat4		;[jd] using eighth-bit quoting, no warning
	lda	parity		;[jd] get parity
	cpi	parnon		;[jd] none?
	mov	a,c		;[jd] restore character
	jz	sdat4		;[jd] no parity, leave char alone
	lda	wrn8		;[jd] look at warning flag
	ora	a		;[jd] have we already given the warning?
	jnz	sdat5		;[jd] yes, skip this
	mov	a,c		;[jd] restore character...
	ani	80h		;[jd] examine parity
	jz	sdat5		;[jd] no parity, no warning.
	call	parwrn		;[jd] ...print warning - parity lost
	mvi	a,0ffh		;[jd] remember that we sent the message
	sta	wrn8		;[jd]
sdat5:	mov	a,c		;[jd] restore character again
	ani	7fh		;[jd] strip parity so not checksummed
sdat4:	lhld	datptr
	mov	m,a		;Put the char in the data packet.
	inx	h
	shld	datptr		;Save position in data packet.
	inr	b		;Increment the count.
	lda	size		;Get the number of chars in char buffer.
	cmp	b		;Have we transfered that many?
	jp	sdat11		;If not get another.
	lda	size		;Number of char in char buffer.
	sta	argblk+1
	lda	pktnum		;Get the packet number.
	sta	argblk
	mvi	a,'D'		;Data packet.
	call	spack		;Send the packet.
	jmp	abort		; Failed, abort.
	call	rpack		;Get a packet.
	jmp	r		; Trashed packet don't change state, retry.
	cpi	'Y'		;ACK?
	jnz	sdata2		;If not try next.
	call	compp
	rnz			;If not hold out for the right one.
	lda	argblk		;Get the packet number back
	call	countp
	lda	numtry		;Get the number of tries.
	sta	oldtry		;Save it.
	xra	a
	sta	numtry		;Reset the number of tries.
	lda	argblk+1	;Get the data length
	cpi	1		;Check if only 1 character?
	jnz	sdat15		;If not, just continue
	lda	data		;Got one character, get it from data
	cpi	'Z'		;Want to abort entire stream?
	jnz	sdat14		;If not, check for just this file
	sta	czseen		;Yes, remember it
	jmp	sdat16		;[MF] and set EOF state
sdat14:	cpi	'X'		;Desire abort of current file?
	jnz	sdat15		;If not, just continue
	sta	czseen		;Yes, remember that
	jmp	sdat16		;[MF] and set EOF
sdat15:	lda	czseen		;Also get control-Z flag
	ora	a		;Check if either given
	jz	sdat12		;If neither given, continue
sdat16:	mvi	a,'Z'		;Change state to EOF
	sta	state		; .  .  .
	ret			;And return

sdat12:	call	gtchr
	jmp	sdat13		;Error go see if its EOF.
	sta	size		;Save the size of the data gotten.
	ret

sdat13:	cpi	0FFH		;Is it EOF?
	jnz	abort		;If not give up.
	mvi	a,'Z'		;Set the state to EOF.
	sta	state
	ret

sdata2:	cpi	'N'		;NAK?
	jnz	sdata3		;See if is an error packet.
	call	updrtr		;Update the number of retries.
	lda	pktnum		;Get the present packet number.
	inr	a		;Increment
	ani	3FH		; modulo 64
	mov	b,a
	lda	argblk		;Get the packet's number.
	cmp	b		;Is the packet's number one more than now?
	rnz			;If not go try again.
	jmp	sdat12		;Just as good as a ACK;go to the ACK code.

sdata3:	cpi	'E'		;Is it an error packet.
	jnz	abort
	call	error
	jmp	abort
;
;       Send EOF
;       called by: send

seof:	lda	numtry		;Get the number of tries.
	cpi	maxtry		;Have we reached the maximum number of tries?
	jm	seof1
	lxi	d,erms14
	call	error3
	jmp	abort		;Change the state to abort.

seof1:	inr	a		;Increment it.
	sta	numtry		;Save the updated number of tries.
	lda	pktnum		;Get the packet number.
	sta	argblk
	xra	a
	sta	argblk+1	;No data.
	lda	czseen		;Check if C-Z or C-X typed
	ora	a		; .  .  .
	jz	seof14		;If not aborted, just keep going
	mvi	a,'D'		;Tell other end to discard packet
	sta	data		;Store in data portion
	mvi	a,1		;One character
	sta	argblk+1	;Store the length
seof14:	mvi	a,'Z'		;EOF packet.
	call	spack		;Send the packet.
	jmp	abort		; Failed, abort.
	call	rpack		;Get a packet.
	jmp	r		; Trashed packet don't change state, retry.
	cpi	'Y'		;ACK?
	jnz	seof2		;If not try next.
	call	compp
	rnz			;If not hold out for the right one.
seof12:	call	countp
	lda	numtry		;Get the number of tries.
	sta	oldtry		;Save it.
	xra	a
	sta	numtry		;Reset the number of tries.
	mvi	c,closf		;Close the file.
	lxi	d,fcb
	call	bdos
;* Check if successful
	lda	czseen		;Desire abort of entire stream?
	cpi	'Z'		;Desire abort of entire stream?
	jz	seof13		;If so, just give up now
	call	mfname		;Get the next file.
	jc	seof13		; No more.
	call	getfil		;and open it (assume success)
	xra	a		;Clear A
	sta	czseen		;Since we have not aborted this file
	mvi	a,'F'		;Set the state to file send.
	sta	state
	ret

seof13:	mvi	a,'B'		;Set the state to EOT.
	sta	state
	ret

seof2:	cpi	'N'		;NAK?
	jnz	seof3		;Try and see if its an error packet.
	call	updrtr		;Update the number of retries.
	lda	pktnum		;Get the present packet number.
	inr	a		;Increment
	ani	3FH		; modulo 64
	mov	b,a
	lda	argblk		;Get the packet's number.
	cmp	b		;Is the packet's number one more than now?
	rnz			;If not go try again.
	jmp	seof12		;Just as good as a ACK;go to the ACK code.

seof3:	cpi	'E'		;Is it an error packet.
	jnz	abort
	call	error
	jmp	abort
;
;       Send EOT
;       called by: send

seot:	lda	numtry		;Get the number of tries.
	cpi	maxtry		;Have we reached the maximum number of tries?
	jm	seot1
	lxi	d,erms14
	call	error3
	jmp	abort		;Change the state to abort.

seot1:	inr	a		;Increment it.
	sta	numtry		;Save the updated number of tries.
	lda	pktnum		;Get the packet number.
	sta	argblk
	xra	a
	sta	argblk+1	;No data.
	mvi	a,'B'		;EOF packet.
	call	spack		;Send the packet.
	jmp	abort		; Failed, abort.
	call	rpack		;Get a packet.
	jmp	r		; Trashed packet don't change state, retry.
	cpi	'Y'		;ACK?
	jnz	seot2		;If not try next.
	call	compp
	rnz			;If not hold out for the right one.
seot12:	call	countp
	lda	numtry		;Get the number of tries.
	sta	oldtry		;Save it.
	xra	a
	sta	numtry		;Reset the number of tries.
	mvi	a,'C'		;Set the state to file send.
	sta	state
	ret

seot2:	cpi	'N'		;NAK?
	jnz	seot3		;Is it error.
	call	updrtr		;Update the number of retries.
	lda	pktnum		;Get the present packet number.
	inr	a		;Increment
	ani	3FH		; modulo 64
	mov	b,a
	lda	argblk		;Get the packet's number.
	cmp	b		;Is the packet's number one more than now?
	rnz			;If not go try again.
	jmp	seot12		;Just as good as a ACK;go to the ACK code.

seot3:	cpi	'E'		;Is it an error packet.
	jnz	abort
	call	error
	jmp	abort
;
;       This routine sets up the data for init packet (either the
;       Send_init or ACK packet).
;       called by: rinit, rfile, sinit
;
; Called by rinit, rfile and sinit.  See what WE want from the other fella
;
; [11] by OBS - Stripped out all the new capas code etc and reverted
;	to Good Ol' Basic Kermit again!
;	Those keen should study the followin gode with care, and remove
;	or add semicolons as indicated.
;
; See also SPAR which decodes what comes in.  It also decodes bits in 
;	the "capability" fields.  (Two CAPAS files allowed from remote
;	machines, but we will only send one at max.)  Note that not all 
;	if any of the capability bits will be used.
;
; Definitions - init packet (data section only.. rest of header assumed OK)
;	Byte 0	Maximum length I want to send
;	     1	The Timeout I want you to use
;	     2	Number of PAD characters I want tot use (May be null)
;	     3	The PAD character I want to use (May be Null)
;	     4	The End-of-Line character I will use (Carriage Return)
;	     5	The control character Quote Character I will use (#)
;	     6	The parity bit Quote Character I will use (&)
;	     7	The Checktype I will use
;	     8	The repeat prefix I will use (Null, as we cannot to repeats)
;	     9	Capability Byte 0 (See SPAR for defs)
;	    10	Capability byte 1 ( --- " --- but we will not send it.)
;	    11	The number of packets I will send per window (not used)
;	    12  MAXL1 - Long packet size, ms count
;	    13	MAXL2 - Long packet size, ls count
;
;
; Enter with HL pointing to the "data" part of the packet.

;
; older part of rpar follows...
;
;
rpar:	lda	rpsiz		;Get the receive packet size.
	adi	space		;Add a space to make it printable.
	mov	m,a		;Put it in the packet.
	inx	h		;Point to the next char.
	lda	rtime		;Get the receive packet time out.
	adi	space		;Add a space.
	mov	m,a		;Put it in the packet.
	inx	h
	lda	rpad		;Get the number of padding chars.
	adi	space
	mov	m,a
	inx	h
	lda	rpadch		;Get the padding char.
	adi	100O		;Uncontrol it.
	ani	7FH
	mov	m,a
	inx	h
	lda	reol		;Get the EOL char.
	adi	space
	mov	m,a
	inx	h
	lda	rquote		;Get the quote char.
	mov	m,a
	inx	h
	mvi	m,'Y'		;[jd] we know how to do 8-bit quoting
	lda	parity		;[jd]
	cpi	parnon		;[jd] parity none?
	jz	rpar1		;[jd] yes, keep going
	lda	qbchr		;[jd] no, better request 8-bit quoting
	mov	m,a

rpar1:
	inx	h		;Advance to next
	lda	chktyp		;Get desired block check type
	mov	m,a		;Store it
	inx	h		;Advance pointer

; Comment out the next two lines for capas etc.  WILL require debugging
	mvi	a,8		; this id the older end for this routine.  May be useful.
	ret

; [11] Rest not needed for now, commented out
; [10] (to ret)
; New additions to rpar follows...

;	lda	rcap1		; get the first capability byte
;	ani	3eh		; mask out bit 0, ie only one CAPAS byte
;	adi	space		; tochar it
;	mov	m,a
;	inx	h
;	mvi	m,space		; No windows, ie space to packet
;	inx	h
;	push	h		; we need the HL regs for maths.
;	lhld	rdpkt		; get receive packet length
;	lxi	d,95		; we want hl div 95 and hl mod 95
;	call	divide		; return with divsion in hl, remainder in de
;	mov	a,l		; two sets of bytes
;	pop	h
;	adi	space		; tochar(maxl1)
;	mov	m,a
;	inx	h
;	mov	a,l
;	adi	space		; tochar(maxl2)
;	mov	m,a
;
; done all, set databytes = 12 and return
;	mvi	a,12		; 12 bits of data
;	ret

;[11] End of commented out code for rpar


;
;       This routine reads in all the send_init packet information.
;       called by: rinit, sinit

;[11] As for rpar, restore the "old" kermit code for non-capas Kermit.
;[10] (to ret at end)
;
; SPAR - routine to decode parameters received from the remote end
;
;	Called by rinit,sinit
;
;	Entry:	a: Number of databytes in packet
;		hl: Pointer to "data" part of packet
;
;spar:	sta	temp4		; save for a while
;				; first clear some variables
;	lda	dspsiz		; get default "send" packet length
;	sta	spktl
;	lda	dstime		; get default time-out
;	sta	stimeo
;	xra	a		; set no pad characters by default
;	sta	spad
;	lda	dspadc		; get the default padding character
;	sta	spadc
;	mvi	a,cr		; default end of line character (CR)
;	sta	seol
;	mvi	a,dsquot	; default quote character
;	sta	squote
;	mvi	a,dsbqut	; default binary quote character
;	sta	qbchr
;	mvi	a,dschkt	; set checktype = 1 for inits
;	sta	inichk
;	mvi	a,space		; no repeat prefixing ( otherwise ~)
;	sta	srept
;
; Now follows the "capabilities" bits... 5 bits per capas byte.
;
; 	Note: Before extracting any data bits, apply unchar() to get the 
;	six ls bits.  If bit 0 = 1 the a subsequent capaa byte follows
;
;	Byte0:	Bit 0:	Set to 1 if there are subsequent CAPAS bytes
;		    1:	(Cap. 5) Set to 1 for long packets.  Second byte
;			AFTER the last capas byte has packet length DIV 95
;			and Thire byte has length MOD 95
;		    2:	(Cap. 4) Sliding Windows.  If used, first byte AFTER
;			last capas byte has TOCHAR(no. of packets in window)
;		    3:	(Cap. 3) Ability to accept "A" (attribute packets)
;		    4:	(Cap. 2) Reserved
;		    5:	(Cap. 1) Reserved
;	Byte 2 onward: not used in this implementation. Any capas bytes sent 
;		will be stored, however.
;
;	lda	temp4		; get the number of bytes to test
;	mov	c,a		; to a count register
;	mov	a,m		; get first byte
;	call	decc		; unchar it, and decrement c
;	sta	spsiz		; save a send packet size
;	jz	sparx		; if no more, exit
;
;	mov	a,m		; get timout
;	call	decc
;	sta	stime		; save timeout
;	jz	sparx
;
;	mov	a,m		; get pad characters
;	call	decc	
;	sta	spadc		; save it
;	jz	sparx
;
;	mov	a,m		; get pad character count
;	call	decc
;	sta	spad
;	jz	sparx
;
;	mov	a,m		; get send EOL
;	call	decc
;	sta	seol
;	jz	sparx
;
;	mov	a,m		; get control quote character
;	call	decc
;	sta	squote
;	jz	sparx
;
;	mov	a,m		; get binary (parity) quote char
;	mov	b,a		; this time we actually WANT accumulator
;	cpi	space		; are we doing 8th bit quoteing
;	jz	spar1		; dont know, assume not
;	cpi	'N'		; definately not?
;	jz	spar1
;	cpi	'Y'		; definately - use &
;	jz	spar2
;	sta	squote		; else save the new character
;spar2:	lda	parity		; see if we are using the parity bit
;	cpi	parnon		; no parity => no quoting
;	jz	spar3		; yup, so use the default quote character &
;
;spar1:	xra	a		; save not quoting
;	sta	squote
;spar3:	call	decc		; update counters etc
;	jz	sparx
;
;	mov	a,m		; get repeat prefixing
;	call	decc
;	push	psw		; save flags
;	cpi	space-32	; we want it?
;	jz	spar4
;	sta	srept
;spar4:	pop	psw		; restore flags
;	jz	sparx
;
;	lxi	d,scapas	; point to start of capability byte(s)
;	push	psw		; must do this...
;spar5:	pop	psw		; cos we restore the spack
;	mov	a,m
;	call	decc		; get scap1 (or n)
;	sta	scap1
;	push	psw
;	ani	01		; another byte following?
;	jnz	spar5
;	pop	psw		; see if any other data bytes (Windows etc)
;	jz	sparx
;
;	mov	a,m		; get window size
;	call	decc
;	sta	swindo
;	jz	sparx
;
;	mov	a,m		; get long packets ms bits
;	call	decc		;
;	mov	d,a		; unchared ms bits-ish
;	mov	a,m
;	call	decc		; ls bits-ish
;	push	h		; and we are doing maths
;	push	b		; and an intermediate result in c
;	push	psw		; we want flags  and the ls bits...
;	mvi	b,0
;	mov	c,d		; get ms bits-ish to bc
;	push	b		; get number to hl
;	pop	h
; now multipy by 95
;	dad	h		;*2
;	dad	h		;*4
;	dad	h		;*8
;	dad	h		;*16
;	push	h		; *16 to ...
;	pop	d		; ... de
;	dad	h		;*32
;	dad	d		; *(32+16) = *48
;	dad	h		; *96
;	mov	a,l		; *(96-1)
;	sub	c
;	mov	l,a
;	mov	a,0
;	sbb	h
;	mov	h,a
;	pop	psw		; restore ls bitsish
;	mov	e,a
;	mvi	d,0
;	dad	d		; *95 + ls bits. Phew.
;	shld	sdpkt		; save long packet length
;	pop	b
;	pop	h		; restore regs
;
;sparx:	ret			; if here, (assume) no more data to read in
;[10] routines required follow
;decc:	mov	a,m		; get data byte
;	sui	space		; unchar it
;	inx	h		; increment input pointer
;	dcr	c		; decrement data counter
;	ret			; return
;[10] end or spar replacement

;[11] Restore older spar....
; Older spar follows...
spar:	sta	temp4		;Save the number of arguments.
; Initialize some variables to their required default values, so we use
; the right values even if the remote Kermit doesn't send the full packet:
;                              	; we don't do anything with timeout values yet.
;                              	; no default pad count/pad character?
	mvi	a,cr		; EOL character = carriage-return
	sta	seol
	mvi	a,'#'		; quote character = '#'
	sta	squote
	mvi	a,'&'		; eighth-bit quote character = '&'
	sta	qbchr
	mvi	a,'1'		; block-check = 1-character-checksum
	sta	inichk
; 
	mov	a,m		;Get the max packet size.
	sbi	space		;Subtract a space.
	sta	spsiz		;Save it.
	lda	temp4
	cpi	3		;Fewer than three pieces?
	rm			;If so we are done.
	inx	h
	inx	h		;Increment past the time out info.
	mov	a,m		;Get the number of padding chars.
	sbi	space
	sta	spad
	lda	temp4
	cpi	4		;Fewer than four pieces?
	rm			;If so we are done.
	inx	h
	mov	a,m		;Get the padding char.
	adi	100O		;Re-controlify it.
	ani	7FH
	sta	spadch
	lda	temp4
	cpi	5		;Fewer than five pieces?
	rm			;If so we are done.
	inx	h
	mov	a,m		;Get the EOL char.
	sbi	space
	sta	seol
	lda	temp4
	cpi	6		;Fewer than six pieces?
	rm			;If so we are done.
	inx	h
	mov	a,m		;Get the quote char.
	sta	squote
	lda	temp4		;Get the amount of data supplied
	cpi	7		;Have an 8-bit quote?
	rm			;If not there, all done
	inx	h		;Yes, get the character
	mvi	a,0		;[jd] 
	sta	quot8		;[jd] assume not quoting
	mov	a,m		;Get the supplied character
	cpi	'N'		;[jd] No?
	jz	spar1		;[jd] then don't try to do it
	cpi	space		;[jd] maybe they don't know about it...
	jz	spar1		;[jd] then don't try to do it.
	cpi	'Y'		;[jd] Yes?
	jnz	spar2		;[jd] if not 'Y', assume it's a quote char.
	lda	parity		;[jd] using parity?
	cpi	parnon		;[jd] no, don't need quoting...
	jz	spar1		;[jd] 
	mvi	a,0ffh		;[jd] else turn on...
	sta	quot8		;[jd] ...quote flag
	jmp	spar1

;[11] Note: If capas etc required, beware of the next two lables, as these 
; are used elswhere.

spar2:	sta	qbchr		;[jd] use their quote char (should validate)
	mvi	a,0ffh
	sta	quot8		;[jd] turn quote flag and fall thru...

spar1:	lda	temp4		;Determine if block check type given
	cpi	8		;Is the field there?
	rm			;If not, all done
	inx	h		;Point to the character
	mov	a,m		;Get the value
	mov	b,a		;Copy value
	lda	chktyp		;Get our type
	cmp	b		;Is it our desired type?
	rnz			; If not, use default (1-character-checksum)
	sta	inichk		; Match, store as type to use after init
	ret			; and return
;[10] end of replacement
;[11] end of replacement of replacement (ie back to original code)
;

;       Copy characters from packet to disk (or screen)
;       called by: rdata

ptchr:	sta	temp1		;Save the size.
	lda	remtxt		;[MF]Get remote command flag
	ora	a		;[MF]Remote command in progress?
	jnz	ptchr0		;[MF]Yes, don't check for file collisions
	lda	flwflg		;[MF]Get File Warning (Set Collision) flag
	cpi	3		;[MF]SET COLLISION DISCARD?
	jnz	ptchr0		;[MF]No
	lda	dscflg		;[MF]Yes, get "discard" flag
	ora	a		;[MF]Discarding file?
	jz	ptchr0		;[MF]No
	mvi	a,'X'		;[MF]Yes, simulate a user rejection
	sta	czseen		;[MF]...
	jmp	rskp		;[MF]and pretend success
ptchr0:				;[MF]
	lxi	h,data		;Beginning of received packet data.
	shld	outpnt		;Remember where we are.
	lda	rquote
	mov	b,a		;Keep the quote char in b.
	mvi	c,0		;[jd] assume no 8-bit quote char
	lda	quot8		;[jd] doing 8-bit quoting?
	ora	a
	jz	ptchr1		;[jd] no, keep going
	lda	qbchr		;[jd] else get 8-bit quote char
	mov	c,a		;[jd] keep this in c
ptchr1:	lxi	h,temp1
	dcr	m		;Decrement # of chars in packet.
	jm	rskp		;Return successfully if done.
	lda	remtxt		; to screen only?
	ana	a
	jnz	ptchr2		; dont do any disk stuff
	lxi	h,chrcnt	;Number of chars remaining in dma.
	dcr	m		;Decrement.
	jp	ptchr2		;Continue if space left.
	call	outbuf		;Output it if full.
	jmp	ptchr9		; Error return if disk is full.
ptchr2:	lhld	outpnt		;Get position in output buffer.
	mov	a,m		;Grab a char.
	inx	h
	shld	outpnt		;and bump pointer.
	mvi	e,0		;[jd] assume nothing to OR in.
	cmp	c		;[jd] is it the binary quote char?
	jnz	ptch2a		;[jd] no, keep going
	mvi	e,80h		;[jd] include parity bit
	lda	temp1
	dcr	a
	sta	temp1		;[jd] decrement character count
	mov	a,m		;[jd] get next character
	inx	h
	shld	outpnt
ptch2a:	cmp	b		;Is it the quote char?
	jnz	ptchr3		;[jd] changed to ptchr3 so includes parity
	mov	a,m		;Get the quoted character
	inx	h
	shld	outpnt		;and bump pointer.
	lxi	h,temp1
	dcr	m		;Decrement # of chars in packet.
	mov	d,a		;Save the char.
	ani	80H		;Turn off all but the parity bit.
	ora	e		;[jd] let parity come from either (???)
	mov	e,a		;Save the parity bit.
	mov	a,d		;Get the char.
	ani	7FH		;Turn off the parity bit.
	cmp	b		;Is it the quote char?
	jz	ptchr3		;If so just go write it out.
	cmp	c		;[jd] maybe it's the 8-bit prefix character?
	jz	ptchr3		;[jd] then don't controllify.
	mov	a,d		;Get the char.
	adi	40H		;Make the character a control char again.
	ani	7FH		;Modulo 128.
ptchr3:	ora	e		;Or in the parity bit.
	sta	temp3		; save for a while
	lda	remtxt		; to screen or disk?
	ana	a
	lda	temp3
	jz	ptch31		; to disk
	push	h
	push	d
	push	b
	mov	e,a		; to display
	mvi	c,dconio
	call	bdos
	pop	b
	pop	d
	pop	h
	jmp	ptchr1		; continue

ptch31:	lhld	bufpnt		;Destination buffer.
	mov	m,a		;Store it.
	inx	h
	shld	bufpnt		;Update the pointer
	jmp	ptchr1		;and loop to next char.

ptchr9:	lxi	d,erms11	; "?Disk full"
	push	d		;[MF] Save pointer
	call	error3		; put it on the error line
	pop	d		;[MF] Restore pointer
	lxi	h,data		;[MF] Where to put the message for "e" packet
	lda	argblk		;[MF] Get packet-number
	call	countp		;[MF]Increment it
	sta	argblk		;[MF] as packet to send
	xra	a		;[MF] Zero length of packet data
	sta	temp1		;[MF] ...
ptch9a:	ldax	d		;[MF] Get a character to copy
	cpi	cr		;[MF] No more to copy?
	jz	ptch9b		;[MF] Yes, we can send the packet
	mov	m,a		;[MF] No, copy the character
	inx	d		;[MF] and increment source/dest pointers
	inx	h		;[MF] ...
	lda	temp1		;[MF] Get character count
	inr	a		;[MF] and increment it
	sta	temp1		;[MF] ...
	jmp	ptch9a		;[MF] Copy entire error message
ptch9b:	mvi	m,0		;[MF]Put in a zero
	lda	temp1		;[MF] Get number of characters in the message
	sta	argblk+1	;[MF] and store as number of packet data chars
	mvi	a,'E'		;[MF] Make it an error packet
	call	spack		;[MF] Send the error packet
	nop			;[MF] Don't really care if
	nop			;[MF] the send fails since we're
	nop			;[MF] bombing off anyway
	ret			; take error return.
;
;       Fill a data packet from file
;       called by: sfile, sdata

gtchr:	lda	squote		;Get the quote char.
	mov	c,a		;Keep quote char in c.
	lda	curchk		;Get current block check type
	sui	'1'		;Get the extra overhead
	mov	b,a		;Get a copy
	lda	spsiz		;Get the maximum packet size.
	sui	5		;Subtract the overhead.
	sub	b		;Determine max packet length
	sta	temp1		;This is the number of chars we are to get.
	lxi	h,filbuf	;Where to put the data.
	shld	cbfptr		;Remember where we are.
	mvi	b,0		;No chars.
gtchr1:	lda	temp1
	dcr	a		;Decrement the number of chars left.
	jp	gtchr2		;Go on if there is more than one left.
	mov	a,b		;Return the count in A.
	jmp	rskp

gtchr2:	sta	temp1
	lda	chrcnt		;Space left in the DMA.
	dcr	a
;* Can improve order here.
	jm	gtchr3
	sta	chrcnt
	jmp	gtchr4

gtchr3:	call	inbuf		;Get another buffer full.
	jmp	gtch30		; If no more return what we got.
	jmp	gtchr4		;If we got some, proceed.

gtch30:	mov	a,b		;Return the count in A.
	ora	a		;Get any chars?
	jnz	rskp		;If so return them.
	jmp	gtceof		;If not, say we found the end of the file.

gtchr4:	lhld	bufpnt		;Position in DMA.
	mov	a,m		;Get a char from the file.
	inx	h
	shld	bufpnt
	mov	d,a		;Save the char.
	ani	80H		;Turn off all but parity.
	mov	e,a		;Save the parity bit.
	jz	gtch4a		;[jd] no parity, skip this check...
	lda	quot8		;[jd] doing eighth-bit quoting?
	ora	a
	jz	gtch4a		;[jd] no, just proceed normally
	lda	temp1		;[jd] get space remaining
	cpi	2		;[jd] 3 chrs left (one cnted already)?
	jm	gtchr9		;[jd] no, skip this
	dcr	a		;[jd] decrement space remaining
	sta	temp1		;[jd] put back.
	lhld	cbfptr		;[jd] Position in character buffer.
	lda	qbchr		;[jd] get quote character
	mov	m,a		;]jd] Put the quote char in the buffer.
	inx	h		;[jd] increment destination buffer pointer
	shld	cbfptr		;[jd] store the pointer back
	inr	b		;[jd] Increment the char count.
	mvi	e,0		;[jd] no parity bit to OR in.
;[jd] fall thru...

gtch4a:	mov	a,d		;Restore the char.
	ani	7FH		;Turn off the parity.
	mov	d,a		;[jd] save here for later...
	cpi	space		;Compare to a space.
	jm	gtchr5		;If less then its a control char, handle it.
	cpi	del		;Is the char a delete?
	jz	gtchr5		;Go quote it.
	lda	quot8		; Are we doing 8th-bit quoting?
	ora	a
	jz	gtch4c		; if not, skip this test and restore character.
	lda	qbchr		; get 8th-bit quote character
	cmp	d		; same as current character?
	jz	gtch4b		; yes, have to quote it...
gtch4c:	mov	a,d		; no. get character back again.
	cmp	c		;Is it the quote char?
	jnz	gtchr8		;If not proceed.
gtch4b:	lxi	h,temp1		;[jd] point to char count
	dcr	m		;[jd] decrement (know room for at least one)
	lhld	cbfptr		;Position in character buffer.
	mov	m,c		;Put the (quote) char in the buffer.
	inx	h
	shld	cbfptr
	inr	b		;Increment the char count.
	mov	a,d		;[jd] restore character again
	jmp	gtchr8

gtchr5:	
	;[gnn] ignore parity for checking
;       ora     e		;Turn on the parity bit.

	cpi	('Z'-100O)     	;Is it a ^Z?
	jnz	gtchr7		;If not just proceed.
	lda	cpmflg		;Was the file created by CPM...
	cpi	1		;in ASCII-mode ?
	jz	gtch52		;Control-Z stops text
	cpi	2		;in BINARY mode?
	jz	gtchr6		;Yes, pass the ^Z
;At this point file-mode is DEFAULT.
;If the rest of the record is filled with ^Zs, we're at EOF, otherwise
;its a regular character.
	lhld	bufpnt		;since CHRCNT is ZERO at EOF-time
	lda	chrcnt		;(set by INBUF5 B.G.E)
	mov	d,a		;Get the number of chars left in the DMA.
gtch51:	dcr	d
	mov	a,d
	jp	gtch53		;Any chars left?
gtch52:	xra	a		;If not, get a zero.
	sta	chrcnt		;Say no more chars in buffer.
	mov	a,b		;Return the count in A.
	jmp	rskp

;Scan rest of buffer for non ^Z -- If we find a non ^Z, fall into gtchr6.
;If we get to the end of the buffer before finding a non ^Z, fall into gtch52.
gtch53:	mov	a,m		;Get the next char.
	inx	h		;Move the pointer.
	cpi	('Z'-100O)     	;Is it a ^Z?
	jz	gtch51		;If so see if the rest are.

gtchr6:	mvi	a,('Z'-100O)   	;Restore the ^Z.
gtchr7:	sta	temp2		;Save the char.
	lxi	h,temp1		;Point to the char total remaining.
	dcr	m		;Decrement it.
	lhld	cbfptr		;Position in character buffer.
	mov	m,c		;Put the quote in the buffer.
	inx	h
	shld	cbfptr
	inr	b		;Increment the char count.
	lda	temp2		;Get the control char back.
	adi	40H		;Make the non-control.
	ani	7fH		;Modulo 200 octal.
gtchr8:	lhld	cbfptr		;Position in character buffer.
	ora	e		;Or in the parity bit.
	mov	m,a		;Put the char in the buffer.
	inx	h
	shld	cbfptr
	inr	b		;Increment the char count.
	jmp	gtchr1		;Go around again.

gtchr9:	;[jd] not enough room left in buffer...
	lhld	bufpnt
	dcx	h
	shld	bufpnt		;[jd] back up over last character
	lxi	h,chrcnt	;[jd] point to character count
	inr	m		;[jd] increment it
	mov	a,b		;[jd] count of chars transferred
	jmp	rskp		;[jd] return it

gtceof:	mvi	a,0FFH		;Get a minus one.
	ret
;

; Little code to allow some expansion of code without changing
;  every futher address, only up to the end of this file.
;   TO BE REMOVED FRO RELEASE!

;	org ($+100h) AND 0FF00H

IF	lasm
	LINK	CPSPK2		;[obs] Link to part two of the packet file
ENDIF	;lasm
