	public	bufpnt, buff, fcb, cpfcb, chrcnt, fixfcb, init, init1,
	public	gofil, outbuf, ptchr, gtchr, gtnfil, getfil, filbuf,
	public	encode, decode, nulref, nulr, decbuf, errpack, rptq,
	public	origr, rptct, rptval, clrfln, cxmsg, biterr, intmsg,
	public	rtpos, erpos,rppos, stpos,nppos,rprpos,nrtpos,sppos,
	public	kbpos,perpos,frpos, prtscr
	include msdefs.h

rptmin	equ	3		; At least 3 of same char in a row.

; equates for screen positioning
scrfln	equ	0316H		; Place for file name.
scrkb	equ	0416H		; Place for percent transferred.
scrper	equ	0516H		; Place for Kbytes transferred.
scrst	equ	0616H		; Place for status.
scrnp	equ	0816H		; Place for number of packets.
scrnrt  equ	0916H		; Place for number of retries.
screrr  equ	0A16H		; Place for error msgs. 
scrhi	equ	0B16H		; Err when 8th bit is on.
scrfr	equ	0B16H		; Rename file.
scrint	equ	0B16H		; Acknowledge interrupt. [20b]
scrsp	equ	0C00H		; Place for send packet.
scrrp	equ	0E00H		; Place for receive packet.
scrrpr	equ	1100H		; Prompt when Kermit ends.



datas	segment	public 'datas'
	extrn	data:byte, flags:byte, trans:byte, pack:byte, hierr:byte
	extrn	dosnum:byte

outlin  db	cr,lf,cr,lf
        db      cr,lf,'           File name:'
        db      cr,lf,'  KBytes transferred:'
        db      cr,lf
        db      cr,lf
        db      cr,lf
        db      cr,lf,'   Number of packets:'
        db      cr,lf,'   Number of retries:'
        db      cr,lf,'          Last error: None'
        db      cr,lf,'        Last warning: None'
        db      '$'

ermes4  db	'Unable to rename file$'
erms10  db	'?Unable to receive data$'
erms11  db	'?Disk full$'
erms12	db	'?Unable to create file$'
erms17  db	'Record length exceeds size of buffer$'
infms5  db	'Renaming file to $'
infms7	db	'File interrupt$'
infms8	db	'File group interrupt$'
hibit	db	'Warning - Non Ascii char$'
crlf	db	cr,lf,'$'
printer	db	0,'PRN        '
spchar	db	24H,26H,23H,40H,21H,25H,27H,28H,29H,2DH
	db	3CH,3EH,7BH,7DH,5FH,5CH,5EH,7EH,7CH,60H
spclen	equ	$-spchar	; Number of special chars.
spchar2	db	24H,26H,23H,40H,21H,25H,27H,28H,29H,2DH
	db	7BH,7DH,5FH,5EH,7EH,60H
spc2len	equ	$-spchar2
next	db	0FFH		; No next character just yet.
rptval	db	0		; Repeated character.
rptct	db	1		; Number of times it's repeated.
rptq	db	drpt		; Repeat prefix.
origr	db	drpt		; Original repeat prefix.
temp1	dw	?		; Temporary storage.
temp2	dw	?
oloc	dw	0		; Original buffer location. [21c]
osiz	dw	0		; Original buffer size. [21c]
chrcnt  dw	?		; Number of chars in the file buffer.
outpnt  dw	?		; Position in packet.
bufpnt  dw	?		; Position in file buffer.
fdtpnt	dw	?		; Pointer to within our file. 
fcbptr  dw	?		; Position in FCB.
cbfptr  dw	?		; Position in character buffer.
filsiz	dw	0		; Double word for filesize (in bytes.)
	dw	0
ofilsz	dw	0		; Original file size percent adjusted (/100).
tfilsz	dw	0		; Bytes transferred.
	dw	0
oldper	dw	?		; old percentage
oldkbt	dw	?		; old KB transferred.
wrpmsg	db	?		; non-zero if we wrote percent message
percnt	dw	100		; Number to divide by for a percent.
bufhex	dw	80H
permsg	db	cr,' Percent transferred:$'
cxzhlp	db	'^X cancels file, ^Z cancels batch'
	db	', ^E aborts protocol'
	db	', ^C quits'
	db	', Return retries'
	db	'$'
asmsg	db	' AS '
asmln	equ	$-asmsg
filbuf  db	60H DUP(?)	; Character buffer.
buff	db	dmasiz DUP(?)	; Use as our DTA.
fcb	db	fcbsiz DUP(?)	; Use as our FCB.
cpfcb	db	fcbsiz DUP(?)	; Save FCB in case of "*".   [7]
decbuf	db	dmasiz DUP(?)	; For decoding incoming data.
datas	ends

code	segment	public
	extrn	spack:near, cmblnk:near, locate:near, nout:near
	extrn	putmod:near, poscur:near, clearl:near, fcbcpy:near
	assume  cs:code,ds:datas

