MS-DOS Kermit sources (Part 3 of 7)

Jim Knutson knutson at ut-ngp.UUCP
Sat Oct 6 02:05:53 AEST 1984


: Run this shell script with "sh" not "csh"
PATH=:/bin:/usr/bin:/usr/ucb
export PATH
all=FALSE
if [ $1x = -ax ]; then
	all=TRUE
fi
/bin/echo 'Extracting mssend.asm'
sed 's/^X//' <<'//go.sysin dd *' >mssend.asm
	public	spar, rpar, error, error1, nout, send, flags, trans, pack
	public	dodec, doenc, curchk, inichk, packlen, send11
	include msdefs.h	

spmin	equ	20		; Minimum packet size.
spmax	equ	94		; Maximum packet size.

datas 	segment	public 'datas'
	extrn	buff:byte, data:byte, fcb:byte, cpfcb:byte, filbuf:byte
	extrn	decbuf:byte, chrcnt:word, bufpnt:word, comand:byte
	extrn	rptq:byte, origr:byte, rptct:byte, rptval:byte

flags	flginfo	<>
trans	trinfo	<>
pack	pktinfo <>
crlf	db	cr,lf,'$'
ender	db	bell,bell,'$' 			;  [4]
erms14  db	'?Unable to receive an acknowledgment from the host$'
erms15  db	'?Unable to find file$'
erms20	db	'Unable to send init packet$'
erms21	db	'Unable to send file header$'
erms22	db	'Unable to send data$'
erms23	db	'Unable to send end-of-file packet$'
erms24	db	'Unable to send break packet$'
infms2  db	cr,'             Sending: In progress$'
infms3  db	'Completed$'
infms4  db	'Failed$'
infms6  db	'Interrupted$'
infms7	db	cr,' Percent transferred: 100%$'
remmsg1	db	'Kermit-MS: File not found$'
filhlp  db      ' Input file spec (possibly wild) $'
filmsg	db	' File name to use on target system or confirm with'
	db	' a carriage return $'

curchk	db	0		; Use to store checksum length.
inichk	db	1		; Original or set checksum length.
chrptr  dw	?		; Position in character buffer.
fcbpt	dw	?		; Position in FCB.
datptr  dw	?		; Position in packet data buffer.
siz	dw	?		; Size of data from gtchr.
temp	dw	0
temp4	dw	0
sendas	dw	50 dup(0)	; Buffer for file name.
difnam	db	0		; Send under different name?
difsiz	db	0		; Size of new file name.
asmsg	db	'  as  $'
datas	ends

code	segment	public
	extrn serini:near, serrst:near, comnd:near, init:near
	extrn spack:near, rpack:near, gtnfil:near, gtchr:near
	extrn getfil:near, clrfln:near, nppos:near, rprpos:near
	extrn erpos:near, rtpos:near, cxmsg:near, stpos:near
	extrn encode:near, nulref:near, decode:near, nulr:near
	extrn errpack:near, updrtr:near, clrmod:near, fcbcpy:near
	extrn perpos:near
	assume	cs:code,ds:datas

;	This routine sets up the data for init packet (either the
;	Send_init or ACK packet).
 
RPAR	PROC	NEAR
	mov ah,trans.rpsiz	; Get the receive packet size.
	add ah,' '		; Add a space to make it printable.
	mov [bx],ah		; Put it in the packet.
	mov ah,trans.rtime	; Get the receive packet time out.
	add ah,' '		; Add a space.
	mov 1[bx],ah		; Put it in the packet.
	mov ah,trans.rpad	; Get the number of padding chars.
	add ah,' '
	mov 2[bx],ah		; Put it in the packet.
	mov ah,trans.rpadch	; Get the padding char.
	add ah,100O		; Uncontrol it.
	and ah,7FH
	mov 3[bx],ah		; Put it in the packet.
	mov ah,trans.reol	; Get the EOL char.
	add ah,' '
	mov 4[bx],ah		; Put it in the packet.
	mov ah,trans.rquote	; Get the quote char.
	mov 5[bx],ah		; Put it in the packet.
	mov ah,trans.ebquot	; Get 8-bit quote char. [21b]
	mov 6[bx],ah		; Add it to the packet. [21b] 
	mov ah,trans.chklen	; Length of checksum.
	add ah,48		; Make into a real digit.
	mov 7[bx],ah
	mov ah,rptq		; Repeat quote char.
	cmp ah,0		; Null means no.
	jne rpar0
	mov ah,' '		; Send a blank instead.
rpar0:	mov 8[bx],ah
	mov ah,09H		; Nine pieces of data.
	ret
RPAR	ENDP
 
;	This routine reads in all the send_init packet information.
 
SPAR	PROC	NEAR
	cmp ax,1
	jge sparx
	mov ah,dspsiz		; Data not supplied by host, use default.
	jmp sparx2
sparx:	mov temp4,ax		; Save the number of arguments.
	mov ah,trans.spsiz
	cmp ah,dspsiz		; Is current value the default?
	jne sparx2		; No, assume changed by user.
	mov ah,[bx]		; Get the max packet size.
	sub ah,' '		; Subtract a space.
	cmp ah,spmin		; Can't be below the minimum.
	jge sparx1
	mov ah,spmin
	jmp sparx2
sparx1:	cmp ah,spmax		; Or above the maximum.
	jle sparx2
	mov ah,spmax
sparx2:	mov trans.spsiz,ah	; Save it.
	mov ax,temp4
	cmp al,2		; Fewer than two pieces?
	jge spar0
	mov ah,dstime		; Data not supplied by host, use default.
	jmp spar02
spar0: 	mov ah,trans.stime
	cmp ah,dstime		; Is current value the default?
	jne spar02		; No, assume changed by user.
	mov ah,1[bx]		; Get the timeout value.
	sub ah,' '		; Subtract a space.
	cmp ah,0
	ja spar01		; Must be non-negative.
	mov ah,0
spar01:	cmp ah,trans.rtime	; Same as other side's timeout.
	jne spar02
	add ah,5		; If so, make it a little different.
spar02:	mov trans.stime,ah	; Save it.
	mov ax,temp4
	cmp al,3		; Fewer than three pieces?
	jge spar1
	mov ah,dspad		; Data not supplied by host, use default.
	jmp spar11
spar1:	mov ah,trans.spad
	cmp ah,dspad		; Is current value the default?
	jne spar11		; No, assume changed by user.
	mov ah,2[bx]		; Get the number of padding chars.
	sub ah,' '
	cmp ah,0
	ja spar11		; Must be non-negative.
	mov ah,0
spar11:	mov trans.spad,ah
	mov ax,temp4
	cmp al,4		; Fewer than four pieces?
	jge spar2
	mov ah,dspadc		; Data not supplied by host, use default.
	jmp spar21
spar2:	mov ah,trans.spadch
	cmp ah,dspadc		; Is current value the default?
	jne spar21		; No, assume changed by user.
	mov ah,3[bx]		; Get the padding char.
	add ah,100O		; Re-controlify it.
	and ah,7FH
	cmp ah,del		; Delete?
	je spar21		; Yes, then it's OK.
	cmp ah,0
	jge spar20
	mov ah,0		; Below zero is no good.
	jmp spar21		; Use zero (null).
spar20:	cmp ah,31		; Is it a control char?
	jle spar21		; Yes, then OK.
	mov ah,0		; No, use null.
spar21:	mov trans.spadch,ah
	mov ax,temp4
	cmp al,5		; Fewer than five pieces?
	jge spar3
	mov ah,dseol		; Data not supplied by host, use default.
	jmp spar31
spar3:  mov ah,trans.seol
	cmp ah,dseol		; Is current value the default?
	jne spar31		; No, assume changed by user.
	mov ah,4[bx]		; Get the EOL char.
	sub ah,' '
	cmp ah,0
	jge spar30		; Cannot be negative.
	mov ah,cr		; If it is, use default of carriage return.
	jmp spar31
spar30:	cmp ah,31		; Is it a control char?
	jle spar31		; Yes, then use it.
	mov ah,cr		; Else, use the default.
spar31:	mov trans.seol,ah
	mov ax,temp4
	cmp al,6		; Fewer than six pieces?
	jge spar4
	mov ah,dsquot		; Data not supplied by host, use default.
	jmp spar41
spar4:	mov ah,trans.squote
	cmp ah,dsquot		; Is current value the default?
	jne spar41		; No, assume changed by user.
	mov ah,5[bx]		; Get the quote char.
	cmp ah,' '		; Less than a space?
	jge spar40
	mov ah,dsquot		; Yes, use default.
	jmp spar41
spar40:	cmp ah,'~'		; Must also be less then a tilde.
	jle spar41
	mov ah,dsquot		; Else, use default.
spar41:	mov trans.squote,ah
	cmp al,7		; Fewer than seven pieces? [21b begin]
	jge spar5
	mov trans.ebquot,'Y'	; Data not supplied by host, use default.
	jmp spar51
spar5:	mov ah,6[bx]		; Get other sides 8-bit quote request.
	call doquo		; And set quote char.  [21b end]
spar51:	cmp al,8		; Fewer than eight pieces?
	jge spar6
	mov trans.chklen,1
	jmp spar61
spar6:	mov ah,inichk
	mov trans.chklen,ah	; Checksum length we really want to use.
	mov ah,7[bx]		; Get other sides checksum length.
	call dochk		; Determine what size to use.
spar61:	cmp al,9		; Fewer than nine pieces?
	jge spar7
	mov rptq,0
	ret
spar7:	mov ah,8[bx]		; Get other sides repeat count prefix.
	mov ch,drpt
	mov rptq,0
	call dorpt
	ret
SPAR	ENDP
 
; Set 8-bit quote character based on my capabilities and the other
; Kermit's request.   [21b]

DOQUO	PROC	NEAR
	cmp trans.ebquot,'N'	; Can I do 8-bit quoting at all?
	je dq3			; No - so forget it.
	cmp trans.ebquot,'Y'	; Can I do it if requested?
	jne dq0			; No - it's a must that I do it.
	mov trans.ebquot,ah	; Do whatever he wants.
	jmp dq1
dq0:	cmp ah,'Y'		; I need quoting - can he do it?
	je dq1			; Yes - then all is settled.
	cmp ah,'N'		; No - then don't quote.
	je dq3
	cmp ah,trans.ebquot	; Both need quoting - chars must match.
	jne dq3
dq1:	mov ah,trans.ebquot
	cmp ah,'Y'		; If Y or N, don't validate prefix.
	je dq2
	cmp ah,'N'
	je dq2
	call prechk		; Is it in range 33-62, 96-126?
	 mov ah,'Y'		; Failed, don't do quoting.
	 nop
	cmp ah,trans.rquote	; Same prefix?
	je dq3			; Not allowed, so don't do quoting. 
	cmp ah,trans.squote	; Same prefix here?
	je dq3			; This is illegal too.
	mov trans.ebquot,ah	; Remember what we decided on.
dq2:	ret
dq3:	mov trans.ebquot,'N'	; Quoting will not be done.
	ret
DOQUO	ENDP
 
; Check if prefix in AH is in the proper range: 33-62, 96-126. 
; RSKP if so else RETURN.
prechk:	cmp ah,33
	jge prec0		; It's above 33.
	ret
prec0:	cmp ah,62
	jg prec1
	jmp rskp		; And below 62.  OK.
prec1:	cmp ah,96
	jge prec2		; It's above 96.
	ret
prec2:	cmp ah,126
	jg prec3
	jmp rskp		; And below 126.  OK.
prec3:	ret

