	public	read12, read2, rin21, rfile3, read, updrtr, nak, rrinit
	include msdefs.h	

datas 	segment	public 'datas'
	extrn	fcb:byte, data:byte, bufpnt:word, chrcnt:word, curchk:byte
	extrn	comand:byte, flags:byte, pack:byte, trans:byte

ermes7  db      '?Unable to receive initiate$'
ermes8  db      '?Unable to receive file name$'
ermes9  db      '?Unable to receive end of file$'
erms10  db      '?Unable to receive data$'
infms1  db	cr,'           Receiving: In progress$'
infms3  db      'Completed$'
infms4  db      'Failed$'
infms6  db      'Interrupted$'
remmsg1	db	'Kermit-MS: Invalid filename'
filhlp2 db      ' Confirm with carriage return or specify name '
	db	' to use for incoming file $'
ender	db	bell,bell,'$'
crlf	db	cr,lf,'$'
temp	dw	0
filopn	db	0		; Says if disk file is open.
datas	ends

code	segment	public
	extrn	gofil:near, outbuf:near, fixfcb:near, comnd:near
	extrn	spack:near, rpack:near, serini:near, serrst:near
	extrn	spar:near, rpar:near, init:near, init1:near, cxmsg:near
	extrn	error:near, ptchr:near, erpos:near, rtpos:near
	extrn	stpos:near, rprpos:near, nppos:near, nout:near
	extrn	dodec:near, doenc:near, errpack:near
	extrn	send11:near, clrmod:near
	assume  cs:code, ds:datas

 
; Update retry count and fall through to send a NAK.
nak0:	call updrtr		; Update retry count.

nak:	mov ax,pack.pktnum     ; Get the packet number we're waiting for.
        mov pack.argblk,ax
        mov pack.argbk1,0
	mov cx,0		; No data, but this may change.
	call doenc		; So call encode.
        mov ah,'N'              ; NAK that packet.
        call spack
	 jmp abort
	 nop			; So 'jmp rskp' in SPACK comes here. [19a]
        ret                     ; Go around again.

updrtr:	cmp pack.state,'A'	; Supposed to abort?
	je upd0			; Yes, don't bother with retry count.
	inc pack.numrtr		; Increment the number of retries.
	cmp flags.xflg,1	; Writing to screen?
	je upd0
	call rtpos		; Position cursor.
	mov ax,pack.numrtr
	call nout		; Write the number of retries.
upd0:	ret

;       Abort
ABORT   PROC    NEAR
	cmp filopn,0		; Disk file open?
	je abort0		; No so don't close.
	cmp flags.xflg,1	; Writing to the screen?
	je abort0		; Yes, don't close "file".
	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

; init variables for read...
rrinit	proc	near
	mov pack.numpkt,0	; Set the number of packets to zero.
	mov pack.numrtr,0	; Set the number of retries to zero.
	mov pack.pktnum,0	; Set the packet number to zero.
	mov pack.numtry,0	; Set the number of tries to zero.
	ret
rrinit	endp

;	RECEIVE command  --  Some code moved to the GET routine. [21a] 
 
READ	PROC	NEAR		
	mov comand.cmrflg,1	; Say we're receiving a file. [21a start]
	mov comand.cmcr,1	; Allow bare CR after RECEIVE.
	mov flags.droflg,0	; Override default drive flag.
	mov flags.nmoflg,0	; Override file name from other host?
	mov dx,offset fcb	; Put filename here. 
	mov bx,offset filhlp2	; Text of help message.
	mov ah,cmifi		; Read in the filename.
	call comnd		
	 jmp r				
	mov comand.cmrflg,0	; Reset flag.
	mov comand.cmcr,0
	mov flags.wldflg,0	; Just in case
	mov ah,cmcfm		; Get a confirm.
	call comnd
	 jmp r
