; Edit history:
;
; [v2.28]
; Clear screen before trying to get init packet in GET, so we don't
; print an error message in the middle of an uninitialized screen
; if the packet never comes. (From Edgar Butt, Univ. of Md.)
; JD 1 May 1985

	public	logout, bye, finish, remote, get, server
	include	msdefs.h

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

remcmd	db	0		; Remote command to be executed. [21c]
rempac	db	0		; Packet type: C (host) or G (generic). [21c] 

cmer05	db	cr,lf,'?Filename must be specified$'	 ; [21a]
ermes7  db	'?Unable to receive initiate$'
erms18	db	cr,lf,'?Unable to tell host that session is finished$'
erms19	db	cr,lf,'?Unable to tell host to logout$'
erms21  db	cr,lf,'?Unable to tell host to execute command$' ; [21c]
infms1	db	'Entering server mode',cr,lf,'$'
remms1	db	'Kermit-MS: Unknown server command$'
remms2	db	'Kermit-MS: Illegal file name$'
remms3	db	'Kermit-MS: Unknown generic command$'
pass	db	lf,cr,' Password: $' 	; When change directory. [21c]
crlf	db	cr,lf,'$'
tmp	db	?,'$'
temp	dw	0
oloc	dw	0		; Original buffer location. [21c]
osiz	dw	0		; Original buffer size. [21c]
inpbuf	dw	0		; Pointer to input buffer. [21c]
cnt	dw	0
delinp	db	BS,BS,BS,'   ',BS,BS,BS,'$'	; When DEL key is used. [21d]
clrspc  db	' ',10O,'$'		; Clear space.

srvchr	db	'SRGIE'		; server cmd characters
srvfln	equ	$-srvchr	; length of tbl
srvfun	dw	srvsnd,srvrcv,srvgen,srvini,serv1

remhlp	db	cr,lf,'CWD connect to a directory'	; [21c start]
	db	cr,lf,'DELETE a file'
	db	cr,lf,'DIRECTORY listing'
	db	cr,lf,'HELP'
	db	cr,lf,'HOST command'
	db	cr,lf,'SPACE in a directory'
	db	cr,lf,'TYPE a file$'			; [21c end]

remtab	db	07H		; Seven entries. [21c start]
	mkeyw	'CWD',remcwd
	mkeyw	'DELETE',remdel
	mkeyw	'DIRECTORY',remdir
	mkeyw	'HELP',remhel
	mkeyw	'HOST',remhos
	mkeyw	'SPACE',remdis
	mkeyw	'TYPE',remtyp		; [21c end]

remfnm	db	' Remote Source File: $'
lclfnm	db	' Local Destination File: $'
filhlp	db	' File name to receive as$'
filmsg	db	' Remote file specification or confirm with carriage return $'
frem	db	' Name of file on remote system $'
genmsg	db	' Enter text to be sent to remote server $'
rdbuf	db	80H DUP(?)
datas	ends

code	segment	public
	extrn comnd:near, serrst:near, spack:near, rpack5:near, init:near
	extrn read12:near, serini:near, read2:near, rpar:near, spar:near
	extrn rin21:near, rfile3:near, error1:near, clrfln:near
	extrn dodel:near, clearl:near, dodec: near, doenc:near
	extrn packlen:near, send11:near, errpack:near, init1:near
	extrn rpack:near,nak:near, rrinit:near, cmblnk:near
	extrn error:near, erpos:near, rprpos:near, clrmod:near
	extrn prompt:near, updrtr:near, cmgetc:near
	assume	cs:code,ds:datas

; LOGOUT - tell remote KERSRV to logout.

LOGOUT	PROC	NEAR
	mov ah,cmcfm
	call comnd		; Get a confirm.
	 jmp r
	call logo
	 jmp rskp		; Go get another command whether we ....
	jmp rskp		; .... succeed or fail.
LOGOUT	ENDP

LOGO	PROC	NEAR
	mov pack.numtry,0	; Initialize count.
	mov pack.numrtr,0	; No retries yet.
	call serini		; Initialize port.  [14]
	mov ah,trans.chklen	; Don't forget the checksum length.
	mov curchk,ah
	mov trans.chklen,1	; Use one char for server functions.