; Set checksum length. 
dochk:	cmp ah,'1'		; Must be 1, 2, or 3.
	jl doc1
	cmp ah,'3'
	jle doc2
doc1:	mov ah,'1'
doc2:	sub ah,48		; Don't want it printable.
	cmp ah,trans.chklen	; Do we want the same thing?
	je dochk0		; Yes, then we're done.
	mov trans.chklen,1	; No, use single character checksum.
dochk0:	ret			; Just return for now.

; Set repeat count quote character.  The one used must be different than
; the control and eight-bit quote characters.  Also, both sides must 
; use the same character.
dorpt:	call prechk		; Is it in the valid range?
	 mov ah,0		; No, don't use their value. 
	 nop
	cmp ah,trans.squote	; Same as the control quote char?
	je dorpt0		; Yes, that's illegal, no repeats.
	cmp ah,trans.rquote	; How about this one?
	je dorpt0		; No good.
	cmp ah,trans.ebquot	; Same as eight bit quote char?
	je dorpt0		; Yes, that's illegal too, no repeats.
	cmp ah,ch		; Are we planning to use the same char?
	jne dorpt0		; No, that's no good either.
	mov rptq,ch		; Use repeat quote char now.
dorpt0:	ret

;	Send command
 
SEND	PROC	NEAR
	mov comand.cmcr,0	; Filename must be specified.
	mov difnam,0		; Assume we'll use original filename.
	mov flags.wldflg,0	; Re-initialize every time.
	mov ah,cmifi		; Parse an input file spec.
	mov dx,offset fcb	; Give the address for the FCB.
	mov bx,offset filhlp	; Text of help message.
	call comnd
	 jmp r			;  Give up on bad parse.
	cmp flags.wldflg,0FFH	; Any wildcards seen?
	je send1		; Yes, get a confirm.
	mov bx,offset sendas	; See if want to send file under dif name.
	mov dx,offset filmsg	; In case user needs help.
	mov ah,cmtxt
	call comnd
	 jmp r
	cmp ah,0		; Different name supplied?
	je send11		; No - keep as it.
	mov difnam,1		; Yes - send different filename.
	mov difsiz,ah		; Remember length of new name.
	jmp send11
send1:  mov ah,cmcfm
	call comnd		; Get a confirm.
	 jmp r			;  Didn't get a confirm.
send11: mov flags.droflg,0	; Reset flags from fn parsing. [21a]
	mov flags.nmoflg,0	; Reset flags from fn parsing. [21a]
	mov ah,sfirst		; Get the first file.
	mov dx,offset fcb
	int dos
	cmp al,0FFH		; Any found?
	jne send12
	cmp pack.state,'R'	; was this from a remote GET?
	jne sen11a		; no, print error and continue
	mov bx,offset remmsg1	; else get error message
	call errpack		; go complain
	jmp abort		; and abort this
sen11a:	mov ah,prstr
	mov dx,offset crlf
	int dos
	mov ah,prstr
	mov dx,offset erms15
	int dos
	ret
send12: cmp flags.wldflg,0	; Any wildcards.      [7 start]
	je send16		; Nope, so no problem.
	mov bx,offset fcb	; Remember what FCB looked like.
	mov di,offset cpfcb
	mov cl,37		; Size of FCB.
	call fcbcpy
	mov di,offset fcb+1	; Copy filename	from DTA to FCB.
	mov bx,offset buff+1
	mov cl,11
	call fcbcpy					; [7 end]
send16:	call serini		; Initialize serial port. [14]
	mov pack.pktnum,0	; Set the packet number to zero.
	mov pack.numtry,0	; Set the number of tries to zero.
	mov pack.numpkt,0 	; Set the number of packets to zero.
	mov pack.numrtr,0	; Set the number of retries to zero.
	mov pack.state,'S'	; Set the state to receive initiate.
	cmp flags.remflg,0	; remote mode?
	jne send2a		; yes, continue below.
	call init		; Clear the line and initialize the buffers.
	call rtpos		; Position cursor.
	mov ax,0
	call nout		; Write the number of retries.
	call stpos		; Print status of file transfer.
	mov ah,prstr		; Be informative.
	mov dx,offset infms2
	int dos
send2:	cmp flags.remflg,0	; remote mode?
	jne send2a		; yes, skip printing
	call nppos		; Number of packets sent.
	mov ax,pack.numpkt
	call nout		; Write the packet number.
send2a:	cmp pack.state,'D'	; Are we in the data send state?
	jne send3
	call sdata
	jmp send2
send3:  cmp pack.state,'F'	; Are we in the file send state?
	jne send4
	call sfile		; Call send file.
	jmp send2
send4:  cmp pack.state,'Z'	; Are we in the EOF state?
	jne send5
	call seof
	jmp send2
send5:  cmp pack.state,'S'	; Are we in the send initiate state?
	jne send6
	call sinit
	jmp send2
send6:  cmp pack.state,'B'	; Are we in the eot state?
	jne send7
	call seot
	jmp send2
send7:  cmp pack.state,'C'	; Are we in the send complete state?
	jne send8
	call serrst		; Reset serial port.  [14]
	cmp flags.remflg,0	; remote mode?
	jne send7a		; yes, no printing.
	cmp flags.cxzflg,0	; completed normally?
	jne send7b		; no, don't bother with this
	call perpos
	mov ah,prstr
	mov dx,offset infms7
	int dos
send7b:	call stpos
	mov ah,prstr
	mov dx,offset infms3	; Plus a little cuteness.
	cmp flags.cxzflg,0	; Completed or interrupted?
	je snd71		; Ended normally.
	mov dx,offset infms6	; Say was interrupted.
snd71:  int dos			; New label. 
	cmp flags.belflg,0	; Bell desired? [17a]
	je sendnb		; [17a]
	mov dx,offset ender	; Ring them bells.   [4]
	int dos
sendnb:	call clrmod
	call rprpos
send7a:	jmp rskp
send8: 	call serrst		; Reset serial port.  [14]
	cmp flags.remflg,0	; remote mode?
	jne send9a		; no, no printing.
	call stpos
	mov ah,prstr
	mov dx,offset infms4	; Plus a little cuteness.
	int dos
	cmp flags.belflg,0	; Bell desired?  [17a]
	je send9		; No.  [17a]
	mov dx,offset ender	; Ring them bells.   [4]
	int dos			;  [4]
send9:	call clrmod
	call rprpos
send9a:	jmp rskp
SEND	ENDP
 
 
;	Send routines
 
;	Send initiate
 

SINIT	PROC	NEAR
	cmp pack.numtry,imxtry	; Have we reached the maximum number of tries?
	jl sinit2
	call erpos
	mov dx,offset erms14
	mov ah,prstr
	int dos			; Print an error message.
	mov bx,offset erms20
	call errpack		; Send error packet just in case.
	jmp abort		; Change the state to abort.
sinit2: 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 ax,pack.numpkt	; Get the packet number.
	mov pack.argblk,ax
	mov ah,trans.chklen
	mov curchk,ah		; Store checksum length we want to use.
	mov trans.chklen,1	; Send init checksum is always 1 char.
	mov ah,'S'		; Send initiate packet.
	call spack		; Send the packet.
	 jmp abort
	call rpack		; Get a packet.
	 jmp sini23		; Trashed packet don't change state, retry.
	push ax
	mov ah,curchk
	mov trans.chklen,ah	; Checksum length we want to use.
	pop ax
	cmp ah,'Y'		; ACK?
	jne sinit3		; If not try next.
	mov ax,pack.pktnum	; Get the packet number.
	cmp ax,pack.argblk	; Is it the right packet number?
	je sini22
	ret			; If not try again.
sini22: inc ax			; Increment the packet number.
	and ax,3FH		; Turn off the two high order bits.
	mov pack.pktnum,ax	; Save modulo 64 of the number.
	inc pack.numpkt		; Increment the number of packets.
	mov ax,pack.argbk1	; Get the number of pieces of data.
	mov bx,offset data	; Pointer to the data.
	call spar		; Read in the data.
	call packlen		; Get max send packet size. [21b]
	mov ah,pack.numtry	; Get the number of tries.
	mov pack.oldtry,ah	; Save it.
	mov pack.numtry,0	; Reset the number of tries.
	mov pack.state,'F'	; Set the state to file send.
	call getfil		; Open the file.
	 jmp abort		;  Something is wrong, die.
	ret
sini23:	mov ah,curchk		; Restore desired checksum length.
	mov trans.chklen,ah
	call updrtr		; Update retry counter.
	ret			; And retry.
sinit3: cmp ah,'N'		; NAK?
	jne sinit4		; If not see if its an error.
	call rtpos		; Position cursor.
	inc pack.numrtr		; Increment the number of retries
	mov ax,pack.numrtr
	call nout		; Write the number of retries.
	ret
sinit4: cmp ah,'E'		; Is it an error packet.
	jne sinit5
	call error
sinit5: jmp abort
SINIT	ENDP
 


;	Send file header
 
SFILE	PROC	NEAR
	cmp pack.numtry,maxtry	; Have we reached the maximum number of tries?
	jl sfile1
	call erpos
	mov dx,offset erms14
	mov ah,prstr
	int dos			; Print an error message.
	mov bx,offset erms21
	call errpack		; Send error packet just in case.
	jmp abort		; Change the state to abort.
sfile1: inc pack.numtry		; Increment it.
	mov flags.cxzflg,0	; Clear ^X,^Z flag. 
	mov datptr,offset data  ; Get a pointer to our data block.
	mov bx,offset fcb+1		; Pointer to file name in FCB.
	mov fcbpt,bx		; Save position in FCB.
	mov cl,0		; Counter for chars in file name.
	mov ch,0		; Counter for number of chars in FCB.
sfil11:	cmp ch,8H		; Ninth char?
	jne sfil12
	mov ah,'.'
	mov bx,datptr
	mov [bx],ah		; Put dot in data packet.	
	inc bx
	mov datptr,bx		; Save new position in data packet.
	inc cl
sfil12:	inc ch
	cmp ch,0CH		; Twelve?
	jns sfil13
	mov bx,fcbpt
	mov ah,[bx]		; Get char of filename.
	inc bx
	mov fcbpt,bx		; Save position in FCB.
	cmp ah,'!'		; Is it a good char?
	jl sfil11		; If not, get the next.
	mov bx,datptr
	mov [bx],ah		; Put char in data buffer.
	inc cl			; Increment counter.
	inc bx
	mov datptr,bx		; Save new position. 
	jmp sfil11		; Get another char.
sfil13: mov ch,0
	cmp flags.remflg,0	; remote mode?
	jne sfil13a		; yes, no printing.
	push cx			; Don't forget the size.
	mov bx,datptr
	mov ah,'$'
	mov [bx],ah		; Put dollar sign for printing.
	call clrfln
	mov ah,prstr
	mov dx,offset data	; Print file name.
	int dos
	pop cx
sfil13a:cmp difnam,0		; Sending file under different name.
	je sfl13x		; No, so don't give new name.
	call newfn
sfl13x:	call doenc		; Do encoding.
	mov ax,pack.pktnum	; Get the packet number.
	mov pack.argblk,ax
	mov ah,'F'		; File header packet.
	call spack		; Send the packet.
	 jmp abort
	call rpack		; Get a packet.
	 jmp tryagn		; Trashed packet don't change state, retry.
	call dodec		; Do all decoding.
	cmp ah,'Y'		; ACK?
	jne sfile2		; If not try next.
	mov ax,pack.pktnum	; Get the packet number.
	cmp ax,pack.argblk
	je sfil14
	ret			; If not hold out for the right one.
