NAME ccsrcv ; File CCSRCV.ASM ;CHINESE ifdef MSDOS include mssrcv.dat else include ccsrcv.dat endif code segment public 'code' extrn gofil:near, outbuf:near, comnd:near extrn spack:near, rpack:near, serini:near, serrst:near extrn spar:near, rpar:near, init:near, cxmsg:near, perpos:near extrn error:near, error1:near, ptchr:near, erpos:near, rtpos:near extrn stpos:near, rprpos:near, nppos:near, nout:near extrn dodec:near, doenc:near, errpack:near, intmsg:near extrn send11:near, clrmod:near, ihostr:near extrn begtim:near, endtim:near, pktsize:near,strlen:near,strcpy:near assume cs:code, ds:datas ; Update retry count and fall through to send a NAK NAK0: call updrtr ; Update retry count nak1: cmp flags.cxzflg,'E' ; Protocol abort sign? jne nak2 ; ne = no ret ; return to do current ('A') state nak2: cmp flags.cxzflg,'C' ; Control-C abort? jne nak ; ne = no mov pack.state,'A' ; set Abort state ret NAK: mov ax,pack.pktnum ; Get the packet number we're waiting for mov pack.seqnum,ax mov pack.datlen,0 ; no data add fsta.nakscnt,1 ; count NAKs sent mov ah,'N' ; NAK that packet call spack jmp abort ; failed nop ret updrtr: cmp pack.state,'A' ; Supposed to abort? je upd0 ; Yes, don't bother with retry count inc pack.numrtr ; Increment the number of retries cmp flags.xflg,1 ; Writing to screen? je upd0 ; e = yes, skip this cmp pack.numrtr,0 ; non-zero item to display? je upd0 ; nothing to display push ax ; save packet type in ah call rtpos ; Position cursor mov ax,pack.numrtr call nout ; Write the number of retries pop ax ; recover packet type in ah upd0: ret ; Abort ABORT PROC NEAR cmp filopn,0 ; Disk file open? je abort0 ; e = no so don't close cmp flags.xflg,1 ; Writing to the screen? je abort0 ; Yes, don't close "file" call outbuf ; flush last buffer to disk, ignore errors nop nop nop mov ah,close2 ; DOS 2.0 file close push bx mov bx,diskio.handle ; file handle int dos pop bx mov filopn,0 ; say file is no longer open cmp flags.abfflg,0 ; save file after closing? je abort0 ; e = yes push dx mov dx,offset diskio.string ; get back file name mov ah,del2 ; delete the file int dos pop dx abort0: mov pack.state,'A' ; Otherwise abort mov byte ptr locfil,0 ; clear local filename or errlev,2 ; set DOS error level or fsta.xstatus,2 ; set status mov kstatus,2 ; global status xor ax,ax ; tell statistics this is a receive operation call endtim ; stop file timer ret ABORT ENDP ackpak proc near ; send an ACK packet mov ah,'Y' ; ack packet call spack jmp abort ; failed nop ret ackpak endp ; init variables for read... rrinit proc near mov pack.numpkt,0 ; Set the number of packets to zero mov pack.numrtr,0 ; Set the number of retries to zero mov pack.pktnum,0 ; Set the packet number to zero mov pack.numtry,0 ; Set the number of tries to zero mov filopn,0 ; say no file opened yet ret rrinit endp ; RECEIVE command -- Some code moved to the GET routine READ PROC NEAR mov flags.nmoflg,0 ; Override file name from other host ; mov bx,offset filhlp2 ; Text of help message mcmsgb filhlp2, cfilhlp2 mov dx,offset locfil ; local file name string mov byte ptr locfil,0 ; clear it first mov ah,cmfile ; allow path names call comnd ret nop nop cmp ah,0 ; was an override filename given? je read0 ; e = no mov flags.nmoflg,1 ; yes, set flag = use this filename read0: mov ah,cmcfm ; Get a confirm call comnd ret nop nop mov pack.state,'R' ; Set the state to receive initiate mov flags.getflg,0 ; Reset flag (not a Get command) mov flags.xflg,0 call serini ; initialize serial port jnc read0b ; nc = success or errlev,2 ; set DOS error level or fsta.xstatus,2 ; set status, failed or kstatus,2 ; global status test flags.remflg,dquiet ; quiet display mode? jnz read0a ; nz = yes. Don't write to screen mov ah,prstr ; mov dx,offset infms4 ; Failed message mcmsg infms4, cinfms4 int dos read0a: ret ; return failure read0b: call rrinit ; init variables for read call init ; setup display form call ihostr ; initialize the host READ12: ; Called by GET & SRVSND, display ok mov kstatus,0 ; global status, success call begtim ; start next statistics group mov flags.cxzflg,0 ; Reset ^X/^Z flag mov ah,trans.chklen ; get desired checksum length mov curchk,ah ; and remember it here test flags.remflg,dquiet ; quiet display mode? jnz read2 ; nz = yes, no printing cmp flags.destflg,2 ; Receiving to the screen? je read21 ; e = yes, no formatted display call stpos mov ah,prstr ; Be informative ; mov dx,offset infms1 mcmsg infms1, cinfms1 int dos test flags.remflg,dserial ; serial display mode? jnz read2 ; nz = yes, skip initial retry display call rtpos ; Position cursor mov ax,pack.numrtr call nout ; Write the number of retries READ2: ; Called by GENERIC server command dispatcher cmp flags.xflg,1 ; Are we receiving to the screen? je read21 ; e = skip the screen stuff call nppos ; Position cursor for number of packets msg mov ax,pack.numpkt call nout ; Write the number of packets read21: mov ah,pack.state ; Get the state cmp ah,'D' ; Data receive state? jne read3 call rdata ; yes, get data packets jmp read2 read3: cmp ah,'F' ; File receive state? jne read4 call rfile ; Call receive file jmp read2 read4: cmp ah,'R' ; Receive initiate state? jne read5 ; ne = no call rinit jmp read2 ; Receive Complete state processor read5: push ax ; save status in ah cmp flags.cxzflg,0 ; Completed or interrupted? je read5a ; e = ended normally or errlev,2 ; set DOS error level or fsta.xstatus,2+80h ; set status, failed + intervention or kstatus,2+80h ; global status read5a: push ax xor ax,ax ; tell statistics this is a receive operation call endtim ; stop file timer pop ax mov ah,curchk ; get working checksum mov trans.chklen,ah ; and restore for next file mov byte ptr locfil,0 ; clear local filename pop ax ; recover status in ah ; mov dx,offset infms3 ; Completed message mcmsg infms3, cinfms3 cmp ah,'C' ; Receive complete state? je read6 ; e = yes, else receive failed or errlev,2 ; set DOS error level or fsta.xstatus,2 ; set status, failed or kstatus,2 ; global status ; mov dx,offset infms4 ; Failed message mcmsg infms4, cinfms4 cmp filopn,2 ; file still open? jne read6 ; ne = no push dx call abort ; close file & maybe delete pop dx read6: cmp flags.xflg,0 ; Did we write to the screen? je read6a ; e = no, so print status cmp flags.destflg,2 ; Receiving to screen? je read6d ; Yes don't reset mov flags.xflg,0 ; Reset it jmp read6d ; Yes, so just return read6a: test flags.remflg,dquiet ; quiet display mode? jnz read6d ; nz = yes, keep going cmp flags.destflg,2 ; Receiving to the screen? je read6d ; e = yes, no formatted display push dx ; save message pointer call stpos ; Position cursor pop dx mov ah,prstr cmp flags.cxzflg,0 ; Completed or interrupted? je read6b ; Ended normally ; mov dx,offset infms6 ; Say was interrupted mcmsg infms6, cinfms6 read6b: int dos cmp flags.belflg,0 ; Bell desired? je read6c ; No mov dx,offset ender ; Ring them bells int dos read6c: test flags.remflg,dserial ; serial display? jnz read6d ; nz = yes call clrmod ; clear Mode Line call rprpos ; Put prompt here read6d: jmp rskp READ ENDP ; Receive routines ; Receive init RINIT PROC NEAR mov ah,pack.numtry ; Get the number of tries cmp ah,imxtry ; Reached the maximum number of tries? jl rinit2 ; mov dx,offset ermes7 mcmsg ermes7, cermes7 test flags.remflg,dquiet ; quiet display mode? jnz rinit1 ; nz = yes. Don't write to screen cmp flags.destflg,2 ; Receiving to the screen? je rinit1 ; e = yes, no formatted display call erpos ; Position cursor mov ah,prstr int dos ; Print an error message rinit1: mov bx,dx 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 call errpack ; Send error packet just in case mov ah,curchk mov trans.chklen,ah ; Reset to desired value jmp abort ; Change the state to abort rinit2: inc ah ; Increment it mov pack.numtry,ah ; Save the updated number of tries mov ah,flags.getflg ; Get cmd? (holds get pkt type in ah) cmp ah,0 ; Have we already read in the packet? jne rin21a ; ne = yes, so don't call RPACK mov ah,dtrans.seol ; restore default end-of-line char mov trans.seol,ah mov ah,trans.chklen mov curchk,ah ; Save checksum length we want to use mov trans.chklen,1 ; Use 1 char for init packet call rpack ; Get a packet jmp rin22 ; Trashed packet: nak, retry call pktsize ; report packet size push ax mov ah,curchk mov trans.chklen,ah ; Reset to desired value pop ax cmp flags.cxzflg,0 ; does the user want out now? jne rinit4 ; ne = yes, quit rin21a: cmp ah,'S' ; Is it a send initiate packet? jne rinit3 ; If not see if its an error rin21: mov flags.getflg,0 ; Reset flag mov pack.numtry,0 ; Reset the number of tries mov ax,pack.seqnum ; Returned packet number. (Synchronize them.) inc ax ; Increment it 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.datlen ; Get the number of arguments received mov bx,offset data ; Get a pointer to the data call spar ; Get data into the proper variables mov bx,offset data ; Get a pointer to our data block call rpar ; Set up the receive parameters xchg ah,al mov ah,0 mov pack.datlen,ax ; Store returned number of arguments mov ah,trans.chklen ; Checksum length we'll use mov curchk,ah ; Save it mov trans.chklen,1 ; Use 1 char for init packet call ackpak ; acknowledge the packet mov ah,curchk ; Checksum length we'll use mov trans.chklen,ah ; Reset to desired value mov pack.state,'F' ; Set the state to file send ret rin22: call nak0 ; nak the packet mov ah,curchk ; and only now change checksum from 1 mov trans.chklen,ah ; Reset to desired value ret ; try again rinit3: cmp ah,'M' ; Message packet? jne rinit3e ; ne = no call dodec ; decode it call error1 ; display it ret rinit3e: cmp ah,'E' ; Is it an error packet? jne rinit4 ; ne = no call error ; yes rinit4: jmp abort RINIT ENDP ; Receive file RFILE PROC NEAR mov dl,maxtry cmp pack.numtry,dl ; Have we reached the maximum number of tries? jl rfile1 ; mov dx,offset ermes8 mcmsg ermes8, cermes8 jmp rcverr ; do error exit rfile1: inc pack.numtry ; Save the updated number of tries call rpack ; Get a packet jmp nak0 ; Trashed packet: nak, retry call pktsize ; report packet size cmp ah,'S' ; Is it a send initiate packet? je rfil10 cmp ah,'I' ; An Initialization packet? je rfil10 ; e = yes, don't decode it call dodec ; Decode all other incoming packets jmp rfile2 ; No, try next type rfil10: mov dl,imxtry ; S and I packets cmp pack.numtry,dl ; Reached the maximum number of tries? jl rfil12 ; If not proceed ; mov dx,offset ermes7 mcmsg ermes7, cermes7 jmp rcverr ; do error exit rfil12: mov ax,pack.pktnum ; Get the present packet number dec ax ; Decrement and ax,3fh ; do module 64 cmp ax,pack.seqnum ; Is the packet's number one less than now? je rfil13 jmp nak0 ; No, NAK and try again rfil13: mov pack.numtry,0 ; Reset the 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.datlen,ax ; Save the number of arguments jmp ackpak ; acknowledge the packet rfile2: cmp ah,'Z' ; Is it an EOF packet? jne rfile3 ; No, try next type mov dl,maxtry ; Z packets cmp pack.numtry,dl ; Have we reached the maximum number of tries? jl rfil21 ; If not proceed ; mov dx,offset ermes9 mcmsg ermes9, cermes9 jmp rcverr ; do error exit rfil21: mov ax,pack.pktnum ; Get the present packet number dec ax ; Decrement and ax,3fh ; do modulo 64 cmp ax,pack.seqnum ; Is the packet's number one less than now? je rfil24 jmp nak0 ; No, NAK and try again rfil24: mov pack.numtry,0 mov pack.datlen,0 ; No data. (The packet number is in seqnum.) jmp ackpak ; acknowledge the packet rfile3: cmp ah,'F' ; Start of file (F or X packet)? je rfil31 ; e = yes cmp ah,'X' ; Text header packet? jne rfile4 ; Neither one. mov flags.xflg,1 ; 'X', say receiving to the screen rfil31: mov ax,pack.seqnum ; Get the packet number cmp ax,pack.pktnum ; Is it the right packet number? je rfil32 jmp nak1 ; No, NAK it and try again rfil32: 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 filopn,0 ; assume not writing to a disk file call dodec ; Decode incoming packet for filename call gofil ; Get a file to write to jmp abort mov chrcnt,maxpack ; reset output buffer to be empty cmp flags.xflg,0 ; writing to a disk file? jne rfil32a ; ne = no mov filopn,2 ; Disk file open for writing rfil32a: test flags.remflg,dserial ; serial display mode? jz rfil33 ; z = no mov ah,prstr mov dx,offset crlf ; display cr/lf int dos rfil33: mov pack.state,'D' ; Set the state to data receive mov pack.numtry,0 ; Reset the number of tries mov pack.datlen,0 ; No data. (The packet number is in seqnum.) jmp ackpak ; acknowledge the packet rfile4: cmp ah,'B' ; End of transmission? jne rfile5 ; ne = no mov ax,pack.pktnum cmp ax,pack.seqnum ; Do we match? je rfil41 jmp nak1 ; No, NAK it and try again rfil41: mov pack.state,'C' ; Set the state to complete mov pack.datlen,0 ; No data. (Packet number already in seqnum) jmp ackpak ; acknowledge the packet rfile5: cmp ah,'M' ; Message packet? jne rfile5e ; ne = no call dodec ; decode it jmp error1 ; display it and return rfile5e:cmp ah,'E' ; Is it an error packet? jne rfile6 ; ne = no call error rfile6: jmp abort RFILE ENDP ; Get file attributes from packet ; Recognize file size in bytes and kilobytes (used if bytes missing), ; file time and date. Reject Mail commands. Return carry clear for success, ; carry set for failure. If rejecting place reason code in byte temp. GETATT PROC NEAR mov bx,offset data ; pointer getat0: push bx sub bx,offset data cmp bx,pack.datlen ; are we beyond end of data? pop bx jl getat1 ; l = not yet clc ret ; has carry clear for success getat1: cmp byte ptr [bx],'1' ; byte length field? jne getat2 ; ne = no mov al,[bx] ; remember attribute mov attrib,al inc bx ; pointer call getas ; get file size call spchk ; check available disk space jnc getat0 ret ; return failure getat2: cmp byte ptr [bx],'!' ; kilobyte length field? jne getat3 ; ne = no mov al,[bx] ; remember attribute mov attrib,al inc bx ; pointer call getak ; get file size jc getat5;;;2a ; carry means decode rejected call spchk ; check available disk space jnc short getat0 getat2a:ret ; return failure getat3: cmp byte ptr [bx],'#' ; date field? jne getat4 ; ne = no mov al,[bx] ; remember attribute mov attrib,al inc bx call getatd ; get file date jmp short getat0 getat4: cmp byte ptr [bx],'+' ; Disposition? jne getat5 ; ne = no mov al,[bx] ; remember attribute mov attrib,al cmp byte ptr [bx+2],'M' ; Mail indicator jne getat5 ; ne = no, ignore field stc ; set carry for failure ret getat5: inc bx ; look at length field mov al,[bx] sub al,' ' ; remove ascii bias mov ah,0 inc ax ; include length field byte add bx,ax ; skip to next attribute jmp getat0 ; Decode File length (Byte) field getas: mov cl,[bx] ; length of file size field inc bx ; point at file size data sub cl,' ' ; remove ascii bias mov ch,0 mov ax,0 ; current length, bytes mov dx,0 getas2: push cx shl dx,1 ; high word of size, times two mov di,dx ; save shl dx,1 shl dx,1 ; times 8 add dx,di ; yields dx * 10 mov di,dx ; save dx mov dx,0 mov cx,10 ; also clears ch mul cx ; scale up previous result in ax mov cl,[bx] ; get a digit inc bx sub cl,'0' ; remove ascii bias add ax,cx ; add to current length adc dx,0 ; extend result to dx add dx,di ; plus old high part pop cx loop getas2 mov ofilsz+2,ax ; low order word mov ofilsz,dx ; high order word ret ; Decode Kilobyte attribute getak: mov ax,ofilsz+2 ; current filesize, low word add ax,ofilsz cmp ax,0 ; zero if not used yet je getak1 ; e = not used before dec bx ; backup pointer stc ; set carry to ignore this field ret getak1: call getas ; parse as if Byte field mov ax,ofilsz+2 ; get low word of size mov dx,ofilsz ; high word mov dh,dl ; times 256 mov dl,ah mov ah,al mov al,0 shl dx,1 ; times four to make times 1024 shl dx,1 rol ax,1 ; two high bits of ah to al rol ax,1 and al,3 ; keep them or dl,al ; insert into high word mov al,0 mov ofilsz,dx ; store high word mov ofilsz+2,ax ; store low word clc ; clear carry ret getatd: ; File date and time mov word ptr ftime,1 ; two seconds past midnight mov word ptr fdate,0 mov dl,[bx] ; field length mov dh,0 sub dl,' ' ; remove ascii bias inc bx ; next field add dx,bx ; where next field begins mov temp,dx ; save in temp mov ax,0 ; recover file date and time mov dh,10 ; multiplier cmp byte ptr[bx+6],' ' ; short form date (yymmdd)? je getad2 ; e = yes add bx,2 ; skip century digits (19) getad2: mov ax,10 mov dx,[bx] ; get year tens and units digits add bx,2 ; dl has tens, dh has units sub dx,'00' ; remove ascii bias mul dl ; ax = high digit times ten add al,dh ; units digit sub ax,80 ; remove rest of 1980 bias jns getad2a ; ns = no sign = non-negative result mov ax,0 ; don't store less than 1980 getad2a:shl al,1 ; adjust for DOS bit format mov fdate+1,al mov ax,[bx] ; get month digits add bx,2 sub ax,'00' ; remove ascii bias cmp al,0 ; tens digit set? je getad2b ; e = no add ah,10 ; add to units digit getad2b:cmp ah,8 ; high bit of month set? jb getad3 ; b = no or fdate+1,1 sub ah,8 ; and deduct it here getad3: mov cl,5 shl ah,cl ; normalize months bits mov fdate,ah mov dx,[bx] ; do day of the month add bx,2 ; dh has units, dl has tens digit sub dx,'00' ; remove ascii bias mov ax,10 mul dl ; ax = ten times tens digit add al,dh ; plus units digit or fdate,al cmp bx,temp ; are we at the end of this field? jae getad5 ; ae = yes, prematurely inc bx ; skip space separator getad4: mov ax,10 ; prepare for hours mov dx,[bx] ; hh digits add bx,2 sub dx,'00' ; remove ascii bias mul dl ; 10*high digit of hours add al,dh ; plus low digit of hours mov cl,3 ; normalize bits shl al,cl mov ftime+1,al ; store hours inc bx ; skip colon mov ax,10 ; prepare for minutes mov dx,[bx] ; mm digits add bx,2 sub dx,'00' ; remove ascii bias mul dl ; 10*high digit of minutes add al,dh ; plus low digit of minutes mov ah,0 mov cl,5 ; normalize bits shl ax,cl or ftime+1,ah ; high part of minutes mov ftime,al ; low part of minutes cmp bx,temp ; are we at the end of this field jae getad5 ; ae = yes, quit here inc bx ; skip colon mov ax,10 ; prepare for seconds mov dx,[bx] ; ss digits add bx,2 sub dx,'00' ; remove ascii bias mul dl ; 10*high digit of seconds add al,dh ; plus low digit of seconds shr al,1 ; store as double-seconds for DOS or ftime,al ; store seconds getad5: ret GETATT ENDP ; Receive data RDATA PROC NEAR mov dl,maxtry cmp pack.numtry,dl ; Get the number of tries jl rdata1 ; mov dx,offset erms10 mcmsg erms10, cerms10 jmp rcverr ; do error exit rdata1: inc pack.numtry ; Save the updated number of tries call rpack ; Get a packet jmp nak0 ; Trashed packet: nak, retry nop call pktsize ; report packet size cmp ah,'D' ; Is it a data packet? je rdat11 ; e = yes cmp ah,'A' ; Attributes packet? jne rdata7 ; ne = no mov ax,pack.pktnum cmp ax,pack.seqnum ; Do we match? je rdata6 jmp nak1 ; No, NAK it and try again rdata6: call getatt ; get file attributes from packet mov pack.numtry,0 ; Reset number of tries jnc rdata6a ; nc = success mov pack.datlen,2 ; 2 bytes (Packet number already in seqnum) mov data,'N' ; Decline the transfer mov al,attrib ; get attribute causing rejection mov data+1,al ; report rejection reason to sender or fsta.xstatus,2 ; set status, failed mov kstatus,2 ; global status jmp short rdata6b rdata6a:mov pack.datlen,0 ; No data. (Packet number already in seqnum) rdata6b:mov ax,pack.pktnum 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 jmp ackpak ; acknowledge the packet rdata7: call dodec ; Decode data jmp rdata2 ; try next type ; D packets rdat11: mov ax,pack.pktnum ; Get the present packet number cmp ax,pack.seqnum ; Is the packet's number correct? jz rdat14 mov dl,maxtry cmp pack.numtry,dl ; Have we reached the maximum number of tries? jl rdat12 ; If not proceed ; mov dx,offset erms10 mcmsg erms10, cerms10 jmp rcverr ; do error exit rdat12: mov ax,pack.pktnum dec ax and ax,3fh ; do modulo 64 cmp ax,pack.seqnum ; Is the packet's number one less than now? je rdat13 jmp nak0 ; No, NAK it and try again rdat13: mov pack.numtry,0 ; Reset number of tries mov pack.datlen,0 ; No data. (The packet number is in seqnum.) jmp ackpak ; acknowledge the packet rdat14: inc pack.pktnum ; Increment the packet number and pack.pktnum,3fh ; Save modulo 64 of the number inc pack.numpkt ; Increment the number of packets mov ax,pack.datlen ; Get the length of the data cmp flags.cxzflg,0 ; Has the user typed a ^X or ^Z? je rdt14x ; No, write out the data or fsta.xstatus,2+80h ; set status, failed + intervention mov kstatus,2+80h ; global status cmp flags.abfflg,1 ; Discard incomplete files? je rdat15 ; If yes don't write data out to file rdt14x: call ptchr ; decode the data and output to file jmp abort ; Unable to write out chars; abort rdat15: mov pack.numtry,0 ; Reset the number of tries mov pack.datlen,0 ; No data. (Packet number still in seqnum.) cmp flags.cxzflg,0 ; Interrupt file transfer? je rdat16 ; Nope or fsta.xstatus,2+80h ; set status, failed + intervention mov kstatus,2+80h ; global status mov bx,offset data ; Send data in ACK in case remote mov ah,flags.cxzflg ; knows about ^X/^Z mov [bx],ah ; Put data into the packet mov pack.datlen,1 ; Set data size to 1 mov cx,1 call doenc rdat16: jmp ackpak ; acknowledge the packet rdata2: cmp ah,'F' ; Start of file? je rdat20 ; e = yes cmp ah,'X' ; Text header packet? jne rdata3 ; No, try next type rdat20: mov dl,maxtry ; F or X packet cmp pack.numtry,dl ; Reached the max number of tries? jl rdat21 ; If not proceed ; mov dx,offset ermes8 mcmsg ermes8, cermes8 jmp rcverr ; do error exit rdat21: mov ax,pack.pktnum dec ax and ax,3fh ; modulo 64 cmp ax,pack.seqnum ; Is the packet's number one less than now? je rdat22 jmp nak0 ; No, NAK it and try again rdat22: mov pack.numtry,0 ; Reset number of tries mov pack.datlen,0 ; No data. (The packet number is in seqnum.) jmp ackpak ; acknowledge the packet rdata3: cmp ah,'Z' ; Is it a EOF packet? je rdat3x ; e = yes jmp rdata4 ; Try and see if its an error rdat3x: mov ax,pack.pktnum ; Get the present packet number cmp ax,pack.seqnum ; Is the packet's number correct? je rdat32 jmp nak0 ; No, NAK it and try again rdat32: 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 call dodec ; Decode incoming packet cmp flags.cxzflg,0 ; Do we want to discard the file? jne rdt32x ; ne = yes cmp fmtdsp,0 ; formatted screen? je rdat32a ; e = no, no message mov ax,ofilsz ; high word of attributes file size or ax,ofilsz+2 ; low word cmp ax,0 ; was file size given by other side? je rdat32a ; e = no call perpos ; position cursor to percent done mov dx,offset donemsg ; say 100% mov ah,prstr int dos rdat32a:cmp pack.datlen,1 ; One piece of data? jne rdat33 ; Nope - finish writing out file? cmp data,'D' ; is the data "D" for discard? jne rdat33 ; Nope - write out file rdt32x: cmp flags.abfflg,0 ; Keep incomplete files? je rdat33 ; Yes, go write it out cmp flags.xflg,1 ; Writing to the screen? je rdt32y ; Don't close "file" cmp flags.destflg,2 ; file destination = screen? je rdt32y ; e = yes, no file to close push bx mov ah,close2 ; DOS 2.0 file close mov bx,diskio.handle ; file handle int dos ; Kill it, ignore errors pop bx mov filopn,0 ; File closed now mov dx,offset diskio.string ; get the filename mov ah,del2 ; DOS 2.0 file delete int dos rdt32y: cmp flags.cxzflg,'X' ; Kill one file or all? je rdt32ya ; e = one (^X) jmp rdat36 ; No so leave flag alone rdt32ya:call cxmsg ; Clear msg about interrupt or errlev,2 ; set DOS error level or fsta.xstatus,2+80h ; set status, failed + intervention mov kstatus,2+80h ; global status test flags.remflg,dquiet ; quiet display? jnz rdt32z ; nz = yes cmp flags.destflg,2 ; Receiving to the screen? je rdt32z ; e = yes, no formatted display call intmsg rdt32z: mov flags.cxzflg,0 ; Reset - ^X only kills one file jmp rdat36 rdat33: cmp flags.eofcz,0 ; should we write a ^Z? jz rdat35 ; no, keep going cmp flags.xflg,0 ; writing to a file? jne rdat35 ; no, skip ^Z rdt33x: cmp chrcnt,0 ; any space left in output buffer? jg rdat34 ; g = yes call outbuf ; Write out buffer if no room for ^Z jmp abort rdat34: mov cl,'Z'- 40h ; Put in a ^Z for EOF push bx mov bx,bufpnt ; Get the dma pointer mov [bx],cl ; Add it pop bx dec chrcnt rdat35: call outbuf ; Output the last buffer jmp abort ; Give up if the disk is full cmp flags.xflg,1 ; Writing to the screen? je rdat37 ; Yes, don't close "file" cmp flags.destflg,2 ; file destination = screen? je rdat37 ; e = yes, no file to close push bx ; do file attributes and close mov cx,word ptr ftime ; new time mov dx,word ptr fdate ; new date mov word ptr fdate,0 mov word ptr ftime,0 ; clear current time/date attributes mov ax,cx or ax,dx jz rdat35b ; z = no attributes to set cmp cx,0 ; time set as null? jne rdat35a ; ne = no inc cl ; two seconds past midnight rdat35a:mov ah,setattr ; set file date/time attributes mov al,1 ; set, not get mov bx,diskio.handle ; file handle int dos ; end of file attributes rdat35b:mov ah,close2 ; DOS 2.0 file close mov bx,diskio.handle ; file handle int dos pop bx mov filopn,0 ; File closed now rdat36: cmp flags.destflg,0 ; Writing to printer? jne rdat37 ; ne = no, skip next part cmp flags.xflg,1 ; Writing to screen? je rdat37 ; Yes, skip this part mov dl,ff ; Send a form feed mov ah,lstout ; Write out to first printer int dos rdat37: mov pack.numtry,0 ; Reset the number of tries mov pack.datlen,0 ; No data. (The packet number is in seqnum.) call ackpak ; acknowledge the packet mov pack.state,'F' mov ax,0 ; tell statistics this was a receive operation call endtim ; get tod & size of file transfer ret rdata4: cmp ah,'M' ; Message packet? jne rdata4e ; ne = no call dodec ; decode it jmp error1 ; display it and return rdata4e: cmp ah,'E' ; Is it an error packet? jne rdata5 ; ne = no call error rdata5: jmp abort RDATA ENDP ; Error exit. Enter with dx pointing to error message. [jrd] rcverr proc near test flags.remflg,dquiet ; quiet display mode? jnz rcver1 ; nz = yes. Don't write to screen cmp flags.destflg,2 ; Receiving to the screen? je rcver1 ; e = yes, no formatted display call erpos ; Position cursor mov ah,prstr int dos ; Print an error message rcver1: mov bx,dx ; set bx to error message call errpack ; Send error packet just in case jmp abort ; Change the state to abort rcverr endp ; Called by GETATT in receiver code to verify sufficient disk space. ; Gets file path from diskio.string setup in mssfil, remote size in ofilsz ; from getatt, and whether a disk file or not via ioctl on the file handle. ; Returns carry clear if enough space. spchk proc near ; check for enough disk space push ax push bx push cx push dx mov ah,ioctl ; ask DOS about this file handle mov al,0 ; get info mov bx,diskio.handle int dos test dl,80h ; handle is a disk file? jnz spchk5b ; nz = no, always enough space inc dl and dl,01fh ; get current drive from bits 5-0 mov ah,36h ; get disk free space int dos cmp ax,0ffffh ; error response? je spchk6 ; e = yes mul bx ; sectors/cluster * clusters = sectors mov bx,dx ; save high word of sectors (> 64K) mul cx ; bytes = sectors * bytes/sector push ax ; save low word of bytes mov ax,bx ; recall sectors high word mov bx,dx ; save current bytes high word mul cx ; high word sectors * bytes/sector add ax,bx ; new high bytes + old high bytes push ax ; save high word, dx:ax mov dx,ofilsz ; high word of file size dx:ax mov ax,ofilsz+2 ; low word mov cx,dx ; copy size long word to cx:bx mov bx,ax shr bx,1 ; divide long word by two shr cx,1 jnc spchk2 ; nc = no carry down or bx,8000h ; get carry down spchk2: shr bx,1 ; divide by two again shr cx,1 jnc spchk3 or bx,8000h ; get carry down spchk3: shr bx,1 ; divide long word by two shr cx,1 jnc spchk4 ; nc = no carry down or bx,8000h ; get carry down spchk4: shr bx,1 ; divide long word by two shr cx,1 jnc spchk5 ; nc = no carry down or bx,8000h ; get carry down spchk5: add ax,bx ; form dx:ax = (17/16) * dx:ax adc dx,cx spchk5a:pop cx ; high word of disk space pop bx ; low word sub bx,ax ; minus inflated file size, low word sbb cx,dx ; and high word js spchk6 ; s = not enough space for file spchk5b:clc jmp short spchk7 ; enough space spchk6: call erpos ; Position cursor mov ah,prstr ; mov dx,offset erms11 ; Not enough space for file mcmsg erms11, cerms11 int dos stc spchk7: pop dx pop cx pop bx pop ax ret spchk 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 code ends end