logo1:	cmp pack.state,'A'	; Did user type a ^C?
	je logo2x		; Yes just leave.
	mov ah,pack.numtry
	cmp ah,maxtry		; Too many times?
	js logo3		; No, try it.
logo2:	mov ah,prstr
	mov dx,offset erms19
	int dos
logo2x:	call serrst		; Reset port.  [14]
	mov ah,curchk
	mov trans.chklen,ah	; Restore value.
	ret
logo3:	inc pack.numtry		; Increment number of tries.
	mov pack.argblk,0	; Packet number zero.
	mov pack.argbk1,1	; One piece of data.
	mov bx,offset data
	mov ah,'L'
	mov [bx],ah		; Logout the remote host.
	mov cx,1		; One piece of data.
	call doenc		; Do encoding.
	mov ah,'G'		; Generic command packet.
	call spack
	 jmp logo2		; Tell user and die.
	 nop
	call rpack5		; Get ACK (w/o screen msgs.)
	 jmp logo1		; Go try again.
	 nop
	push ax
	call dodec		; Decode packet.
	mov ah,curchk
	mov trans.chklen,ah	; Restore value.
	pop ax
	cmp ah,'Y'		; ACK?
	jne logo4
	call serrst		; Reset port.  [14]
	jmp rskp
logo4:	cmp ah,'E'		; Error packet?	
	jnz logo1		; Try sending the packet again.
	call error1
	call serrst		; Reset port.  [14]
	ret
LOGO	ENDP

; FINISH - tell remote KERSRV to exit.

FINISH	PROC	NEAR
	mov ah,cmcfm		; Parse a confirm.
	call comnd
	 jmp r
	mov pack.numtry,0	; Initialize count.
	mov pack.numrtr,0	; No retries yet.
	call serini		; Initialize port.  [14]
	mov ah,trans.chklen	; Don't forget the checksum length.
	mov curchk,ah
	mov trans.chklen,1	; Use one char for server functions.
fin1:	cmp pack.state,'A'	; ^C typed?
	je fin2x
	mov ah,pack.numtry
	cmp ah,maxtry		; Too many times?
	js fin3			; Nope, try it.
fin2:	mov ah,prstr
	mov dx,offset erms18
	int dos
fin2x:	call serrst		; Reset port.  [14]
	mov ah,curchk
	mov trans.chklen,ah	; Restore value.
	jmp rskp		; Go home.
fin3:	inc pack.numtry		; Increment number of tries.
	mov pack.argblk,0	; Packet number zero.
	mov pack.argbk1,1	; One piece of data.
	mov bx,offset data
	mov ah,'F'
	mov [bx],ah		; Finish running Kermit.
	mov cx,1		; One piece of data.
	call doenc		; Do encoding.
	mov ah,'G'		; Generic command packet.
	call spack
	 jmp fin2		; Tell user and die.
	 nop
	call rpack5		; Get ACK (w/o screen stuff).
	 jmp fin1		; Go try again.
	 nop
	push ax
	call dodec		; Decode data.
	mov ah,curchk
	mov trans.chklen,ah	; Restore value.
	pop ax
	cmp ah,'Y'		; Got an ACK?
	jnz fin4
	call serrst		; Reset port. [14]
	jmp rskp		; Yes, then we're done.
fin4:	cmp ah,'E'		; Error packet?
	jnz fin1		; Try sending it again.
	call error1
	call serrst		; Reset port.  [14]
	jmp rskp
FINISH	ENDP

; BYE command - tell remote KERSRV to logout & exits to DOS.  

BYE	PROC	NEAR
	mov ah,cmcfm		; Parse a confirm.
	call comnd
	 jmp r
	call logo		; Tell the mainframe to logout.
 	 jmp rskp		; Failed - don't exit.
	mov flags.extflg,1	; Set exit flag.
	jmp rskp					; [8 end]
BYE	ENDP

; Tell remote server to send the specified file(s).