sfil14: inc ax			; Increment the packet number.
	and ax,3FH		; Turn off the two high order bits.
	mov pack.pktnum,ax	; Save modulo 64 of the number.
	inc pack.numpkt		; Increment the number of packets.
	mov ah,pack.numtry	; Get the number of tries.
	mov pack.oldtry,ah	; Save it.
	mov pack.numtry,0	; Reset the number of tries.

sfil15: mov ah,0		; Get a zero.
	mov bx,offset fcb
	add bx,20H
	mov [bx],ah		; Set the record number to zero.
;	mov flags.eoflag,ah	; Indicate not EOF.  (Done in GETFIL).
	mov ah,0FFH
	mov flags.filflg,ah	; Indicate file buffer empty.
	call gtchr
	 jmp sfil16		; Error go see if its EOF.
	 nop
	jmp sfil17		; Got the chars, proceed.
sfil16: cmp ah,0FFH		; Is it EOF?
	je sfl161
	jmp abort		; If not give up.
sfl161: mov ah,'Z'		; Set the state to EOF.
	mov pack.state,ah
	ret
sfil17: mov siz,ax

	mov pack.state,'D'	; Set the state to data send.
	ret
sfile2: cmp ah,'N'		; NAK?
	jne sfile3		; Try if error packet.
	call rtpos		; Position cursor.
	inc pack.numrtr		; Increment the number of retries
	mov ax,pack.numrtr
	call nout		; Write the number of retries.
	mov ax,pack.pktnum	; Get the present packet number.
	inc ax			; Increment.
	and ax,03FH		; Account for wraparound.  [18]
	cmp ax,pack.argblk	; Is the packet's number one more than now?
	jz sfil14		; Just as good as a ACK; go to the ACK code.
	ret			; If not go try again.
sfile3: cmp ah,'E'		; Is it an error packet.
	jne sfile4
	call error
sfile4: jmp abort
SFILE	ENDP
 
 
;	Send data
 
SDATA	PROC	NEAR
	cmp flags.cxzflg,0	; Have we seen ^X or ^Z?
	je sdata2		; Nope, just continue.
	cmp flags.cxzflg,'C'	; Stop it all? [25]
	jne sdata1		; It was a ^X or ^Z.
	mov pack.state,'A'	; It was a ^C -- abort [25]
	ret
sdata1:	mov pack.state,'Z'	; Else, abort sending the file.
	ret
sdata2: cmp pack.numtry,maxtry	; Have we reached the maximum number of tries?
	jl sdata3
	call erpos
	mov dx,offset erms14
	mov ah,prstr
	int dos			; Print an error message.
	mov bx,offset erms22
	call errpack		; Send error packet just in case.
	jmp abort		; Change the state to abort.
sdata3: inc pack.numtry		; Increment it.
	mov datptr,offset data  ; Get a pointer to our data block.
	mov chrptr,offset filbuf ; Pointer to chars to be sent.
	mov cx,siz		; number to transfer
	mov si,chrptr		; source of characters
	mov di,datptr		; destination
	cmp flags.eofcz,0	; stopping on ctl-z's?
	jz sdata6		; no, do blind copy
sdata4:	lodsb			; get a byte
	cmp al,'Z'-40H		; is it a ctl-z?
	je sdata5		; yes, break loop
	stosb			; else copy it
	loop sdata4		; and keep going
sdata5:	mov ax,siz		; size to send
	sub ax,cx		; minus actually sent...
	jmp short sdata7
sdata6:	rep movsb		; just copy data
	mov ax,siz		; this is how many were moved
sdata7:	mov pack.argbk1,ax
	mov ax,pack.pktnum	; Get the packet number.
	mov pack.argblk,ax
	mov ah,'D'		; Data packet.
	call spack		; Send the packet.
	 jmp tryagn		; if can't send it, retry before giving up
	call rpack		; Get a packet.
	 jmp tryagn		; Trashed packet don't change state, retry.
	call dodec		; Do all decoding.
	cmp ah,'Y'		; ACK?
	jne sdat14		; If not try next.
	mov ax,pack.pktnum	; Get the packet number.
	cmp ax,pack.argblk	; Is it the right packet number?
	jz sdata8
	ret			; If not hold out for the right one.
sdata8: inc ax			; Increment the packet number.
	and ax,3FH		; Turn off the two high order bits.
	mov pack.pktnum,ax	; Save modulo 64 of the number.
	inc pack.numpkt		; Increment the number of packets.
	mov ah,pack.numtry	; Get the number of tries.
	mov pack.oldtry,ah	; Save it.
	mov pack.numtry,0	; Reset the number of tries.
	cmp pack.argbk1,1	; Does the ACK contain data?
	jne sdat11		; Nope, so continue.
	mov bx,offset data	; If yes, check the data field.
	mov ah,[bx]		; Pick it up.
	cmp ah,'X'		; Other side requests ^X?
	jne sdata9		; Nope.
	jmp sdat10		; And leave.
sdata9: cmp ah,'Z'		; Other side requests ^Z?
	jne sdat11		; Nope.
sdat10:	mov flags.cxzflg,ah	; Yes remember it.
	mov pack.state,'Z'	; Abort sending file(s).
	ret
sdat11: call gtchr
	 jmp sdat12		; Error go see if its EOF.
	mov siz,ax		; Save the size of the data gotten.
	ret

sdat12: cmp ah,0FFH		; Is it EOF?
	je sdat13
	jmp abort		; If not give up.

sdat13: mov pack.state,'Z'	; Set the state to EOF.
	ret
sdat14: cmp ah,'N'		; NAK?
	jne sdat15		; See if is an error packet.
	call rtpos		; Position cursor.
	inc pack.numrtr		; Increment the number of retries
	mov ax,pack.numrtr
	call nout		; Write the number of retries.
	mov ax,pack.pktnum	; Get the present packet number.
	inc ax			; Increment.
	and ax,03FH		; Account for wraparound.  [18]
	cmp ax,pack.argblk	; Is the packet's number one more than now?
	jz sdata8		; Just as good as ACK; goto ACK code.
	ret			; If not go try again.
sdat15: cmp ah,'E'		; Is it an error packet.
	jne sdat16
	call error
sdat16: jmp abort
SDATA	ENDP
 
 
;	Send EOF
 
SEOF	PROC	NEAR
	cmp pack.numtry,maxtry	; Have we reached the maximum number of tries?
	jl seof1
	call erpos		; Position cursor.
	mov dx,offset erms14
	mov ah,prstr
	int dos			; Print an error message.
	mov bx,offset erms23
	call errpack		; Send error packet just in case.
	jmp abort		; Change the state to abort.
seof1:  inc pack.numtry		; Increment it.
	mov ax,pack.pktnum	; Get the packet number.
	mov pack.argblk,ax
	mov pack.argbk1,0	; No data.
	cmp flags.cxzflg,0	; Seen a ^X or ^Z?
	je seof11		; Nope, send normal EOF packet.
	mov bx,offset data	; Get data area of packet.
	mov ah,'D'		; Use "D" for discard.
	mov [bx],ah		; And add it to the packet.
	mov pack.argbk1,1	; Set data size to 1.
seof11:	mov cx,pack.argbk1	; Put size in CX.
	call doenc		; Encode the packet.
	mov ah,'Z'		; EOF packet.
	call spack		; Send the packet.
	 jmp abort
	call rpack		; Get a packet.
	 jmp tryagn		;  Trashed packet don't change state, retry.
	call dodec		; Do decoding.
	cmp ah,'Y'		; ACK?
	jne seof2		; If not try next.
	mov ax,pack.pktnum	; Get the packet number.
	cmp ax,pack.argblk	; Is it the right packet number?
	jz seof12
	ret			; If not hold out for the right one.
seof12: inc ax			; Increment the packet number.
	and ax,3FH		; Turn off the two high order bits.
	mov pack.pktnum,ax	; Save modulo 64 of the number.
	inc pack.numpkt		; Increment the number of packets.
	mov ah,pack.numtry	; Get the number of tries.
	mov pack.oldtry,ah	; Save it.
	mov pack.numtry,0	; Reset the number of tries.
	mov ah,closf		; Close the file.
	mov dx,offset fcb
	int dos
	call gtnfil		; Get the next file.
	 jmp seof13		;  No more.
	mov pack.state,'F'	; Set the state to file send.
	cmp flags.cxzflg,'X'	; Control-X seen?
	jne seof14
	call cxmsg		; Clear out the interrupt msg.
seof14:	mov flags.cxzflg,0	; Reset the flag.
	ret
seof13: mov pack.state,'B'	; Set the state to EOT.
	ret
seof2:  cmp ah,'N'		; NAK?
	jne seof3		; Try and see if its an error packet.
	call rtpos		; Position cursor.
	inc pack.numrtr		; Increment the number of retries
	mov ax,pack.numrtr
	call nout		; Write the number of retries.
	mov ax,pack.pktnum	; Get the present packet number.
	inc ax			; Increment.
	and ax,03FH		; Account for wraparound.  [18]
	cmp ax,pack.argblk	; Is the packet's number one more than now?
	jz seof12		; Just as good as a ACK; go to the ACK code.
	ret			; If not go try again.
seof3:  cmp ah,'E'		; Is it an error packet?
	jne seof4
	call error
seof4:  jmp abort
SEOF	ENDP
 
 
;	Send EOT
 
SEOT	PROC	NEAR
	cmp pack.numtry,maxtry	; Have we reached the maximum number of tries?
	jl seot1
	call erpos	       ; Position cursor.
	mov dx,offset erms14
	mov ah,prstr
	int dos			; Print an error message.
	mov bx,offset erms24
	call errpack		; Send error packet just in case.
	jmp abort		; Change the state to abort.
seot1:  inc pack.numtry		; Increment it.
	mov ax,pack.pktnum	; Get the packet number.
	mov pack.argblk,ax
	mov pack.argbk1,0	; No data.
	mov cx,pack.argbk1
	call doenc		; Encode packet.
	mov ah,'B'		; EOF packet.
	call spack		; Send the packet.
	 jmp abort
	call rpack		; Get a packet.
	 jmp tryagn		; Trashed packet don't change state, retry.
	call dodec		; Decode packet.
	cmp ah,'Y'		; ACK?
	jne seot2		; If not try next.
	mov ax,pack.pktnum	; Get the packet number.
	cmp ax,pack.argblk	; Is it the right packet number?
	jz seot12
	ret			; If not hold out for the right one.
seot12: inc ax			; Increment the packet number.
	and ax,3FH		; Turn off the two high order bits.
	mov pack.pktnum,ax	; Save modulo 64 of the number.
	inc pack.numpkt		; Increment the number of packets.
	mov ah,pack.numtry	; Get the number of tries.
	mov pack.oldtry,ah	; Save it.
	mov pack.numtry,0	; Reset the number of tries.
	mov pack.state,'C'	; Set the state to file send.
	ret
seot2:  cmp ah,'N'		; NAK?
	jne seot3		; Is it error.
	call rtpos		; Position cursor.
	inc pack.numrtr		; Increment the number of retries
	mov ax,pack.numrtr
	call nout		; Write the number of retries.
	mov ax,pack.pktnum	; Get the present packet number.
	inc ax			; Increment.
	and ax,03FH		; Account for wraparound.  [18]
	cmp ax,pack.argblk	; Is the packet's number one more than now?
	jz seot12		; Just as good as a ACK; go to the ACK code.
	ret			; If not go try again.
seot3:  cmp ah,'E'		; Is it an error packet.
	jne seot4
	call error
