; ; =============================================== ; ; PROGRAM STARTS HERE ; ; =============================================== ; ; ; Save CP/M stack, initialize new one for this program ; begin: lxi h,0 dad sp lxi sp,stack+2; Reset the stack push h; Save return to ccp ; " " ; initialize lxi h,firstoclear mvi b,lastoclear-firstoclear; ng if > 256 call fillz; zero storage area lxi h,dbuf shld recptr; set i/o pointer call ilprt db cr,lf,'RXMD v',vers+'0','.',modlev+'0','.',fixlvl+'0',' ',0 call chkrsx jnz begin1; BYERSX is present call ilprt db cr,lf,'BYERSX is not running...aborting...',0 exeunt: lhld stack sphl ret ; begin1: lhld bdos+1 lxi d,lastmem mov a,l sub e mov a,h sbb d jnc begin2 call ilprt db cr,lf,'Not enough memory...aborting...',0 jmp exeunt ; begin2: mvi a,setusr call sysquery sta oldusr; Save current drive/user sta actusr mvi a,curdrv call dos sta olddrv sta actdrv; and init actual drv/usr mvi e,gwrtprt mvi c,rsxmast call bdos; need 16 bit return value here shld wpmask; get incoming wrt protect mask call qwheel jnz begin3; wheel, no secureit mode mvi a,setsecure call dorsx; set secure mode for general user lxi d,0 mvi a,swrtprt; remove write protection call dos begin3: mvi e,0; Set parity off for file xfrs mvi a,sgbaud call dos; get existing parity. sta oldbd ani 0cfh; mask parity field ori 010h; set no parity (can set stops here) mov e,a mvi a,sgbaud call dos; and set it up call catch; Flush the line prior to rcv/send ; " " ; Check primary option lxi h,fcb+1 mov a,m sta optsav; Save option for later use sta crcflg; Insure in CRC mode now cpi 'L'; Send a file from a library? jz begin5 cpi 'S'; Send a normal file? jz begin5 cpi 'R'; Receive a file? jnz opterr; None of these, show help guide call mspeed; check i/o baud rate sui 5 sbb a; 0 for nc, ffh for cy cma; 0 for < 5, i.e. <1200 baud sta kflg; Set the 1k flag for now ; " " ; Check for additional receive options inx h mov a,m; Get the receive option, if any cpi ' '; Next column a space character? jz rckbch; If yes, see if requesting batch cpi 'P' jnz begin4 sta prvtfl; set the private flag inx h mov a,m begin4: cpi ' ' jz rckbch; see if requesting batch cpi 'B'; For batch mode jz rckbch cpi 'C' jz rcksm cpi 'X' jnz opterr; None of these, show help guide xra a; Orig. XMODEM protocol, sta kflg; reset the 1k flag jmp rcrc ; ; select send mode begin5: inx h mov a,m; Get next char on command line cpi 'B'; Requesting batch mode? jz sbch cpi 'X'; 'X' for XMODEM protocol? jz sndfl; If yes go send the file cpi 'K' jnz sndfl; 'K' to force 1k transmissions sta kflg; Else set the 1k flag call ilprt db '1k protocol enabled',0 jmp sndfl ; ; ============================================== ; ; ---> SNDFL sends a CP/M file ; ; =============================================== ; bchmsg: sta bchflg; Set the batch flag call ilprt db '- (Batch is enabled)',cr,lf,0 ret ; ; Displays the Batch enabled message for send ; sbch: call bchmsg ; " " ; The CP/M file specified in the RXMD command is transferred over the ; phone to another computer with modem using the "R" (receive) ; option. The data is sent one record at a time with headers and ; checksums, and retransmission on errors. ; sndfl: xra a sta sndflg; Show in send mode lda bchflg ora a jnz sbtch; Batch mode requested call logdu sndfl1: lda optsav cpi 'L' cnz cnrec; Ignore if in library mode call opnfil; Open the file call rdblk1; Put up to 16k from file into buffer call catch; Flush input mvi e,60; Wait up to 1 minute for initial 'NAK' call waitnak call setflg; Can't use 1k if not 8 records in file ; " " ; Loops back to this point after a successful transmission for next one sndlp: call gtratio; Check the ACK ratio if using 1k blocks call rdrecd; Read a record jc sndeof; Send 'EOF' if done call incrno; Bump record number if sent ok xra a; Initialize error count to zero sta errct ; " " ; Comes back here to repeat previous transmission if no ACK was received sndrpt: call ckabort; Want to stop sending for some reason? call funchk; Check the function keys call sndhdr; Send a header call sndrec; Send data record call sndchk; Send CRC or checksum value call gtack; Get the 'ACK' jc sndrpt; No 'ACK', repeat transmission call setptr; Successful record so increase pointers lda optsav; Get the command option again cpi 'L' jnz sndlp; If not library option, exit call setlbr; Set library pointers and size left lhld rcnt mov a,h ora l jnz sndlp; not finished, send more ; " " ; File sent, send EOT but do local log-keeping first sndeof: call eofsnd call alldon jmp done ; ; Sends batch mode sbtch: lda fstflg; If first time through ora a jnz sbtch1; If not first time, exit call ilprt db 'wait while calculating.....',0 call logdu; Check disk, user call tnmbuf; Put all requested files into NAMBUF ; " " ; Total number of files, total records and total length is shown, ; user then gets up to 5 seconds to abort. xra a sta remoff; Show following to remote on 1st time call ilprt db cr,'Ready to send in batch mode' db cr,lf,'Total files : ',0 lda filcnt; Get total files sta shocnt push psw call decouta; Show remote # of files pop psw ora a; Abort if no files to send jz nofile call ilprt db cr,lf,'Total records : ',0 lhld totrec; Get total records - all files push h call decout; Show remote call ilprt db ' (',0 pop h call decoutk; Show # of k call ilprt db 'k)' db cr,lf,'Disk space : ',0 lhld blokk; Get k required on remote disk for 2k dad h; Double the size for 2k blocks call decout; Print it call ilprt db 'k with 2k blocks',0 ; " " sbtch1: lda filcnt ora a jz sbtch2 lda fstflg sta remoff call ilprt db cr,lf,'Time for files: ',0 lxi d,ktable; using k mode lhld totrec; Get number of records call filtim call showtime call crlf lda fstflg ora a jnz sbtch2 inr a; Now show we have been this way sta fstflg call ilprt db 'CTL-X to cancel',cr,lf,cr,lf,0 ; " " sbtch2: call ckabort call sndfn; Sends file name to receive jc sbtch4; No more files, exit call showfil; Show the batch filename jmp sndfl1; Send the file ; sbtch4: lda gotone; Did we actually send at least one? ora a jz abort; If not, don't act like we did call eofsnd; No more files so send EOT to finish call xfrdon jmp exit ; nofile: call erxit db cr,lf,'++ Ask again, no files found ++','$' ; eofsnd: mvi a,eot; Send an 'EOT' call send lda chkeot; Did not get an ACK, try again inr a sta chkeot; Limit number of retries to 4 cpi 4; (to prevent possible 'lock-up') rnc; Quit if already sent 4 or more call gtack; Get the ACK jc eofsnd; Resend if carry is set ret ; alldon: lda bchflg ora a rnz; In batch mode, ignore message call crlf; (Want to keep this a separate message) ; " " xfrdon: call ilprt db cr,lf,'[Transfer completed]',cr,lf,0 ret ; ; ============================================== ; ; ---> RCVFL Receive a CP/M file ; ; ============================================== ; ; Can be invoked by "RXMD R FILENAME.TYPE" or "RXMD RC FILENAME.TYP" ; if checksum is to be used. ; ; Allows batch mode to private area if R, RB or RPB is typed rckbch: lda fcb1+1; Was a file requested cpi ' ' jnz rcrc; Can't use batch if file requested call bchmsg; Show batch enabled message jmp rcvfl ; rcrc: mvi a,1 sta crcflg; Show in CRC mode call ilprt db ' - (CRC is enabled)',cr,lf,0 jmp rcvfl; All set to receive a file ; rcksm: xra a sta crcflg sta kflg; Can't use 1k blocks with checksum call ilprt db ' - Checksum enabled',cr,lf,0 ; " " rcvfl: lda bchflg ora a jnz rcvbch; If batch mode requested exit call ducheck; Find drive/user/filetype permitted call cktyp; Check for restricted file types call chekfil; Set d/u access call display; Display drive/user area call makefil; Open the file, ready to receive ; " " rcvlp: call rcvrecd; Get a record jc rcveot; Exit if 'EOT' for end of current file call incrno; Bump record number, if received ok call wrrecd; Write the record call sndack; Ack the record jmp rcvlp; Loop until 'EOF' ; ; Got EOT on record so flush buffers then done rcveot: lhld recdno mov a,h ora l jz rcvsabt; Abort and erase a zero length file call sndack; Ack the record call wrblock; Write the last block call closfil; Close the file call alldon jmp done ; ; ------------------------------------------------ ; ; Using batch so reset flags ; rcvbch: xra a sta frstim; Needs to be reset for each new file mvi a,1 sta sndflg; Shows we are in receive batch mode lda fstflg ora a jnz rcvbc1; Following for first batch file only call ducheck; Find drive/user/filetype permitted call chekfil; Set d/u access call display; Display drive/user area lxi h,nambuf shld nbsave mvi a,1 sta fstflg ; " " rcvbc1: call rcvfn; Get and display batch file name jc rcvbc2; If all done, exit call cktyp; Change file type if needed call chekfil; Already have a file with that name? call makefil call bchinr call ilprt db 'Waiting.....',0 mvi a,crc call send mvi a,ksnd; Request 1k blocks call send jmp rcvlp; Go receive the file ; rcvbc2: xra a; Zero the batch mode flag sta bchflg lda gotone; Were there any files received? ora a jz abort call xfrdon; Show transmission is finished call wait1; Delay to let remote get into ter. md. ; " " ; Finished with the file transfer done: lda bchflg ora a jz exit; not batch, all done so go finish up lda olddrv; Restore original drive call dskset lda oldusr; Restore original user call usrset lxi d,tbuf; Reset to default DMA address mvi a,stdma call dos mvi b,12; Zero out fntbuf lxi h,fntbuf call fillz ; " " ; Now fill in the batch file name mvi b,12; Put file name in fntbuf lxi h,fcb+1 lxi d,fntbuf done2: mvi a,4; Start of file type? cmp b jz done4; Put in period if so mov a,m cpi ' '; Don't put in space jz done3 stax d; Store in fntbuf inx d done3: inx h dcr b mov a,b ora a; End of file name? jz done5; Display file name jmp done2; Loop for another character ; done4: mov a,m cpi ' '; Is file type empty? jz done5; Go if so mvi a,'.'; Else put period in message stax d inx d dcr b jmp done2 ; done5: mvi a,1; Display filename locally only sta remoff sta gotone; Indicates there was a file handled call crlf lxi h,fntbuf call tstr; Display the file name call ilprt db ' Transferred',cr,lf,0 ; " " ; Now reset some flags for another possible batch file xra a sta eoflg; Clear end of file flag sta chkeot; Clear the "resend EOT" flag lxi h,0 shld accerr; Reset accumulated error count shld recnbf; Zero num of rcds in the buffer shld recdno; Zero current rcd number shld rcdcnt; Zero transmit rcd counter lxi h,dbuf; Reset buffer pointers shld recptr lda sndflg; Goes to either send or ora a; Receive file, depending jz sndfl; Upon which routine set lda filcnt cpi 50; jc rcvfl; not 50 files yet, get next call ilprt db cr,lf,'++ 50 batch uploads is the limit ++',cr,lf,0 xra a sta bchflg; Reset the batch mode flag jmp exit ; ; ------------------------------------- ; help guide ; ; Invalid option opterr: call crlf call ilprt db cr,lf,' Uploads files to ',0 call setgrv; set general receive area jz optx1; not jammed call showsz jmp optx3 optx1: call ilprt db 'specified or current disk/user',0 optx3: call setpvt; set private rcv area jz optx4; private not enabled call ilprt db cr,lf,' Private files to ',0 call showsz optx4: call crlf lda optsav; Check 'option' cpi 'A'; If 'A' (avail upload space option) jz exit; Skip error message ; " " call erxit; Exit with error db '++ Examples of valid options: ++',cr,lf,cr,lf db ' RXMD A to show areas' db '/available space for uploads',cr,lf db ' RXMD L CAT.LBR CAT.COM to send a file ' db 'from a library',cr,lf db ' RXMD L CAT CAT.COM (.LBR extent may ' db 'be omitted)',cr,lf db ' RXMD LK PATCH PATCH.AQM to send library file with ' db '1k protocol',cr,lf db ' RXMD RB (or just R) to receive RX/KMD-type 1k ' db 'batch mode',cr,lf db ' RXMD R HELLO.DOC to receive a file ' db 'from you',cr,lf db ' RXMD RC HELLO.DOC to receive a file via ' db 'checksum',cr,lf db ' RXMD RP HELLO.DOC to receive in a private ' db 'area',cr,lf db ' RXMD RPC HELLO.DOC to receive a private file ' db 'via checksum',cr,lf db ' RXMD RX HELLO.DOC to force CRC protocol',cr,lf db ' RXMD SB HELLO.* to send RX/KMD-type 1k batch ' db 'mode',cr,lf db ' RXMD S HELLO.DOC to send a file',cr,lf db ' RXMD S B1:HELLO.DOC to send from a ' db 'named drive/area',cr,lf db ' RXMD SK RXMD.DOC to manually select 1k ' db 'protocol',cr,lf,cr,lf db '(Using just R tells sender you have CRC, 1k and ' db 'checksum modes)' db '$' ; ; Show drive/user and size available showsz: call showdu call ilprt db ' - ',0 lda actdrv adi 'A' jmp kshow ; ; Show actually selected dsk/user showdu: lda actdrv adi 'A' call ctype lda actusr call decouta mvi a,':' jmp ctype