; Edit history:
;
; [v2.28]
; Make packlen less conservative so we can send bigger packets.
;     (from Edgar Butt, Univ. of Md.)
; Make ack's with incorrect sequence number update the retry counter
; like a nak would; don't increment the retry count when a nak is
; found for the expected packet + 1, since this is the same as
; an ack.
; Moved handling of ack/nak to a subroutine and took out a ton
; of repeated code (motivated by a suggestion from Edgar Butt).
; JD 1 May 1985
;
	public	spar, rpar, error, error1, nout, send, flags, trans, pack
	public	dodec, doenc, curchk, inichk, packlen, send11, dtrans
	include msdefs.h	

spmin	equ	20		; Minimum packet size.
spmax	equ	94		; Maximum packet size.

datas 	segment	public 'datas'
	extrn	buff:byte, data:byte, fcb:byte, cpfcb:byte, filbuf:byte
	extrn	decbuf:byte, chrcnt:word, bufpnt:word, comand:byte
	extrn	rptq:byte, origr:byte, rptct:byte, rptval:byte

flags	flginfo	<>
trans	trinfo	<>
dtrans	trinfo	<>			; default trans info
pack	pktinfo <>
crlf	db	cr,lf,'$'
ender	db	bell,bell,'$' 			;  [4]
erms14  db	'?Unable to receive an acknowledgment from the host$'
erms15  db	'?Unable to find file$'
erms20	db	'Unable to send init packet$'
erms21	db	'Unable to send file header$'
erms22	db	'Unable to send data$'
erms23	db	'Unable to send end-of-file packet$'
erms24	db	'Unable to send break packet$'
infms2  db	cr,'             Sending: In progress$'
infms3  db	'Completed$'
infms4  db	'Failed$'
infms6  db	'Interrupted$'
infms7	db	cr,' Percent transferred: 100%$'
remmsg1	db	'Kermit-MS: File not found$'
filhlp  db      ' Input file spec (possibly wild) $'
filmsg	db	' File name to use on target system or confirm with'
	db	' a carriage return $'

curchk	db	0		; Use to store checksum length.
inichk	db	1		; Original or set checksum length.
chrptr  dw	?		; Position in character buffer.
fcbpt	dw	?		; Position in FCB.
datptr  dw	?		; Position in packet data buffer.
siz	dw	?		; Size of data from gtchr.
temp	dw	0
temp4	dw	0
sendas	dw	50 dup(0)	; Buffer for file name.
difnam	db	0		; Send under different name?
difsiz	db	0		; Size of new file name.
asmsg	db	'  as  $'
filopn	db	0		; Says if disk file is open.
datas	ends

code	segment	public
	extrn serini:near, serrst:near, comnd:near, init:near
	extrn spack:near, rpack:near, gtnfil:near, gtchr:near
	extrn getfil:near, clrfln:near, nppos:near, rprpos:near
	extrn erpos:near, rtpos:near, cxmsg:near, stpos:near
	extrn encode:near, nulref:near, decode:near, nulr:near
	extrn errpack:near, updrtr:near, clrmod:near, fcbcpy:near
	extrn perpos:near, prtfn:near
	assume	cs:code,ds:datas

;	This routine sets up the data for init packet (either the
;	Send_init or ACK packet).
 
RPAR	PROC	NEAR
	mov ah,trans.rpsiz	; Get the receive packet size.
	add ah,' '		; Add a space to make it printable.
	mov [bx],ah		; Put it in the packet.
	mov ah,trans.rtime	; Get the receive packet time out.
	add ah,' '		; Add a space.
	mov 1[bx],ah		; Put it in the packet.
	mov ah,trans.rpad	; Get the number of padding chars.
	add ah,' '
	mov 2[bx],ah		; Put it in the packet.
	mov ah,trans.rpadch	; Get the padding char.
	add ah,100O		; Uncontrol it.
	and ah,7FH
	mov 3[bx],ah		; Put it in the packet.
	mov ah,trans.reol	; Get the EOL char.
	add ah,' '
	mov 4[bx],ah		; Put it in the packet.
	mov ah,trans.rquote	; Get the quote char.
	mov 5[bx],ah		; Put it in the packet.
	mov ah,trans.ebquot	; Get 8-bit quote char. [21b]
	mov 6[bx],ah		; Add it to the packet. [21b] 
	mov ah,trans.chklen	; Length of checksum.
	add ah,48		; Make into a real digit.
	mov 7[bx],ah
	mov ah,rptq		; Repeat quote char.
	cmp ah,0		; Null means no.
	jne rpar0
	mov ah,' '		; Send a blank instead.
rpar0:	mov 8[bx],ah
	mov ah,09H		; Nine pieces of data.
	ret
RPAR	ENDP
 
