	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

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
	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:	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 init		; Clear line and initialize buffers.
	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,0	; No retries yet.
	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:	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 serrst		; Reset port. 
	mov ah,curchk
	mov trans.chklen,ah	; Restore value.
	jmp rskp		; Go home.
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 rpack5		; Get ACK (w/o screen stuff).
	 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	; "Get" as vs "Receive".
	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.
	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.
ipk0:   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 rpack5             ; 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?
        je ipk0                 ; Yes, try again.
	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. 
input0:	mov ah,conin		; Read in a char.
	int dos
	cmp al,CR		; Done with input?
	jne input1
	mov ah,cl		; Return count in AH.
	jmp r
input1:	cmp al,BS		; Backspace?
	je inpt11		; 
	cmp al,DEL		; Or delete?
	jne input3
	call dodel		; Erase weird character.
inpt11:	dec cl			; Don't include in char count. 
	cmp cl,0		; Backspaced too much? 
	jns input2		; No, is OK.
	push bx
	call clearl
	pop bx	
	mov ah,conout
	mov dl,bell
	int dos
	mov cl,0
	jmp input0
input2:	dec bx			; 'Remove' from buffer.
	mov ah,prstr	
	mov dx,offset clrspc
	int dos
	jmp input0		; Go get more.
input3:	cmp al,'U'-64		; Control-U?
	jne input4
	mov ah,prstr
	mov dx,offset pass+1
	int dos	
	push bx
	push cx
	call clearl		; Blank out the line. 
	pop cx
	pop bx
	mov cl,0		; Reset count to zero.
	mov bx,inpbuf		; Start at head of buffer.
	jmp input0
input4:	cmp al,0		; Two character sequence?
	jne input5
	mov ah,conin
	int dos			; Get second char.
	cmp al,83		; Delete key?
	je inpt40		; Yup. 
	cmp al,75		; Backarrow key?
	je inpt40
	call dodel		; Erase weird character.
	jmp input0		; And go on computing.
inpt40:	mov ah,prstr
	mov dx,offset delinp	; Erase weird character. 
	int dos
	jmp inpt11		; Remove the offending char.
input5: 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