read1:	cmp flags.remflg,0	; remote mode?
	jne read12		; yes, no printing
	cmp flags.destflg,2	; Receiving to the screen? [27c]
	je read12		; Yes no printing [27c]
	call init
read12:	mov flags.cxzflg,0	; Reset ^X/^Z flag. [20c] 
	call rrinit		; init variables for read
	call serini		; Initialize serial port. [14]
	cmp flags.remflg,0	; in remote mode?
	jne read12a		; yes, no printing
	call init1		; Clear the line and initialize the buffers.
	cmp flags.destflg,2	; Receiving to the screen? [27c]
	je read12a		; Yes no printing [27c]
	call stpos
	mov ah,prstr		; Be informative.
	mov dx,offset infms1
	int dos
	call rtpos		; Position cursor.
	mov ax,pack.numrtr
	call nout		; Write the number of retries.
read12a:mov pack.state,'R'	; Set the state to receive initiate.
read2: 	cmp flags.xflg,1	; Are we receiving to the screen. [21c]
	je read21		; Skip the screen stuff. [21c]
	cmp flags.remflg,0	; maybe remote mode?
	jne read21		; yup, skip the screen stuff
	call nppos		; Position cursor for number of packets msg.
	mov ax,pack.numpkt
	call nout		; Write the number of packets.
read21: mov ah,pack.state	; Get the state. [21c]
	cmp ah,'D'		; Are we in the data send state?
	jne read3
	call rdata
	jmp read2
read3:  cmp ah,'F'		; Are we in the file receive state?
	jne read4
	call rfile		; Call receive file.
	jmp read2
read4:  cmp ah,'R'		; Are we in the receive initiate state?
	jne read5
	call rinit
	jmp read2
read5:  cmp ah,'C'		; Are we in the receive complete state?
	jne read6
	call serrst		; Reset serial port. [14]
	cmp flags.xflg,0	; Did we write to the screen? [21c]
	je read51		; No so print status. [21c]
	cmp flags.destflg,2	; Receiving to screen? [27c]
	je read51a		; Yes don't reset. [27c]
	mov flags.xflg,0	; Reset it. [21c]
	jmp rskp		; Yes, so just return. [21c]	
read51:	cmp flags.remflg,0	; remote mode?
	jne read51a		; yes, keep going
	call stpos		; Position cursor. [21c]
	mov ah,prstr
	mov dx,offset infms3	; Plus a little cuteness.
	cmp flags.cxzflg,0	; Completed or interrupted? [20c]
	je read13		; Ended normally. [20c]
	mov dx,offset infms6	; Say was interrupted. [20c]
read13: int dos
	cmp flags.belflg,0	; Bell desired?  [17a]
	je readnb		; No.  [17a]
	mov dx,offset ender	; Ring them bells.    [4]
	int dos			; [4]
readnb:	call clrmod		; clear 25th line
	call rprpos		; Put prompt here.
read51a:jmp rskp
read6: 	call serrst		; Reset serial port. [14]
	cmp flags.xflg,0	; Did we write out to screen? [21c]
	je read61		; No so print status. [21c]
	cmp flags.destflg,2	; Receiving to screen? [27c]
	je read7a		; Yes don't reset. [27c]
	mov flags.xflg,0	; Reset it. [21c]
	jmp rskp		; Print onto screen. [21c]
read61:	cmp flags.remflg,0	; remote mode?
	jne read7a		; yes, no printing.
	call stpos		; Position cursor.  [21c]
	mov ah,prstr
	mov dx,offset infms4	; Plus a little cuteness.
	int dos
	cmp flags.belflg,0	; Bell desired?  [17a]
	je read7		; No.  [17a]
	mov dx,offset ender	; Ring them bells.   [4]
	int dos			;  [4]
read7:	call clrmod		; clear mode line
	call rprpos		; Put prompt here.
read7a:	jmp rskp
READ	ENDP
 
 
;	Receive routines
 
;	Receive init
 