; This routine reads in all the send init packet information.
; Enter with BX/ packet address, AX/ packet length
; This could probably be done much more legibly if it were table
; driven, but I'm afraid to touch it...
 
SPAR	PROC	NEAR
	cmp ax,1
	jge sparx
	mov ah,dspsiz		; Data not supplied by host, use default.
	jmp sparx2
sparx:	mov temp4,ax		; Save the number of arguments.
	mov ah,trans.spsiz
	cmp ah,dspsiz		; Is current value the default?
	jne sparx2		; No, assume changed by user.
	mov ah,[bx]		; Get the max packet size.
	sub ah,' '		; Subtract a space.
	cmp ah,spmin		; Can't be below the minimum.
	jge sparx1
	mov ah,spmin
	jmp sparx2
sparx1:	cmp ah,spmax		; Or above the maximum.
	jle sparx2
	mov ah,spmax
sparx2:	mov trans.spsiz,ah	; Save it.
	mov ax,temp4
	mov ah,dtrans.stime	; pick up default stime
	cmp al,2		; Fewer than two pieces?
	jl spar02		; yes, use default
spar0:	cmp ah,dstime		; Is current value the default?
	jne spar02		; No, assume changed by user.
	mov ah,1[bx]		; Get the timeout value.
	sub ah,' '		; Subtract a space.
	cmp ah,0
	ja spar01		; Must be non-negative.
	mov ah,0
spar01:	cmp ah,trans.rtime	; Same as other side's timeout.
	jne spar02
	add ah,5		; If so, make it a little different.
spar02:	mov trans.stime,ah	; Save it.
	mov ax,temp4
	mov ah,dtrans.spad	; get default send padding
	cmp al,3		; Fewer than three pieces?
	jl spar11		; yes, use default
spar1:	cmp ah,dspad		; Is current value the default?
	jne spar11		; No, assume changed by user.
	mov ah,2[bx]		; Get the number of padding chars.
	sub ah,' '
	cmp ah,0
	ja spar11		; Must be non-negative.
	mov ah,0
spar11:	mov trans.spad,ah
	mov ax,temp4
	mov ah,dtrans.spadch	; pick up default send pad character
	cmp al,4		; Fewer than four pieces?
	jl spar21
spar2:	cmp ah,dspadc		; Is current value the default?
	jne spar21		; No, assume changed by user.
	mov ah,3[bx]		; Get the padding char.
	add ah,100O		; Re-controlify it.
	and ah,7FH
	cmp ah,del		; Delete?
	je spar21		; Yes, then it's OK.
	cmp ah,0
	jge spar20
	mov ah,0		; Below zero is no good.
	jmp spar21		; Use zero (null).
spar20:	cmp ah,31		; Is it a control char?
	jle spar21		; Yes, then OK.
	mov ah,0		; No, use null.
spar21:	mov trans.spadch,ah
	mov ax,temp4
	mov ah,dtrans.seol	; get default send eol char
	cmp al,5		; Fewer than five pieces?
	jl spar31		; yes, use default
spar3:	cmp ah,dseol		; Is current value the default?
	jne spar31		; No, assume changed by user.
	mov ah,4[bx]		; Get the EOL char.
	sub ah,' '
	cmp ah,0
	jge spar30		; Cannot be negative.
	mov ah,cr		; If it is, use default of carriage return.
	jmp spar31
spar30:	cmp ah,31		; Is it a control char?
	jle spar31		; Yes, then use it.
	mov ah,cr		; Else, use the default.
spar31:	mov trans.seol,ah
	mov ax,temp4
	mov ah,dtrans.squote	; send quote
	cmp al,6		; Fewer than six pieces?
	jl spar41
spar4:	cmp ah,dsquot		; Is current value the default?
	jne spar41		; No, assume changed by user.
	mov ah,5[bx]		; Get the quote char.
	cmp ah,' '		; Less than a space?
	jge spar40
	mov ah,dsquot		; Yes, use default.
	jmp spar41
spar40:	cmp ah,'~'		; Must also be less then a tilde.
	jle spar41
	mov ah,dsquot		; Else, use default.
spar41:	mov trans.squote,ah
	cmp al,7		; Fewer than seven pieces? [21b begin]
	jge spar5
	mov trans.ebquot,'Y'	; Data not supplied by host, use default.
	jmp spar51
spar5:	mov ah,6[bx]		; Get other sides 8-bit quote request.
	call doquo		; And set quote char.  [21b end]
spar51:	cmp al,8		; Fewer than eight pieces?
	jge spar6
	mov trans.chklen,1
	jmp spar61
spar6:	mov ah,inichk
	mov trans.chklen,ah	; Checksum length we really want to use.
	mov ah,7[bx]		; Get other sides checksum length.
	call dochk		; Determine what size to use.