; Position cursor for an error message.

ERPOS	PROC 	NEAR
	cmp flags.xflg,1	; Packet header seen? [21c start] 
	jne erp0		; No, do as normal. 
	mov dx,offset crlf
	mov ah,prstr
	int dos
	ret
erp0:	mov dx,screrr
	jmp poscur
ERPOS	ENDP

; Position cursor for number of retries message.

RTPOS	PROC 	NEAR
	cmp flags.xflg,1	; Packet header seen? [21c]
	jne rtp0		; No, do as normal.
	ret
rtp0:	mov dx,scrnrt
	jmp poscur
RTPOS	ENDP

; Reassure user that we acknowledge his ^X/^Z.

INTMSG	PROC	NEAR
	cmp flags.xflg,0	; Writing to screen?
	jne int1		; Yes. Don't do anything.
	mov dx,scrint
	call poscur
	call clearl
	mov dx,offset infms7    ; File interrupted?
	cmp flags.cxzflg,'X'	; Yes. 
	je int0
	mov dx,offset infms8	; File group interrupted.
int0:   mov ah,prstr
        int dos
int1:	ret
INTMSG	ENDP

; Print err message that found a non-standard-Ascii char in the file.

BITERR	PROC	NEAR
	cmp flags.remflg,0	; remote mode?
	jne biter1		; yes, no printing.
	push bx
	mov dx,scrhi
	call poscur
	call clearl
	mov ah,prstr
	mov dx,offset hibit
	int dos
	pop bx
biter1:	ret
BITERR	ENDP		

;  Clear out message about interrupted file.

CXMSG	PROC	NEAR
	cmp flags.xflg,0	; Writing to screen?
	jne cxm0		; Yes. Don't do anything.
	mov dx,scrint
	call poscur
	call clearl
cxm0:	ret
CXMSG	ENDP

;  Clear out the old filename on the screen. 

CLRFLN	PROC	NEAR
	mov dx,scrfln
	call poscur
	call clearl		; Clear to end of line. [19a]
	ret
CLRFLN	ENDP

; some random screen positioning functions
kbpos:	mov dx,scrkb		; KBytes transferred.
	call poscur
	jmp clearl
perpos:	mov dx,scrper		; Percent transferred.
	call poscur
	jmp clearl
frpos:	mov dx,scrfr		; Say renamed file.
	call poscur
	jmp clearl
stpos:	mov dx,scrst		; Print status of file transfer.
	call poscur
	jmp clearl
nppos:	mov dx,scrnp		; Number of packets sent.
	jmp poscur
rprpos:	mov dx,scrrpr		; Reprompt position.
	jmp poscur
nrtpos:	mov dx,scrnrt		; Number of retries.
	jmp poscur
sppos:	mov dx,scrsp		; Send packet location.
	jmp poscur
rppos:	mov dx,scrrp		; Receive packet location.
	jmp poscur



;	Initialize buffers and clear line.
 
INIT	PROC	NEAR
	call cmblnk
	call locate
	mov ah,prstr		; Put statistics headers on the screen.
	mov dx,offset outlin
	int dos
	mov dx,offset cxzhlp
	call putmod		; write mode line
	mov wrpmsg,0		; haven't printed the messsage yet.
	call init1
	ret
INIT	ENDP
 
INIT1	PROC	NEAR
	mov chrcnt,dmasiz	       ; Number of chars left.
	mov bufpnt,offset buff	       ; Addr for beginning.
	mov hierr,0
	ret
INIT1	ENDP

;	Output the chars in a packet.

; Called with AX = size of the data, BX = address of source.

FILEIO	PROC	NEAR 	
ptchr:  mov cx,ax
	mov ax,offset outbuf	;Where to put data when buffer gets full.
	jmp decode

; CX = Size of data, BX = Address of data, AX = Routine to call to
; dump data.

decode: push si
	push di
	push es
	push dx
	push ax
	mov ax,ds
	mov es,ax
	pop ax
	mov si,bx		; Source of data.
	mov bx,ax		; Coroutine to call.
	mov di,bufpnt		; Destination of data.
	mov dh,0		; assume no quote char
	cmp trans.ebquot,'N'	; no quoting?
	je decod1		; yes, keep going
	cmp trans.ebquot,'Y'	; or not doing it?
	je decod1		; yes, keep going
	mov dh,trans.ebquot	; otherwise use quote char

decod1:	mov rptct,0		; Reset.
	mov rptval,0		; Ditto.
	dec cx
	jge dcod11		; More data.
	jmp decod6		; Else, we're through.
dcod11:	dec chrcnt		; Decrement number of chars in dta.
	jns decod2		; Continue if space left.
	push cx
	push dx
	push bx
	call bx			; Output it if full.
	 jmp decod5		;  Error return if disk is full.
	 nop
	pop bx
	pop dx
	pop cx
	mov di,bufpnt
