	PAGE 59, 132

	TITLE MSSERV -- Module to handle all Server functions

; Update 20 Jan 86

IF1
 %OUT >> Starting pass 1
ELSE
 %OUT >> Starting pass 2
ENDIF

    PUBLIC Logout, Bye, Finish, Remote, Get, Server, Enter_Server

    INCLUDE MsDefs.H

DataS	SEGMENT	PUBLIC 'DataS'

    EXTRN data:byte, flags:byte, trans:byte, pack:byte, curchk:byte
    EXTRN fcb:byte, Data_2:BYTE, CurDsk:BYTE

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

ermes7  DB 'Unable to Receive Initiate$'
erms18	DB '? Unable to tell host that session is finished',cr,lf,'$'
erms19	DB '? Unable to tell host to logout',cr,lf,'$'
erms21  DB '? Unable to tell host to execute command',cr,lf,'$' ; [21c]
erms70	DB '? Unable to send INIT (I) packet',cr,lf,'$'
infms1  DB cr,'              Server: Waiting for request$'
infms2  DB cr,'             Getting: Waiting for file$'
infms3  DB cr,'             Getting: Sending request to remote server$'
remms1	DB 'Remote '
	Program_name
	db ': Unknown server command$'
remms2	DB 'Remote '
	Program_name
	db ': Illegal file name$'
remms3	DB 'Remote '
	Program_name
	db ': Unknown generic server command$'
remms4  DB 'Remote '
	Program_name
	db ': Unable to change directories$'; [jrd]
pass	DB 'Password: $'	; When changing remote directories
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 ' ', Bs, '$'		; Clear space

srvchr	DB 'SRGIE'		; server cmd characters
srvfln	EQU $-srvchr		; length of tbl
srvfun	DW srvsnd,srvrcv,srvgen,srvini,RSkp

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 7
	mkeyw	'CWD',remcwd
	mkeyw	'DELETE',remdel
	mkeyw	'DIRECTORY',remdir
	mkeyw	'HELP',remhel
	mkeyw	'HOST',remhos
	mkeyw	'SPACE',remdis
	mkeyw	'TYPE',remtyp

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$'
SrvBuf	DB 80H DUP(?)

DataS	ENDS

Code	SEGMENT	PUBLIC

    EXTRN comnd:near, spack:near, RPack:near, init:near
    EXTRN 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, PrtScr:NEAR
    EXTRN packlen:near, send11:near, errpack:near, init1:near
    EXTRN NAK:NEAR, rrinit:near, Error:near, Prompt:NEAR, Read1:NEAR
    EXTRN Close_transfer_screen:NEAR, Show_retries:NEAR
    EXTRN Do_CXZ_mode_line:NEAR, Show_error:NEAR, Show_status:NEAR

    ASSUME cs:Code, ds:DataS

; LOGOUT - tell remote KERSRV to logout

LOGOUT	PROC
	mov ah,cmcfm
	call comnd		; Get a confirm
	 jmp r
	mov al, flags.remflg	; Pick up current value of remote flag
	push ax			; Save it
	mov flags.remflg, 1	; Force us into remote mode for LOGOUT command
	call logo
	 nop
	 nop
	 nop
	pop ax
	mov flags.remflg, al	; Restore original value
	jmp rskp
LOGOUT	ENDP

LOGO	PROC

	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:	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 SHORT logo2	;  Tell user and die
	 nop

	call RPack		; Get ACK (w/o screen msgs.)
	 jmp SHORT 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

	jmp rskp

logo4:	cmp ah,'E'		; Error packet?
	 jnz logo1		;  Try sending the packet again

	jmp error1

LOGO	ENDP


; FINISH - tell remote KERSRV to exit

FINISH	PROC
	mov ah,cmcfm		; Parse a confirm
	call comnd
	 jmp r

	mov al, flags.remflg	; Pick up current value of remote flag
	push ax			; Save it
	mov flags.remflg, 1	; Force us into remote mode for LOGOUT command

	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:	mov ah,curchk
	mov trans.chklen,ah	; Restore value
	jmp SHORT fin5		; 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 SHORT fin2		;  Tell user and die
	 nop

	call RPack		; Get ACK (w/o screen stuff)
	 jmp SHORT 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
	jmp SHORT fin5		; Yes, then we're done

fin4:	cmp ah,'E'		; Error packet?
	 jnz fin1		;  Try sending it again

	call error1

fin5:	pop ax
	mov flags.remflg, al	; Restore original value
	jmp rskp

FINISH	ENDP


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

BYE	PROC

	mov ah,cmcfm		; Parse a confirm
	call comnd
	 jmp r

	mov al, flags.remflg	; Pick up current value of remote flag
	push ax			; Save it
	mov flags.remflg, 1	; Force us into remote mode for LOGOUT command

	call logo		; Tell the mainframe to logout
	 jmp SHORT Bye_1	;  Don't exit yet
	 nop			;  3 bytes

	mov flags.extflg,1	; Set exit flag