spar61:	cmp al,9		; Fewer than nine pieces?
	jge spar7
	mov rptq,0
	ret
spar7:	mov ah,8[bx]		; Get other sides repeat count prefix.
	mov ch,drpt
	mov rptq,0
	call dorpt
	ret
SPAR	ENDP
 
; Set 8-bit quote character based on my capabilities and the other
; Kermit's request.   [21b]

DOQUO	PROC	NEAR
	cmp trans.ebquot,'N'	; Can I do 8-bit quoting at all?
	je dq3			; No - so forget it.
	cmp trans.ebquot,'Y'	; Can I do it if requested?
	jne dq0			; No - it's a must that I do it.
	mov trans.ebquot,ah	; Do whatever he wants.
	jmp dq1
dq0:	cmp ah,'Y'		; I need quoting - can he do it?
	je dq1			; Yes - then all is settled.
	cmp ah,'N'		; No - then don't quote.
	je dq3
	cmp ah,trans.ebquot	; Both need quoting - chars must match.
	jne dq3
dq1:	mov ah,trans.ebquot
	cmp ah,'Y'		; If Y or N, don't validate prefix.
	je dq2
	cmp ah,'N'
	je dq2
	call prechk		; Is it in range 33-62, 96-126?
	 mov ah,'Y'		; Failed, don't do quoting.
	 nop
	cmp ah,trans.rquote	; Same prefix?
	je dq3			; Not allowed, so don't do quoting. 
	cmp ah,trans.squote	; Same prefix here?
	je dq3			; This is illegal too.
	mov trans.ebquot,ah	; Remember what we decided on.
dq2:	ret
dq3:	mov trans.ebquot,'N'	; Quoting will not be done.
	ret
DOQUO	ENDP
 
; Check if prefix in AH is in the proper range: 33-62, 96-126. 
; RSKP if so else RETURN.
prechk:	cmp ah,33
	jge prec0		; It's above 33.
	ret
prec0:	cmp ah,62
	jg prec1
	jmp rskp		; And below 62.  OK.
prec1:	cmp ah,96
	jge prec2		; It's above 96.
	ret
prec2:	cmp ah,126
	jg prec3
	jmp rskp		; And below 126.  OK.
prec3:	ret

; Set checksum length. 
dochk:	cmp ah,'1'		; Must be 1, 2, or 3.
	jl doc1
	cmp ah,'3'
	jle doc2
doc1:	mov ah,'1'
doc2:	sub ah,48		; Don't want it printable.
	cmp ah,trans.chklen	; Do we want the same thing?
	je dochk0		; Yes, then we're done.
	mov trans.chklen,1	; No, use single character checksum.
dochk0:	ret			; Just return for now.

; Set repeat count quote character.  The one used must be different than
; the control and eight-bit quote characters.  Also, both sides must 
; use the same character.
dorpt:	call prechk		; Is it in the valid range?
	 mov ah,0		; No, don't use their value. 
	 nop
	cmp ah,trans.squote	; Same as the control quote char?
	je dorpt0		; Yes, that's illegal, no repeats.
	cmp ah,trans.rquote	; How about this one?
	je dorpt0		; No good.
	cmp ah,trans.ebquot	; Same as eight bit quote char?
	je dorpt0		; Yes, that's illegal too, no repeats.
	cmp ah,ch		; Are we planning to use the same char?
	jne dorpt0		; No, that's no good either.
	mov rptq,ch		; Use repeat quote char now.
dorpt0:	ret

;	Send command
 
SEND	PROC	NEAR
	mov comand.cmcr,0	; Filename must be specified.
	mov difnam,0		; Assume we'll use original filename.
	mov flags.wldflg,0	; Re-initialize every time.
	mov ah,cmifi		; Parse an input file spec.
	mov dx,offset fcb	; Give the address for the FCB.
	mov bx,offset filhlp	; Text of help message.
	call comnd
	 jmp r			;  Give up on bad parse.
	cmp flags.wldflg,0FFH	; Any wildcards seen?
	je send1		; Yes, get a confirm.
	mov bx,offset sendas	; See if want to send file under dif name.
	mov dx,offset filmsg	; In case user needs help.
	mov ah,cmtxt
	call comnd
	 jmp r
	cmp ah,0		; Different name supplied?
	je send11		; No - keep as it.
	mov difnam,1		; Yes - send different filename.
	mov difsiz,ah		; Remember length of new name.
	jmp send11
send1:  mov ah,cmcfm
	call comnd		; Get a confirm.
	 jmp r			;  Didn't get a confirm.