decod2:	cmp rptct,0		; Doing a repeat?
	je dcod20		; No, so go get a character.
	mov ah,0
	mov al,rptval		; Get the character we're repeating.
	jmp decod4		; And write it out to the file.
dcod20:	lodsb			; Pick up a char.
	cmp rptq,0		; Doing repeat quoting?
	je dcod21		; Nope, skip this part.
	cmp al,rptq		; Did we pick up the repeat quote char?	
	jne dcod21		; No, continue processing it.
	lodsb			; Get the size.
	dec cx			; Modify buffer count.
	sub al,20H		; Was made printable.
	mov rptct,al		; Remember how many repetitions.
	lodsb			; Get the char to repeat.
	dec cx			; Modify buffer count.
dcod21:	mov ah,00H		; Assume no 8-bit quote char. [21b start]
	cmp al,dh		; This the 8-bit quot char?
	jne decod3
	lodsb			; Get the real character.
	dec cx			; Decrement # chars in packet
	mov ah,80H		; Turn on 8-bit quot char flag. [21b end] 
decod3: cmp al,trans.squote	; Is it the quote char? [21b] [21c]
	jne decod4		; If not proceed.
	lodsb			; Get the quoted character
	dec cx			; Decrement # of chars in packet.
	or ah,al		; save parity (combine with prefix)
	and ah,80h		; only parity
	and al,7FH		; Turn off the parity bit.
	cmp al,trans.squote	; Is it the quote char? [21c]
	je decod4		; If so just go write it out.
	cmp al,dh		; This the 8-bit quot char?
	je  decod4		; If so, just go write it out
	cmp al,rptq		; Is is the repeat quote character?
	je decod4		; If so, just write it out.
	add al,40H		; Make it a control char again.
	and al,7FH		; Modulo 128.
decod4: or al,ah		; or in parity
	stosb			; store the character
	dec rptct		; Repeat counter.
	cmp rptct,0		; Write out char again?
	jg dcod41
	jmp decod1		; No, get next char.
dcod41:	mov rptval,al		; Save the char.
	jmp dcod11		; and loop to next char.
decod5:	pop bx
	pop dx			; dx is pushed twice (really)
	pop cx
	pop dx
	pop es
	pop di
	pop si
	ret
decod6:	mov bufpnt,di
	pop dx
	pop es
	pop di
	pop si
	jmp rskp		; Return successfully if done.



	; output the buffer, reset bufpnt and chrcnt
 
outbuf: cmp flags.xflg,1	; Writing to screen? [21c] 
	je outbf2		; Yes, handle specially. [21c] 
	push bx
	mov ah,writef		; The write code.
	mov dx,offset fcb
	int dos			; Write the record.
	pop bx
	cmp al,0		; Successful.
	jz outbf1
	push ax			; Remember the return code. [20d]
	call abfil		; Fix things up before aborting. [20d]
	pop ax			; Retrive return code. [20d]
	cmp al,01
	jz outbf0
	call erpos
	mov ah,prstr
	mov dx,offset erms17	; Record length exceeds dta.
	int dos
	ret
outbf0: call erpos
	mov ah,prstr		; Tell about it.
	mov dx,offset erms11	; Disk full error.
	int dos
	ret
outbf1:	add tfilsz+2,80H	; Say 128 more characters received.
	adc tfilsz,0
	call kbpr		; Print the kilobytes received.
	call perpr		; Print the percent ('?' for now).
outb11:	mov bufpnt,offset buff	; Addr for beginning.
	mov chrcnt,dmasiz-1	; Buffer size.
	jmp rskp
outbf2:	mov cx,dmasiz-1		; Number of chars to write. [21c]
	sub cx,chrcnt		; minus # of unused in buffer
	jle outb11		; none to print, don't try
	mov di,offset buff	; Where they are. [21c]
	call prtscr		; Output buffer to screen. [21c]
	jmp outb11		; Reset counter & pointer. [21c]

;  Tidy up before aborting.	[20d]
ABFIL	PROC	NEAR
	mov flags.xflg,1	; Writing to screen?
	je abfil0		; Yes don't delete "file".
	mov ah,closf		; Close the file.
	mov dx,offset fcb
	int dos
	cmp flags.abfflg,1	; Delete what got across or keep it?
	jne abfil0		; Nope, keep it.
	mov ah,delf		; Delete it.
	mov dx,offset fcb
	int dos
abfil0:	mov bx,offset erms10	; Text of message to send.
	call errpack		; Send an error packet.
	ret
ABFIL	ENDP

; General routine for sending an error packet.  Register BX should
; point to the text of the message being sent in the packet. [20f]

ERRPACK	PROC	NEAR
	mov di,offset data	; Where to put the message.
	mov al,0
errp1:	mov ah,[bx]
	cmp ah,'$'		; At end of message?
	je errp2
	inc al			; Remember number of chars in msg.
	mov [di],ah
	inc bx
	inc di
	jmp errp1