RINIT	PROC	NEAR
	mov ah,pack.numtry	; Get the number of tries.
	cmp ah,imxtry		; Have we reached the maximum number of tries?
	jl rinit2
	call erpos		; Position cursor.
	mov dx,offset ermes7
	mov ah,prstr
	int dos			; Print an error message.
	mov bx,dx
	call errpack		; Send error packet just in case.
	jmp abort		; Change the state to abort.
rinit2: inc ah			; Increment it.
	mov pack.numtry,ah	; Save the updated number of tries.
	mov ax,pack.argbk2	; get packet type if here from get
	cmp flags.getflg,1	; Have we already read in the packet? [21a] 
	je rin21a		; Yes, so don't call RPACK. [21a]
	mov ah,trans.chklen
	mov curchk,ah		; Save checksum length we want to use.
	mov trans.chklen,1	; Use 1 char for init packet.
	call rpack		; Get a packet.
	 jmp rin22		; Trashed packet: nak, retry.
	push ax
	mov ah,curchk
	mov trans.chklen,ah	; Reset to desired value.
	pop ax
rin21a:	cmp ah,'S'		; Is it a send initiate packet?
	jne rinit3		; If not see if its an error.
rin21:	mov flags.getflg,0	; Reset flag. [21a]
	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 ax,pack.argblk	; Returned packet number.  (Synchronize them.)
	inc ax			; Increment it.
	and ax,3FH		; Turn off the two high order bits.
	mov pack.pktnum,ax	; Save modulo 64 of the number.
	mov bx,pack.numpkt
	inc bx			; Increment the number of packets.
	mov pack.numpkt,bx
	mov ax,pack.argbk1	; Get the number of arguments received.
	mov bx,offset data	; Get a pointer to the data.
	call spar		; Get the data into the proper variables.
	mov bx,offset data	; Get a pointer to our data block.
	call rpar		; Set up the receive parameters.
	xchg ah,al
	mov ah,0
	mov pack.argbk1,ax	; Store the returned number of arguments.
	mov ah,trans.chklen	; Checksum length we'll use.
	mov curchk,ah		; Save it.
	mov trans.chklen,1	; Use 1 char for init packet.
	mov ah,'Y'		; Acknowledge packet.
	call spack		; Send the packet.
	 jmp abort
	mov ah,curchk		; Checksum length we'll use.
	mov trans.chklen,ah	; Reset to desired value.
	mov ah,'F'		; Set the state to file send.
	mov pack.state,ah
	ret
rin22:	mov ah,curchk
	mov trans.chklen,ah	; Reset to desired value.
	jmp nak0		; Try again.
rinit3: cmp ah,'E'		; Is it an error packet?
	jne rinit4
	call error
rinit4:	jmp abort
RINIT	ENDP
 

;	Receive file
 
RFILE	PROC	NEAR
	cmp pack.numtry,maxtry	; Have we reached the maximum number of tries?
	jl rfile1
	call erpos		; Position cursor.
	mov dx,offset ermes8
	mov ah,prstr
	int dos			; Print an error message.
	mov bx,dx
	call errpack		; Send error packet just in case.
	jmp abort		; Change the state to abort.
rfile1: inc pack.numtry		; Save the updated number of tries.
	call rpack		; Get a packet.
	 jmp nak0		;  Trashed packet: nak, retry.
	cmp ah,'S'		; Is it a send initiate packet?
	je rfil10
	call dodec		; Decode all incoming packets.
	jmp rfile2		;  No, try next type.
rfil10:	cmp pack.oldtry,imxtry	; Have we reached the maximum number of tries?
	jl rfil12		; If not proceed.
	call erpos		; Position cursor.
	mov dx,offset ermes7
	mov ah,prstr
	int dos			; Print an error message.
	mov bx,dx
	call errpack		; Send error packet just in case.
	jmp abort		; Change the state to abort.