seot4:  jmp abort
SEOT	ENDP
 
tryagn:	call updrtr
	ret

newfn:	mov ah,prstr
	mov dx,offset asmsg
	int dos
	mov ah,dconio
	mov si,offset sendas	; Buffer where the name is.
	mov di,offset data
	mov ch,0
	mov cl,difsiz		; Length of name.
newf0:	lodsb			; Get a char.
	cmp al,61H
	jb newf1		; Leave alone if less than 'a'?
	cmp al,7AH
	ja newf1		; Leave alone if over 'z'.
	sub al,20H		; Uppercase the letters.
newf1:	stosb
	mov dl,al
	cmp flags.remflg,0	; should we print?
	jne newf2		; no, we're in remote mode.
	int dos			; Print them.
newf2:	loop newf0
	mov ch,0
	mov cl,difsiz		; Reset the length field.
	ret

; Do encoding.  Expectx CX to be the data size.
doenc:	jcxz doen0
	mov chrcnt,cx		; Number of chars in filename.
	mov bx,offset data	; Source of data.
	mov bufpnt,bx
	mov bx,offset nulref	; Null routine for refilling buffer.
	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 encode		; Make a packet with size in AX.
	 nop
	 nop
	 nop
	mov pack.argbk1,ax	; Save number of char in filename.
	mov cx,ax
	call movpak		; Move to data part of packet.
doen0:	ret

; CX is set before this is called.
movpak:	push es
	mov ax,ds
	mov es,ax
	mov si,offset filbuf	; Move from here
	mov di,offset data	; to here
	repne movsb
	pop es
	ret

; Do decoding.
dodec:	cmp pack.argbk1,0
	je dodc0
	push ax			; Save packet size.
	mov cx,pack.argbk1	; Size of data.
	mov bx,offset data	; Address of data.
	mov ax,offset nulr	; Routine to dump buffer (null routine).
	mov bufpnt,offset decbuf  ; Where to put output.
	mov chrcnt,80H		; Buffer size.
	call decode
	 nop     
	 nop     
	 nop     
	call decmov		; Move decoded data back to "data" buffer.
 	pop ax
dodc0:	ret

; Move decoded data from decode buffer back to "data". 
decmov:	push si
	push di
	push es
	mov ax,ds
	mov es,ax
	mov cx,bufpnt		; Last char we added.
	sub cx,offset decbuf	; Get actual number of characters.
	mov pack.argbk1,cx	; Remember size of real data.
	lea si,decbuf		; Data is here.
	lea di,data		; Move to here.
	repne movsb		; Copy the data.
	pop es
	pop di
	pop si
	ret

;	Abort
 
ABORT	PROC	NEAR
	mov pack.state,'A'	; Otherwise abort.
	ret
ABORT	ENDP

; This is where we go if we get an error packet.  A call to ERROR 
; positions the cursor and prints the message.  A call to ERROR1
; just prints a CRLF and then the message.  [8]
 
ERROR	PROC	NEAR
	mov pack.state,'A'	; Set the state to abort.
	call erpos		; Position the cursor.
	jmp error2
error1:	mov ah,prstr
	mov dx,offset crlf
	int dos
error2: mov bx,pack.argbk1	; Get the length of the data.
	add bx,offset data	; Get to the end of the string.
	mov ah,'$'		; Put a dollar sign at the end.
	mov [bx],ah
	mov ah,prstr		; Print the error message.
	mov dx,offset data
	int dos
	ret
ERROR	ENDP
 
; Set the maximum data packet size. [21b]

PACKLEN	PROC	NEAR
	mov ah,trans.spsiz	; Maximum send packet size. 
	sub ah,4		; Size minus control info. 
	sub ah,trans.chklen	; And minus checksum chars.
	sub ah,2		; Leave room at end: 2 for possible #X.
	cmp trans.ebquot,'N'	; Doing 8-bit quoting?
	je pack0		; Nope so we've got our size.
	cmp trans.ebquot,'Y'
	je pack0		; Not doing it in this case either.
	sub ah,1		; Another 1 for 8th-bit quoting. 
pack0:	cmp rptq,0		; Doing repeat character quoting?
	je pack1		; Nope, so that's all for now.
	sub ah,2		; Another 2 for repeat prefix.
pack1:	mov trans.maxdat,ah	; Save max length for data field.
	ret
PACKLEN	ENDP

 ; Print the number in AX on the screen in decimal rather that hex. [19a]

NOUT 	PROC	NEAR
	cmp flags.xflg,1	; Writing to screen? [21c]
	je nout1		; Yes, just leave. [21c]
	push ax
	push dx
	mov temp,10		; Divide quotient by 10.
;	cwd			; Convert word to doubleword.
	mov dx,0		; High order word should be zero.
	div temp		; AX <-- Quo, DX <-- Rem.
	cmp ax,0		; Are we done?	
	jz nout0		; Yes.
	call nout		; If not, then recurse.
nout0:	add dl,'0'		; Make it printable.
	mov temp,ax
	mov ah,conout
	int dos	
	mov ax,temp
	pop dx
	pop ax
nout1:	ret			; We're done. [21c]
NOUT	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
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
	/bin/chmod 640 mssend.asm
	/bin/echo -n '	'; /bin/ls -ld mssend.asm
fi
/bin/echo 'Extracting msserv.asm'
sed 's/^X//' <<'//go.sysin dd *' >msserv.asm
	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 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 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 data
	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 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 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 pack.argbk1,ax	; Remember number of chars we read.
	mov byte ptr [bx],'$'	; use for printing.
get5:	cmp flags.remflg,0	; remote mode?
	jne get6		; yes, don't print anything
	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...
	call serini		; Initialize port. 
	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
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
	/bin/chmod 640 msserv.asm
	/bin/echo -n '	'; /bin/ls -ld msserv.asm
fi
/bin/echo 'Extracting msset.asm'
sed 's/^X//' <<'//go.sysin dd *' >msset.asm
	public setcom, status, stat0, baudprt, escprt, prmptr, dodef
	public setcpt, docom, shomac, atoi
	include msdefs.h

setextra  equ	100
macmax	equ	20			; max # of macros

datas 	segment	public 'datas'
	extrn	comand:byte, flags:byte, trans:byte, cptfcb:byte, takadr:word
	extrn	taklev:byte, inichk:byte, portval:word, curdsk:byte
	extrn	setktab:byte, setkhlp:byte

kerm    db      'Kermit-MS>$'
crlf	db      cr,lf,'$'
crlfsp	db	cr,lf,' '	; crlf space
	db	'$'
eqs	db	' = $'
ermes1	db	cr,lf,'?Too many macros$'
ermes2	db	cr,lf,'?No room in table for macro$'
ermes3  db      cr,lf,'?Not confirmed$'
ermes4	db	cr,lf,'?No room in take stack to expand macro$'
ermes5	db	cr,lf,'?Not implemented$'
erms23	db	cr,lf,'?0 or null scan code not allowed$' ;[jd] 
erms24	db	cr,lf,'?Capture file already open (use close command)$' ;[jd]
filhlp	db	' Input file specification for session logging$'
macmsg	db	' Specify macro name followed by body of macro $'
shmmsg	db	' Confirm with carriage return $'
prmmsg	db	' Enter new prompt string $'
sk1msg	db	' Decimal scan code for key $'
sk2msg	db	' Redefinition string for key $'
prterr	db	'?Unrecognized value$'
unrec	db	'Baud rate is unknown$'
defpmp	db	'Definition string: $'
esctl	db	'Control-$'         ; [6]
nonmsg	db	'none$'
delmsg	db	'delete$'
onmsg	db	'On'
offmsg	db	'Off'
tmp	db	?,'$'
sum	db	0
min	db	0
max	db	0
desta	dw	0
numerr	dw	0
numhlp	dw	0
stflg	db	0		; Says if setting SEND or RECEIVE parameter.
srtmp	db	0
savsp	dw	0
temp	dw	0
temp1   dw      ?               ; Temporary storage.
temp2   dw      ?               ; Temporary storage.

locst   db      'Local echo $'
belon	db	'Ring bell after transfer$'
beloff	db	'No bell after transfer$'
vtemst  db	'HEATH-19 emulation $'
cm1st	db	'Communications port: 1$'
cm2st	db	'Communications port: 2$'
capmsg	db	'Session logging $'
eofmsg	db	'EOF mode: $'
flost	db	'No flow control used$'
floxmsg	db	'Flow control: XON/XOFF $'
handst	db	'Handshake used: $'
destst	db	'File destination: $'
diskst	db	'Default disk: $'
blokst	db	'Block check used: $'
ebyst	db	'8-bit quoting done only on request$'
ebvst	db	'8-bit quoting will be done with: $'
sqcst	db	'Send cntrl char prefix: $'
rqcst	db	'Receive cntrl char prefix: $'
debon	db	'Debug mode $'
flwon	db	'Warning $'
parmsg	db	'Parity $'
abfdst	db	'Discard incomplete file$'
abfkst	db	'Keep incomplete file$'
eolst	db	'End-of-line character: $'
ssohst	db	'Send start-of-packet char: $'
rsohst	db	'Receive start-of-packet char: $'
stimst	db	'Send timeout (seconds): $'
rtimst	db	'Receive timeout (seconds): $'
spakst	db	'Send packet size: $'
rpakst	db	'Receive packet size: $'
snpdst	db	'# of send pad chars: $'
rnpdst	db	'# of receive pad chars: $'
timmsg	db	'Timer $'
escmes  db      'Escape character: $'
b03st	db	'Baud rate is 300$'
b12st	db	'Baud rate is 1200$'
b18st	db	'Baud rate is 1800$'
b24st	db	'Baud rate is 2400$'
b48st	db	'Baud rate is 4800$'
b96st	db	'Baud rate is 9600$'
b04st	db	'Baud rate is 45.5$'
b05st	db	'Baud rate is 50$'
b07st	db	'Baud rate is 75$'
b11st	db	'Baud rate is 110$'
b13st	db	'Baud rate is 134.5$'
b15st	db	'Baud rate is 150$'
b06st	db	'Baud rate is 600$'
b20st	db	'Baud rate is 2000$'
b19st	db	'Baud rate is 19200$'
b38st	db	'Baud rate is 38400$'

eolhlp	db	cr,lf,'Decimal number between 0 and 31$'
eolerr	db	cr,lf,'Illegal end-of-line character$'
timerr	db	cr,lf,'Illegal timeout value$' 
timhlp	db	cr,lf,'Decimal number between 0 and 94$'
soherr	db	cr,lf,'Illegal start-of-packet character$'
quohlp	db	cr,lf,'Decimal number between 33 and 126$'
quoerr	db	cr,lf,'Illegal control character prefix$'
pakerr	db	cr,lf,'Illegal packet length$'
pakhlp	db	cr,lf,'Decimal number between 20 and 94$'
npderr	db	cr,lf,'Illegal number of pad characters$'
npdhlp	db	cr,lf,'Decimal number between 0 and 99$'
paderr	db	cr,lf,'Illegal pad character$'
padhlp	db	cr,lf,'Decimal number between 0 and 31 or 127$'
eschlp  db      cr,lf,'Enter literal value (ex: Cntrl ])  $'
desterr	db	cr,lf,'Illegal destination device$'
dskhlp	db	cr,lf,'Default disk drive to use, such as A:$'
dskerr	db	cr,lf,'Invalid drive specification$' 