get	PROC	NEAR
	mov flags.droflg,0	; Reset flags from fn parsing.
	mov flags.nmoflg,0	; Reset flags from fn parsing.
	mov flags.cxzflg,0	; no ctl-c typed yet...
	mov bx,offset rdbuf	; Where to put text.  [8 start]
	mov dx,offset filmsg	; In case user needs help.
	mov ah,cmtxt
	call comnd		; Get text or confirm.
	 jmp r			; Fail. 
	cmp ah,0		; Read in any chars?
	jne get4		; Yes, then OK.
; empty line, ask for file names
get1:	mov dx,offset remfnm	; ask for remote first
	call prompt
	mov bx,offset rdbuf
    	mov dx,offset frem
	mov ah,cmtxt
	call comnd		; get a line of text
	 jmp r
	cmp flags.cxzflg,'C'	; ctl-C typed?
	jne get2		; no, continue
	jmp rskp
get2:	cmp ah,0
	je get1			; ignore empty lines
	mov bl,ah
	mov bh,0
	mov byte ptr rdbuf[bx],'$' 	; terminate name for printing
	mov cnt,bx		; remember length here
	mov dx,offset lclfnm
	call prompt
	mov ah,cmifi
	mov bx,offset filhlp
	mov dx,offset fcb
	call comnd
	 jmp r
	mov ah,cmcfm
	call comnd
	 jmp r
	cmp flags.cxzflg,'C'	; control-C typed?
	jne get3		; no, keep going
	jmp rskp
get3:	mov flags.nmoflg,1	; remember changed name
	jmp short get5
get4:	mov al,ah
	mov ah,0
	mov cnt,ax		; Remember number of chars we read.
	mov byte ptr [bx],'$'	; use for printing.
get5:	cmp flags.destflg,2	; receiving to screen?
	je get5a		; yes, skip screen stuff
	mov flags.xflg,0	; no, reset x flag
	cmp flags.remflg,0	; in remote mode?
	jne get5a		; yes, don't print anything
	call init		; init screen
get5a:	call ipack		; Initialize.
	 jmp get8		; Sorry can't do it.
	 nop
	mov cx,cnt		; Get back filename size.
	mov pack.argbk1,cx	; Need it here to send packet.
	inc cx			; Don't forget "$" for printing.
	push es			; Prepare to put string into packet. 
	mov ax,ds
	mov es,ax
	mov si,offset rdbuf	; Move from here
	mov di,offset data	; to here.
	rep movsb		; Perform the string move.
	pop es
	cmp flags.remflg,0	; remote mode?
	jne get6		; yes, don't print anything
	cmp flags.destflg,2	; Receiving to screen? [27c]
	je get6			; Yes skip screen stuff. [27c]
	call clrfln		; Prepare to print filename.
	mov ah,prstr
	mov dx,offset data	; Print file name.
	int dos
get6:	call init1		; init buffers
	mov pack.numtry,0	; Initialize count.
	mov pack.numrtr,-1	; No retries yet (gets incremented below).
	mov pack.state,'R'	; this is what state will soon be...
	mov cx,pack.argbk1	; Data size.
	call doenc		; Encode data.
	mov ah,trans.chklen	; Don't forget the checksum length.
	mov curchk,ah
	mov trans.chklen,1	; Use one char for server functions.
get7:	call updrtr
	cmp pack.state,'A'	; Did user type a ^C?
	je get9			; Yes - just return to main loop.
	mov ah,pack.numtry
	cmp ah,maxtry		; Too many times?
	jbe get10		; Nope, try it.
get8:	cmp flags.remflg,0	; remote mode?
	jne get9		; yes, no printing
	call erpos
	mov ah,prstr
	mov dx,offset ermes7	; Can't get init packet. 
	int dos
get9:	call rprpos
	call clrmod
	call serrst		; Reset port. 
	mov ah,curchk
	mov trans.chklen,ah	; Restore value.
	jmp rskp
get10:	inc pack.numtry		; Increment number of tries.
	mov pack.argblk,0	; Start at packet zero.
	mov ah,'R'		; Receive init packet.
	call spack		; Send the packet.
	 jmp get8		; Tell user we can't do it.
	 nop
	call rpack		; Get ACK
	 jmp get7		; Got a NAK - try again.
	 nop
	push ax
	mov ah,curchk
	mov trans.chklen,ah	; Restore value.
	pop ax
	mov pack.argbk2,ax	; this is where rinit wants pkt type if getting
	mov flags.getflg,1	; note this is a get
	jmp read12		; go join read code
