Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Posting-Version: version B 2.10.1 6/24/83; site ut-ngp.UUCP Path: utzoo!linus!philabs!cmcl2!seismo!ut-sally!ut-ngp!knutson From: knutson@ut-ngp.UUCP (Jim Knutson) Newsgroups: net.sources Subject: MS-DOS Kermit sources (Part 3 of 7) Message-ID: <1006@ut-ngp.UUCP> Date: Fri, 5-Oct-84 12:05:53 EDT Article-I.D.: ut-ngp.1006 Posted: Fri Oct 5 12:05:53 1984 Date-Received: Sun, 7-Oct-84 04:03:18 EDT Organization: U.Texas Computation Center, Austin, Texas Lines: 3547 : 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 stentstent stent stent stent stent stent stent stent stent stent stent stent stent stent stent stent stent stent stent stent stent stent stent stent stent stent stent stent stent 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