Files
RomWBW/Source/Apps/ZMD/zmd.z80
Wayne Warthen d265f1323d Add ZMD
2021-10-13 17:33:40 -07:00

4858 lines
131 KiB
Z80 Assembly
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
;
TITLE ZMD.Z80 - 09/29/88 - Z80 RCP/M File Transfer Program
; Copyrighted (c) 1987, 1988
; Robert W. Kramer III
PAGE
;- -;
; Update History ;
; ;
; Date Release Comments ;
; -------- ------- ---------------------------------------------- ;
; ;
; 09/29/88 v1.50 - If an LBR/ARK/ARC member extraction is being ;
; made, a check at OPNOK5: determines if (FCB+9) ;
; is an 'L' for a .LBR member extraction. If so, ;
; ZMD informs the receiver that the file is ready ;
; for downloading. If (FCB+9) is other than an ;
; 'L' an ARC/ARK member extraction is assumed and ;
; the receiver is told to name the received file ;
; accordingly. Extractions on LBR/ARC/ARK files ;
; with the high bit set in (FCB+9) triggers this ;
; test unreliable. The simple fix has been made, ;
; which strips the parity bit of (FCB+9) before ;
; anylizing it. ;
; - Fixed a problem that caused some systems to ;
; ignore the first character typed in some ZMD ;
; utilities. The modification was made at the ;
; TYPE: routine in ZMDSUBS. Instead of using ;
; BDOS function 2 to display a character, we are ;
; now using BDOS call 6. ;
; - Fixed CONSTAT: routine in ZMDSUBS to properly ;
; react to cancel requests from Sysop. ;
; - Modified all low level I/O routines to preserve ;
; HL, DE, and BC registers. Whether you're using ;
; BYE's extended BDOS calls or have a custom I/O ;
; overlay installed in ZMD, those registers are ;
; will return intact. This allows those writing ;
; overlays to not have to worry about register ;
; integrity. ;
; - Single file Receive now defaults to 1k blocks. ;
; - Library extractions now default to 1k blocks. ;
; - Fixed bugs in the handshaking that have been ;
; around since 1k Batch was implemented on CPM ;
; systems. This required several modifications ;
; to the SNDFIL routines. All of them were ;
; modified specifically for the Batch routines, ;
; however, other Send routines were directly ;
; effected by them. ;
; ;
; 1. ZMD does not use the BDOS call 35 to get ;
; the file size since this information is ;
; supplied in the directory entry for each ;
; extent retreived during filename lookup. ;
; ;
; 2. We no longer open a file to send until ;
; the receiver has ACKnowledged header 0 ;
; *AND* sent his invitation for CRC ('C'). ;
; Previously, opening the file immediately ;
; after the header 0 ACK caused the 'C' to ;
; be missed during the time the sender is ;
; opening the file and filling his transmit ;
; buffer. ;
; ;
; 3. I personally feel there is no need to ;
; purge the line of incoming characters at ;
; anytime during a batch session. All of the;
; occurences of CALL CATCH have been removed;
; from the Send batch routines with the ;
; exception of the GTACK routine, in which ;
; case a call to CATCH is only made if the ;
; current byte received is other than an ;
; ACK, NAK, 7Bh, FBh, or a CANCEL. ;
; ;
; I do not have the resources to change all ;
; the other CP/M file transfer utilities ;
; floating around, so you may still notice ;
; some minor delays between files in BATCH ;
; protocol. Since most of the problem was ;
; in the Send routines, you'll not notice ;
; lengthy delays when using ZMD to send. ;
; Delays when using ZMD to receive will be ;
; dependant upon what software the sender ;
; is using. (IBM comm programs don't seem ;
; to have this problem, however all CP/M ;
; comm programs will have these irritating ;
; delays - except ZMD). ;
; ;
; - Added code to initialize KDRV with current ;
; drive at program startup. CPM3 systems were ;
; experiencing problems with BDOS 46. ;
; - CPM3 BDOS call 46 returns the current disk space;
; free in the first 3 bytes of the currently set ;
; DMA. This was being done during a check for ;
; the batch intention and destroying the current ;
; command line buffer (at 80h where DMA address is;
; usually set). CPM3 systems should now have no ;
; problems with ZMD. ;
; - Fixed bug to allow 255 files to be transferred ;
; when descriptions are disabled (either by the ;
; ZINSTL program or by using the 'RW' option). ;
; - Added CKWILD routine to prevent commands such ;
; as 'ZMD R *.*' enter '*.*' into the directory. ;
; Using any wildcards in the filename or extent ;
; of the receive filename will trigger YMODEM 1k ;
; Batch. ;
; - Log file routines were writing some filename ;
; attributes to the log file. Fixed at PUTLOG: ;
; - Modified ZMDSUBS.REL and send/send Batch code ;
; to take care of incorrect drive display problem ;
; for local terminal. Created new subroutine to ;
; poke the current binary 'BDOS' drive/user area ;
; into (DUU) and (DUD) in both SNDFIL: and SBTCH: ;
; routines. Both DUD and DUU have been moved to ;
; the ZMDSUBS file for global use. ;
; - Fixed EDATE routines for LOG and FOR files. ;
; Previously, the EDATE setting had no effect on ;
; the ZMD.Z80 program. ;
; - Fixed message upload routine at RCVFL to check ;
; for access restrictions. If ACCESS is set to ;
; NO, the message upload will be accepted, else ;
; bit 3 of AFBYTE will be anylized. ;
; ;
; 03/18/88 v1.49 - No change(s) made to this file ;
; 03/13/88 v1.48 - Had a small problem with TPA fix which has been ;
; corrected. CHKTPA was calculating the total ;
; number of bytes available for DBUF, but wasn't ;
; clearing register L (forcing an even amount of ;
; sectors before initializing OUTSIZ buffer limit ;
; comparison word). This may have introduced ;
; minimal garbage to your FOR file if your FOR ;
; file is large enough to fill available TPA with ;
; ZMD, ZFORS or to the log file if running ZMDEL. ;
; - Rewrote OUTCHR routine in ZMDSUBS. ;
; - Redefined buffer table at end of programs. STACK;
; and filename buffers now EQUated with offsets ;
; from the last switch/toggle in program instead ;
; of with DS directive. ;
; - Some systems which do NOT have an interrupt ;
; driven keyboard may have noticed problems when ;
; an invalid key was entered in the ZNEWP, ZFORP ;
; and ZMDEL programs. In ZNEWP and ZFORP, if a ;
; CR was entered to pause the output, output was ;
; limited to one line at a time per key pressed. ;
; If an invalid key was hit, output would have ;
; remained in a paused state until one of the ;
; abort keys were pressed. This was difficult to ;
; find since my keyboard is interrupt driven and ;
; I could not duplicate the problem on my own ;
; system. ;
; - Fixed a problem in the MODE parsing routines ;
; that caused ZMD to default to 128 byte blocks ;
; in single file SEND mode. Now defaults to 1k ;
; YMODEM. ;
; 02/25/88 v1.47 - Fixed a problem that caused only partial display;
; of the help guide if an invalid command such as ;
; ZMD RPC with no filename was entered. ;
; - Repaired routine that loads access flags byte ;
; into AFBYTE. If ACCESS was disabled and BYE ;
; was running, a check for a modem overlay was ;
; being made that caused a system hang up. v1.46 ;
; was the only version with this problem. ;
; - And then there were TPA problems. Past versions ;
; of ZMD required at least 48k TPA to run. If ;
; your system has less, and descriptions enabled, ;
; you most likely had a system hang up during the ;
; FOR file read/write operations. This version ;
; will run on any system with as little as 24k of ;
; available TPA. Maximum number of uploads is ;
; automatically calculated according to your TPA ;
; limitations. If upload descriptions have been ;
; disabled (either during installation or during ;
; program execution with the RW or RP options), ;
; as many as 255 files may be uploaded. ;
; - Fixed time out error in CRC receive routine. ;
; Register B contains the number of seconds to ;
; wait for a character on entry to RECV and some- ;
; how I inadvertanly removed the line that loads ;
; this value on entry. (Label RCVCRC2) ;
; - Fixed description routine so that the caller ;
; will be asked for the category of each uploaded ;
; file if ASKAREA is disabled. Problem caused ZMD ;
; to ask only 1 time for the file descriptor of ;
; uploaded files - no matter how many of them ;
; there were. ;
; 01/27/88 v1.46 - Fixed BYE time routines. Now displays correct ;
; time on system when exiting. ;
; - Fixed SUBS file so that discrepency check will ;
; not turn off CLOCK, and DSTAMP if MODE is set ;
; to 255. (So ZFORS and ZFORP can react to the ;
; clock related features without BYE running). ;
; - Added prompt to tell remote when ZMD is waiting ;
; for him to come back to terminal mode. Gets ;
; redisplayed every 3 seconds for a total of ;
; approximately 30 seconds before continuing on ;
; automatically. ;
; - Added code to SUBS file that determines if we ;
; are in private mode or not. If so, only private ;
; drive/user information is displayed when asking ;
; for file descriptors/categories choice. If in ;
; regular mode or in SPACE routines only the ;
; regular drive/user is shown. Fix is for upload ;
; routing routines. ;
; - Repaired message file exit routine. Command ;
; line wasn't being properly built. ;
; - Fixed so that batch mode is not valid with the ;
; RM option. (Slipped by during a rewrite of the ;
; command tail parsing routines). ;
; 01/17/88 v1.45 - First public release ;
; 01/14/88 v1.43 - Removed MBYE/BYE3 specific switches in ZMDHDR. ;
; Added new switch CLOCK. Removed Extended BDOS ;
; calls from time and date routines. Rewrote for ;
; 100% compatibility with BYE5/MBYE/BYE3 remote ;
; console programs. RTC switch can be set for ;
; user defined time and date routines at RTCTIM ;
; in ZMDHDR.Z80 ;
; - Fixed an error in send routines that allowed ;
; FCB+9-FCB+12 to remain initialized to nulls, if ;
; file requested had less than 3 characters in ;
; the filename extent. ;
; 12/29/87 v1.41 - Removed and rewrote description routines to be ;
; universal with ZMD, ZFORS and ZINSTL programs. ;
; Routine is now requested from ZMDSUBS.REL ;
; 12/23/87 v1.40 - Fixed numerous trivial bugs. ;
; - Rewrote the help and time/date routines. ;
; - Added code to determine if BIOS local console ;
; output address has been included in the modem ;
; overlay and if not calculate it according to ;
; standard CP/M specifications and store it for ;
; program use. ;
; 12/13/87 v1.39 - Rewrote common subroutines for inclusion in ;
; ZMDSUBS.REL subroutines file. ;
; 12/07/87 v1.38 - Modified to support drive/user area requests ;
; in SEND BATCH mode. Drive/user restrictions ;
; remain enforced. ;
; 10/02/87 v1.37 - Wrote code for automatic host disk block size ;
; detection. All file sizes (and total file ;
; sizes) are rounded to reflect this block size. ;
; 08/29/87 V1.36 - Rewrote all time routines. Moved RTC reader ;
; code insert address to ZMDHDR. Moved all date ;
; and time routines together to be updated all ;
; in same pass. Values stored at end of program ;
; to free up registers and retain values for any ;
; subsequent use. ;
; 08/14/87 v1.35 - Removed access restriction routines and rewrote ;
; completely. Access switches now bit mapped. ;
; 07/24/87 v1.34 - Updated to detect and process batch filename ;
; requests automatically. (AUTO-BATCH). ;
; - Removed entire SBTCH routines and threw away. ;
; Rewrote from scratch to enhance speed, ;
; efficiency, readability, and user friendliness. ;
; ZMD is capable of locating multiple filenames ;
; on multiple drive user areas with full drive ;
; and user area, filename, and time restrictions ;
; in force in 5 seconds (all other CP/M file ;
; transfer programs take 7 minutes or more) to ;
; find maximum 255 filenames. ;
; - Complete rewrites of: command line parsing, ;
; exit, abort, credit and descriptions routines. ;
; 06/18/87 v1.30 - Removed conditional assembly and modified to ;
; support .COM file installation/reconfiguration ;
; without reassembling. ;
; 06/17/87 v1.29 - Converted entire program to Microsoft MACRO-80 ;
; language. Programs no longer compatible with ;
; 8080 microcomputers. ;
;- -;
;-------------------------------------------------------------------------;
; EXTERNAL Declarations: |
;-------------------------------------------------------------------------
;
EXTRN BCDBIN,BLKSIZ,BUFSTR,BYECHK,CATCH,CHARLN,CKDIR,CLEARIT
EXTRN CMDBUF,CNREC,CONIN,CONONL,CONSTAT,CPDEHL,CPM3,CRCCHK
EXTRN CRCVAL,DATDEC,DATMSG,DBUF,DECOUT,DELAY,DIVREC,DSCFLG
EXTRN DSKSAV,DVHLDE,ERXIT,EXIT,FILCNT,FILTM1,FINCRC,FUNCHK
EXTRN GETDSC,GETKIND,GETOFF,GETSPD,GTCURDU,HEXO,ILPRT,ILPRTB
EXTRN ILPRTL,INCRNO,INITFCB,INITFLG,INITIT,INPUT,KDRV,KIND
EXTRN KSHOW,KTIM,LBRARC,LCASE,LOGBUF,LOW41K,MATCH,MCHFTYP
EXTRN MEMFCB,MODE,MOVFCB,MSGFLG,NAMBUF,NOARK,OLDDRV
EXTRN OLDUSR,PGSIZE,PRINTV,PRIVATE,RDARC,RDCOUNT,RECAR1
EXTRN RECARE,RECDR1,RECDRX,RECTBL,RECV,RENFCB,RENTYP,RSDMA
EXTRN RSTLCK,SEND,SENDBEL,SETLCK,SHOCAT,SHONM,SHONM3,SHOSPD
EXTRN SNDABT,SPCDRV,STACK,STDMA,STORTM,TYPE,UCASE,USRSAV
EXTRN WAIT1,WHLCHK,XTIM,NEWNAM,SHONM4,NOROOM,BYEBDOS,BATCH
EXTRN FILIMT,PUPFLG,CHKTPA
;
;-------------------------------------------------------------------------;
; PUBLIC Declarations: |
;-------------------------------------------------------------------------;
;
PUBLIC KTABLE,XTABLE,KECTBL,DONE,EOTFLG,ABORT,ABORTX,HELP
PUBLIC KFLG,FCBBUF,HDRADR,RCNT,RECDNO,SAVEHL,RCDCNT,TIME
;
;-------------------------------------------------------------------------;
; Program Starts Here |
;-------------------------------------------------------------------------;
.Z80
ASEG
ORG 100H ; Program starts
JP BEGIN ; Jump around configuration table
INCLUDE ZMDHDR.Z80 ; Include the ZMD header overlay
.REQUEST ZMDSUBS ; Include the ZMD subroutines
;
;
; Save current CP/M stack address
;
BEGIN: LD (STACK),SP ; Save current CP/M stack address
;LD SP,STACK ; Initialize new one for ZMD
LD SP,0C000H ; [WBW] For HBIOS Fastpath
;
; Save current drive and user area for later
;
LD A,255
CALL RECAR1 ; Get current user
LD (OLDUSR),A ; Save current user
LD C,CURDRV ; Current drive
CALL BDOS
LD (OLDDRV),A ; Save current drive
ADD A,'A' ; Make it ASCII
LD (KDRV),A ; And store as default drive for DPB info
;
; Display signon message and check environmental discrepencies
;
LD HL,ZMDNAM ; Point to this program's name
CALL PRINTV ; Display it and version number
;
; If running under CPM3 tell rest of program
;
LD C,GETVER ; Get CPM version
CALL BDOS
CP 48 ; Version 3.0?
JR C,$+5 ; No, it's 2.n so skip next
LD (CPM3),A ; Else set CPM3 switch on
;
; Locate modem I/O routines
;
CALL BYECHK ; BYE extended BDOS valid?
CP 5
JR NZ,BEGIN0 ; No, check for I/O overlay
LD A,255
LD (BYEBDOS),A ; Enable BYE extended BDOS for modem I/O
JR BEGIN1
BEGIN0: LD A,(MDINP+2) ; Check for MDINP address
OR A ; Anything there?
JP Z,NOIO ; No overlay either, bitch then exit
LD (INITFLG),A ; Tell exit routine to 'UNINIT'
CALL MINIT ; Initialize system routine (if included)
LD (MHZ),A ; [WBW] Save system speed reported by HBIOS
;
; Get bit mapped access flags byte
;
BEGIN1: LD A,(ACCESS) ; Using access flags byte?
OR A
JR Z,BEGIN3 ; No
CALL BYECHK ; Check version of BYE
CP 5 ; BYE5?
JR NZ,BEGIN2 ; No
LD E,255
LD C,85 ; Get access flags byte
CALL BDOS
LD (AFBYTE),A ; Store it
JR BEGIN3
BEGIN2: LD DE,ACBOFF ; Offset to access flags byte
CALL GETOFF ; Get address
LD A,(HL) ; HL points to access flags byte
LD (AFBYTE),A ; Store it
;
; Set WRTLOC, display time on system
;
BEGIN3: CALL SETLCK ; Set WRTLOC if needed
CALL CATCH ; Gobble up garbage characters from line
CALL TIME ; Get clock values and display time on
;
;-------------------------------------------------------------------------;
; P a r s e ' M o d e ' f r o m C o m m a n d T a i l |
;-------------------------------------------------------------------------;
;
; Second character in CP/M FCB contains program mode
;
LD HL,FCB+1
LD A,(HL) ; Get the main option
LD (MODE),A ; Save it for later use
CP 'F' ; Free space?
JP Z,SPACE ; Yes
CP 'A' ; .ARC/.ARK member extraction?
JP Z,CKSND-3 ; Yes
CP 'L' ; .LBR member extraction?
JP Z,CKSND-3 ; Yes
CP 'S' ; Send a file?
JP Z,CKSND ; Yes
CP 'R' ; Receive a file?
JP NZ,HELP ; No, show help guide
;
; Check additional 'R'eceive mode options
;
INC HL ; Point to next option
LD A,(HL) ; Put in A
CP 'P' ; Receive Private?
JR Z,CKRCV2-3 ; Yes
CP 'W' ; Receive Privileged? (No descriptions)
JR NZ,CKRCV1 ; No
LD A,(PUPOPT) ; Is >0 if allowing privileged uploads
LD (PUPFLG),A ; Sets our flag this way
OR A ; Allowed?
JP Z,HELP ; No, show help guide
JR CKRCV2 ; Else get next option
CKRCV1: CP 'M' ; Receive message?
JR NZ,CKRCV3 ; No
LD A,(FCB1+1) ; See if a filename was requested
CP ' '
JP Z,HELP ; No, batch mode not allowed
LD A,(MSGFIL) ; Is >0 if allowing message uploads
LD (MSGFLG),A ; Sets our flag this way
OR A ; Allowed?
JP Z,HELP ; No, show help guide
LD A,'P' ; Else...
LD (PRIVATE),A ; Set the private flag
CKRCV2: INC HL ; Point to next option
LD A,(HL) ; Put in A
CKRCV3: CP ' ' ; Anything there?
JP Z,BCHMSG ; No, see if requesting Batch
CP 'B' ; Batch mode?
JP Z,BCHMSG ; Yes
CP 'C' ; Force Checksum?
JP Z,CHKMSG ; Yes
CP 'X' ; Force 128 byte packets?
JP Z,XMDMSG ; Yes
CP 'K' ; Force 1k packets?
JP Z,YMDMSG ; Yes
JP HELP ; Invalid option, show help guide
;
; Check additional 'S'end mode options
;
LD (LBRARC),A ; Set .LBR/.ARK/.ARC extraction flag
CKSND: INC HL ; Next option on command line
LD A,(LBRARC) ; Get the member extraction flag
OR A ; Is is set?
JR Z,CKSND0 ; No, we can check for batch
LD A,(HL) ; Get the character
CP ' ' ; Any more options?
JP Z,YMDMSG ; No, and batch not used with extractions
CKSND0: LD A,(HL) ; Get the character back
CP ' ' ; Any more options?
JR Z,BCHMSG ; No, check for batch intention
CP 'C' ; Force checksums?
JP Z,CHKMSG ; Show protocol
CP 'X' ; Force XMODEM protocol?
JP Z,XMDMSG ; Show protocol
CP 'K' ; Force 1k protocol?
JP Z,YMDMSG ; Show protocol
LD A,(LBRARC) ; Get LBR/ARC extraction flag
OR A ; Enabled?
JP NZ,NOMSG ; Yes, ignore Batch
LD A,(HL) ; Get option back
CP 'B' ; Forcing batch?
JR NZ,CKSND1 ; No
LD A,(PRIVATE) ; Get special download area flag
OR A ; Enabled?
JP NZ,NOMSG ; Yes, don't allow batch
JP BCMSG2 ; Go set batch flag and display mode
CKSND1: CP 'P' ; Send private?
JP NZ,HELP ; No
LD (PRIVATE),A ; Enable private download
JR CKSND ; Loop for more options
;
; Display the currently selected (or default) protocol.
;
BCHMSG: LD A,(MODE) ; Get main option again
CP 'R' ; Receiving?
JR NZ,BCMSG1 ; No
LD A,(FCB1+1) ; Was a file requested?
CP ' '
JR Z,BCMSG2 ; No, in batch receive
LD HL,FCB1+1 ; Point to secondary FCB
CALL CKWILD ; Check for wildcards
LD A,(BATCH) ; Batch enabled now?
OR A
JR NZ,BCMSG2 ; Yes, report protocol
JR YMDMSG ; Else, single file receive. Default to 1k
;
; Scan the command line to see if there was any intention of batch and if
; so, set program environment to Ymodem 1k batch protocol.
;
BCMSG1: XOR A ; Clear accumulator
LD (MODE),A ; Gets us back from the SBTCH routines
CALL SBTCH ; Check for batch intention
LD A,'S'
LD (MODE),A ; Fix the transfer mode flag
LD A,(BATCH) ; Get the batch mode flag
OR A ; Was it enabled?
JR Z,YMDMSG ; No, sending single file. Default to 1k
BCMSG2: CALL LOW41K ; 1k packets allowed?
JP C,TOOSLOW ; No, can't use batch
LD A,1
LD (BATCH),A ; Enable batch
CALL ILPRTB
DB '1k Batch',0
JR MSGEND
YMDMSG: CALL LOW41K ; 1k packets allowed?
JR C,NOMSG ; No
LD (KFLG),A ; Enable 1k
CALL ILPRTB
DB '1k',0
JR MSGEND
XMDMSG: XOR A ; Clear accumulator
LD (KFLG),A ; Disable 1k blocks
CALL ILPRTB
DB '128 byte CRC',0
JR MSGEND
CHKMSG: XOR A ; Clear accumulator
LD (CRCFLG),A ; Disable CRC
LD (KFLG),A ; Disable 1k blocks (not allowed in Checksum)
CALL ILPRTB
DB '128 byte Checksum',0
MSGEND: CALL ILPRTB
DB ' enabled',0
NOMSG: CALL CHKTPA ; Calculate TPA limitations
CALL ILPRTB
DB CR,LF,0
LD A,(MODE) ; Get transfer mode
CP 'R' ; Receiving?
JP Z,RCVFL ; Yes
LD A,'S'
LD (MODE),A ; Else make mode an 'S' (send mode)
;
;-------------------------------------------------------------------------;
; ----> SNDFIL - S e n d f i l e ( s ) |
;-------------------------------------------------------------------------;
;
; The file specified in the ZMD command line is transferred over the phone
; to another computer with modem using the "S"end option. The data is sent
; 1 record at a time with headers, checksums, and retransmission on errors.
;
SNDFIL: LD A,(BATCH) ; Batch mode requested?
OR A
JP NZ,SBTCH ; Yes, go handle batch mode
;
; Take care of single file transfer - not in batch
;
CALL LOGDU ; Log into drive and get DPB info
CALL GTCDUD ; Get current binary drive/user in DUU/DUD
CALL CNREC ; Calculate number of records (unless LBRARC)
CALL CATCH ; Clear the decks
CALL OPNFIL ; Open the file and check restrictions
;
; Loop back here for the start of each BATCH file sent
;
SNDFL1: LD E,60 ; Number of seconds to wait for initial 'NAK'
SNDFL2: CALL FUNCHK ; Check for function keys
CALL SNDABT ; Local abort?
LD B,1
CALL RECV ; Wait 1 second for initial NAK
JR C,SNDFL3 ; No character
CP CRC ; CRC request?
JR Z,SNDFL4 ; Yes
CP KSND ; 1k request?
JR Z,SNDFL7 ; Yes
CP NAK ; NAK for checksum?
JR Z,SNDFL8 ; Yes
CP CANCEL ; Cancel?
JP Z,ABORT ; Yes
SNDFL3: DEC E ; One less second
JP Z,ABORT ; Abort if 0
JR SNDFL2 ; Else wait some more
;
; Got a 'C', now wait up to 1 second for 'K'
;
SNDFL4: LD A,(BATCH) ; In batch mode?
OR A
JR NZ,SNDFL7 ; Yes, don't wait for 'K'
LD B,1
CALL RECV ; Get character from remote
JR C,SNDFL5 ; No character received, so not using 1k
AND 7FH ; Strip high bit
CP '{'
JR Z,SNDFL4 ; Disregard noisy lines
CP KSND ; Requesting 1k?
JR Z,SNDFL7 ; Exit if yes, otherwise set CRC
;
; Turn on the flag for CRC
;
SNDFL5: LD A,(KFLG) ; KFLG manually set from 'SK'?
OR A
JR NZ,SNDFL7 ; If yes, keep it set
SNDFL6: XOR A
LD (KFLG),A ; Defaults to 128 character blocks
INC A
LD (CRCFLG),A ; Insures in CRC mode
CALL ILPRTL
DB CR
DB 'CRC',0
JP SNDFL10
;
; Turn on the flag for 1k blocks and insure in CRC mode
;
SNDFL7: CALL LOW41K ; 1k packets allowed?
JP C,SNDFL6 ; No
LD (KFLG),A ; Set the flag for 1k blocks
LD (CRCFLG),A ; Insures in CRC mode
LD A,(BATCH) ; In Ymodem Batch?
OR A
CALL NZ,OPNFIL ; Yes, then open file/check restrictions
CALL ILPRTL
DB CR
DB 'Ymodem',0
JR SNDFL10
;
; Turn on checksum flag, insure sending 128 character blocks
;
SNDFL8: LD A,(BATCH) ; In batch mode now?
OR A
JR NZ,SNDFL9 ; If yes, exit
XOR A
LD (CRCFLG),A ; Make sure in checksum mode
LD (KFLG),A ; Defaults to 128 character blocks
CALL ILPRTL
DB CR
DB 'Checksum',0
JR SNDFL10
SNDFL9: CALL ILPRTL
DB CR
DB '-- Checksum not used in batch'
DB CR,LF,0
JP SNDFL2 ; If yes, ignore checksum request
SNDFL10:CALL ILPRTL
DB ' requested '
DB CR,LF,0
CALL RDBLOK ; Put up to 16k from file into buffer
CALL SETFLG ; Disable 1k if less than 8 records left
;
; Loop back here to send the next 1k/128 byte block after a successful trans-
; mission. If using 1k blocks, check the ACK ratio. Check total error count
; vs. records sent, and switch from 1k to 128 byte transmissions if higher.
;
SNDLP: LD A,(KFLG) ; Using 1k blocks?
OR A
JP Z,RDRECD ; If not, skip checking 1k error ratio
LD A,(ERRCNT) ; See if we got any errors last record
CP 4 ; 4 or more?
JR NC,SNDLP1 ; Yes, switch to 128 size
LD A,(ACCERR) ; See if up to minimum errors yet
CP 3 ; Had as many as three errors yet?
JR C,RDRECD ; If not, don't get excited too quickly
LD HL,(RECDNO) ; Get current record number increment
LD DE,65528 ; Have not successfully sent this 1k yet
ADD HL,DE ; Subtract the current increment, then
LD DE,(ACCERR) ; Number of non-'ACK' errors in HL
CALL DVHLDE ; Get ratio in BC of records/hit
CALL GETSPD ; Get current speed
CP 5 ; 1200 baud?
LD A,70 ; for 1200 bps
JR Z,$+4 ; If 1200, skip next line
LD A,42 ; for 2400 bps
CP C ; Compare with actual ratio
JR C,RDRECD ; Continue if less hits than allowed
SNDLP1: XOR A ; Clear A
LD (KFLG),A ; Reset system to 128 byte blocks
CALL ILPRTL ; Inform locally
DB ' - YMODEM 1k blocks disabled'
DB CR,LF,0
;
; Read a record, refill buffer if empty, update record read
;
RDRECD: LD A,(RECNBF) ; Any records in the buffer?
OR A
JR Z,RDBLOCK ; No, go get some
LD A,(KFLG) ; Using 1k blocks?
OR A
JR Z,RDREC1 ; No, exit
LD A,(RECNBF) ; See how many records in buffer
CP 8 ; 8 or more records?
JR NC,RDREC2 ; Yes, stay in 1k blocks
XOR A
LD (KFLG),A ; Reset the 1k flag for 128 byte
RDREC1: LD A,(RECNBF) ; Point to number of records in buffer
DEC A ; Decrement it for 128 character blocks
LD (RECNBF),A ; Store it
JP SNDLP2 ; Send it
RDREC2: SUB 8 ; Subtract 8 records (1k worth)
LD (RECNBF),A ; Store it
JP SNDLP2 ; Send it
;
; Buffer is empty - read in another block of 16k
;
RDBLOCK:LD A,(EOFLG) ; Get 'EOF' flag
CP 1 ; Is it set?
SCF ; To show 'EOF'
JP Z,SNDLP2 ; Got 'EOF'
CALL RDBLOK ; Read up to 16k into DBUF
JR RDRECD ; Pass record to caller
;
; Read up to 16k from the disk file into the buffer, ready to send
;
RDBLOK: LD C,0 ; Set number of records in block to 0
LD DE,DBUF ; Point to disk buffer as destination
RDBLOK1:PUSH BC
PUSH DE
LD A,(LBRARC) ; Get ARK/ARC/LBR extraction flag
OR A ; Enabled?
JR Z,RDBLOK2 ; No, skip next
LD A,(FCB+9) ; Get filetype byte 1
AND 7FH ; Strip high bit
CP 'A' ; Is it an ARK/ARC extraction?
CALL Z,RDARC ; Yes, (flags saved at RDARC)
JR Z,RDBLOK3 ; Same flags
RDBLOK2:CALL STDMA ; Set DMA address
LD C,READ
LD DE,FCB
CALL BDOS
RDBLOK3:POP DE
POP BC
OR A ; Read ok?
JR NZ,RDBLOK5 ; If not, error or end of file
LD HL,128 ; Add length of one record
ADD HL,DE ; To next buffer
EX DE,HL ; Buffer to 'DE'
INC C ; More records?
LD A,(BUFSIZ)
ADD A,A
ADD A,A
ADD A,A
CP C
JR NZ,RDBLOK1 ; Read more
;
; Buffer is full or got EOF
;
RDBLOK4:LD (RECNBF),A ; Store record count
LD HL,DBUF ; Get the beginning buffer address
LD (RECPTR),HL ; Save for next record
JP RSDMA ; Reset DMA address to default
RDBLOK5:DEC A ; 'EOF'?
JR NZ,READERR ; Got 'EOF'
RDBLOK6:INC A
LD (EOFLG),A ; Set EOF flag
LD A,C
JR RDBLOK4
READERR:CALL ILPRTB
DB CR,LF
DB '-- Read Error: ',0
CALL SHONM3
JP EXIT
;
; Now send the next record
;
SNDLP2: JP C,SNDEOF ; Send 'EOF' if done
CALL INCRNO ; Bump record number if sent ok
XOR A ; Initialize error count to zero
LD (ERRCNT),A
SNDRPT: CALL CKABORT ; Check for remote abort
CALL SNDABT ; Check for local abort
CALL SNDHDR ; Send a header
CALL SNDREC ; Send data record
CALL SNDCHK ; Send CRC or checksum value
CALL GTACK ; Get the 'ACK'
CP ACK ; ACK?
JR NZ,SNDRPT ; No, repeat transmission
LD DE,128 ; For 128 character blocks
LD A,(KFLG) ; See if last block sent was 1k
OR A
JR Z,$+5 ; No, skip next line
LD DE,1024 ; Else set for 1024 character blocks
LD HL,(RECPTR) ; Get the buffer pointer
ADD HL,DE ; Increment for the record just sent
LD (RECPTR),HL ; New buffer address for next block
LD A,(LBRARC) ; Get LBR/ARC/ARK extraction flag
OR A ; Enabled?
JP Z,SNDLP ; No
LD A,(KFLG) ; 1k enabled?
LD DE,65535 ; 128 byte
OR A
JR Z,$+5
LD DE,65528 ; 1k
LD HL,(RCNT) ; Alter the records-sent count
ADD HL,DE
LD (RCNT),HL ; One less transmission to go
OR A ; 'K' flag set?
CALL NZ,SETFLG ; Yes, see if enough records for 1k packet
LD HL,(RCNT) ; See if anything was actually sent
LD A,H
OR L ; L and H both zero now?
JP NZ,SNDLP ; No, continue
;
; End of Transmission (Send mode)
;
SNDEOF: LD A,(LOGLDS) ; Counting transfers?
OR A
JR Z,SNDEOF1 ; No
LD A,(PRIVATE) ; Is this a private transfer?
OR A
JR NZ,SNDEOF1 ; Yes, don't increment download count
LD IY,(DNLDS) ; Get Downloads counter address
INC (IY) ; One more download since log in
SNDEOF1:CALL LOGCALL ; Log transfer if supposed to
CALL EOFSND
CALL ADDTON ; Update BYE's time on byte if supposed to
CALL ALLDON
JP DONE
;
; See if enough records left to use 1k protocol
;
SETFLG: LD HL,(RCNT)
LD A,H ; Anything in the 'H' register?
OR A
RET NZ ; Yes, enough records for another 1k packet
LD A,L ; Get number of records in 'L' register
CP 8 ; At least 8 yet?
RET NC ; Yes, keep going
XOR A ; Reset the 'K' flag
LD (KFLG),A
RET
;
; HL points to filename FCB - now search for it wildcards. If any, enable
; BATCH flag and pad with '?' as needed
;
CKWILD: LD B,8 ; Check first 8 bytes
CALL CKWLD1
LD B,3 ; And check filetype
CKWLD1: LD A,(HL) ; Get the character
CP '*' ; '*'?
JR NZ,CKWLD2 ; No, check for little wildcards
LD (BATCH),A ; Enable AUTO-BATCH
LD A,'?' ; Fill rest with '?' character
JP INITIT ; Initialize
CKWLD2: CP '?' ; '?'?
JR NZ,$+5 ; No, don't enable AUTO-BATCH
LD (BATCH),A ; Enable AUTO-BATCH
INC HL ; Point to next character
DJNZ CKWLD1 ; Loop until B=0
RET
;
; Get the current drive/user
;
GTCDUD: LD A,0FFH ; Stuffed into E at RECAR1
CALL RECAR1 ; Get current user area
LD (DUU),A ; Store it
LD C,CURDRV ; Get current drive
CALL BDOS
LD (DUD),A ; Store it
RET
;
;-------------------------------------------------------------------------;
; S e n d B a t c h |
;-------------------------------------------------------------------------;
;
; Copy original command line buffer to internal work buffer
;
SBTCH: LD A,(FSTFLG) ; If first time through
OR A
JP NZ,SBTCH1 ; If not first time, exit
LD HL,TBUF ; Source
LD DE,CMDBUF ; Destination
LD BC,128 ; Count
LDIR ; Move
;
; Locate end of command line and place a ' ' as a delimiter
;
LD HL,CMDBUF ; Point to number of bytes in line
LD B,0 ; Zero high order
LD C,(HL) ; Number of characters in command line
INC HL ; Point to start of line
ADD HL,BC ; Plus number of characters equals end of line
LD (HL),' ' ; Place the delimiter at end of line
INC BC ; Increment character count for delimiter
;
; Count ambiguous/unambiguous filenames in command line
;
XOR A ; Clear accumulator
LD (FILCNT),A ; Reset the file count
LD (NAMECT),A ; Reset name count (used in parsing routines)
LD HL,CMDBUF+2 ; Point to command tail option
LD A,' ' ; Looking for space/non-space characters
CPIR ; On command option, look for next space
JP PO,SCANDN ; If at end of line, done
CPI ; Find first character of first name
JP PO,SCANDN ; If at end of line, done
JR Z,$-5 ; Eat extra spaces
DEC HL ; CPI is one ahead of us, so back up
LD (BGNMS),HL ; Store address of beginning name
INC HL ; And it was supposed to be, so restore it
SCANLP: CPIR ; Move to end of current name (next space)
EX AF,AF' ; Save A (match char) & current flags (result)
LD A,(NAMECT) ; Get current name count
INC A ; Bump it one
LD (NAMECT),A ; Put it back
CP 255 ; 255 names?
JR Z,SCANDN ; Yes, that's all we allow
EX AF,AF' ; Restore A and old flags
JP PO,SCANDN ; If at end of line, done
CPI ; Find next non-space character
JP PO,SCANDN ; If at end of line, done
JR Z,$-5 ; Was a space, keep looking
JR SCANLP ; Found next non-space, find next name
SCANDN: LD A,(NAMECT) ; Get the ambiguous filename count
OR A ; Were there any?
JP Z,HELP ; No, they must need help
CP 1 ; Just 1 name?
JR Z,$+5 ; If only 1, don't force AUTO-BATCH here
LD (BATCH),A ; Else set batch mode flag (for AUTO-BATCH)
LD HL,NAMBUF ; Get start of batch filename buffer
LD (NBSAVE),HL ; Save as address of the first name
;
; Place a name in work buffer
;
TNLP: LD B,0 ; Initialize character count
LD HL,(BGNMS) ; Source is address of first name
LD DE,FCBBUF+2 ; Destination
TNLP1: LD A,(HL) ; Get a byte in A
CP ' ' ; A space?
JR Z,TNLP2 ; Yes, done with name
LD (DE),A ; Move character to FCB buffer
INC HL ; Increment pointers
INC DE
INC B ; Bump count of characters in name
JR TNLP1 ; Loop until space
TNLP2: INC HL ; Point to next character
LD A,(HL) ; Put it in A
CP ' ' ; Is it a ' '?
JR Z,TNLP2 ; Yes, eat extra spaces
LD (BGNMS),HL ; Store address of next name
LD HL,FCBBUF+1 ; # characters in filename
LD (HL),B ; Before name
;
; Initialize FCB for search routines
;
LD A,0 ; String of all 0's for intitialization
LD HL,FCB ; Destination
LD B,16 ; 16 bytes
CALL INITIT ; Initialize FCB
LD HL,FCBBUF+1 ; Point to # of bytes in command line
LD D,0 ; Zero high order
LD E,(HL) ; Load DE pair with # bytes
INC HL ; Increment to start of command line
ADD HL,DE ; Point to byte after last character
LD (HL),CR ; Store CR for delimiter
;
; Check for valid drive/user combination and move filename to FCB
;
LD HL,FCBBUF+2 ; Start of filename
LD DE,DUSAVE ; Isolate possible 'duu:'
LD BC,4 ; Up to 4 bytes
LDIR ; For logging into specified d/u
LD HL,FCBBUF+1 ; Point to amount of characters in filename
LD B,(HL) ; In B for d/u parsing routines
INC B ; Increment character count for CR terminator
INC HL ; And point to start filename again
LD (SAVEHL),HL ; Initialize 'current' address pointer
LD A,(MODE) ; Get transfer mode
PUSH AF ; Save it while checking valid d/u
XOR A ; Zero accumulator for new mode
LD (MODE),A ; Save it (keeps us out of trouble in LGDU1:)
CALL LGDU1 ; Check valid d/u and copy filename to FCB
CALL GTCDUD ; Get current binary drive user in DUU/DUD
POP AF ; Get possible previously determined mode
LD (MODE),A ; Restore
LD HL,FCB+1 ; Filename FCB
CALL CKWILD ; Check it for wildcards, enable Batch if any
LD A,(MODE) ; Get file transfer mode
OR A ; 0=checking batch intention
RET Z ; All done if so
;
; Now search directory and store first matching filename
;
CALL RSDMA ; Reset to default memory address
LD A,'?'
LD (FCBEXT),A ; Fetch all extents of matching filenames
XOR A
LD (FCBRNO),A ; Clear FCB record number byte
LD DE,FCB ; Use default FCB for search
LD C,SRCHF ; Search for first occurence
CALL BDOS
CP 0FFH ; Anything found?
JP Z,NEXTNM ; No, go get next ambiguous filename
LD HL,(LIST) ; Initialize list pointer parameters
LD (LISTPOS),HL ; Save current position of list
;
; Calculate offset to matched directory entry
;
FNDENT: AND 3 ; Zero based, two bit index
ADD A,A ; *2
ADD A,A ; *4
ADD A,A ; *8
ADD A,A ; *16
ADD A,A ; *32 to make position index
LD C,A ; Put in BC
XOR B ; Clear MSB
LD HL,TBUF ; Address of default command line buffer
ADD HL,BC ; And offset to matched directory entry
LD A,(DUD) ; Get drive number
LD (HL),A ; Put in front of name in name buffer
;
; Check the match for download restrictions
;
PUSH HL ; Save address of matched entry
PUSH HL ; Save another copy
POP IX ; As address of filename to check
CALL RESTRCT ; Check for download restrictions
POP HL ; Get our matched entry address back
JP NZ,DONEXT ; NZ=entry not allowed
;
; Trap zero length file before adding to list
;
PUSH HL ; Save matched entry address
POP IY ; Get a copy in IY
LD A,(IY+12) ; Get the extent byte
OR A ; Is this the first extent? (#0)
JR NZ,COPYNM ; No, can't be 0 length (at least 16k already)
LD A,(IY+15) ; Get it
OR A ; Any records?
JP Z,DONEXT ; No, zero length, but in batch so no messages
;
; Copy the name to list
;
COPYNM: LD A,(FSTFLG) ; Displayed the following message yet?
OR A
JR NZ,NAM2LST ; Yes, they alreay know to wait
PUSH HL ; Save matched entry address
CALL ILPRTB
DB CR,LF
DB 'Locating selection(s)...',0
LD A,1
LD (FSTFLG),A ; Set so message don't show again
POP HL ; Restore matched entry address
NAM2LST:LD DE,(LISTPOS) ; Pointer to current load point in list
LD B,12 ; Move drive number and name to list
NM2LST1:LD A,(HL) ; HL contains address of entry
AND 7FH ; All done with high bits
LD (DE),A ; Move it to list
INC HL ; Increment pointer
INC DE
DJNZ NM2LST1 ; Loop until B equals 0
LD A,(HL) ; Get the EX byte
LD (DE),A ; Put it in list
INC HL ; Increment to RC byte
INC HL
INC HL
INC DE
LD A,(HL) ; Get it
LD (DE),A ; Put it in list
INC DE ; Point to start of next name in list
LD A,(DUU)
LD (DE),A
INC DE
INC DE
LD (LISTPOS),DE ; Store address of next load point
;
; Search for next occurance of specified filename
;
DONEXT: LD C,SRCHN ; Search next function code
LD DE,FCB ; Filename specification field
CALL BDOS
CP 0FFH ; See if all through directory yet
JP NZ,FNDENT ; If not, calculate code offset and add 2 list
;
; Trap conditions of 0 files found
;
LD HL,(LISTPOS) ; Get the end of list address
LD DE,(LIST) ; Get beginning of list address
CALL CPDEHL ; Are they the same?
JP Z,NEXTNM ; Yes, none of the files found were allowed
;
; Prepare associated sort parameters
;
LD HL,(LIST) ; Adjust I and J pointers for initial sort
LD (LISTI),HL ; Beginning of list
LD DE,ITEMSZ ; Get offset to next name
ADD HL,DE ; Add the offset
LD (LISTJ),HL ; Into J variable
;
; Don't need a sort if only 1 file extent found
;
LD HL,(LIST) ; Was there more than one entry found?
LD BC,ITEMSZ
ADD HL,BC
EX DE,HL
LD HL,(LISTPOS) ; Next load name of list is start of buffer
LD (LISTEND),HL ; Set list end marker
CALL CPDEHL ; Compare DE address with HL address
JP Z,MINNN ; If same, no sort needed
;
; Sort the list by disk, filename, and EX byte.
;
SORT: LD HL,(LISTI) ; Compare entries I and J
LD DE,(LISTJ)
LD B,13 ; Number of bytes to compare
CALL MATCH ;
JR NC,SORT1 ; Swap entries if J is larger than I
LD HL,(LISTI) ; Get our original pointers back
LD DE,(LISTJ)
LD B,ITEMSZ ; Counter for number of bytes to swap
SWAP: LD C,(HL) ; Get character from string 1
LD A,(DE) ; And one from other string
LD (HL),A ; Second into first
LD A,C ; First into second
LD (DE),A
INC HL ; Bump swap pointers
INC DE
DJNZ SWAP ; Loop until B=0
SORT1: LD HL,(LISTJ) ; Increment J pointer
LD DE,ITEMSZ ; By the amount of items per entry
ADD HL,DE
LD (LISTJ),HL
LD DE,(LISTEND) ; Get the address of the end of list
CALL CPDEHL ; DE and HL the same?
JR NZ,SORT ; No, so more J loop
LD HL,(LISTI) ; Get the I pointer
LD DE,ITEMSZ ; Get offset to next name
ADD HL,DE ; Add
LD (LISTI),HL
ADD HL,DE ; Add offset to next name
LD (LISTJ),HL ; Start J loop over again
LD DE,(LISTEND) ; Get the address of the end of list
CALL CPDEHL ; DE and HL the same?
JR NZ,SORT ; No, must be more I loop to go
;
; List minimization loop
;
LD HL,(LIST) ; Point to the beginning of our list
LD (LISTI),HL ; Initialize current name pointer
LD DE,ITEMSZ ; Get offset to next name
ADD HL,DE ; Add it to current name address
LD (LISTJ),HL ; Store as next name
MINCL: LD DE,(LISTEND) ; End of list address
LD HL,(LISTJ) ; Next name address
CALL CPDEHL ; Are they the same?
JR Z,MINNN ; Yes, go set kbytes on last name (End of list)
LD DE,(LISTJ) ; Next name address
LD HL,(LISTI) ; Current name address
LD B,12 ; # of bytes to check
CALL MATCH ; Are they the same?
JR NZ,MINNN ; No, go set kbytes on last extent (Next name)
;
; Increment next name pointer and get parameter bytes
;
LD HL,(LISTJ) ; Fetch EX and RC from next name
LD DE,ITEMSZ ; Offset to next name
ADD HL,DE ; Add it
LD (LISTJ),HL ; Save bumped J value
DEC HL ; Point to parameter bytes of previous name
DEC HL
DEC HL
LD B,(HL) ; Save the RC byte
DEC HL
LD C,(HL) ; Save the EX number
LD HL,(LISTI) ; Point at current name
ADD HL,DE ; Point at current name info bytes
DEC HL
DEC HL
DEC HL
LD D,(HL) ; Fetch that RC byte
DEC HL
LD E,(HL) ; Fetch current EX byte
LD A,E ; Check if new EXtent is bigger than last
CP C
JR NC,MINCL ; Skip using size of a less or equal EX
LD (HL),C ; Put new sizes into the location
INC HL
LD (HL),B ; New RC byte too
JR MINCL ; Continue handling as current file
;
; File size computation loop
;
MINNN: LD HL,(LISTI) ; Point to name to convert records
LD DE,ITEMSZ-4 ; Index to largest extent number
ADD HL,DE ; Add the offset
LD B,(HL) ; Get the extent number for a loop counter
INC HL ; Bump to the last extent RC byte
PUSH HL ; Save pointer to list parameters
LD HL,0 ; Zero extent total record count
LD DE,128 ; Set size of one extent
;
; Calculate total number of 128 byte records
;
MINEL: LD A,B ; Get the number of extents left
OR A ; Any more?
JR Z,MINELD ; No, done with 128 multiply
ADD HL,DE ; Else add another 128 to HL
DEC B ; 1 less extent left
JR MINEL ; Loop until no more
MINELD: EX DE,HL ; Total extent size to DE
POP HL ; Get back RC byte pointer
LD B,0
LD C,(HL) ; Get final extent size to BC
EX DE,HL ; Add remainder to total records in DE
ADD HL,BC
LD B,H ; Move total record count to BC
LD C,L
LD HL,(TOTREC) ; Get current total records
ADD HL,BC ; Add records of this file
LD (TOTREC),HL ; And save it for later display
EX DE,HL ; Get table entry pointer back in HL
CALL ROUNDK ; Get disk space needed for file DE
LD (HL),D ; Put kilobyte count in table
DEC HL
LD (HL),E
LD A,(FILCNT) ; Bump the file count
CP 255 ; 255 file names yet?
JR Z,MINN0 ; Yes, that's all we allow
INC A ; Else bump it one
LD (FILCNT),A ; Store it
LD HL,(FILEK) ; Get current total file kilobytes
ADD HL,DE ; Add in the current file's kilobyte size
LD (FILEK),HL ; And store it
LD HL,(LISTI) ; Source
LD DE,(NBSAVE) ; Destination
LD BC,16 ; 16 byte count
LDIR ; Move filename to names buffer
LD (NBSAVE),DE ; And store address to put next filename
MINN0: LD DE,(LISTJ) ; Done with all names
LD HL,(LISTEND) ; Check if at end of list
CALL CPDEHL
JR Z,NEXTNM ; Get next ambiguous filename, if finished
LD HL,(LISTI) ; Point to LISTI value
LD DE,ITEMSZ ; Point to next position
ADD HL,DE
LD (LISTI),HL ; Set new working LISTI
LD DE,(LISTI)
LD HL,(LISTJ) ; Next name position to copy from
CALL CPDEHL ; See if pointers only one apart
JR Z,MINN1 ; If so, don't cover up one name
LD BC,ITEMSZ
LDIR ; Move that name up there
JR MINN2
MINN1: LD DE,ITEMSZ ; No open slot, so just move LISTJ up one slot
ADD HL,DE
MINN2: LD (LISTJ),HL
JP MINCL ; Go to MIN NAME start of loop
NEXTNM: LD A,(OLDDRV)
CALL RECDRX ; Restore default drive
LD A,(OLDUSR)
CALL RECAR1 ; Restore default user
LD A,(NAMECT) ; Get number of names found
DEC A ; Decrement it
LD (NAMECT),A ; Put it back
JP NZ,TNLP ; Loop until zero
LD (FSTFLG),A ; Done with first time flag, reinitialize it
LD HL,NAMBUF ; Save start of buffer
LD (NBSAVE),HL
LD A,(FILCNT) ; Get total files
LD (SHOCNT),A
OR A ; Were there any?
JR NZ,NXTNM1 ; Yes
CALL ILPRT
DB CR,LF,0
JP NOFILE ; No
NXTNM1: CALL ILPRTB
DB CR
DB 'Number of files found > ',0
LD A,(SHOCNT)
LD L,A
LD H,0
CALL DECOUT ; Show number of files found
LD HL,(TOTREC)
LD (RCNT),HL
LD A,1
LD (SBSHOW),A ; Get's us back early
CALL OPNOK2 ; Go show total file stats
XOR A
LD (SBSHOW),A
SBTCH1: LD A,(FILCNT) ; Get the count of files to send
OR A ; Is there any?
JP Z,SNDFN ; No
LD A,(FSTFLG) ; Past first batch file yet?
LD (CONONL),A ; Toggle to local display only
OR A
CALL NZ,CLEARIT ; Else show local
CALL ILPRT
DB CR,LF,LF
DB 'Total transfer time > ',0
CALL GETSPD ; Get speed indicator
CP 1 ; Are we at 300 bps?
LD HL,XTABLE ; This gives us 128-byte transfer time
JR Z,$+5 ; Yes, skip next line, show 128-byte time
LD HL,KTABLE ; This gives us 1k transfer time
LD D,0
LD E,A ; Set up for table access
ADD HL,DE ; Index to proper factor
ADD HL,DE
LD E,(HL)
INC HL
LD D,(HL)
LD HL,(TOTREC) ; Get number of records
CALL FILTM1
CALL XFRTIM ; Check for time restrictions
CALL ILPRT
DB CR,LF,0
LD A,(FSTFLG)
OR A
CALL Z,DLRDY
;
; Send the batch filename to remote
;
SNDFN: CALL CKABORT ; Check for remote abort
LD HL,FCB
CALL INITFCB ; Initialize FCB
XOR A
LD (ERRCNT),A ; Reset the error count
INC A
LD (CONONL),A ; Set to local display only
LD A,(FILCNT) ; Get file count
OR A
JP Z,CCHECK ; No more files, exit
LD A,1
LD (CRCFLG),A ; Make sure in CRC mode
LD A,0FFH
CALL RECAR1 ; Get the current user area
LD B,A ; Save current user area
PUSH BC ; On stack
LD HL,(NBSAVE) ; Get start of filename
LD BC,14 ; Offset to user area
ADD HL,BC ; Point to binary user area
LD A,(HL) ; Get it
POP BC ; Get current user area back
CP B ; Same?
CALL NZ,RECAR1 ; No, but it is now
CALL SPCDRV ; Get disk parameter block info
LD HL,(NBSAVE) ; Get address of next batch filename
INC (HL) ; Escape default situation in FCB drive byte
LD DE,FCB ; Where to put it
LD BC,12 ; 12 bytes for drive and filename
LDIR ; Move
LD BC,4 ; Next filename is 4 bytes away
ADD HL,BC ; Add offset
LD (NBSAVE),HL ; Store address for next filename
LD HL,(RECPTR) ; Where to load the 0 block
EX DE,HL ; Put into DE
LD HL,FCB+1 ; Get the start of the filename in HL
LD B,8
SZMD1: LD A,(HL)
AND 7FH ; Strip any high bit set
OR A
JR Z,SZMD6 ; Null pathname
CP ' '
JR Z,SZMD3
SZMD2: CALL LCASE ; Put file name in lower case for UNIX
LD (DE),A
INC HL
INC DE
DJNZ SZMD1
JR SZMD4
SZMD3: INC HL ; Skip over spaces if short name
DJNZ SZMD3
SZMD4: LD A,(HL)
CP ' '
JR Z,SZMD6 ; Missing file type field
LD A,'.' ; Send name-type seperator
LD (DE),A
INC DE
LD B,3
SZMD5: LD A,(HL)
AND 7FH ; Strip any high bit set
CP ' '
JR Z,SZMD6
CALL LCASE ; Put in lower case for UNIX
LD (DE),A
INC HL
INC DE
DJNZ SZMD5
SZMD6: EX DE,HL ; Get the address back to HL
LD (HL),0
INC HL
LD (HDRADR),HL
CALL CNREC ; Get number of records in this file
CALL CHARLN ; Include the ASCII character length
SZMD7: LD (HL),0 ; Fill rest with zeroes
INC L ; Pad to end of block with binary 0
JR NZ,SZMD7
LD HL,(RCNT)
LD (BUFSTR),HL ; Store the file length at end of block
XOR A ; Make sure the header starts with Zero
LD (RCDCNT),A
;
; Wait for 'C' from remote to indicate he is ready
;
CCHECK: LD E,60 ; Wait up to 60 seconds to abort
CCHECK1:CALL CKABORT ; Manually requesting an abort?
LD B,3
CALL RECV ; Wait up to 5 seconds for a character
JR C,CCHECK2 ; No character, decrement counter
CP CANCEL ; If they sent a CTL-X, abort now
CALL Z,CKCAN
CP CRC ; If they sent a CRC, go to work
JR Z,SZMD8
JR CCHECK ; None of these, wait some more
CCHECK2:DEC E ; One less to go
JR NZ,CCHECK1
JP ACKMSG ; Abort if timed out and no character
SZMD8: LD A,(FILCNT) ; Any files to send?
OR A
JR NZ,SZMD9 ; Yes, continue
XOR A ; Reset the pointers
LD (ACKCHK),A ; Reset flag for normal GTACK use
LD (RCDCNT),A ; Reset the record counter
LD (KFLG),A ; Show in 128 size now
LD HL,(RECPTR)
LD (HL),A ; Reset record pointer
LD A,SOH ; Send a start of header
CALL SEND
CALL SNDHNM ; This header is a zero count
CALL SNDREC ; Send an empty record
CALL SNDCRC ; Send the CRC for the empty record
LD A,(GOTONE) ; Did we actually send at least one?
OR A
JP Z,ABORT ; If not, don't act like we did
CALL EOFSND ; No more files so send EOT to finish
CALL XFRDON
JP EXIT
;
; Now send the 128 byte filename record
;
SZMD9: DEC A ; Decrement file count for this one
LD (FILCNT),A ; Store it
SZMD10: XOR A
LD (KFLG),A
LD A,SOH ; Send SOH
LD (ACKCHK),A
CALL SEND ; Send SOH character to the modem
CALL SNDHNM ; Send header (record number, inverse)
CALL SNDREC ; Send a 128 byte record
CALL SNDCRC ; Send a two byte CRC
CALL GTACK
CP ACK
JR NZ,SZMD10 ; Not an ACK, send it again
XOR A
LD (ACKCHK),A ; Reset flag for normal GTACK use
CALL LOW41K ; Check speed being used
JR C,$+7 ; Don't allow 1k blocks if less than MINKSPD
LD A,1
LD (KFLG),A ; Change to 1k for normal file xfer
XOR A ; Clear A
LD (ERRCNT),A ; Start fresh for the main file
JP SNDFL1
;
; Send EOT. Get Acknowledgement from remote. Try up to 4 times then abort.
;
EOFSND: LD A,EOT ; Send an 'EOT'
CALL SEND
LD A,(CHKEOT) ; Did not get an ACK, try again
INC A
LD (CHKEOT),A ; Limit number of retries to 4
CP 4 ; (to prevent possible 'lock-up')
RET NC ; Quit if already sent 4 or more
CALL GTACK ; Get the ACK
CP ACK
JR NZ,EOFSND ; Resend if no ACK
RET
ALLDON: LD A,(BATCH) ; In batch mode?
OR A
RET NZ ; If yes, ignore message
CALL ILPRT ; (Want to keep this a separate message)
DB CR,LF,0
XFRDON: CALL ILPRTL
DB CR,LF
DB '-- Transfer completed'
DB CR,LF,0
RET
;
;-------------------------------------------------------------------------;
; ----> RCVFL - R e c e i v e f i l e ( s ) |
;-------------------------------------------------------------------------;
;
; The filename specified in ZMD command line is transferred over the phone
; from the user's computer to the RCPM system via modem using the 'R'
; (receive) option. The data is sent one record at a time, with headers
; and checksums and retransmissions on errors. 'RM' option is disallowed
; at time of command tail parsing at beginning of program (MSGFLG cannot
; be set unless MSGFIL is enabled).
;
RCVFL: LD A,(MSGFLG) ; Get message file upload flag
OR A ; Enabled?
JR Z,RCVF2 ; No, skip the rest
CALL WHLCHK ; Yes, WHEEL byte set?
JR NZ,RCVF1 ; Yes, turn it off and skip access check
LD A,(ACCESS) ; Checking access restrictions?
OR A
JR Z,RCVF3 ; No
LD A,(AFBYTE) ; Get access flags byte
AND 8 ; Test for write access (bit 3)
JP Z,NOACC ; Not allowed to write messages
RCVF1: XOR A ; Clear A
LD HL,(WHEEL) ; Point to WHEEL byte
LD (HL),A ; And stuff a 0 to turn WHEEL off
JR RCVF3 ; WHEEL 'was' on, so skip access check
;
; Check additional receive flags
;
RCVF2: LD A,(ACCESS) ; Checking access restrictions?
OR A
JR Z,RCVF3 ; No
CALL WHLCHK ; SYSOP online?
JR NZ,RCVF3 ; Yep, skip all this checking
LD A,(PUPFLG) ; Privileged transfer option request?
OR A
LD A,(AFBYTE) ; Get access flags byte
JR Z,$+7 ; No
AND 80H ; Test for privileged user access (bit 7)
JP Z,NOACC ; Not allowed to use "RW" option
AND 40H ; Test for upload access (bit 6)
JP Z,NOACC ; Not allowed to upload files
;
; User has the access he asked for
;
RCVF3: LD A,(BATCH) ; Requesting batch mode?
OR A
JP NZ,RBTCH ; Yes, go do batch stuff first
CALL RCVFL1 ; Find drive/user/filetype permitted
LD IX,FCB
CALL RESTRCT ; Check restrictions on uploads
CALL CONTIN ; Display drive/user area
CALL MAKEFIL ; Open the file, ready to receive
;
; Receive records until EOT
;
RCVLP: XOR A
LD (ERRCNT),A ; Initialize error count to zero
CALL RCVRECD ; Receive a record
JR NC,RCVLP1 ; If not EOT, store this record and get next
LD HL,(RECDNO) ; Get number of records
LD A,H
OR L ; 0 length file?
JP Z,ABORT ; Yes, abort and erase file
LD A,(EOTFLG) ; This the first EOT character?
OR A
JP NZ,RCVEOT ; No, exit
LD A,NAK
LD (EOTFLG),A ; Set the flag
CALL SEND ; Send a NAK
JR RCVLP ; Go wait another EOT
;
; Increment record number
;
RCVLP1: CALL INCRNO ; Bump record number, if received ok
LD HL,(RECPTR) ; Get buffer address
LD DE,128 ; 128 chars/record
LD A,(KFLG) ; Using 1k blocks?
OR A
JR Z,$+5 ; If not, skip next line
LD DE,1024 ; 1k/record
ADD HL,DE ; To next buffer
LD (RECPTR),HL ; Save buffer address
LD A,(KFLG) ; Using 1k blocks?
OR A
LD A,(RECNBF) ; Get number of records in buffer
JR Z,$+6 ; If not, skip next 2 lines
ADD A,8 ; Increment it 8 records for 1k
JR $+3 ; Skip next line
INC A ; Else only 1 record
LD (RECNBF),A ; Store new record count
;
; If 16k in buffer, write to disk
;
LD C,A ; Put the record count in C
LD A,(BUFSIZ) ; Buffer size in A
ADD A,A
ADD A,A
ADD A,A
CP C ; Is the buffer full, yet?
CALL Z,WRBLOCK ; No, return
CALL SNDACK ; Ack the record
JP RCVLP ; Loop until 'EOF'
;
; End of transmission received
;
RCVEOT: CALL SNDACK ; ACK the record
CALL WRBLOCK
JP RCVEOT0
WRBLOCK:LD A,(RECNBF) ; Number of records in the buffer
OR A ; 0 means end of file
RET Z ; None to write
LD C,A ; Save count
LD DE,DBUF ; Point to disk buff
WRBLOK1:PUSH HL
PUSH DE
PUSH BC
CALL STDMA ; Set DMA
LD DE,FCB ; Then write the block
LD C,WRITE
CALL BDOS
POP BC
POP DE
POP HL
OR A ; Write error?
JR Z,WRBLOK2 ; No
CALL RSDMA ; Reset DMA to normal
LD A,CANCEL ; Cancel
CALL SEND ; Sender
CALL SEND
CALL SEND
CALL CLOSFIL ; Kill received file
CALL ILPRTB ; Exit with msg:
DB CR,LF
DB '-- Write Error: ',0
CALL SHONM3
JP EXIT
WRBLOK2:LD HL,128 ; Length of 1 record
ADD HL,DE ; 'HL'= next buff
EX DE,HL ; To 'DE' for setdma
DEC C ; More records?
JR NZ,WRBLOK1 ; Yes, loop
XOR A ; Get a zero
LD (RECNBF),A ; Reset number of records
LD HL,DBUF ; Reset buffer
LD (RECPTR),HL ; Save buffer address
JP RSDMA
;
; Write record to log file if LOGCAL is YES
;
RCVEOT0:CALL CLOSFIL ; Close the file
LD HL,(RECDNO) ; Get # of records
LD (RCNT),HL ; Stuff in RCNT
CALL XTIM ; Calculate approximate transfer time
CALL STORTM ; Store time
CALL LOGCALL ; Log transfer if supposed to
RCVEOT1:LD A,(LOGLDS) ; Counting uploads?
OR A
JR Z,RCVEOT2 ; No
LD A,(PRIVATE) ; Private upload?
OR A
JR NZ,RCVEOT2 ; Yes, no credit for private uploads
LD IY,(UPLDS) ; Get Upload Counter
INC (IY) ; One more upload since log in
RCVEOT2:CALL ALLDON ; If not in BATCH, print transfer complete
JP CRED ; Credit upload time and ask for descriptions
;
;-------------------------------------------------------------------------;
; R e c e i v e B a t c h |
;-------------------------------------------------------------------------;
;
RBTCH: XOR A ; Using batch so reset some flags
LD (FRSTIM),A ; Needs to be reset for each new file
LD A,(FSTFLG) ; First batch file?
OR A
JR Z,RBTCH0 ; Yes, give them time to setup
LD A,CRC
CALL SEND ; In case he's quick like us
JP RBTCH1
;
; Initial setup only
;
RBTCH0: CALL RCVFL1 ; Find drive/user/filetype permitted
CALL CONTIN ; Display drive/user area
LD HL,NAMBUF
LD (NBSAVE),HL
LD A,1
LD (FSTFLG),A ; No need to run those routines again
;
; Get the batch file name and display
;
RBTCH1: LD HL,FCB
CALL INITFCB ; Initialize FCB
XOR A
LD (RCVTRY),A
INC A ; Set to local display only
LD (CONONL),A
RBTCH2: CALL CKABORT ; Check for user abort
LD B,5
CALL RECV ; Wait up to 5 seconds for SOH from remote
JR C,RBTCH3 ; No character, decrement counter
CP CANCEL ; Was it a CTL-X for cancel?
CALL Z,CKCAN ; Check for abort
CP SOH
JR Z,RBTCH5 ; Got SOH
JR RBTCH2 ; None of these, wait some more
RBTCH3: LD A,CRC ; Send a 'C'
CALL SEND
RBTCH4: LD A,(RCVTRY)
INC A
LD (RCVTRY),A
CP 20
JR C,RBTCH2
JP ABORT ; Quit and try to force him to quit also
RBTCH5: LD B,5
CALL RECV ; Wait up to 5 seconds for sector number
JP C,TOTERR
LD D,A ; Save sector number in D
OR A ; Must be a 0 if sending batch
JP NZ,WRGHDR
LD B,5
CALL RECV ; Wait up to 5 seconds for reciprocal
JP C,TOTERR
CPL ; Invert it and compare to sector #
CP D
JP NZ,CRCERR ; Bad match
LD HL,0
LD (CRCVAL),HL ; Clear CRC counter
LD E,128 ; Expecting a 128 character block
LD HL,(RECPTR) ; Point to the buffer address
RBTCH6: LD B,5
CALL RECV ; Up to 5 seconds for 128 byte header block
JP C,TOTERR ; Exit if no character
LD (HL),A ; Store the character
INC HL ; Point to next buffer location
DEC E ; One less to go
JR NZ,RBTCH6
LD E,2 ; Number of CRC bytes to get
RBTCH7: LD B,5
CALL RECV ; Up to 5 seconds for CRC bytes
JP C,TOTERR
DEC E ; Done?
JR NZ,RBTCH7 ; No
CALL CRCCHK ; Compare CRC received against ours
OR A ; Ok?
JP NZ,CRCERR ; No
CALL SNDACK ; Yes, acknowledge to remote
;
; Decode pathname into CPM format
;
LD DE,FCB+1 ; Where to put it
LD HL,(RECPTR) ; Where to get it
LD B,8 ; Filename length
RBTCH8: LD A,(HL) ; Get the character from the buffer
OR A ; Was it a zero?
JR Z,RBTCH12 ; If yes, all done
CP '.' ; Was it a delimiter?
JR Z,RBTCH9
CALL UCASE ; Insure name is in upper case
CP '_' ; Is it an underline?
JR NZ,$+4 ; No
LD A,'-' ; Else make it a dash
LD (DE),A ; Store filename character in FCB
INC DE ; Increment pointers
INC HL
DJNZ RBTCH8 ; If not 8, keep going
LD A,(HL) ; Get the character back
OR A ; We had 8, was there an extent?
JR Z,RBTCH11 ; If zero, was all done
JR RBTCH10 ; Else must be a '.'
RBTCH9: LD A,' ' ; Spaces to make up 8 spaces for name
LD (DE),A ; Store space character in FCB
INC DE ; Increment pointers
DJNZ RBTCH9 ; Keep going until in extent area
RBTCH10:INC HL ; Skip the '.' position
LD B,3 ; Extent length
RBTCH11:LD A,(HL) ; Get the character from the buffer
OR A ; Was it a zero?
JR Z,RBTCH12 ; If yes, all done
CALL UCASE ; Insure extent is in upper case
LD (DE),A ; Store extent character
INC DE ; Increment pointers
INC HL
DJNZ RBTCH11 ; Keep going until finished
RBTCH12:LD A,(FCB+1) ; See if there was any filename at all
CP ' '
JP Z,RBCHDON ; No, all done, no more files
CALL CLEARIT ; Clear screen locally if suppose to
RBTCH13:LD HL,(BUFSTR) ; Get the file length, if provided
LD A,H
OR L
JR NZ,$+7 ; If not both zero, length is provided
CALL SHONM ; Else show the filename
JR RBTCH14 ; And wait to receive
LD (RCNT),HL ; Store the file length
CALL OPNOK1 ; Show filename and file sizes
CALL ILPRTL
DB CR,LF
DB 'Ymodem transfer time > ',0
CALL GETSPD ; Get speed indicator
CP 5 ; Are we less than 1200 bps?
JR C,$+7 ; Yes, skip 1k time
CALL KTIM ; Get 1k transfer time
JR $+5 ; Skip 128 byte transfer time
CALL XTIM ; Get 128 byte transfer time
CALL XFRTIM ; Display transfer time
RBTCH14:CALL ILPRTL
DB CR,LF,LF,0 ; Finish the filename line
XOR A ; Reset the carry flag
LD (RCVTRY),A ; Reset the error counter
LD IX,FCB
CALL RESTRCT ; Check restrictions on uploads
CALL CHEKFIL ; Already have a file with that name?
CALL MAKEFIL ; If not, make it
CALL BCHINR
CALL WAITMSG ; Display '[ waiting ]' message locally
LD A,CRC
CALL SEND
JP RCVLP ; Start receiving the file
RBCHDON:XOR A ; Zero the batch mode flag
LD (BATCH),A
LD A,(GOTONE) ; Were there any files received?
OR A
JP Z,ABORT ; No, abort
CALL XFRDON ; Show transmission is finished
JP CRED ; Ask for descriptions
CRCERR: CALL ILPRTL
DB '-- CRC error'
DB CR,LF,0
JP INCERR
WRGHDR: CALL ILPRTL
DB '-- Wrong header type'
DB CR,LF,0
JR INCERR
TOTERR: CALL ILPRTL
DB '-- Timeout receiving filename'
DB CR,LF,0
INCERR: CALL WAIT1 ; Make sure sender has stopped
LD A,NAK ; Tell sender it was not successful
CALL SEND
LD A,(RCVTRY) ; Increment the error counter
INC A
LD (RCVTRY),A
CP 33
JP C,RBTCH4 ; Send a NAK and tell him to try again
JP ABORT ; Else abort
;
;-------------------------------------------------------------------------;
; C r e d i t R o u t i n e s |
;-------------------------------------------------------------------------;
;
; The following credits the caller for the amount of time spent uploading
; any non-private files with descriptions.
;
CRED: LD A,(BATCH)
OR A
JR NZ,CRED0A
LD E,10 ; Set up for a 30 second wait
CRED0: LD B,3 ; 3 seconds to receive a character
CALL RECV
JR NC,CRED0A ; Got one, continue
CALL ILPRTB ; Make sure this goes to modem
DB CR
DB '-- Hit a key'
DB CR,0 ; Let them know we're waiting
DEC E ; 2 less seconds
JR NZ,CRED0 ; Wait until 0
CRED0A: LD A,(CREDIT) ; Credit caller with upload time?
OR A
JP Z,CRED2 ; No
CALL WHLCHK ; WHEEL byte set?
JP NZ,CRED2 ; Yes, skip credit
LD A,(PUPFLG) ; Privileged transfer request?
OR A
JP NZ,CRED2 ; Yes, skip credit
LD A,(PRIVATE) ; Was this a private file?
OR A
JP NZ,CRED2 ; Yes, skip credit
LD A,(BATCH) ; In batch mode now?
OR A
JP NZ,CRED1 ; If yes, skip following messages
CALL ILPRTB ; Show to remote also
DB CR,LF
DB 'Thanks for the ',0
CALL SHOCAT ; Show upload area descriptor, if supposed to
CALL ILPRTB
DB 'upload(s)!',CR,LF,0
CALL ILPRTB
DB 'Upload time has been credited to time left.',0
CRED1: LD A,(MAXTOS) ; Get maximum time allowed
OR A ; Unlimited?
JR Z,CRED2 ; Yes, skip credit
LD HL,(RECDNO) ; Else get the number of records
LD (RCNT),HL
CALL XTIM ; Get transfer time in C
LD A,(MAXTOS) ; Get maximum time allowed back
INC A ; Increment to next full minute
ADD A,C ; Add upload time
LD (MAXTOS),A ; Save for internal use
;
; If not still in BATCH mode, ask for file description
;
CRED2: LD A,(BATCH) ; Still in batch?
OR A
JP NZ,DONE ; Yes, see if anymore files left
LD A,(HIDEIT) ; Did we make this upload a $SYS file?
OR A
JR Z,CRED3 ; No, skip all this
CALL WHLCHK ; Wheel byte set?
JR NZ,CRED3 ; Yes, file not set to $SYS
LD A,(PRIVATE) ; Was this a private upload?
OR A
JR NZ,CRED3 ; Yes, file not set to $SYS
CALL ILPRTB
DB CR,LF
DB 'Uploads remain hidden until cleared by Sysop.',0
CRED3: CALL ILPRTB
DB CR,LF,LF,0
CALL RSTLCK ; Clear WRTLOC before descriptions
CALL ADDTON ; Update BYE's time on byte if supposed to
;
;-------------------------------------------------------------------------;
; D e s c r i p t i o n R o u t i n e s |
;-------------------------------------------------------------------------;
ASK: LD A,(PRIVATE) ; Private upload?
OR A
JP NZ,EXIT ; Yes, no descriptions
LD A,(PUPFLG) ; Privileged transfer request?
OR A
JP NZ,EXIT ; Yes, no descriptions
LD A,(DESCRIB) ; Requiring descriptions?
OR A
JR NZ,ASK1 ; Yes
LD A,(MSGDESC) ; To BBS message base?
OR A
JP Z,EXIT ; No
LD (DSCFLG),A ; Set flag to show message base descriptions
LD A,(PRUSR) ; Get the private user
LD (USER),A ; FOR destination
LD A,(PRDRV) ; Get the private drive
LD (DRIVE),A ; FOR destination
ASK1: CALL GETTIME
LD HL,DATMSG+6
LD A,(EDATE) ; European date format?
OR A
JR Z,ASK1A ; No
LD A,(DAY)
CALL DATDEC ; Print DD
INC HL
LD A,(MONTH) ; Print MM
JR ASK1B ; And finish with YY
ASK1A: LD A,(MONTH)
CALL DATDEC ; Print MM
INC HL
LD A,(DAY)
ASK1B: CALL DATDEC ; Print DD
INC HL
LD A,(YEAR)
CALL DATDEC ; Print YY
LD A,(FILCNT) ; Any batch filenames?
OR A
JR Z,ASK3 ; No
LD HL,NAMBUF ; Point to name buffer
LD (NBSAVE),HL
ASK2: LD IY,FILCNT ; One less file to describe
DEC (IY)
LD HL,(NBSAVE) ; Get address of next batch filename
LD DE,FCB ; Where to put it
LD BC,12
LDIR
LD (NBSAVE),HL ; Store address for next filename
ASK3: LD A,(DESCRIB) ; FOR file descriptions?
OR A
JR Z,ASK6 ; No
LD A,(ASKAREA) ; Using upload routing?
OR A
JR Z,ASK4 ; No, KIND contents doesn't matter
LD A,(KIND) ; Do we have a the upload area yet?
OR A
JR NZ,ASK6 ; Yes, don't ask them twice
CALL ILPRTB
DB CR,LF,LF
DB 'Upload category: '
DB CR,LF,0
JR ASK5
ASK4: LD A,(ASKIND) ; Need file descriptors for FOR entries?
OR A
JR Z,ASK6 ; No
CALL ILPRTB
DB CR,LF,LF,0
CALL SHONM3 ; Show the file name
CALL ILPRTB
DB ' - this file is for:'
DB CR,LF,0
ASK5: CALL GETKIND ; Get file category for description header
CALL TYPE ; Output to both consoles
ASK6: CALL ILPRTB
DB CR
DB 'Describe ',0
CALL SHONM3 ; Show the filename
CALL ILPRTB
DB ' - 7 lines or less - ^W disables WRAP - CR when done',0
LD HL,FCB+1 ; FCB contains current filename
LD DE,NEWNAM ; Needed in here for description routines
LD B,8 ; Filename is up to 8 bytes long
CALL ASK7 ; Go store it until a space
LD A,'.'
LD (DE),A ; Add seperator
INC DE
LD HL,FCB+9 ; Point to file extent at FCB
LD B,3 ; File extent is up to 3 bytes long
CALL ASK7 ; Go store until space or B=3
LD A,LF ; Stuff Terminator
LD (DE),A
CALL GETDSC ; Show typing guide and get upload description
JP Z,ASK2 ; If we got a description, get next
JP ASK3 ; Else get this one over again
;
; Small subroutine to store the filename located at FCB+1 into buffer area
; located at DE
;
ASK7: LD A,(HL) ; Get character
AND 7FH ; Done with high bits
CP ' ' ; A space?
RET Z ; Yes, all done
LD (DE),A ; Else store it in destination
INC HL ; Increment source pointer
INC DE ; Increment destination
DJNZ ASK7 ; Keep looping until B=0 or (HL)=' '
RET
;
;-----------------------
; Set upload drive/user
;
RCVFL1: CALL LOGDU ; Select drive/user for upload
LD A,(PUPFLG) ; Place "RW" file as needed
OR A ; Can only be set if user is privileged
JR NZ,RCVFL2 ; Privileged, else check if sysop...
CALL WHLCHK ; Let WHEEL user put file wherever he wants
JR Z,RCVFL6 ; If WHEEL byte not set, stay normal
RCVFL2: LD A,(RCVDRV)
OR A
JR Z,RCVFL3
SUB 'A' ; Convert ASCII drive to binary
JR RCVFL4
RCVFL3: LD A,(OLDDRV)
RCVFL4: INC A
LD (FCB),A
ADD A,'A'-1 ; Convert binary to ASCII
LD (DRV),A ; Drive
LD A,(RCVDRV) ; See if a drive was requested
OR A
LD A,(OLDUSR) ; Current user
JR Z,RCVFL5 ; If not, use current user
LD A,(RCVUSR) ; Else get requested user
RCVFL5: LD (USR),A ; User
RET
RCVFL6: LD A,(SETAREA)
OR A
JR NZ,RCVFL7
LD A,(ASKAREA)
OR A
JR Z,RCVFL8
RCVFL7: LD A,(DRV)
SUB 40H
LD (FCB),A
RCVFL8: LD A,(PRIVATE) ; Receiving to a private area?
OR A
RET Z ; If not, exit
LD A,(PRDRV) ; Private area takes precedence
SUB 40H ; Convert to binary
LD (FCB),A ; Store drive to be used
RET
;
; Display where file(s) will go, open file and display name
;
CONTIN: LD A,(ASKAREA) ; Upload routing enabled?
OR A
JR NZ,CONT0 ; No
LD A,(ASKIND)
OR A
JR Z,CONT1
CONT0: CALL WHLCHK ; Is WHEEL byte set?
JR NZ,CONT1 ; No, skip this
CALL GETKIND ; Get upload area
LD A,CR ; So the line feed (LF) doesn't get printed
LD (CONT1+4),A
CONT1: CALL ILPRTB
DB CR,LF
DB 'Receiving on: Drive ',0
LD A,(PRIVATE) ; Private upload?
OR A
LD A,(PRUSR) ; Get private user area
LD B,A ; Put in B for now
LD A,(PRDRV) ; Get private drive
JR NZ,CONT2+3 ; Yes, priority 1
LD A,(USR) ; Get the regular user area
LD B,A ; And put it in B
LD A,(PUPFLG) ; Privileged upload?
OR A
JR NZ,CONT2 ; Yes, priority 2
CALL WHLCHK ; WHEEL set?
JR NZ,CONT2 ; Yes, priority 3
LD A,(SETAREA) ; Uploading to designated drive/user?
OR A
JR NZ,CONT2 ; Yes, priority 4
LD A,(ASKAREA) ; Upload routing enabled?
OR A
JR Z,CONT3 ; No
CONT2: LD A,(DRV) ; Get regular upload drive
PUSH AF ; Save ASCII upload drive
SUB 40H ; Convert drive to binary
LD (FCB),A ; Store it in File Control Block
POP AF ; Get ASCII drive back
JR CONT4 ; All done, now display it
CONT3: LD A,(OLDUSR) ; Get current user area for default
LD B,A ; Save in B
DB 0,0 ; Contains 'LD B,n' (DUU) from GETDU
LD A,(OLDDRV) ; Get current drive for default
ADD A,'A' ; Convert to ASCII
DB 0,0 ; Contains 'LD A,n' (DUD) from GETDU
CONT4: LD (KDRV),A ; Save it for KSHOW
CALL TYPE ; Print the drive to store on
CALL ILPRTB
DB ', User ',0
LD A,B ; B contains the user area
LD (USR),A ; Save for MSGDESC upload info
LD H,0
LD L,A ; Binary user area in L
CALL DECOUT ; Decimal output
CALL ILPRTB
DB '. (',0
CALL KSHOW ; Show available space remaining
CALL ILPRTB
DB ')',0
CALL CHEKFIL ; See if file exists
LD A,(DESCRIB) ; Descriptions enabled?
OR A
JR NZ,CONT5 ; Yes
LD A,(MSGDESC) ; Message base descriptions?
OR A
JR Z,CONT6 ; No
CONT5: LD A,(PRIVATE) ; Private upload?
OR A
JR NZ,CONT6 ; Yes, no descriptions
LD A,(PUPFLG) ; Privileged upload?
OR A
JR NZ,CONT6 ; Yes, no descriptions
CALL ILPRTB
DB CR,LF
DB 'Description(s) needed - ',0
JR CONT7
CONT6: CALL ILPRTB
DB CR,LF,0
CONT7: CALL ILPRTB
DB 'Abort: ^X pause ^X'
DB CR,LF,LF,0
CALL WAITMSG
RET
;
; Increment the file count
;
BCHINR: LD HL,(NBSAVE) ; Where to put the name
LD DE,FCB ; Where to get the name
EX DE,HL
LD BC,12 ; Move current filename to buffer for ASK:
LDIR
EX DE,HL
LD (NBSAVE),HL ; Store address for next filename
LD A,(FILCNT) ; Increment the file count
INC A
LD (FILCNT),A
RET
;
;-------------------------------------------------------------------------;
; T r a n s f e r c o m p l e t e |
;-------------------------------------------------------------------------;
;
; Done transferring current file. Check to see if in BATCH mode and if so,
; display filename transferred and reset flags for next possible file.
; Otherwise eat garbage from line, reset WRTLOC, do timekeeping and exit
; to CP/M (Forward text file to BBS message base if supposed to).
;
DONE: LD A,(BATCH) ; Still in batch mode?
OR A
JP Z,EXIT ; No. All done
LD A,(OLDDRV) ; Restore the original drive
CALL RECDRX
LD A,(OLDUSR) ; Restore the original number
CALL RECAR1
CALL RSDMA ; Reset to default DMA address
LD A,1 ; Display filename locally only
LD (GOTONE),A ; Indicates there was a file handled
CALL ILPRTL ; Display the file name
DB CR,LF,0
CALL SHONM3 ; Show the filename at FCB+1
CALL ILPRT
DB ' transferred',CR,LF,0
;
; Now reset some flags for another possible batch file
;
XOR A
LD (EOFLG),A ; Clear end of file flag
LD (EOTFLG),A ; And end of transmission flag
LD (CHKEOT),A ; Clear the "resend EOT" flag
LD HL,0
LD (ACCERR),HL ; Reset the accumulate error count
LD (RECNBF),HL ; Zero number of records in the buffer
LD (RECDNO),HL ; Zero the current record number
LD (RCDCNT),HL ; Zero the transmit record counter
LD HL,DBUF ; Reset buffer pointers
LD (RECPTR),HL
LD A,(MODE) ; Get transfer mode
CP 'S' ; Sending files?
JP Z,SNDFIL ; Yes
LD A,(FILIMT) ; Maximum upload (TPA limitation)
LD B,A ; Into B for comparison
LD A,(FILCNT) ; Get current count received
CP B ; Received BATCH transfer limit yet?
JP C,RCVFL
LD A,CANCEL
CALL SEND
CALL SEND
CALL SEND
CALL WAIT1
CALL ILPRTB
DB CR,LF
DB '-- ',0
LD A,(FILIMT)
LD H,0
LD L,A
CALL DECOUT
CALL ILPRTB
DB ' file limit in BATCH receive',CR,LF,0
XOR A
LD (BATCH),A ; Reset the batch mode flag to zero
JP CRED3 ; Go back and ask for descriptions
;
;-------------------------------------------------------------------------;
; C o m m o n S u b r o u t i n e s |
;-------------------------------------------------------------------------;
;
; Universal access check routine checks restrictions of current file being
; considered for transfer.
;
; On entry: IX = start address of byte before filename
; On exit: Z = File ok to send/receive
; NZ = Transfer denied
;
; Each bit of this word contains an image of the high bit within the filename
; pointed to by IX+1 on entry.
;
HBITMAP:DW 0000000000000000B
;
; First, make a bit map containing an image of the high bits in the filename
; pointed to by IX+1 on entry.
;
RESTRCT:LD B,11 ; Number of bytes to map
LD HL,0 ; Initialize destination for bit map
PUSH IX ; Save current filename address
INC IX ; Skip past drive indicator
ACCMASK:LD A,(IX) ; Get next character of filename
AND 80H ; Isolate attribute bit
RLCA ; Move MS bit into LS bit
OR L ; OR in any previously set bits
LD L,A ; Save result
ADD HL,HL ; Shift HL left one bit for next time
INC IX ; IY+1 equals next character in filename-type
DJNZ ACCMASK ; Loop through all 11 bytes
POP IX ; Get our original filename pointer back
;
; Most significant bit will already be in bit 11 of HL, so only 4 shifts are
; necessary
;
ADD HL,HL ; 000?????$??????00
ADD HL,HL ; 00??????$?????000
ADD HL,HL ; 0???????$????0000
ADD HL,HL ; ????????$???00000
LD (HBITMAP),HL ; Store filename high bit image
;
; See which (if any) restrictions we need to enforce
;
CALL WHLCHK ; WHEEL byte set?
JP NZ,SENDOK ; Yes, transfer is approved
LD A,(ACCMAP) ; Get user defined restriction flags
LD B,A
LD A,(MODE) ; Get the file transfer mode
CP 'S' ; Sending?
JR Z,RSTRCT2 ; Yes, check send restrictions
;
; Check RECEIVE restrictions
;
LD IX,FCB
BIT NOCOMR,B ; Rename '.COM' uploads to '.OBJ'?
JR Z,RSTRCT1 ; No, check for ZCPR restrictions
LD DE,COMCHG ; Compare to 'COM'
CALL MCHFTYP ; Are they the same?
CALL Z,RENTYP ; Yes, rename it to 'OBJ'
RSTRCT1:BIT ZCPR,B ; Using with ZCPR?
RET Z ; No, all done
LD DE,SYSCHK ; Compare to 'SYS'
CALL MCHFTYP ; Are they the same?
JR Z,FTYPERR ; Yes, tell them to use a different filetype
LD DE,NDRCHK ; Compare to 'NDR'
CALL MCHFTYP ; ...
JR Z,FTYPERR ; ...
LD DE,RCPCHK ; Compare to 'RCP'
CALL MCHFTYP ; ...
RET NZ ; If no match, filetype is ok to receive
FTYPERR:CALL ERXIT
DB CR,LF
DB '-- Use a different file extent','$'
;
; Check SEND restrictions
;
RSTRCT2:LD A,(BATCH) ; In BATCH?
OR A
JR NZ,RSTRT2A ; Yes, require send access for any batch file
BIT DWNTAG,B ; Allow F3 tagged file regardless of access?
JR Z,RSTRT2A ; No, skip this
BIT 5,H ; Byte 3 of filename set?
JP NZ,SENDOK ; Yes, send it immediately
RSTRT2A:LD A,(ACCESS)
OR A
JR Z,RSTRCT3
LD A,(AFBYTE) ; Get BYE or BBS bit mapped access flag
AND 20H ; Download access allowed?
JP Z,NOACC ; No, inform user of restricted function
RSTRCT3:LD A,(LBRARC) ; Get member extraction flag
OR A ; Enabled?
JR NZ,RSTRCT4 ; Yes, skip these restrictions
BIT TAGFIL,B ; Restricting tagged files?
JR Z,RSTRCT4 ; No
BIT 7,H ; First byte of filename set?
JR NZ,NOSEND ; Yes, can't send it
RSTRCT4:BIT NOSYS,B ; Restricting $SYS files?
JR Z,RSTRCT5 ; No
BIT 6,L ; First byte of filetype set?
JR NZ,NOSEND ; Yes, can't send
RSTRCT5:LD A,(LBRARC) ; Get member extraction flag
OR A ; Enabled?
RET NZ ; Yes, and file was not tagged (returning NZ)
BIT NOLBS,B ; Restricting files with labels (#)?
JR Z,RSTRCT6 ; No
LD A,(IX+11) ; Get possible label
AND 7FH ; Strip the high bit
CP '#' ; Labeled?
JR Z,NOSEND ; Yes, can't send
RSTRCT6:BIT NOCOMS,B ; Allow sending 'COM' files?
JP Z,SENDOK ; Yes
LD DE,COMCHG ; Point to string to compare with
CALL MCHFTYP ; Is it a .COM file?
JP NZ,SENDOK ; No
;
; Common exit point
;
COMTRY: LD A,(BATCH) ; In batch mode?
OR A
JP NZ,NOSND2 ; Yes, just set flag to not include (NZ)
POP HL ; Remove call from OPNOK from stack
CALL ERXIT
DB CR,LF
DB '-- Can''t send .COM files','$'
NOSEND: LD A,(BATCH) ; Are we in batch mode?
OR A
JP NZ,NOSND2 ; Yes, no error messages, just checking
LD DE,LBRNAM
CALL NOSND0
JR Z,NOSND1
LD DE,ARKNAM
CALL NOSND0
JR Z,NOSND1
LD DE,ARCNAM
CALL NOSND0
JR Z,NOSND1
CALL ERXIT
DB CR,LF
DB '-- File is not for distribution','$'
NOSND0: LD B,3
LD HL,FCB+9
CALL MATCH
RET
NOSND1: CALL ERXIT
DB CR,LF
DB '-- Individual members only','$'
NOSND2: LD A,1 ; Return NZ if file not allowed
OR A
RET
SENDOK: XOR A ; Return Z if file is ok
RET
;
; See if next character is ' ' or non ' '. File name error if no ASCII
; character.
;
CHKFSP: LD A,(BATCH) ; Requesting batch mode now?
OR A
JR Z,CHKFSP2 ; Exit if not
LD A,(MODE) ; Sending batch?
CP 'S'
JR Z,CHKFSP2 ; If yes, exit
DEC B
JR Z,CHKFSP1
INC B
JR CHKFSP2
CHKFSP1:POP HL ; Do not return to LOGDU
RET ; Return instead to SNDFIL
CHKFSP2:DEC B
JP Z,NFN1 ; Error if end of chars.
LD A,(HL)
CP ' '+1
RET NC ; Ok if valid character so return
INC HL
JR CHKFSP
;
; Check next character to see if a space or non-space, go to menu if a command
; error.
;
CHKSP: LD A,(BATCH) ; Requesting batch mode?
OR A
JR Z,CHKSP2 ; Exit if not
LD A,(MODE) ; Sending in batch mode now?
CP 'S'
JR Z,CHKSP2 ; If yes, exit
DEC B
JR Z,CHKSP1
INC B
JR CHKSP2
CHKSP1: POP HL ; Don't return to LOGDU
RET ; Return to SNDFIL
CHKSP2: DEC B
JP Z,HELP
INC HL
LD A,(HL) ; Get the character there
CP ' ' ; Space character?
RET ; Z = space, NZ = non-space
;
; Determine the amount of disk storage needed for the current file. On
; entry: BC = total record count of file
;
ROUNDK: LD DE,(BLKSIZ) ; Fetch block size in kilobytes
PUSH DE ; Save block size
PUSH BC ; Save file record count
LD B,3 ; Make a mask for size limit
MSKCMP: OR A ; Clear carry
RL E ; Make mask for size limit
RL D ; Shift until
DJNZ MSKCMP ; Shift until DE is A
DEC DE ; Mask of records per block
POP BC ; Get a copy of file record count
PUSH BC
LD A,C ; Mask file size with block size mask
AND E
LD C,A
LD A,B
AND D
OR C ; Zero result indicates no block
POP BC
PUSH AF ; Remainder in file size
LD A,D ; Compliment mask and zero file size
CPL ; Remainder in BC
AND B
LD B,A
LD A,E
CPL
AND C
LD C,A
LD E,3 ; Shift count to divide masked file
MINKL: OR A ; Clear carry
RR B ; Rotate high byte through carry
RR C
DEC E ; Decrement shift count
JR NZ,MINKL
POP AF ; Check if even block size
POP DE ; Get back block size
PUSH HL ; Save kilobyte insert address
LD HL,0 ; Initial zero of remainderI
JR Z,MINKS ; Zero if even
EX DE,HL ; Block size to HL if remainder
MINKS: ADD HL,BC ; Add in total kilobyte count
EX DE,HL ; Total size to DE
POP HL ; Get back load address
RET
;
; Log into drive and user
;
; (If specified). If none mentioned, falls through to 'TRAP' routine for
; normal use.
;
LOGDU: LD HL,TBUF ; Point to default buffer command line
LD B,(HL) ; Store number of characters in command
INC B ; Add in current location
CALL CHKSP ; Skip spaces to find 1st command
JR Z,$-3 ; Loop until non-space character
CALL CHKSP ; Skip 1st command (non-spaces)
JR NZ,$-3 ; Loop until a space
INC HL
CALL CHKFSP ; Skip spaces to find 2nd command
LD (SAVEHL),HL ; Save start address of the 2nd command
;
; Now pointing to the first byte in the argument. (If it was of a format
; similar to: 'B6:HELLO.DOC' then we point at the drive character 'B'. Then
; transfer up to 4 bytes from the command line buffer (pointed at by HL) to
; the drive/user storage buffer pointed at by DE
;
LGDU1: PUSH HL ; Save command line position
PUSH BC ; And character count
LD DE,DUSAVE ; Destination buffer
LD C,4 ; Drive/user is 4 characters maximum 'B15:'
LGDU2: LD A,(HL) ; Get character
CP ' '+1 ; Space or return?
JP C,TRAP ; Yes, all done
LD (DE),A ; Else store it in DUSAVE
INC HL ; Increment to next argument
INC DE ; Increment DUSAVE
CP ':' ; Was it a colon?
JR Z,LGDU3 ; Yes, was drive/user requested
DEC B ; One less position to check
DEC C ; One less to go
JR NZ,LGDU2 ; Loop until a colon or C=0
JP TRAP ; Move name to FCB
;
; Get Disk and User from DUSAVE and log in if valid.
;
LGDU3: EXX ; Save HL (buffer) pointer and BC (char count)
POP BC ; We don't need these back, but fix the stack
POP HL
EXX ; And get HL and BC back to continue
LD A,(BATCH) ; Requesting batch mode?
OR A
JR Z,LGDU4 ; No
LD A,(MODE) ; Get program transfer mode
CP 'R' ; Receiving batch?
JR Z,LGDU5 ; Yes, skip next two lines
LGDU4: CALL CHKFSP ; See if a file name is included
LD (SAVEHL),HL ; Save location of the filename
LGDU5: LD A,(PRIVATE) ; Uploading to a private area?
OR A
JP NZ,TRAP2 ; If yes, going to a specified area
LD A,(OLDDRV) ; Get current drive
LD (DUD),A
ADD A,'A'
LD (RCVDRV),A
LD HL,DUSAVE ; Point to drive/user
LD A,(HL) ; Get 1st character
CP '0' ; It is a ' ', CR or LF?
JR C,LGDU6 ; Yes, skip next 2 lines
CP '9'+1 ; Is it an ASCII number 0-9?
JR C,LGDU10
LGDU6: LD (RCVDRV),A ; Allows SYSOP to upload to any drive
CP 'A'-1
JR C,LGDU9 ; Satisfied with current drive
SUB 'A'
LD (DUD),A
LD A,(PUPFLG) ; Privileged user upload request?
OR A
LD A,(DUD)
JR NZ,LGDU8 ; Yes
CALL WHLCHK
LD A,(DUD)
JR NZ,LGDU8
LD A,(USEMAX) ; Using ZCPR low memory bytes?
OR A
JR NZ,LGDU7 ; Yes
LD A,(MAXDRV)
LD C,A
LD A,(DUD)
CP C
JP NC,ILLDU ; Drive selection not available
JR LGDU8
LGDU7: LD A,(DUD) ; Get the drive back
LD IY,(DRIVMAX) ; Point to max drive byte
INC (IY)
CP (IY) ; And check it
PUSH AF ; Save flags from the CP
DEC (IY) ; Restore max drive to normal
POP AF ; Restore flags from the CP
JP NC,ILLDU
LGDU8: INC HL ; Get 2nd character
LGDU9: LD A,(HL)
CP ':'
JP Z,LGDU17 ; Colon for drive only, no user number
CALL CKNUM ; Check if numeric
LGDU10: SUB '0' ; Convert ASCII to binary
LD (DUU),A ; Save it
INC HL ; Get 3rd character if any
LD A,(HL)
CP ':'
JR Z,LGDU11
LD A,(DUU)
CP 1 ; Is first number a '1'?
JP NZ,ILLDU
LD A,(HL)
CALL CKNUM
SUB 38
LD (DUU),A
INC HL ; Get 4th (and last character) if any
LD A,(HL)
CP ':'
JP NZ,ILLDU
LGDU11: LD A,(MODE)
CP 'R' ; Receiving a file?
LD A,(DUU)
JR Z,LGDU12
LD A,(SPLDRV)
SUB 'A'
LD C,A
LD A,(DUD)
CP C
JR NZ,LGDU12
LD A,(SPLUSR)
LD C,A
LD A,(DUU)
CP C
JR Z,LGDU15
LGDU12: CALL WHLCHK ; SYSOP using the system?
JR Z,LGDU13
LD A,(DUU) ; Restore desired user area
LD (RCVUSR),A ; Allows SYSOP to upload anywhere
JR NZ,LGDU15 ; If yes, let him have all user areas
LGDU13: LD A,(USEMAX) ; Using ZCPR low memory bytes?
OR A
JR NZ,LGDU14 ; Yes
LD A,(MAXUSR) ; Check for maximum user download area
ADD A,1
LD C,A
LD A,(DUU)
CP C
JP NC,ILLDU ; Error if more (and not special area)
JR LGDU15
LGDU14: LD A,(DUU)
LD IY,(USRMAX) ; Point at maximum user byte
CP (IY) ; And check it
JP NC,ILLDU
LGDU15: LD E,A
LD A,(SETAREA) ; Using designated drv/usr for reg. uploads?
OR A
JR NZ,LGDU16 ; Yes
LD A,(ASKAREA) ; Using upload routing?
OR A
JR NZ,LGDU16 ; Yes
LD A,E
LD (CONT3+5),A ; Store requested user area
LD A,6 ; 'LD B,n' instruction
LD (CONT3+4),A
LGDU16: LD C,SETUSR ; Set to requested user area
CALL BDOS
LGDU17: LD A,(DUD) ; Get drive
LD E,A
LD A,(SETAREA) ; Using designated drv/usr for reg. uploads?
OR A
JR NZ,LGDU18 ; Yes
LD A,(ASKAREA) ; Using upload routing?
OR A
JR NZ,LGDU18 ; Yes
LD A,E
ADD A,'A'
LD (CONT3+12),A ; Store requested drive
LD A,3EH ; 'LD A,n' instruction
LD (CONT3+11),A
LGDU18: LD C,SELDSK ; Set to requested drive
CALL BDOS
JR TRAP2 ; Now find file selected
;
; If we get here, no d/u was specified. Restore original command line pointer
; and character count and move name to FCB.
;
TRAP: POP BC ; Get original character count back
POP HL ; And original command line buffer position
;
; Check for no file name or ambiguous name
;
TRAP1: LD A,(PRIVATE) ; Get the private transfer flag
OR A ; Is it enabled?
JR Z,TRAP2 ; No, current du stays normal
LD A,(SPLUSR) ; Get the special download user area
CALL RECAR1 ; Set user area to special download user
LD A,(SPLDRV) ; Get the special download drive
CALL RECDR1 ; Set drive to special download drive
TRAP2: CALL SPCDRV ; Keep DPB info straight
LD HL,FCB
CALL INITFCB ; Make sure FCB initialized
CALL MOVFCB ; Move the filename into the file block
LD HL,FCB+1 ; Point to file name
LD A,(HL) ; Get first character
CP ' ' ; Any there?
JR NZ,TRAP3 ; Yes, check wildcards
LD HL,FCB+9 ; Else point to file extent
LD A,(HL) ; Get character
CP ' ' ; Space also?
JP Z,NFN ; Yes, we have no filename, exit with error
LD HL,FCB+1 ; Else point to start again
TRAP3: LD A,(PRIVATE) ; Get the private transfer flag
OR A ; Is it enabled?
RET Z ; No, then don't trap wildcards
LD B,11 ; Else check all 11 characters of filename
TRAP4: LD A,(HL) ; Get char from FCB
CP '?' ; Ambiguous?
JR Z,NOWILD ; Yes, exit with error message
CP '*' ; Even more ambiguous?
JR Z,NOWILD ; Yes, exit with error message
INC HL ; Point to next character
DJNZ TRAP4 ; Not done, check some more
RET
CKNUM: CP '0'
JR C,ILLDU ; Error if less than ascii '0'
CP '9'+1
RET C ; Error if more than ascii '9'
ILLDU: CALL ERXIT
DB CR,LF
DB '-- Unauthorized drive/user','$'
NFN: CALL ILPRT
DB CR,LF,0
NFN1: CALL ERXIT ; Print message, exit
DB '-- No filename(s) requested','$'
NOWILD: CALL ERXIT ; Print message, exit
DB CR,LF
DB '-- Wildcards not valid for PRIVATE downloads','$'
;
; Previous record repeated, due to the last ACK being garbaged. ACK it so the
; sender will catch up
;
RCVACK: CALL SNDACK ; Send the ACK
XOR A
LD (ERRCNT),A ; Reset the error count
;
; Receive a record - returns with carry bit set if EOT received
;
RCVRECD:CALL FUNCHK ; Check function keys
CALL SNDABT ; See if wanting to abort
LD A,(FRSTIM) ; Have we started, yet?
OR A
LD B,10 ; Check every ten seconds if already started
JR Z,$+4 ; If yes, skip next line
LD B,5 ; Check every 5 seconds until started
CALL RECV ; Get character
JP C,RCVSTOT ; Timeout error if no character received
CP SOH ; SOH?
JP Z,RCVSOH ; Yes, get record
CP STX ; STX for 1k blocks?
JR NZ,$+11 ; No
LD (KFLG),A ; Set the 1k flag
LD (CRCFLG),A ; Insure in CRC mode for 1k blocks
JP RCVS1
CP CANCEL ; Was it a CTL-X to abort?
CALL Z,CKCAN ; If yes, check for aborting
OR A ; Get another character, if a null
JR Z,RCVRECD
CP 7BH ; V.22 synch character, ignore
JR Z,RCVRECD
CP 0FBH ; V.22 synch character with high bit set
JR Z,RCVRECD
CP EOT ; See if end of transmission
SCF ; Set carry
RET Z ; Return with carry set
CP CRC ; Ignore our own character coming back
JR Z,RCVRECD
CP KSND ; Ignore our own character coming back
JR Z,RCVRECD
CP NAK ; Ignore our own character coming back
JR Z,RCVRECD
CALL ILPRTL ; Show locally only
DB CR,'-- ',0
LD A,B
CALL HEXO
CALL ILPRTL
DB 'H received not SOH',CR,LF,0
JR RCVSR
;
; Checksum error
;
CKSMERR:CALL ILPRTL
DB ' - Checksum error',CR,LF,0
JR RCVSR ; Go check the error limit and send NAK
;
; Bad record number in header error
;
HDRERR: CALL ILPRTL
DB ' - Error in header',CR,LF,0
JR RCVSR ; Go check error limit and send NAK
;
; Timed out on receive error
;
RCVSTOT:LD A,(FRSTIM) ; First time flag set yet?
OR A
JR Z,RCVSR ; If not, don't show an error
CALL TOTMSG
;
; Didn't get SOH or EOT or did not get valid header so purge the line, then
; send NAK.
;
RCVSR: CALL WAIT1 ; Get anything coming in and discard
CALL SNDABT ; See if wanting to abort
LD A,(FRSTIM) ; Get first time switch
OR A ; Has first 'SOH' been received?
LD A,NAK
JR NZ,RCVSR1 ; Yes, then send 'NAK'
LD A,(CRCFLG) ; Get the 'CRC' flag
OR A ; 'CRC' in effect?
LD A,NAK ; Put 'NAK' in 'A' register
JR Z,RCVSR1 ; No, send the 'NAK' for checksum
LD A,CRC ; Tell sender we have 'CRC'
CALL SEND
LD A,(KFLG) ; Requesting 1k transmissions?
OR A
JR Z,RCVSR1 ; If not, exit
LD A,KSND ; Tell sender we also have 1k capability
RCVSR1: CALL SEND ; The 'NAK' or 'CRC' request
LD A,(ERRCNT) ; Get the error count
INC A ; Increment error count
LD (ERRCNT),A ; Store new value
LD B,A ; Keep the error count for now
LD A,(FRSTIM) ; Have we gotten under way yet?
OR A
LD A,B ; get the value back
JR Z,RCVSR2 ; If not, exit
CP 10 ; 10 errors the limit, once under way
JP NC,ABORT ; Abort if over the limit
CALL RDCOUNT ; Display record count before repeating
JP RCVRECD ; Less than 10, keep going
RCVSR2: CP 7 ; 7 times for 1k/CRC yet? (40 seconds)
JP C,RCVRECD ; Keep trying if less
XOR A ; Else flip to checksum mode
LD (CRCFLG),A
LD A,B ; Get the count back
CP 3 ; Another 3 times for checksum?
JP C,RCVRECD ; If less, try again, quit at 60 seconds
JP ABORT
;
; Aborts with 1 CTL-X if first time flag is not set, two otherwise
;
CKCAN: LD A,(FRSTIM) ; First time flag set yet?
OR A
JR Z,CKCAN1 ; If not, abort
LD B,2
CALL RECV ; Maximum of 2 seconds for extra ^X
RET C ; No additional character, ignore single ^X
CP CANCEL ; Got a character, is it a ^X?
RET NZ ; No, ignore 1st ^X and return
CKCAN1: POP HL ; Reset stack for CALL CKCAN
JP ABORT ; Got 2nd ^X, abort and close file
;
; Got SOH - get block number (complemented)
;
RCVSOH: XOR A
LD (KFLG),A ; If SOH, clear the 1k flag
RCVS1: LD A,1 ; Get something to store
LD (FRSTIM),A ; Indicate first 'SOH' or 'STX' recvd.
LD B,5
CALL RECV ; Wait up to 5 seconds for block number
JP C,RCVSTOT ; Got timeout
LD D,A ; Save block number
LD B,5
CALL RECV ; 5 seconds for complimented record number
JP C,RCVSTOT ; Timeout
CPL ; Get the complement
CP D ; Same as original block number?
JP NZ,HDRERR ; No, go report bad record number in header
LD A,D ; Get record number
LD (RCVCNT),A ; Save it
LD C,0 ; Initialize checksum
LD HL,0 ; Initialize CRC
LD (CRCVAL),HL ; Clear CRC counter
LD DE,128 ; For 128 character blocks
LD A,(KFLG) ; Using 1k blocks?
OR A
JR Z,$+5 ; If not, skip next line
LD DE,1024 ; If using 1k blocks
LD HL,(RECPTR) ; Get buffer address
RCVCHR: LD B,5
CALL RECV ; 5 seconds for character
JP C,RCVSTOT ; Timeout
LD (HL),A ; Store the character
INC HL ; Point to next character
DEC DE ; One less to go
LD A,E ; See if 'D' and 'E' are both empty
OR D
JR NZ,RCVCHR ; No, get next character
LD A,(CRCFLG) ; Using 'CRC'?
OR A
JP NZ,RCVCRC ; If yes go get 'CRC'
;
; Verify checksum
;
LD D,C ; Save checksum
LD B,5
CALL RECV ; Up to 5 seconds for checksum
JP C,RCVSTOT ; Timeout
CP D ; Checksum ok?
JP NZ,CKSMERR ; No, report error
;
; Got a record, it's a duplicate if equal to the previous number, it's OK if
; previous + 1 record
;
CHKSNUM:LD A,(RCVCNT) ; Get received record number
LD B,A ; Save it
LD A,(RCDCNT) ; Get previous record number
CP B ; Previous record repeated?
JP Z,RCVACK ; If yes 'ACK' to catch up
INC A ; Increment by 1 for 120 character block
CP B ; Match this one we just got?
JP NZ,ABORT ; No match, stop the sender, exit
RET ; Else return with carry not set, was ok
;
; Receive the Cyclic Redundancy Check characters (2 bytes) and see if the CRC
; received matches the one calculated. If they match, get next record, else
; send a NAK requesting the record be sent again.
;
RCVCRC: LD E,2 ; Number of bytes to receive
RCVCRC2:LD B,5
CALL RECV ; Up to 5 seconds for CRC byte
JP C,RCVSTOT ; Timeout
DEC E ; Decrement the number of bytes
JR NZ,RCVCRC2 ; Get both bytes
CALL CRCCHK ; Check received CRC against calc'd CRC
OR A ; Is CRC okay?
JR Z,CHKSNUM ; Yes, go check record numbers
CALL ILPRTL ; Show locally only
DB ' - CRC error',CR,LF,0
JP RCVSR ; Go check error limit and send NAK
;
;------------------
; Send subroutines
;------------------
;
; Send an ACK for the record
;
SNDACK: LD A,ACK ; Get 'ACK'
JP SEND ; And send it
;
; Send SOH, block number and complemented block number (3 bytes total)
;
SNDHDR: LD A,(KFLG) ; Sending 1k blocks?
OR A
LD A,STX ; If yes, send a STX rather than SOH
JR NZ,$+4
LD A,SOH ; Send start of header
CALL SEND
SNDHNM: LD A,(RCDCNT) ; Send the current record number
CALL SEND
LD A,(RCDCNT) ; Get the record number again
CPL ; Complemented
JP SEND ; From SENDHDR
;
; Send data record
;
SNDREC: LD C,0 ; Initialize checksum
LD HL,0 ; Initialize CRC
LD (CRCVAL),HL
LD A,(KFLG) ; Sending 1k blocks?
OR A
LD DE,1024
JR NZ,$+5 ; If yes, skip the next line
LD DE,128
LD HL,(RECPTR) ; Get buffer address
SENDC: LD A,(HL) ; Get a character
CALL SEND ; Send it
INC HL ; Point to next character
DEC DE
LD A,E
OR D
JR NZ,SENDC ; If DE not zero, keep going
RET ; From SENDREC
;
; Send the CRC or checksum value
;
SNDCHK: LD A,(CRCFLG) ; See if sending 'CRC' or 'checksum'
OR A
JR NZ,SNDCRC ; If not zero, send the 'CRC' value
;
; Send Checksum
;
SNDCKS: LD A,C ; Send the checksum
JP SEND ; From SNDCKS
;
; Send CRC (2 characters). Call FINCRC to calculate the CRC which will be
; in 'DE' upon return.
;
SNDCRC: CALL FINCRC ; Calculate the 'CRC' for this record
LD A,D ; Put first 'CRC' byte in accumulator
CALL SEND ; Send it
LD A,E ; Put second 'CRC' byte in accumulator
CALL SEND ; Send it
XOR A ; Set zero return code
RET
;
; Get acknowlegement
;
; After a record is sent, a character is returned telling if it was received
; properly or not. An ACK allows the next record to be sent. A NAK causes
; the current record to be resent. If no character (or any character other
; than ACK or NAK) is received after a short wait (10-12 seconds), a timeout
; error message is shown and the record will be resent.
;
GTACK: LD B,12
CALL RECV ; Wait up to 12 seconds for ACK or NAK
JR NC,GTACK1 ; Got one
CALL TOTMSG
JP ACKERR ; Set the carry bit and return
GTACK1: CP ACK ; See if an ACK already
RET Z ; If yes, return
CP NAK ; See if a NAK
JR Z,GTACK2 ; If yes, print error, then resend
CP 07BH ; V.22 synch character?
JR Z,GTACK ; If yes, ignore it
CP 0FBH ; V.22 synch character?
JR Z,GTACK ; If yes, ignore it
CP CANCEL ; CTL-X to cancel attempt?
CALL Z,CKCAN
GTACK2: LD B,A ; Save the character
LD A,(CHKEOT) ; Sending EOT?
OR A
JP NZ,ACKERR ; If yes, don't show error (for ZMD)
CALL ILPRTL
DB ' - ',0
LD A,B
CP NAK
JR Z,GTACK3
CALL HEXO
CALL ILPRTL
DB 'H',0
JR GTACK4
GTACK3: CALL ILPRTL
DB 'NAK',0
GTACK4: CALL ILPRTL
DB ' received not ACK',CR,LF,0
CALL CATCH ; None of them, establish clear line again
;
; Timeout or error on ACK - bump error count then resend the record if
; error limit is not exceeded
;
ACKERR: LD A,(ACCERR) ; Count accumulated errors on ACK
INC A ; Add in this error
LD (ACCERR),A
LD A,(ERRCNT) ; Get count
INC A ; Bump it
LD (ERRCNT),A ; Save back
CP 10 ; At limit?
JR NC,ACKMSG ; If yes, send error message and abort
LD A,(ACKCHK) ; Checking after a batch header?
OR A
CALL Z,RDCOUNT ; Yes, show the record count for repeat
LD A,B ; Get character back
CP NAK ; NAK?
JP NZ,GTACK ; No, ignore and wait for ACK or NAK
RET ; And go back
;
; Reached error limit
;
ACKMSG: CALL WAIT1 ; Wait for any input to stop
LD A,CANCEL ; Tell remote we are quitting
CALL SEND
CALL SEND
CALL SEND
LD B,2
CALL RECV ; Up to 2 seconds for remote to quit too
LD A,BS
CALL SEND ; Clear any CTL-X from buffer
CALL SEND
CALL SEND
CALL ERXIT
DB CR
DB '-- File transfer aborted','$'
;
; Routines to trap abort conditions
;
; Check to see if a cancel requested. Fall through to ABORT if so.
;
CKABORT:CALL CONSTAT
OR A
RET Z
CALL CONIN
CP CANCEL
RET NZ
;
; Aborts send or receive routines and returns to command line
;
ABORT: CALL WAIT1 ; 1- second delay to clear input
CALL CATCH
LD A,(EOTFLG) ; Timed out after only 1 EOT?
OR A
JP NZ,RCVEOT+3 ; Accept as valid EOT then
LD A,CANCEL ; Show you are cancelling
CALL SEND ; They may quit also with enough CTL-X
CALL SEND
CALL SEND
CALL WAIT1 ; 1-second delay to clear input
CALL CATCH
LD A,BS
CALL SEND
CALL SEND
CALL SEND
ABORTX: CALL CATCH ; Eat garbage characters
CALL ABRTMSG ; Show we have aborted
LD A,(MODE) ; Get file transfer mode
CP 'R' ; Sending a file?
JP NZ,EXIT ; Yes, quit to CP/M
;
; Take care of received file (if any).
;
CLOSFIL:LD C,CLOSE ; Get function
LD DE,FCB ; Point to file
CALL BDOS ; Close it
INC A ; Close ok?
JR NZ,CLOSFL1 ; Yes
CALL ILPRT ; No, abort
DB CR,LF
DB '-- Received file not closed',0
JP NTDEL1
CLOSFL1:LD A,(EOTFLG) ; Get end of transmission flag
OR A ; Received entire file?
RET NZ ; Yes, return to RCVEOT routines
CALL ILPRTB
DB CR,LF
DB '-- Upload has been cancelled',0
;
; Delete the received file
;
LD C,DELETE ; Get function
LD DE,FCB ; Point to file
CALL BDOS ; Delete it
INC A ; Delete ok?
JR Z,NOTDEL ; No
CALL ERXIT ; Print second half of message
DB CR,LF
DB '-- Partial file is deleted','$'
;
; Unsuccessful delete
;
NOTDEL: CALL ILPRT
DB CR,LF
DB '-- Received file not deleted'
NTDEL1: CALL ERXIT
DB ' or no file received','$'
;
; See if a file exists. If it exists, ask for a different name.
;
CHEKFIL:LD A,(SETAREA) ; Uploading to designated drive/user?
OR A
JR NZ,CHEKF1 ; Yes
LD A,(ASKAREA) ; Upload routing enabled?
OR A
JR NZ,CHEKF1 ; Yes
LD A,(PRIVATE) ; Receiving in private area?
OR A
JR Z,$+5 ; No
CHEKF1: CALL RECARE ; Set the designated area up
LD C,SRCHF ; See if it exists
LD DE,FCB ; Point to control block
CALL BDOS
INC A ; Found?
RET Z ; No, return
LD A,CANCEL ; Tell the remote we are aborting
CALL SEND ; Send several cancel requests
CALL SEND
CALL SEND
CHEKF2: LD B,1
CALL RECV ; Up to 1 seconds for character
JR NC,CHEKF2 ; Wait until no more characters
LD A,(BATCH) ; Using batch mode now?
LD (CONONL),A ; If not, send message to modem also
OR A
JR Z,CHEKF3 ; If not, exit
LD A,CANCEL
CALL SEND
CALL SEND
CALL SEND
LD A,BS
CALL SEND
CHEKF3: CALL ERXIT ; Exit, print error message
DB CR,LF
DB '-- File already exists','$'
;
; Make the file to be received
;
MAKEFIL:XOR A ; Set extent and record number to 0
LD (FCBEXT),A
LD (FCBRNO),A
LD A,(HIDEIT)
OR A
JR Z,MAKEF1 ; HIDEIT not enabled, skip all this
CALL WHLCHK
JR NZ,MAKEF1 ; Don't make it $SYS if SYSOP online
LD A,(PRIVATE)
OR A
JR NZ,MAKEF1 ; Don't make it $SYS if private upload
LD DE,FCB+10 ; Point at second char of file extent
LD A,(DE)
OR 80H ; And turn on the high bit (Make file $SYS)
LD (DE),A ; Put it back
MAKEF1: LD C,MAKE ; Get BDOS FNC
LD DE,FCB ; Point to FCB
CALL BDOS ; To the make
PUSH AF ; Save MAKE error code
LD C,SETFILE ; Set up for BDOS FUNCTION 30
LD DE,FCB
CALL BDOS ; Set file attributes
POP AF ; Error code from BDOS make function
INC A ; 0FFH=bad?
RET NZ ; Open ok
LD HL,FCB+1
JP NOROOM ; Tell them directory might be full
;
; Open file to be sent
;
OPNFIL: XOR A ; Zero accumulator
LD (FCBEXT),A ; Set extent to 0
LD (FCBRNO),A ; Set record number to 0
LD DE,FCB ; Point to file
LD C,OPEN ; Open it
CALL BDOS
INC A ; Open ok?
JR NZ,OPNOK ; Yes, check restrictions
LD A,(LBRARC) ; Get extraction flag
OR A ; Enabled?
JP Z,NOFILE ; No, abort
LD HL,ARCNAM ; Force .ARC filetype
CALL CHNGEXT ; Try to open it
JR NZ,OPNOK ; File found
LD HL,ARKNAM ; Force .ARK filetype
CALL CHNGEXT ; Try to open it
JR NZ,OPNOK ; File found
LD HL,LBRNAM ; Force .LBR filetype
CALL CHNGEXT ; Try to open it
JR NZ,OPNOK ; File found
JP NOARK ; Not found and no more filetypes to try
CHNGEXT:LD DE,FCB+9
LD BC,3
LDIR
LD C,OPEN
LD DE,FCB
CALL BDOS
INC A
RET ; Z flag set=file not found
;
; Requested file was found, now check some restrictions
;
OPNOK: LD IX,FCB ; Point to filename
CALL RESTRCT ; Check it for restrictions
LD A,(LBRARC) ; Get the member extraction flag
OR A ; Enabled?
JR Z,OPNOK1 ; No, skip this
CALL RSDMA ; Reset to default DMA address
LD C,READ ; Read first file record
LD DE,FCB
CALL BDOS
OR A ; Read ok?
JP NZ,READERR ; If not, error
CALL CKDIR ; Take care of LBR stuff
OPNOK1: LD HL,(RCNT) ; Get record count
LD A,H
OR L
JP Z,ZEROLN ; Can't send 0-length files
LD A,(BATCH)
OR A
JR Z,OPNOK1A ; Don't clear screen unless in BATCH mode
LD A,(FSTFLG) ; Get first file sent flag
OR A ; Sent it already?
LD A,1 ; Show we have for next time
LD (FSTFLG),A
CALL Z,CLEARIT ; No, need to clear screen here first time
OPNOK1A:CALL SHONM ; Show the name of this file
CALL LOW41K ; Less than MINKSPD?
JR C,OPNOK3 ; Yes, don't show 1k packets
OPNOK2: CALL ILPRT
DB CR,LF
DB 'Ymodem packets total > ',0
LD HL,(RCNT) ; Get record count
CALL DIVREC ; Divide number of records by 8
CALL DECOUT ; Show # of 1k packets
OPNOK3: CALL ILPRT
DB CR,LF
DB 'Xmodem packets total > ',0
LD HL,(RCNT) ; Get original count
CALL DECOUT ; Show # of 128 byte packets
LD A,(MODE) ; Get transfer mode
CP 'R' ; Receiving?
RET Z ; Yes, all done
CALL ILPRT
DB CR,LF
DB 'Disk space you need > ',0
LD A,(SBSHOW) ; Displaying intial BATCH screen to remote?
OR A
PUSH AF ; Save answer
LD HL,(FILEK) ; Get precalculated total 'k' for all files
JR NZ,OPNOK4 ; Go show it
LD BC,(RCNT) ; Else get single file record count back
CALL ROUNDK ; Round disk space needed
EX DE,HL
;
OPNOK4: CALL DECOUT ; Decimal output
CALL ILPRT
DB 'k (',0
LD HL,(BLKSIZ) ; Get host disk block size
CALL DECOUT ; Decimal output
CALL ILPRT
DB 'k blocks)',0
POP AF ; Displaying initial BATCH screen to remote?
RET NZ ; Yes, then we're done in here
;
; Show transfer time, first for 1k blocks, then for 128-byte blocks. If we are
; at 300 bps, report both transfer times the same. (skip the 1k times for
; speeds slower than MINKSPD bps.)
;
KSPD: CALL LOW41K ; Less than MINKSPD?
JR C,XSPD ; Yes, skip 1k display
CALL ILPRT
DB CR,LF
DB 'Ymodem time / 1k > ',0
CALL GETSPD ; Get current modem speed
CP 1 ; At 300 bps?
JR Z,KSPD1 ; 1k transfer time in BC (minutes) if >300
CALL KTIM
JR KSPD2
KSPD1: LD HL,XECTBL
LD (RECTBL+1),HL
CALL XTIM
KSPD2: CALL STORTM ; Store it
CALL XFRTIM ; Display it
XSPD: CALL ILPRT
DB CR,LF
DB 'Xmodem time / 128 byte > ',0
LD HL,XECTBL ; 128 size values (300 bps)
LD (RECTBL+1),HL
CALL XTIM ; Xmodem transfer time
LD A,(KFLG) ; If 'SK' set, 1k time already stored
OR A
CALL Z,STORTM
CALL XFRTIM
LD HL,KECTBL ; Restore to original 1k values
LD (RECTBL+1),HL
CALL ILPRT
DB CR,LF,0
LD A,(BATCH) ; In batch mode?
OR A
JP Z,OPNOK5 ; No, couldn't have been here before
LD A,(FSTFLG) ; Yes, been here before?
OR A
JP Z,OPNOK5 ; No, following gets shown next time
;
; In batch, show files remaining after this one is sent
;
CALL ILPRTL
DB CR,LF
DB 'Files remaining > ',0
LD A,(SHOCNT) ; Get cumulative files
DEC A
LD (SHOCNT),A ; Less one
LD L,A
LD H,0
CALL DECOUT
CALL ILPRTL
DB CR,LF
DB 'Ymodem packets remaining > ',0
LD HL,(RCNT) ; Get this file's record count again
EX DE,HL ; Put in DE
LD HL,(TOTREC) ; Total records remaining
LD A,L
SUB E
LD L,A
LD A,H
SBC A,D
LD H,A
JR NC,$+5
LD HL,0 ; In case of a slightly negative number
PUSH HL ; Save it for Xmodem packets show
CALL DIVREC ; Divide number of records by 8
CALL DECOUT
CALL ILPRTL
DB CR,LF
DB 'Xmodem packets remaining > ',0
POP HL ; Get total records remaining after this file
LD (TOTREC),HL
CALL DECOUT ; Show remote remaining records
CALL ILPRTL
DB CR,LF,LF,0
CALL WAITMSG ; Display '[ waiting ]' message locally
RET
;
; If sending an ARC or ARK file, tell user to rename to .ARK or .ARC file type.
;
OPNOK5: LD A,(LBRARC) ; Get extraction flag
OR A ; Enabled?
JP Z,DLRDY ; No, skip this
LD A,(FCB+9) ; Point to member filetype
AND 7FH ; Strip parity
CP 'L' ; LBR member extraction?
JP Z,DLRDY ; Yes, skip this
CALL ILPRTB
DB CR,LF
DB 'You MUST name file > ',0
LD D,8 ; Filename count - ignore filetype
LD HL,MEMFCB ; Get requested member name
OPNOK6: LD A,(HL)
CP ' ' ; Short filename?
JR Z,OPNOK7 ; If so, fill in type
CALL TYPE
DEC D ; One less...
INC HL ; Next character
JR NZ,OPNOK6 ; Loop until done
OPNOK7: LD A,(FCB+11) ; Get last character of parent filetype
LD ($+9),A ; Stuff it below to display
CALL ILPRTB
DB '.AR?' ; Either a 'C' or a 'K' gets poked at '?'
DB CR,LF,0
CALL DLRDY ; Tell them their download(s) are ready
RET
;
; These routines display the transfer time in minutes & seconds and check for
; time restrictions, if a clock is enabled.
;
XFRTIM: PUSH HL ; Save seconds in 'L'
CALL WHLCHK ; Sysop online?
JR NZ,SKPTIM ; Yes, then skip the limit
LD A,(MAXTOS)
OR A
JR Z,SKPTIM
LD D,C ; Save minutes for now
INC D ; Increment to next full minute
LD A,(TIMEON) ; Using TIMEON?
OR A
LD A,D ; Get length of this program
JR Z,XFRTM1 ; No, don't increment time
LD HL,TON ; Point to time on system
ADD A,(HL) ; Else add time on system to transfer time
XFRTM1: LD (XFRMIN),A ; Store it
OR A
LD A,B ; Get hours in A
JR NZ,$+3 ; Don't increment if not zero
INC A ; Increment to next full minute
LD (XFRMIN+1),A
SKPTIM: LD H,B ; Get most significant in H (hours)
LD L,C ; Get least significant byte of minutes in L
CALL DECOUT ; Print decimal number of minutes
CALL ILPRT
DB ':',0
POP HL ; Get seconds back
LD A,L ; Get the number of seconds
CP 10 ; 10 seconds or more?
JR NC,$+7 ; If yes, disregard next two lines
CALL ILPRT
DB '0',0
CALL DECOUT ; Print decimal number of seconds
CALL ILPRT
DB ' at ',0
CALL GETSPD ; Get modem speed value in A
CALL SHOSPD ; Display in BPS
;
; Determine if the caller has enough time left online to make the
; requested download(s).
;
XFRTM3: LD A,(MODE) ; Get transfer mode
CP 'R' ; Receiving?
RET Z ; Yes, all done
LD A,(MAXTOS) ; Get maximum time allowed
OR A ; Unlimited?
RET Z ; Yes, skip time restriction
LD A,(XFRMIN+1) ; Get most significant byte of minutes
OR A ; 0?
JR NZ,OVERTM ; If not, over 255 minutes
LD A,(XFRMIN) ; Get least significant byte of minute count
LD B,A ; Put in B
LD A,(MAXTOS) ; Get maximum time allowed
INC A
SBC A,B
RET NC
;
; There is not enough time to download the requested file(s). Inform user and
; abort to CP/M.
;
OVERTM: CALL ILPRTB
DB CR,LF,LF,0
CALL ABRTMSG ; Display both local and remote we aborted
CALL ILPRTB
DB CR,LF,LF
DB 'Required send time exceeds the ',0
LD A,(TLOS) ; Get time left on system
LD H,0 ; Zero H
LD L,A ; Time left on system in L
CALL DECOUT ; Decimal output routine
CALL ERXIT ; Display following message and abort to CP/M
DB ' minutes allowed','$'
;
;-------------------------------------------------------------------------;
; L o g F i l e T r a n s f e r |
;-------------------------------------------------------------------------;
;
; Main log file routine, adds record to log file
;
LOGCALL:LD A,(LOGCAL) ; Logging file transfers?
OR A
RET Z ; No
CALL GTCURDU ; Get current drive/user in USRSAV and DSKSAV
LD HL,FCBCLR ; FCB to initialize
LD DE,LSTCLR ; Filename to insert
CALL RENFCB ; Initialize FCB
LD A,(LASTDRV)
SUB 'A'
LD (DEFDSK),A
LD A,(LASTUSR)
LD (DEFUSR),A
LD DE,FCBCLR
CALL OPENF ; Open LASTCALR file
JR NZ,LGCAL1
CALL ILPRT
DB CR,LF
DB '-- File not Found: LASTCALR.???'
DB CR,LF,0
RET ; Now go send EOT
LGCAL1: LD C,SETRRD ; Get random record #
LD DE,FCBCLR ; (for first record in file)
CALL BDOS
LD DE,DBUF ; Set DMA to DBUF
CALL STDMA
LD C,RRDM ; Read first (and only) record
LD DE,FCBCLR
CALL BDOS
LD HL,DBUF ; Set pointer to beginning of record
LD A,(CLOCK) ; Is there a clock installed?
OR A
JR Z,LGCAL2 ; No, skip this then
LD DE,0 ; Zero DE
LD A,(LCNAME) ; Offset to start of caller's name
LD E,A ; To E
ADD HL,DE ; HL now points to start of name
LGCAL2: LD (CLRPTR),HL
LD DE,LOGBUF ; Set DMA address to LOGBUF
CALL STDMA
LD HL,FCBLOG ; FCB to initialize
LD DE,LOGNAM ; Filename to insert
CALL RENFCB ; Initialize FCB
LD A,(LOGDRV)
SUB 'A'
LD (DEFDSK),A
LD A,(LOGUSR)
LD (DEFUSR),A
LD DE,FCBLOG
CALL OPENF ; Open log file
JR NZ,LGCAL5 ; If file exists, skip create
LD DE,FCBLOG
LD C,MAKE ; Create a new file if needed
CALL BDOS
INC A
JR NZ,LGCAL3 ; No error, continue
CALL ILPRT ; File create error
DB CR,LF
DB '-- Directory Full: ',0
LD HL,LOGNAM
CALL SHONM4
RET ; Go back and send EOT
LGCAL3: LD DE,LOGBUF ; Set DMA back to LOGBUF
CALL STDMA
LD C,SETRRD ; Set random record #
LD DE,FCBLOG ; (for first record in file)
CALL BDOS
LGCAL4: LD A,EOF
LD (LOGBUF),A
JR LGCAL6
LGCAL5: LD DE,LOGBUF ; Set DMA to LOGBUF
CALL STDMA
LD C,FILSIZ ; Get file length
LD DE,FCBLOG
CALL BDOS
LD HL,(FCBLOG+33) ; Back up to last record
LD A,L
OR H
JR Z,LGCAL4 ; Unless zero length file
DEC HL
LD (FCBLOG+33),HL
LD DE,FCBLOG
LD C,RRDM ; And read it
CALL BDOS
LGCAL6: CALL RSTLP ; Initialize LOGPTR and LOGCNT
LGCAL7: LD A,(LOGCNT)
INC A
LD (LOGCNT),A
CP 129
JR NZ,LGCAL8
LD HL,(FCBLOG+33)
INC HL
LD (FCBLOG+33),HL
LD HL,LOGBUF+1
LD (LOGPTR),HL
LD A,1
LD (LOGCNT),A
LD A,EOF
JR LGCAL8A
LGCAL8: LD HL,(LOGPTR)
LD A,(HL)
INC HL
LD (LOGPTR),HL
LGCAL8A:CP EOF
JR NZ,LGCAL7 ; Until EOF
LD A,(LOGCNT) ; Then backup one character
DEC A
LD (LOGCNT),A
LD HL,(LOGPTR)
DEC HL
LD (LOGPTR),HL
;
; Print file transfer mode to LOG file (R, S, P, A, L)
;
LD A,(PUPFLG)
OR A ; Privileged upload option request?
JR Z,LGCAL8B ; No, skip next 2 lines
LD A,'P' ; Else,
JR LGCAL9 ; Show as private upload for log file
LGCAL8B:LD A,(PRIVATE)
OR A
JR NZ,LGCAL9
LD A,(MODE) ; Get transfer mode back and put in file
LGCAL9: CALL PUTLOG
;
; Print baud rate to LOG file
;
CALL GETSPD ; Get speed factor
ADD A,30H
CALL PUTLOG
CALL PUTSP ; Blank
;
; Print program size (in minutes and seconds) to LOG file
;
LD A,(PGSIZE) ; Now the program size in minutes..
CALL PNDEC ; Of transfer time (mins)
LD A,':'
CALL PUTLOG ; ':'
LD A,(PGSIZE+2)
CALL PNDEC ; And seconds
CALL PUTSP ; Blank
;
; Log the drive and user area as a prompt
;
LD A,(FCB)
OR A
JR NZ,WDRV
LD A,(DSKSAV)
INC A
WDRV: ADD A,'A'-1
CALL PUTLOG
LD A,(USRSAV)
CALL PNDEC
LD A,'>' ; Make it look like a prompt
CALL PUTLOG
LD A,(LBRARC)
OR A ; Member extraction?
JR Z,WDRV1 ; No, won't be member name
LD HL,MEMFCB ; Name of file in library
LD B,11
CALL PUTSTR
CALL PUTSP ; ' '
;
; Put filename in LOG file
;
WDRV1: LD HL,FCB+1 ; Now the name of the file
LD B,11
CALL PUTSTR
LD A,(LBRARC)
OR A ; Member extraction?
JR Z,WDRV2 ; No, won't be member name
LD C,1
JR SPLOOP
WDRV2: LD C,13
SPLOOP: PUSH BC
CALL PUTSP ; Put ' '
POP BC
DEC C
JR NZ,SPLOOP
;
; Print number of 'k' to LOG file
;
LD HL,(RECDNO) ; Get record count
CALL DIVREC ; Divide record count by 8
EXKB2: CALL PNDEC3 ; Print to log file (right just xxxk)
LD HL,LOGK ; 'k '
LD B,2
CALL PUTSTR
XOR A
LD (COMMA),A ; Reset field counter
;
; Print date and time of transfer to LOG file
;
LD A,(CLOCK) ; Clock available in BYE?
OR A
JR NZ,EXKB3 ; Yes, continue
LD A,(RTC) ; Else how about an RTC overlay?
OR A
JR Z,CLOOP ; Nope, foget date and time
EXKB3: CALL GETTIME ; Get CURRENT time for log
LD A,(EDATE) ; European date format?
OR A
JR Z,EXKB4 ; No
LD A,(DAY)
CALL PNDEC ; Print DD
LD A,'/' ; '/'
CALL PUTLOG
LD A,(MONTH)
CALL PNDEC ; Print MM
JR EXKB5
EXKB4: LD A,(MONTH)
CALL PNDEC ; Print MM
LD A,'/' ; '/'
CALL PUTLOG
LD A,(DAY)
CALL PNDEC ; Print DD
EXKB5: LD A,'/' ; '/'
CALL PUTLOG
LD A,(YEAR)
CALL PNDEC ; Print YY
CALL PUTSP ; ' '
LD A,(HOUR) ; Get current hour
CALL PNDEC ; Print hr to file
LD A,':' ; With ':'
CALL PUTLOG ; Between HH:MM
LD A,(MINUTE) ; Get min
CALL PNDEC ; And print min
CALL PUTSP ; Print a space
;
; Print name of caller to LOG file
;
CLOOP: LD HL,(CLRPTR)
LD A,(HL)
INC HL
LD (CLRPTR),HL
CP EOF ; End of file?
JR Z,QUIT ; Yes
CP CR ; Do not print 2nd line of 'LASTCALR'
JR NZ,CLOP1
CEND: CALL PUTLOG
LD A,LF
CALL PUTLOG ; And add a LF
JR QUIT
CLOP1: CP ' ' ; Space?
JR NZ,CLOP1A ; No, check for comma
LD A,',' ; Convert space to comma for field checking
CLOP1A: CP ',' ; Comma?
JR NZ,CLOP2
LD A,(COMMA)
CP 1 ; Is this the second comma or space?
JR NZ,CLOP1B ; No, bump the counter
LD A,CR
JR CEND ; Yes, stop taking data from lastcalr
CLOP1B: INC A ; Bump it one
LD (COMMA),A
LD A,' ' ; Instead send a ' '
CLOP2: CALL PUTLOG
JR CLOOP
QUIT: LD A,EOF ; Put in EOF
CALL PUTLOG
LD A,(LOGCNT) ; Check count of chars in buffer
CP 1
JR NZ,QUIT ; Fill last buffer & write it
LD DE,FCBCLR ; Close lastcaller file
LD C,CLOSE
CALL BDOS
INC A
JR Z,QUIT1
LD HL,(FCBLOG+33) ; Move pointer back to show
DEC HL ; Actual file size
LD (FCBLOG+33),HL
LD DE,FCBLOG ; Close log file
LD C,CLOSE
CALL BDOS
INC A
RET NZ ; If OK, return now...
QUIT1: CALL ILPRT ; If error, oops
DB CR,LF
DB '-- Close Error: ',0
LD HL,LOGNAM
CALL SHONM4
RET ; Go back and send EOT
;
;-------------------------
; LOGCAL Support Routines
;
; Open file with FCB pointed to by DE (disk/user passed in DEFDSK and DEFUSR)
;
OPENF: PUSH DE ; Save FCB address
LD A,(DEFDSK) ; Get disk for file
CALL RECDRX ; Log into it
LD A,(DEFUSR) ; Get default user
CALL RECAR1 ; Log into it
POP DE ; Get FCB address
LD A,(CPM3) ; Using with CPM3?
OR A
JR Z,OPENF1 ; No
PUSH DE ; Save FCB address
CALL RSDMA ; Set DMA to 80H
POP DE ; Get back pointer to FCB
PUSH DE ; Save FCB pointer again
LD C,SRCHF ; Search for first match
CALL BDOS
INC A ; Did file match?
POP DE
RET Z ; No, return
PUSH DE
DEC A ; A=directory code (0-3)
ADD A,A ; *2
ADD A,A ; *4
ADD A,A ; *8
ADD A,A ; *16
ADD A,A ; *32
LD E,A
LD D,0
LD HL,TBUF ; Add (32*dir code) to default DMA
ADD HL,DE ; to find first match filename
POP DE ; DE=FCB
PUSH DE ; Save DE again
INC HL ; Move HL past user # byte in buffer
INC DE ; Move DE past drive # byte in FCB
LD BC,11
LDIR ; Move name found to FCB
POP DE ; And continue with open
OPENF1: LD C,OPEN ; Open file
CALL BDOS
CP 0FFH ; Not present?
RET ; Return to caller
;
; Write character to log file
;
PUTLOG: LD HL,(LOGPTR) ; Get pointer
AND 7FH ; Strip any attributes
LD (HL),A ; Put data
INC HL ; Increment pointer
LD (LOGPTR),HL ; Update pointer
LD B,A ; Save character in B
LD A,(LOGCNT) ; Get count
INC A ; Increment it
LD (LOGCNT),A ; Update count
CP 129 ; Check it
RET NZ ; If not EOB, return
PUSH BC ; Save character
LD DE,FCBLOG ; Else, write this sector
LD C,WRDM
CALL BDOS
OR A
JR Z,ADVRCP ; If ok, cont.
CALL ILPRT
DB CR,LF
DB '-- Disk Full: ',0
LD HL,LOGNAM
CALL SHONM4
RET
ADVRCP: LD HL,(FCBLOG+33) ; Advance record number
INC HL
LD (FCBLOG+33),HL
CALL RSTLP ; Reset buffer pointers
POP AF ; Get saved character
JP PUTLOG ; Put it in buffer and return
RSTLP: LD HL,LOGBUF ; Reset pointers
LD (LOGPTR),HL ; And return
LD A,0
LD (LOGCNT),A
RET
;
; Print number in decimal format (into log file) IN: HL=binary number
; OUT: nnn=right justified with spaces
;
PNDEC3: LD A,H ; Check high byte
OR A
JR NZ,DECOT ; If on, is at least 3 digits
LD A,L ; Else, check low byte
CP 100
JR NC,TEN
CALL PUTSP
TEN: CP 10
JR NC,DECOT
CALL PUTSP
JR DECOT
;
; Print number in decimal format (into log file)
;
PNDEC: CP 10 ; Two column decimal format routine
JR C,ONE ; One or two digits to area number?
JR TWO
ONE: PUSH AF
LD A,'0'
CALL PUTLOG
POP AF
TWO: LD H,0
LD L,A
DECOT: PUSH BC
PUSH DE
PUSH HL
LD BC,-10
LD DE,-1
DECOT2: ADD HL,BC
INC DE
JR C,DECOT2
LD BC,10
ADD HL,BC
EX DE,HL
LD A,H
OR L
CALL NZ,DECOT
LD A,E
DECOT3: ADD A,'0'
CALL PUTLOG
DECOT4: POP HL
POP DE
POP BC
RET
;
; Put string to log file
;
PUTSTR: LD A,(HL)
PUSH HL
PUSH BC
CALL PUTLOG
POP BC
POP HL
INC HL
DJNZ PUTSTR
RET
;
; Puts a single space in log file, saves PSW/HL
;
PUTSP: PUSH AF
PUSH HL
LD A,' '
CALL PUTLOG
POP HL
POP AF
RET
;
;-------------------------------------------------------------------------;
; T I M E & D A T E R o u t i n e s |
;-------------------------------------------------------------------------;
;
; Get RTCBUF address if running BYE
;
TIME: LD A,(CLOCK) ; Clock in BYE?
OR A
JR Z,TIME1 ; No
LD DE,25 ; Offset to RTCBUF address
CALL GETOFF ; Point to JP COLDBOOT + offset in DE
LD E,(HL) ; HL points to RTCBUF address
INC HL ; To most significant byte of address
LD D,(HL)
EX DE,HL ; Back to HL
LD (RTCBUF),HL ; Save for later use
CALL GETTIME ; Store RTCBUF contents internally
LD HL,(RTCBUF) ; Get RTC buffer address
LD DE,7 ; Offset to time on system (TOS) word
ADD HL,DE ; Address in HL
LD A,(HL) ; Get minutes on system
LD (TON),A ; Store time on system for SHOWTOS
;
; Get MAXTOS if restricting downloads to time left
;
LD A,(TIMEON) ; Policing time on system?
OR A
JP Z,SHOWTOS ; No
LD DE,24 ; Offset to maximum time allowed
CALL GETOFF ; Point to JP COLDBOOT + offset in D
LD A,(MODE) ; Exiting? (Gets set NZ in exit routine)
OR A
JR Z,TIME0 ; No, skip next
LD A,(MAXTOS) ; Reset maximum time allowed
LD (HL),A
JR TIME0A
TIME0: LD A,(HL) ; Get maximum time allowed
LD (MAXTOS),A ; Store it
LD (HL),0 ; Disable BYE from checking time for now
TIME0A: LD A,(TON)
LD B,A ; Save time on system for comparison
LD A,(MAXTOS) ; Get maximum time allowed
SUB B ; Get time left on system
LD (TLOS),A ; Store time left on system
JP SHOWTOS ; Go show TON
;
; Get TON if RTC
;
TIME1: LD A,(RTC) ; Clock reader code installed in ZMD?
OR A
JP Z,SHOWTOS ; No
CALL GETTIME
LD HL,(LHOUR) ; Get address to logon hour
LD A,(HOUR)
CP (HL) ; Same as current hour?
INC HL ; Point to logon minute
LD D,(HL) ; Get it in D
JR NZ,TIME2 ; No, not the same
LD A,(MINUTE) ; Else get current minute
SUB D ; Subtract logon minute
LD (TON),A ; Store it as time on system
JR TIME3 ; Get maximum allowed
TIME2: LD A,60 ; Fake an hour
SUB D ; Subtract logon minute
LD HL,MINUTE ; Point to current minute
ADD A,(HL) ; Add them
LD (TON),A ; Store as current time on system
;
; Get MAXTOS if TIMEON
;
TIME3: LD A,(TIMEON) ; Restricting downloads to time left?
OR A
JR Z,SHOWTOS ; No
CALL WHLCHK ; WHEEL byte set?
JR NZ,SHOWTOS ; Yes, just display time on system
LD A,(MODE) ; Else been here before?
OR A
JR NZ,TIME4 ; Yes (MODE is 0 first time through)
LD A,(MAXMIN)
LD (MAXTOS),A ; Else set maximum time allowed
LD (TLOS),A ; And current time left on system
TIME4: LD A,(MAXTOS) ; Get current maximum time allowed
OR A ; Unlimited?
JR Z,SHOWTOS ; Yes, just display time on system
LD A,(MAXMIN) ; Else get original maximum minutes allowed
LD B,A ; Into B
LD A,(TON) ; Get current time on system
SUB B ; Time up?
JR C,SHOWTOS ; No, just display time on system
CALL ILPRTB
DB CR,LF,LF
DB '-- Your time is up, please share the system with others'
DB CR,LF,0
POP HL
LD A,0CDH
LD (0),A
JP 0
;
; Display the time on system
;
SHOWTOS:LD A,(DSPTOS) ; Display time on system message?
OR A
RET Z ; No, all done
LD A,(MODE) ; Else exiting?
OR A
JR Z,SHOTOS1 ; Yes, no line feed
CALL ILPRTB
DB CR,LF,0
SHOTOS1:CALL ILPRTB
DB 'Online ',0
LD A,(TON) ; Get time on system
LD H,0 ; Zero H
LD L,A ; TON in L
CALL DECOUT ; Decimal output
CALL ILPRTB
DB ' minute',0
LD A,(TON) ; Get time on system
CP 1 ; 1?
JR Z,SHOTOS2 ; Yes, leave display as 'minute'
CALL ILPRTB
DB 's',0 ; Else make it plural
SHOTOS2:LD A,(MODE)
OR A
RET NZ
CALL ILPRT
DB CR,LF,0
RET
;
; Transfer BYE's RTCBUF contents to internal storage
;
GETTIME:LD A,(RTC) ; User installed clock routines?
OR A
JP NZ,RTCTIM ; Yes, go do it
LD HL,(RTCBUF)
LD A,(HL) ; 00:
CALL BCDBIN ; Convert to binary
LD (HOUR),A ; Save
CALL GETTIM3 ; :00
LD (MINUTE),A ; Save
INC HL ; Skip seconds
INC HL ; Skip '19'nn
CALL GETTIM3 ; YY
LD (YEAR),A ; Save
CALL GETTIM3 ; MM
LD (MONTH),A ; Save
CALL GETTIM3 ; DD
LD (DAY),A ; Save
RET ; And return
GETTIM3:INC HL ; Increment to next RTC byte value
LD A,(HL) ; Get it
JP BCDBIN ; Return with binary value in A
;
; Add the time of the last upload/download to BYE's time on system byte
;
ADDTON: LD A,(TIMEON) ; Using TIMEON?
OR A
RET Z
CALL BYECHK ; If so, see if BYE is running
OR A ; 0 if no clock, or 0 if no BYE.
LD HL,TON ; Prepare for internal RTC
JR Z,ADDTN1
LD HL,(RTCBUF) ; Get RTC buffer address
LD DE,7 ; Get offset to TOS word
ADD HL,DE ; Add offset, HL contains TON address
ADDTN1: PUSH HL ; Save it
LD HL,(RECDNO)
LD (RCNT),HL
CALL XTIM ; Calculate transfer time
POP HL ; Restore TON address
LD A,(HL) ; Get time on in A
LD B,A ; Save it
LD A,(MODE) ; Get current transfer mode
CP 'S' ; Is this a download?
JR Z,ADDTN2 ; Yes, subtract download time
LD A,(CREDIT) ; Else crediting upload time?
OR A
RET Z ; No, skip this
LD A,B ; Else get time on system back
SUB C ; Subtract upload time
LD (HL),A ; Store it
RET
ADDTN2: LD A,B
INC A ; Bump it one
ADD A,C ; Add transfer time
LD (HL),A ; Put it back for BYE
RET
;
;-------------------------------------------------------------------------;
; A v a i l a b l e U p l o a d S p a c e |
;-------------------------------------------------------------------------;
;
; This routine is called with the 'F' option from both CP/M (with 'ZMD F')
; or from The HELP Guide routines. First determine where uploads are
; suppose to go.
;
SPACE: CALL RSTLCK ; Go reset WRTLOC if needed
CALL WHLCHK ; WHEEL byte set?
JR NZ,SPACE1 ; Yes, give space for current drive/user
LD A,(ASKAREA)
OR A
JR NZ,SPACE2
LD A,(SETAREA)
OR A
JR NZ,SPACE2 ; Yes
SPACE1: LD A,(OLDDRV) ; Get currently logged drive
ADD A,'A' ; Make it ASCII
LD (DRV),A
LD (KDRV),A ; Store it for KSHOW
LD A,(OLDUSR) ; Get currently logged user
LD (USR),A ; Store it for KSHOW
SPACE2: CALL WHLCHK
CALL Z,GETKIND ; Get upload area if ASKAREA
CALL ILPRTB
DB CR
DB ' Regular ',0
CALL SPACE8
CALL ILPRTB
DB CR,LF
DB ' Private ',0
LD A,1
LD (PRVSPC),A
CALL SPACE8
JP EXIT ; Exit to CP/M
;
; Displays the file descriptor/category when showing available upload space.
;
SPACE8: CALL WHLCHK
CALL Z,SHOCAT ; Show upload area descriptor, if supposed to
CALL ILPRTB
DB 'uploads received on ',0
LD A,(PRVSPC) ; Want private area space?
OR A
JR NZ,SPACE9 ; Yes, do private stuff
LD A,(DRV) ; Get drive to receive regular upload
LD (KDRV),A ; Store it for KSHOW
CALL TYPE ; Output to modem
LD A,(USR) ; Get user area to receive regular upload
JR SPACE10 ; Go show free space
SPACE9: LD A,(PRDRV) ; Get drive to receive private upload
LD (KDRV),A ; Store it for KSHOW
CALL TYPE ; Output to modem
LD A,(PRUSR) ; Get user area to receive private upload
SPACE10:LD H,0
LD L,A ; User area in L
CALL DECOUT ; Decimal output
CALL ILPRTB
DB ':',0
LD A,(PRVSPC) ; Getting private info?
OR A
JR Z,SPACE11 ; No
LD A,(DRV) ; Else get regular drive
LD HL,PRDRV ; Point to private drive
CP (HL) ; Private same as regular drive?
RET Z ; Yes, don't report 'k' this time
SPACE11:CALL ILPRTB
DB ' (',0
LD A,(KDRV) ; Get upload drive
CALL KSHOW ; Show available space for drive
CALL ILPRTB
DB ')',0
RET
;
;-------------------------------------------------------------------------;
; R u n t i m e H e l p G u i d e |
;-------------------------------------------------------------------------;
;
; Either 'ZMD' was entered by itself from CP/M, or an invalid option
; given.
;
HELP: CALL ILPRTB
DB CR,LF,' mode drive/user'
DB CR,LF,' / /'
DB CR,LF,'Usage: ZMD SK {du:} <fn>'
DB CR,LF,' / /'
DB CR,LF,' protocol filename'
DB CR,LF
DB CR,LF,'Mode: Protocol:'
DB CR,LF,' S - Send file from BBS '
DB 'X - Xmodem 128 byte blocks (CRC)'
DB CR,LF,' SP - Send from private area '
DB 'C - Xmodem 128 byte blocks (Checksum)'
DB CR,LF,' A - Send ARK/ARC/LBR member '
DB 'K - Ymodem 1024 byte blocks (CRC only)'
DB CR,LF,' R - Receive file from YOU'
DB CR,LF,' RP - Receive in private area',0
CALL ILPRTB
DB CR,LF,0
LD A,(MSGFIL)
OR A
JR Z,HELP1
CALL ILPRTB
DB ' RM - Receive preformatted message base upload',0
HELP1: CALL ILPRTB
DB CR,LF,0
CALL WHLCHK
JR Z,HELP2
CALL ILPRTB
DB ' RW - Receive without description(s)',0
HELP2: CALL ILPRTB
DB CR,LF,' F - Displays available upload space'
DB CR,LF
DB CR,LF
DB CR,LF
DB '--SPACE BAR displays specific examples--',0
CALL INPUT
CP ' '
JP NZ,EXIT
LD HL,ZMDNAM
CALL PRINTV
CALL ILPRTB
DB 'Usage examples:'
DB CR,LF
DB CR,LF,' ZMD S filename.ext '
DB 'Send single file (Automatic detect)'
DB CR,LF,' ZMD S B4:filename.ext '
DB 'Send single file (Automatic detect)'
DB CR,LF,' ZMD SK filename.ext '
DB 'Send single file (Ymodem 1k)'
DB CR,LF,' ZMD S filename.* '
DB 'Send from current d/u (Ymodem 1k Batch)'
DB CR,LF,' ZMD S D1:*.* B9:*.doc '
DB 'Send from multiple d/u (Ymodem 1k Batch)'
DB CR,LF,' ZMD A librnam lbrmber.ext '
DB 'Send ARK/ARC/LBR member (Automatic detect)'
DB CR,LF,' ZMD AK librnam lbrmber.ext '
DB 'Send ARK/ARC/LBR member (Ymodem 1k)'
DB CR,LF
DB CR,LF,' ZMD R filename.ext '
DB 'Receive single file (Automatic detect)'
DB CR,LF,' ZMD R '
DB 'Receive multiple files (Ymodem 1k Batch)'
DB CR,LF,' ZMD RPC filename.ext '
DB 'Receive to private area (Checksum)'
DB CR,LF,LF
DB 'Protocol may be omitted for automatic protocol detection.'
DB CR,LF
DB 'Ymodem 1k Batch is enabled upon detection of wildcards or'
DB ' multiple'
DB CR,LF
DB ' filenames on command line (can also be forced with'
DB ' ''SB'' mode).',0
JP EXIT
ABRTMSG:CALL ILPRTB
DB CR
DB '-- ZMD Aborted',0
RET
NOACC: CALL SENDBEL ; Send a bell out modem only
CALL ERXIT
DB CR,LF
DB '-- Restricted Function - Access Denied','$'
ZEROLN: CALL ERXIT
DB CR,LF
DB '-- File empty - ZMD aborted','$'
NOFILE: CALL ERXIT
DB CR
DB '-- No matching filename(s) found','$'
NOIO: XOR A
LD (RTC),A
LD (TIMEON),A
LD (DSPTOS),A
LD (CLOCK),A
CALL ERXIT
DB BELL
DB '-- Modem I/O unavailable - Aborting','$'
TOOSLOW:CALL ERXIT
DB CR,LF,LF
DB '-- YMODEM 1k/BATCH not valid - Modem speed too slow','$'
TOTMSG: CALL ILPRTL
DB ' - Timeout, no character received',CR,LF,0
RET
DLRDY: CALL ILPRT
DB CR,LF
DB 'Your file(s) now ready to download',0
CALL CONT6
RET
WAITMSG:CALL ILPRTL
DB ' -- Waiting --'
DB CR,0
RET
;
;-------------------------------
; File type restriction storage
;-------------------------------
;
; Don't allow ___ (If ZCPR is YES)
; \
SYSCHK: DB 'SYS'
NDRCHK: DB 'NDR'
RCPCHK: DB 'RCP'
;
; If receiving __ change it to __ (If NOCOMR is YES)
; \ \
COMCHG: DB 'COM', 'OBJ'
PRLCHG: DB 'PRL', 'OBP'
;
; If the library extraction flag (LBRARC) is set and an unsuccessful open with
; the default filetype occurs, the following file types are copied to FCB+9
; and the open attempt is repeated.
;
ARCNAM: DB 'ARC' ; Copied to FCB+9
LBRNAM: DB 'LBR' ; Copied to FCB+9
ARKNAM: DB 'ARK' ; Copied to FCB+9
;
;---------------------
; LOGCALL allocations
;---------------------
;
DEFDSK: DB 0 ; Disk for open stored here
DEFUSR: DB 0 ; User for open stored here
CLRPTR: DW LOGBUF
LOGPTR: DW DBUF
LOGCNT: DB 0
LOGK: DB 'k '
DUSAVE: DB 0,0,0,0 ; Buffer for drive/user
;
;------------------
; Time allocations
;------------------
;
MAXTOS: DB 0 ; Maximum time left on system
RTCBUF: DW 0 ; RTCBUF address
TLOS: DB 0 ; Current time left on system
TON: DB 0 ; Current time on system
;
XTABLE: DW 5, 13, 19, 25, 30, 48, 85, 141, 210, 280, 0
KTABLE: DW 5, 14, 21, 27, 32, 53, 101, 190, 330, 525, 0
XECTBL: DB 192, 74, 51, 38, 32, 20, 11, 8, 5, 3, 0
KECTBL: DB 192, 69, 46, 36, 30, 18, 10, 5, 3, 2, 0
;
;--------------------
; Batch mode storage
;--------------------
;
BGNMS: DW 0 ; Start address of filenames in TBUFF
LIST: DW DBUF ; Filename storage in send batch mode
LISTPOS:DW 0 ; Next position to store matching filename
LISTEND:DW 0 ; Address of last matching filename
LISTI: DW 0 ; Pointer 1 for two-dimensional bubble sort
LISTJ: DW 0 ; Pointer 2 for two-dimensional bubble sort
FILEK: DW 0 ; Total kilobytes of files found (send batch)
FCBBUF: DS 21 ; Batch filename from command line
FSTFLG: DB 0 ; Set to 1 when command line scan done
NAMECT: DB 0 ; # of names on command line
NBSAVE: DW 0 ; Start address in NAMBUF for next file
SBSHOW: DB 0 ; Set shows partial stat display in batch
SHOCNT: DB 0 ; Counter to show files left
TOTREC: DW 0 ; Total records to be sent
;
;------------------------
; Temporary storage area
;------------------------
;
ACKCHK: DB 0 ; Lets batch header user GTACK routine
AFBYTE: DB 0 ; Access flags byte storage
CHKEOT: DB 0 ; Prevents locking up after an EOT
COMMA: DB 0 ; Field counter for logcal
CRCFLG: DB 1 ; For sending checksum rather than CRC
EOFLG: DB 0 ; EOF (End of file) flag
EOTFLG: DB 0 ; EOT (End of transmission) status flag
ERRCNT: DB 0 ; Error count
FRSTIM: DB 0 ; Turned on after first 'SOH' received
GOTONE: DB 0 ; Prevents asking for a description
KFLG: DB 1 ; For sending 1k blocks (Defaults to 1k)
PRVSPC: DB 0 ; Shows in private display in SPACE: if set
RCVCNT: DB 0 ; Record number received
RCVTRY: DB 0 ; Keeps track of number of attempts
RCVDRV: DB 0 ; Requested drive number
RCVUSR: DB 0 ; Requested user number
ACCERR: DW 0 ; No 'ACK' error count for 1k ratio
HDRADR: DW 0 ; Current location in batch header block
RCNT: DW 0 ; Record count
RECDNO: DW 0 ; Current record number
RCDCNT: DW 0 ; Used in sending the record header
RECPTR: DW DBUF
RECNBF: DW 0 ; Number of records in the buffer
SAVEHL: DW 0 ; Saves TBUF command line address
XFRMIN: DW 0 ; Transfer time in mins for TIMEON
;
END ; 'Almost'...