errp2:	mov ah,0
	mov pack.argbk1,ax
	mov ah,'E'		; And send an error packet.
	call spack
	 ret			; Return if succeed or fail.
	nop
	nop
	ret
ERRPACK	ENDP

;	Get the chars from the file.
 
gtchr:  cmp flags.filflg,0	; Is there anything in the DMA?
	jz gtchr0		; Yup, proceed.
	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 inbuf
	 jmp gtchr1		; No more chars, go return EOF.
	 nop			; Make three bytes long.
gtchr0:	mov bx,offset inbuf
	jmp encode
gtchr1:	mov ax,0ffffh
	ret

; encode - writes data portion of kermit packet into filbuf.
; expects BX to contain the address of a routine to refill the buffer,
; chrcnt to be the # of chars in the buffer, trans.maxdat to contain
; the maximum size of the data packet, bufpnt to contain a pointer to
; the source of the characters.
; Returns: AX/ the number of characters actually written to the buffer.

encode:	mov cl,trans.maxdat	; Maximum packet size. [21b]
	mov ch,0
	mov di,offset filbuf	; Where to put the data.
	mov si,bufpnt		; pointer into source buffer
	mov dl,trans.rquote	; send quote char
	mov dh,0		; assume no 8-bit quoting
	cmp trans.ebquot,'N'	; not doing 8-bit quoting
	je encod1
	cmp trans.ebquot,'Y'	; or can but won't?
	je encod1
	mov dh,0ffh		; remember we have to do it
encod1: dec cx			; Decrement output buffer counter.
	jge encod2		; Go on if there is more than one left.
	sub di,offset filbuf
	mov ax,di
	mov bufpnt,si		; update pointer into DMA.
	jmp rskp
encod2: cmp chrcnt,0		; Any data in buffer?
	jg encod3		; yes, skip over buffer refill.
	call bx			; Get another buffer full.
	 jmp encod8
	mov si,bufpnt		; update position in DMA.
	cmp chrcnt,0 		; no characters returned?
	jne encod3		; Got some, keep going.
	jmp encod8		; none, assume eof.
encod3: dec chrcnt		; Decrement input count.
	lodsb
        cmp flags.eofcz,0       ; Is a control-z an end of file? [27b]
        je encd30               ; No, don't have to look for one. [27b]
        cmp al,'Z'-40H          ; Is this a control-Z? [27b]
        jne encd30              ; No, skip eof-processing. [27b]
        mov flags.eoflag,0FFH   ; Yes, set eof flag. [27b]
        jmp encod8              ; Go set character count and return. [27b]
encd30: cmp rptq,0		; Are we doing repeat prefixing? 
	je encd3x		; Nope, skip next part.
	cmp chrcnt,0		; Are we on the last character?
	jle encd31		; Yes, so there's no next character.
	cmp rptct,94		; Max number that we can put in a byte.
	je encd31		; Then that's it.
	mov ah,[si]		; Get the next character.
	cmp al,ah		; Is current char == next char?
	jne encd31
	inc rptct		; Number of times char appears.
	mov rptval,al		; Remember the character.
	inc cx			; Repeats don't take up so much buffer space.
	jmp encod1		; Keep checking for more.
encd31:	cmp rptct,1		; Were previous characters repeats?
	je encd3x		; No, so just add this char.
	cmp rptct,rptmin	; Are we within bounds for repeat prefixing?
	jge encd32		; Yes, use repeat prefixing.
	mov al,rptct
	mov ah,0
	sub si,ax		; Not enough characters to warrant it.
	mov rptval,0		; Clear out this value.
	inc cx			; Adjust output buffer pointer.
	mov al,rptq
	mov origr,al		; Save original repeat prefix.
	mov rptq,0		; Pretend we're not doing the prefixing.
	mov al,rptct
	mov ah,0
	add chrcnt,ax		; Adjust input buffer pointer.
	jmp encod1		; Reprocess those characters.
encd32:	push ax			; Do repeat prefixing - save data.
	mov al,rptq		; Add repeat prefix char.
	stosb
	dec cx			; Account for it in buffer size.
	mov al,rptct		; Get the repeat count.
	add al,20H		; Make it printable.
	stosb			; Add to buffer.
	dec cx
	pop ax			; Get back the actual character.
	mov rptct,1		; Reset repeat count.
	mov rptval,0		; And this.
encd3x:	cmp dh,0		; are we doing 8-bit quoting?
	je encod4		; no, forget this.
	test al,80h		; parity on?
	je encod4		; no, don't bother with this
	and al,7fh		; turn off parity
	push ax			; save original char for a bit
	dec cx			; decrement # of chars left
	mov al,trans.ebquot	; get quote char
	stosb			; save in buffer
	pop ax			; restore character