send11: mov flags.droflg,0	; Reset flags from fn parsing. [21a]
	mov flags.nmoflg,0	; Reset flags from fn parsing. [21a]
	mov ah,sfirst		; Get the first file.
	mov dx,offset fcb
	int dos
	cmp al,0FFH		; Any found?
	jne send12
	cmp pack.state,'R'	; was this from a remote GET?
	jne sen11a		; no, print error and continue
	mov bx,offset remmsg1	; else get error message
	call errpack		; go complain
	jmp abort		; and abort this
sen11a:	mov ah,prstr
	mov dx,offset crlf
	int dos
	mov ah,prstr
	mov dx,offset erms15
	int dos
	ret
send12: cmp flags.wldflg,0	; Any wildcards.      [7 start]
	je send16		; Nope, so no problem.
	mov bx,offset fcb	; Remember what FCB looked like.
	mov di,offset cpfcb
	mov cl,37		; Size of FCB.
	call fcbcpy
	mov di,offset fcb+1	; Copy filename	from DTA to FCB.
	mov bx,offset buff+1
	mov cl,11
	call fcbcpy					; [7 end]
send16:	call serini		; Initialize serial port. [14]
	mov pack.pktnum,0	; Set the packet number to zero.
	mov pack.numtry,0	; Set the number of tries to zero.
	mov pack.numpkt,0 	; Set the number of packets to zero.
	mov pack.numrtr,0	; Set the number of retries to zero.
	mov pack.state,'S'	; Set the state to receive initiate.
	cmp flags.remflg,0	; remote mode?
	jne send2a		; yes, continue below.
	call init		; Clear the line and initialize the buffers.
	call rtpos		; Position cursor.
	mov ax,0
	call nout		; Write the number of retries.
	call stpos		; Print status of file transfer.
	mov ah,prstr		; Be informative.
	mov dx,offset infms2
	int dos
send2:	cmp flags.remflg,0	; remote mode?
	jne send2a		; yes, skip printing
	call nppos		; Number of packets sent.
	mov ax,pack.numpkt
	call nout		; Write the packet number.
send2a:	cmp pack.state,'D'	; Are we in the data send state?
	jne send3
	call sdata
	jmp send2
send3:  cmp pack.state,'F'	; Are we in the file send state?
	jne send4
	call sfile		; Call send file.
	jmp send2
send4:  cmp pack.state,'Z'	; Are we in the EOF state?
	jne send5
	call seof
	jmp send2
send5:  cmp pack.state,'S'	; Are we in the send initiate state?
	jne send6
	call sinit
	jmp send2
send6:  cmp pack.state,'B'	; Are we in the eot state?
	jne send7
	call seot
	jmp send2
send7:  cmp pack.state,'C'	; Are we in the send complete state?
	jne send8
	call serrst		; Reset serial port.  [14]
	cmp flags.remflg,0	; remote mode?
	jne send7a		; yes, no printing.
	cmp flags.cxzflg,0	; completed normally?
	jne send7b		; no, don't bother with this
	call perpos
	mov ah,prstr
	mov dx,offset infms7
	int dos
send7b:	call stpos
	mov ah,prstr
	mov dx,offset infms3	; Plus a little cuteness.
	cmp flags.cxzflg,0	; Completed or interrupted?
	je snd71		; Ended normally.
	mov dx,offset infms6	; Say was interrupted.
snd71:  int dos			; New label. 
	cmp flags.belflg,0	; Bell desired? [17a]
	je sendnb		; [17a]
	mov dx,offset ender	; Ring them bells.   [4]
	int dos
sendnb:	call clrmod
	call rprpos
send7a:	jmp rskp
send8: 	call serrst		; Reset serial port.  [14]
	cmp flags.remflg,0	; remote mode?
	jne send9a		; no, no printing.
	call stpos
	mov ah,prstr
	mov dx,offset infms4	; Plus a little cuteness.
	int dos
	cmp flags.belflg,0	; Bell desired?  [17a]
	je send9		; No.  [17a]
	mov dx,offset ender	; Ring them bells.   [4]
	int dos			;  [4]
send9:	call clrmod
	call rprpos
send9a:	jmp rskp
SEND	ENDP
 
 
;	Send routines
 
;	Send initiate
 

SINIT	PROC	NEAR
	cmp pack.numtry,imxtry	; Have we reached the maximum number of tries?
	jl sinit2
	call erpos
	mov dx,offset erms14
	mov ah,prstr
	int dos			; Print an error message.
	mov bx,offset erms20
	call errpack		; Send error packet just in case.
	jmp abort		; Change the state to abort.