rfil12: inc pack.oldtry		; Save the updated number of tries.
	mov ax,pack.pktnum	; Get the present packet number.
	cmp ax,0		; Had we wrapped around? [18 start]
	jne rfilx 
	mov ax,64
rfilx:  dec ax			; Decrement.  [18 end -- new label]
	cmp ax,pack.argblk	; Is the packet's number one less than now?
	je rfil13
	jmp nak0		; No, NAK and try again.
rfil13: call updrtr		; Update retry count.
	mov pack.numtry,0	; Reset the 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 ah,'Y'		; Acknowledge packet.
	call spack		; Send the packet.
	 jmp abort
	ret
rfile2: cmp ah,'Z'		; Is it an EOF packet?
	jne rfile3		;  No, try next type.
	cmp pack.oldtry,maxtry	; Have we reached the maximum number of tries?
	jl rfil21		; If not proceed.
	call erpos		; Position cursor.
	mov dx,offset ermes9
	mov ah,prstr
	int dos			; Print an error message.
	mov bx,dx
	call errpack		; Send error packet just in case.
	jmp abort		; Change the state to abort.
rfil21: inc pack.oldtry		; Increment it.
	mov ax,pack.pktnum	; Get the present packet number.
	cmp ax,0		; Had we wrapped around? [18 start]
	jne rfily
	mov ax,64
rfily:  dec ax			; Decrement.  [18 end -- new label]
	cmp ax,pack.argblk	; Is the packet's number one less than now?
	je rfil24
	jmp nak0		; No, NAK and try again.
rfil24: call updrtr		; Update retry count.
	mov pack.numtry,0
	mov pack.argbk1,0	; No data.  (The packet number is in argblk.)
	mov cx,0
	call doenc
	mov ah,'Y'		; Acknowledge packet.
	call spack		; Send the packet.
	 jmp abort
	ret
rfile3: cmp ah,'F'		; Start of file?
	je rfil31		; Yes. [21c]
	cmp ah,'X'		; Text header packet? [21c]
	jne rfile4		; Neither one. 
rfil31: mov ax,pack.argblk	; Get the packet number. [21c]
	cmp ax,pack.pktnum	; Is it the right packet number?
	je rfil32
	jmp nak			; No, NAK it and try again.
rfil32: 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.
	call gofil		; Get a file to write to.
	 jmp abort
	mov filopn,1		; Disk file open.
	call init1		; Initialize all the buffers.
	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.argbk1,0	; No data.  (The packet number is in argblk.)
	mov cx,0
	call doenc
	mov ah,'Y'		; Acknowledge packet.
	call spack		; Send the packet.
	 jmp abort
	mov pack.state,'D'	; Set the state to data receive.
	ret
rfile4: cmp ah,'B'		; End of transmission.
	jne rfile5
	mov ax,pack.pktnum
	cmp ax,pack.argblk	; Do we match?
	je rfil41
	jmp nak			; No, NAK it and try again.
rfil41: mov pack.argbk1,0	; No data.  (Packet number already in argblk).
	mov cx,0
	call doenc
	mov ah,'Y'		; Acknowledge packet.
	call spack		; Send the packet.
	 jmp abort
	mov pack.state,'C'	; Set the state to complete.
	ret
rfile5: cmp ah,'E'		; Is it an error packet.
	jne rfile6
	call error
rfile6: jmp abort
RFILE	ENDP
 
 
;	Receive data
 
RDATA	PROC	NEAR
	cmp pack.numtry,maxtry	; Get the number of tries.
	jl rdata1
	call erpos		; Position cursor.
	mov dx,offset erms10
	mov ah,prstr
	int dos			; Print an error message.
	mov bx,dx
	call errpack		; Send error packet just in case.
	jmp abort		; Change the state to abort.
rdata1: inc pack.numtry		; Save the updated number of tries.
	call rpack		; Get a packet.
	 jmp nak0		;  Trashed packet: nak, retry.
	cmp ah,'D'		; Is it a data packet?
	je rdat11
	call dodec		; Decode data.
	jmp rdata2		;  No, try next type.