encod4:	mov ah,al		; save character
	and ah,80h		; only parity
	and al,7fh		; turn off parity in character
	cmp al,' '		; Compare to a space.
	jl encod5		; If less then its a control char.
	cmp al,del		; Is the char a delete?
	jz encod5		; Go quote it.
	cmp al,dl		; Is it the quote char?
	je encod6		; Yes - go add it. [21b start]
	cmp dh,0		; are we doing 8-bit quoting?
	je encd41		; no, don't translate it
	cmp al,trans.ebquot	; Is it the 8-bit quote char?
	je encod6		; Yes, just output with quote
encd41:	cmp origr,0		; Doing repeat prefixing?
	je encod7		; No, don't check for quote char.
	cmp al,origr		; Is this the repeat quote character.
	je encod6		; Yes, then quote it.
	jmp short encod7	; else don't quote it.
encod5:	add al,40h		; control char, uncontrollify
	and al,7fh
encod6:	push ax			; save the char
	dec cx
	mov al,dl
	stosb
	pop ax
encod7:	or al,ah		; put parity back
	stosb
	cmp rptct,1		; One occurence of this char?
	jne encd7x
	mov al,origr
	mov rptq,al		; Restore repeat quote char.
	jmp encod1		; Yes, so loop around for some more.
encd7x:	dec rptct		; Add another entry of this char.
	jmp encod1		; With quoting and all.
 
encod8: sub di,offset filbuf
	or di,di
	je encod9		; Nope.
	mov ax,di
	jmp rskp
encod9: mov ax,0FFFFH		; Get a minus one.
	ret


inbuf:  mov ah,flags.eoflag	; Have we reached the end?
	cmp ah,0
	jz inbuf0
	ret			; Return if set.
inbuf0:	push si
	push di
	push dx
	push bx			
	push cx
	mov bx,offset buff	; Set the r/w buffer pointer.
	mov bufpnt,bx
	mov ah,readf		; Read a record.
	mov dx,offset fcb
	int dos
	mov cx,filsiz
	cmp cx,0		; Check for 128 chars or less left.
	jne inbuf1		; Still have data left.
	mov ax,ds
	mov es,ax
	mov si,offset filsiz+2
	mov di,offset bufhex
	cmps filsiz+2,es:bufhex
	ja inbuf1		; More than 128 chars.
	mov flags.eoflag,0FFH	; Set End-of-file.
	mov cx,filsiz+2
	mov chrcnt,cx		; Return proper number of chars.
	mov flags.filflg,0	; Buffer not empty.
	pop cx
	pop bx
	pop dx
	pop di
	pop si
	jmp rskp
inbuf1:	sub filsiz+2,80H	; Sent another 128 chars.
	sbb filsiz,0		; Account for the doubleword.
	add tfilsz+2,80H	; Book keeping for the same.
	adc tfilsz,0
	push ax
	call kbpr		; Print the kilobytes sent.
	call perpr		; Print the percent sent.
	pop ax
	mov al,80H		; Use as counter for number of chars read.
	pop cx
	pop bx
	pop dx
	pop di
	pop si
	mov ah,0		; Zero the flag (buffer not empty).
	mov chrcnt,ax		; Number of chars read from file.
	mov flags.filflg,0	; Buffer not empty.
	jmp rskp

nulref:	mov chrcnt,0		; No data to return.
	jmp rskp

nulr:	ret

; Print the number of Kilobytes transferred.

kbpr:	cmp flags.remflg,0	; remote mode?
	jne kbpr1		; yes, no printing.
	mov ax,tfilsz+2
	mov bx,tfilsz
	mov cl,10
	shr ax,cl		; divide by 1024
	mov cl,6		; high order moves 16-10 = 6 bits
	shl bx,cl
	or ax,bx
	cmp ax,oldkbt		; is it the same?
	je kbpr1		; yes, skip printing
	mov oldkbt,ax		; save new # of kb
	push ax
	call kbpos		; Postion the cursor.
	pop ax
	call nout		; Print the number of KBytes transferred.
kbpr1:	ret

; Print the percent transferred.

perpr:	cmp flags.remflg,0	; remote mode?
	jne perpr5		; yes, no printing.
	mov ax,tfilsz
	or ax,tfilsz+2
	cmp ax,oldper		; same as it was before?
	je perpr5		; yes, don't bother printing.
	mov oldper,ax		; remember this for next time
	cmp ofilsz,0		; No divide by zeroes.
	je perpr5		; If not proceed.
	cmp wrpmsg,0		; did we write the percentage message?
	jne perpr1		; yes, skip this part
	call perpos		; position cursor
	mov dx,offset permsg
	mov ah,prstr
	int dos			; write out message
	mov wrpmsg,1		; init flag so we don't do it again
perpr1:	call perpos		; Position the cursor.
perpr2:	mov dx,tfilsz		; Get the high order word.
	mov ax,tfilsz+2		; Get the low order word.
	div ofilsz		; Div by percent adjusted original file size.
	cmp ax,100		; > 100% ?
	jle perpr3		; no, accept it
	mov ax,100		; else just use 100
perpr3:	call nout
	mov dl,'%'		; Load a percent sign.
perpr4:	mov ah,conout		; Print the character.
	int dos
