	public	spar, rpar, error, error1, nout, send, flags, trans, pack
	public	dodec, doenc, curchk, inichk, packlen, send11
	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	<>
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
	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.
 
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
	cmp al,2		; Fewer than two pieces?
	jge spar0
	mov ah,dstime		; Data not supplied by host, use default.
	jmp spar02
spar0: 	mov ah,trans.stime
	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
	cmp al,3		; Fewer than three pieces?
	jge spar1
	mov ah,dspad		; Data not supplied by host, use default.
	jmp spar11
spar1:	mov ah,trans.spad
	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
	cmp al,4		; Fewer than four pieces?
	jge spar2
	mov ah,dspadc		; Data not supplied by host, use default.
	jmp spar21
spar2:	mov ah,trans.spadch
	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
	cmp al,5		; Fewer than five pieces?
	jge spar3
	mov ah,dseol		; Data not supplied by host, use default.
	jmp spar31
spar3:  mov ah,trans.seol
	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
	cmp al,6		; Fewer than six pieces?
	jge spar4
	mov ah,dsquot		; Data not supplied by host, use default.
	jmp spar41
spar4:	mov ah,trans.squote
	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
	cmp ah,'Y'		; ACK?
	jne sinit3		; If not try next.
	mov ax,pack.pktnum	; Get the packet number.
	cmp ax,pack.argblk	; Is it the right packet number?
	je sini22
	ret			; If not try again.
sini22: inc ax			; Increment the packet number.
	and ax,3FH		; Turn off the two high order bits.
	mov pack.pktnum,ax	; Save modulo 64 of the number.
	inc pack.numpkt		; Increment the number of packets.
	mov ax,pack.argbk1	; Get the number of pieces of data.
	mov bx,offset data	; Pointer to the data.
	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.
sinit3: cmp ah,'N'		; NAK?
	jne sinit4		; If not see if its an error.
	call rtpos		; Position cursor.
	inc pack.numrtr		; Increment the number of retries
	mov ax,pack.numrtr
	call nout		; Write the number of retries.
	ret
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 ah,'$'
	mov [bx],ah		; Put dollar sign for printing.
	call clrfln
	mov ah,prstr
	mov dx,offset data	; Print file name.
	int dos
	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.
	cmp ah,'Y'		; ACK?
	jne sfile2		; If not try next.
	mov ax,pack.pktnum	; Get the packet number.
	cmp ax,pack.argblk
	je sfil14
	ret			; If not hold out for the right one.
sfil14: inc ax			; Increment the packet number.
	and ax,3FH		; Turn off the two high order bits.
	mov pack.pktnum,ax	; Save modulo 64 of the number.
	inc pack.numpkt		; Increment the number of packets.
	mov ah,pack.numtry	; Get the number of tries.
	mov pack.oldtry,ah	; Save it.
	mov pack.numtry,0	; Reset the number of tries.

sfil15: mov ah,0		; Get a zero.
	mov bx,offset fcb
	add bx,20H
	mov [bx],ah		; Set the record number to zero.
;	mov flags.eoflag,ah	; Indicate not EOF.  (Done in GETFIL).
	mov ah,0FFH
	mov flags.filflg,ah	; 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
sfile2: cmp ah,'N'		; NAK?
	jne sfile3		; Try if error packet.
	call rtpos		; Position cursor.
	inc pack.numrtr		; Increment the number of retries
	mov ax,pack.numrtr
	call nout		; Write the number of retries.
	mov ax,pack.pktnum	; Get the present packet number.
	inc ax			; Increment.
	and ax,03FH		; Account for wraparound.  [18]
	cmp ax,pack.argblk	; Is the packet's number one more than now?
	jz sfil14		; Just as good as a ACK; go to the ACK code.
	ret			; If not go try again.
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
;	cmp flags.eofcz,0	; stopping on ctl-z's?
;	jz sdata6		; no, do blind copy
;sdata4:	lodsb			; get a byte
;	cmp al,'Z'-40H		; is it a ctl-z?
;	je sdata5		; yes, break loop
;	stosb			; else copy it
;	loop sdata4		; and keep going
;sdata5:	mov ax,siz		; size to send
;	sub ax,cx		; minus actually sent...
;	jmp short sdata7
;sdata6:	
	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.
	cmp ah,'Y'		; ACK?
	jne sdat14		; If not try next.
	mov ax,pack.pktnum	; Get the packet number.
	cmp ax,pack.argblk	; Is it the right packet number?
	jz sdata8
	ret			; If not hold out for the right one.