Bye_1:	pop ax
	mov flags.remflg, al	; Restore original value
	jmp rskp

BYE	ENDP


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

Get	PROC

	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 data	; 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 RSkp		;  Failed

	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 data
	mov dx,offset frem
	mov ah,cmtxt
	call comnd		; get a line of text
	 jmp RSkp

	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 data[bx],'$' ; terminate name for printing
	mov pack.argbk1,bx	; remember length here
	mov dx,offset lclfnm
	call prompt
	mov ah,cmifi
	mov bx,offset filhlp
	mov dx,offset fcb
	call comnd
	 jmp RSkp

	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 pack.argbk1,ax	; Remember number of chars we read
	mov byte ptr [bx],'$'	; use for printing

get5:	push cx			; Save regs
	push si
	push di
	mov cx, 5Ah		; Size of the Data and Data_2 buffers
	mov si, OFFSET Data	; Copy from ...
	mov di, OFFSET Data_2	; Copy to ...
	rep movsb		; Copy from Data to Data_2
	mov cx, Pack.ArgBk1	; Pick up size of data packet
	mov Temp, cx		; Save it for a minute
	pop di			; Restore regs
	pop si
	pop cx

	call Init		; Clear line and initialize buffers

	mov dx, OFFSET InfMs3	; Say we are sending a request for the file
	call Show_status	; Display the message

	call IPack		; Send our INITIATE params to the server
	 jmp Get_error		;  Couldn't do it

	push cx			; Save regs
	push si
	push di
	mov cx, Temp		; Get back size of data packet
	mov Pack.ArgBk1, cx	; Restore it
	mov cx, 5Ah		; Size of the Data and Data_2 buffers
	mov si, OFFSET Data_2	; Copy from ...
	mov di, OFFSET Data	; Copy to ...
	rep movsb		; Copy from Data_2 back to Data area
	pop di			; Restore regs
	pop si
	pop cx

	call serini		; Initialize port
	mov pack.pktnum,0	; Set packet number to zero
	mov pack.numtry,0	; Initialize count
	mov pack.numpkt,0	; Set the number of packets to zero
	mov pack.numrtr,0	; No retries yet
	mov pack.state,'R'	; this is what state will soon be..
	cmp flags.remflg,0	; remote mode?
	 jne get6		; yes, don't print anything

	mov dx, OFFSET InfMs2	; Say we are waiting for the file
	call Show_status	; Display the message
	call clrfln		; Prepare to print filename
	mov ah,prstr
	mov dx,offset data	; Print file name
	int dos

get6:	call init1		; init buffers
	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
	call Show_retries	; Give a progress report
	cmp pack.numtry, imxtry	; Too many times?
	 jb get10		;  Nope, try it

Get8:	mov dx, OFFSET ErMes7	; Unable to Receive Initiate
	jmp SHORT Get8a		; Joint common code

Get_error:
	mov dx, OFFSET erms70	; Message to say we couldn't send INIT packet

Get8a:	call Show_error

Get9:	call Close_transfer_screen ; Erase mode line, go to lower left
	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 SHORT get8		;  Tell user we can't do it
	 nop

	call RPack		; Get ACK (w/o screen stuff)
	 jmp SHORT Get11	;  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 Read1		; go join read code

Get11:	inc Pack.NumRtr		; Bump number of retries
	jmp Get7		; Go try again

GET	ENDP


; Server command

Server	PROC
	mov	ah,cmcfm
	call	comnd
	 jmp	r

; Pre-confirmed entry to Server Mode, enter from Terminal Emulation Mode

Enter_Server:
	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 (Turn on server screen)

	mov Flags.NmOFlg, 0	; Clear the name override flag
				;  (CMIFI leaves it set)
	mov Flags.DrOFlg, 0	; Likewise for drive override

	call	Init		; Clear screen, display template & mode line
	call	serini		; Init serial port

; should reset to default parms here..
; should increase timeout interval

Serv1:	mov	trans.chklen,1	; checksum len = 1
	mov	pack.pktnum,0	; pack number resets to 0
	mov	pack.numtry,0	; no retries yet

	mov dx, OFFSET infms1	; Message is "Server: Waiting for request"
	call Show_status	; Display status

	call	rpack		; Get a packet
	 jmp SHORT Serv2	;  No good, NAK and continue
	 nop

	jmp SHORT Serv3		; Try to figure this out

    PUBLIC Serv2, Serv3

serv2:	cmp Flags.CxzFlg, 'C'	; Control-C?
	 je Serv5		;  Yes

	call	nak		; nak the packet
	jmp	serv1		; and keep reading packets

serv3:	mov	di,offset srvchr ; server characters
	mov	cx,srvfln	; length of string
	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 looking 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..

	call Do_CXZ_mode_line	; Called rtn trashed the mode line
	jmp	serv1		; Keep going for more cmds