rdat11: mov ax,pack.pktnum	; Get the present packet number.
	cmp ax,pack.argblk	; Is the packet's number correct?
	jz rdat14
	cmp pack.oldtry,maxtry	; Have we reached the maximum number of tries?
	jl rdat12		; If not proceed.
	call erpos		; Position cursor.
	mov dx,offset erms10
	mov ah,prstr
	int dos			; Print an error message.
	mov bx,dx
	call errpack		; Send error packet just in case.
	jmp abort		; Change the state to abort.
rdat12: inc pack.oldtry		; Save the updated number of tries.
	mov ax,pack.pktnum
	cmp ax,0		; Had we wrapped around? [18 start]
	jne rdatx
	mov ax,64
rdatx:	dec ax			; [14] [18 end -- new label]
	cmp ax,pack.argblk	; Is the packet's number one less than now?
	je rdat13
	jmp nak0		; No, NAK it and try again.
rdat13: call updrtr		; Update retry count.
	mov pack.numtry,0	; Reset number of tries.
	mov pack.argbk1,0	; No data.  (The packet number is in argblk.)
	mov cx,0
	call doenc
	mov ah,'Y'		; Acknowledge packet.
	call spack		; Send the packet.
	 jmp abort
	ret
rdat14: 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 ax,pack.argbk1	; Get the length of the data.
	cmp flags.cxzflg,0	; Has the user typed a ^X or ^Z? [20c]
	je rdt14x		; No, write out the data.
	cmp flags.abfflg,1	; Discard incomplete files?
	je rdat15		; If yes don't write data out to file. [20c]
rdt14x:	mov bx,offset data	; Where the data is. [25]
	call ptchr
	 jmp abort		;  Unable to write out chars; abort.
rdat15: mov pack.numtry,0	; Reset the number of tries.
	mov pack.argbk1,0	; No data.  (Packet number still in argblk.)
	mov cx,0
	cmp flags.cxzflg,0	; Interrupt file transfer? [20c]
	je rdat16		; Nope. [20c] 
	mov bx,offset data	; Send data in ACK in case remote... [20c] 
	mov ah,flags.cxzflg	; ... knows about ^X/^Z. [20c]
	mov [bx],ah		; Put data into the packet. [20c]
	mov pack.argbk1,1	; Set data size to 1. [20c]
	mov cx,1
rdat16: call doenc
	mov ah,'Y'		; Acknowledge packet.
	call spack		; Send the packet.
	 jmp abort
	ret
rdata2: cmp ah,'F'		; Start of file?
	je rdat20		; Yup. [21c]
	cmp ah,'X'		; Text header packet? [21c]
	jne rdata3		;  No, try next type.
rdat20: cmp pack.oldtry,maxtry	; Reached the max number of tries? [21c]
	jl rdat21		; If not proceed.
	call erpos		; Position cursor.
	mov dx,offset ermes8
	mov ah,prstr
	int dos			; Print an error message.
	mov bx,dx
	call errpack		; Send error packet just in case.
	jmp abort		; Change the state to abort.
rdat21: inc pack.oldtry		; Save the updated number of tries.
	mov ax,pack.pktnum
	cmp ax,0		; Had we wrapped around? [18 start]
	jne rdaty
	mov ax,64
rdaty:	dec ax			; [14 Omitted accidentally - D.T.] [18 end]
	cmp ax,pack.argblk	; Is the packet's number one less than now?
	je rdat22
	jmp nak0		; No, NAK it and try again.
rdat22: call updrtr		; Update retry count.
	mov pack.numtry,0	; Reset number of tries.
	mov pack.argbk1,0	; No data.  (The packet number is in argblk.)
	mov cx,0
	call doenc
	mov ah,'Y'		; Acknowledge packet.
	call spack		; Send the packet.
	 jmp abort
	ret