sdata8: inc ax			; Increment the packet number.
	and ax,3FH		; Turn off the two high order bits.
	mov pack.pktnum,ax	; Save modulo 64 of the number.
	inc pack.numpkt		; Increment the number of packets.
	mov ah,pack.numtry	; Get the number of tries.
	mov pack.oldtry,ah	; Save it.
	mov pack.numtry,0	; Reset the number of tries.
	cmp pack.argbk1,1	; Does the ACK contain data?
	jne sdat11		; Nope, so continue.
	mov bx,offset data	; If yes, check the data field.
	mov ah,[bx]		; Pick it up.
	cmp ah,'X'		; Other side requests ^X?
	jne sdata9		; Nope.
	jmp sdat10		; And leave.
sdata9: cmp ah,'Z'		; Other side requests ^Z?
	jne sdat11		; Nope.
sdat10:	mov flags.cxzflg,ah	; Yes remember it.
	mov pack.state,'Z'	; Abort sending file(s).
	ret
sdat11: 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
sdat14: cmp ah,'N'		; NAK?
	jne sdat15		; See if is an error packet.
	call rtpos		; Position cursor.
	inc pack.numrtr		; Increment the number of retries
	mov ax,pack.numrtr
	call nout		; Write the number of retries.
	mov ax,pack.pktnum	; Get the present packet number.
	inc ax			; Increment.
	and ax,03FH		; Account for wraparound.  [18]
	cmp ax,pack.argblk	; Is the packet's number one more than now?
	jz sdata8		; Just as good as ACK; goto ACK code.
	ret			; If not go try again.
sdat15: cmp ah,'E'		; Is it an error packet.
	jne sdat16
	call error
sdat16: jmp abort
SDATA	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.
	cmp ah,'Y'		; ACK?
	jne seof2		; If not try next.
	mov ax,pack.pktnum	; Get the packet number.
	cmp ax,pack.argblk	; Is it the right packet number?
	jz seof12
	ret			; If not hold out for the right one.
seof12: inc ax			; Increment the packet number.
	and ax,3FH		; Turn off the two high order bits.
	mov pack.pktnum,ax	; Save modulo 64 of the number.
	inc pack.numpkt		; Increment the number of packets.
	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 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
seof2:  cmp ah,'N'		; NAK?
	jne seof3		; Try and see if its an error packet.
	call rtpos		; Position cursor.
	inc pack.numrtr		; Increment the number of retries
	mov ax,pack.numrtr
	call nout		; Write the number of retries.
	mov ax,pack.pktnum	; Get the present packet number.
	inc ax			; Increment.
	and ax,03FH		; Account for wraparound.  [18]
	cmp ax,pack.argblk	; Is the packet's number one more than now?
	jz seof12		; Just as good as a ACK; go to the ACK code.
	ret			; If not go try again.
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.
	cmp ah,'Y'		; ACK?
	jne seot2		; If not try next.
	mov ax,pack.pktnum	; Get the packet number.
	cmp ax,pack.argblk	; Is it the right packet number?
	jz seot12
	ret			; If not hold out for the right one.
seot12: inc ax			; Increment the packet number.
	and ax,3FH		; Turn off the two high order bits.
	mov pack.pktnum,ax	; Save modulo 64 of the number.
	inc pack.numpkt		; Increment the number of packets.
	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,'C'	; Set the state to file send.
	ret
seot2:  cmp ah,'N'		; NAK?
	jne seot3		; Is it error.
	call rtpos		; Position cursor.
	inc pack.numrtr		; Increment the number of retries
	mov ax,pack.numrtr
	call nout		; Write the number of retries.
	mov ax,pack.pktnum	; Get the present packet number.
	inc ax			; Increment.
	and ax,03FH		; Account for wraparound.  [18]
	cmp ax,pack.argblk	; Is the packet's number one more than now?
	jz seot12		; Just as good as a ACK; go to the ACK code.
	ret			; If not go try again.
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,4		; Size minus control info. 
	sub ah,trans.chklen	; And minus checksum chars.
	sub ah,2		; Leave room at end: 2 for possible #X.
	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.
;	cwd			; Convert word to doubleword.
	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