get11:	mov ah,prstr		; Complain if no filename. 
	mov dx,offset cmer05
	int dos
	jmp rskp
GET	ENDP

; server command

server	proc	near
	mov	ah,cmcfm
	call	comnd
	 jmp	r
	push	es
	mov	ax,ds
	mov	es,ax		; address data segment
	mov	al,flags.remflg	; get remote flag
	push	ax		; preserve for later
	mov	flags.remflg,1	; set remote if server
	call	cmblnk		; clear screen
	mov	ah,prstr
	mov	dx,offset infms1
	int	dos
; should reset to default parms here...
; should increase timeout interval
serv1:	call	serini		; init serial line (send & recv reset it)
	mov	trans.chklen,1	; checksum len = 1
	mov	pack.pktnum,0	; pack number resets to 0
	mov	pack.numtry,0	; no retries yet.
	call	rpack		; get a packet
	 jmp	short serv2	; no good, nak and continue
	 nop
	jmp	short serv3	; try to figure this out
serv2:	cmp	flags.cxzflg,'C' ; ctl-C?
	je	serv5		; yes, stop this.
	call	nak		; nak the packet
	jmp	serv1		; and keep readiserv2 packets

serv3:	mov	di,offset srvchr ; server characters
	mov	cx,srvfln	; length of striserv2
	mov	al,ah		; packet type
	repne	scasb		; hunt for it
	je	serv4		; we know this one, go handle it
	mov	bx,offset remms1 ; else give a message
	call	errpack		; back to local kermit
	jmp	serv1		; and keep lookiserv2 for a cmd
serv4:	sub	di,offset srvchr+1 ; find offset, +1 for pre-increment
	shl	di,1		; convert to word index.
	call	srvfun[di]	; call the appropriate handler
	 jmp	serv5		; someone wanted to exit...
; should we reset serial line?
	jmp	serv1		; else keep goiserv2 for more cmds.

serv5:
;** restore timer values
	pop	ax		; get this off stack
	mov	flags.remflg,al	; restore old flag
	call	serrst		; reset serial handler
	pop	es		; restore register
	jmp	rskp		; and return
server	endp

; server commands.

; srvsnd - receives a file that the local kermit is sending.
srvsnd	proc	near
	mov	bx,offset data
	call	spar		; parse the send-init packet
	call	packlen		; figure max packet
	mov	bx,offset data
	call	rpar		; make answer for them
	mov	al,ah		; length of packet
	mov	ah,0
	mov	pack.argbk1,ax	; store length for spack
	mov	ah,'Y'		; ack
	call	spack		; answer them
	 jmp	rskp		; can't answer, forget this
	call	rrinit		; init variables for init
	inc	pack.pktnum	; count the send-init packet.
	mov	pack.state,'F'	; expecting file name about now
	call	read2		; and join read code
	 nop
	 nop
	 nop			; ignore errors
	jmp	rskp		; and return for more
srvsnd	endp

; srvrcv - send a file that they're receiving.
srvrcv	proc	near
	mov	si,offset data	; this should be filename
	mov	di,offset fcb	; this is where filename goes
	mov	al,1		; skip leading separators
	mov	ah,prsfcb	; parse an fcb
	int	dos		; let dos do the work
	cmp	al,0ffh		; invalid?
	jne	srvrc1		; no, keep going
	mov	bx,offset remms2 ; complain
	call	errpack		; that we can't find it
	jmp	rskp		; and return
srvrc1:	mov	pack.state,'R'	; remember state.
	call	send11		; this should send it
	 jmp	rskp
	jmp	rskp		; return in any case
srvrcv	endp

; srvgen - generic server commands.
; We only support Logout and Finish right now.
srvgen	proc	near
	mov	al,data		; get 1st packet char
	cmp	al,'F'		; maybe finish?
	je	srvge1		; yup, handle
	cmp	al,'L'		; logout?
	jne	srvge2		; no.