%OUT >> About half way through source file


Serv5:	call Close_transfer_screen ; Close out the file transfer screen
	pop	ax		; get this off stack
	mov	flags.remflg,al	; restore old flag
	pop	es		; restore register
	jmp	rskp		; and return

Server	ENDP


;                        ***   Server Commands   ***

; srvsnd - receives a file that the local kermit is sending
srvsnd	PROC
	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	Read1		;  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
	call DoDec		; Fix up the encoded filename
	mov	si,offset data	; this should be it after decoding
	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:	cmp	al, 1		; Wildcards used?
	 jne	 SrvRc2		;  No

	mov Flags.WldFlg, 0FFh	; Flag the wildcard

SrvRc2:	mov	pack.state,'R'	; remember state
	call	send11		; this should send it
	 nop
	 nop
	 nop

	jmp	rskp		; return in any case

SrvRcv	ENDP


    PUBLIC SrvGen

; srvgen - generic server commands
; We only support Logout and Finish right now
srvgen	PROC
	call DoDec		; Decode the data packet
	mov	al,data		; get 1st packet char
	cmp al, 'C'		; Remote CWD (Change Working Directory)?
	 jne srvge0		;  No

	call Remote_CWD		; Use other routine to do the CWD
	jmp RSkp		; Return normally

srvge0:	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


    PUBLIC Remote_CWD

; Do a REMOTE CWD for the other Kermit

Remote_CWD PROC

	mov cl, data+1		; get the filename byte count
	sub cl, ' '   		; ascii to numeric
	cmp cl, 0     		; anything there?
	 jle srcwd3   		; le = no, an error

	sub ch, ch     		; set up counter
	mov si, OFFSET data+2	; received dir spec, from rpack
	mov di, OFFSET srvbuf	; destination
	rep movsb        	; copy data to srvbuf, cx chars worth

	mov BYTE PTR [di],0	; plant terminator
	mov dx, OFFSET srvbuf	; for DOS
	mov ax, dx    		; dir spec pointer for isfile
	cmp BYTE PTR [di-1], ':' ; did user just type A: or similar?
	 je srcwd1   		; e = yes, so skip directory part

	mov ah, chdir 		; want to do change dir
	int Dos
	 jnc srcwd1   		; nc = ok

srcwd3: mov bx, OFFSET remms4	; an error.
	jmp errpack  		; send the bad news, ret from there

srcwd1: mov dl, data+3		; see if drive given (look for :)
	cmp dl, ':'
	 jne srcwd2   		; ne = no drive

	mov dl, data+2
	and dl, 5fH   		; convert to upper case
	sub dl, 'A'   		; count A = 0 for seldsk call
	mov ah, seldsk
	int Dos      		; change disks
	 jc srcwd3   		; c = an error

	inc dl       		; now make A = 1 etc internally
	mov curdsk, dl		; and update internal current disk code

srcwd2: mov ah, 'Y'		; return an ack
	mov pack.argbk1, 0	; no data
	call spack		; Send the packet
	 nop
	 nop
	 nop

	ret			; Done here

Remote_CWD ENDP

; srvini - init parms based on init packet
srvini	PROC

	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
	mov dx,offset remtab	; Parse a keyword from the REMOTE table
	mov bx,offset remhlp
	mov ah,cmkey
	call comnd
	 jmp r

	mov al, flags.remflg	; Pick up current value of remote flag
	push ax			; Save it
	mov flags.remflg, 1	; Force us into remote mode for LOGOUT command

	call bx			; Call the appropriate routine
	 nop			;  Tolerate skip and non-skip returns
	 nop
	 nop

	pop ax
	mov flags.remflg, al	; Restore original value
	jmp rskp

REMOTE	ENDP

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

REMDIS	PROC
	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
	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
	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
	mov remcmd,' '		; Don't need one
	mov rempac,'C'		; Packet type = remote command
	jmp genric
REMHOS	ENDP

; REMDIR - Do a directory. [21c]

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

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

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

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

REMCWD	PROC
	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
	mov bx,offset SrvBuf	; 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 SrvBuf+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 genr0a		; 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

genr0a:	push ax			; Save ax
	mov ah, PrStr		; Code to type a string
	mov dx, OFFSET CrLf	; A CrLf
	int Dos			; Type it
	pop ax			; Get back ax

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 SrvBuf	; Start of data buffer
	mov ah,remcmd		; Command subtype
	mov [bx],ah
	call ipack		; Send init parameters
	 jmp SHORT 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:	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 SrvBuf	; 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 RPack		; 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

	mov ah,prstr
	mov dx,offset crlf	; Go to a new line
	int dos

	mov ah,prstr
	mov dx,offset crlf	; Go to a new line
	int dos

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

    PUBLIC genr4,genr5,genr51,genr6

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
	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 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?
	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
	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


; 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
