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