sinit2: inc pack.numtry		; Save the updated number of tries.
	mov bx,offset data	; Get a pointer to our data block.
	call rpar		; Set up the parameter information.
	xchg ah,al
	mov ah,0
	mov pack.argbk1,ax	; Save the number of arguments.
	mov ax,pack.numpkt	; Get the packet number.
	mov pack.argblk,ax
	mov ah,trans.chklen
	mov curchk,ah		; Store checksum length we want to use.
	mov trans.chklen,1	; Send init checksum is always 1 char.
	mov ah,'S'		; Send initiate packet.
	call spack		; Send the packet.
	 jmp abort
	call rpack		; Get a packet.
	 jmp sini23		; Trashed packet don't change state, retry.
	push ax
	mov ah,curchk
	mov trans.chklen,ah	; Checksum length we want to use.
	pop ax
	call acknak		; was it ok?
	cmp al,0		; maybe an ack?
	je sini22		; yes, go handle it
	cmp al,1		; maybe a nak?
	jne sinit4		; no, check for error or something
	ret			; else just return and try again
sini22:	mov ax,pack.argbk1
	mov bx,offset data	; point to data for spar
	call spar		; Read in the data.
	call packlen		; Get max send packet size. [21b]
	mov ah,pack.numtry	; Get the number of tries.
	mov pack.oldtry,ah	; Save it.
	mov pack.numtry,0	; Reset the number of tries.
	mov pack.state,'F'	; Set the state to file send.
	call getfil		; Open the file.
	 jmp abort		;  Something is wrong, die.
	mov filopn,1		; Disk file is open.
	ret
sini23:	mov ah,curchk		; Restore desired checksum length.
	mov trans.chklen,ah
	call updrtr		; Update retry counter.
	ret			; And retry.
sinit4: cmp ah,'E'		; Is it an error packet.
	jne sinit5
	call error
sinit5: jmp abort
SINIT	ENDP
 


;	Send file header
 
SFILE	PROC	NEAR
	cmp pack.numtry,maxtry	; Have we reached the maximum number of tries?
	jl sfile1
	call erpos
	mov dx,offset erms14
	mov ah,prstr
	int dos			; Print an error message.
	mov bx,offset erms21
	call errpack		; Send error packet just in case.
	jmp abort		; Change the state to abort.
sfile1: inc pack.numtry		; Increment it.
	mov flags.cxzflg,0	; Clear ^X,^Z flag. 
	mov datptr,offset data  ; Get a pointer to our data block.
	mov bx,offset fcb+1		; Pointer to file name in FCB.
	mov fcbpt,bx		; Save position in FCB.
	mov cl,0		; Counter for chars in file name.
	mov ch,0		; Counter for number of chars in FCB.
sfil11:	cmp ch,8H		; Ninth char?
	jne sfil12
	mov ah,'.'
	mov bx,datptr
	mov [bx],ah		; Put dot in data packet.	
	inc bx
	mov datptr,bx		; Save new position in data packet.
	inc cl
sfil12:	inc ch
	cmp ch,0CH		; Twelve?
	jns sfil13
	mov bx,fcbpt
	mov ah,[bx]		; Get char of filename.
	inc bx
	mov fcbpt,bx		; Save position in FCB.
	cmp ah,'!'		; Is it a good char?
	jl sfil11		; If not, get the next.
	mov bx,datptr
	mov [bx],ah		; Put char in data buffer.
	inc cl			; Increment counter.
	inc bx
	mov datptr,bx		; Save new position. 
	jmp sfil11		; Get another char.
sfil13: mov ch,0
	cmp flags.remflg,0	; remote mode?
	jne sfil13a		; yes, no printing.
	push cx			; Don't forget the size.
	mov bx,datptr
	mov byte ptr[bx],0	; terminate with a null
	call prtfn		; print filename
	pop cx
sfil13a:cmp difnam,0		; Sending file under different name.
	je sfl13x		; No, so don't give new name.
	call newfn
sfl13x:	call doenc		; Do encoding.
	mov ax,pack.pktnum	; Get the packet number.
	mov pack.argblk,ax
	mov ah,'F'		; File header packet.
	call spack		; Send the packet.
	 jmp abort
	call rpack		; Get a packet.
	 jmp tryagn		; Trashed packet don't change state, retry.
	call dodec		; Do all decoding.
	call acknak		; see what they had to say
	cmp al,0		; ack'd ok?
	je sfil14		; yes, on to next state
	cmp al,1		; maybe a nak?
	jne sfile3		; no, check for error
	ret			; if nak, just return and try again

sfil14:	mov fcb+20h,0		; set record number to zero
	mov flags.filflg,0FFH	; Indicate file buffer empty.
	call gtchr
	 jmp sfil16		; Error go see if its EOF.
	 nop
	jmp sfil17		; Got the chars, proceed.
sfil16: cmp ah,0FFH		; Is it EOF?
	je sfl161
	jmp abort		; If not give up.