srvge1:	mov	pack.argbk1,0	; 0-length data
	mov	ah,'Y'
	call	spack		; ack it
	 nop
	 nop
	 nop			; *** ignore error?
	ret			; and return to signal exit.
srvge2:	mov	bx,offset remms3
	call	errpack
	jmp	rskp
srvgen	endp

; srvini - init parms based on init packet
srvini	proc	near
	mov	bx,offset data
	call	spar		; parse info
	call	packlen		; this should really be part of spar, but...
	mov	bx,offset data
	call	rpar		; get receive info
	mov	al,ah
	mov	ah,0
	mov	pack.argbk1,ax	; set size of return info
	mov	ah,'Y'
	call	spack		; send the packet off
	 jmp	rskp
	jmp	rskp		; and go succeed
srvini	endp

;	This is the REMOTE command. [21c]

REMOTE	PROC	NEAR
	mov dx,offset remtab	; Parse a keyword from the REMOTE table.
	mov bx,offset remhlp
	mov ah,cmkey
	call comnd
	 jmp r
	call bx			; Call the appropriate routine.
	 jmp r			; Command failed.
	jmp rskp
REMOTE	ENDP

; REMDIS - Get disk usage on remote system. [21c]

REMDIS	PROC	NEAR
	mov remcmd,'U'		; Disk usage command.
	mov rempac,'G'		; Packet type = generic.
	jmp genric		; Execute generic Kermit command.
REMDIS	ENDP


; REMHEL - Get help about remote commands. [21c] 

REMHEL	PROC	NEAR
	mov remcmd,'H'		; Help......
	mov rempac,'G'		; Packet type = generic.
	jmp genric		; Execute generic Kermit command.
REMHEL	ENDP

; REMTYP - Print a remote file. [21c]

REMTYP	PROC	NEAR
	mov remcmd,'T'		; Type the file.
	mov rempac,'G'		; Packet type = generic.
	jmp genric
REMTYP	ENDP

; REMHOS - Execute a remote host command. [21c]

REMHOS	PROC	NEAR
	mov remcmd,' '		; Don't need one.
	mov rempac,'C'		; Packet type = remote command.
	jmp genric
REMHOS	ENDP

; REMDIR - Do a directory. [21c]

REMDIR	PROC	NEAR
	mov remcmd,'D'
	mov rempac,'G'		; Packet type = generic.
	jmp genric
REMDIR	ENDP

; REMDEL - Delete a remote file. [21c]

REMDEL	PROC	NEAR
 	mov remcmd,'E'
	mov rempac,'G'		; Packet type = generic.
	jmp genric
REMDEL	ENDP

; REMCWD - Change remote working directory.  [21c]

REMCWD	PROC	NEAR
	mov remcmd,'C'
	mov rempac,'G'		; Packet type = generic.
	jmp genric
REMCWD	ENDP

; GENRIC - Send a generic command to a remote Kermit server. [21c]

GENRIC	PROC	NEAR
	mov bx,offset rdbuf	; Where to put the text.
	cmp rempac,'C'		; Remote host command? 
	je genra		; Yes, leave as is. 
	add bx,2		; Leave room for type and size.
genra:	mov ah,cmtxt		; Parse arbitrary text up to a CR.
	mov dx,offset genmsg	; In case they want text.
	call comnd
	 jmp r
	mov al,ah		; Don't forget the size.
	mov ah,0
	mov cnt,ax		; Save it here.
	mov flags.xflg,1	; output coming to screen
	cmp rempac,'C'		; Remote host command? 
	jne genrb		; No, skip this part. 
	call ipack
	 jmp genr2
	mov pack.numtry,0
	mov ah,trans.chklen
	mov curchk,ah		; Save desired checksum length.
	mov trans.chklen,1	; Use 1 char for server functions.
	mov pack.numrtr,0	; No retries yet.
	jmp genr1		; Send the packet.