sethlp	db      cr,lf,'BAUD rate'	
	db	cr,lf,'BELL'
	db	cr,lf,'BLOCK-CHECK-TYPE'
	db	cr,lf,'DEBUG'
	db	cr,lf,'DEFAULT-DISK'
	db	cr,lf,'DESTINATION'
	db	cr,lf,'END-OF-LINE character'
	db	cr,lf,'EOF CTRL-Z or NOCTRL-Z'
	db      cr,lf,'ESCAPE character change'
	db	cr,lf,'FLOW-CONTROL'
	db	cr,lf,'HANDSHAKE'
        db      cr,lf,'HEATH-19'
	db	cr,lf,'INCOMPLETE file'
	db	cr,lf,'KEY' 
        db      cr,lf,'LOCAL-ECHO echoing (half-duplex)'
	db	cr,lf,'PARITY type'
	db	cr,lf,'PORT for communication'
	db	cr,lf,'PROMPT'
	db	cr,lf,'RECEIVE parameter'
	db	cr,lf,'REMOTE on/off'
	db	cr,lf,'SEND parameter'
	db	cr,lf,'TAKE-ECHO' 
	db	cr,lf,'TIMER'
        db      cr,lf,'WARNING'
	db	'$'

settab  db      24
	mkeyw	'BAUD',baudst
	mkeyw	'BELL',bellst
	mkeyw	'BLOCK-CHECK-TYPE',blkset
	mkeyw	'DEBUG',debst
	mkeyw	'DEFAULT-DISK',dskset
	mkeyw	'DESTINATION',desset
	mkeyw	'END-OF-LINE',eolset
	mkeyw	'EOF',seteof
	mkeyw	'ESCAPE',escape
	mkeyw	'FLOW-CONTROL',floset
	mkeyw	'HANDSHAKE',hndset
	mkeyw	'HEATH19-EMULATION',vt52em
	mkeyw	'INCOMPLETE',abfset
	mkeyw	'KEY',setkey
	mkeyw	'LOCAL-ECHO',lcal
	mkeyw	'PARITY',setpar
	mkeyw	'PORT',comset
	mkeyw	'PROMPT',promset
	mkeyw	'RECEIVE',recset
	mkeyw	'REMOTE',remset
	mkeyw	'SEND',sendset
	mkeyw	'TAKE-ECHO',takset
	mkeyw	'TIMER',timset
	mkeyw	'WARNING',filwar

 
seoftab	db	2
	mkeyw	'CTRL-Z',1
	mkeyw	'NOCTRL-Z',0

stsrtb	db	06		; Number of options.
	mkeyw	'PACKET-LENGTH',srpack
	mkeyw	'PADCHAR',srpad
	mkeyw	'PADDING',srnpd
	mkeyw	'QUOTE',srquo
	mkeyw	'START-OF-PACKET',srsoh
	mkeyw	'TIMEOUT',srtim

ontab   db      02H             ; Two entries.
	mkeyw	'OFF',00H
	mkeyw	'ON',01H

destab	db	02H		; Two choices.
	mkeyw	'DISK',01H
	mkeyw	'PRINTER',00H

; What type of block check to use.
blktab	db	03H
	mkeyw	'1-CHARACTER-CHECKSUM',1
	mkeyw	'2-CHARACTER-CHECKSUM',2
	mkeyw	'3-CHARACTER-CRC-CCITT',3

; If abort when receiving files, can keep what we have or discard. [20d]

abftab	db	02H		; Only two options. 
	mkeyw	'DISCARD',01H
	mkeyw	'KEEP',00H

partab	db	05H		; Five entries.			[10 start]
	mkeyw	'EVEN',PAREVN
	mkeyw	'MARK',PARMRK
	mkeyw	'NONE',PARNON
	mkeyw	'ODD',PARODD
	mkeyw	'SPACE',PARSPC

flotab	db	2
	mkeyw	'NONE',flonon
	mkeyw	'XON/XOFF',floxon

hndtab	db	7
	mkeyw	'BELL',bell
	mkeyw	'CR',cr
	mkeyw	'ESC',esc
	mkeyw	'LF',lf
	mkeyw	'NONE',0
	mkeyw	'XOFF',xoff
	mkeyw	'XON',xon

BStab	db	02H			;Two entries [19c start]
	mkeyw	'BACKSPACE',00H
	mkeyw	'DELETE',01H

bdtab	db	010H		; 16 entries
	mkeyw	'110',b0110
	mkeyw	'1200',b1200
	mkeyw	'134.5',b01345
	mkeyw	'150',b0150
	mkeyw	'1800',b1800
	mkeyw	'19200',b19200
	mkeyw	'2000',b2000
	mkeyw	'2400',b2400
	mkeyw	'300',b0300
	mkeyw	'38400',b38400
	mkeyw	'45.5',b00455
	mkeyw	'4800',b4800
	mkeyw	'50',b0050
	mkeyw	'600',b0600
	mkeyw	'75',b0075
	mkeyw	'9600',b9600

ten	dw	10			; multiplier for setatoi
rdbuf	db	80H DUP(?)
prm	db	30 dup(0)		; Buffer for new prompt.
prmptr	dw	kerm			; pointer to prompt
defkw	db	100 dup (?)
macnum	dw	0			; one macro yet
mactab	dw	ibmmac			; default ibm mac is macro 0
	dw	macmax dup (?)		; empty macro table
defptr	dw	macbuf
macbuf	db	macmax*100 dup (?)	; buffer for macro defs
rmlft	db	setextra		; space left in set table
mcctab	db	1			; macro cmd table, one initially
	mkeyw	'IBM',0			; macro # 0
	db	setextra dup (?)	; room for more.

ibmmac	db	imlen-1
	db	'set timer on',cr,'set parity mark',cr
	db	'set local-echo on',cr,'set handshake xon',cr
	db	'set flow none',cr
imlen	equ	$-ibmmac

; structure for status information
stent	struc
sttyp	dw	?		; type (actually routine to call)
msg	dw	?		; message to print
val2	dw	?		; needed value: another message, or tbl addr
tstcel	dw	?		; address of cell to test, in data segment
basval	dw	0		; base value, if non-zero
stent	ends

sttab	stent	<onoff,vtemst,,flags.vtflg>
	stent	<onoff,locst,,ecoflg,portval>
	stent	<baudprt>
	stent	<srchkw,parmsg,partab,parflg,portval>
	stent	<onechr,escmes,,trans.escchr>
	stent	<onoff,capmsg,,flags.capflg>
	stent	<msg2,flost,floxmsg,floflg,portval>
	stent	<prhnd>
	stent	<srchkw,destst,destab,flags.destflg>
	stent	<drnum,diskst,,curdsk>
	stent	<onoff,flwon,,flags.flwflg>
	stent	<msg2,beloff,belon,flags.belflg>
	stent	<msg2,abfkst,abfdst,flags.abfflg>
	stent	<srchkw,eofmsg,seoftab,flags.eofcz>
	stent	<onechr,sqcst,,trans.rquote>
	stent	<onechr,rqcst,,trans.squote>
	stent	<onechr,rsohst,,trans.rsoh>
	stent	<onechr,ssohst,,trans.ssoh>
	stent	<stnum,rtimst,,trans.rtime>
	stent	<stnum,stimst,,trans.stime>
	stent	<stnum,rpakst,,trans.rpsiz>
	stent	<stnum,spakst,,trans.spsiz>
	stent	<stnum,snpdst,,trans.spad>
	stent	<stnum,rnpdst,,trans.rpad>
	stent	<onoff,timmsg,,flags.timflg>
	stent	<pr8bit>
	stent	<onechr,eolst,,trans.seol>
	stent	<srchkw,blokst,blktab,trans.chklen>
	stent	<msg2,cm2st,cm1st,flags.comflg>
	stent	<onoff,debon,,flags.debug>
	dw	0		; end of table
sttbuf	db	2000 dup (?)	; big buffer for status msg.
datas	ends

code	segment	public
	extrn cmcfrm:near, prserr:near, comnd:near, dobaud:near
	extrn cmgtch:near, repars:near, coms:near, vts:near, defkey:near
	extrn inicpt:near, prompt:near, nout:near, prtscr:near
	extrn prkey:near
	assume	cs:code,ds:datas

; This is the SET command.
 
SETCOM  PROC    NEAR
        mov dx,offset settab    ; Parse a keyword from the set table.
        mov bx,offset sethlp
        mov ah,cmkey
        call comnd
         jmp r
        call bx
	 nop
	 nop
	 nop
	jmp rskp
SETCOM	endp

docom	proc	near
	mov	dx,offset mcctab
	mov	bx,0
	mov	ah,cmkey
	call	comnd
	 jmp	r
	push	bx
	mov	ah,cmcfm
	call	comnd
	 pop	bx
	 ret
	 nop
	pop	bx
	cmp	taklev,maxtak		; room in take level?
	jl	docom2			; yes, continue
	mov	dx,offset ermes4	; else complain
	jmp	reterr
docom2:	inc	taklev			; increment take level (overflow)
	add	takadr,size takinfo
	shl	bx,1
	mov	si,mactab[bx]		; point to macro
	mov	cl,[si]			; get size from macro
	mov	ch,0
	inc	si			; point to actual definition
	mov	bx,takadr		; point to current buffer
	mov	[bx].takfcb,0ffh	; flag as a macro
	mov	[bx].takptr,si		; point to beginning of def
	mov	[bx].takchl,cl		; # of chars left in buffer
	mov	[bx].takcnt,cx		; and in definition
	mov	word ptr [bx].takcnt+2,0 ; zero high order...
	jmp	rskp
docom	endp
 
; the define command
dodef	proc	near
	cmp	macnum,macmax		; get current macro count
	jl	dode1			; no, go on
	mov	dx,offset ermes1	; else complain
	jmp	reterr			; and return

dode1:	mov	ah,cmtxt
	mov	bx,offset defkw+1	; buffer for keyword
	mov	dx,offset macmsg
	call	comnd
	 ret
	 nop
	 nop
	cmp	ah,0
	jne	dode2
	ret
dode2:	push	es
	mov	bx,ds
	mov	es,bx
	cld
	mov	cl,ah
	mov	ch,0			; length
	mov	si,offset defkw+1	; pointer to keyword
	mov	ah,0			; # of chars in keyword
; uppercase keyword, look for end
dode3:	lodsb				; get a byte
	cmp	al,'a'
	jb	dode4
	cmp	al,'z'
	ja	dode4
	sub	al,'a'-'A'
	mov	[si-1],al		; uppercase if necessary
dode4:	inc	ah			; increment word count
	cmp	al,' '			; is it the break character?
	loopne	dode3			; no, loop thru rest of word
dode5:	jne	dode6			; ended with break char?
	dec	ah			; yes, don't count in length
dode6:	mov	defkw,ah		; store length in front of it
	add	ah,4			; add keyword overhead length
	cmp	ah,rmlft		; will it fit in buffer
	jb	dode7			; yes, keep going
	mov	dx,offset ermes2	; else complain
	jmp	reterr

dode7:	sub	rmlft,ah		; subtract space used in tbl
	mov	di,defptr		; pointer to free space
	inc	macnum			; count the macro
	mov	bx,macnum
	shl	bx,1			; double for word idx!!!
	mov	mactab[bx],di		; install into table
	mov	[di],cl			; store length
	inc	di
	jcxz	dode10			; no copy if 0 length

; copy definition into buffer, changing commas to crs
dode8:	lodsb				; get a byte
	cmp	al,','			; comma?
	jne	dode9			; no, keep going
	mov	al,cr			; else replace with cr
dode9:	stosb
	loop	dode8			; keep copying

