; CN8IPR.A86 ; * * * * * * * * * * * * * * * * version 3.0 * * ** * * * * * * * * * * * * ; Allows packet echo for ICL VME systems - CGL ; * * * * * * * * * * * * * * * version 2.9 * * * * * * * * * * * * * * * ; [34c] Add sorted wildcard SENDs with initial filename ; * * * * * * * * * * * * * * * version 2.7 * * * * * * * * * * * * * * * ; [31] Fix display on file renaming. ; RonB, 05/05/84 ; [30c] Isolate ANSI escape sequences for machine independence. ; [29g] Add 8th bit quoting. ; [29d] Enlarge receive buffer and check for packet overruns. ; [29b] Add TAKE processing (close command file when aborting). ; [29a] Send error packet when aborting. ; RonB, 04/08/84 ; * * * * * * * * * * * * * * * version 2.6 * * * * * * * * * * * * * * * ; [28b] Make file-not-found error more informative (include filename). ; [28a] Clear attribute bits from filename before sending ; RonB, 03/27/84 ; [25] - make KERCMD more modular by eliminating some use of text ; strings by other modules (KERPRO, KERSYS), and moving some ; parsing into KERCMD (ESCAPE and EOLSET logic in KERSYS) ; * * * * * * * * * * * * * * * version 2.4 * * * * * * * * * * * * * * * ; [21a] Add timeout enable/disable ; RonB,03/05/84 ; [20a] Fix version & send/receive header ; [20e] Clean up environment better before rebooting in KABORT ; RonB,03/02/84 ; [19f] Add ^X/^Z file interruption - adapted from PC Kermit V1.20 ; Put in Help line for above. ; [19g] Put in timeouts. ; R. Garland 2/84 ; * * * * * * * * * * * * * * * version 2.1 * * * * * * * * * * * * * * * ; [14] Fix nout to print decimal. ; RonB,12/28/83 ; [13] Use control-Z's for filler in partial sectors instead of nulls. ; RonB,12/27/83 ; [12] Allow user abort from the keyboard in the send and receive routines. ; RonB,12/27/83 ; [9] Fix filename parsing, and add wildcard ability. ; RonB,12/26/83 ; * * * * * * * * * * * * * * * version 2.0 * * * * * * * * * * * * * * * ; This module contains the routines that actually implement the Kermit ; protocol. ; Packet definitions. maxpkt equ '~'-' '+2O ;Maximum size of a packet. maxtry equ 05O ;Default number of retries on a packet. imxtry equ 20O ;Default number of retries send initiate. drpsiz equ 5EH ;Default receive packet size. dspsiz equ 20H ;Default send packet size. dstime equ 0AH ;Default send time out interval. drtime equ 05H ;Default receive time out interval. dspad equ 00H ;Default send padding. drpad equ 00H ;Default receive padding. dspadc equ 00H ;Default send padding char. drpadc equ 00H ;Default receive padding char. dseol equ cr ;Default send EOL char. dreol equ cr ;Default receive EOL char. dsquot equ '#' ;Default send quote char. drquot equ '#' ;Default receive quote char. dqbin equ '&' ;Default 8th-bit quote char. ;[29g] bufsiz equ 80H ;Size of DMA. ; A few control characters ctlc equ 03H ;[19f] ctlx equ 18H ;[19f] ctlz equ 1AH ;[19f] DSEG $ ; Program storage. belflg db 1 ;Use bell. incmod db 0 ;Insert Character mode. hierr db 0 ;Non-ascii char (non-zero if yes). parflg db defpar ;Parity flag (default none.) flwflg db 0 ;File warning flag (default off). ibmflg db 0 ;IBM flag (default off). vmeflg db 0 ;VME flag (default off); incnt dw 0 ;Number of chars read in from port. pktptr dw 0 ;Position in receive packet. spsiz db dspsiz ;Send packet size. rpsiz db drpsiz ;Receive packet size. stime db dstime ;Send time out. rtime db drtime ;Receive time out. spad db dspad ;Send padding. rpad db drpad ;Receive padding. spadch db dspadc ;Send padding char. rpadch db drpadc ;Receive padding char. seol db dseol ;Send EOL char. reol db dreol ;Receive EOL char. squote db dsquot ;Send quote char. rquote db drquot ;Receive quote char. ebquot db 'Y' ;Send 8th-bit quote char. ;[29g] pktnum dw 0 ;Packet number. numpkt dw 0 ;Total number of packets sent. numrtr dw 0 ;Total number of retries. numtry db 0 ;Number of tries on this packet. oldtry db 0 ;Number of tries on previous packet. cxzflg db 0 ;[19f] flag for ^X/^Z file interruption state db 0 ;Present state of the automaton. packet rb 4 ;Packet (data is part of it). data rb 60H ;Data and checksum field of packet. ;[29d] recpkt rb 100H ;Receive packet storage. ;[29d] temp dw 0 argblk dw 0 ;For subroutine arguments. argbk1 dw 0 argbk2 dw 0 argbk3 dw 0 tickst dw 10*(7470/clckrt);[19g] "magic" formula for loops/tick ;[19g] CLCKRT is the system clock rate ... ;[19g] ... defined in KERIO ticklp dw 0 ;[19g] Dynamic loop count for tick tickct db dstime ;[19g] # ticks for timeout to occur tmodon db 0 ;[19g] flag for time-out message CSEG $ ; Check for a user abort or interrupt during the send or receive ;[12] begin ; modified by Rg. kabort: call dbinst ;Check if a char has been typed. jmp r ;[19f] Merrily return. call dbin ;Get the character. cmp al, ctlc ;Abort if control-C [19f] je kabrt2 cmp al, ctlx ;[19f] Is it control-x ? je kabrta ;[19f] yes cmp al, ctlz ;[19f] control-z ? jne kabrtb ;[19f] no kabrta: add al, 100O ;[19f] make into 'X' or 'Z' mov cxzflg, al ;[19f] set the flag call intmsg ;[19f] reassure the user ret ;[19f] return kabrtb: cmp al, cr ;if do a timeout ;[29a] begin jne kabrtc pop bx ;return of kabort pop bx ;receive packet pointer ;... next is return of inpkt ret ;return to timeout routine ;[29a] end kabrtc: cmp al, escchr ;or the escape character followed by 'C'. jne kabrt9 mov cx, 1000 ;Only wait just so long for the next char. kabrt1: push cx call dbin pop cx cmp al, 0 loope kabrt1 cmp al, ctlc ;Control-C also works here. [19f] je kabrt2 and al, 137O ;Capitalize it. cmp al, 'C' ;If not a 'C' then continue. jne kabrt9 kabrt2: cmp tkflg, 0 ;Close any command file in use ;[29b] begin je kabrt3 call tkcls ;[29b] end kabrt3: call binst ;Clear out extraneous input ;[29a] begin jmp kabrt4 ;If none, go abort this transmission. call bin jmps kabrt2 kabrt4: pop bx ;return from kabort pop bx ;receive packet pointer pop bx ;return from inpkt pop bx ;return from rpack ;... next is return from r??? to read mov dx, offset erms21 ;Print '* aborted *' message. jmp fatal ;[29a] end kabrt9: mov dl, bell ;beep [19f] call dbout ; [19f] ret ;return no error [19f] ; Send the generic finish command to the remote Kermit. finsen: mov ah, 'F' ;Ask for the finish command. call gensen ret ; Send the generic logout command to the remote Kermit. byesen: mov ah, 'L' ;Ask for the logout command. call gensen ret ; This procedure processes all the generic single packet sends. gensen: mov temp, ax ;Save the specific generic command. mov numtry, 0 ;Initialize count. call cfibf ;Clear out input buffer of extra NAKs. fins1: mov ah, numtry cmp ah, maxtry ;Too many times? js fins3 ;Nope, try it. fins2: mov dx, offset erms18 call tcrmsg ret fins3: inc numtry ;Increment number of tries. mov argblk, 0 ;Packet number zero. mov argbk1, 1 ;One piece of data. mov bx, offset data mov ax, temp ;Get the generic command. mov [bx], ah ;Finish running Kermit. mov ah, 'G' ;Generic command packet. call spack jmp fins2 ;Tell user and die. call rpack ;Get ACK. jmp fins1 ;Go try again. cmp ah, 'Y' ;Got an ACK? jnz fins4 ret ;Yes, then we're done. fins4: cmp ah, 'E' ;Error packet? jnz fins1 ;Try sending it again. call error1 ret ; Packet routines ; Send_Packet ; This routine assembles a packet from the arguments given and sends it ; to the host. ; ; Expects the following: ; AH - Type of packet (D,Y,N,S,R,E,F,Z,T) ; ARGBLK - Packet sequence number ; ARGBK1 - Number of data characters ; ; Returns: +1 always spack: push ax ;Save the packet type. mov bx, offset packet ;Get address of the send packet. mov ah, soh ;Get the start of header char. mov [bx], ah ;Put in the packet. inc bx ;Point to next char. mov ax, argbk1 ;Get the number of data chars. xchg ah, al add ah, ' '+3 ;Real packet character count made printable. mov [bx], ah ;Put in the packet. inc bx ;Point to next char. mov cl, ah ;Start the checksum. mov ax, argblk ;Get the packet number. xchg ah, al add ah, ' ' ;Add a space so the number is printable. mov [bx], ah ;Put in the packet. inc bx ;Point to next char. add cl, ah ;Add the packet number to the checksum. pop ax ;Get the packet type. mov [bx], ah ;Put in the packet. inc bx ;Point to next char. add cl, ah ;Add the type to the checksum. mov dx, argbk1 ;Get the packet size. spack2: cmp dx, 0 ;Are there any chars of data? jz spack3 ; No, finish up. dec dx ;Decrement the char count. mov ah, [bx] ;Get the next char. inc bx ;Point to next char. add cl, ah ;Add the char to the checksum. jmp spack2 ;Go try again. spack3: sp3x: mov ah, cl ;Get the character total. mov ch, cl ;Save here too (need 'cl' for shift). and ah, 0C0H ;Turn off all but the two high order bits. mov cl, 6 shr ah, cl ;Shift them into the low order position. mov cl, ch add ah, cl ;Add it to the old bits. and ah, 3FH ;Turn off the two high order bits. (MOD 64) add ah, ' ' ;Add a space so the number is printable. mov [bx], ah ;Put in the packet. inc bx ;Point to next char. mov ah, seol ;Get the EOL the other host wants. mov [bx], ah ;Put in the packet. inc bx ;Point to next char. mov ah, 0 ;Get a null. mov [bx], ah ;Put in the packet. cmp debug, 0 ;debug mode. je spack4 inc bx mov ah, '$' mov [bx], ah mov dx, offset scrsp ;Print string to move cursor. call poscur ;[30c] begin call clreol ;Clear current line mov dl, lf ; and next one call bout call clreol mov dx, offset scrsp ;Print string to move cursor. call poscur ;[30c] end mov dx, offset spmes call tmsg mov dx, offset packet call tmsg ;Debug end. spack4: call outpkt ;Call the system dependent routine. jmp rskp ; Write out a packet. outpkt: mov dh, spad ;Get the number of padding chars. outpk2: dec dh cmp dh, 0 jl outpk3 ;If none left proceed. mov al, spadch ;Get the padding char. call prtout ;Output it. jmp outpk2 outpk3: mov bx, offset packet ;Point to the packet. outlup: mov al, [bx] ;Get the next character. cmp al, 0 ;Is it a null? jnz outlp2 ret outlp2: call prtout ;Output the character. inc bx ;Increment the char pointer. jmp outlup ; Receive_Packet ; This routine waits for a packet arrive from the host. rpack: call inpkt ;Read up to a carriage return. jmp rptimo ; User timed us out. rpack0: call getchr ;Get a character. jmp rpack ; Hit the carriage return, go try again. cmp ah, soh ;Is the char the start of header char? jne rpack0 ; No, go until it is. rpack1: call getchr ;Get a character. jmp r ; Hit the carriage return, return bad. cmp ah, soh ;Is the char the start of header char? jz rpack1 ; Yes, then go start over. mov cl, ah ;Start the checksum. sub ah, ' '+3 ;Get the real data count. mov dh, ah ;Save it for later. mov al, ah ;Swap halves. mov ah, 0 mov argbk1, ax ;Save the data count. call getchr ;Get a character. jmp r ; Hit the carriage return, return bad. cmp ah, soh ;Is the char the start of header char? jz rpack1 ; Yes, then go start over. add cl, ah ;Add it to the checksum. sub ah, ' ' ;Get the real packet number. mov al, ah ;Swap halves. mov ah, 0 mov argblk, ax ;Save the packet number. call getchr ;Get a character. jmp r ; Hit the carriage return, return bad. cmp ah, soh ;Is the char the start of header char? jz rpack1 ; Yes, then go start over. mov temp, ax ;Save the message type. ; CGL mod for VME packet echo cmp ah, packet + 3 ; compare with the type of this received one je rpack ; if the same go back and get next ; end of CGL mod add cl, ah ;Add it to the checksum. mov bx, offset data ;Point to the data buffer. rpack2: dec dh ;Any data characters? js rpack3 ; If not go get the checksum. call getchr ;Get a character. jmp r ; Hit the carriage return, return bad. cmp ah, soh ;Is the char the start of header char? jz rpack1 ; Yes, then go start over. mov [bx], ah ;Put the char into the packet. inc bx ;Point to the next character. add cl, ah ;Add it to the checksum. jmp rpack2 ;Go get another. rpack3: call getchr ;Get a character. jmp r ; Hit the carriage return, return bad. cmp ah, soh ;Is the char the start of header char? jz rpack1 ; Yes, then go start over. sub ah, ' ' ;Turn the char back into a number. mov dh, cl ;Get the character total. and dh, 0C0H ;Turn off all but the two high order bits. mov ch, cl mov cl, 6 shr dh, cl ;Shift them into the low order position. mov cl, ch add dh, cl ;Add it to the old bits. and dh, 3FH ;Turn off the two high order bits. (MOD 64) cmp dh, ah ;Are they equal? jz rpack4 ; If so finish up. call cfibf ;Clear out any other characters on the line. ret ;And return failure. rpack4: mov ah, 0 mov [bx], ah ;Put a null at the end of the data. mov ax, temp ;Get the type. call cfibf ;Clear out any other characters on the line. jmp rskp rptimo: call cfibf ;On a time out clear out any remaining chars. ret inpkt: mov bx, offset recpkt ;Point to the beginning of the packet. mov incnt, 0 inpkt2: mov al, stime ;[19g] set up timeout loop. mov tickct, al ;[19g] mov ax, tickst ;[19g] "magic" number loops/tick mov ticklp, ax ;[19g] inpkta: cmp tmrflg, 0 ;Is timeout disabled? ;[21a] je inpktb ; If so, skip tick routine ;[21a] dec ticklp ;[19g] cmp ticklp, 0 ;[19g] done this tick? jne inpktb ;[19g] not yet mov ax, tickst ;[19g] reload loop count mov ticklp, ax ;[19g] call ticmsg ;[19g] beep for debugging dec tickct ;[19g] cmp tickct, 0 ;[19g] timed-out? jne inpktb ;[19g] not yet call tmomsg ;[19g] alert user jmp inpkt9 ;[19g] go time-out inpktb: push bx ;[19g][12] bx gets trashed by kb status check. call kabort ;[19g] Doesn't return if user aborted. pop bx ;[19g] call instat ;Any char there? jmp inpkta ; Go until there is one. call inchr ;Get the character. mov [bx], al ;Put the char in the packet. inc bx inc incnt cmp incnt, length recpkt ;Have we overrun the input buffer? ;[29d] jb inpktc jmp inpkt ;If so, just clear and restart inpktc: cmp al, reol ;Is it the EOL char? ;[29d] end jne inpkt2 ;If not loop for another. cmp incnt, 1 ;Ignore bare CR. jne inpkt6 jmp inpkt inpkt6: cmp ibmflg, 0 ;Is this the (dumb) IBM mainframe? jz inpkt4 ;If not then proceed. inpkt5: cmp state, 'S' ;Check if this is the Send-Init packet. jz inpkt4 ;If so don't wait for the XON. inpkt3: call instat ;Wait for the turn around char. jmp inpkt3 call inchr cmp al, xon ;Is it the IBM turn around character? jne inpkt3 ;If not, go until it is. inpkt4: cmp debug, 0 jz inpkt7 ;If not debugging don't print the packet. mov al, '$' ;Get a dollar sign. mov [bx], al ;Put in the packet. inc bx ;Point to next char. mov dx, offset scrrp ;Print the packet. call poscur ;[30c] begin call clreol ;Clear current line mov dl, lf ; and next one call bout call clreol mov dx, offset scrrp ;Print string to move cursor. call poscur ;[30c] end mov dx, offset rpmes call tmsg mov dx, offset recpkt call tmsg inpkt7: mov bx, offset recpkt mov pktptr, bx ;Save the packet pointer. call tmoclr ;[19g] Clear timeout message jmp rskp ;If so we are done. inpkt9: ret ;return failure on time out. getchr: push bx mov bx, pktptr ;Get the packet pointer. mov ah, [bx] ;Get the char. inc bx mov pktptr, bx pop bx ;Restore BX. cmp ah, reol ;Is it the EOL char? jne getcr2 ;If not return retskp. ret ;If so return failure. getcr2: jmp rskp ;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. error: mov state, 'A' ;Set the state to abort. mov dx, offset screrr call poscur ;[30c] jmp error2 error1: call tcrlf error2: mov bx, offset data ;Get to the string. add bx, argbk1 ;Add the length of the data. mov ah, '$' ;Put a dollar sign at the end. mov [bx], ah mov dx, offset data ;Print the error message. call tmsg ret ; Jump here if we die during a transfer. Print the error message in ; DX and abort. fatal: push dx ;Save the error message. mov dx, offset screrr call poscur ;[30c] pop dx call tmsg jmp abort ;Change the state to abort. ; Print the status message in DX, ring the bell and position of the prompt. fnstat: push dx mov dx, offset scrst ;Print string to move cursor. call poscur ;[30c] pop dx call tmsg mov dx, offset ender ;Ring them bells. call tmsg mov dx, offset scrhlp ;[19f] Cursor position call poscur ;[30c] call clreol ;[19f] Clear help line ;[30c] mov dx, offset scrrpr ;Put cursor back call poscur ;[30c] ret ; This routine sets up the data for init packet (either the ; Send_init or ACK packet). rpar: mov ah, 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, rtime ;Get the receive packet time out. add ah, ' ' ;Add a space. mov 1[bx], ah ;Put it in the packet. mov ah, rpad ;Get the number of padding chars. add ah, ' ' mov 2[bx], ah ;Put it in the packet. mov ah, rpadch ;Get the padding char. add ah, 100O ;Uncontrol it. and ah, 7FH mov 3[bx], ah ;Put it in the packet. mov ah, reol ;Get the EOL char. add ah, ' ' mov 4[bx], ah ;Put it in the packet. mov ah, rquote ;Get the quote char. mov 5[bx], ah ;Put it in the packet. mov ah, ebquot ;Get 8th-bit quote char ;[29g] begin mov 6[bx], ah ;Put it in the packet. mov ah, '1' ;Set single character check type mov 7[bx], ah ;Put it in the packet. mov ah, ' ' ;Set no repeat prefix mov 8[bx], ah ;Put it in the packet. mov ah, 0 ;Initialize capability byte cmp tmrflg, 0 ;Are we able to time out? je rpar1 ; No, leave bit set to zero or ah, 20h ; Otherwise set timeout capability flag rpar1: add ah, ' ' ;Add space to make it printable mov 9[bx], ah ;Put it in the packet. mov ah, 10 ;Ten pieces of data. ;[29g] end ret ; This routine reads in all the send_init packet information. spar: push cx ;Save CX. mov cx, ax ;Save the number of arguments. mov ah, [bx] ;Get the max packet size. sub ah, ' ' ;Subtract a space. mov spsiz, ah ;Save it. mov ax, cx ;[19g] cmp al, 2 ;[19g] Fewer than two pieces? jge spar1 ;[19g] ;[29g] jmp sparx1 ;[29g] spar1: mov ah, 1[bx] ;[19g] Get the timeout value sub ah, ' ' ;[19g] mov stime, ah ;[19g] save it. mov ax, cx cmp al, 3 ;Fewer than three pieces? jge spar2 ;[29g] jmp sparx2 ;[29g] spar2: mov ah, 2[bx] ;Get the number of padding chars. sub ah, ' ' mov spad, ah mov ax, cx cmp al, 4 ;Fewer than four pieces? jge spar3 ;[29g] jmp sparx3 ;[29g] spar3: mov ah, 3[bx] ;Get the padding char. add ah, 100O ;Re-controlify it. and ah, 7FH mov spadch, ah mov ax, cx cmp al, 5 ;Fewer than five pieces? jge spar4 ;[29g] jmp sparx4 ;[29g] spar4: mov ah, 4[bx] ;Get the EOL char. sub ah, ' ' mov seol, ah mov ax, cx cmp al, 6 ;Fewer than six pieces? jge spar5 ;[29g] jmp sparx5 ;[29g] spar5: mov ah, 5[bx] ;Get the quote char. mov squote, ah mov ax, cx ;[29g] begin cmp al, 7 ;Fewer than seven pieces? jge spar6 jmp sparx6 spar6: mov ah, 6[bx] ;Get the 8th-bit quote char. call doquo ;Set the quote character. jmp sparxx sparx1: mov stime, dstime ;Default timeout interval sparx2: mov spad, dspad ;Default number of padding chars sparx3: mov spadch, dspadc ;Default pad character sparx4: mov seol, dseol ;Default eol character sparx5: mov squote, dsquot ;Default send quote character. sparx6: mov ebquot, 'N' ;No 8th bit quoting. sparxx: pop cx ;[29g] end ret ;If so we are done. ; Set 8-bit quote character based on my capabilities ;[29g] begin ; and the other Kermit's request. doquo: cmp ebquot,'N' ;Can I do 8-bit quoting at all? je dq2 ;No - so forget it. cmp ebquot,'Y' ;Can I do it if requested? jne dq0 ;No - it's a must that I do it. mov ebquot,ah ;Do whatever he wants. jmp dq2 dq0: cmp ah,'Y' ;I need quoting - can he do it? je dq2 ;Yes - then all is settled. cmp ah,'N' ;No - then don't quote. je dq1 cmp ah,ebquot ;Both need quoting - chars must match. je dq2 mov ah,'N' dq1: mov ebquot,ah dq2: mov ah,ebquot cmp ah,rquote ;Same prefix? je dq3 ;Not allowed, so don't do quoting. cmp ah,squote ;Same prefix here? je dq3 ;This is illegal too. ret dq3: mov ebquot,'N' ;Quoting will not be done. ret ;[29g] end ; These are some utility routines. ; Increment the packet number. incpkt: inc ax ;Increment it. and ax, 3FH ;Turn off the two high order bits. mov pktnum, ax ;Save modulo 64 of the number. inc numpkt ;Increment the number of packets. ret ; Check if the packet number is the present packet. chkpeq: mov ax, argblk ;Get the packet number. cmp ax, pktnum ;Is it the right packet number? je chkpe2 ret ;No. chkpe2: jmp rskp ;Yes. ; Is the packet number one more than present. chkpom: mov ax, pktnum ;Get the present packet number. inc ax ;Increment. and ax, 03FH ;Account for wraparound. cmp ax, argblk ;Is the packet's number one more than now? jz chkpm2 ;Yes, success. ret chkpm2: jmp rskp ; Check if the packet number is the previous packet. chkpol: inc oldtry ;Save the updated number of tries. mov ax, pktnum ;Get the present packet number. cmp ax, 0 ;Had we wrapped around? jne chkpl2 mov ax, 64 chkpl2: dec ax ;Decrement. cmp ax, argblk ;Is the packet's number one less than now? je chkpl3 jmp rskp chkpl3: ret ; Abort abort: mov argblk, 0 ;packet number 0 ;[29a] begin mov argbk1, 0 ;no data mov ah, 'E' ;error type call spack jmp $ ;[29a] end mov state, 'A' ;Otherwise abort. ret ; ACK the packet. uupack: call updat ;[19f] entry which doesn't zero argbk1 jmp ack1 ;[19f] upack: call updat ;Update the number of tries. ack: mov argbk1, 0 ;No data. (Packet number already in argblk). ack1: mov ah, 'Y' ;Acknowledge packet. call spack ;Send the packet. jmp r jmp rskp updat: mov ah, numtry ;Get the number of tries. mov oldtry, ah ;Save it. mov numtry, 0 ;Reset the number of tries. ret ; Re-ACK the previous packet. reack: call nretry ;Increment and print the number of retries. mov numtry, 0 ;Reset the number of tries. mov ah, 'Y' ;Acknowledge packet. call spack ;Send the packet. jmp r jmp rskp ; NAK that packet. nak: mov ax, pktnum ;Get the packet number we're waiting for. mov argblk, ax mov argbk1, 0 mov ah, 'N' ;NAK that packet. call spack jmp abort call nretry ;Increment and print the number of retries. ret ;Go around again. ; Print the number of retries. nretry: inc numrtr ;Increment the number of retries. pretry: mov dx, offset scrnrt call poscur ;[30c] mov ax, numrtr call nout ;Write the number of retries. ret ; Print the number of packets. pnmpkt: mov dx, offset scrnp ;Print string to move cursor. call poscur ;[30c] mov ax, numpkt call nout ;Write the number of packets. ret ; This routine prints the number in AX on the screen. nout: push ax ;save all registers ;[14] begin push bx push cx push dx mov cx, 0 ;number of digits to print mov bx, 10 ;radix to use for dividing nout1: mov dx, 0 ;clear high word of dividend div bx ;divide dx:ax by 10 push dx ;push this remainder inc cx ;count it cmp ax, 0 ;anything left in the quotient? jne nout1 ; if so, keep dividing nout2: pop dx ;get a digit add dl, '0' ;make it ascii push cx ;save our count call bout ;print the digit pop cx ;repeat until all digits printed loop nout2 pop dx ;restore all registers pop cx pop bx pop ax ret ; Initialize file buffers and paint screen. init: call dspver ;Clear screen and display version header mov dx, offset scrnp ;Position to packet location call poscur mov dx, offset pktlin ;[20a] call tmsg mov dx, offset scrhlp ;[19f] Cursor position call poscur ;[19f] for help line ;[30c] call revon ;Bottom line reverse ;[30c] mov dx, offset infm10 ;[19f] Help for file transfer call tmsg ;[19f] call revoff ;[30c] init1: mov chrcnt, bufsiz ;Number of chars left. mov bufpnt, offset dma ;Addr for beginning. ret ; Clear out the old filename on the screen. clrfln: mov dx, offset scrfr ;Move cursor to file rename. ;[31] begin call poscur call clreol ;Clear to EOL. ;[31] end mov dx, offset scrfln ;Move cursor to file name position. call poscur ;[30c] call clreol ;Clear to EOL. ;[30c] ret ; acknowledge ^X/^Z with a message [19f] start intmsg: mov dx, offset scrint ;position info call poscur ;output it ;[30c] mov dx, offset infms8 ;File message cmp cxzflg, 'X' ;but first check je intm01 ;yes it was X mov dx, offset infms9 ;no it was 'Z' - file group. cmp cxzflg, 'Z' ;or was it? je intm01 ;yes - go output call clreol ;anything else - clear line ;[30c] jmps intm02 ;[30c] intm01: call tmsg ;output it intm02: ret ;goodbye [19f] end ; let the time-out clock "tick" ;[19g] start ticmsg: mov dl, bell ;output a ... call dbout ;... beep! ret ; notify of time-out tmomsg: mov dx, offset scrst ;cursor position call poscur ;[30c] mov dx, offset timoms ;timeout message call tmsg mov tmodon, 1 ;flag for message ret ; clear time-out message tmoclr: cmp tmodon, 0 ;message on screen? jne tmocl1 ;yes - go get it ret ;nothing to clear - return tmocl1: mov dx, offset scrst ;cursor position call poscur ;[30c] call clreol ;clear line ;[30c] mov tmodon, 0 ;indicate line is clear ret ;[19g] end ; RECEIVE command read: call init ;Paint the screen and initialize file buffers. call cfibf ;Clear out any stacked NAKs. read1: mov numpkt, 0 ;Set the number of packets to zero. mov numrtr, 0 ;Set the number of retries to zero. mov pktnum, 0 ;Set the packet number to zero. mov numtry, 0 ;Set the number of tries to zero. mov cxzflg, 0 ;[19f] reset ^X/^Z flag call pretry mov state, 'R' ;Set the state to receive initiate. read2: call pnmpkt mov ah, state ;Get the state. cmp ah, 'D' ;Are we in the data send state? jne read3 call rdata jmp read2 read3: cmp ah, 'F' ;Are we in the file receive state? jne read4 call rfile ;Call receive file. jmp read2 read4: cmp ah, 'R' ;Are we in the receive initiate state? jne read5 call rinit jmp read2 read5: cmp ah, 'C' ;Are we in the receive complete state? jne read6 mov dx, offset infms3 ;Plus a little cuteness. cmp cxzflg,0 ;[19f] an interruption? je read59 ;[19f] no - do normal thing mov dx, offset infms7 ;[19f] substitute 'interrupted' message. read59: call fnstat ret read6: mov dx, offset infms4 ;Plus a little cuteness. call fnstat ret ; Receive routines ; Receive init rinit: mov ah, numtry ;Get the number of tries. cmp ah, imxtry ;Have we reached the maximum number of tries? jl rinit2 mov dx, offset ermes7 ;Print this error and die. jmp fatal rinit2: inc ah ;Increment it. mov numtry, ah ;Save the updated number of tries. call rpack ;Get a packet. jmp nak ; Trashed packet: nak, retry. cmp ah, 'S' ;Is it a send initiate packet? jne rinit3 ;If not see if its an error. mov ebquot, 'Y' ;Initialize my 8th-bit quote flag ;[29g] mov ah, numtry ;Get the number of tries. mov oldtry, ah ;Save it. mov numtry, 0 ;Reset the number of tries. mov ax, argblk ;Returned packet number. (Synchronize them.) call incpkt ;Increment the packet number. mov ax, argbk1 ;Get the number of arguments received. mov bx, offset data ;Get a pointer to the data. call spar ;Get the 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 argbk1, ax ;Store the returned number of arguments. call ack1 ;ACK the packet. jmp abort mov ah, 'F' ;Set the state to file send. mov state, ah ret rinit3: cmp ah, 'E' ;Is it an error packet? jne rinit4 call error rinit4: jmp abort ; Receive file rfile: cmp numtry, maxtry ;Have we reached the maximum number of tries? jl rfile1 mov dx, offset ermes8 ;Print this error and die. jmp fatal rfile1: inc numtry ;Save the updated number of tries. call rpack ;Get a packet. jmp nak ; Trashed packet: nak, retry. cmp ah, 'S' ;Is it a send initiate packet? jne rfile2 ; No, try next type. cmp oldtry, imxtry ;Have we reached the maximum number of tries? jl rfil12 ;If not proceed. mov dx, offset ermes7 ;Print this error and die. jmp fatal rfil12: call chkpol ;Check the packet number, is it right? jmp nak ;No, NAK and try again. 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 argbk1, ax ;Save the number of arguments. call reack ;Re-ACK the old packet. jmp abort ret rfile2: cmp ah, 'Z' ;Is it an EOF packet? jne rfile3 ; No, try next type. cmp oldtry, maxtry ;Have we reached the maximum number of tries? jl rfil21 ;If not proceed. mov dx, offset ermes9 ;Print this error and die. jmp fatal rfil21: call chkpol ;Check the packet number, is it right? jmp nak ;No, NAK and try again. mov argbk1, 0 ;No data. call reack ;Re-ACK the previous packet jmp abort ret rfile3: cmp ah, 'F' ;Start of file? jne rfile4 call chkpeq ;Packet numbers equal? jmp nak ; No, NAK it and try again. call incpkt ;Increment the number of packets. call gofil ;Get a file to write to. jmp abort call init1 ;Initialize all the file buffers. call upack ;Update counters and ACK the packet. jmp abort mov state, 'D' ;Set the state to data receive. ret rfile4: cmp ah, 'B' ;End of transmission? jne rfile5 call chkpeq ;Packet numbers equal? jmp nak ; No, NAK it and try again. call ack ;ACK the packet. jmp abort mov state, 'C' ;Set the state to complete. ret rfile5: cmp ah, 'E' ;Is it an error packet? jne rfile6 call error rfile6: jmp abort ; Receive data rdata: cmp numtry, maxtry ;Get the number of tries. jl rdata1 mov dx, offset erms10 ;Print this error and die. jmp fatal rdata1: inc numtry ;Save the updated number of tries. call rpack ;Get a packet. jmp nak ; Trashed packet: nak, retry. cmp ah, 'D' ;Is it a data packet? je rdat11 jmp rdata2 ; No, try next type. rdat11: call chkpeq ;Packet numbers equal? jmp rdat12 ; No, check if previous packet. call incpkt ;Increment the number of packets. mov ax, argbk1 ;Get the length of the data. cmp cxzflg, 0 ;[19f] interrupt requested? jne rdat1a ;[19f] yes - skip put to file. call ptchr jmp abort ; Unable to write out chars;abort. call upack ;ACK the packet. jmp abort ret rdat1a: mov bx, offset data ;[19f] data location mov ah, cxzflg ;[19f] get the ^X/^Z flag mov [bx], ah ;[19f] stick it in the packet mov argbk1, 1 ;[19f] data length is 1 call uupack ;[19f] ACK the packet (without zeroing argbk1) jmp abort ;[19f] ret ;[19f] rdat12: cmp oldtry, maxtry ;Have we reached the maximum number of tries? jl rdat13 ;If not proceed. mov dx, offset erms10 ;Print this error and die. jmp fatal rdat13: call chkpol ;Check the packet number, is it right? jmp nak ;No, NAK it and try again. mov argbk1, 0 ;No data. call reack ;Re-ACK the previous packet. jmp abort ret rdata2: cmp ah, 'F' ;Start of file? jne rdata3 ; No, try next type. cmp oldtry, maxtry ;Have we reached the maximum number of tries? jl rdat21 ;If not proceed. mov dx, offset ermes8 ;Print this error and die. jmp fatal rdat21: call chkpol ;Check the packet number, is it right? jmp nak ; No, NAK it and try again. mov argbk1, 0 ;No data. call reack ;Re-ACK the previous packet jmp abort ret rdata3: cmp ah, 'Z' ;Is it a EOF packet? je rdat32 jmp rdata4 ;Try and see if its an error. rdat32: call chkpeq ;Packet numbers equal? jmp nak ; No, NAK it and try again. call incpkt ;Increment the packet number. cmp cxzflg, 0 ;This file interrupted? [19f] start jne rdat3a ;yes jump cmp argbk1, 1 ;1 byte of data in EOF packet? jmp rdat3b ;no - finish up file mov bx, offset data ;pointer to data mov ah, [bx] ;get the data cmp ah, 'D' ;is it D as in Discard? jne rdat3b ;no - finish writing file rdat3a: mov dx, offset fcb ;get file's fcb call delete ;delete the file. cmp cxzflg, 'X' ;Kill one file or batch? jne rdat37 ;whole batch - leave flag mov cxzflg, 0 ;clear flag call intmsg ;clear message jmp rdat37 ;go to clean up. [19f] end rdat3b: mov bx, bufpnt ;Get the dma pointer. mov ax, 80H sub ax, chrcnt ;Get the number of chars left in the DMA. cmp ax, 80H jne rdat34 call outbuf ;Write out buffer if no room for ^Z. jmp abort jmp rdat36 ;Go close the file. rdat34: mov cl, 'Z'-100O ;Put in a ^Z for EOF. mov [bx], cl inc ax dec chrcnt mov cx, chrcnt mov temp, cx inc bx rdt3: inc ax cmp ax, 80H jg rdat35 ;Pad till full. mov cl, 1AH ;Use control-Z's ;[13] mov [bx], cl inc bx jmp rdt3 rdat35: call outbuf ;Output the last buffer. jmp abort ; Give up if the disk is full. rdat36: mov dx, offset fcb call closf ;Close up the file. rdat37: call upack ;ACK the packet. jmp abort mov state, 'F' ret rdata4: cmp ah, 'E' ;Is it an error packet. jne rdata5 call error rdata5: jmp abort ; Send a file. send: cmp wldflg,0FFh je send12 mov dircnt,0 ;If not wild, just use the name in the FCB mov dindex,0 call getopn ;Open the file jmps send19 send12: call getwld ;If wild, get sorted list of matching names jmp r ; on error, message already printed mov dindex,0 ;Start at first one call getfil ;Get and open first file jmp r send19: call init ;Paint the screen and initialize file buffers. call cfibf ;Clear out any stacked NAKs. mov pktnum, 0 ;Set the packet number to zero. mov numtry, 0 ;Set the number of tries to zero. mov numpkt, 0 ;Set the number of packets to zero. mov numrtr, 0 ;Set the number of retries to zero. call pretry ;Print the number of retries. mov state,'S' ;Set the state to receive initiate. send2: call pnmpkt ;Print the number of packets. cmp state, 'S' ;Are we in the send initiate state? jne send3 call sinit jmp send2 send3: cmp state, 'F' ;Are we in the file send state? jne send4 call sfile ;Call send file. jmp send2 send4: cmp state, 'D' ;Are we in the data send state? jne send5 call sdata jmp send2 send5: cmp state, 'Z' ;Are we in the EOF state? jne send6 call seof jmp send2 send6: cmp state, 'B' ;Are we in the eot state? jne send7 call seot jmp send2 send7: cmp state, 'C' ;Are we in the send complete state? jne send8 mov dx, offset infms3 ;Plus a little cuteness. cmp cxzflg, 0 ;[19f] Interrupted? je send7a ;[19f] no mov dx, offset infms7 ;[19f] substitute "interrupted" message send7a: call fnstat ret send8: mov dx, offset infms4 ;Plus a little cuteness. call fnstat ret ; Send routines ; Send initiate sinit: cmp numtry, imxtry ;Have we reached the maximum number of tries? jl sinit2 mov dx, offset erms14 jmp fatal sinit2: mov ah, 'Y' ;Reset our quote capability ;[29g] begin cmp parflg, parnon ;If we have parity, je sini21 ; send our quote preference mov ah, dqbin sini21: mov ebquot, ah ;Set our quote capability ;[29g] end inc 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 argbk1, ax ;Save the number of arguments. mov ax, numpkt ;Get the packet number. mov argblk, ax mov ah, 'S' ;Send initiate packet. call spack ;Send the packet. jmp abort call rpack ;Get a packet. jmp r ; Trashed packet don't change state, retry. cmp ah, 'Y' ;ACK? jne sinit3 ;If not try next. call chkpeq ;Is it the right packet number? jmp nretry ;Increment the retries and go try again. call incpkt ;Increment the packet number. mov ax, argbk1 ;Get the number of pieces of data. mov bx, offset data ;Pointer to the data. call spar ;Read in the data. mov ah, numtry ;Get the number of tries. mov oldtry, ah ;Save it. mov numtry, 0 ;Reset the number of tries. mov state, 'F' ;Set the state to file send. ret sinit3: cmp ah, 'N' ;NAK? jne sinit4 ;If not see if its an error. call nretry ret sinit4: cmp ah, 'E' ;Is it an error packet? jne sinit5 call error sinit5: jmp abort ; Send file header sfile: cmp numtry, maxtry ;Have we reached the maximum number of tries? jl sfile1 mov dx, offset erms14 jmp fatal sfile1: inc numtry ;Increment it. mov cxzflg, 0 ;[19f] clear ^X/^Z flag push ds pop es mov di, offset data ;Get a pointer to our data block. mov si, offset fcb+1 ;Pointer to file name in FCB. mov cx,11 sfil11: cmp cx,3 ;Separate file type with period jne sfil12 mov al,'.' stosb sfil12: lodsb and al,7Fh ;Strip off attribute bits cmp al,' ' ;Printable, nonspace characters only jbe sfil13 cmp al,7Fh jae sfil13 stosb sfil13: loop sfil11 mov byte ptr [di],'$' ;Terminate filename for printing sub di, offset data mov argbk1, di ;Save number of characters in name call clrfln mov dx, offset data ;Print file name. call tmsg mov ax, pktnum ;Get the packet number. mov argblk, ax mov ah, 'F' ;File header packet. call spack ;Send the packet. jmp abort call rpack ;Get a packet. jmp r ; Trashed packet don't change state, retry. cmp ah, 'Y' ;ACK? jne sfile2 ;If not try next. call chkpeq ;Packet number right. jmp nretry ;Increment the retries and go try again. sfil14: call incpkt ;Increment the packet number. call updat ;Update the number of tries. sfil15: mov byte ptr fcb+20h,0 ;Set the record number to zero. mov eoflag, 0 ;Indicate not EOF. mov filflg, 0FFh ;Indicate file buffer empty. call gtchr jmp sfil16 ;Error go see if its EOF. jmp sfil18 ;Got the chars, proceed. sfil16: cmp ah, 0FFH ;Is it EOF? je sfil17 jmp abort ;If not give up. sfil17: mov state, 'Z' ;Set the state to EOF. ret sfil18: mov siz, ax mov state, 'D' ;Set the state to data send. ret sfile2: cmp ah, 'N' ;NAK? jne sfile3 ;Try if error packet. call chkpom ;Is the packet's number one more than now? jmp nretry ;Increment the retries and go try again. jmp sfil14 ;If so, join the ACK. sfile3: cmp ah, 'E' ;Is it an error packet. jne sfile4 call error sfile4: jmp abort ; Send data sdata: cmp cxzflg, 0 ;[19f] Interrupt flag on? je sdata0 ;[19f] no mov state, 'Z' ;[19f] yes - abort sending file ret sdata0: cmp numtry, maxtry ;Have we reached the maximum number of tries? jl sdata1 mov dx, offset erms14 jmp fatal sdata1: inc numtry ;Increment it. mov dx, offset data ;Get a pointer to our data block. mov datptr, dx mov dx, offset filbuf ;Pointer to chars to be sent. mov cbfptr, dx mov cx, 1 ;First char. sdat11: mov bx, cbfptr mov ah, [bx] inc cbfptr mov bx, datptr mov [bx], ah ;Put the char in the data packet. inc datptr ;Save position in data packet. inc cx ;Increment the count. cmp cx, siz ;Have we transfered that many? jle sdat11 ;If not get another. mov ax, siz ;Number of char in char buffer. mov argbk1, ax mov ax, pktnum ;Get the packet number. mov argblk, ax mov ah, 'D' ;Data packet. call spack ;Send the packet. jmp abort call rpack ;Get a packet. jmp r ; Trashed packet don't change state, retry. cmp ah, 'Y' ;ACK? jne sdata2 ;If not try next. call chkpeq ;Right packet number? jmp nretry ;Increment the retries and go try again. sdat12: call incpkt ;Increment the packet number. call updat ;Update the number of tries. cmp argbk1,1 ;1 byte of data there? [19f] start jne sdt12b ;no - go on mov bx, offset data ;pointer to data mov ah, [bx] ;get the data cmp ah, 'X' ;an 'X'? je sdt12a ;yes - go cmp ah, 'Z' ;or a 'Z' je sdt12a ;also go jmp sdt12b ;neither one - go on sdt12a: mov cxzflg, ah ;'X' or 'Z' - set the interrupt flag [19f] end ret sdt12b: call gtchr jmp sdat13 ;Error go see if its EOF. mov siz, ax ;Save the size of the data gotten. ret sdat13: cmp ah, 0FFH ;Is it EOF? je sdat14 jmp abort ;If not give up. sdat14: mov state, 'Z' ;Set the state to EOF. ret sdata2: cmp ah, 'N' ;NAK? jne sdata3 ;See if is an error packet. call chkpom ;Is the packet's number one more than now? jmp nretry ;Increment the retries and go try again. jmp sdat12 sdata3: cmp ah, 'E' ;Is it an error packet. jne sdata4 call error sdata4: jmp abort ; Send EOF seof: cmp numtry, maxtry ;Have we reached the maximum number of tries? jl seof1 mov dx, offset erms14 jmp fatal seof1: inc numtry ;Increment it. mov ax, pktnum ;Get the packet number. mov argblk, ax mov argbk1, 0 ;No data. cmp cxzflg, 0 ;[19f] interrupt flag set? je seof1a ;[19f] no - go on mov bx, offset data ;[19f] point to data mov ah, 'D' ;[19f] get 'D' as in Discard mov [bx], ah ;[19f] stuff it into packet mov argbk1, 1 ;[19f] set data length of 1 seof1a: mov ah, 'Z' ;EOF packet. call spack ;Send the packet. jmp abort call rpack ;Get a packet. jmp r ; Trashed packet don't change state, retry. cmp ah, 'Y' ;ACK? jne seof2 ;If not try next. call chkpeq ;Is it the right packet number? jmp nretry ;Increment the retries and go try again. seof12: call incpkt ;Increment the packet number. call updat ;Update the number of tries. mov dx, offset fcb ;Close the file. call closf call getfil ;Get and open the next file. jmp seof13 ; No more. mov state, 'F' ;Set the state to file send. cmp cxzflg, 'X' ;[19f] 'X' in interrupt flag? mov cxzflg, 0 ;[19f] meantime reset it jne sef13a ;[19f] no - go on call intmsg ;[19f] clear interrupt message sef13a: ret ;[19f] goodbye seof13: mov state, 'B' ;Set the state to EOT. ret seof2: cmp ah, 'N' ;NAK? jne seof3 ;Try and see if its an error packet. call chkpom ;Is the packet's number one more than now? jmp nretry ;Increment the retries and go try again. jmp seof12 seof3: cmp ah, 'E' ;Is it an error packet? jne seof4 call error seof4: jmp abort ; Send EOT seot: cmp numtry, maxtry ;Have we reached the maximum number of tries? jl seot1 mov dx, offset erms14 jmp fatal seot1: inc numtry ;Increment it. mov ax, pktnum ;Get the packet number. mov argblk, ax mov argbk1, 0 ;No data. mov ah, 'B' ;EOF packet. call spack ;Send the packet. jmp abort call rpack ;Get a packet. jmp r ;Trashed packet don't change state, retry. cmp ah, 'Y' ;ACK? jne seot2 ;If not try next. call chkpeq ;Is it the right packet number. jmp nretry ;Increment the retries and go try again. seot12: call incpkt ;Increment the packet number. call updat ;Update the number of tries. mov state, 'C' ;Set the state to file send. ret seot2: cmp ah, 'N' ;NAK? jne seot3 ;Is it error. call chkpom ;Is the packet's number one more than now? jmp nretry ;Increment the retries and go try again. jmp seot12 seot3: cmp ah, 'E' ;Is it an error packet. jne seot4 call error seot4: jmp abort