From ebb2ff2af569d5822b70ee555a32d27cf7494816 Mon Sep 17 00:00:00 2001 From: Jeff Armstrong Date: Sun, 25 Oct 2026 17:42:06 -0400 Subject: Initial import of 4.11 --- src/cpspk1.asm | 1904 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1904 insertions(+) create mode 100644 src/cpspk1.asm (limited to 'src/cpspk1.asm') diff --git a/src/cpspk1.asm b/src/cpspk1.asm new file mode 100644 index 0000000..6ea4831 --- /dev/null +++ b/src/cpspk1.asm @@ -0,0 +1,1904 @@ +; CPSPK1.ASM +; KERMIT - (Celtic for "FREE") +; +; This is the CP/M-80 implementation of the Columbia University +; KERMIT file transfer protocol. +; +; Version 4.0 +; +; Copyright June 1981,1982,1983,1984 +; Columbia University +; +; Originally written by Bill Catchings of the Columbia University Center for +; Computing Activities, 612 W. 115th St., New York, NY 10025. +; +; Contributions by Frank da Cruz, Daphne Tzoar, Bernie Eiben, +; Bruce Tanner, Nick Bush, Greg Small, Kimmo Laaksonen, Jeff Damens, and many +; others. +; +; This file contains the (system-independent) routines that implement +; the KERMIT protocol, and the commands that use them: +; RECEIVE, SEND, FINISH, and LOGOUT. +; +; revision history: +; +;edit 23, 16-Jan-1991 by MF. The bug of (22) was not fixed (although +; the error described needed to be corrected). Really fixed the bug this: +; time. changed "lda 'E'" after "ptch9b" to "mvi a,'E'" -- Zilog +; mnemonic thinking must've addled my brain! +;edit 22, 14-Jan-1991 by MF. Fix bug in the code which sends an "E" packet +; to the remote Kermit on encountering "disk full" so that +; uncontrollified is not copied to the packet data area (and +; hence sent to the remote Kermit). This should fix a bug reported +; by Russell Lang of Monash University in Australia wherein a PC +; running Kermit in Server mode complained of invalid characters when +; receiving the "disk full" error packet from CP/M Kermit. +;edit 21 of 3-Jan-1991 by MF. Reverse part of edit 20 which flushes comm +; input at EOF send: the problem of multiple copies of packets being +; sent when a stream of files being sent is partially interrupted with +; ^X has been fixed by modifying "inchr" in CPSPK2.ASM. +;edit 20, 2-Jan-1991 by MF. Tightened up code just after "sdata1" and around +; "sdat14". Added code to flush comm input after user has typed ^X +; or ^Z to interrupt file sends so that duplicate packets are not +; sent after the interrupt character (especially ^X) has been typed. +;edit 19, 14-Dec-1990 by MF. Place "<<>>" around "F" and "X" packets coming +; as replies to REMOTE commands a la VMS Bliss Kermit. +; Also type each character of "X" or "F" packet explicitly in case +; dollar-signs are part of the filename (as in VMS Bliss Kermit +; when a REMOTE TYPE is given and SET FILE NAMING FULL is in effect). +; Expanded code is at label rfil3f. +;edit 18, 27-Nov-1990 by MF. Fix bug introduced with edit 17 which resulted +; in "E" packet being sent twice when receiving file(s) and disk-full +; occurred. Sorry about that, folks! +;edit 17, 27-Nov-1990 by MF. When receiving files, make the decision as to +; whether to delete a partially-received file on a "disk full" +; condition subject to the setting of the SET INCOMPLETE-FILES +; switch in conformity with the behavior of MSDOS Kermit. +; An "E" packet is still sent to the remote Kermit. Also try to close +; any incomplete file whether deleting it or not (labels rdat16 and +; rdat3a). If keeping incomplete files, try to write outstanding +; buffers to disk, giving an error if the disk is full. +;edit 16, 23-Nov-1990 by MF. When receiving, cause the file being written +; to disk to **always** be deleted and an "E" packet to be sent when a +; "disk full" condition is encountered (per suggestion of +; RJL@MONU1.CC.MONASH.EDU.AU). +;edit 15, 15-Nov-1990 by MF. Changed code for the Receive Complete state +; to always go into RECEIVE if AUTORECEIVE is on. This will happen +; most of the time anyway as most mainframe Kermits issue a prompt +; after a single SEND command (wild-carded or not), thus guaranteeing +; that the modem status check of Kermit-80 ver. 4.09 would **always** +; have characters ready for input (the mainframe Kermit's prompt), +; defeating the status check and the Console input check (originally +; intended to drop the user out of the loop if he/she typed a key with +; no comm input present). Eliminate "any key" message there also. +; the user can drop out by hitting ^C. +; Of course, none of the foregoing applies if the Receive Complete +; state occurs as the result of a "Get" command where Autoreceive +; is meaningless and we just drop back to Kermit command-level. +;edit 14, 1-Oct-1990 by MF. Added code to send an "I" packet before an +; "R" packet in GET command. +; Modified routine "sinit" to ignore "E" packets when sending an +; "i" packet (per KPROTO.DOC). +;edit 13, 14-Sep-1990 by MF. Added code to implement SET FILE COLLISION +; and SET INCOMPLETE commands. +;edit 12, 9-Sep-1990 by MF. Added code to prevent packet counts +; from being displayed during Remote commands. Fixed +; AUTORECEIVE code, file colision Rename algorithm and eliminated +; multiple display of initial messages during GET/RECEIVE. +; edit 11, 28 July, 1987 by OBSchou. Commented out capas etc support +; (Long packets etc) as this is not worth the effort coding... but +; I have left what WAS done for any enthusiast. Also set in a few +; to NOT write to screen if SET TERMINAL QUIET set. Hopefully speeds +; up transfers on systems taking forever to update screens. +; +; edit 10, 8 April, 1987 by OBSchou. Tarted up all sorts of bits n bobs +; to cope with all the new aditions for Kermit-80 V 4.09 +; Look for the [10] for most cahnges. spar and rpar largely replaced +; +; edit 9, March 30th by OBSchou. Set bits for automatically receiving +; another file if a remote sender sends files in seperate sessions. +; The code simply checks the serial line, and if there is some +; activity, assume its another SEND INIT packet. As there is no +; simple way to go to receive with the control-a, just ignore the +; packet. Causes one retry on the sender, but so what. Really +; should make it a server gizzmo. +; +; edit 8: January 28, 1987 by OBSchou +; Two major issues: firstly split CPSPKT.ASM into CPSPK(1 2).ASM +; making it far easier to handle this file. +; Second, some mode to the GET routines to correctly print the file +; name instead of the fireworks. Trouble was with GET +; and RECEIVE . However, new bugs discovered... +; +; edit 7: August 11, 1986 Godfrey N. Nix [gnn] Nottingham University +; To ignore echoed packets (ie send 'S' receive 'S' before 'A'); +; To allow character other than SOH for packet header (see also +; updates to CP4MIT and CP4UTL for other code needed); +; To permit SEND and RECEIVE to specify a host filename which +; is of a different structure to that of CP/M. +; +; edit 6a: [OBSchou] 7 March, 1985. +; Edited file with additions from MJ Carter. He writes: +; 25th September 1985, M J Carter [majoc], Nottingham University +; Code in gofil() amended, for exactly the same reasons to the +; alteration to cmifil() in cpscmd.asm. If there is any deep +; reason why gofil() has to be used instead of a call to comnd(cmofil), +; I can't see it. The bug (on a British Micro Mimi 803) caused +; gofil() to overwrite existing files in GET and RECEIVE, even +; with file warning SET ON. +; +;edir 6: November 22, 1984 +; Change SEND's 'Unable to find file' error exit from calling +; error3 to calling prtstr instead. I don't know about you, but +; I greatly dislike having messages dumped into pre-existing +; junk on the screen where I have to spend lots of time hunting +; for them. [Hal Hostetler] +; +; edit 5: September 9, 1984 +; Call flsmdm in init to flush old input when starting transfers. +; Select console before returning from inpkt. +; Replace inline code with calls to makfil/clofil to set up for +; multisector buffering on output. +; Remove superfluous call to clrlin in error3. +; +; edit 4: August 21, 1984 (CJC) +; Fix comment in inpkt: packet is terminated by NUL on return, not CR. +; If debugging, display the outgoing packet before putting the EOL +; character on, so the dumped packet doesn't get overwritten. +; +; edit 3: July 27, 1984 +; add link directive for LASM. CP4PKT is linked by CP4MIT, and links +; to CP4TT. Add Toad Hall TACtrap to permit operations through a TAC. +; +; edit 2: June 8, 1984 +; formatting and documentation; remove some unused labels; move setpar +; to cp4mit.m80; add module version string; make all arithmetic on +; 'pktnum' modulo 64; apply defaults correctly for missing parameters +; in send-init packet (and corresponding ack). +; +; edit 1: May, 1984 +; extracted from CPMBASE.M80 version 3.9; modifications are described +; in the accompanying .UPD file. +; +pk1ver: db 'CPSPK1.ASM (23) 16-Jan-1991$' ; name, edit number, date + +; GET command [gnn] +; here from: kermit + +read: mvi a,0ffh ;[obs 8] we are doing a get + sta getrxflg ;[obs 8] so set flag + lxi d,remdat ;Where to put the text (if any.) + mvi a,cmtxt + call comnd ;Get either some text or a confirm. + jmp kermt3 ; Didn't get anything. + ora a ;Get any chars? + jz kermt3 ;[gnn] GET must have a filename + sta rdl ;Store the number of chars. + xchg ;Get pointer into HL. + mvi m,'$' ;Put in a dollar sign for printing. + call init ;Clear the line and initialize the buffers. + lda quietd ; quiet display? + ana a + jz read01 ;[MF]No, go ahead and position cursor + call prcrlf ;[MF]Yes, keep from overwriting the prompt + jmp read00 ;[MF]and write filename +read01: call scrfln ;Position cursor [MF] +read00: lxi d,remdat ;Print the file name, in either case + call prtstr + jmp read0a ;[gnn] go get local name if any + + +; enter here for RECEIVE command [gnn] +read0: mvi a,0 ;[gnn] + sta rdl ;[gnn][MF] flag entry as receive, not get + sta getrxflg ;[obs 8] doing a receive, so reset flag + call init ;clear line, initialise buffers +read0a: lxi d,remnam ;[gnn] save local name here + mvi a,cmtxt ;[gnn] + call comnd ;[gnn] read second filename if present + jmp kermt3 ;[gnn] error exit + sta remlen ;[gnn] save length of name, may be zero + sta getrxflg ;[obs 8] May also be receive so + ;[obs 8]pretend get for printing filename + lda rdl ;[gnn] look at first name + ora a ;[gnn] receive or get? + jz read1 ;[gnn] receive + + mvi a,'I' ;[MF]Set state to send "I" packet + sta state ;[MF]... + +; jmp read12 ;[obs] [gnn] does not want this + +read1: ;call init ;Clear the line and initialize the buffers. +read12: xra a + sta czseen ;Clear the ^X/^Z flag initially. + lxi h,0 + shld numpkt ;Set the number of packets to zero. + shld numrtr ;Set the number of retries to zero. + sta pktnum ;Set the packet number to zero. + sta numtry ;Set the number of tries to zero. + lda quietd ; quiet display? + ana a + jnz read13 ; yes, so dont write... + call scrnrt ;Position cursor + lxi h,0 + call nout ;Write the number of retries. +read13: lda rdl ;[MF]Get or receive? + ora a ;[MF]... + jnz read2 ;[MF]Get, don't reset state + mvi a,'R' + sta state ;Set the state to receive initiate. + ;... +; +;RECEIVE state table switcher. + +read2: lda quietd ; noisy display? + ana a + jnz read21 ; no, a quiet one + lda remtxt ;[MF] In Remote command? + ora a + jnz read21 ;[MF] Yes, don't write to screen + call scrnp ;Position cursor + lhld numpkt + call nout ;Write the current packet number. +read21: lda state ;Get the state. + cpi 'D' ;Are we in the DATA receive state? + jnz read22 + call rdata + jmp read2 + +read22: cpi 'X' ; F packet but not an F packet? + jnz read3 ; nope, so try next one + call rfile ; 'get' the filename (but dont open it) + jmp read2 + +read3: cpi 'F' ;Are we in the FILE receive state? + jnz read4 + call rfile ;Call receive file. + jmp read2 + +read4: cpi 'R' ;Are we in the Receive-Initiate state? + jnz read5 + call rinit + lda state ;[jd] get new state + cpi 'F' ;[jd] went into receive state? + jnz read2 ;[jd] no + lxi d,inms24 ;[jd] yes, get receiving... message + call finmes ;[jd] go print it + jmp read2 + +read5: cpi 'C' ;Are we in the Receive-Complete state? + jnz read6 + lxi d,infms3 ;Put in "Complete" message. + lda czseen ;Or was it interrupted? + ora a ; . . . + jz read5a ;No. + xra a ;Yes, clear flag. + sta czseen ; ... + lxi d,inms13 ;Issue "interrupted" message. +read5a: lda remtxt ;[MF] Doing a Remote command? + ora a + cz finmes ;Print completion message in right place if not +; + lda rdl ;[MF]Receive or Get? + ora a ;[MF]... + jnz kermit ;[MF]Get, Autoreceive means nothing. + lda autorc ; see if we want autoreceives + ana a + jz kermit ;[MF]No autoreceives, so drop out + lxi d,autmes ;[MF]Yes, tell the user what we're doing + call prtstr ;[MF]... + jmp read1 ;[MF]Try another Receive (we get one + ;[MF]retry from the sender as the ^A is lost) + +read6: cpi 'Y' ;[MF]Simple ack (from remote command)? + jz kermit ;[MF]Yes + + cpi 'I' ;[MF]Exchanging parameters via info packet? + jnz read7 ;[MF]No + call sinit ;[MF]Yes, send the packet + lda state ;[MF]Now see what happened + cpi 'X' ;[MF]Did we exchange parameters successfully? + jz read6a ;[MF]Yes, go send the filespec + cpi 'A' ;[MF]No, are we in abort state? + jnz read2 ;[MF]No, try again + jmp kermit ;[MF]Yes, it's a real disaster, we must stop +read6a: lda rdl ;[MF]Get length of filespec + sta argblk+1 ;[MF]as length of packet + mov c,a ;[MF]We must copy the filespec + mvi b,0 ;[MF]... + lxi h,remdat ;[MF]from the temporary buffer + lxi d,data ;[MF]to the packet data area + call mover ;[MF]Do it. +; for GET we must send the name of the file we want [gnn] + + mvi a,'1' ;Start with single character checksum + sta curchk ;Save the type + xra a ;Start a packet zero. + sta argblk + mvi a,'R' ;Receive init packet. + call spack ;Send the packet. + jmp kermt3 ; Die! + xra a + sta czseen ;Clear the ^X/^Z flag initially. + lxi h,0 + shld numpkt ;Set the number of packets to zero. + sta pktnum ;Set the packet number to zero. + sta numtry ;Set the number of tries to zero. + mvi a,'R' ;[MF]Set state to Receive-Initiate + sta state ;[MF]... + jmp read21 ;[MF]and go around again + ;[MF]without retyping packet-number + +read7: cpi 'A' ;Are we in the Receive-"Abort" state? + jnz read8 +read8: lxi d,infms4 ;Anything else is equivalent to "abort". + call finmes + jmp kermit +; +; Receive routines + +; Receive init +; called by: read + +rinit: lda numtry ;Get the number of tries. + cpi imxtry ;Have we reached the maximum number of tries? + jm rinit2 + lxi d,ermes4 + call error3 ;Move cursor and print an error message. + jmp abort ;Change the state to abort. + +rinit2: inr a ;Increment it. + sta numtry ;Save the updated number of tries. + mvi a,'1' ;Reset block check type to single character + sta curchk ;Store as current type for initialization + call rpack ;Get a packet. + jmp nak ; Trashed packet: nak, retry. + cpi 'S' ;Is it a send initiate packet? + jnz rinit3 ;If not see if its an error. +rini2a: lda numtry ;Get the number of tries. + sta oldtry ;Save it. + xra a + sta numtry ;Reset the number of tries. + lda argblk ;Returned packet number. (Synchronize them.) + call countp + lda argblk+1 ;Get the number of arguments received. + lxi h,data ;Get a pointer to the data. + call spar ;Get the data into the proper variables. + lxi h,data ;Get a pointer to our data block. + call rpar ;Set up the receive parameters. + sta argblk+1 ;Store the returned number of arguments. + mvi a,'Y' ;Acknowledge packet. + call spack ;Send the packet. + jmp abort ; Failed, abort. + lda inichk ;Now switch to agreed upon check-type + sta curchk ;For all future packets + mvi a,'F' ;Set the state to file send. + sta state + ret + +rinit3: cpi 'E' ;Is it an error packet. + jnz nak0 ;If not NAK whatever it is. + call error + jmp abort +; +; Receive file +; called by: read + +rfile: lda numtry ;Get the number of tries. + cpi maxtry ;Have we reached the maximum number of tries? + jm rfile1 + lxi d,ermes5 + call error3 ;Move cursor and print an error message. + jmp abort ;Change the state to abort. + +rfile1: inr a ;Increment it. + sta numtry ;Save the updated number of tries. + call rpack ;Get a packet. + jmp nak ; Trashed packet: nak, retry. + cpi 'S' ;Is it a send initiate packet? + jnz rfile2 ; No, try next type. + lda oldtry ;Get the number of tries. + cpi imxtry ;Have we reached the maximum number of tries? + jm rfil12 ;If not proceed. + lxi d,ermes4 + call error3 ;Move cursor and print an error message. + jmp abort ;Change the state to abort. + +rfil12: inr a ;Increment it. + sta oldtry ;Save the updated number of tries. + lda pktnum ;Get the present packet number. + dcr a ;Decrement + ani 3FH ; modulo 64 + mov b,a + lda argblk ;Get the packet's number + cmp b ;Is the packet's number one less than now? + jnz nak0 ;No, NAK and try again. + call updrtr ;Update the retry count. + xra a + sta numtry ;Reset the number of tries. + lxi h,data ;Get a pointer to our data block. + call rpar ;Set up the parameter information. + sta argblk+1 ;Save the number of arguments. + mvi a,'Y' ;Acknowledge packet. + call spack ;Send the packet. + jmp abort ; Failed, abort. + ret + +rfile2: cpi 'Z' ;Is it an EOF packet? + jnz rfile3 ; No, try next type. + lda oldtry ;Get the number of tries. + cpi maxtry ;Have we reached the maximum number of tries? + jm rfil21 ;If not proceed. + lxi d,ermes6 + call error3 ;Move cursor and print an error message. + jmp abort ;Change the state to abort. + +rfil21: call tryagn + ret + +rfile3: cpi 'F' ;Start of file? + jnz rfil3b + mov c,a ;[MF]Save packet type + lda remtxt ;[MF]Doing a remote server command? + ora a ;[MF]... + mov a,c ;[MF]Restore packet type + jnz rfil3d ;[MF]If yes, same as x packet + call compp + jnz nak0 ;No, NAK it and try again. + call countp + mov c,a ;[MF] + lda remtxt ;[MF]Doing a remote command? + ora a ;[MF]... + mov a,c ;[MF] + jnz rfil3a ;[MF]Yes, don't open a file + call gofil ;Get a file to write to, and init output buffer. + jmp abort +rfil3a: lda numtry ;Get the number of tries. + sta oldtry ;Save it. + call ackp + mvi a,'D' ;Set the state to data receive. + sta state + lda czseen ;Check if we punted a file + cpi 'Z' ;and didn't want any more + rz ;If that was the request, keep telling other end + xra a ;Otherwise, clear flag (^X is only for one file) + sta czseen ;And store the flag back + ret + +rfil3b: cpi 'X' ;Start of 'file?' , but not a file? + jnz rfile4 +rfil3d: call compp + jnz nak0 ;No, NAK it and try again. + call countp + + call selcon ;[MF]Select Console + lda argblk+1 ; get length + ora a ;[MF]Anything to write? + jz rfil3e ;[MF]No + push psw ;[MF]Yes, save character count + mvi e,'<' ;[MF]Write "<<" as in VMSKermit + push d ;[MF]... + call outcon ;[MF]... + pop d ;[MF]... + call outcon ;[MF]... + pop psw ;[MF]Restore character count + lxi h,data ; lets write the filename (?) to display +rfil3f: push psw ;[MF]Save loop counter + mov e,m ;[MF]Get character to write + inx h ;[MF]and increment character pointer + push h ;[MF]Save the pointer + call outcon ;[MF]Write character to display + pop h ;[MF]Restore pointer + pop psw ;[MF]and loop counter + dcr a ;[MF]Decrement the counter + jnz rfil3f ;[MF]Display entire filename + mvi e,'>' ;[MF]Put in ">>" as in VMSKermit + push d ;[MF]... + call outcon ;[MF]... + pop d ;[MF]... + call outcon ;[MF]... + call prcrlf ;[MF]New line +rfil3e: lda numtry ;Get the number of tries. + sta oldtry ;Save it. + call ackp + mvi a,'D' ; expecting a D packet + sta state + lda czseen ;Check if we punted a file + cpi 'Z' ;and didn't want any more + rz ;If that was the request, keep telling other end + xra a ;Otherwise, clear flag (^X is only for one file) + sta czseen ;And store the flag back + ret + +rfile4: cpi 'B' ;End of transmission. + jnz rfile5 + call compp + jnz nak0 ;No, NAK it and try again. + xra a ;No data. (Packet number already in argblk). + sta argblk+1 + mvi a,'Y' ;Acknowledge packet. + call spack ;Send the packet. + jmp abort + mvi a,'C' ;Set the state to complete. + sta state + ret + +rfile5: cpi 'E' ;Is it an error packet. + jnz abort + call error + jmp abort +; +; Receive data +; called by: read + +rdata: lda numtry ;Get the number of tries. + cpi maxtry ;Have we reached the maximum number of tries? + jm rdata1 + lxi d,erms10 + call error3 ;Display error message. +rdat16: lda remtxt ;[MF]Is a Remote command in progress? + ora a ;[MF]... + jnz abort ;[MF]Yes, don't worry about file disposition + lda incflg ;[MF]Are we keeping incomplete files? + ora a ;[MF]... + jnz rdat17 ;[MF]Yes + lxi d,fcb ;[MF]No, close the file, ignoring errors + push d ;[MF]while protecting the pointer + mvi c,closf ;[MF]... + call bdos ;[MF]... + pop d ;[MF]Now delete the file, ignoring errors + mvi c,delf ;[MF]... + call bdos ;[MF]... + jmp abort ;Change the state to abort. +rdat17: call clofil ;[MF]Try to close the file, writing + ;[MF]outstanding buffers to disk + jmp rdat37 ;[MF]We can't, the disk is full + jmp abort ;[MF]Change the state to "abort" + +rdata1: inr a ;Increment it. + sta numtry ;Save the updated number of tries. + call rpack ;Get a packet. + jmp nak ; Trashed packet: nak, retry. + cpi 'D' ;Is it a data packet? + jnz rdata2 ; No, try next type. + call compp ;check for correct packet number (zero flag = ok) + jz rdat14 ;its correct + lda oldtry ;Get the number of tries. + cpi maxtry ;Have we reached the maximum number of tries? + jm rdat12 ;If not proceed. + lxi d,erms10 + call error3 ;Display err msg. + jmp rdat16 ;[MF]Change the state to abort. + +rdat12: call tryagn + ret + +rdat14: call countp + lda numtry ;Get the number of tries. + sta oldtry ;Save it. + lda argblk+1 ;Get the length of the data. + call ptchr + jmp rdat3b ;[MF] Unable to write out chars;abort. + xra a + sta numtry ;Reset the number of tries. + sta argblk+1 ;No data. (Packet number still in argblk.) + mov c,a ;Assume no data + lda czseen ;Check if control-X typed + ora a ; . . . + jz rdat15 ;Zero if not typed + mov c,a ;Get the type of character typed + mvi a,1 ;One data character + sta argblk+1 ;Save the count + mov a,c ;Get the possible data character + sta data ;Store in data area +rdat15: mvi a,'Y' ;Acknowledge packet. + call spack ;Send the packet. + jmp rdat16 ;[MF] + ret + +rdata2: cpi 'F' ;Start of file? + jnz rdata3 ; No, try next type. + lda oldtry ;Get the number of tries. + cpi maxtry ;Have we reached the maximum number of tries? + jm rdat21 ;If not proceed. + lxi d,ermes5 + call error3 ;Display err msg. + jmp rdat16 ;[MF]Change the state to abort. + +rdat21: call tryagn + ret + +rdata3: cpi 'Z' ;Is it a EOF packet? + jnz rdata4 ;Try and see if its an error. + call compp + jnz nak0 ;No, NAK it and try again. + call countp + lda argblk+1 ;Get the data length + cpi 1 ;Have one item? + jnz rdat33 ;If not, ignore data + lda data ;Yes, get the character + cpi 'D' ;Is it a 'D' for discard? + jz rdat36 ;If so, punt file +rdat33: lda remtxt ;[MF]Writing text to disk? + ora a ;[MF]... + jnz rdat38 ;[MF]No, don't close file + call clofil ;Finish off the file. + jmp rdat37 ; Give up if the disk is full. +rdat38: xra a ;Since we kept the file, + sta czseen ;don't say it was discarded. + lda numtry ;Get the number of tries. [MF] + sta oldtry ;Save it. [MF] + call ackp ;[MF] + jmp rdat39 ;[MF]and get ready to get more files +rdat36: lda numtry ;Get the number of tries. + sta oldtry ;Save it. + call ackp + lda remtxt ;[MF]Is a Remote command in progress? + ora a ;[MF]... + jnz rdat39 ;[MF]Yes, don't worry about file disposition + lda dscflg ;[MF]Is the file being punted because + ora a ;[MF]of a collision? + jnz rdat39 ;[MF]Yes, don't delete the existing file + lda incflg ;[MF]No, are we keeping incomplete files? + ora a ;[MF]... + jnz rdat3a ;[MF]Yes + lxi d,fcb ;[MF]No, close the file, + mvi c,closf ;[MF]ignoring errors + push d ;[MF]... + call bdos ;[MF]... + pop d ;[MF]Now delete the file, + mvi c,delf ;[MF]ignoring errors + call bdos ;[MF]... + jmp rdat39 ;[MF]and continue +rdat3a: call clofil ;[MF]Try to close the file, writing + ;[MF]outstanding buffers to disk + jmp rdat37 ;[MF]Can't, disk is full +rdat39: mvi a,'F' + sta state + ret + +rdat37: call ptchr9 ; Send "?Disk full" on the error line [MF] + ; and to the remote Kermit [MF] +rdat3b: lda remtxt ;[MF]Doing a Remote command? + ora a ;[MF]... + jnz abort ;[MF]Yes, just abort + lxi d,fcb ;[MF]Close the file, ignoring errors + push d ;[MF]Protect fcb pointer + mvi c,closf ;[MF]... + call bdos ;[MF]... + pop d ;[MF]Restore pointer + lda incflg ;[MF]Are we keeping incomplete files? + ora a ;[MF]... + jnz abort ;[MF]Yes, just abort transfer + mvi c,delf ;[MF]No, delete the file, ignoring errors + call bdos ;[MF]... + jmp abort ;[MF] abort transfer + +rdata4: cpi 'E' ;Is it an error packet. + jnz rdat16 ;[MF] + call error + jmp rdat16 ;[MF] +; +; SEND command +; here from: kermit + +send: mvi a,cmifi ;Parse an input file spec. + lxi d,fcb ;Give the address for the FCB. + call comnd + jmp kermit ; Give up on bad parse. +; section to get remote filename [gnn] + lxi d,remnam ;[gnn] where to put filename + mvi a,cmtxt ;[gnn] + call comnd ;[gnn] get the text to end of the line + jmp kermt3 ;[gnn] failure in reading buffer + sta remlen ;[gnn] save length (may be zero) +; + xra a + sta mfflg1 ; clear flags... + sta mfflg2 + sta mfflg3 ;[gnn] + sta fcbcnt ;[gnn] clear fcbcount + lxi h,fcb0 ;[gnn] and fcb pointer + shld xfcbptr +; + call mfname ;handle (multi) files + jnc send14 ;got a valid file-name + lxi d,erms15 + call prtstr ;Display error msg. ([hh] where it's visible) + jmp kermit + +send14: call init ;Clear the line and initialize the buffers. + xra a + sta pktnum ;Set the packet number to zero. + sta numtry ;Set the number of tries to zero. + sta wrn8 ;[jd] we haven't sent the 8-bit-lost warning + lxi h,0 + shld numpkt ;Set the number of packets to zero. + shld numrtr ;Set the number of retries to zero. + lda quietd ; a quiet display? + ana a + jnz send15 ; yup, dont write + call scrnrt ;Position cursor + lxi h,0 + call nout ;Write the number of retries. +send15: mvi a,'1' ;Reset to use single character checksum + sta curchk ;For startup + mvi a,'S' + sta state ;Set the state to receive initiate. + ;... +; +;SEND state table switcher + +send2: lda quietd ; a quiet display? + ana a + jnz send21 ; yes, so dont write + call scrnp ;Position cursor + lhld numpkt + call nout ;Write the packet number. +send21: lda state ;Get the state. + cpi 'D' ;Are we in the data send state? + jnz send3 + call sdata + jmp send2 + +send3: cpi 'F' ;Are we in the file send state? + jnz send4 + call sfile ;Call send file. + jmp send2 + +send4: cpi 'Z' ;Are we in the EOF state? + jnz send5 + call seof + jmp send2 + +send5: cpi 'S' ;Are we in the send initiate state? + jnz send6 + call sinit + lda state ;[jd] get state back + cpi 'F' ;[jd] into file send state yet? + jnz send2 ;[jd] no + lxi d,inms23 ;[jd] yes, print sending... + call finmes ;[jd] + jmp send2 + +send6: cpi 'B' ;Are we in the eot state? + jnz send7 + call seot + jmp send2 + +send7: cpi 'C' ;Are we in the send complete state? + jnz send8 ;No... + lxi d,infms3 ;Yes, write "Complete" message. + lda czseen ;Or was it interrupted? + ora a ; . . . + jz send7a ;No. + lxi d,inms13 ;Yes, then say "Interrupted" instead. +send7a: call finmes + jmp kermit + +send8: cpi 'A' ;Are we in the send "abort" state? + jnz send9 + lxi d,infms4 ;Print message. + call finmes + jmp kermit + +send9: lxi d,infms4 ;Anything else is equivalent to "abort". + call finmes + jmp kermit +; +; Send routines + +; Send initiate +; called by: send + +sinit: lda numtry ;Get the number of tries. + cpi imxtry ;Have we reached the maximum number of tries? + jm sinit2 + lxi d,erms14 + call error3 ;Display ermsg + jmp abort ;Change the state to abort. + +sinit2: inr a ;Increment it. + sta numtry ;Save the updated number of tries. + mvi a,'1' ;Reset to use single character checksum + sta curchk ;For startup + lda chktyp ;Get our desired block check type + sta inichk ;Store so we tell other end + lxi h,data ;Get a pointer to our data block. + call rpar ;Set up the parameter information. + sta argblk+1 ;Save the number of arguments. + lda numpkt ;Get the packet number. + sta argblk + lda state ; load state (I or S) + + call spack ;Send the packet. + jmp abort ; Failed, abort. + call rpack ;Get a packet. + jmp r ; Trashed packet don't change state, retry. + cpi 'Y' ;ACK? + jnz sinit3 ;If not try next. + call compp ;compare packets. If ok, zero flag set + rnz ;If not try again. + call countp ;increment packet number modulo 64 + lda argblk+1 ;Get the number of pieces of data. + lxi h,data ;Pointer to the data. + call spar ;Read in the data. (decode what they want) + lda numtry ;Get the number of tries. + sta oldtry ;Save it. + xra a + sta numtry ;Reset the number of tries. + lda state ; se if S or I state + cpi 'I' ; I state, so set X as next state + jnz sinita +sinitb: mvi a,'X' + sta state + ret + +sinita: lda inichk ;Get the agreed upon block check type + sta curchk ;Store as type to use for packets now + mvi a,'F' ;Set the state to file send. (Assumed) + sta state + call getfil ;Open the file. + ret ; assume success; mfname thinks the file exists. + +sinit3: cpi 'N' ;NAK? + jnz sinit4 ;If not see if its an error. + call updrtr ;Update the number of retries. + lda pktnum ;Get the present packet number. + inr a ;Increment + ani 3FH ; modulo 64 + mov b,a + lda argblk ;Get the packet's number. + cmp b ;Is the packet's number one more than now? + rnz ;If not assume its for this packet, go again. + xra a + sta numtry ;Reset number of tries. + mvi a,'F' ;Set the state to file send. + sta state + ret + +sinit4: cpi 'E' ;Is it an error packet. + jnz abort + lda state ;[MF]Get state + cpi 'I' ;[MF]If an "I" packet was sent, + jz sinitb ;[MF]Ignore the error, pretend success + call error ;[MF]else display the error info + jmp abort ;[MF]and abort +; +; Send file header +; called by: send +;[5a] Question [majoc]: Why could not the filename +; parsing have been done by comnd, like all the rest? + +sfile: lda numtry ;Get the number of tries. + cpi maxtry ;Have we reached the maximum number of tries? + jm sfile1 + lxi d,erms14 + call error3 + jmp abort ;Change the state to abort. + +sfile1: inr a ;Increment it. + sta numtry ;Save the updated number of tries. + xra a ;Clear A + sta czseen ;No control-Z or X seen + lxi h,data ;Get a pointer to our data block. + shld datptr ;Save it. +; use remote name if given, else use local name [gnn] + lda remlen ;[gnn] anything given? + ora a ;[gnn] + jnz sfile4 ;[gnn] use remote name + + lxi h,fcb+1 ;Pointer to the file name in the FCB. + shld fcbptr ;Save position in FCB. + mvi b,0 ;No chars yet. + mvi c,0 +sfil11: mov a,b + cpi 8H ;Is this the ninth char? + jnz sfil12 ;If not proceed. + mvi a,'.' ;Get a dot. + lhld datptr + mov m,a ;Put the char in the data packet. + inx h + shld datptr ;Save position in data packet. + inr c +sfil12: inr b ;Increment the count. + mov a,b + cpi 0CH ;Twelve? + jp sfil13 + lhld fcbptr + mov a,m + ani 7fH ;Turn off CP/M 2 or 3's high bits. + inx h + shld fcbptr ;Save position in FCB. + cpi '!' ;Is it a good character? + jm sfil11 ;If not get the next. + lhld datptr + mov m,a ;Put the char in the data packet. + inx h + shld datptr ;Save position in data packet. + inr c + jmp sfil11 ;Get another. + +sfil13: mov a,c ;Number of char in file name. + sta argblk+1 + lhld datptr + mvi a,'$' + mov m,a ;Put in a dollar sign for printing. + lda quietd ; a quiet display + ana a + jnz sfi13a ; yes, dont write + call scrfln ;Position cursor +sfi13a: lxi d,data ;Print the file name though, in either case + call prtstr + lda pktnum ;Get the packet number. + sta argblk + mvi a,'F' ;File header packet. + call spack ;Send the packet. + jmp abort ; Failed, abort. + call rpack ;Get a packet. + jmp r ; Trashed packet don't change state, retry. + cpi 'Y' ;ACK? + jnz sfile2 ;If not try next. + call compp + rnz ;If not hold out for the right one. +sfil14: call countp + lda numtry ;Get the number of tries. + sta oldtry ;Save it. + xra a + sta numtry ;Reset the number of tries. + sta bytes ;[10] clear the "bytes transferred" counter + sta bytes+1 ;[10] + sta bytes+2 ;[10] + sta bytes+3 ;[10] + call gtchr ;Fill the first data packet + jmp sfil16 ;Error go see if its EOF. +; ;Got the chars, proceed. + sta size ;Save the size of the data gotten. + mvi a,'D' ;Set the state to data send. + sta state + ret + +sfil16: cpi 0FFH ;Is it EOF? + jnz abort ;If not give up. + mvi a,'Z' ;Set the state to EOF. + sta state + ret + +sfile2: cpi 'N' ;NAK? + jnz sfile3 ;Try if error packet. + call updrtr ;Update the number of retries. + lda pktnum ;Get the present packet number. + inr a ;Increment + ani 3FH ; modulo 64 + mov b,a + lda argblk ;Get the packet's number. + cmp b ;Is the packet's number one more than now? + rnz ;If not go try again. + jmp sfil14 ;Just as good as a ACK;go to the ACK code. + +sfile3: cpi 'E' ;Is it an error packet. + jnz abort + call error + jmp abort + +; copy remote name into packet to send [gnn] +sfile4: xchg ;[gnn] keep pointer to packet + lxi h,remnam ;[gnn] set pointer to name + mov c,a ;[gnn] keep count of length + mov b,a ;[gnn] and set as loop counter +sfil41: mov a,m ;[gnn] get a character + stax d ;[gnn] copy it to packet + inx h ;[gnn] + inx d ;[gnn] move pointers + dcr b ;[gnn] + mov a,b ;[gnn] + ora a ;[gnn] done them all? + jnz sfil41 ;[gnn] repeat until done + xchg ;[gnn] get final position + shld datptr ;[gnn] and save it + jmp sfil13 ;[gnn] now go and send packet + +; +; Send data +; called by: send + +sdata: lda numtry ;Get the number of tries. + cpi maxtry ;Have we reached the maximum number of tries? + jm sdata1 + lxi d,erms14 + call error3 + jmp abort ;Change the state to abort. + +sdata1: inr a ;Increment it. + sta numtry ;Save the updated number of tries. + lxi h, data ;Get a pointer to our data block. + shld datptr ;Save it. + lxi h,filbuf ;Pointer to chars to be sent. + shld cbfptr ;Save position in char buffer. + mvi b,1 ;First char. +sdat11: lhld cbfptr + mov a,m + inx h + shld cbfptr ;Save position in char buffer. + mov c,a ;[jd] preserve character temporarily + lda quot8 ;[jd] doing eighth-bit quoting? + ora a ;[jd] + mov a,c ;[jd] restore char + jnz sdat4 ;[jd] using eighth-bit quoting, no warning + lda parity ;[jd] get parity + cpi parnon ;[jd] none? + mov a,c ;[jd] restore character + jz sdat4 ;[jd] no parity, leave char alone + lda wrn8 ;[jd] look at warning flag + ora a ;[jd] have we already given the warning? + jnz sdat5 ;[jd] yes, skip this + mov a,c ;[jd] restore character... + ani 80h ;[jd] examine parity + jz sdat5 ;[jd] no parity, no warning. + call parwrn ;[jd] ...print warning - parity lost + mvi a,0ffh ;[jd] remember that we sent the message + sta wrn8 ;[jd] +sdat5: mov a,c ;[jd] restore character again + ani 7fh ;[jd] strip parity so not checksummed +sdat4: lhld datptr + mov m,a ;Put the char in the data packet. + inx h + shld datptr ;Save position in data packet. + inr b ;Increment the count. + lda size ;Get the number of chars in char buffer. + cmp b ;Have we transfered that many? + jp sdat11 ;If not get another. + lda size ;Number of char in char buffer. + sta argblk+1 + lda pktnum ;Get the packet number. + sta argblk + mvi a,'D' ;Data packet. + call spack ;Send the packet. + jmp abort ; Failed, abort. + call rpack ;Get a packet. + jmp r ; Trashed packet don't change state, retry. + cpi 'Y' ;ACK? + jnz sdata2 ;If not try next. + call compp + rnz ;If not hold out for the right one. + lda argblk ;Get the packet number back + call countp + lda numtry ;Get the number of tries. + sta oldtry ;Save it. + xra a + sta numtry ;Reset the number of tries. + lda argblk+1 ;Get the data length + cpi 1 ;Check if only 1 character? + jnz sdat15 ;If not, just continue + lda data ;Got one character, get it from data + cpi 'Z' ;Want to abort entire stream? + jnz sdat14 ;If not, check for just this file + sta czseen ;Yes, remember it + jmp sdat16 ;[MF] and set EOF state +sdat14: cpi 'X' ;Desire abort of current file? + jnz sdat15 ;If not, just continue + sta czseen ;Yes, remember that + jmp sdat16 ;[MF] and set EOF +sdat15: lda czseen ;Also get control-Z flag + ora a ;Check if either given + jz sdat12 ;If neither given, continue +sdat16: mvi a,'Z' ;Change state to EOF + sta state ; . . . + ret ;And return + +sdat12: call gtchr + jmp sdat13 ;Error go see if its EOF. + sta size ;Save the size of the data gotten. + ret + +sdat13: cpi 0FFH ;Is it EOF? + jnz abort ;If not give up. + mvi a,'Z' ;Set the state to EOF. + sta state + ret + +sdata2: cpi 'N' ;NAK? + jnz sdata3 ;See if is an error packet. + call updrtr ;Update the number of retries. + lda pktnum ;Get the present packet number. + inr a ;Increment + ani 3FH ; modulo 64 + mov b,a + lda argblk ;Get the packet's number. + cmp b ;Is the packet's number one more than now? + rnz ;If not go try again. + jmp sdat12 ;Just as good as a ACK;go to the ACK code. + +sdata3: cpi 'E' ;Is it an error packet. + jnz abort + call error + jmp abort +; +; Send EOF +; called by: send + +seof: lda numtry ;Get the number of tries. + cpi maxtry ;Have we reached the maximum number of tries? + jm seof1 + lxi d,erms14 + call error3 + jmp abort ;Change the state to abort. + +seof1: inr a ;Increment it. + sta numtry ;Save the updated number of tries. + lda pktnum ;Get the packet number. + sta argblk + xra a + sta argblk+1 ;No data. + lda czseen ;Check if C-Z or C-X typed + ora a ; . . . + jz seof14 ;If not aborted, just keep going + mvi a,'D' ;Tell other end to discard packet + sta data ;Store in data portion + mvi a,1 ;One character + sta argblk+1 ;Store the length +seof14: mvi a,'Z' ;EOF packet. + call spack ;Send the packet. + jmp abort ; Failed, abort. + call rpack ;Get a packet. + jmp r ; Trashed packet don't change state, retry. + cpi 'Y' ;ACK? + jnz seof2 ;If not try next. + call compp + rnz ;If not hold out for the right one. +seof12: call countp + lda numtry ;Get the number of tries. + sta oldtry ;Save it. + xra a + sta numtry ;Reset the number of tries. + mvi c,closf ;Close the file. + lxi d,fcb + call bdos +;* Check if successful + lda czseen ;Desire abort of entire stream? + cpi 'Z' ;Desire abort of entire stream? + jz seof13 ;If so, just give up now + call mfname ;Get the next file. + jc seof13 ; No more. + call getfil ;and open it (assume success) + xra a ;Clear A + sta czseen ;Since we have not aborted this file + mvi a,'F' ;Set the state to file send. + sta state + ret + +seof13: mvi a,'B' ;Set the state to EOT. + sta state + ret + +seof2: cpi 'N' ;NAK? + jnz seof3 ;Try and see if its an error packet. + call updrtr ;Update the number of retries. + lda pktnum ;Get the present packet number. + inr a ;Increment + ani 3FH ; modulo 64 + mov b,a + lda argblk ;Get the packet's number. + cmp b ;Is the packet's number one more than now? + rnz ;If not go try again. + jmp seof12 ;Just as good as a ACK;go to the ACK code. + +seof3: cpi 'E' ;Is it an error packet. + jnz abort + call error + jmp abort +; +; Send EOT +; called by: send + +seot: lda numtry ;Get the number of tries. + cpi maxtry ;Have we reached the maximum number of tries? + jm seot1 + lxi d,erms14 + call error3 + jmp abort ;Change the state to abort. + +seot1: inr a ;Increment it. + sta numtry ;Save the updated number of tries. + lda pktnum ;Get the packet number. + sta argblk + xra a + sta argblk+1 ;No data. + mvi a,'B' ;EOF packet. + call spack ;Send the packet. + jmp abort ; Failed, abort. + call rpack ;Get a packet. + jmp r ; Trashed packet don't change state, retry. + cpi 'Y' ;ACK? + jnz seot2 ;If not try next. + call compp + rnz ;If not hold out for the right one. +seot12: call countp + lda numtry ;Get the number of tries. + sta oldtry ;Save it. + xra a + sta numtry ;Reset the number of tries. + mvi a,'C' ;Set the state to file send. + sta state + ret + +seot2: cpi 'N' ;NAK? + jnz seot3 ;Is it error. + call updrtr ;Update the number of retries. + lda pktnum ;Get the present packet number. + inr a ;Increment + ani 3FH ; modulo 64 + mov b,a + lda argblk ;Get the packet's number. + cmp b ;Is the packet's number one more than now? + rnz ;If not go try again. + jmp seot12 ;Just as good as a ACK;go to the ACK code. + +seot3: cpi 'E' ;Is it an error packet. + jnz abort + call error + jmp abort +; +; This routine sets up the data for init packet (either the +; Send_init or ACK packet). +; called by: rinit, rfile, sinit +; +; Called by rinit, rfile and sinit. See what WE want from the other fella +; +; [11] by OBS - Stripped out all the new capas code etc and reverted +; to Good Ol' Basic Kermit again! +; Those keen should study the followin gode with care, and remove +; or add semicolons as indicated. +; +; See also SPAR which decodes what comes in. It also decodes bits in +; the "capability" fields. (Two CAPAS files allowed from remote +; machines, but we will only send one at max.) Note that not all +; if any of the capability bits will be used. +; +; Definitions - init packet (data section only.. rest of header assumed OK) +; Byte 0 Maximum length I want to send +; 1 The Timeout I want you to use +; 2 Number of PAD characters I want tot use (May be null) +; 3 The PAD character I want to use (May be Null) +; 4 The End-of-Line character I will use (Carriage Return) +; 5 The control character Quote Character I will use (#) +; 6 The parity bit Quote Character I will use (&) +; 7 The Checktype I will use +; 8 The repeat prefix I will use (Null, as we cannot to repeats) +; 9 Capability Byte 0 (See SPAR for defs) +; 10 Capability byte 1 ( --- " --- but we will not send it.) +; 11 The number of packets I will send per window (not used) +; 12 MAXL1 - Long packet size, ms count +; 13 MAXL2 - Long packet size, ls count +; +; +; Enter with HL pointing to the "data" part of the packet. + +; +; older part of rpar follows... +; +; +rpar: lda rpsiz ;Get the receive packet size. + adi space ;Add a space to make it printable. + mov m,a ;Put it in the packet. + inx h ;Point to the next char. + lda rtime ;Get the receive packet time out. + adi space ;Add a space. + mov m,a ;Put it in the packet. + inx h + lda rpad ;Get the number of padding chars. + adi space + mov m,a + inx h + lda rpadch ;Get the padding char. + adi 100O ;Uncontrol it. + ani 7FH + mov m,a + inx h + lda reol ;Get the EOL char. + adi space + mov m,a + inx h + lda rquote ;Get the quote char. + mov m,a + inx h + mvi m,'Y' ;[jd] we know how to do 8-bit quoting + lda parity ;[jd] + cpi parnon ;[jd] parity none? + jz rpar1 ;[jd] yes, keep going + lda qbchr ;[jd] no, better request 8-bit quoting + mov m,a + +rpar1: + inx h ;Advance to next + lda chktyp ;Get desired block check type + mov m,a ;Store it + inx h ;Advance pointer + +; Comment out the next two lines for capas etc. WILL require debugging + mvi a,8 ; this id the older end for this routine. May be useful. + ret + +; [11] Rest not needed for now, commented out +; [10] (to ret) +; New additions to rpar follows... + +; lda rcap1 ; get the first capability byte +; ani 3eh ; mask out bit 0, ie only one CAPAS byte +; adi space ; tochar it +; mov m,a +; inx h +; mvi m,space ; No windows, ie space to packet +; inx h +; push h ; we need the HL regs for maths. +; lhld rdpkt ; get receive packet length +; lxi d,95 ; we want hl div 95 and hl mod 95 +; call divide ; return with divsion in hl, remainder in de +; mov a,l ; two sets of bytes +; pop h +; adi space ; tochar(maxl1) +; mov m,a +; inx h +; mov a,l +; adi space ; tochar(maxl2) +; mov m,a +; +; done all, set databytes = 12 and return +; mvi a,12 ; 12 bits of data +; ret + +;[11] End of commented out code for rpar + + +; +; This routine reads in all the send_init packet information. +; called by: rinit, sinit + +;[11] As for rpar, restore the "old" kermit code for non-capas Kermit. +;[10] (to ret at end) +; +; SPAR - routine to decode parameters received from the remote end +; +; Called by rinit,sinit +; +; Entry: a: Number of databytes in packet +; hl: Pointer to "data" part of packet +; +;spar: sta temp4 ; save for a while +; ; first clear some variables +; lda dspsiz ; get default "send" packet length +; sta spktl +; lda dstime ; get default time-out +; sta stimeo +; xra a ; set no pad characters by default +; sta spad +; lda dspadc ; get the default padding character +; sta spadc +; mvi a,cr ; default end of line character (CR) +; sta seol +; mvi a,dsquot ; default quote character +; sta squote +; mvi a,dsbqut ; default binary quote character +; sta qbchr +; mvi a,dschkt ; set checktype = 1 for inits +; sta inichk +; mvi a,space ; no repeat prefixing ( otherwise ~) +; sta srept +; +; Now follows the "capabilities" bits... 5 bits per capas byte. +; +; Note: Before extracting any data bits, apply unchar() to get the +; six ls bits. If bit 0 = 1 the a subsequent capaa byte follows +; +; Byte0: Bit 0: Set to 1 if there are subsequent CAPAS bytes +; 1: (Cap. 5) Set to 1 for long packets. Second byte +; AFTER the last capas byte has packet length DIV 95 +; and Thire byte has length MOD 95 +; 2: (Cap. 4) Sliding Windows. If used, first byte AFTER +; last capas byte has TOCHAR(no. of packets in window) +; 3: (Cap. 3) Ability to accept "A" (attribute packets) +; 4: (Cap. 2) Reserved +; 5: (Cap. 1) Reserved +; Byte 2 onward: not used in this implementation. Any capas bytes sent +; will be stored, however. +; +; lda temp4 ; get the number of bytes to test +; mov c,a ; to a count register +; mov a,m ; get first byte +; call decc ; unchar it, and decrement c +; sta spsiz ; save a send packet size +; jz sparx ; if no more, exit +; +; mov a,m ; get timout +; call decc +; sta stime ; save timeout +; jz sparx +; +; mov a,m ; get pad characters +; call decc +; sta spadc ; save it +; jz sparx +; +; mov a,m ; get pad character count +; call decc +; sta spad +; jz sparx +; +; mov a,m ; get send EOL +; call decc +; sta seol +; jz sparx +; +; mov a,m ; get control quote character +; call decc +; sta squote +; jz sparx +; +; mov a,m ; get binary (parity) quote char +; mov b,a ; this time we actually WANT accumulator +; cpi space ; are we doing 8th bit quoteing +; jz spar1 ; dont know, assume not +; cpi 'N' ; definately not? +; jz spar1 +; cpi 'Y' ; definately - use & +; jz spar2 +; sta squote ; else save the new character +;spar2: lda parity ; see if we are using the parity bit +; cpi parnon ; no parity => no quoting +; jz spar3 ; yup, so use the default quote character & +; +;spar1: xra a ; save not quoting +; sta squote +;spar3: call decc ; update counters etc +; jz sparx +; +; mov a,m ; get repeat prefixing +; call decc +; push psw ; save flags +; cpi space-32 ; we want it? +; jz spar4 +; sta srept +;spar4: pop psw ; restore flags +; jz sparx +; +; lxi d,scapas ; point to start of capability byte(s) +; push psw ; must do this... +;spar5: pop psw ; cos we restore the spack +; mov a,m +; call decc ; get scap1 (or n) +; sta scap1 +; push psw +; ani 01 ; another byte following? +; jnz spar5 +; pop psw ; see if any other data bytes (Windows etc) +; jz sparx +; +; mov a,m ; get window size +; call decc +; sta swindo +; jz sparx +; +; mov a,m ; get long packets ms bits +; call decc ; +; mov d,a ; unchared ms bits-ish +; mov a,m +; call decc ; ls bits-ish +; push h ; and we are doing maths +; push b ; and an intermediate result in c +; push psw ; we want flags and the ls bits... +; mvi b,0 +; mov c,d ; get ms bits-ish to bc +; push b ; get number to hl +; pop h +; now multipy by 95 +; dad h ;*2 +; dad h ;*4 +; dad h ;*8 +; dad h ;*16 +; push h ; *16 to ... +; pop d ; ... de +; dad h ;*32 +; dad d ; *(32+16) = *48 +; dad h ; *96 +; mov a,l ; *(96-1) +; sub c +; mov l,a +; mov a,0 +; sbb h +; mov h,a +; pop psw ; restore ls bitsish +; mov e,a +; mvi d,0 +; dad d ; *95 + ls bits. Phew. +; shld sdpkt ; save long packet length +; pop b +; pop h ; restore regs +; +;sparx: ret ; if here, (assume) no more data to read in +;[10] routines required follow +;decc: mov a,m ; get data byte +; sui space ; unchar it +; inx h ; increment input pointer +; dcr c ; decrement data counter +; ret ; return +;[10] end or spar replacement + +;[11] Restore older spar.... +; Older spar follows... +spar: sta temp4 ;Save the number of arguments. +; Initialize some variables to their required default values, so we use +; the right values even if the remote Kermit doesn't send the full packet: +; ; we don't do anything with timeout values yet. +; ; no default pad count/pad character? + mvi a,cr ; EOL character = carriage-return + sta seol + mvi a,'#' ; quote character = '#' + sta squote + mvi a,'&' ; eighth-bit quote character = '&' + sta qbchr + mvi a,'1' ; block-check = 1-character-checksum + sta inichk +; + mov a,m ;Get the max packet size. + sbi space ;Subtract a space. + sta spsiz ;Save it. + lda temp4 + cpi 3 ;Fewer than three pieces? + rm ;If so we are done. + inx h + inx h ;Increment past the time out info. + mov a,m ;Get the number of padding chars. + sbi space + sta spad + lda temp4 + cpi 4 ;Fewer than four pieces? + rm ;If so we are done. + inx h + mov a,m ;Get the padding char. + adi 100O ;Re-controlify it. + ani 7FH + sta spadch + lda temp4 + cpi 5 ;Fewer than five pieces? + rm ;If so we are done. + inx h + mov a,m ;Get the EOL char. + sbi space + sta seol + lda temp4 + cpi 6 ;Fewer than six pieces? + rm ;If so we are done. + inx h + mov a,m ;Get the quote char. + sta squote + lda temp4 ;Get the amount of data supplied + cpi 7 ;Have an 8-bit quote? + rm ;If not there, all done + inx h ;Yes, get the character + mvi a,0 ;[jd] + sta quot8 ;[jd] assume not quoting + mov a,m ;Get the supplied character + cpi 'N' ;[jd] No? + jz spar1 ;[jd] then don't try to do it + cpi space ;[jd] maybe they don't know about it... + jz spar1 ;[jd] then don't try to do it. + cpi 'Y' ;[jd] Yes? + jnz spar2 ;[jd] if not 'Y', assume it's a quote char. + lda parity ;[jd] using parity? + cpi parnon ;[jd] no, don't need quoting... + jz spar1 ;[jd] + mvi a,0ffh ;[jd] else turn on... + sta quot8 ;[jd] ...quote flag + jmp spar1 + +;[11] Note: If capas etc required, beware of the next two lables, as these +; are used elswhere. + +spar2: sta qbchr ;[jd] use their quote char (should validate) + mvi a,0ffh + sta quot8 ;[jd] turn quote flag and fall thru... + +spar1: lda temp4 ;Determine if block check type given + cpi 8 ;Is the field there? + rm ;If not, all done + inx h ;Point to the character + mov a,m ;Get the value + mov b,a ;Copy value + lda chktyp ;Get our type + cmp b ;Is it our desired type? + rnz ; If not, use default (1-character-checksum) + sta inichk ; Match, store as type to use after init + ret ; and return +;[10] end of replacement +;[11] end of replacement of replacement (ie back to original code) +; + +; Copy characters from packet to disk (or screen) +; called by: rdata + +ptchr: sta temp1 ;Save the size. + lda remtxt ;[MF]Get remote command flag + ora a ;[MF]Remote command in progress? + jnz ptchr0 ;[MF]Yes, don't check for file collisions + lda flwflg ;[MF]Get File Warning (Set Collision) flag + cpi 3 ;[MF]SET COLLISION DISCARD? + jnz ptchr0 ;[MF]No + lda dscflg ;[MF]Yes, get "discard" flag + ora a ;[MF]Discarding file? + jz ptchr0 ;[MF]No + mvi a,'X' ;[MF]Yes, simulate a user rejection + sta czseen ;[MF]... + jmp rskp ;[MF]and pretend success +ptchr0: ;[MF] + lxi h,data ;Beginning of received packet data. + shld outpnt ;Remember where we are. + lda rquote + mov b,a ;Keep the quote char in b. + mvi c,0 ;[jd] assume no 8-bit quote char + lda quot8 ;[jd] doing 8-bit quoting? + ora a + jz ptchr1 ;[jd] no, keep going + lda qbchr ;[jd] else get 8-bit quote char + mov c,a ;[jd] keep this in c +ptchr1: lxi h,temp1 + dcr m ;Decrement # of chars in packet. + jm rskp ;Return successfully if done. + lda remtxt ; to screen only? + ana a + jnz ptchr2 ; dont do any disk stuff + lxi h,chrcnt ;Number of chars remaining in dma. + dcr m ;Decrement. + jp ptchr2 ;Continue if space left. + call outbuf ;Output it if full. + jmp ptchr9 ; Error return if disk is full. +ptchr2: lhld outpnt ;Get position in output buffer. + mov a,m ;Grab a char. + inx h + shld outpnt ;and bump pointer. + mvi e,0 ;[jd] assume nothing to OR in. + cmp c ;[jd] is it the binary quote char? + jnz ptch2a ;[jd] no, keep going + mvi e,80h ;[jd] include parity bit + lda temp1 + dcr a + sta temp1 ;[jd] decrement character count + mov a,m ;[jd] get next character + inx h + shld outpnt +ptch2a: cmp b ;Is it the quote char? + jnz ptchr3 ;[jd] changed to ptchr3 so includes parity + mov a,m ;Get the quoted character + inx h + shld outpnt ;and bump pointer. + lxi h,temp1 + dcr m ;Decrement # of chars in packet. + mov d,a ;Save the char. + ani 80H ;Turn off all but the parity bit. + ora e ;[jd] let parity come from either (???) + mov e,a ;Save the parity bit. + mov a,d ;Get the char. + ani 7FH ;Turn off the parity bit. + cmp b ;Is it the quote char? + jz ptchr3 ;If so just go write it out. + cmp c ;[jd] maybe it's the 8-bit prefix character? + jz ptchr3 ;[jd] then don't controllify. + mov a,d ;Get the char. + adi 40H ;Make the character a control char again. + ani 7FH ;Modulo 128. +ptchr3: ora e ;Or in the parity bit. + sta temp3 ; save for a while + lda remtxt ; to screen or disk? + ana a + lda temp3 + jz ptch31 ; to disk + push h + push d + push b + mov e,a ; to display + mvi c,dconio + call bdos + pop b + pop d + pop h + jmp ptchr1 ; continue + +ptch31: lhld bufpnt ;Destination buffer. + mov m,a ;Store it. + inx h + shld bufpnt ;Update the pointer + jmp ptchr1 ;and loop to next char. + +ptchr9: lxi d,erms11 ; "?Disk full" + push d ;[MF] Save pointer + call error3 ; put it on the error line + pop d ;[MF] Restore pointer + lxi h,data ;[MF] Where to put the message for "e" packet + lda argblk ;[MF] Get packet-number + call countp ;[MF]Increment it + sta argblk ;[MF] as packet to send + xra a ;[MF] Zero length of packet data + sta temp1 ;[MF] ... +ptch9a: ldax d ;[MF] Get a character to copy + cpi cr ;[MF] No more to copy? + jz ptch9b ;[MF] Yes, we can send the packet + mov m,a ;[MF] No, copy the character + inx d ;[MF] and increment source/dest pointers + inx h ;[MF] ... + lda temp1 ;[MF] Get character count + inr a ;[MF] and increment it + sta temp1 ;[MF] ... + jmp ptch9a ;[MF] Copy entire error message +ptch9b: mvi m,0 ;[MF]Put in a zero + lda temp1 ;[MF] Get number of characters in the message + sta argblk+1 ;[MF] and store as number of packet data chars + mvi a,'E' ;[MF] Make it an error packet + call spack ;[MF] Send the error packet + nop ;[MF] Don't really care if + nop ;[MF] the send fails since we're + nop ;[MF] bombing off anyway + ret ; take error return. +; +; Fill a data packet from file +; called by: sfile, sdata + +gtchr: lda squote ;Get the quote char. + mov c,a ;Keep quote char in c. + lda curchk ;Get current block check type + sui '1' ;Get the extra overhead + mov b,a ;Get a copy + lda spsiz ;Get the maximum packet size. + sui 5 ;Subtract the overhead. + sub b ;Determine max packet length + sta temp1 ;This is the number of chars we are to get. + lxi h,filbuf ;Where to put the data. + shld cbfptr ;Remember where we are. + mvi b,0 ;No chars. +gtchr1: lda temp1 + dcr a ;Decrement the number of chars left. + jp gtchr2 ;Go on if there is more than one left. + mov a,b ;Return the count in A. + jmp rskp + +gtchr2: sta temp1 + lda chrcnt ;Space left in the DMA. + dcr a +;* Can improve order here. + jm gtchr3 + sta chrcnt + jmp gtchr4 + +gtchr3: call inbuf ;Get another buffer full. + jmp gtch30 ; If no more return what we got. + jmp gtchr4 ;If we got some, proceed. + +gtch30: mov a,b ;Return the count in A. + ora a ;Get any chars? + jnz rskp ;If so return them. + jmp gtceof ;If not, say we found the end of the file. + +gtchr4: lhld bufpnt ;Position in DMA. + mov a,m ;Get a char from the file. + inx h + shld bufpnt + mov d,a ;Save the char. + ani 80H ;Turn off all but parity. + mov e,a ;Save the parity bit. + jz gtch4a ;[jd] no parity, skip this check... + lda quot8 ;[jd] doing eighth-bit quoting? + ora a + jz gtch4a ;[jd] no, just proceed normally + lda temp1 ;[jd] get space remaining + cpi 2 ;[jd] 3 chrs left (one cnted already)? + jm gtchr9 ;[jd] no, skip this + dcr a ;[jd] decrement space remaining + sta temp1 ;[jd] put back. + lhld cbfptr ;[jd] Position in character buffer. + lda qbchr ;[jd] get quote character + mov m,a ;]jd] Put the quote char in the buffer. + inx h ;[jd] increment destination buffer pointer + shld cbfptr ;[jd] store the pointer back + inr b ;[jd] Increment the char count. + mvi e,0 ;[jd] no parity bit to OR in. +;[jd] fall thru... + +gtch4a: mov a,d ;Restore the char. + ani 7FH ;Turn off the parity. + mov d,a ;[jd] save here for later... + cpi space ;Compare to a space. + jm gtchr5 ;If less then its a control char, handle it. + cpi del ;Is the char a delete? + jz gtchr5 ;Go quote it. + lda quot8 ; Are we doing 8th-bit quoting? + ora a + jz gtch4c ; if not, skip this test and restore character. + lda qbchr ; get 8th-bit quote character + cmp d ; same as current character? + jz gtch4b ; yes, have to quote it... +gtch4c: mov a,d ; no. get character back again. + cmp c ;Is it the quote char? + jnz gtchr8 ;If not proceed. +gtch4b: lxi h,temp1 ;[jd] point to char count + dcr m ;[jd] decrement (know room for at least one) + lhld cbfptr ;Position in character buffer. + mov m,c ;Put the (quote) char in the buffer. + inx h + shld cbfptr + inr b ;Increment the char count. + mov a,d ;[jd] restore character again + jmp gtchr8 + +gtchr5: + ;[gnn] ignore parity for checking +; ora e ;Turn on the parity bit. + + cpi ('Z'-100O) ;Is it a ^Z? + jnz gtchr7 ;If not just proceed. + lda cpmflg ;Was the file created by CPM... + cpi 1 ;in ASCII-mode ? + jz gtch52 ;Control-Z stops text + cpi 2 ;in BINARY mode? + jz gtchr6 ;Yes, pass the ^Z +;At this point file-mode is DEFAULT. +;If the rest of the record is filled with ^Zs, we're at EOF, otherwise +;its a regular character. + lhld bufpnt ;since CHRCNT is ZERO at EOF-time + lda chrcnt ;(set by INBUF5 B.G.E) + mov d,a ;Get the number of chars left in the DMA. +gtch51: dcr d + mov a,d + jp gtch53 ;Any chars left? +gtch52: xra a ;If not, get a zero. + sta chrcnt ;Say no more chars in buffer. + mov a,b ;Return the count in A. + jmp rskp + +;Scan rest of buffer for non ^Z -- If we find a non ^Z, fall into gtchr6. +;If we get to the end of the buffer before finding a non ^Z, fall into gtch52. +gtch53: mov a,m ;Get the next char. + inx h ;Move the pointer. + cpi ('Z'-100O) ;Is it a ^Z? + jz gtch51 ;If so see if the rest are. + +gtchr6: mvi a,('Z'-100O) ;Restore the ^Z. +gtchr7: sta temp2 ;Save the char. + lxi h,temp1 ;Point to the char total remaining. + dcr m ;Decrement it. + lhld cbfptr ;Position in character buffer. + mov m,c ;Put the quote in the buffer. + inx h + shld cbfptr + inr b ;Increment the char count. + lda temp2 ;Get the control char back. + adi 40H ;Make the non-control. + ani 7fH ;Modulo 200 octal. +gtchr8: lhld cbfptr ;Position in character buffer. + ora e ;Or in the parity bit. + mov m,a ;Put the char in the buffer. + inx h + shld cbfptr + inr b ;Increment the char count. + jmp gtchr1 ;Go around again. + +gtchr9: ;[jd] not enough room left in buffer... + lhld bufpnt + dcx h + shld bufpnt ;[jd] back up over last character + lxi h,chrcnt ;[jd] point to character count + inr m ;[jd] increment it + mov a,b ;[jd] count of chars transferred + jmp rskp ;[jd] return it + +gtceof: mvi a,0FFH ;Get a minus one. + ret +; + +; Little code to allow some expansion of code without changing +; every futher address, only up to the end of this file. +; TO BE REMOVED FRO RELEASE! + +; org ($+100h) AND 0FF00H + +IF lasm + LINK CPSPK2 ;[obs] Link to part two of the packet file +ENDIF ;lasm -- cgit v1.2.3