dode10:	mov	defptr,di		; update free ptr
	mov	bl,defkw
	mov	bh,0
	lea	di,defkw+1[bx]		; end of keyword
	mov	al,'$'
	stosb
	mov	ax,macnum
	stosb				; low-order
	mov	al,0			; high-order is always 0.
	stosb

; now install into table
	pop	es
	mov	bx,offset mcctab
	mov	dx,offset defkw
	call	addtab
	jmp	rskp
dodef	endp

; add an entry to a keyword table
; enter with bx/ table address, dx/ ptr to new entry
; no check is made to see if the entry fits in the table.
addtab	PROC	NEAR
	push	es
	cld
	mov	ax,ds
	mov	es,ax		; address data segment
	mov	bp,bx		; remember where tbl starts
	mov	cl,[bx]		; pick up length of table
	mov	ch,0
	inc	bx		; point to actual table...
addta1:	push	cx		; preserve count
	mov	si,dx		; point to entry
	lodsb			; get length of new entry
	mov	cl,[bx]		; and length of table entry...
	mov	ah,0		; assume they're the same size
	cmp	al,cl		; are they the same?
	lahf			; remember result of comparison...
	jae	addta2		; is new smaller? no, use table length
	mov	cl,al		; else use length of new entry
addta2:	mov	ch,0
	lea	di,[bx+1]	; point to actual keyword
	repe	cmpsb		; compare strings
	pop	cx		; restore count
	jb	addta4		; below, insert before this one
	jne	addta3		; not below or same, keep going
	sahf			; same. get back result of length comparison
	jb	addta4		; if new len is smaller, insert here
	jne	addta3		; if not same size, keep going
	mov	si,bx		; else this is where entry goes
	jmp	short addta6	; no insertion required...
addta3:	mov	al,[bx]
	mov	ah,0
	add	bx,ax		; skip this entry
	add	bx,4		; len + $ + value...
	loop	addta1		; and keep looking
addta4:	mov	si,bx		; this is first location to move
	mov	di,bx
	inc	ds:byte ptr [bp] ; remember we're adding one...
	jcxz	addta6		; no more entries, forget this stuff
	mov	bh,0		; this stays 0
addta5:	mov	bl,[di]		; get length
	lea	di,[bx+di+4]	; end is origin + length + 4 for len, $, value
	loop	addta5		; loop thru remaining keywords
	mov	cx,di
	sub	cx,si		; compute # of bytes to move
	push	si		; preserve loc for new entry
	mov	si,di		; first to move is last
	dec	si		; minus one
	mov	di,dx		; new entry
	mov	bl,[di]		; get length
	lea	di,[bx+si+4]	; dest is source + length of new + 4
	std			; move backwards
	rep	movsb		; move the table down
	cld			; put flag back
	pop	si
addta6:	mov	di,si		; this is where new entry goes
	mov	si,dx		; this is where it comes from
	mov	cl,[si]		; length
	mov	ch,0
	add	cx,4		; overhead bytes
	rep	movsb		; stick it in
	pop	es
	ret			; and return
addtab	endp

; Show defined macros.
SHOMAC	PROC	NEAR
	mov ah,cmtxt
	mov bx,offset rdbuf
	mov dx,offset shmmsg
	call comnd
	 jmp r 
	cmp ah,0		; Bare CR means show all macros.
	jne shom2		; No, he wants specific macro expanded.
	mov si,offset mcctab	; Table of macro names.
	lodsb
	mov cl,al		; Number of macro entries.
	mov ch,0
shom0:	jcxz shom1		; Done if none left to display.
	lodsb			; Length of macro name.
	push ax			; Don't forget it.
	mov ah,prstr
	mov dx,offset crlfsp	; Go to new line.
	int dos
	mov dx,si		; Print macro name.
	int dos
	mov dx,offset eqs
	int dos
	pop ax
	mov ah,0
	add si,ax		; Skip over name.
	inc si			; Get to macro number.
	mov bx,[si]		; Pick it up.
	call expmac		; Expand the macro.
	dec cx
	add si,2		; Skip over macro number.
	jmp shom0		; And do the rest.
shom1:	mov ah,prstr
	mov dx,offset crlf
	int dos
	jmp rskp
shom2:	mov ah,prstr
	mov dx,offset ermes3
	int dos
	jmp rskp
SHOMAC	ENDP

; Expand the macro, called with BX/macro number.
expmac:	push si
	push cx
	mov si,offset mactab	; Table of address expansions.
	shl bx,1		; Double and use as index into table.
	mov si,[si+bx]		; Get address of expansion in question.
	mov ax,si		; Address of string.
	inc ax			; Don't print length.
	mov cl,[si]		; Length of string.
	mov ch,0
	call prkey		; Print it.
	pop cx
	pop si
	ret

seteof	proc	near
	mov ah,cmkey
	mov bx,0
	mov dx,offset seoftab
	call comnd
	 jmp r
	push bx
	mov ah,cmcfm
	call comnd
	 jmp seteo1		; error return...
	 nop
	pop bx
	mov flags.eofcz,bl	; set value
	jmp rskp		; and return
seteo1:	pop bx
	ret
seteof	endp

;       This is the ESCAPE character SET subcommand.     [6 start]
 
ESCAPE  PROC    NEAR
	call cmgtch		; Get a char.
	cmp ah,0
	jns es1			; Terminator or no?
	and ah,7FH		; Turn off minus bit.
	cmp ah,'?'
	jne es0
	mov dx,offset eschlp
	mov ah,prstr
	int dos
	mov dx,offset crlf
	int dos
	mov dx,comand.cmprmp
	int dos
	mov bx,comand.cmdptr
	mov al,'$'
	mov [bx],al
	mov dx,offset comand.cmdbuf
	int dos
	dec comand.cmcptr		; Ignore dollar sign.
	dec comand.cmccnt
	mov comand.cmaflg,0
	jmp repars
es0:	mov ah,prstr
	mov dx,offset ermes3
	int dos
	ret
es1:  	mov temp,ax
	call cmcfrm
	 jmp es0
	 nop			; Take up 3 bytes.
	mov ax,temp
	mov trans.escchr,ah	; Save new value.
	ret
ESCAPE  ENDP			; [6 end]

; 	This is the End-of-line character SET subcommand.

EOLSET	PROC	NEAR
	mov min,0
	mov max,1FH
	mov sum,0
	mov tmp,10
	mov temp1,0
	mov desta,offset trans.seol
	mov numhlp,offset eolhlp
	mov numerr,offset eolerr
	jmp num0		; Common routine for parsing numerical input.
EOLSET	ENDP

num0:	call cmgtch		; Get the first char into AH.
	cmp ah,0
	js num1
	cmp ah,'0'
	jl num1
	cmp ah,'9'
	ja num1
	mov temp1,1
	sub ah,30H
	mov dl,ah
	mov al,sum
	mul tmp
	add al,dl
	mov sum,al
	jmp num0
num1:	and ah,7FH
	cmp ah,CR
	jne num2
	cmp temp1,0
	je num21
	mov al,sum
	cmp al,min
	jl num3
	cmp al,max
	jg num3
	mov bx,desta
	mov [bx],al
	ret
num2:	cmp ah,03FH		; Question mark?
	je num4
num21:	mov ah,prstr
	mov dx,offset ermes3
	int dos
	jmp prserr
num3:	mov ah,prstr
	mov dx,numerr
	int dos
	jmp prserr
num4:	mov ah,prstr
	mov dx,numhlp
	int dos
	mov dx,offset crlf
	int dos
	mov dx,comand.cmprmp
	int dos
	mov bx,comand.cmdptr
	mov al,'$'
	mov [bx],al
	mov dx,offset comand.cmdbuf
	int dos
	dec comand.cmcptr		; Don't count the dollar sign.
	dec comand.cmccnt		; Or the question mark.
	mov comand.cmaflg,0		; Check for more input.
	jmp repars
 
;       This is the LOCAL echo SET subcommand.
 
LCAL    PROC    NEAR
        mov dx,offset ontab
        mov bx,0
        mov ah,cmkey
        call comnd
         jmp r
        push bx                 ; Save the parsed value.
        mov ah,cmcfm
        call comnd              ; Get a confirm.
         jmp lcl0		;  Didn't get a confirm.
	 nop
        pop bx
	mov si,portval
        mov [si].ecoflg,bl     ; Set the local echo flag.
	mov [si].hndflg,bl	; This goes on/off with local echo.
	xor bl,01		; Toggle this.
	mov [si].floflg,bl	; This is the opposite.
	ret
lcl0:	pop bx
	ret
LCAL    ENDP
 
;       This is the VT52 emulation SET subcommand.
 
VT52EM  PROC    NEAR
	call vts
	ret
VT52EM  ENDP
 
; This is the SET subcommand to choose between COM1 and COM2. [19b]
  
COMSET  PROC    NEAR
	call coms
	ret
COMSET  ENDP

FILWAR  PROC    NEAR
        mov dx,offset ontab
        mov bx,0
        mov ah,cmkey
        call comnd
         jmp r
        push bx
        mov ah,cmcfm
        call comnd              ; Get a confirm.
         jmp fil0		; Didn't get a confirm.
	 nop
        pop bx
        mov flags.flwflg,bl     ; Set the filewarning flag.
	ret
fil0:	pop bx
	ret
FILWAR  ENDP

;       This is the SET aborted-file command.  [20d]
 
ABFSET  PROC    NEAR
        mov dx,offset abftab
        mov bx,0
        mov ah,cmkey
        call comnd
         jmp r
        push bx
        mov ah,cmcfm
        call comnd              ; Get a confirm.
         jmp abf0		;  Didn't get a confirm.
	 nop
        pop bx
        mov flags.abfflg,bl     ; Set the aborted file flag.
	ret
abf0:	pop bx
	ret
ABFSET  ENDP

;       This is the SET Parity command.				[10 start]
 
SETPAR  PROC    NEAR
        mov dx,offset partab
        mov bx,0
        mov ah,cmkey
        call comnd
         jmp r
        push bx
        mov ah,cmcfm
        call comnd              ; Get a confirm.
         jmp par0		;  Didn't get a confirm.
	 nop
        pop bx
	mov si,portval
        mov [si].parflg,bl	; Set the parity flag.
	cmp bl,parnon		; Resetting parity to none? [21b]
	je setp0		; Yes, reset 8 bit quote character. [21b]
	mov trans.ebquot,dqbin	; Else, do quoting.  [21b]
	ret			; That's it.  [21b]
setp0:	mov trans.ebquot,'Y'	; If none, say will quote upon request. [21b]
	ret
par0:	pop bx
	ret
SETPAR  ENDP							; [10 end]

; Sets debugging mode on and off.

DEBST	PROC    NEAR
        mov dx,offset ontab
        mov bx,0
        mov ah,cmkey
        call comnd
         jmp r
        push bx
        mov ah,cmcfm
        call comnd              ; Get a confirm.
         jmp deb0		; Didn't get a confirm.
	 nop
        pop bx
        mov flags.debug,bl	; Set the DEBUG flag.
	ret
deb0:	pop bx
	ret
DEBST   ENDP

; Turn bell on or off.    [17a start]

BELLST	PROC	NEAR
	mov dx,offset ontab
	mov bx,0
	mov ah,cmkey
	call comnd
	 jmp r
	push bx
	mov ah,cmcfm
	call comnd
	 jmp bel0
	 nop
	pop bx
	mov flags.belflg,bl
	ret
bel0:	pop bx
	ret
BELLST	ENDP                      ;  [17a end]