rdata3: cmp ah,'Z'		; Is it a EOF packet?
	je rdat3x		; [13]
	jmp rdata4		; Try and see if its an error. [13]
rdat3x: mov ax,pack.pktnum	; Get the present packet number. [13]
	cmp ax,pack.argblk	; Is the packet's number correct?
	je rdat32
	jmp nak0		; No, NAK it and try again.
rdat32: 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
	cmp flags.cxzflg,0	; Do we want to discard the file? [20c]
	jne rdt32x		; Yes. [20c]
	cmp pack.argbk1,1	; One piece of data? [20c]
	jne rdat33		; Nope - finish writing out file? [20c]
	mov bx,offset data	; Get data area. [20c]
	mov ah,[bx]		; Get the data. [20c]
	cmp ah,'D'		; "D" for discard? [20c]
	jne rdat33		; Nope - write out file. [20c]
rdt32x:	cmp flags.abfflg,0	; Keep incomplete files?
	je rdat33		; Yes, go write it out.
	cmp flags.xflg,1	; Writing to the screen?
	je rdt32y		; Don't close "file".
	mov ah,closf		; First, close the file.
	mov dx,offset fcb	; Give the file parameters. [20c]
	int dos			; Kill it, ignore errors. [20c]
	mov ah,delf		; Delete the file if opened. [20c]
	int dos
rdt32y:	cmp flags.cxzflg,'X'	; Kill one file or all? [20c]
	jne rdat36		; No so leave flag alone. [20c]
	call cxmsg		; Clear msg about interrupt. [20c]
	mov flags.cxzflg,0	; Reset - ^X only kills one file. [20c]
	jmp rdat36
rdat33: mov bx,bufpnt		; Get the dma pointer.
	mov ax,80H
	sub ax,chrcnt		; Get the number of chars left in the DMA.
	cmp flags.destflg,0	; Add ^Z if writing to printer.
	je rdt33x
	cmp flags.eofcz,0	; should we write a ^Z?
	jz rdat35		; no, keep going
	cmp flags.xflg,0	; writing to a file?
	jne rdat35		; no, skip ^Z
rdt33x:	cmp ax,80H		;   [13 start]
	jne rdat34
	call outbuf		; Write out buffer if no room for ^Z.
	 jmp abort
	mov ax,0		;   [13 end]
	inc chrcnt		; Increment size by one (not two). [21b]
rdat34: mov cl,'Z'-100O		; Put in a ^Z for EOF.
	mov [bx],cl		; Add it. [21c]
	inc ax
	dec chrcnt
rdat35:	mov cx,chrcnt
	mov temp,cx
	call outbuf		; Output the last buffer.
	 jmp abort		; Give up if the disk is full.
	mov ax,temp		; Prepare for the function call.
	call fixfcb
	cmp flags.xflg,1	; Writing to the screen?
	je rdat37		; Yes, don't close "file".
	mov ah,closf		; Close up the file.
	mov dx,offset fcb
	int dos
rdat36:	cmp flags.destflg,1	; Writing to disk?
	je rdat37		; Yes, skip next part.
	cmp flags.xflg,1	; Writing to screen?
	je rdat37		; Yes, skip this part.
	mov dl,ff		; Send a form feed.
	mov ah,lstout		; Write out to first printer.
	int dos
rdat37:	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.argbk1,0	; No data.  (The packet number is in argblk.)
	mov cx,0
	call doenc
	mov ah,'Y'		; Acknowledge packet.
	call spack		; Send the packet.
	 jmp abort
	mov pack.state,'F'
	mov filopn,0		; File closed now.
	ret
rdata4: cmp ah,'E'			; Is it an error packet.
	jne rdata5
	call error
rdata5: jmp abort
RDATA	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

R	PROC	NEAR
	ret
R	ENDP

code	ends 
	end
 
