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