genrb:	mov ax,cnt
	cmp ax,0		; Any data?
	je genr0		; Nope.
	mov ah,al		; Don't overwrite the real count value.
	add ah,32		; Do the char function.
	mov temp,bx		; Remember where we are.
	mov bx,offset rdbuf+1	; Size of remote command.
	mov [bx],ah
	mov ah,0
	inc al			; For the size field.
	cmp remcmd,'C'		; Change working directory?
	jne genr0		; No, so don't ask for password.
	mov cnt,ax		; Save here for a bit.
	mov ah,prstr
	mov dx,offset pass	; Send along an optional password. 
	int dos
	mov bx,temp		; Where to put the password.
	push bx			; Is safe since subroutine never fails.
	inc bx			; Leave room for count field.
	call input		; Read in the password.
	mov temp,bx		; Remember end of data pointer.
	pop bx			; Where to put the size.
	cmp ah,0		; No password given?
	jne genrc
	mov ax,cnt
	jmp genr0		; Then that's it.
genrc:	mov al,ah
	add ah,32		; Make it printable.
	mov [bx],ah		; Tell remote host the size.
	mov ah,0
	push ax			; Remember the count.
	call clearl		; Clear to end-of-line.
	pop ax
	inc al			; For second count value.
	add ax,cnt		; Total for both fields of input.
genr0:	inc al			; For the char representing the command.
	mov pack.argbk1,ax	; Set the size.
	mov cnt,ax		; And remember it. 
	mov pack.numtry,0	; Initialize count
	mov bx,offset rdbuf	; Start of data buffer.	
	mov ah,remcmd		; Command subtype.
	mov [bx],ah
	call ipack		; Send init parameters.
	 jmp genr2
	 nop			; Make it 3 bytes long.
	mov ah,trans.chklen
	mov curchk,ah		; Save desired checksum length.
	mov trans.chklen,1	; Use 1 char for server functions.
	mov pack.numrtr,0	; No retries yet.
genr1:	cmp pack.state,'A'	; Did the user type a ^C?
	je genr2x
	mov ah,pack.numtry
	cmp ah,maxtry		; Too many tries?
	js genr3		; Nope, keep trying.
genr2:	mov ah,prstr
	mov dx,offset erms21	; Print error msg and fail.
	int dos
genr2x:	call serrst		; Reset the port.
	mov ah,curchk
	mov trans.chklen,ah	; Restore.
	jmp rskp
genr3:	push es			; Prepare to put string into packet. 
	mov ax,ds
	mov es,ax
	mov si,offset rdbuf	; Move from here
	mov di,offset data	; to here.
	mov cx,cnt		; Move this many characters.
	rep movsb		; Perform the string move.
	pop es
	mov ax,cnt
	mov pack.argbk1,ax	; How much data to send.
	mov cx,ax		; Size of data.
	call doenc		; Encode it.
	inc pack.numtry		; Increment number of trials.
	mov pack.argblk,0	; Packet number 0.
	mov ah,rempac		; Packet type.
	call spack		; Send the packet.
	 jmp genr2		; Tell user we can't do it.
	 nop
	call rpack5		; Get ACK (w/o screen stuff)
	 jmp genr1		; Got a NAK - try again.
	 nop
	push ax
	mov ah,curchk
	mov trans.chklen,ah	; Restore.
	pop ax
	cmp ah,'Y'		; Is all OK?
	jne genr4
	cmp pack.argbk1,0	; Any data in the ACK?
	je genr31		; Nope - just return. 
	call dodec		; Decode data.
	mov ah,prstr
	mov dx,offset crlf	; First go to a new line.
	int dos	
	mov di,offset data	; Where the reply is.
	mov cx,pack.argbk1	; How much data we have. 
	call prtscr		; Print it on the screen.
genr31:	jmp rskp		; And we're done. 
genr4:	cmp ah,'X'		; Text packet?
	je genr5
	cmp ah,'S'		; Handling this like a file?
	jne genr6
	mov pack.state,'R'	; Set the state.
	mov bx,offset rin21	; Where to go to.
	jmp genr51		; Continue.
genr5:	mov pack.state,'F'
	call dodec		; Decode data.
	mov bx,offset rfile3	; Jump to here.