sfl161: mov ah,'Z'		; Set the state to EOF.
	mov pack.state,ah
	ret

sfil17: mov siz,ax
	mov pack.state,'D'	; Set the state to data send.
	ret

sfile3: cmp ah,'E'		; Is it an error packet.
	jne sfile4
	call error
sfile4: jmp abort
SFILE	ENDP
 
 
;	Send data
 
SDATA	PROC	NEAR
	cmp flags.cxzflg,0	; Have we seen ^X or ^Z?
	je sdata2		; Nope, just continue.
	cmp flags.cxzflg,'C'	; Stop it all? [25]
	jne sdata1		; It was a ^X or ^Z.
	mov pack.state,'A'	; It was a ^C -- abort [25]
	ret
sdata1:	mov pack.state,'Z'	; Else, abort sending the file.
	ret
sdata2: cmp pack.numtry,maxtry	; Have we reached the maximum number of tries?
	jl sdata3
	call erpos
	mov dx,offset erms14
	mov ah,prstr
	int dos			; Print an error message.
	mov bx,offset erms22
	call errpack		; Send error packet just in case.
	jmp abort		; Change the state to abort.
sdata3: inc pack.numtry		; Increment it.
	mov datptr,offset data  ; Get a pointer to our data block.
	mov chrptr,offset filbuf ; Pointer to chars to be sent.
	mov cx,siz		; number to transfer
	mov si,chrptr		; source of characters
	mov di,datptr		; destination
	rep movsb		; just copy data
	mov ax,siz		; this is how many were moved
sdata7:	mov pack.argbk1,ax
	mov ax,pack.pktnum	; Get the packet number.
	mov pack.argblk,ax
	mov ah,'D'		; Data packet.
	call spack		; Send the packet.
	 jmp tryagn		; if can't send it, retry before giving up
	call rpack		; Get a packet.
	 jmp tryagn		; Trashed packet don't change state, retry.
	call dodec		; Do all decoding.
	call acknak		; see if ack or nak, check packet number
	cmp al,0		; 0 => ack ok, go on
	je sdat11
	cmp al,1		; 1 => nak, retry count incremented, try again
	jne sdat15		; else look for other packet types...
	ret			; else return

sdat11:	cmp	pack.argbk1,1	; any data?
	jne	sdat23
	mov	bl,data		; get 1st byte
	cmp	bl,'X'
	je	sdat24
	cmp	bl,'Y'
	jne	sdat23		; not x or y, just keep going
sdat24:	mov	flags.cxzflg,bl	; set flag appropriately
	mov	pack.state,'Z'	; simulate eof
	ret			; and return

sdat23: call gtchr
	 jmp sdat12		; Error go see if its EOF.
	mov siz,ax		; Save the size of the data gotten.
	ret

sdat12: cmp ah,0FFH		; Is it EOF?
	je sdat13
	jmp abort		; If not give up.

sdat13: mov pack.state,'Z'	; Set the state to EOF.
	ret

sdat15: cmp ah,'E'		; Is it an error packet.
	jne sdat16
	call error
sdat16: jmp abort
SDATA	ENDP
 
 
; check the current packet for an ack or nak and handle it from any of
; the send states.  Returns: 0 if an ack received with the correct expected
; packet number, or if a nak received with the NEXT packet number (the
; packet number is incremented, retry count reset); 1 if a nak or ack
; with a bad packet number is received, retry count is updated and displayed.
; Finally, 2 is returned if anything else is seen.
; 

ACKNAK	PROC	NEAR
	cmp	ah,'Y'		; ack packet?
	jne	ackna1		; no, keep going
	mov	bx,pack.pktnum
	cmp	bx,pack.argblk	; is it what we were expecting?
	jne	ackna2		; no, update retries and punt
; packet ok, increment packet number
ackna0:	mov	bx,pack.pktnum	; reload packet number (!!!)
	inc	bx
	and	bx,03fh		; increment packet number
	mov	pack.pktnum,bx	; store back
	inc	pack.numpkt	; increment # of packets
	mov	bl,0
	xchg	bl,pack.numtry
	mov	pack.oldtry,bl	; oldtry <- numtry, numtry <- 0
	mov	al,0		; ack'd ok
	ret
; not a 'Y'...
ackna1:	cmp	ah,'N'		; a nak?
	je	ackna5		; yes, go on
	mov	al,2
	ret			; unknown packet type
ackna5:	mov	bx,pack.pktnum
	inc	bx
	and	bx,3fh
	cmp	bx,pack.argblk	; maybe a nak for pktnum+1?
	je	ackna0		; yes, treat as ack
; nak or bad ack, update retry stuff
ackna2:	call rtpos		; Position cursor.
	inc pack.numrtr		; Increment the number of retries
	mov ax,pack.numrtr
	call nout		; Write the number of retries.
	mov	al,1		; nak code
	ret			; and return 