perpr5:	ret

getfil: mov ah,0FFH
	mov flags.filflg,ah	; Nothing in the DMA.
	mov ax,0
	mov flags.eoflag,ah	; Not the end of file.
	mov bx,offset fcb+0CH
	mov [bx],ax		; Zero the current block number.
	mov bx,offset fcb+0EH
	mov [bx],ax		; Ditto for Lrecl.
	mov bx,offset fcb+20H
	mov [bx],ah		; Zero the current record (of block).
	inc bx
	mov [bx],ax		; Same for record (of file). 
	mov bx,offset fcb+23H
	mov [bx],ax
	mov ah,openf		; Open the file.
	mov dx,offset fcb
	int dos
	mov dx,word ptr fcb+18	; get file size (hi order word)
	mov filsiz,dx
	mov ax,word ptr fcb+16	; lo order word
	mov filsiz+2,ax
	div percnt		; Divide by 100.
	mov ofilsz,ax
	mov tfilsz,0		; Set bytes sent to zero.
	mov tfilsz+2,0
	mov oldkbt,-1
	mov oldper,-1
	cmp filsiz,0		; Null file?
	jne getfl0		; Nope.
	cmp filsiz+2,0		; Null file?
	jne getfl0		; Nope.
	mov flags.eoflag,0FFH	; Set EOF.
getfl0:	jmp rskp


gtnfil: cmp flags.cxzflg,'Z'	; Did we have a ^Z? [20b]
	je gtn5			; If yes, we're done sending files. [20b]
	cmp flags.wldflg,0	; Was there a "*"?		[7 start]
	je gtn5			; Nope.
	mov bx,offset cpfcb	; Get FCB from last check for file.  
	mov di,offset fcb	; Copy to FCB.
	mov cl,37		; Size of FCB.
	call fcbcpy
gtn2:	mov ah,snext
	mov dx,offset fcb	; More files?
	int dos
	cmp al,0FFH
	je gtn5
	mov bx,offset fcb
	mov di,offset cpfcb
	mov cl,37
	call fcbcpy		; Copy from FCB.
	mov di,offset fcb+1	; Get name of next file to send.
	mov bx,offset buff+1
	mov cl,11
	call fcbcpy
	call getfil		; Initialize
	 jmp r
	jmp rskp			
gtn5:	mov flags.wldflg,0	; Reset wild card flag.
	ret			 			;  [7 end]


;	Get the file name (including host to micro translation)
 
gofil:  cmp flags.xflg,1	; Remote command? [21c]
	jne goflx		; No.... [21c]
	jmp gofla		; Yes so skip this stuff. [21c]
goflx:	cmp flags.nmoflg,1	; Overriding name from other side? [21a]
	jne gofil0		; No - get the filename. [21a]
	jmp gofil7		; Yes, so ignore packet contents. [21a]
gofil0:	mov bx,offset data	; Get the address of the file name. [21a]
	mov fdtpnt,bx		; Store the address.
	mov bx,offset fcb+1	; Address of the FCB.
	mov fcbptr,bx		; Save it.
	mov ax,0
	mov temp1,ax		; Initialize the char count.
	mov temp2,ax
	cmp flags.droflg,1	; Default drive? [21a]
	je gofil1		; No - don't blank out value in FCB. [21a]
	mov si,offset fcb
	mov [si],ah		; Set the drive to default to current.
gofil1: mov ch,' '		; Moved the label. [21a]
	mov [bx],ch		; Blank the FCB.
	inc bx
	inc ah
	cmp ah,0BH		; Twelve?
	jl gofil1
gofil2: mov bx,fdtpnt		; Get the NAME field.
	mov ah,[bx]
	inc bx
	mov fdtpnt,bx
	cmp ah,'.'		; Seperator?
	jne gofil3
	mov bx,offset fcb+9H
	mov fcbptr,bx
	mov ax,temp1
	mov temp2,ax
	mov temp1,9H
	jmp gofil6
gofil3: cmp ah,0		; Trailing null?
	jz gofil7		; Then we're done.
	call verlet		; Verify that the char is legal. 
	mov bx,fcbptr
	mov [bx],ah
	inc bx
	mov fcbptr,bx
	mov ax,temp1		; Get the char count.
	inc ax
	mov temp1,ax
	cmp ax,8H		; Are we finished with this field?
	jl gofil2
gofil4: mov temp2,ax
	mov bx,fdtpnt
	mov ah,[bx]
	inc bx
	mov fdtpnt,bx
	cmp ah,0
	jz gofil7
	cmp ah,'.'		; Is this the terminator?
	jne gofil4		; Go until we find it.
gofil6: mov bx,fdtpnt		; Get the TYPE field.
	mov ah,[bx]
	inc bx
	mov fdtpnt,bx
	cmp ah,0		; Trailing null?
	jz gofil7		; Then we're done.
	call verlet		; Verify that the char is legal. 
	mov bx,fcbptr
	mov [bx],ah
	inc bx
	mov fcbptr,bx
	inc temp1		; Increment char count.
	cmp temp1,0CH		; Are we finished with this field?
	jl gofil6