genr51:	mov tmp,ah		; Save packet type.
	mov flags.xflg,1	; Remember we saw an "X" packet.
	mov pack.numtry,0
	mov pack.numrtr,0
	mov pack.numpkt,0
	mov pack.pktnum,0
	mov flags.cxzflg,0
	mov ah,tmp		; Packet type.
	call bx			; Handle it almost like filename.
	call read2		; Receive the rest.
	 jmp r			; Oops, we failed.
	jmp rskp		; Done OK.
genr6:	cmp ah,'E'		; Error packet?
	je genr6x		
	jmp genr1		; Try again.
genr6x: call dodec		; Decode data.
	call error1		; Print the error messge.
	call serrst
	jmp rskp		; And return.
GENRIC	ENDP

; Send "I" packet with transmission parameters. [21c]

IPACK	PROC	NEAR
	mov ah,trans.chklen
	mov curchk,ah		; Initialize.
	call serini
	mov pack.pktnum,0	; Use packet number 0.
	mov pack.numtry,0	; Number of retries.
	mov pack.numrtr,-1	; no retries (incremented below)
ipk0:	call updrtr
	cmp pack.state,'A'	; Did user type a ^C?
	je ipk0x
	cmp pack.numtry,imxtry  ; Reached our limit?
	jl ipk1
ipk0x:	ret			; Yes, so we fail. 
ipk1:	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 pack.argblk,0	; Use packet number 0.
	mov ah,trans.chklen
	mov curchk,ah		; Save real value.
	mov trans.chklen,1	; One char for server function.
	mov ah,'I'		; "I" packet.
	call spack		; Send the packet.
	 jmp ipk4
	 nop
	call rpack	       ; Get a packet.
	 jmp ipk4		; Try again.
	 nop
	push ax
	mov ah,curchk
	mov trans.chklen,ah	; Reset.
	pop ax
	cmp ah,'Y'		; ACK?
	jne ipk3		; If not try next.
	mov ax,pack.pktnum	; Get the packet number.
	cmp ax,pack.argblk	; Is it the right packet number?
	je ipk2
	 jmp ipk0		; If not try again.
ipk2:	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.
	mov ah,trans.chklen
	mov curchk,ah		; This is what we decided on.
	call packlen		; Get max send packet size. [21b] 
	mov pack.numtry,0	; Reset the number of tries.
	jmp rskp
ipk3:	cmp ah,'N'		; NAK?
	jne ipk3y		; Yes, try again.
	jmp ipk0
ipk3y:	cmp ah,'E'		; Is it an error packet.
	je ipk3x
	jmp ipk0		; Trashed data. 
ipk3x:	jmp rskp		; Other side doesn't know about "I" packet.
ipk4:	mov ah,curchk
	mov trans.chklen,ah	; Reset.	
	jmp ipk0		; Keep trying.
IPACK	ENDP

; Returns in AH the count of characters read in.
;	  in BX the updated pointer to the input buffer.

INPUT	PROC	NEAR
	mov cl,0		; Keep a count.	
	mov inpbuf,bx		; Where to put data. 
	mov comand.cmquiet,1	; turn on quiet mode
input0:	call cmgetc		; get a character nicely
	cmp al,CR		; Done with input?
	jne input1
	push cx			; save count
	mov ah,prstr
	mov dx,offset crlf
	int dos			; echo a carriage return
	pop cx
	mov ah,cl		; Return count in AH.
	mov comand.cmquiet,0	; turn off quiet mode
	jmp r
input1:	cmp al,BS		; Backspace?
	je inpt11		; 
	cmp al,DEL		; Or delete?
	jne input3
inpt11:	dec cl			; Don't include in char count. 
	cmp cl,0		; Backspaced too much? 
	jns input2		; No, is OK.
	mov ah,conout
	mov dl,bell
	int dos
	mov cl,0
	jmp input0
input2:	dec bx			; 'Remove' from buffer.
	jmp input0		; Go get more.
input3:	cmp al,'U'-64		; Control-U?
	jne input4
	mov cl,0		; Reset count to zero.
	mov bx,inpbuf		; Start at head of buffer.
	jmp input0
input4:	mov [bx],al		; Add char to buffer.
	inc cl			; Include in count.
	inc bx
	jmp input0
INPUT	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

; 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