ACKNAK	ENDP

;	Send EOF
 
SEOF	PROC	NEAR
	cmp pack.numtry,maxtry	; Have we reached the maximum number of tries?
	jl seof1
	call erpos		; Position cursor.
	mov dx,offset erms14
	mov ah,prstr
	int dos			; Print an error message.
	mov bx,offset erms23
	call errpack		; Send error packet just in case.
	jmp abort		; Change the state to abort.
seof1:  inc pack.numtry		; Increment it.
	mov ax,pack.pktnum	; Get the packet number.
	mov pack.argblk,ax
	mov pack.argbk1,0	; No data.
	cmp flags.cxzflg,0	; Seen a ^X or ^Z?
	je seof11		; Nope, send normal EOF packet.
	mov bx,offset data	; Get data area of packet.
	mov ah,'D'		; Use "D" for discard.
	mov [bx],ah		; And add it to the packet.
	mov pack.argbk1,1	; Set data size to 1.
seof11:	mov cx,pack.argbk1	; Put size in CX.
	call doenc		; Encode the packet.
	mov ah,'Z'		; EOF packet.
	call spack		; Send the packet.
	 jmp abort
	call rpack		; Get a packet.
	 jmp tryagn		;  Trashed packet don't change state, retry.
	call dodec		; Do decoding.
	call acknak		; see what they had to say
	cmp al,0		; ack?
	je seof12		; yes, go close file and proceed
	cmp al,1		; maybe a nak?
	jne seof3		; no, check for error packet
	ret			; if nak, just return...

seof12:	mov ah,closf		; Close the file.
	mov dx,offset fcb
	int dos
	call gtnfil		; Get the next file.
	 jmp seof13		;  No more.
	mov pack.state,'F'	; Set the state to file send.
	cmp flags.cxzflg,'X'	; Control-X seen?
	jne seof14
	call cxmsg		; Clear out the interrupt msg.
seof14:	mov flags.cxzflg,0	; Reset the flag.
	ret
seof13: mov pack.state,'B'	; Set the state to EOT.
	mov filopn,0		; No files open.
	ret
seof3:  cmp ah,'E'		; Is it an error packet?
	jne seof4
	call error
seof4:  jmp abort
SEOF	ENDP
 
 
;	Send EOT
 
SEOT	PROC	NEAR
	cmp pack.numtry,maxtry	; Have we reached the maximum number of tries?
	jl seot1
	call erpos	       ; Position cursor.
	mov dx,offset erms14
	mov ah,prstr
	int dos			; Print an error message.
	mov bx,offset erms24
	call errpack		; Send error packet just in case.
	jmp abort		; Change the state to abort.
seot1:  inc pack.numtry		; Increment it.
	mov ax,pack.pktnum	; Get the packet number.
	mov pack.argblk,ax
	mov pack.argbk1,0	; No data.
	mov cx,pack.argbk1
	call doenc		; Encode packet.
	mov ah,'B'		; EOF packet.
	call spack		; Send the packet.
	 jmp abort
	call rpack		; Get a packet.
	 jmp tryagn		; Trashed packet don't change state, retry.
	call dodec		; Decode packet.
	call acknak		; see if good ack or nak
	cmp al,0		; ack'd ok?
	je seot12		; yes, done with this
	cmp al,1		; maybe a nak?
	jne seot3		; no, check for error
	ret			; else just return
seot12:	mov pack.state,'C'	; Set the state to file send.
	ret

seot3:  cmp ah,'E'		; Is it an error packet.
	jne seot4
	call error
seot4:  jmp abort
SEOT	ENDP
 
tryagn:	call updrtr
	ret

newfn:	mov ah,prstr
	mov dx,offset asmsg
	int dos
	mov ah,dconio
	mov si,offset sendas	; Buffer where the name is.
	mov di,offset data
	mov ch,0
	mov cl,difsiz		; Length of name.
newf0:	lodsb			; Get a char.
	cmp al,61H
	jb newf1		; Leave alone if less than 'a'?
	cmp al,7AH
	ja newf1		; Leave alone if over 'z'.
	sub al,20H		; Uppercase the letters.
newf1:	stosb
	mov dl,al
	cmp flags.remflg,0	; should we print?
	jne newf2		; no, we're in remote mode.
	int dos			; Print them.
newf2:	loop newf0
	mov ch,0
	mov cl,difsiz		; Reset the length field.
	ret