gofil7:	cmp flags.remflg,0	; remote mode?
	jne gofil7a		; yes, don't print it.
	call prtfn		; Print the file name. [21a]
gofil7a:cmp flags.destflg,0	; Writing to the printer?
	jne gf7y
	push es
	mov ax,ds
	mov es,ax		; Set this up.
	mov cx,11
	mov si,offset printer
	mov di,offset fcb
	repne movsb		; Change name in FCB to be printer.
	pop es
	jmp gofil9
gf7y:	mov ah,flags.flwflg	; Is file warning on?
	cmp ah,0
	jnz gf7x
	jmp gofil9		; If not, just proceed.
gf7x:	mov ah,openf		; See if the file exists.
	mov dx,offset fcb
	int dos
	cmp al,0FFH		; Does it exist?
	jnz gf8x
	jmp gofil9		; If not create it.
gf8x:	cmp flags.remflg,0	; remote mode?
	jne gf8xa		; yes, skip printing
	call frpos		; Position cursor. 
	mov ah,prstr		; Inform the user we are renaming the file.
	mov dx,offset infms5
	int dos
gf8xa:	mov ax,temp2		; Get the number of chars in the file name.
	cmp ax,0
	jne gofil8
	mov ax,temp1
	mov temp2,ax
gofil8: mov ch,0
	mov cl,al
	mov al,0		; Says if first field is full.
	cmp cl,9H		; Is the first field full?
	jne gofl81
	mov al,0FFH		; Set a flag saying so.
	dec cl
gofl81: mov bx,offset fcb	; Get the FCB.
	add bx,cx		; Add in the character number.
	mov ah,'&'
	mov [bx],ah		; Replace the char with an ampersand.
	push ax
	push bx
	mov ah,openf		; See if the file exists.
	mov dx,offset fcb
	int dos
	pop bx
	cmp al,0FFH		; Does it exist?
	pop ax
	jz gofl89		; If not create it.
	cmp al,0		; Get the flag.
	jz gofl83
	dec cl			; Decrement the number of chars.
	cmp cl,0
	jz gofl88		; If no more, die.
	jmp gofl81
gofl83: inc cl			; Increment the number of chars.
	cmp cl,9H		; Are we to the end?
	jl gofl81		; If not try again ; else fail. 
 
gofl88:	cmp flags.remflg,0	; remote mode?
	jne gofl88a		; yes, no printing
	call erpos		; Position cursor.
	mov ah,prstr		; Tell the user that we can't rename it.
	mov dx,offset ermes4
	int dos
gofl88a:mov bx,dx		; Tell host can't rename.  [20f]
	call errpack		; Send error packet before abort. [20f]
	ret
 
gofl89:	cmp flags.remflg,0	; remote mode
	jne gofil9		; yes, don't have to print it
	mov bx,offset fcb+0CH	; Point past the end of the file name.
	mov dh,[bx]		; Save the present contents.
	mov ah,'$'
	mov [bx],ah		; Put in a dollar sign.
	push dx
	mov ah,prstr		; Print the file name.
	mov dx,offset fcb+1
	int dos
	pop dx
	mov bx,offset fcb+0CH	; Restore over the dollar sign.
	mov [bx],dh
gofil9: mov ah,delf		; Delete the file if it exists.
	mov dx,offset fcb
	int dos
	mov ax,0
	mov si,offset fcb+0CH
	mov [si],ax		; Zero current block.
	mov si,offset fcb+0EH
	mov [si],ax		; Same for Lrecl.
	mov si,offset fcb+20H
	mov [si],ah		; Zero the current record (within block).
	inc si
	mov [si],ax		; Zero record (within file).
	mov si,offset fcb+23H
	mov [si],ax
	mov ofilsz,0		; File size unknown.
	mov tfilsz,0		; Set bytes received to zero.
	mov tfilsz+2,0
	mov oldkbt,-1
	mov oldper,-1
	mov ah,makef		; Now create it.
	mov dx,offset fcb
	int dos
	cmp al,0FFH		; Is the disk full?
	je gf9x
	jmp rskp
gf9x:	cmp flags.remflg,0	; remote mode?
	jne gf9xa		; yes, don't try printing
	call erpos		; Position cursor.
	mov ah,prstr		; If so tell the user.
	mov dx,offset erms12
	int dos
	mov bx,dx
gf9xa:	call errpack		; Send an error packet.
	ret
gofla:  cmp pack.argbk1,0	; Any data in "X" packet? [21c start]
	je gofla1		; Nothing to print. 
	mov ah,prstr
	mov dx,offset crlf
	int dos	
	int dos			; Print another crlf.
	mov di,offset data	; Where data is.
	mov cx,pack.argbk1	; How much data we have.
	call prtscr		; Print it on the screen.