; Toggle echo'ing of TAKE file to be either ON or OFF.
TAKSET	PROC	NEAR
	mov dx,offset ontab
	mov bx,0
	mov ah,cmkey
	call comnd
	 jmp r
	push bx
	mov ah,cmcfm
	call comnd
	 jmp tak0
	 nop
	pop bx
	mov flags.takflg,bl
	ret
tak0:	pop bx
	ret
TAKSET	ENDP                      ;  [17a end]

; Set timer ON/OFF during file transfer.
TIMSET	PROC	NEAR
	mov dx,offset ontab
	mov bx,0
	mov ah,cmkey
	call comnd
	 jmp r
	push bx
	mov ah,cmcfm
	call comnd
	 jmp tim0
	 nop
	pop bx
	mov flags.timflg,bl
	ret
tim0:	pop bx
	ret
TIMSET	ENDP                      ;  [17a end]

; Allow user to change the "Kermit-MS>" prompt.
PROMSET	PROC	NEAR
	mov ah,cmtxt
	mov bx,offset prm		; Read in the prompt.
	mov dx,offset prmmsg
	call comnd
	 jmp r
	cmp ah,0			; Just a bare CR?
	jne prom0
	mov ax,offset kerm
	jmp prom1
prom0:	mov byte ptr [bx],'$'		; End of string.
	mov ax,offset prm
prom1:	mov prmptr,ax			; Remember it.
	jmp rskp
PROMSET	ENDP

; Set Flow-Control subcommand.
FLOSET	PROC	NEAR
        mov dx,offset flotab
  	xor bx,bx
        mov ah,cmkey
        call comnd
         jmp r
        push bx
        mov ah,cmcfm
        call comnd              ; Get a confirm.
         jmp flox		; Didn't get a confirm.
	 nop
        pop bx
	mov si,portval
	mov [si].flowc,bx	; Flow control value.
	cmp bx,0		; Turning it off?
	je flo0			; Yes.
        mov [si].floflg,1	; Say we're doing flow control.
	mov [si].hndflg,0	; So don't do handshaking.
	ret
flo0:	mov [si].floflg,bl	; Say we're not doing flow control.
	ret
flox:	pop bx
	ret
FLOSET	ENDP

; Set Handshake subcommand.
HNDSET	PROC	NEAR
        mov dx,offset hndtab
        mov bx,0
        mov ah,cmkey
        call comnd
         jmp r
        push bx
        mov ah,cmcfm
        call comnd              ; Get a confirm.
         jmp hndx		; Didn't get a confirm.
	 nop
        pop bx
	mov si,portval
	cmp bl,0		; Setting handshake off?
	je hnd0			; Yes.
	mov [si].floflg,0	; Else, turn flow control off.
	mov [si].hndflg,1	; And turn on handshaking.
	mov [si].hands,bl	; Use this char as the handshake.
	ret
hnd0:	mov [si].hndflg,0	; No handshaking.
	mov [si].floflg,1	; If one is off, the other is on.
	ret
hndx:	pop bx
	ret
HNDSET	ENDP

; Set block check type sub-command.
BLKSET	PROC	NEAR
        mov dx,offset blktab
        mov bx,0
        mov ah,cmkey
        call comnd
         jmp r
        push bx
        mov ah,cmcfm
        call comnd              ; Get a confirm.
         jmp blk0		; Didn't get a confirm.
	 nop
        pop bx
	mov trans.chklen,bl	; Use this char as the handshake.
	mov inichk,bl		; Save here too.
	ret
blk0:	pop bx
	ret
BLKSET	ENDP

; Set destination for incoming file.
DESSET	PROC	NEAR
        mov dx,offset destab
        mov bx,0
        mov ah,cmkey
        call comnd
         jmp r
        push bx
        mov ah,cmcfm
        call comnd              ; Get a confirm.
         jmp des0		; Didn't get a confirm.
  	 nop
        pop bx
        mov flags.destflg,bl	; Set the destination flag.
	ret
des0:	pop bx
	ret
DESSET	ENDP

; Set default disk for sending/receiving, etc.
DSKSET	PROC	NEAR
	mov comand.cmcr,1	; Don't want filename specified.
	mov ah,cmifi		; Parse for drive specification.
	mov dx,offset rdbuf	; Read into handy buffer.
	mov bx,offset dskhlp	; Text of help message.
	call comnd
	 jmp r
	mov ah,cmcfm
	call comnd
	 jmp r
	cmp flags.nmoflg,0	; Fail if specified file name.
	je dsk1
dsk0:	mov ah,prstr
	mov dx,offset dskerr	; Illegal drive specification.
	int dos
	ret
dsk1:	mov bx,offset rdbuf
	mov ah,[bx]		; Get the drive they said to use.
	cmp ah,0		; Did they type a bare CR?
	je dsk0			; Yes, complain.
	mov curdsk,ah		; And remember it.
	dec ah
	mov dl,ah
	mov ah,seldsk
	int dos
	ret
DSKSET	ENDP	

;  This function sets the baud rate.

BAUDST  PROC    NEAR
        mov dx,offset bdtab
        mov bx,0
        mov ah,cmkey
        call comnd
         jmp r
	push bx
	mov ah,cmcfm
	call comnd		; Get a confirm.
	 jmp bau0		; Didn't get one.
 	 nop
	pop bx
	mov si,portval
	mov ax,[si].baud	; Remember original value. [25]
	mov [si].baud,bx	; Set the baud rate.
	call dobaud		; Use common code. [19a] 
	ret
bau0:	pop bx
	ret
BAUDST  ENDP

SENDSET	PROC	NEAR
	mov stflg,'S'		; Setting SEND parameter 
sndst0: mov dx,offset stsrtb    ; Parse a keyword.
        mov bx,0
        mov ah,cmkey
        call comnd
         jmp r
        call bx
	 nop
	 nop
	 nop
	jmp rskp
SENDSET	ENDP

recset:	mov stflg,'R'		; Setting RECEIVE paramter.
	jmp sndst0

remset	proc	near
	mov	ah,cmkey
	mov	dx,offset ontab
	mov	bx,0
	call	comnd
	 jmp	r
	push	bx		; save parsed value
	mov	ah,cmcfm
	call	comnd		; confirm
	 pop	bx
	 ret			; return on failure
	 nop
	pop	bx
	mov	flags.remflg,bl	; set remote setting
	jmp	rskp		; and return
remset	endp

; Set send/receive start-of-header.
srsoh:	mov min,0
	mov max,1FH
	mov sum,0
	mov tmp,10
	mov desta,offset trans.ssoh	; Assume SEND.
	cmp stflg,'S'			; Setting SEND paramter?
	je srsoh0
	mov desta,offset trans.rsoh
srsoh0:	mov numhlp,offset eolhlp	; Reuse help message.
	mov numerr,offset soherr
	mov temp1,0
	jmp num0		; Common routine for parsing numerical input.

; Set send/receive timeout.
srtim:	mov min,0
	mov max,94
	mov sum,0
	mov tmp,10
	mov desta,offset trans.stime	; Assume SEND.
	cmp stflg,'S'			; Setting SEND paramter?
	je srtim0
	mov desta,offset trans.rtime
srtim0:	mov numhlp,offset timhlp	; Reuse help message.
	mov numerr,offset timerr
	mov temp1,0
	jmp num0		; Common routine for parsing numerical input.

; Set send/receive packet length.
srpack:	mov min,20
	mov max,94
	mov sum,0
	mov tmp,10
	mov desta,offset trans.spsiz
	cmp stflg,'S'		; Setting SEND paramter?
	je srpak0
	mov desta,offset trans.rpsiz
srpak0:	mov numhlp,offset pakhlp
	mov numerr,offset pakerr
	mov temp1,0
	jmp num0		; Parse numerical input.

; Set send/receive number of padding characters.
srnpd:	mov min,0
	mov max,99
	mov sum,0
	mov tmp,10
	mov desta,offset trans.spad
	cmp stflg,'S'		; Setting SEND paramter?
	je srnpd0
	mov desta,offset trans.rpad
srnpd0:	mov numhlp,offset npdhlp
	mov numerr,offset npderr
	mov temp1,0
	jmp num0		; Parse numerical input.

; Set send/receive padding character.
srpad:	mov min,0
	mov max,127
	mov sum,0
	mov tmp,10
	mov srtmp,0FFH		; Haven't seen anything yet.
	mov desta,offset srtmp
	mov numhlp,offset padhlp
	mov numerr,offset paderr
	mov temp1,0
	mov savsp,sp
	call num0		; Parse numerical input.
	mov sp,savsp
	mov temp,offset trans.spadch
	cmp stflg,'S'
	je srpad1
	mov temp,offset trans.rpadch
srpad1:	mov bx,offset srtmp
	mov ah,[bx]
	cmp ah,0FFH		; Did they end up not doing the command?
	je srpad3
	cmp ah,127		; This is allowed.
	je srpad2
	cmp ah,32
	jb srpad2		; Between 0 and 31 is OK too.
	mov ah,prstr
	mov dx,offset paderr
	int dos
	ret
srpad2:	mov bx,temp		; Set the real pad char.
	mov [bx],ah
srpad3:	ret

; Set send/receive control character prefix.
srquo:	mov min,33
	mov max,126
	mov sum,0
	mov tmp,10
	mov desta,offset trans.rquote	; Used for outgoing packets.
	cmp stflg,'S'			; Setting outgoing quote char?
	je srquo0	
	mov desta,offset trans.squote	; For incoming quote char.
srquo0:	mov numhlp,offset quohlp
	mov numerr,offset quoerr
	mov temp1,0
	jmp num0			; Parse numerical input.

;       This is the STATUS command.
 
STATUS  PROC    NEAR
        mov ah,cmcfm
        call comnd              ; Get a confirm.
         jmp r                  ;  Didn't get a confirm.
	mov dx,offset crlf
	mov ah,prstr
	int dos			; initial crlf
        call stat0
	mov cx,di		; End of buffer
	sub cx,ax		; Get length of buffer.
	dec cx			; Account for null.
	mov di,ax		; Buffer pointer.
	call prtscr		; Put data onto the screen. 
        jmp rskp
STATUS	ENDP
 
; Return a pointer to status message in AX, ptr to end in DI.

STAT0   PROC    NEAR
	push	es
	mov	ax,ds
	mov	es,ax		; address data segment
	cld			; make sure strings go the right way
	mov	di,offset sttbuf ; point to destination buffer
	mov	bx,offset sttab	; table to control printing
	mov	al,' '		; start with a space
	stosb			; in the buffer
	mov	ax,0		; need-new-line flag
stat01:	cmp	word ptr [bx],0	; end of table?
	je	stat02		; yes, exit routine
	push	bx
	push	di		; remember important values
	push	ax
	call	[bx].sttyp	; call the appropriate routine
	pop	ax
	pop	cx		; return buffer value
	pop	bx		; and ptr
	or	ax,ax		; do we need a newline?
	jne	stat03		; yes, go put one in
	sub	cx,di		; else see how many columns they used
	add	cx,40		; this is where we'd like to be
; if cx is negative here, we have a problem...
	mov	al,' '
	rep	stosb		; add right # of spaces
	mov	ax,1		; note we need a newline next time
	jmp	short stat04	; and keep looping around
stat03:	mov	cx,3
	mov	si,offset crlfsp
	rep	movsb		; append crlf to string
	xor	ax,ax		; reset newline flag
stat04:	add	bx,size stent	; advance to next one
	jmp	stat01
stat02:	mov	al,0		; end buffer
	stosb
	mov	ax,offset sttbuf
	pop	es		; restore this
	ret			; and return
STAT0	ENDP