; Do encoding.  Expectx CX to be the data size.
doenc:	jcxz doen0
	mov chrcnt,cx		; Number of chars in filename.
	mov bx,offset data	; Source of data.
	mov bufpnt,bx
	mov bx,offset nulref	; Null routine for refilling buffer.
	mov ah,rptq
	mov origr,ah		; Save repeat prefix here.
	mov rptct,1		; Number of times char is repeated.
	mov rptval,0		; Value of repeated char.
	call encode		; Make a packet with size in AX.
	 nop
	 nop
	 nop
	mov pack.argbk1,ax	; Save number of char in filename.
	mov cx,ax
	call movpak		; Move to data part of packet.
doen0:	ret

; CX is set before this is called.
movpak:	push es
	mov ax,ds
	mov es,ax
	mov si,offset filbuf	; Move from here
	mov di,offset data	; to here
	repne movsb
	pop es
	ret

; Do decoding.
dodec:	cmp pack.argbk1,0
	je dodc0
	push ax			; Save packet size.
	mov cx,pack.argbk1	; Size of data.
	mov bx,offset data	; Address of data.
	mov ax,offset nulr	; Routine to dump buffer (null routine).
	mov bufpnt,offset decbuf  ; Where to put output.
	mov chrcnt,80H		; Buffer size.
	call decode
	 nop     
	 nop     
	 nop     
	call decmov		; Move decoded data back to "data" buffer.
 	pop ax
dodc0:	ret

; Move decoded data from decode buffer back to "data". 
decmov:	push si
	push di
	push es
	mov ax,ds
	mov es,ax
	mov cx,bufpnt		; Last char we added.
	sub cx,offset decbuf	; Get actual number of characters.
	mov pack.argbk1,cx	; Remember size of real data.
	lea si,decbuf		; Data is here.
	lea di,data		; Move to here.
	repne movsb		; Copy the data.
	mov al,0		; Null to end the string.
	stosb
	pop es
	pop di
	pop si
	ret

;	Abort
 
ABORT	PROC	NEAR
	cmp filopn,0		; Any disk files open?
	je abort0		; No so don't do a close.
	mov ah,closf		; Close the file and ignore errors.
	mov dx,offset fcb
	int dos
abort0:	mov pack.state,'A'	; Otherwise abort.
	ret
ABORT	ENDP

; This is where we go if we get an error packet.  A call to ERROR 
; positions the cursor and prints the message.  A call to ERROR1
; just prints a CRLF and then the message.  [8]
 
ERROR	PROC	NEAR
	mov pack.state,'A'	; Set the state to abort.
	call erpos		; Position the cursor.
	jmp error2
error1:	mov ah,prstr
	mov dx,offset crlf
	int dos
error2: mov bx,pack.argbk1	; Get the length of the data.
	add bx,offset data	; Get to the end of the string.
	mov ah,'$'		; Put a dollar sign at the end.
	mov [bx],ah
	mov ah,prstr		; Print the error message.
	mov dx,offset data
	int dos
	ret
ERROR	ENDP
 
; Set the maximum data packet size. [21b]

PACKLEN	PROC	NEAR
	mov ah,trans.spsiz	; Maximum send packet size. 
	sub ah,3		; - sequence, type, possible #X at end
	sub ah,trans.chklen	; And minus checksum chars.
	cmp trans.ebquot,'N'	; Doing 8-bit quoting?
	je pack0		; Nope so we've got our size.
	cmp trans.ebquot,'Y'
	je pack0		; Not doing it in this case either.
	sub ah,1		; Another 1 for 8th-bit quoting. 
pack0:	cmp rptq,0		; Doing repeat character quoting?
	je pack1		; Nope, so that's all for now.
	sub ah,2		; Another 2 for repeat prefix.
pack1:	mov trans.maxdat,ah	; Save max length for data field.
	ret
PACKLEN	ENDP

 ; Print the number in AX on the screen in decimal rather that hex. [19a]

NOUT 	PROC	NEAR
	cmp flags.xflg,1	; Writing to screen? [21c]
	je nout1		; Yes, just leave. [21c]
	push ax
	push dx
	mov temp,10		; Divide quotient by 10.
	mov dx,0		; High order word should be zero.
	div temp		; AX <-- Quo, DX <-- Rem.
	cmp ax,0		; Are we done?	
	jz nout0		; Yes.
	call nout		; If not, then recurse.
nout0:	add dl,'0'		; Make it printable.
	mov temp,ax
	mov ah,conout
	int dos	
	mov ax,temp
	pop dx
	pop ax
nout1:	ret			; We're done. [21c]
NOUT	ENDP

; Jumping to this location is like retskp.  It assumes the instruction
;   after the call is a jmp addr.
 
RSKP	PROC	NEAR
	pop bp
	add bp,3
	push bp
	ret
RSKP	ENDP
 
; Jumping here is the same as a ret.
 
R	PROC	NEAR
	ret
R	ENDP

code	ends 
	end