gofla1:	mov ah,prstr
	mov dx,offset crlf
	int dos
	jmp rskp		; And done. [21c end]
FILEIO	ENDP

; Passed char of incoming filename in AH.  Verify that it is legal
; and if not change it to an "X".
verlet:	cmp ah,'0'
	jl ver2			; See if it's a legal weird char.
	cmp ah,'z'+1
	jns ver2
	cmp ah,'9'
	jle ver1		; It's between 0-9 so it's OK.
	cmp ah,'A'
	jl ver2			; Coud be a weird char.
	cmp ah,'Z'
	jle ver1		; It's A-Z so it's OK.
	cmp ah,'a'
	jl ver2
	and ah,137O		; It's a-z, capitalize.
ver1:	ret

ver2:	push es
	mov cx,ds
	mov es,cx		; Scan uses ES register.
	mov di,offset spchar	; Special chars.
	mov cx,spclen		; How many of them.
	cmp dosnum,0		; Under version 2.0
	je ver3
	mov di,offset spchar2
	mov cx,spc2len
ver3:	mov al,ah		; Char is in al.
	repnz scasb		; Search string for input char.
	pop es
	mov ah,al		; Return it in AH.
	cmp cx,0		; Was it there?
	jnz ver1		; Yes, return it.
	mov ah,'X'		; If illegal, replace with "X".
	mov flags.nmoflg,1
	ret

; Print incoming filename(s). [21a]
PRTFN	PROC	NEAR
	call clrfln		; Position cursor & blank out the line.
	mov di,offset data	; Where to put the name.
	mov bx,offset fcb	; Where it is now.
	cmp flags.droflg,0	; Drive specified?
	je prtfn1
	mov dl,[bx]		; Which one did they say?
	add dl,'@'		; Make it readable.
	mov ah,dconio		; Print the drive name. 
	int dos
	mov dl,':'
	int dos
prtfn1:	inc bx			; Point to start of filename.
	cmp flags.nmoflg,0	; Is filename in packet?
	je prtfn2		; no, keep going
	add di,pack.argbk1	; bump by length of remote name
	mov si,offset asmsg	; something to put after it
	mov cx,asmln		; length of it
	rep movsb		; add this to the buffer
prtfn2:	mov cx,8		; At most 8 letters in file name.
	mov si,bx		; this is source now
prtfn3:	lodsb			; get a letter
	cmp al,' '		; Done with name?
	je prtfn4		; yes, continue
	stosb			; else store
	loop prtfn3		; and loop thru rest
prtfn4: mov si,offset fcb+9	; Point to file type. 
	cmp byte ptr [si],' '	; is there a type?
	je prtfn5		; Nope so we're done.
	mov al,'.'		; Add the dot.
	stosb
	mov cx,3		; At most 3 letters in file type.
	rep movsb		; copy type (incl trailing spaces)
prtfn5:	mov byte ptr [di],'$'	; end the string
	mov ah,prstr		; Print the file name.
	mov dx,offset data
	int dos
	mov flags.droflg,0	; Reset flag once have the full name.
	mov flags.nmoflg,0
	ret
PRTFN	ENDP

; Print data onto the screen.  If text has no "$" in it, just print
; it.  Else, do special output for the "$".  
; Routine expects: DI = Start of buffer we are to print.
;		   CX = Number of characters to print.	 [21c]

PRTSCR	PROC	NEAR
	mov al,'$'		; This is what we're looking for.
	mov oloc,di		; Remember original buffer address. 
	mov osiz,cx		; And original size. 
	push es
	mov bx,ds
	mov es,bx		; Have ES point to data area.
prts0:	repnz scasb		; Search for "$" in the buffer.
	cmp cx,0		; Found one?
	je prts1		; No, do a regular DOS call.
	mov ah,prstr
	mov dx,oloc		; Print up to the "$". 
	int dos
	mov ah,dconio
	mov dl,'$'
	int dos			; Print the "$"
	mov oloc,di		; New starting location.
	mov osiz,cx		; New size.
	jmp prts0
prts1:	mov bx,oloc		; The buffer location.
	add bx,osiz		; Point past the data.
	mov [bx],al		; Add "$" for printing.
	mov ah,prstr
	mov dx,oloc
	int dos
	pop es
	ret
PRTSCR	ENDP

FIXFCB  PROC	NEAR	
	push ax			; Don't forget this.  [22]
	mov bx,offset fcb+18
	mov di,offset filsiz
	mov ax,[bx]
	mov [di],ax
	mov bx,offset fcb+16
	mov ax,[bx]
	mov 2[di],ax
	pop ax			; Get number of chars in last buffer full. [22]
	sub filsiz+2,ax		; Get real file size.
	sbb filsiz,0
	mov bx,offset fcb+18
	mov di,offset filsiz
	mov ax,[di]
	mov [bx],ax
	mov bx,offset fcb+16
	mov ax,2[di]
	mov [bx],ax
	ret
FIXFCB	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