; handler routines for status
; all are called with di/ destination buffer, bx/ stat ptr.  They
; can change any register but the segment registers, must update
; di to the end of the buffer.

; copy the message into the buffer
stmsg	proc	near
	mov	si,[bx].msg	; get message address
stms1:	lodsb			; get a byte
	stosb			; drop it off
	cmp	al,'$'		; end of message?
	jne	stms1		; no, keep going
	dec	di		; else back up ptr
	ret			; and return
stmsg	endp

; get address of test value in stent.  Returns address in si
stval	proc	near
	mov	si,[bx].basval	; get base value
	cmp	si,0		; any there?
	je	stva1		; no, keep going
	mov	si,[si]		; yes, use as base address
stva1:	add	si,[bx].tstcel	; add offset of test cell
	ret			; and return it
stval	endp

; print a single character
onechr	proc	near
	call	stmsg		; copy message part first
	call	stval		; pick up test value address
	mov	al,[si]		; this is char to print
	cmp	al,' '		; printable?
	jae	onech1		; yes, keep going
	add	al,64		; make printable.
	mov	byte ptr [di],'^'
	inc	di		; note ctrl char
onech1:	stosb			; drop char off
	ret			; and return
onechr	endp

; numeric field...
stnum	proc	near
	call	stmsg		; copy message
	call	stval		; pick up value address
	mov	al,[si]		; get value
	mov	ah,0		; high order is 0
	call	outnum		; put number into buffer
	ret			; and return
stnum	endp

; translate the number in ax...
outnum	proc	near
	cwd
	mov	bx,10
	div	bx		; divide to get digit
	push	dx		; save remainder digit
	or	ax,ax		; test quotient
	jz	outnu1		; zero, no more of number
	call	outnum		; else call for rest of number
outnu1:	pop	ax		; get digit back
	add	al,'0'		; make printable
	stosb			; drop it off
	ret			; and return
outnum	endp

; on/off field
onoff	proc	near
	call	stmsg		; copy message
	call	stval		; get value cell
	mov	al,[si]
	mov	si,offset onmsg
	mov	cx,2		; assume 2-byte 'ON' message
	or	al,al		; test value
	jnz	onof1		; on, have right msg
	mov	si,offset offmsg
	mov	cx,3
onof1:	rep	movsb		; copy right message in
	ret			; and return
onoff	endp

; print first message if false, second if true
msg2	proc	near
	call	stval		; get value cell
	mov	al,[si]
	mov	si,[bx].msg	; assume off
	or	al,al		; is it?
	jz	msg21		; yes, continue
	mov	si,[bx].val2	; else use alternate message
msg21:	jmp	stms1		; handle copy and return
msg2	endp

; search a keyword table for a value, print that value
srchkw	proc	near
	call	stmsg		; first print message
	call	stval
	mov	al,[si]		; get value to hunt for
	mov	ah,0		; high order is 0
	mov	bx,[bx].val2	; this is table address
	jmp	prttab		; and look in table.
srchkw	endp

; Print the drive name.
drnum	proc	near
	call	stmsg		; copy message part first
	call	stval		; pick up test value address
	mov	al,[si]		; this is char to print
	add	al,'@'		; Make it printable.
	stosb
	mov	byte ptr [di],':'
	inc	di		; end with a colon
	ret			; and return
drnum	endp

; print 8-bit quoting
pr8bit	proc	near
	mov	bl,trans.ebquot	; get quote char
	mov	si,offset ebyst	; assume no 8-bit quoting
	cmp	bl,'Y'		; on request only?
	je	pr8bi1		; yes, continue
	mov	si,offset ebvst	; else variable
pr8bi1:	call	stms1		; copy message in
	cmp	bl,'Y'		; not doing it?
	je	pr8bi2		; no, forget this part
	mov	[di],bl		; else drop off char too
	inc	di
pr8bi2:	ret			; and return
pr8bit	endp

; Print the handshake.
prhnd:	mov si,offset handst	; copy in initial message
	call stms1
	mov si,offset nonmsg	; assume no handshake
	mov bx,portval
	cmp [bx].hndflg,0	; Is handshaking in effect?
	jne prh0		; Yes, print what we're using.
	jmp stms1		; no, say so and return
prh0:	mov al,'^'		; Doing handshaking with control char.
	stosb
	mov al,[bx].hands
	add al,40H		; Make printable.
	stosb			; put in buffer
	ret			; and return

; Print the pad character in AL.
prpad:	cmp al,127		; Are they using a delete?
	jne prpad0
	mov ah,prstr
	mov dx,offset delmsg
	int dos
	ret
prpad0:	mov dl,'^'
	mov ah,conout
	push ax
	int dos
	pop ax
	mov dl,al
	add dl,40H		; Make printable.
	int dos
	ret

; Print value from table.  BX/address of table, AL/value of variable.
prttab:	mov cl,[bx]		; Number of entries in our table.
	inc bx			; Point to the data.
prtt0:	mov dl,[bx]		; Length of keyword.
	inc bx			; Point to keyword.
	mov dh,0
	inc dx			; Account for "$" in table.
	mov si,dx		; Put to index register.
	cmp ax,[bx+si]		; Is this the one?
	je prtt1
	add bx,dx		; Go to end of keyword.
	add bx,2		; Point to next keyword.
	dec cl			; Any more keywords to check?
	jnz prtt0		; Yes, go to it.
	mov bx,offset prterr
prtt1:	mov si,bx
prtt2:	jmp stms1		; copy in message
	ret			; and return

;	This routine prints out the escape character in readable format.  

ESCPRT	PROC	NEAR		; [6 start]
	mov dl,trans.escchr
	cmp dl,' '
	jge escpr2
	push dx
	mov ah,prstr
	mov dx,offset esctl
	int dos
	pop dx
	add dl,040H		; Make it printable.
escpr2:	mov ah,conout
	int dos
	ret
ESCPRT	ENDP			; [6 end]
 
; Print information on the baud rate. [19a]

BAUDPRT	PROC	 NEAR
	mov si,portval
	mov ax,[si].baud
	mov dx,offset b48st	; Assume 4800 baud.
	cmp ax,B4800
	jnz bdprt0
	jmp bdprt2
bdprt0:	mov dx,offset b12st
	cmp ax,B1200
	jnz bdprt1
	jmp bdprt2
bdprt1:	mov dx,offset b18st
	cmp ax,B1800
	jz bdprt2
	mov dx,offset b24st
	cmp ax,B2400
	jz bdprt2
	mov dx,offset b96st
	cmp ax,B9600
	jz bdprt2
	mov dx,offset b03st
	cmp ax,B0300
	jz bdprt2
	mov dx,offset b04st
	cmp ax,B00455
	jz bdprt2
	mov dx,offset b05st
	cmp ax,B0050
	jz bdprt2
	mov dx,offset b07st
	cmp ax,b0075
	jz bdprt2
	mov dx,offset b11st
	cmp ax,B0110
	jz bdprt2
	mov dx,offset b13st
	cmp ax,B01345
	jz bdprt2
	mov dx,offset b15st
	cmp ax,B0150
	jz bdprt2
	mov dx,offset b06st
	cmp ax,B0600
	je bdprt2
	mov dx,offset b20st
	cmp ax,B2000
	jz bdprt2
	mov dx,offset b19st
	cmp ax,B19200
	jz bdprt2
	mov dx,offset b38st
	cmp ax,B38400
	jz bdprt2
	mov dx,offset unrec	; Unrecognized baud rate.
bdprt2:	mov si,dx		; this is baud rate
bdprt3:	jmp stms1		; go copy it and return
BAUDPRT	ENDP
 
setkey	proc	near		
	cmp	setktab,0	; any table?
	jne	setk0		; yes, use it
	mov	dx,offset ermes5
	jmp	reterr		; else print error message
setk0:	mov	dx,offset setktab	; set key options
	mov	bx,offset setkhlp
	mov	ah,cmkey
	call	comnd
	 jmp	r
	cmp	bx,-1		;[jd] do we have scan code?
	jne	setk1		;[jd] yes, skip this part

	mov	ah,cmtxt
	mov	bx,offset rdbuf	; handy buffer
	mov 	dx,offset sk1msg
	call	comnd
	 jmp	r		; fail return
	mov	si,offset rdbuf	; this is parsed number
	call	atoi		; Convert input to real number.
	 jmp	reterr		; No good.
	mov	bx,ax		; put accumulation into bl
setat3:	cmp	bx,0		; is scan code 0?
	jne	setk2		; no, have scan code, look for def

setk1:	push	bx		; save our scan code
	mov	ah,cmcfm
	call	comnd
	 jmp 	short setkx	; no good, pop bx and return
	nop			; waste a byte
	pop	bx
; scan code is in bl, ask for string part
setk2:	push	bx
	mov	dx,offset defpmp
	call	prompt
	mov	ah,cmtxt
	mov	bx,offset rdbuf
	mov	dx,offset sk2msg
	call	comnd		; read the definition
	 jmp	short setkx	; pop bx and fail return
	 nop
	mov	cl,ah
	mov	ch,0		; set up length of definition
	pop	ax		; get scan code back
	mov	si,offset rdbuf	; point to definition
	call	defkey		; go define the key
	ret			; use ret for now...
	jmp	rskp		; and return
setkx:	pop	bx		; pop junk off stack
	ret			; and return
setkey	endp

; Convert input in buffer pointed to by SI to real number which is returned
; in AX.  Return on failure, return skip on success.
ATOI	PROC	NEAR
	mov	cl,ah		; Number of chars of input.
	mov	ch,0		; size of string
	jcxz	atoi4		; Fail on no input.
	mov	ax,0		; init sum
	mov	bh,0		; high order of this stays 0.
atoi0:	xchg	al,bl		; save current sum
	lodsb			; grab a byte
	cmp	al,' '		; leading space?
	jne	atoi1		; no, continue
	xchg	al,bl		; put sum back
	jmp	short atoi2	; and continue loop
atoi1:	cmp	al,'9'
	ja	atoi3		; out of range, done
	cmp	al,'0'
	jb	atoi3
	xchg	al,bl		; put sum back into al
	mul	ten		; shift one digit
	sub	bl,'0'		; convert to binary
	add	ax,bx		; add to sum
atoi2:	loop	atoi0		; loop thru all chars
atoi3:	jmp	rskp
atoi4:	mov	dx,offset erms23	; complain and return
	ret
ATOI	ENDP

;  addition for capture of raw output

setcpt	proc	near
	test	flags.capflg,0FFH
	jz	setcp1			; no capture file, keep going
	mov	dx,offset erms24
	jmp	reterr
setcp1:	mov 	comand.cmcr,0		; Filename must be specified.
	mov	ah,cmifi
	mov	dx,offset cptfcb
	mov 	bx,offset filhlp
	call	comnd
	 jmp	r
	mov	ah,cmcfm
	call	comnd			; confirm with carriage return
	 jmp	r
	mov	ah,delf
	mov	dx,offset cptfcb
	int	dos			; open up file
	mov	ah,makef
	mov	dx,offset cptfcb
	int	dos
	mov 	cptfcb+32,0

	call	inicpt			; init capture variables
	mov	flags.capflg,0FFH	; know we have capture routine
	jmp	rskp		; and return

setcpt	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

; routine to print an error message, then retskp
; expects message in dx
reterr	proc	near
	mov	ah,prstr
	int	dos
	jmp	rskp
reterr	endp

code	ends 
	end//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
	/bin/chmod 640 msset.asm
	/bin/echo -n '	'; /bin/ls -ld msset.asm
fi



More information about the Comp.sources.unix mailing list