home *** CD-ROM | disk | FTP | other *** search
- ;
- ; TITLE 'XMODEM ver. 12.5 - 07/13/86'
- ;
- ; XMDM125.ASM - REMOTE CP/M FILE TRANSFER PROGRAM
- ;
- ; Originally adapted from Ward Christensen's MODEM2
- ; by Keith Petersen, W8SDZ
- ;
- ; ASEG ;Needed by M80 assemblers, comment out if using MAC
- ;
- ; This program allows a remote user to transfer files (to or from) RCPM
- ; systems running under BYE (remote console program). It can be assem-
- ; bled with ASM, LASM, MAC, M80, SRLMAC and other 8080 assemblers.
- ;
- ; All comments and past revisions have been removed from this file and
- ; put into the XMODEM.UPD file. Place only the current revision at the
- ; beginning of this file and move the one that was here to XMODEM.UPD.
- ;
- ;=======================================================================
- ;
- ; v12.5 Fixed conditional assembly bug which caused date to
- ; 07/13/86 appear in log twice when MBBS and BYEBDOS were both set
- ; to YES.
- ; Fixed conditional assembly bug which did not allow MBFMSG
- ; to be set to YES while MBDESC was set to NO.
- ; Removed patch to log download before sending EOF because
- ; EOF would not be sent, leaving caller's program in file
- ; transfer mode, if LOGCALL routine exited with an error.
- ; This problem was noticed by Keith Petersen.
- ; Modified to abort any download which would result in a
- ; user exceeding his time limit when BYEBDOS is YES.
- ; Fixed bug which would cause caller to be logged off
- ; without updating log file if transmission errors caused
- ; his download to put him over time limit when BYEBDOS was
- ; YES and CLOCK and TIMEON in BYE were YES (call to TCHECK
- ; in BYE's extended BDOS call would hang up on caller).
- ; Revised comments for some equates to make them easier to
- ; understand.
- ; - Murray Simsolo
- ;
- ;========================================================================
- ;
- VERSION EQU 1
- INTERM EQU 2
- MODLEV EQU 5
- VMONTH EQU 07
- VDAY EQU 13
- VYEAR EQU 86
- ;
- NO EQU 0
- YES EQU NOT NO
- ;
- ; Define ASCII characters used
- ;
- BS EQU 08H ; Backspace character
- ACK EQU 06H ; Acknowledge
- CAN EQU 18H ; CTL-X for cancel
- CR EQU 0DH ; Carriage return
- CRC EQU 'C' ; CRC request character
- EOF EQU 1AH ; End of file - ^Z
- EOT EQU 04H ; End of transmission
- LF EQU 0AH ; Line feed
- NAK EQU 15H ; Negative acknowledge
- RLEN EQU 128 ; Record length
- TAB EQU 09H ; Horizontal tab
- SOH EQU 01H ; Start of header for 128-byte blocks
- STX EQU 02H ; 'Start of header' for 1024 byte blocks
- ;
- ;=======================================================================
- ;
- ; Conditional equates - change to suit your system, then assemble
- ;
- MHZ EQU 4 ; Clock speed, use integer (2,4,5,8, etc.)
- CPM3 EQU NO ; Yes, if operating in CP/M v3.0 environment
- STOPBIT EQU NO ; No, if using 1 stop bit, yes if using 2
- BYEBDOS EQU NO ; Yes, if using BYE338-up, BYE501-up, or NUBYE
- ; with its I/O (CLOCK in BYE must be YES)
- ; No if using your own hardware overlay
- LUXMOD EQU NO ; Set to YES if LUXMODEM version desired rather
- ; than standard XMODEM with upload options.
- ;
- ;=======================================================================
- ;
- ; If OK2400 is YES, then it overrides the TAGLBR and MAXMIN restrictions
- ; if the current caller is operating at 2400 baud (or higher).
- ;
- OK2400 EQU NO ; Yes, no restrictions for 2400 bps callers
- ;
- MSPEED EQU 3CH ; Location of speed byte set by BYE prgm, must
- ; be set for OK2400 or BYEBDOS to work
- ;
- DSPFNAM EQU YES ; Set to YES if you wish XMODEM to display the
- ; file name being up or downloaded for user to
- ; see and verify system received name correctly.
- ;
- ; If ZCPR3 is YES, then NO filetypes of .NDR or .RCP will be received.
- ; This is for security if you need LDR.COM on A0: for cold starts or if
- ; LDR is in the defined path. (If you don't have LDR on-line or
- ; accessible, then this equate isn't necessary for ZCPR3 systems.)
- ;
- ZCPR3 EQU NO ; Yes, NO filetypes .NDR or .RCP received
- ;
- ;=======================================================================
- ;
- ; If ZCPR2 = yes, then the following will all be NO if wheel is set
- ; in local non-zero (0FFH) mode. SYSOP rules...
- ;
- ZCPR2 EQU NO ; Yes, if using ZCPR* with WHEEL byte
- ;
- WHEEL EQU 3EH ; Location of wheel byte (normally 3EH)
- NOCOMR EQU YES ; Yes, change .COM to .OBJ on receive
- NOCOMS EQU YES ; Yes, .COM files not sent
- NOLBS EQU NO ; Yes, .??# files not sent
- NOSYS EQU YES ; Yes, no $SYS files sent or reported
- ;
- ;=======================================================================
- ;
- ; The following are only used by NZCPR or ZCMD systems
- ;
- USEMAX EQU NO ; Yes, using NZCPR for maximum du: values
- ; No, use MAXDRV and MAXUSR specified next
- DRIVMAX EQU 03DH ; Location of MAXDRIV byte
- USRMAX EQU 03FH ; Location of MAXUSER byte
- ;
- ;=======================================================================
- ;
- ; Hard-coded system maximums allowed if USEMAX above is NO
- ;
- MAXDRV EQU 4 ; Number of disk drives used (1=A, 2=B, etc)
- MAXUSR EQU 5 ; Maximum 'SEND' user allowed
- ;
- ;=======================================================================
- ;
- ; File transfer buffer size - 16k is the same buffer length used in IMP,
- ; MDM7 and MEX so all those modem programs as well as XMODEM would be
- ; transferring from the buffer simultaneously, minimizing any delays.
- ; Slower floppy disk drives may require the use of a smaller buffer, try
- ; 8k, 4k, or 2k and use largest that does not result in a time-out at
- ; the sending end. Please note the requirement for the protocol to ac-
- ; cept any mixture of 1K and small blocks may result in effective buffer
- ; usage extending an additional 896 bytes (7*128) beyond the 'end' of
- ; the buffer defined here. (Actually, due to handshaking, the buffers
- ; are NOT loaded simultaneously, so the above statement is misleading,
- ; too large a buffer will slow things down if you have a slow disk
- ; drive.. Too small a buffer will really slow you down though, so
- ; stick with 16k...)
- ;
- BUFSIZ EQU 16 ; File transfer buffer size in Kbytes (16k)
- ;
- ;=======================================================================
- ;
- ; DESCRIB is used to ask the uploader to give a description of the file
- ; he just uploaded. If YES and ZCPR2 is YES and wheel is set, it does
- ; NOT ask for a description unless ASKSYS is set to YES.
- ; (If using on an MBBS v4.1 and up system, use MBDESC instead of
- ; this option.) (NDESC can be used with either DESCRIB or MBDESC.)
- ;
- DESCRIB EQU NO ; Yes asks for a description of uploaded file
- DRIVE EQU 'A' ; Drive area for description of upload
- USER EQU 14 ; User area for description of upload
- BSIZE EQU 32*1024 ; Set for 16k, 24k or 32k as desired for DESCRIB
- ;
- NDESC EQU NO ; If YES, user can add a "N" to option to skip
- ; description for pre-arranged uploads or
- ; for the sysop..
- ASKSYS EQU NO ; If YES, and ZCPR2=YES, the system will ask
- ; the sysop for a description of the uploaded
- ; file
- ASKIND EQU NO ; IF YES, user is asked for the category of
- ; the uploaded file. This category is auto-
- ; matically added to the file description.
- ;
- ;=======================================================================
- ;
- ; XMODEM transfer log options
- ;
- LOGCAL EQU YES ; Yes, logs XMODEM transfers
- LOGDRV EQU 'A' ; Drive to place 'XMODEM.LOG' file
- LOGUSR EQU 14 ; User area to put 'XMODEM.LOG' file
- ;
- ; OxGate BBS puts the date after the caller's name. If you are using
- ; either BYEBDOS or B3RTC or RTC, and have an OxGate, then set this
- ; equate to YES, so the date doesn't appear twice.
- ;
- OXGATE EQU NO ; If yes, and B3RTC or RTC is yes, does not read
- ; date in OxGate's LASTCALR file.
- ;
- KNET EQU NO ; If yes, the log file is called XMODEM.TX# with
- ; $SYS attr set (for K-NET 84(tm) RCP/M Systems)
- ;
- LASTDRV EQU 'A' ; Drive to read 'LASTCALR' file from
- LASTUSR EQU 14 ; User area of 'LASTCALR' file, if 'LOGCAL' yes
- ;
- ;=======================================================================
- ;
- ; The receiving station sends an 'ACK' for each valid sector received.
- ; It sends a 'NAK' for each sector incorrectly received. In poor con-
- ; ditions either may be garbled. Waiting for a valid 'NAK' can slow
- ; things down somewhat, giving more time for the interference to quit.
- ;
- RETRY EQU NO ; Yes requires a valid NAK to resend a record
- ; No resends a record after any non-ACK
- ;
- ; Note that some modem programs will send a "C" instead of a NAK when
- ; operating in CRC mode. Therefore, RETRY EQU NO will allow XMODEM to
- ; work correctly with more programs.
- ;
- ;=======================================================================
- ;
- ; When sending in 1K block mode, XMODEM will downshift to 128 byte
- ; blocks when the ratio of successfully transmitted blocks to total
- ; errors falls below the ratio defined here.
- ;
- DWNSHFT EQU 5 ; must have at least this many good blocks for
- ; every error, or will downshift to size 128
- ;
- MINKSP EQU 5 ; set this equate to the minimum MSPEED value
- ; allowed to use the 1k block protocol..
- ;
- ; MSPEED values: 1=300, 5=1200, 6=2400
- ;
- ;=======================================================================
- ;
- ; Allows uploading to be done on a specified driver and user area so all
- ; can readily find the latest entries.
- ;
- SETAREA EQU YES ; Yes, using designated du: to receive files
- ; No, upload to currently logged du:
- SPCDU EQU YES ; Yes, upload to designated du: if wheel set
- ;
- DRV EQU 'B' ; Drive to receive file on
- USR EQU 0 ; User area to receive file in
- ;
- ASKAREA EQU NO ; If YES, ask user what type of upload and
- ; set area accordingly. For Multiple
- ; Operating system support.
- ;
- SYSNEW EQU NO ; If YES, then new uploads are made $SYS
- ; to "hide" them from users until cleared...
- ;
- ;=======================================================================
- ;
- ; Selects the DU: for uploading private files with XMODEM RP option.
- ;
- PRDRV EQU 'B' ; Private drive for SYSOP to receive file
- PRUSR EQU 14 ; Private user area for SYSOP to receive file
- ;
- ;=======================================================================
- ;
- ; Selects the DU: for private download files. This permits Sysop
- ; to put file(s) in this area, then leave a private note to that
- ; person mentioning the name(s) of the file and its location.
- ;
- SPLDRV EQU 'B' ; Special drive area for downloading SYSOP files
- SPLUSR EQU 14 ; Special user area for downloading SYSOP files
- ;
- ;=======================================================================
- ;
- ; Selects the DU: used for message files uploaded with the "RM" option.
- ; (Used only if MBFMSG option enabled)
- ;
- MSGDRV EQU 'A' ; Drive used to receive message files
- MSGUSR EQU 15 ; User used to receive message files
- ;
- ;=======================================================================
- ;
- ; SYSOP may use NSWP or TAG and set the high bit of F1 to disallow the
- ; sending of large .LBR files. If TAGLBR is YES, only LUX or the option
- ; XMODEM L will allow transfer of individual member files from tagged
- ; .LBR files. The entire .LBR file can NOT be sent using XMODEM S NAME.
- ;
- TAGLBR EQU NO ; Yes tagged .LBR files not sent
- ;
- ; Note: The OK2400 equate if YES will bypass this restriction if the
- ; caller is operating at 2400 baud (or faster).
- ;
- ;=======================================================================
- ;
- ; Some modems will either go onhook immediately after carrier loss or
- ; can be set to lower values. A good value with the Smartmodem is five
- ; seconds, since it catches all "call forwarding" breaks. Not all is
- ; lost after timeout in XMODEM; BYE will still wait some more, but the
- ; chance of someone slipping in is less now.
- ;
- TIMOUT EQU 2 ; Seconds to abort after carrier loss
- ;
- ;=======================================================================
- ;
- ; Count the number of up/down loads since login. Your BBS program can
- ; check UPLDS and NDLDS when user logs out and update either the users
- ; file or another file for this purpose.
- ;
- LOGLDS EQU NO ; Count number of up/down loads since login.
- ;
- IF LOGLDS
- UPLDS EQU 054H ; Clear these values to Zero from your BBS pro-
- DNLDS EQU 055H ; gram when somebody logs in. NOTE: Clear
- ; ONLY when a user logs in. Not when he re-
- ; enters the BBS program for CP/M.
- ENDIF
- ;
- ;======================================================================
- ;
- ; Maximum file transfer time allowed.
- ;
- ; NOTE: If ZCPR2 = YES and WHEEL byte is set, send time is unlimited.
- ;
- ; TIME 300 BPS 1200 BPS
- ; ------ ------- --------
- ; 30 min 48.7k 180k
- ; 45 min 73.1k 270k
- ; 60 min 97.5k 360k
- ;
- MAXTIM EQU YES ; Yes if limiting transmission time
- ;
- MAXMIN EQU 60 ; Minutes for maximum file transfer time.
- ; this should be set to 60 if TIMEON is YES
- ; (99 minutes maximum.) (This is ignored if
- ; BYEBDOS is set.)
- ;
- ; Note: The OK2400 equate if YES will bypass MAXMIN limits.
- ;
- ;======================================================================
- ;
- ; The following equates need to be set ONLY if you are NOT using the
- ; BYE-BDOS calls supported in BYE338 and newer.
- ;
- ; Length of external patch program. If over 128 bytes, get/set size
- ;
- LARGEIO EQU NO ; Yes, if modem patch area over 128 bytes
- LARSIZE EQU 0 ; If 'LARGEIO' set patch area size (bytes) here
- ;
- ;=======================================================================
- ;
- ; USECON allows XMODEM to display the record count on the local CRT
- ; during transfers. All new remote console programs support this
- ; feature. BYE3* and MBYE3* will tell XMODEM where to find the local
- ; console's output vector.
- ;
- USECON EQU YES ; Yes to get CONOUT address from BYE
- ; NO, get CONOUT address from the XMODEM overlay
- ;
- CONOFF EQU 15 ; Offset to COVECT where original console output
- ; routine address is stored in BYE3/MBYE
- ; versions immediately followed by BYE as a
- ; check to insure BYE is running.
- ;
- ;=======================================================================
- ; start of TIMEON area
- ;
- RTC EQU NO ; If YES, add clock and date reader code at
- ; start of GETTIME: and GETDATE: below
- ;
- ; The TIMEON and RTC equates should be NO if B3RTC is YES
- ;
- TIMEON EQU NO ; If YES and BYEBDOS is NO, add your clock reader
- ; code at the start of label GETTIME: and return
- ; time in registers A & B. Also set to YES if
- ; BYEBDOS is YES and you want XMODEM to check
- ; time on system (not necessary if TIMEON in BYE
- ; is YES - saves unnecessary code).
- TOSEXIT EQU NO ; If YES, time on system displayed on exit if
- ; B3RTC or TIMEON or BYEBDOS set to YES
- ;
- IF TIMEON AND NOT CPM3
- LHOUR EQU 050H ; Set by BBS (or BYE) in binary when user logs
- LMIN EQU 051H ; on and his status
- STATUS EQU 053H
- ENDIF
- ;
- IF TIMEON AND CPM3
- LHOUR EQU 022H ; Set by BBS (or BYE) in binary when user logs
- LMIN EQU 023H ; on and his status
- STATUS EQU 024H
- ENDIF
- ;
- ; end of TIMEON area
- ;========================================================================
- ; Miscellaneous Support Bytes
- ;========================================================================
- ; Set this equate to enable access byte support. ACBOFF specifies
- ; the offset from the JMP COLDBOOT instruction as above with WRTLOC.
- ; MBBS and some newer BBS's support this byte, therefore, it is no
- ; longer specific to MBBS. You must determine if your system uses this.
- ;
- ACCESS EQU NO ; Yes, check flags for upload/dwnld restrictions
- ACBOFF EQU 21 ; # of bytes from JMP COLDBOOT to ACCESS byte.
- ACWRIT EQU 8 ; Bit to test for BBS msg write OK (1=OK,0=NOT OK)
- ACDNLD EQU 32 ; Bit to test for downloads OK (1=OK,0=NOT OK)
- ACUPLD EQU 64 ; Bit to test for uploads OK (1=OK,0=NOT OK)
- DWNTAG EQU NO ; If YES, files with F3 attribute bit can be
- ; downloaded regardless of access byte restrictions
- ;
- ; Access byte flag bit assignments
- ;
- ; Bit ; Used for
- ; 0 ; System access (no admittance if off)
- ; 1 ; BBS access (if off, dumped to CP/M)
- ; 2 ; Read access (if off, no "R" command allowed)
- ; 3 ; Write access (if off, no "E" command allowed)
- ; 4 ; CP/M access (if off, no admittance to CP/M)
- ; 5 ; Download access (if off, no downloads permitted)
- ; 6 ; Upload access (if off, no uploads permitted)
- ; 7 ; Privileged user (if on, user is "privileged")
- ;
- ; Of these bits, only 5 and 6 are used by XMODEM. Bit numbers are
- ; powers of 2, bit 0 being least significant bit of byte.
- ;-------------------------------------------------------------------------
- ; The CONFUN and WRTLOC are supported by BYE339 and many BBS's require
- ; the WRTLOC for propoer operation. These functions are not specific to
- ; MBBS and therefore have been made independant of the MBBS equate.
- ;
- ; (Set CONFUN/WRTLOC YES if using with MBBS)
- ;
- CONFUN EQU YES ; Yes, check local console for function keys
- SYSABT EQU YES ; If yes, sysop can abort up/downloads with ^X
- ; (CONFUN must be enabled to use this option)
- ;
- ; If you set CONFUN true, a call to the console status check routine in
- ; the BIOS will be done during waiting periods and when sector counts
- ; are displayed on the local console in order to allow MBYE and BYE339
- ; function keys to work. This is for MBYE. Other versions of BYE3
- ; may or may not check for console function keys during the console
- ; status check "MSTAT" routine.
- ;
- WRTLOC EQU YES ; Yes, set/reset WRTLOC so BYE won't hang up
- LOCOFF EQU 12 ; # of bytes from JMP COLDBOOT to WRTLOC byte
- ;
- ; NOTE: Code to set/reset WRTLOC assumes WRTLOC byte to be
- ; located "LOCOFF" bytes from the JMP COLDBOOT instruction at
- ; the beginning of the BYE3 BIOS jump table. On BYE3 versions
- ; and MBYE versions, this offset is usually 12. Note:
- ; TIMEON and RTC should be set to no if B3RTC is on.
- ; (If BYEBDOS is enabled, the appropriate extended BDOS
- ; calls are used to set and reset the WRTLOC if this
- ; equate is set and LOCOFF is ignored in these cases.)
- ;
- ; End of Miscellaneous Support Bytes
- ;=======================================================================
- ; start of MBBS/MBYE specific information
- ;
- B3RTC EQU NO ; If YES, your clock is setup in BYE3 (or MBYE)
- ; set to NO if using BYEBDOS
- B3COFF EQU 25 ; OFFSET from COLDBOOT: to RTCBUF address
- B3CMOS EQU 7 ; OFFSET from RTCBUF: to mins on system
- ;
- MBMXT EQU NO ; If YES, running MBYE with max. time on system
- MBMXO EQU 24 ; OFFSET from COLDBOOT: to MXML address
- ;
- ; If B3RTC is YES and LOGCAL is YES, the log file will show
- ; the date and time of all up/downloads. Note: Set RTC, TIMEON,
- ; and BYEBDOS to NO if using B3RTC or MBMXT.
- ;
- ; Note: Some of these equates may not be valid if you are using MBYE*
- ; with another BBS program - check them carefully.
- ;
- MBBS EQU NO ; Yes if running MBBS v2.9 up
- LOGSYS EQU NO ; Set YES if running MBBS v3.1 or earlier
- MBDESC EQU NO ; Yes if running MBBS v4.0 up for upload desc.
- NEWPRV EQU NO ; Yes: all new uploads are private initially
- MBFMSG EQU NO ; Yes if running MBYE v4.1 up with MFMSG
- ;
- ;
- ;----------------------------------------------------------------------
- ;
- ; If B3RTC is YES download time may be limited using the following
- ; equates instead of using MAXMIN. MAXMIN will be the default value
- ; if BYE is not running.
- ;
- B3TOS EQU NO ; Yes if using BYE3/MBYE and want to show time on sys
- ;
- MTOS EQU NO ; Yes if using maximum time on system instead
- ; of MAXMIN to limit transmission time
- ;
- IF MTOS AND MBMXT ; both must be YES
- MXTOS EQU YES ; (leave YES)
- ENDIF
- ;
- IF NOT (MTOS AND MBMXT) ; (if either is NO)
- MXTOS EQU NO ; (leave NO)
- ENDIF
- ;
- MXTL EQU NO ; Yes if limiting transmission time to time
- ; left plus MAXMIN. MXTOS must be yes.
- ;
- IF MXTL AND MXTOS ; both must be YES
- MTL EQU YES ; (leave YES)
- ENDIF
- ;
- IF NOT (MXTL AND MXTOS); (if either are NO)
- MTL EQU NO ; (leave NO)
- ENDIF
- ;
- ; end of MBBS/MBYE specific information
- ;=======================================================================
- ;
- ORG 100H
- JMP BEGIN
- ;
- ;-----------------------------------------------------------------------
- ;
- ; This is the I/O patch area. Assemble the appropriate I/O patch file
- ; for your modem, then integrate it into this program via DDT (or SID).
- ; Initially, all jumps are to zero, which will cause an unpatched XMODEM
- ; to simply execute a warm boot. All routines must end with RET.
- ;
- IF NOT BYEBDOS ; Universal I/O
- CONOUT: JMP 0 ; See 'CONOUT' discussion above
- MINIT: JMP 0 ; Initialization routine (if needed)
- UNINIT: JMP 0 ; Undo whatever MINIT did (or return)
- SENDR: JMP 0 ; Send character (via POP PSW)
- CAROK: JMP 0 ; Test for carrier
- MDIN: JMP 0 ; Receive data byte
- GETCHR: JMP 0 ; Get character from modem
- RCVRDY: JMP 0 ; Check receive ready (A - ERRCDE)
- SNDRDY: JMP 0 ; Check send ready
- SPEED: JMP 0 ; Get speed value for transfer time
- EXTRA1: JMP 0 ; Extra for custom routine
- EXTRA2: JMP 0 ; Extra for custom routine
- EXTRA3: JMP 0 ; Extra for custom routine
- ENDIF
- ;
- ;-----------------------------------------------------------------------
- ;
- IF NOT (LARGEIO OR BYEBDOS)
- ORG 100H+80H ; Origin plus 128 bytes for patches
- ENDIF
- ;
- IF LARGEIO AND NOT BYEBDOS
- ORG 100H+LARSIZE ; I/O patch area size if over 128 bytes
- ENDIF
- ;
- ; PRIVATE/SETAREA UPLOAD DISK/USER AREAS:
- ;
- ; (Here at start (usually 180H unless LARGEIO) so can be easily patched
- ; in .COM file using DDT without needing to reassemble. All references
- ; are made to these locations in memory and not to DRV/PRDRV/USR/PRUSR
- ; equates directly.)
- ;
- XPRDRV: DB PRDRV ; Private uploads go to this disk/user
- XPRUSR: DB PRUSR
- ;
- XDRV: DB DRV ; Forced uploads (if SETAREA EQU YES)
- XUSR: DB USR ; Go to this disk/user
- ;
- IF MBFMSG
- XMDRV: DB MSGDRV ; Message uploads go to this disk/user
- XMUSR: DB MSGUSR ; (if MBFMSG option enabled)
- ENDIF
- ;
- ;-----------------------------------------------------------------------
- ;
- ; File descriptors, change as desired if this list is not suitable.
- ; Move the line with the terminating '$' up, if fewer descriptors are
- ; desired.
- ;
- IF ASKIND AND DESCRIB
- ;
- KIND0: DB ' 0) - CP/M',CR,LF
- KIND1: DB ' 1) - ZCPR',CR,LF
- KIND2: DB ' 2) - MS-DOS/PC-DOS',CR,LF
- KIND3: DB ' 3) - dBASE',CR,LF
- KIND4: DB ' 4) - Basic',CR,LF
- KIND5: DB ' 5) - General',CR,LF
- KIND6: DB ' 6) - Modems',CR,LF
- KIND7: DB ' 7) - Games',CR,LF
- KIND8: DB ' 8) - Xerox/KPro',CR,LF
- KIND9: DB ' 9) - RCP/M',CR,LF
- DB '$'
- ENDIF
- ;.....
- ;
- ;----------------------------------------------------------------------
- ;
- ; If ASKAREA and SETAREA are set, then set these areas up and modify
- ; the message text in the FILTYP: function below if you desire a
- ; different choice. (As released in XMDM121, 1 = CP/M, 2 = MS/PC-DOS
- ; and 3 = General Interest.)
- ;
- IF ASKAREA AND SETAREA
- ;
- MAXTYP EQU '3' ; Set maximum type choice # here
- ;
- TYPTBL: DB 'B',0 ; CHOICE 1 (CP/M NORMAL)
- DB 'B',9 ; CHOICE 1 (CP/M PRIVATE)
- DB 'B',3 ; CHOICE 2 (MS/PC-DOS NORMAL)
- DB 'B',9 ; CHOICE 2 (MS/PC-DOS PRIVATE)
- DB 'B',0 ; CHOICE 3 (General interest NORMAL)
- DB 'B',9 ; CHOICE 3 (General interest PRIVATE)
- ;
- ENDIF
- ;
- ;=======================================================================
- ;
- ; PROGRAM STARTS HERE
- ;
- ;=======================================================================
- ;
- ; Save CP/M stack, initialize new one for this program
- ;
- BEGIN: LXI H,0
- DAD SP
- SHLD STACK
- LXI SP,STACK ; Initialize new stack
- ;
- IF BYEBDOS
- CALL BYECHK
- JZ BYEOK
- CALL ILPRT
- DB 'You need to be running BYEBDOS',CR,LF,0
- JMP EXIT2 ; Get stack pointer back and return
- ;
- BYEOK: MVI C,BDSTOS ; Get current maximum time on system
- MVI E,255
- CALL BDOS
- STA MAXTOS
- ENDIF
- ;
- IF B3RTC AND MXTOS AND (NOT BYEBDOS)
- CALL BYECHK ; If BYE not active
- MVI A,MAXMIN ; (we'll use MAXMIN as default)
- JNZ EXTMXT ; Skip MXML update
- LHLD 0001H ; Get JMP COLDBOOT
- DCX H
- MOV D,M
- DCX H
- MOV E,M
- LXI H,MBMXO ; + MBMXO offset to MXML
- DAD D
- MOV A,M ; = max time allowed on system
- ;
- EXTMXT: STA MAXTOS ; Store max download time
- ENDIF
- ;
- ; Get address of RTCBUF in BYE3 or MBYE
- ;
- IF B3RTC AND (NOT BYEBDOS)
- CALL BYECHK ; See if BYE3/MBYE is running
- JNZ NOBYE0 ; If not, skip this junk
- LHLD 0001H ; Get COLDBOOT addr
- DCX H ; (just before JMP WBOOT)
- MOV D,M ; And stuff in DE
- DCX H
- MOV E,M
- LXI H,B3COFF ; Add offset to RTCBUF address
- DAD D ; (in HL)
- MOV E,M ; Get RTCBUF address
- INX H ; And
- MOV D,M ; Stuff in DE
- XCHG ; Swap into HL
- SHLD RTCBUF ; Save for use later
- ENDIF
- ;
- NOBYE0: IF CONFUN ; Console status checks to be done?
- LHLD 0001H ; If so get addr of warmboot (jmp table)
- INX H
- INX H
- INX H ; + 3 = address of console status check
- SHLD CONCHK+1 ; Stuff after call for FUNCHK
- ENDIF
- ;
- IF WRTLOC ; Set WRITE LOCK?
- CALL SETLCK
- ENDIF
- ;
- ; Save the current drive and user area
- ;
- NOBYE1: MVI E,0FFH ; Get the current user area
- MVI C,SETUSR
- CALL BDOS
- STA OLDUSR ; Save user number here
- MVI C,CURDRV ; Get the current drive
- CALL BDOS
- STA OLDDRV ; Save drive here
- ;
- IF B3TOS OR TIMEON
- CALL TIME ; Get user's time status
- ENDIF
- ;
- IF BYEBDOS AND (NOT TIMEON)
- MVI C,BDPTOS ; Display time on system and
- CALL BDOS ; log off if over time limit
- ENDIF
- ;
- CALL ILPRT
- DB CR,LF
- ;
- IF LUXMOD
- DB 'LUX-'
- ENDIF
- ;
- DB 'XMODEM v'
- DB VERSION+'0',INTERM+'0','.',MODLEV+'0',' - '
- DB VMONTH/10+'0',VMONTH MOD 10+'0','/'
- DB VDAY/10+'0',VDAY MOD 10+'0','/'
- DB VYEAR/10+'0',VYEAR MOD 10+'0',CR,LF,0
- ;
- ; Stuff address of BIOS CONOUT vector in our routine as default.
- ;
- IF USECON AND NOT BYEBDOS
- LHLD 0001H ; Point to warm boot for normal BIOS
- LXI D,9
- DAD D ; Calc addr of normal BIOS conout vector
- SHLD CONOUT+1 ; Save in case no BYE program is active
- CALL BYECHK
- JNZ NOBYE
- XCHG ; Point to the console output routine
- SHLD CONOUT+1 ; Save vector address supplied by BYE
- ENDIF
- ;
- ; Get option
- ;
- NOBYE: LXI H,FCB+1 ; Get primary option
- MOV A,M
- STA OPTSAV ; Save option
- CPI 'R' ; Receive file?
- JZ RECVOPT
- ;
- ; Send option processor
- ; Single option: "K" - force 1k mode
- ;
- INX H ; Look for a 'K'
- MOV A,M
- CPI ' ' ; Is it a space?
- JZ ALLSET ; Then we're ready to send...
- CPI 'K'
- JNZ OPTERR ; "K" is the only setable 2nd option
- LDA MSPEED
- CPI MINKSP ; If less than MINKSP bps, ignore 1k
- JC ALLSET ; Request
- MVI A,'K' ; Set 1k mode
- STA KFLAG ; First, force us to 1K mode
- CALL ILPRT
- DB '(1k protocol selected)',CR,LF,0
- JMP ALLSET ; That's it for send...
- ;
- ; Receive option processor
- ; 3 or 4 options: "X" - disable auto-protocol select
- ; "P" - receive file in private area
- ; "C" - force checksum protocol
- ; "M" - message file upload (if MBFMSG)
- ;
- RECVOPT:MVI A,'K' ; First off, default to 1K mode
- STA KFLAG
- MVI A,0 ; And default to CRC mode
- STA CRCFLG
- ;
- CALL RCVOPC ; Check 1st option
- CALL RCVOPC ; Check 2nd option
- CALL RCVOPC ; Check 3rd option
- ;
- IF MBFMSG
- CALL RCVOPC ; Check 4th option
- ENDIF
- ;
- IF NDESC
- CALL RCVOPC ; Check 4th (or 5th) option
- ENDIF
- ;
- JMP OPTERR ; If 5th or 6th option, whoops!
- ;
- RCVOPC: INX H ; Increment pointer to next character
- MOV A,M ; Get option character HL points to
- CPI ' ' ; Space?
- JNZ CHK1ST ; No, we have an option
- POP PSW ; Else, we are done (restore stack)
- JMP ALLSET ; Exit routine now
- ;
- CHK1ST: CPI 'P' ; Got a "P" option?
- JNZ CHK2ND ; Nope
- STA PRVTFL ; Yep, set private upload flag
- RET ; Check next option
- ;
- CHK2ND: CPI 'C' ; Got a "C" option?
- JNZ CHK3RD ; Nope
- STA CRCFLG ; Set checksum flag (crc flag="C")
- CALL ILPRT
- DB '(Checksum protocol selected)',CR,LF,0
- RET
- ;
- CHK3RD: CPI 'X' ; Got an "X" for first option?
- JNZ CHK4TH
- MVI A,0
- STA KFLAG ; Disable "1K" flag
- CALL ILPRT
- DB '(128 byte protocol only)',CR,LF,0
- RET
- ;
- CHK4TH:
- IF MBFMSG ; Allowing "RM" for message uploads?
- CPI 'M' ; Got an "M" for message upload?
- JNZ CHK5TH ; If not, bad option
- STA MSGFLG ; If "M", set MSGFLG
- MVI A,'P' ; Also, set PRVTFL
- STA PRVTFL
- LDA XMDRV ; And copy XMDRV
- STA XPRDRV
- LDA XMUSR ; And XMUSR to XPRDRV / XPRUSR
- STA XPRUSR
- RET
- ENDIF
- ;
- CHK5TH:
- IF NDESC ; Allowing "RN" to skip upload descript?
- CPI 'N' ; Got an 'N'?
- JNZ BADROP ; If nope, is NG..
- STA NDSCFL ; else set flag to skip descript phase
- RET
- ENDIF
- ;
- BADROP: POP PSW ; Restore stack
- JMP OPTERR ; is bad option
- ;
- ; All options have been set, gobble up garbage characters from the line
- ; prior to receive or send and initialize whatever has to be initialized
- ;
- ALLSET: CALL GETCHR
- CALL GETCHR
- CALL MINIT
- ;
- ; Jump to appropriate function
- ;
- LDA OPTSAV ; Get primary option again
- ;
- IF LOGCAL
- STA LOGOPT ; But save it
- ENDIF
- ;
- CPI 'L' ; To send a file from a library?
- JZ SENDFIL
- CPI 'R' ; To receive a file?
- JZ RCVFIL
- CPI 'S'
- JZ SENDFIL ; Otherwise go send a file
- ;
- ; Invalid option
- ;
- OPTERR:
- ;
- IF ASKAREA AND SETAREA
- LDA OPTSAV ; Check 'option'
- CPI 'A' ; If 'A' (avail upload space option)
- CZ FILTYP ; ask type of upload...
- ENDIF
- ;
- IF NOT (SETAREA OR LUXMOD)
- CALL ILPRT
- DB CR,LF,'Uploads files to specified or '
- DB 'current disk/user',0
- ENDIF
- ;
- IF SETAREA AND NOT LUXMOD
- CALL ILPRT
- DB CR,LF,'Uploads files to ',0
- LDA XDRV
- CALL CTYPE
- LDA XUSR
- MVI H,0
- MOV L,A
- CALL DECOUT
- MVI A,':'
- CALL CTYPE
- CALL ILPRT
- DB ' (',0
- LDA XDRV
- STA KDRV
- CALL KSHOW
- MVI A,')'
- CALL CTYPE
- ENDIF
- ;
- IF NOT LUXMOD
- CALL ILPRT
- DB CR,LF,'Private files to ',0
- LDA XPRDRV
- CALL CTYPE
- LDA XPRUSR
- MVI H,0
- MOV L,A
- CALL DECOUT
- MVI A,':'
- CALL CTYPE
- LDA XPRDRV ; If private drive is
- MOV B,A
- LDA XDRV ; The same as forced upload drive
- SUB B
- JZ SKSK2 ; Skip showing space available 2nd time
- CALL ILPRT
- DB ' (',0
- LDA XPRDRV ; Else show it..
- STA KDRV
- CALL KSHOW
- MVI A,')'
- CALL CTYPE
- ;
- SKSK2: CALL ILPRT
- DB CR,LF,0
- ENDIF
- ;
- LDA OPTSAV ; Check 'option'
- CPI 'A' ; If 'A' (avail upload space option)
- JZ EXIT ; Skip error message
- ;
- IF WRTLOC AND NOT BYEBDOS
- CALL RSTLCK
- ENDIF
- ;
- CALL ERXIT ; Exit with error
- DB '++ Examples of valid options: ++ '
- DB '(use Ctrl-C or Ctrl-K to abort)',CR,LF,LF
- ;
- IF NOT LUXMOD
- DB 'XMODEM S HELLO.DOC send a file to you',CR,LF
- DB 'XMODEM S B1:HELLO.DOC send from a named '
- DB 'drive/area',CR,LF
- DB 'XMODEM SK HELLO.DOC send in 1k blocks',CR,LF
- DB 'XMODEM L CAT.LBR CAT.COM send a file from a library'
- DB CR,LF
- DB 'XMODEM LK CAT.LBR CAT.COM send in 1k blocks',CR,LF
- DB ' The ".LBR" file extension may be omitted',CR,LF,LF
- DB 'XMODEM R HELLO.DOC receive a file from you'
- DB CR,LF
- DB 'XMODEM RP HELLO.DOC receive in a private area'
- DB CR,LF
- ENDIF
- ;
- IF (MBDESC OR DESCRIB) AND NDESC
- DB 'XMODEM RN FILE.EXT receive without description'
- DB CR,LF
- ENDIF
- ;
- IF (NOT LUXMOD) AND MBFMSG
- DB 'XMODEM RM MESSAGE.FIL receive message for MBBS'
- DB CR,LF
- ENDIF
- ;
- IF NOT LUXMOD
- DB ' Add "C" for forced checksum ("RC" "RPC")',CR,LF
- DB ' Add "X" for forced 128 byte protocol ("RX" "RPX")'
- DB CR,LF
- DB ' "R" switches from CRC to checksum after 5 retries'
- DB CR,LF,LF
- DB 'XMODEM A shows areas/space for '
- DB 'uploads$'
- ENDIF
- ;
- IF LUXMOD
- DB 'SEND MEMBERNAME.TYP sends member with CRC'
- DB CR,LF
- DB 'SENDK MEMBERNAME.TYP sends using 1k packets'
- DB CR,LF,LF
- DB 'XMODEM S MEMBERNAME.TYP same as SEND command'
- DB CR,LF
- DB 'XMODEM SK MEMBERNAME.TYP same as SENDK',CR,LF,LF
- DB '(XMODEM can NOT receive while in LUX.)$'
- ENDIF
- ;
- ;
- ;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- ;
- ; ---> SENDFIL sends a CP/M file
- ;
- ;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- ;
- ; The CP/M file specified in the XMODEM command is transferred over the
- ; phone to another computer running modem with the "R" (receive) option.
- ; The data is sent one record at a time with headers and checksums, and
- ; retransmission on errors.
- ;
- SENDFIL:CALL LOGDU ; Check file name or drive/user option
- LDA OPTSAV
- CPI 'L' ; If library option skip 'CNREC'
- CNZ CNREC ; Ignore if in library mode
- CALL OPENFIL ; Open the file
- MVI E,100 ; Wait 100 sec for initial 'NAK'
- CALL WAITNAK
- LHLD RCNT ; XMDM116.FIX
- CALL CKKSIZ ; XMDM116.FIX -- Murray Simsolo
- ;
- SENDLP: CALL CHKERR ; Check ratio of blocks to errors
- CALL RDRECD ; Read a record
- JC SENDEOF ; Send 'EOF' if done
- CALL INCRRNO ; Bump record number
- XRA A ; Initialize error count to zero
- STA ERRCT
- ;
- SENDRPT:CALL SENDHDR ; Send a header
- CALL SENDREC ; Send data record
- LDA CRCFLG ; Get 'CRC' flag
- ORA A ; 'CRC' in effect?
- CZ SENDCRC ; Yes, send 'CRC'
- CNZ SENDCKS ; No, send checksum
- CALL GETACK ; Get the 'ACK'
- JC SENDRPT ; Repeat if no 'ACK'
- CALL UPDPTR ; Update buffer pointers and counters
- LDA OPTSAV ; Get the command option again
- CPI 'L'
- JNZ SENDLP ; If not library option, go ahead
- ;
- ;
- ; Check to see if done sending LBR member yet, downshift to small blocks
- ; if less that 8 remaining
- ;
- LHLD RCNT
- MOV A,H
- ORA L ; See if L and H both zero now
- JZ SENDEOF ; If finished, exit
- LDA KFLAG ; Was last record a 1024 byte one?
- ORA A
- JZ SNRPT0 ; Just handled an normal 128 byte record
- DCX H ; Otherwise, must have be a BIG one, so
- DCX H ; Seven ...
- DCX H
- DCX H
- DCX H
- DCX H
- DCX H ; Plus
- ;
- SNRPT0: DCX H ; One, is either 1 or 8
- SHLD RCNT ; One (or eight) less to go
- CALL CKKSIZ ; Check to see if at least 8 left
- JMP SENDLP ; Loop until EOF
- ;
- ; File sent, send EOT's
- ;
- SENDEOF: IF LOGLDS
- LDA DNLDS ; Get Down loads Counter
- INR A ; One more download since log in
- STA DNLDS ; And update counter
- ENDIF
- ;
- SNDEOFL:LDA EOFCTR ; Get EOF counter
- CPI 5 ; Tried five times ?
- JZ EXITLG ; Yes, quit trying
- MVI A,EOT ; Send an 'EOT'
- CALL SEND
- LDA EOFCTR ; Get EOF counter
- INR A ; Add one
- STA EOFCTR ; Save new count
- CALL GETACK ; Get the ACK
- JC SNDEOFL ; Loop if no ACK
- JMP EXITLG ; All done
- ;.....
- ;
- ;
- ;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- ;
- ; ---> RCVFIL Receive a CP/M file
- ;
- ;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- ;
- ; Receives a file in block format as sent by another person doing
- ; "XMODEM S FILENAME.TYP". Can be invoked by "XMODEM R FILENAME.TYPE"
- ; or by "XMODEM RC FILENAME.TYP" if checksum is to be used.
- ;
- RCVFIL: IF ACCESS
- CALL BYECHK
- JNZ RCVFL1
- LHLD 0001H ; Get JMP COLDBOOT
- DCX H
- MOV D,M
- DCX H
- MOV E,M
- LXI H,ACBOFF ; + ACBOFF
- DAD D
- MOV A,M ; = ACCESS byte address
- ANI ACUPLD ; Test upload access bit
- JNZ RCVFL0 ; If bit on, uploads OK
- CALL ERXIT
- DB 'Sorry, but you are not allowed to upload files '
- DB 'at this time...$'
- ENDIF
- ;
- RCVFL0: IF ACCESS AND MBFMSG
- LDA MSGFLG
- ORA A ; Is this "RM" upload?
- JZ RCVFL1 ; If not, skip ACWRIT check
- MOV A,M
- ANI ACWRIT ; If "RM", check if WRITE access
- JNZ RCVFL1 ; If so, ok
- CALL ERXIT
- DB 'Sorry, but you are not allowed to enter messages '
- DB 'at this time...$'
- ENDIF
- ;
- RCVFL1:
- CALL LOGDU ; Check file name or drive/user option
- ;
- IF ZCPR2
- LDA WHEEL ; Let SYSOP put file wherever he wants
- ORA A
- JZ RCVFL5 ; If WHEEL byte not set, stay normal
- LDA RCVDRV
- ORA A
- ENDIF
- ;
- ;
- IF ZCPR2 AND NOT SPCDU
- JZ RCVFL2
- ENDIF
- ;
- IF ZCPR2 AND SPCDU
- JZ RCVFL2
- ENDIF
- ;
- IF ZCPR2
- SUI 'A' ; Convert ASCII drive to binary
- JMP RCVFL3
- ;
- RCVFL2: LDA OLDDRV
- ;
- RCVFL3: INR A
- STA FCB
- ADI 'A'-1 ; Convert binary to ASCII
- STA XDRV ; Drive
- LDA RCVDRV ; See if a drive was requested
- ORA A
- LDA OLDUSR ; Current user
- JZ RCVFL4 ; If not, use current user
- LDA RCVUSR ; Else get requested user
- ;
- RCVFL4: STA XUSR ; User
- JMP CONTIN
- ENDIF ; ZCPR2
- ;
- RCVFL5: IF SETAREA
- LDA XDRV
- SUI 40H
- STA FCB
- ENDIF
- ;
- LDA PRVTFL ; Receiving to a private area?
- ORA A
- JZ RCVFL6 ; If not, exit
- LDA XPRDRV ; Private area takes precedence
- SUI 40H
- STA FCB ; Store drive to be used
- ;
- RCVFL6: IF NOCOMR
- LXI H,FCB+9 ; Point to filetype
- MVI A,'C' ; 1st letter
- CMP M ; Is it C ?
- JNZ RCVFL7 ; If not, continue normally
- INX H ; Get 2nd letter
- MVI A,'O' ; 2nd letter
- CMP M ; Is it O ?
- JNZ RCVFL7 ; If not, continue normally
- INX H ; Get 3rd letter
- MVI A,'M' ; 3rd letter
- CMP M ; Is it M ?
- JNZ RCVFL7 ; If not, continue normally
- CALL ILPRT ; Print renaming message
- DB 'Auto-renaming file to ".OBJ"',CR,LF,0
- LXI H,FCB+9
- MVI M,'O'
- INX H
- MVI M,'B'
- INX H
- MVI M,'J'
- JMP CONTIN
- ENDIF ; NOCOMR
- ;
- RCVFL7: IF NOCOMR AND CPM3
- LXI H,FCB+9 ; Point to filetype
- MVI A,'P' ; 1st letter
- CMP M ; Is it P ?
- JNZ RCVFL8 ; If not, continue normally
- INX H ; Get 2nd letter
- MVI A,'R' ; 2nd letter
- CMP M ; Is it R ?
- JNZ RCVFL8 ; If not, continue normally
- INX H ; Get 3rd letter
- MVI A,'L' ; 3rd letter
- CMP M ; Is it L ?
- JNZ RCVFL8 ; If not, continue normally
- CALL ILPRT ; Print renaming message
- DB 'Auto-renaming file to ".OBP"',CR,LF,0
- LXI H,FCB+9
- MVI M,'O'
- INX H
- MVI M,'B'
- INX H
- MVI M,'P'
- JMP CONTIN
- ENDIF ; NOCOMR AND CPM3
- ;
- ; Check to see if filetype is .NDR, if so do NOT allow upload
- ;
- RCVFL8: IF ZCPR3
- LXI H,FCB+9 ; Point to filetype
- MVI A,'N' ; 1st letter
- CMP M ; Is it N ?
- JNZ RCVFL9 ; If not, continue normally
- INX H ; Get 2nd letter
- MVI A,'D' ; 2nd letter
- CMP M ; Is it D ?
- JNZ RCVFL9 ; If not, continue normally
- INX H ; Get 3rd letter
- MVI A,'R' ; 3rd letter
- CMP M ; Is it R ?
- JNZ RCVFL9 ; If not, continue normally
- CALL ERXIT ; Print renaming message
- DB 'Cannot receive filetype ".NDR"',CR,LF,'$'
- ;
- ; Check to see if filetype is .RCP, if so do NOT allow upload
- ;
- RCVFL9: LXI H,FCB+9 ; Point to filetype
- MVI A,'R' ; 1st letter
- CMP M ; Is it R ?
- JNZ CONTIN ; If not, continue normally
- INX H ; Get 2nd letter
- MVI A,'C' ; 2nd letter
- CMP M ; Is it C ?
- JNZ CONTIN ; If not, continue normally
- INX H ; Get 3rd letter
- MVI A,'P' ; 3rd letter
- CMP M ; Is it P ?
- JNZ CONTIN ; If not, continue normally
- CALL ERXIT ; Abort with error msg
- DB 'Cannot receive filetype ".RCP"',CR,LF,'$'
- ENDIF ; ZCPR3
- ;
- CONTIN:
- IF MBFMSG
- LDA MSGFLG
- ORA A ; Is this "RM" upload?
- JNZ DONT ; If yes, skip asking what kind of upload
- ENDIF
- ;
- IF ASKAREA AND SETAREA AND (NOT ZCPR2)
- CALL FILTYP ; Ask caller what kinda beast it is
- ENDIF
- ;
- IF ASKAREA AND SETAREA AND ZCPR2
- LDA WHEEL ; Don't ask the SYSOP
- ORA A
- JNZ DONT ; If WHEEL byte set, skip asking
- CALL FILTYP ; Ask caller what kinda beast it is
- ENDIF
- ;
- DONT: CALL ILPRT ; Print the message
- ;
- IF NOT DSPFNAM
- DB CR,LF,'File will be received on ',0
- ENDIF
- ;
- IF DSPFNAM
- DB CR,LF,'Receiving: ',0
- ENDIF
- ;
- LDA PRVTFL ; Going to store in the private area?
- ORA A
- JZ CONT1 ; If not, exit
- ;
- LDA XPRDRV ; Get private drive
- JMP CONT2 ; If yes, it takes priority
- ;
- CONT1:
- IF SETAREA
- LDA XDRV ; Setarea uses a specified drive
- ENDIF
- ;
- IF NOT SETAREA
- LDA OLDDRV ; Otherwise get current drive
- ADI 'A' ; Convert to ASCII
- ;
- NOTDRV: DB 0,0 ; Filled in by 'GETDU' if requested
- ENDIF
- ;
- CONT2:
- STA KDRV ; Save drive for KSHOW
- SUI 40H ; Convert ASCII to binary
- STA FCB ; Stuff in FCB
- LDA KDRV ; Get ASCII version back again
- CALL CTYPE ; Print the drive to store on
- LDA PRVTFL ; Going to store in the private area?
- ORA A
- JZ NOPRVL ; If nope, skip ahead
- ;
- IF LOGCAL
- MVI A,'P' ; If private upload
- STA LOGOPT ; Show "P" as option
- ENDIF
- ;
- LDA XPRUSR ; Get private user area
- JMP CONT3 ; It takes priority
- ;
- NOPRVL:
- IF SETAREA
- LDA XUSR ; Setarea takes next precedence
- ENDIF
- ;
- IF NOT SETAREA
- LDA OLDUSR ; Get current drive for default
- ;
- NOTUSR: DB 0,0 ; Filled in by 'GETDU' if requested
- ENDIF
- ;
- CONT3: MVI H,0
- MOV L,A
- CALL DECOUT ; Print the user area
- ;
- IF NOT DSPFNAM
- CALL ILPRT
- DB ':',CR,LF,0
- ENDIF
- ;
- IF DSPFNAM
- MVI A,':'
- CALL CTYPE ; We showed disk/user:
- LXI H,FCB+1 ; Now display filename
- CALL DSPFN
- CALL ILPRT
- DB CR,LF,0
- ENDIF
- ;
- CALL KSHOW ; Show available space remaining
- CALL ILPRT
- DB CR,LF,0
- CALL CHEKFIL ; See if file exists
- CALL MAKEFIL ; If not, start a new file
- CALL ILPRT
- DB 'File open - ready to receive',CR,LF
- DB 'To cancel: Ctrl-X, pause, Ctrl-X',CR,LF,0
- ;
- IF B3RTC AND (NOT MBMXT OR BYEBDOS)
- CALL GETTOS ; Get time on system
- SHLD TOSSAV ; Save it for exit
- ENDIF
- ;
- RCVLP: CALL RCVRECD ; Get a record
- JC RCVEOT ; Got 'EOT'
- CALL WRRECD ; Write the record
- CALL INCRRNO ; Bump record number
- CALL SENDACK ; Ack the record
- JMP RCVLP ; Loop until 'EOF'
- ;
- ;
- ; Got EOT on record so flush buffers then done
- ;
- RCVEOT: LHLD RECDNO ; Check for zero length file
- MOV A,H ; If no records, no file
- ORA L
- JNZ EOT1 ; If not zero, continue, else abort
- CALL RCVSABT ; Abort and erase the zero length file
- JMP EXIT ; And exit
- ;
- EOT1: CALL WRBLOCK ; Write the last block
- CALL SENDACK ; Ack the record
- CALL CLOSFIL ; Close the file
- XRA A ; Clear CTYPE's console
- STA CONONL ; Output only flag
- ;
- IF LOGLDS
- LDA UPLDS ; Get Upload Counter
- INR A ; One more upload since log in
- STA UPLDS ; Update Counter
- ENDIF
- ;
- ; Logging upload or crediting time on?
- ;
- IF LOGCAL
- LHLD VRECNO ; If yes, get virtual # of recs
- SHLD RCNT ; And stuff in RCNT
- CALL FILTIM ; Calculate appox. xfer time
- ENDIF
- ;
- IF B3RTC AND MBMXT AND (NOT BYEBDOS)
- CALL BYECHK ; If BYE not active
- JNZ EXITLG ; Skip MXML update
- LHLD 0001H ; Get JMP COLDBOOT
- DCX H
- MOV D,M
- DCX H
- MOV E,M
- LXI H,MBMXO ; + MBMXO offset to MXML
- DAD D
- MOV A,M ; = max time allowed on system
- ORA A ; Check it (zero?)
- JZ EXITLG ; If unlimited time, skip update
- INR A ; Else, increment it (for secs)
- ADD C ; Add mins LSB (can't be >255)
- JC MAK255 ; If overflow, make it max (255)
- JZ MAK255 ; (if zero, make 255)
- MOV M,A ; Update it (credit them for upload)
- JMP EXITLM
- ;
- MAK255: MVI A,255 ; If up to max, make sure they don't
- MOV M,A ; Get LESS than what they had..
- ENDIF
- ;
- IF B3RTC AND NOT (BYEBDOS OR MBMXT)
- CALL BYECHK
- JNZ EXITLG ; SKIP this if BYE not running
- LHLD RTCBUF ; Get address of RTCBUF in HL
- LXI D,B3CMOS ; Add offset to mins on system
- DAD D ; (addr in HL)
- LDA TOSSAV ;Get saved time on system
- MOV M,A ; And restore it
- INX H ; (don't count upload time
- LDA TOSSAV+1 ; Against them)
- MOV M,A
- ENDIF
- ;
- IF BYEBDOS AND (NOT B3RTC)
- LDA MAXTOS ; Get maximum time allowed
- ORA A
- JZ EXITLG ; If zero, he's a super-guy anyway
- INR A
- ADD C ; Add in upload time
- JC MAK254 ; Make it 254 minutes if overflow
- JZ MAK254 ; (or zero)
- CPI 255 ; (or 255)
- JNZ MAXSTR
- ;
- MAK254: MVI A,254 ; (254 is max allowed)
- ;
- MAXSTR: STA MAXTOS ; Save for internal use
- MOV E,A
- MVI C,BDSTOS ; Set maximum time on system
- CALL BDOS
- ENDIF
- ;
- EXITLM: IF BYEBDOS OR (B3RTC AND MBMXT)
- CALL ILPRT
- DB CR,LF,'Upload time credited towards maximum timeon.'
- DB CR,LF,0
- ENDIF
- ;
- JMP EXITLG
- ;
- ;-----------------------------------------------------------------------
- ;
- ; SUBROUTINES
- ;
- ;-----------------------------------------------------------------------
- ;
- ; FILTYP: Ask file type for uploads
- ;
- IF ASKAREA AND SETAREA
- ;
- ; Routine to get file type for uploads (modified from XMDM10XX.ASM
- ; by Russ Pencin (Dallas Connection)). (Modify MAXTYP and TYPTBL
- ; near the top of the program.)
- ;
- FILTYR: CALL ILPRT
- DB CR,LF,0
- ;
- FILTYP: CALL ILPRT ; Modify message as needed
- DB CR,LF,'Is file for:',CR,LF,CR,LF
- DB ' (1) CP/M',CR,LF
- DB ' (2) MS/PC-DOS',CR,LF
- DB 'or (3) General interest?',CR,LF,CR,LF
- DB 'Enter choice (1, 2 or 3): ',0
- ENDIF ;ASKAREA AND SETAREA
- ;
- IF ASKAREA AND SETAREA AND WRTLOC
- CALL RSTLCK ;Turn off WRTLOC so RDCON will work
- ENDIF
- ;
- IF ASKAREA AND SETAREA
- MVI C,RDCON
- CALL BDOS
- CPI '1' ;is it a cpm file
- JC FILTYR ;nope, ask again use default upload area(s)
- CPI MAXTYP+1
- JNC FILTYR
- SUI '1' ;GET OFFSET FOR TYPTBL
- RAL
- RAL
- MVI D,0
- MOV E,A
- LXI H,TYPTBL
- DAD D
- MOV A,M
- STA XDRV ;set drive
- INX H
- MOV A,M ;user
- STA XUSR
- INX H
- MOV A,M ;private drive
- STA XPRDRV
- INX H
- MOV A,M ;and private user values
- STA XPRUSR
- CALL ILPRT
- DB CR,LF,0
- ENDIF ;ASKAREA AND SETAREA
- ;
- IF ASKAREA AND SETAREA AND WRTLOC
- CALL SETLCK ;Turn WRTLOC back on
- ENDIF
- ;
- IF ASKAREA AND SETAREA
- RET
- ENDIF
- ;
- ;---------------------------------------------------------------------
- ; WRTLOC ROUTINES (SETLCK AND RSTLCK)
- ;
- IF WRTLOC AND NOT BYEBDOS
- SETLCK: CALL BYECHK ; Is BYE running
- RNZ ; If not, skip this
- LHLD 0001H ; Get JMP COLDBOOT
- DCX H
- MOV D,M
- DCX H
- MOV E,M
- LXI H,LOCOFF ; + LOCOFF
- DAD D
- ORI 0FFH ; = WRTLOC address
- MOV M,A ; Turn the lock on
- RET
- ;
- RSTLCK: CALL BYECHK ; Is BYE running
- RNZ ; Nope, don't touch a thing
- LHLD 0001H ; If so, time to reset it
- DCX H ; Get JMP COLDBOOT addr.
- MOV D,M
- DCX H
- MOV E,M
- LXI H,LOCOFF ; + LOCOFF bytes
- DAD D ; = WRTLOC address
- XRA A ; Clear it
- MOV M,A ; (so ctrl-C/ctrl-K work)
- RET
- ENDIF ;WRTLOC AND NOT BYEBDOS
- ;
- IF WRTLOC AND BYEBDOS
- SETLCK: MVI C,BDWRTL ; Set/Get writeloc function
- MVI E,1 ; Turn on WRTLOC flag
- CALL BDOS
- RET
- ;
- RSTLCK: MVI C,BDWRTL ; Set/Get writeloc function
- MVI E,0 ; Turn off WRTLOC flag
- CALL BDOS
- RET
- ENDIF
- ;
- ;---------------------------------------------------------------------
- ;
- ; Display file name function
- ;
- IF DSPFNAM ; HL=FCB address
- DSPFN: MVI B,8
- ;
- PRNAM: MOV A,M
- ANI 7FH ; Strip any attribute bits
- CPI ' ' ; Don't print blanks
- CNZ CTYPE ; Print filename
- INX H
- DCR B
- JNZ PRNAM
- ;
- PRDOT: MVI A,'.' ; After first part, print dot
- CALL CTYPE
- MVI B,3
- ;
- PRTYP: MOV A,M
- ANI 7FH ; Strip any attribute bits
- CPI ' ' ; Don't print blanks
- CNZ CTYPE ; Print filetype
- INX H
- DCR B
- JNZ PRTYP
- RET
- ENDIF ; DSPFNAM
- ;
- ; Check to see if BYE is running before getting CONOUT, checking MBBS
- ; ACCESS byte or setting/resetting WRTLOC. This routine also returns
- ; the address of the original cold boot routine in DE.
- ;
- ; Go through a big search to see if BYE is active.
- ;
- IF BYEBDOS
- BYECHK: MVI C,32 ; This bizarre combination determines
- MVI E,241 ; If BYE is not there.
- CALL BDOS
- CPI 77 ; Is it there?
- RET
- ENDIF
- ;
- IF (NOT BYEBDOS) AND (USECON OR ACCESS OR WRTLOC)
- BYECHK: LHLD 0001H ; Point to warm boot again
- DCX H ; If BYE active,
- MOV D,M ; Pick up pointer to BYE variables
- DCX H ; (COVECT) followed by 'BYE'
- MOV E,M
- LXI H,CONOFF ; Calculate address of BYE variable
- DAD D ; Where ptr to orig BIOS vector stored
- MOV E,M ; Load that address into DE, if BIOS
- INX H ; Is active, DE now points to original
- MOV D,M ; BIOS console output vector
- INX H ; Point to BYE signon message
- ;
- ; Note that if more BYE variables are added after the cold boot pointer,
- ; extra INX may be needed. Fix to match your BYE.
- ;
- MOV A,M ; Get letter
- ANI 05FH ; Convert to upper case if needed
- CPI 'B' ; Try to match 'BYE'
- RNZ ; Out if BYE not active
- INX H
- MOV A,M
- ANI 05FH ; Convert to upper case if needed
- CPI 'Y'
- RNZ
- INX H
- MOV A,M
- ANI 05FH ; Convert to upper case if needed
- CPI 'E'
- RET
- ENDIF
- ;
- ; Check next character to see if a space or non-space, file name error
- ; if no ASCII character.
- ;
- CHKFSP: DCR B
- JZ NFN ; Error if end of chars.
- MOV A,M
- CPI ' '+1
- RNC ; Ok if valid character so return
- INX H
- JMP CHKFSP ; Look at next character
- ;
- ; Check next character to see if a space or non-space, go to menu if a
- ; command error.
- ;
- CHKSP: DCR B
- JZ OPTERR
- INX H
- MOV A,M ; Get the char. there
- CPI ' ' ; Space character?
- RET ; JZ = space, JNZ = non-space
- ;
- ; Exit, but first write record to log file and ask for description
- ;
- EXITLG:
- ;
- IF LOGCAL OR MBDESC OR MBFMSG
- CALL LOGCALL
- ENDIF
- ;
- ; Ask sysop for a description of the file if ASKSYS is yes
- ;
- IF DESCRIB AND ZCPR2 AND (NOT ASKSYS)
- LDA WHEEL ; If its the Sysop, don't ask
- ORA A ; For a description because he
- JNZ EXIT ; Might want to batch recv files
- ENDIF
- ;
- IF DESCRIB AND NDESC
- LDA NDSCFL ; If user picked "N" option
- ORA A ; allow them to skip upload
- JNZ EXIT ; descript
- ENDIF
- ;
- IF DESCRIB AND WRTLOC
- CALL RSTLCK ; Clear WRTLOC before DESCRIB
- ENDIF
- ;
- IF DESCRIB
- CALL ASK ; If yes, ask for description of file
- ENDIF
- ;
- ; Finished, clean up and return to CP/M, send thank-you and timeon
- ; messages if enabled.
- ;
- EXIT: XRA A
- STA CONONL ; Reset 'console only' flag for timeon
- ;
- IF WRTLOC
- CALL RSTLCK ; Clear WRTLOC
- ENDIF
- ;
- NOBYE2: CALL UNINIT ; Reset vectors (if needed)
- LDA OLDDRV ; Restore the original drive
- CALL RECDRX
- LDA OLDUSR ; Restore the original number
- CALL RECARE
- LXI D,TBUF ; Reset to default DMA address
- MVI C,SETDMA
- CALL BDOS
- LDA OPTSAV ; If so check option flag
- CPI 'R' ; Was it 'R' for receive
- JNZ EXIT1 ; If not, then skip this,
- CALL ILPRT ; And print
- DB CR,LF,'Thanks for the upload',CR,LF,0
- ;
- IF SYSNEW
- CALL ILPRT
- DB CR,LF,'(Upload set as SYS file and cannot be examined'
- DB CR,LF,'or downloaded until released by the SYSOP....)'
- DB CR,LF,0
- ENDIF
- ;
- IF B3RTC AND NOT (MBMXT OR BYEBDOS)
- CALL ILPRT ; And print
- DB CR,LF,'Time online is not increased during uploads'
- DB CR,LF,0
- ENDIF
- ;
- IF MBFMSG
- LDA MSGFLG ; Was this a "XMODEM RM" upload?
- ORA A
- JZ NOTMSG
- CALL BYECHK
- JNZ EXIT1
- CALL ILPRT
- DB CR,LF
- DB 'Loading MFMSG for message input, please stand by...'
- DB CR,LF,LF,0
- LXI D,81H ; Our buffer starts at 81H
- MVI C,0 ; C=# of characters (stuff at 80H)
- CALL MBDFIL
- STA 80H ; Save # of chars in 80H
- MVI A,0C2H ; Stuff C2H (JNZ instruction)
- STA 0000H
- ORA A ; Make sure NZ flag set so JNZ will jump
- JMP 0000H
- ;
- NOTMSG: ENDIF ; MBFMSG
- ;
- IF MBFMSG AND NOT MBDESC
- JMP EXIT1 ; If not message upload, exit
- ENDIF
- ;
- ;-----------------------------------------------------------------------
- ;
- IF MBDESC AND ZCPR2 AND (NOT ASKSYS)
- LDA WHEEL ; If its the Sysop, don't ask
- ORA A ; For a description because he
- JNZ EXIT1 ; Might want to batch recv files
- ENDIF
- ;
- IF MBDESC AND NDESC
- LDA NDSCFL ; If user picked "N" option
- ORA A ; allow them to skip upload
- JNZ EXIT1 ; descript
- ENDIF
- ;
- IF MBDESC
- CALL BYECHK
- JNZ EXIT1
- CALL ILPRT
- DB CR,LF
- DB 'Loading MBBS for upload description, '
- DB 'please stand by...',CR,LF,LF,0
- ENDIF
- ;
- IF MBDESC AND NEWPRV
- MVI A,'P' ; ALL "NEW UPLOADS:" private to start
- ENDIF
- ;
- IF MBDESC AND NOT NEWPRV
- LDA PRVTFL ; 80H=0 if public, "P" if private
- ENDIF
- ;
- IF MBDESC
- STA 80H ; Stuff "private" flag in page zero
- LXI D,82H ; Our buffer starts at 82H
- MVI C,0 ; C=# of characters (stuff at 81H)
- LXI H,MBDSH ; Heading ("NEW UPLOAD: ")
- ;
- MBDSHP: MOV A,M
- CPI 0
- JZ MBDFS
- CALL MBDPUT
- INX H
- JMP MBDSHP
- ;
- MBDFS: CALL MBDFIL
- STA 81H ; Save # of chars in 81H
- MVI A,0CAH ; Stuff CAH (JZ instruction)
- STA 0000H
- XRA A ; Make sure Z flag set so JZ will jump
- JMP 0000H
- ;
- MBDSH: DB 'NEW UPLOAD: ',0 ; Heading stuffed ahead of filename
- ENDIF ; MBDESC
- ;
- IF MBDESC OR MBFMSG
- MBDFIL: LDA FCB ; Get drive code
- ORA A ; Check it
- JNZ MWDRV ; If auto login, use it
- LDA DSKSAV ; Else, get current disk
- INR A
- ;
- MWDRV: ADI 'A'-1
- CALL MBDPUT ; Stuff in command line buffer
- LDA USRSAV ; Get user #
- CPI 10 ; Are we 0-9 or above?
- JC US0 ; Must be 0-9
- ORA A ; Clear flags
- DAA ; Decimal adjust
- RAR ; Shift down tens digit
- RAR
- RAR
- RAR
- ANI 0FH ; Mask out tens digit
- ADI '0' ; Make it ASCII
- CALL MBDPUT
- LDA USRSAV
- ORA A ; Clear flags
- DAA ; Decimal adjust
- ANI 0FH ; Mask out singles digit
- ;
- US0: ADI '0' ; Make it ASCII
- CALL MBDPUT
- MVI A,':' ; Put in a colon
- CALL MBDPUT
- LXI H,FCB+1 ; Stuff in filename without spaces
- MVI B,8
- ;
- DESNM: MOV A,M
- CPI ' '
- CNZ MBDPUT
- INX H
- DCR B
- JNZ DESNM
- MVI A,'.'
- CALL MBDPUT
- MVI B,3
- ;
- DESNM3: MOV A,M
- CPI ' '
- JZ DESGO
- CPI 0
- JZ DESGO
- CALL MBDPUT
- INX H
- DCR B
- JNZ DESNM3
- ;
- DESGO: MOV A,C
- RET
- ;
- MBDPUT: ANI 7FH ; Strip off any high bits
- STAX D ; Short routine to stuff A in (DE) and
- INX D ; Increment pointer and character count
- INR C
- RET
- ENDIF ; MBDESC OR MBFMSG
- ;
- ;-----------------------------------------------------------------------
- ;
- EXIT1: IF (TIMEON OR B3TOS) AND (NOT LUXMOD) AND TOSEXIT
- CALL TIME ; Tell user how long he's been on
- ENDIF
- ;
- IF (BYEBDOS AND (NOT TIMEON)) AND TOSEXIT AND (NOT LUXMOD)
- MVI C,BDPTOS ; Print time on system
- CALL BDOS
- ENDIF
- ;
- EXIT2: XRA A
- LHLD STACK
- SPHL
- RET
- ;
- ; Check local console status in order to let BYE function keys work in
- ; MBYE and possibly other BYE versions also. (Your BYE must check for
- ; console function keys in MSTAT.)
- ;
- IF CONFUN
- FUNCHK: PUSH B ; Save everything
- PUSH D ; (to be safe)
- PUSH H
- PUSH PSW
- ;
- CONCHK: CALL 0000H ; Address patched in by START
- ;
- ENDIF
- ;
- IF CONFUN AND SYSABT
- ORA A ; If SYSABT set, check for
- JZ CONDNE ; CANCEL (^X) typed by sysop
- MVI C,RDCON
- CALL BDOS
- CPI CAN
- JNZ CONDNE
- STA SYSABF
- ENDIF
- ;
- CONDNE:
- IF CONFUN
- POP PSW ; For BIOS JMP CONSTAT
- POP H
- POP D
- POP B ; Restore everything
- RET ; And return
- ENDIF
- ;
- ; Get Disk and User from DUSAVE and log in if valid.
- ;
- GETDU: CALL CHKFSP ; See if a file name is included
- SHLD SAVEHL ; Save location of the filename
- LDA PRVTFL ; Uploading to a private area?
- ORA A
- JNZ TRAP ; If yes, going to a specified area
- LXI H,DUSAVE ; Point to drive/user
- LDA OLDDRV ; Get current drive
- STA DUD
- ADI 'A'
- STA RCVDRV
- MOV A,M ; Get 1st character
- CPI '0'
- JC GETDU1
- CPI '9'+1
- JC NUMER1
- ;
- GETDU1: STA RCVDRV ; Allows SYSOP to upload to any drive
- CPI 'A'-1
- JC NUMER ; Satisfied with current drive
- SUI 'A'
- STA DUD
- ;
- IF ZCPR2
- LDA WHEEL ; SYSOP using the system?
- ORA A
- LDA DUD ; Get the value back (flags stay)
- JNZ GETDU2 ; If sysop, all things are possible
- ENDIF
- ;
- IF NOT USEMAX
- CPI MAXDRV
- JNC ILLDU ; Drive selection not available
- ENDIF
- ;
- IF USEMAX
- PUSH H
- LXI H,DRIVMAX ; Point to max drive byte
- INR M
- CMP M ; And check it
- PUSH PSW ; Save flags from the CMP
- DCR M ; Restore max drive to normal
- POP PSW ; Restore flags from the CPM
- JNC ILLDU
- POP H
- ENDIF
- ;
- GETDU2: INX H ; Get 2nd character
- ;
- NUMER: MOV A,M
- CPI ':'
- JZ OK4 ; Colon for drive only, no user number
- CALL CKNUM ; Check if numeric
- ;
- NUMER1: SUI '0' ; Convert ASCII to binary
- STA DUU ; Save it
- INX H ; Get 3rd character if any
- MOV A,M
- CPI ':'
- JZ OK1
- LDA DUU
- CPI 1 ; Is first number a '1'?
- JNZ ILLDU
- MOV A,M
- CALL CKNUM
- SUI '0'-10
- STA DUU
- INX H ; Get 4th (and last character) if any
- MOV A,M
- CPI ':'
- JNZ ILLDU
- ;
- OK1: LDA OPTSAV ; Get the option back
- CPI 'R' ; Receiving a file?
- LDA DUU ; Get desired user area
- JZ OK2 ; Yes, can not use special download area
- LDA DUD ; Get desired drive
- CPI SPLDRV-'A' ; Special download drive requested?
- LDA DUU ; Get user area requested
- JNZ OK2 ; If none, exit
- CPI SPLUSR ; Special download area requested?
- JZ OK3 ; If yes, process request
- ;
- OK2: IF ZCPR2
- LDA WHEEL ; SYSOP using the system?
- ORA A
- LDA DUU ; Restore desired user area
- STA RCVUSR ; Allows SYSOP to upload anywhere
- JNZ OK3 ; If yes, let him have all user areas
- ENDIF
- ;
- IF NOT USEMAX
- CPI MAXUSR+1 ; Check for maximum user download area
- JNC ILLDU ; Error if more (and not special area)
- ENDIF
- ;
- IF USEMAX
- PUSH H
- LXI H,USRMAX ; Point at maximum user byte
- CMP M ; And check it
- JNC ILLDU
- POP H
- ENDIF
- ;
- OK3: MOV E,A
- ;
- IF NOT SETAREA
- STA NOTUSR+1 ; Store requested user area
- MVI A,3EH ; 'MVI A,--' instruction
- STA NOTUSR
- ENDIF
- ;
- MVI C,SETUSR
- CALL BDOS ; Set to requested user area
- ;
- OK4: LDA DUD ; Get drive
- MOV E,A
- ;
- IF NOT SETAREA
- ADI 'A'
- STA NOTDRV+1 ; Store requested drive
- MVI A,3EH ; 'MVI A,--' instruction
- STA NOTDRV
- ENDIF
- ;
- MVI C,SELDSK
- CALL BDOS ; Set to requested drive
- ;
- XIT: JMP TRAP ; Now find file selected
- ;
- ; Shows available space on upload disk/area. Uses KDRV data area which
- ; must be loaded before calling this routine. (So KSHOW will work with
- ; user specified disk if SETAREA equate is not set YES.)
- ;
- ; Print the free space remaining for the received file
- ;
- CPMVER EQU 0CH
- CURDPB EQU 1FH
- GALLOC EQU 1BH
- SELDSK EQU 0EH
- GETFRE EQU 46
- ;
- KDRV: DB 0 ; Drive stored here before calling KSHOW
- ;
- KSHOW: LDA KDRV ; Get drive ('A','B','C',etc.)
- SUI 41H ; Convert to numeric (0,1,2,etc.)
- MOV E,A ; Stuff in E for BDOS call
- MVI C,SELDSK ; Select the directory drive to retrieve
- CALL BDOS ; The proper allocation vector
- MVI C,CURDPB ; It's 2.X or MP/M...request DPB
- CALL BDOS
- INX H
- INX H
- MOV A,M ; Get block shift
- STA BLKSHF
- INX H ; Bump to block mask
- MOV A,M
- INX H
- INX H
- MOV E,M ; Get max block #
- INX H
- MOV D,M
- XCHG
- SHLD BLKMAX ; Save it
- XCHG
- INX H
- MOV E,M ; Get directory size
- INX H
- MOV D,M
- XCHG
- ;
- ; Calculate # of K free on selected drive
- ;
- MVI C,CPMVER ; Get CP/M version number
- CALL BDOS
- MOV A,L ; Get returned version number
- CPI 30H ; 3.0?
- JC FREE20 ; Use old method if not
- LDA KDRV ; Get drive #
- SBI 'A' ; Change from ASCII to binary
- MOV E,A ; Use new Compute Free Space BDOS call
- MVI C,GETFRE
- CALL BDOS
- MVI C,3 ; Answer is a 24-bit integer
- ;
- FRE3L1: LXI H,80H+2 ; Answer is in 1st 3 bytes of DMA adr
- MVI B,3 ; Convert it from sectors to K
- ORA A ; By dividing by 8
- ;
- FRE3L2: MOV A,M
- RAR
- MOV M,A
- DCX H
- DCR B
- JNZ FRE3L2 ; Loop for 3 bytes
- DCR C
- JNZ FRE3L1 ; Shift 3 times
- LHLD 80H ; Now get result in K
- JMP SAVFRE ; Go store it
- ;
- FREE20: MVI C,GALLOC ; Get address of allocation vector
- CALL BDOS
- XCHG
- LHLD BLKMAX ; Get its length
- INX H
- LXI B,0 ; Init block count to 0
- ;
- GSPBYT: PUSH D ; Save alloc address
- LDAX D
- MVI E,8 ; Set to process 8 blocks
- ;
- GSPLUP: RAL ; Test bit
- JC NOTFRE
- INX B
- ;
- NOTFRE: MOV D,A ; Save bits
- DCX H ; Count down blocks
- MOV A,L
- ORA H
- JZ ENDALC ; Quit if out of blocks
- MOV A,D ; Restore bits
- DCR E ; Count down 8 bits
- JNZ GSPLUP ; Do another bit
- POP D ; Bump to next byte..
- INX D ; Of alloc. vector
- JMP GSPBYT ; Process it
- ;
- ENDALC: POP D ; Clear stack of allocation vector ptr.
- MOV L,C ; Copy block to HL
- MOV H,B
- LDA BLKSHF ; Get block shift factor
- SUI 3 ; Convert from sectors to K
- JZ SAVFRE ; Skip shifts if 1K blocks...
- ; ; Return free in HL
- FREKLP: DAD H ; Multiply blocks by K/BLK
- DCR A
- JNZ FREKLP
- ;
- ; Print the amount of free space remaining on the selected drive
- ;
- SAVFRE: CALL DECOUT
- CALL ILPRT
- DB 'k available for uploads',0
- RET
- ;
- ; Log into drive and user (if specified). If none mentioned, it falls
- ; through to 'TRAP' routine for normal use.
- ;
- LOGDU: LXI H,TBUF ; Point to default buffer command line
- MOV B,M ; Store number of characters in command
- INR B ; Add in current location
- ;
- LOG1: CALL CHKSP ; Skip spaces to find 1st command
- JZ LOG1
- ;
- LOG2: CALL CHKSP ; Skip 1st command (non-spaces)
- JNZ LOG2
- INX H
- CALL CHKFSP ; Skip spaces to find 2nd command
- SHLD SAVEHL ; Save start address of the 2nd command
- ;
- ; Now point to the first byte in the argument, i.e., if it was of format
- ; similar to: B6:HELLO.DOC then we point at the drive character 'B'.
- ;
- LXI D,DUSAVE
- MVI C,4 ; Drive/user is 4 characters maximum
- ;
- CPLP: MOV A,M
- CPI ' '+1 ; Space or return, finished
- JC TRAP
- STAX D
- INX H
- INX D
- CPI ':'
- JZ GETDU ; If colon, get drive/user and log in
- DCR B ; One less position to check
- DCR C ; One less to go
- JNZ CPLP
- ;
- ; Check for no file name or ambiguous name
- ;
- TRAP: CALL MOVEFCB ; Move the filename into the file block
- LXI H,FCB+1 ; Point to file name
- MOV A,M ; Get first character of file name
- CPI ' ' ; Any there?
- JNZ ATRAP ; Yes, check for ambigous file name
- ;
- NFN: CALL ERXIT ; Print message, exit
- DB '++ No file name requested ++$'
- ;
- ATRAP: MVI B,11 ; 11 characters to check
- ;
- TRLOOP: MOV A,M ; Get char from FCB
- CPI '?' ; Ambiguous?
- JZ TRERR ; Yes, exit with error message
- CPI '*' ; Even more ambiguous?
- JZ TRERR ; Yes, exit with error message
- INX H ; Point to next character
- DCR B ; One less to go
- JNZ TRLOOP ; Not done, check some more
- RET
- ;
- TRERR: CALL ERXIT ; Print message, exit
- DB '++ Wild-card options are not valid ++$'
- ;
- CKNUM: CPI '0'
- JC ILLDU ; Error if less than ascii '0'
- CPI '9'+1
- RC ; Error if more than ascii '9'
- ;
- ILLDU: CALL ERXIT
- DB '++ Improper drive/user combination ++$'
- ;
- ; Receive a record - returns with carry bit set if EOT received
- ;
- RCVRECD:XRA A ; Initialize error count to zero
- STA ERRCT
- ;
- RCVRPT: IF CONFUN ; Check for function key?
- CALL FUNCHK ; Yeah, why not?
- ENDIF
- ;
- IF CONFUN AND SYSABT
- LDA SYSABF ; If SYSABT option, check
- ORA A ; to see if Abort
- JNZ RCVSABT ; If so, bail out now...
- ENDIF
- ;
- MVI B,10-1 ; 10-second timeout
- CALL RECV ; Get any character received
- JC RCVSTOT ; Timeout
- ;
- RCVRPTB:CPI SOH ; 'SOH' for a 128-byte block?
- JZ RCVSOH ; Yes
- CPI STX ; A 1024-byte block?
- JZ RCVSTX ;
- ORA A ;
- JZ RCVRPT ; Ignore nulls
- CPI CRC ; Ignore our own 'CRC' if needed
- JZ RCVRPT
- CPI NAK ; Ignore our own 'NAK' if needed
- JZ RCVRPT
- CPI CAN ; CANcel?
- JZ CANRCV ; (look for CAN CAN)
- CPI EOT ; End of transfer?
- STC ; Return with carry set if 'EOT'
- RZ
- ;
- ; Didn't get SOH or EOT - or - didn't get valid header - purge the line,
- ; then send nak
- ;
- RCVSERR:MVI B,1 ; Wait for 1 second
- CALL RECV ; After last char. received
- JNC RCVSERR ; Loop until sender done
- LDA FRSTIM ; Is it the first time?
- ORA A
- MVI A,NAK
- JNZ RCVSER2 ; If not first time, send NAK
- ;
- ; First time through...do crc/1k/checksum select
- ;
- LDA CRCFLG ; Get 'CRC' flag
- ORA A ; 'CRC' in effect?
- MVI A,NAK ; Put 'NAK' in accum
- JNZ RCVSER2 ; And go send it
- MVI A,CRC ; Tell sender 'CRC' is in effect
- CALL SEND
- LDA KFLAG ; Did we want 1k protocol?
- ORA A
- JZ RCVSERX ; No, just send the "C"
- MVI A,'K' ; Else send a C and a K
- ;
- RCVSER2:CALL SEND ; The 'NAK' or 'CRC' request
- ;
- RCVSERX:LDA ERRCT ; Abort if
- INR A ; We have reached
- STA ERRCT ; The error
- CPI 10 ; Limit?
- JZ RCVSABT ; Yes, abort
- CPI 5 ; Have we tried 5 times already?
- JNZ RCVRPT ; No, try again with same mode
- MVI A,'C' ; Else flip to checksum mode if CRC
- STA CRCFLG
- JMP RCVRPT ; And try again
- ;
- ; Error limit exceeded, so abort
- ;
- CANRCV: CALL DELAY ; Wait 100ms
- CALL RCVRDY ; Character waiting?
- JZ RCVRPT ; If so, no pause, skip CANcel
- MVI B,4
- CALL RECV ; Else wait for 2nd character
- JC RCVSERR ; If no second character received, error
- CPI CAN
- JNZ RCVRPTB ; If second character not CAN, check it
- ;
- RCVSABT:CALL CLOSFIL ; Close file
- CALL ILPRT
- DB CR,LF,CR,LF,'++ Receive cancelled ++',0
- CALL DELFILE ; Delete received file
- CALL ERXIT ; Print second half of message
- DB '++ Partial file deleted ++$'
- ;
- ; Deletes the received file (used if receive aborts)
- ;
- DELFILE:LXI D,FCB ; Point to file
- MVI C,DELET ; Get function
- CALL BDOS ; Delete it
- INR A ; Delete ok?
- RNZ ; Yes, return
- CALL ERXIT ; No, abort
- DB '++ Can''t delete received file ++$'
- ;
- ; Timed out on receive
- ;
- RCVSTOT:JMP RCVSERR ; Bump error count, etc.
- ;
- ; Got SOH or STX - get block number, block number complemented
- ;
- RCVSOH: LXI H,128 ; 128 bytes in this block
- XRA A ; Zero-out KFLAG
- JMP RCVHDR
- ; ;
- RCVSTX: MVI A,0FFH ; Set KFLAG true
- LXI H,1024 ; 1024 bytes in block
- ;
- RCVHDR: SHLD BLKSIZ ; Store block size for later
- STA KFLAG ; Set KFLAG as appropriate
- MVI B,1 ; Timeout = 1 sec
- MVI A,1 ; Need something to store at FRSTIM
- STA FRSTIM ; Indicate first 'SOH' received
- CALL RECV ; Get record
- JC RCVSTOT ; Got timeout
- MOV D,A ; D=block number
- MVI B,1 ; Timeout = 1 sec
- CALL RECV ; Get complimented record number
- JC RCVSTOT ; Timeout
- CMA ; Calculate the complement
- CMP D ; Good record number?
- JZ RCVDATA ; Yes, get data
- ;
- ; Got bad record number
- ;
- JMP RCVSERR ; Bump error count
- ;
- RCVDATA:MOV A,D ; Get record number
- STA RCVRNO ; Save it
- MVI C,0 ; Initialize checksum
- CALL CLRCRC ; Clear CRC counter
- LHLD BLKSIZ ; Get block size,
- XCHG ; And put in DE pair to initialize count
- LHLD RECPTR ; Get buffer address
- ;
- RCVCHR: MVI B,1 ; 1 sec timeout
- CALL RECV ; Get the character
- JC RCVSTOT ; Timeout
- MOV M,A ; Store the character
- INX H ; Point to next character
- DCX D ; Done?
- MOV A,D
- ORA E
- JNZ RCVCHR ; No, loop if <= BLKSIZ
- LDA CRCFLG ; Get 'CRC' flag
- ORA A ; 'CRC' in effect?
- JZ RCVCRC ; Yes, to receive 'CRC'
- ;
- ; Verify checksum
- ;
- MOV D,C ; Save checksum
- MVI B,1 ; Timeout length
- CALL RECV ; Get checksum
- JC RCVSTOT ; Timeout
- CMP D ; Checksum ok?
- JNZ RCVSERR ; No, error
- ;
- ; Got a record, it's a duplicate if = previous, or OK if = 1 + previous
- ; record.
- ;
- CHKSNUM:LDA RCVRNO ; Get received
- MOV B,A ; Save it
- LDA RECDNO ; Get previous
- CMP B ; Prev repeated?
- JZ RECVACK ; 'ACK' to catch up
- INR A ; Calculate next record number
- CMP B ; Match?
- JNZ ABORT ; No match - stop sender, exit
- RET ; Carry off - no errors
- ;
- ; 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: MVI E,2 ; Number of bytes to receive
- ;
- RCVCRC2:MVI B,1 ; 1 sececond timeout
- CALL RECV ; Get crc byte
- JC RCVSTOT ; Timeout
- DCR E ; Decrement the number of bytes
- JNZ RCVCRC2 ; Get both bytes
- CALL CHKCRC ; Check received CRC against calc'd CRC
- ORA A ; Is CRC okay?
- JZ CHKSNUM ; Yes, go check record numbers
- JMP RCVSERR ; Go check error limit and send NAK
- ;
- ; Previous record repeated, due to the last ACK being garbaged. ACK it
- ; so sender will catch up
- ;
- RECVACK:CALL SENDACK ; Send the ACK
- JMP RCVRECD ; Get next block
- ;
- ; Send an ACK for the record
- ;
- SENDACK:MVI A,ACK ; Get 'ACK'
- CALL SEND ; And send it
- RET
- ;
- ; Send the record header
- ;
- ; Send [(SOH) or (STX)] (block number) (complemented block number)
- ;
- SENDHDR:LDA KFLAG ; 1k blocks enabled?
- ORA A
- JNZ SENDBIG ; Yes
- MVI A,SOH ; 128 blocks, use SOH
- JMP MORHDR ; Send it
- ;
- SENDBIG:MVI A,STX ; 1024 byte block - Start of Header
- ;
- MORHDR: CALL SEND ; One Start of Header or another
- LDA RECDNO ; Then send record number
- CALL SEND
- LDA RECDNO ; Then record number
- CMA ; Complemented
- CALL SEND ; Record number
- RET ; From SENDHDR
- ;
- ; Send the data record
- ;
- SENDREC:MVI C,0 ; Initialize checksum
- CALL CLRCRC ; Clear the 'CRC' counter
- LDA KFLAG ; Are we using 1K blocks?
- ORA A
- JNZ SEND1 ; Yes, 1k size
- LXI D,128 ; Initialize small count
- JMP SEND2
- ;
- SEND1: LXI D,1024 ; Initialize big count
- ;
- SEND2: LHLD RECPTR ; Get buffer address
- ;
- SENDC: MOV A,M ; Get a character
- CALL SEND ; Send it
- INX H ; Point to next character
- DCX D ; Done?
- MOV A,D
- ORA E
- JNZ SENDC ; Loop if <=Blocksize
- RET ; From SENDREC
- ;
- ; Send the checksum
- ;
- SENDCKS:MOV A,C ; Send the
- CALL SEND ; Checksum
- RET ; From 'SENDCKS'
- ;
- ; Send the two Cyclic Redundancy Check characters. Call FINCRC to cal-
- ; culate the CRC which will be in 'DE' upon return.
- ;
- SENDCRC:CALL FINCRC ; Calculate the 'CRC' for this record
- MOV A,D ; Put first 'CRC' byte in accumulator
- CALL SEND ; Send it
- MOV A,E ; Put second 'CRC' byte in accumulator
- CALL SEND ; Send it
- XRA A ; Set zero return code
- RET
- ;
- ; Returns with carry clear if ACK received. If an ACK is not received,
- ; the error count is incremented, and if less than 10, carry is set and
- ; the record is resent. if the error count is 10, the program aborts.
- ; waits 12 seconds to avoid any collision with the receiving station.
- ;
- GETACK: MVI B,10 ; Wait 10 seconds max
- CALL RECVDG ; Receive with garbage collect
- JC ACKERR ; Timed out
- CPI ACK ; Was it an 'ACK' character?
- RZ ; Yes, return
- ;
- IF RETRY
- CPI NAK ; Was it an authentic 'NAK'?
- JNZ GETACK ; Ignore if neither 'ACK' nor 'NAK'
- ENDIF
- ;
- ; Timeout or error on ACK - bump error counters then resend the record
- ; if error limit is not exceeded.
- ;
- ACKERR: LDA ERRCT ; Get count
- INR A ; Bump it
- STA ERRCT ; Save back
- LHLD TOTERR ; Total errors this run
- INX H
- SHLD TOTERR ; Update and put back
- CPI 10 ; At limit?
- RC ; If not, go resend the record
- ;
- ; Reached error limit
- ;
- CALL ERXIT
- DB '++ Send file cancelled ++$'
- ;
- CHKERR: LDA KFLAG
- ORA A ; Check to see if in 1024 mode
- RZ ; No, so don't bother with rest
- LHLD TOTERR ; Check on errors to date...
- MOV A,L ; Skip if less than DWNSHFT error so far
- CPI DWNSHFT
- RC ; Not enough errors to bother with yet
- XCHG ; Total errors to DE
- LHLD RECDNO ; Get records sent so far
- CALL DVHLDE ; Divide by errors so far
- MOV A,C ; Take low order byte of quotient...
- CPI DWNSHFT ; Compare to specified ratio...
- RNC ; Better ratio than needed, so return
- XRA A ; Noisy line, let's try
- STA KFLAG ; 128 byte blocks
- RET
- ;
- ABORT: LXI SP,STACK
- ;
- ABORTL: MVI B,1 ; One second without characters
- CALL RECV
- JNC ABORTL ; Loop until sender done
- MVI A,CAN ; CTL-X
- CALL SEND ; Stop sending end
- ;
- ABORTW: MVI B,1 ; One second without chracters
- CALL RECV
- JNC ABORTW ; Loop until sender done
- MVI A,CR ; Get a space...
- CALL SEND ; To clear out CTL-X
- CALL ERXIT ; Exit with abort message
- DB '++ XMODEM aborted ++$'
- ;
- ; Increment record number
- ;
- INCRRNO:PUSH H
- LHLD RECDNO ; Increment record number
- INX H
- SHLD RECDNO
- LHLD VRECNO ; Update Virtual Record Number
- LDA KFLAG ; Was last record a 1024 byte one?
- ORA A ;
- JZ INCRR1 ; Just handled an normal 128 byte record
- INX H ; Otherwise, must have be a BIG one, so
- INX H ; Seven ...
- INX H
- INX H
- INX H
- INX H
- INX H ; Plus
- ;
- INCRR1: INX H ; One
- SHLD VRECNO ; Equals the new virtual record number
- ;
- IF NOT (USECON OR BYEBDOS)
- LHLD CONOUT+1 ; Check to see if showing count on crt
- MOV A,H ; If both zero, user did not fill out
- ORA L ; 'CONOUT: jmp 0000H' in patch area
- JZ INCRN5 ; With his own console output address
- ENDIF
- ;
- ; Display the record count on the local CRT if "CONOUT" was filled in by
- ; the implementor
- ;
- MVI A,1
- STA CONONL ; Set local only
- LDA OPTSAV ; See if receive or send mode
- CPI 'R'
- JZ RMSG
- CALL ILPRT
- DB CR,'Sending # ',0
- JMP REST
- ;
- RMSG: CALL ILPRT
- DB CR,'Received # ',0
- ;
- REST: LDA KFLAG
- ORA A
- JZ REST1
- LHLD VRECNO
- DCX H ; Stupid but simple way to subtract 7
- DCX H ; Without dying on high-byte
- DCX H
- DCX H
- DCX H
- DCX H
- DCX H
- CALL DECOUT
- MVI A,'-'
- CALL CTYPE
- ;
- REST1: LHLD VRECNO ; Virtual record number to minimize
- CALL DECOUT ; Confusion between 1K and normal
- CALL ILPRT ; 'record' sizes (always in terms of
- DB ' ',18H,0 ; 128-byte records)
- ;
- IF CONFUN ; Check for sysop console function
- CALL FUNCHK ; Keys if CONFUN EQU YES
- ENDIF
- ;
- INCRN5: POP H ; Here from above if no CONOUT
- RET
- ;
- ; See if file exists - if it exists, ask for a different name.
- ;
- CHEKFIL: IF NOT SETAREA
- LDA PRVTFL ; Receiving in private area?
- ORA A
- CNZ RECAREA ; If yes, set drive and user area
- ENDIF
- ;
- IF SETAREA
- CALL RECAREA ; Set the designated area up
- ENDIF
- ;
- LXI D,FCB ; Point to control block
- MVI C,SRCHF ; See if it
- CALL BDOS ; Exists
- INR A ; Found?
- RZ ; No, return
- CALL ERXIT ; Exit, print error message
- DB '++ File exists, use a different name ++$'
- ;
- ; Makes the file to be received
- ;
- MAKEFIL:XRA A ; Set extent and record number to 0
- STA FCBEXT
- STA FCBRNO
- LXI D,FCB ; Point to FCB
- MVI C,MAKE ; Get BDOS FNC
- CALL BDOS ; To the make
- INR A ; 0FFH=bad?
- RNZ ; Open ok
- ;
- ; Directory full - can't make file
- ;
- CALL ERXIT
- DB '++ Error: can''t make file -'
- DB ' directory may be full? ++$'
- ;
- ; Computes record count, and saves it until a successful file-open.
- ;
- CNREC: MVI C,CFSIZE ; Computes file size
- LXI D,FCB
- CALL BDOS ; Read first
- LHLD RANDOM ; Get the file size
- SHLD RCNT ; Save total record count
- MOV A,H
- ORA L
- RNZ ; Return if not zero length
- ;
- NONAME: CALL ERXIT
- DB '++ File not found, check DIR ++','$'
- ;
- ; Opens the file to be sent
- ;
- OPENFIL:XRA A ; Set extent and rec number to 0
- STA FCBEXT ; For proper open
- STA FCBRNO
- LXI D,FCB ; Point to file
- MVI C,OPEN ; Get function
- CALL BDOS ; Open it
- INR A ; Open ok?
- JNZ OPENOK ; If yes, exit
- LDA OPTSAV ; Get command line option
- CPI 'L' ; Want to send a library file?
- JNZ NONAME ; Exit, if not
- CALL ILPRT
- DB CR,LF,'++ Member not found, check DIR ++',CR,LF,0
- JMP OPTERR
- ;
- ; Check to see if the SYSOP has tagged a .LBR file for NO SEND - if so,
- ; only allow XMODEM L NAME to transfer individual files. If requested
- ; file is a $SYS file or has any high bits set, disallow unless WHEEL.
- ;
- OPENOK: IF ZCPR2
- LDA WHEEL ; Check wheel status if ZCPR2
- ORA A ; Is it zero
- JNZ OPENOK1 ; If non-zero skip all restrictions
- ENDIF
- ;
- IF DWNTAG
- LDA FCB+3 ; Regardless of access byte?
- ANI 80H ; If so,
- JNZ OPENOK1 ; Allow it if F3 set regardless
- ENDIF
- ;
- IF ACCESS
- CALL BYECHK
- JNZ SNDFOK
- LHLD 0001H ; Get JMP COLDBOOT
- DCX H
- MOV D,M
- DCX H
- MOV E,M
- LXI H,ACBOFF ; + ACBOFF
- DAD D
- MOV A,M ; = ACCESS byte address
- ANI ACDNLD ; Test download access bit
- JNZ SNDFOK ; If bit on, downloads OK
- CALL ERXIT
- DB 'Sorry, but you are not allowed to download files '
- DB 'at this time...','$'
- ENDIF
- ;
- SNDFOK: IF NOSYS AND NOT LUXMOD
- LDA FCB+10
- ANI 80H
- JNZ NONAME ; If $SYS then fake a "file not found"
- ENDIF
- ;
- IF OK2400 AND TAGLBR AND NOT LUXMOD
- LDA MSPEED ; Check baudrate byte set by BYE
- CPI 6 ; Is caller >=2400 baud?
- JNC OPENOK1 ; If so - let em send the file (PAT2)
- ENDIF
- ;
- IF TAGLBR AND NOT LUXMOD
- LDA OPTSAV ; Has SYSOP tagged a large .LBR file?
- CPI 'L' ; Using XMODEM L?
- JZ OPENOK1 ; Yes, skip tag test
- LDA FCB+1 ; First char of file name
- ANI 80H ; Check bit 7 for tag
- JZ OPENOK1 ; If on, file cannot be sent
- ENDIF
- ;
- IF TAGLBR AND NOT LUXMOD
- OPENOT: CALL ERXIT ; Exit with message
- DB '++ File is not for distribution, sorry. ++',CR,LF,CR,LF
- DB 'For large LBR files please use XMODEM L or LUX',CR,LF
- DB 'to transfer individual member files','$'
- ENDIF
- ;
- OPENOK1:LDA OPTSAV
- CPI 'L'
- JNZ OPN2
- LXI D,TBUF
- MVI C,SETDMA
- CALL BDOS
- MVI C,READ
- LXI D,FCB
- CALL BDOS
- ORA A ; Read ok?
- JNZ LERROR
- LHLD TBUF+14 ; Value in buffer where DIRSIZE is
- SHLD DIRSZ
- LXI H,TBUF
- MOV A,M
- ORA A
- JZ CKDIR ; Check directory present?
- ;
- NOTLBR: CALL ERXIT
- DB '++ Bad .LBR directory, notify Sysop ++','$'
- ;
- ; Check to see if there is a .LBR file directory with that name and
- ; complain if not.
- ;
- CKDIR: MVI B,11 ; Maximum length of file name
- MVI A,' ' ; First entry must be all blanks
- INX H
- ;
- CKDLP: CMP M
- JNZ NOTLBR
- DCR B
- INX H
- JNZ CKDLP
- ;
- ; The first entry in the .LBR directory is indeed blank. Now see if the
- ; directory size is more than 0.
- ;
- MOV D,M ; Get directory starting location
- INX H ; Which must be 0000H...
- MOV A,M
- ORA D
- JNZ NOTLBR ; Directory does not start in record 0
- INX H
- MOV A,M ; Get size of directory
- INX H
- ORA M
- JZ NOTLBR ; Directory must be >0 records!
- LXI H,TBUF ; Point to directory
- ;
- ; The next routine checks the .LBR directory for the specified member.
- ; Name one sector at a time.
- ;
- CMLP: MOV A,M ; Get member active flag
- ORA A ; 00=active, anything else can be...
- MVI B,11 ; Regarded as invalid (erased or blank)
- INX H ; Point to member name
- JNZ NOMTCH ; No match if inactive entry
- ;
- CKLP: LDAX D ; Now compare the file name specified...
- CMP M ; Against the member file name
- JNZ NOMTCH ; Exit loop if no match found
- INX H
- INX D
- DCR B
- JNZ CKLP ; Check all 11 characters
- MOV E,M ; Got the file - get file address
- INX H
- MOV D,M
- XCHG
- SHLD INDEX ; Save file address in .LBR
- XCHG
- INX H
- MOV E,M ; Get the file size
- INX H
- MOV D,M
- XCHG
- DCX H
- SHLD RCNT ; Save size a # of records
- LHLD INDEX ; Get file address
- SHLD RANDOM ; Place it into random field
- XRA A
- STA RANDOM+2 ; Must zero the 3rd byte
- STA FCBRNO ; Also zero FCB record #
- LXI D,FCB ; Point to FCB of .LBR file
- MVI C,RRDM ; Read random
- CALL BDOS
- JMP OPENOK3 ; No need to error check
- ;
- ; Come here if no file name match and another sector is needed
- ;
- NOMTCH: INX H ; Skip past the end of the file entry
- DCR B
- JNZ NOMTCH
- LXI B,20 ; Point to next file entry
- DAD B
- LXI D,MEMFCB ; Point to member name again
- MOV A,H ; See if we checked all 4 entries
- ORA A
- JZ CMLP ; No, check next
- LHLD DIRSZ ; Get directory size
- MOV A,H
- ORA L
- JNZ INLBR ; Continue if still more to check
- CALL ERXIT
- DB '++ Member not found, check DIR ++$'
- ;
- INLBR: DCX H ; Decrement dirctory size
- SHLD DIRSZ
- MVI C,READ ; Read next sector of directory
- LXI D,FCB
- CALL BDOS
- ORA A ; Read ok?
- JNZ LERROR
- LXI H,TBUF ; Set our pointers for compare
- LXI D,MEMFCB
- JMP CMLP ; Check next sector
- ;
- OPN2: IF ZCPR2
- LDA WHEEL ; Check status of wheel if zcpr2
- ORA A ; Is it zero
- JNZ OPENOK3 ; If not then skip the # and .com check
- ENDIF
- ;
- IF NOLBS OR NOCOMS ; Check for send restrictions
- LXI H,FCB+11
- MOV A,M ; Check for protect attr
- ANI 7FH ; Remove CP/M 2.x attrs
- ENDIF
- ;
- IF NOLBS ; Do not allow '#' to be sent
- CPI '#' ; Chk for '#' as last first
- JNZ OPELOK ; If '#', can not send, show why
- CALL ERXIT
- DB '++ File not for distribution ++$'
- ;
- OPELOK: ENDIF
- ;
- IF NOCOMS ; Do not allow '.COM' to be sent
- CPI 'M' ; If not, check for '.COM'
- JNZ OPENOK3 ; If not, ok to send
- DCX H
- MOV A,M ; Check next character
- ANI 7FH ; Strip attributes
- CPI 'O' ; 'O'?
- JNZ OPENOK3 ; If not, ok to send
- DCX H
- MOV A,M ; Now check 1st character
- ANI 7FH ; Strip attributes
- CPI 'C' ; 'C' as in '.COM'?
- JNZ OPENOK3 ; If not, continue
- CALL ERXIT ; Exit with message
- DB '++ Sending .COM files not allowed ++$'
- ENDIF ; NOCOMS
- ;
- OPENOK3: IF NOT DSPFNAM
- CALL ILPRT ; Print the message
- DB 'File open: ',0
- ENDIF
- ;
- IF DSPFNAM
- CALL ILPRT
- DB 'Sending: ',0
- LDA OPTSAV
- CPI 'L'
- JNZ SFNNL ; If not L opt, just show name
- LXI H,MEMFCB
- CALL DSPFN
- CALL ILPRT
- DB ' from ',0
- ;
- SFNNL: LXI H,FCB+1
- CALL DSPFN
- CALL ILPRT
- DB CR,LF,'File size: ',0
- ENDIF
- ;
- LHLD RCNT ; Get record count
- LDA OPTSAV
- CPI 'L'
- JNZ OPENOK4 ; If send from library add 1 to
- INX H ; Show correct record count
- ;
- OPENOK4:CALL CKKSIZ ; Check to see if it is at least 1K...
- CALL DECOUT ; Print decimal number of records
- PUSH H
- CALL ILPRT
- DB ' records (',0
- POP H ; Get # of 128 byte records
- LXI D,8 ; Divide by 8
- CALL DVHLDE ; To get # of 1024 byte blocks
- MOV A,H
- ORA L ; Check if remainder
- MOV H,B ; Get quotient
- MOV L,C
- JZ EXKB ; If 0 remainder, exact kilobytes
- INX H ; Else, increment to next k
- ;
- EXKB: CALL DECOUT ; Show # of kilobytes
- CALL ILPRT
- DB 'k)',CR,LF,0
- CALL ILPRT
- DB 'Send time: ',0
- CALL FILTIM ; Get file xfer time in mins in BC
- PUSH H ; Save seconds in HL
- ;
- IF ZCPR2 AND MAXTIM
- LDA WHEEL ; Check wheel status if zcpr2
- ORA A ; Is it zero
- JNZ SKIPTIM ; If its not then skip the limit
- ENDIF
- ;
- IF OK2400 ; No restrictions for 2400 bps callers?
- LDA MSPEED ; Check baudrate byte set by BYE
- CPI 6 ; Is >=2400?
- JNC SKIPTIM ; If so, skip time check
- ENDIF
- ;
- IF MAXTIM
- MOV A,C ; If limiting get length of this program
- INR A ; Increment to next full minute
- ENDIF
- ;
- IF MAXTIM AND TIMEON
- LXI H,TON
- ADD M ; Add time on to xfer time, TON will
- ENDIF
- ;
- IF MAXTIM
- STA MINUTE ; Store value for later comparison
- MOV A,B ; Get high byte of minute if >255
- JNZ MXTMC2 ; If no carry from increment/add
- INR A
- ;
- MXTMC2: STA MINUTE+1
- ENDIF
- ;
- SKIPTIM:MOV L,C
- MOV H,B
- CALL DECOUT ; Print decimal number of minutes
- MVI A,':'
- CALL CTYPE ; Output colon
- POP H ; Get seconds
- MOV A,L
- CPI 10
- MVI A,'0' ; Needs a leading zero
- CC CTYPE
- CALL DECOUT ; Print the seconds portion
- CALL ILPRT
- DB ' at ',0
- LXI H,SPTBL ; Start of baud rate speeds
- MVI D,0 ; Zero the 'D' register
- CALL SPEED ; Get speed indicator
- ADD A ; Index into the baud rate table
- ADD A
- MOV E,A ; Now have the index factor in 'DE'
- DAD D ; Add to 'HL'
- XCHG ; Put address in 'DE' regs.
- MVI C,PRINT ; Show the baud
- CALL BDOS
- CALL SPEED
- CPI 5
- MVI A,'0' ; Adds a zero for 1200, 2400, 4800 and
- CNC CTYPE ; 9600 bps
- ;
- OPENOK5:CALL ILPRT
- DB ' baud',CR,LF,0
- ;
- IF ZCPR2 AND MAXTIM
- LDA WHEEL ; Check wheel status if zcpr2
- ORA A ; Is it zero
- JNZ SKIPEM ; If not then no time limits
- ENDIF
- ;
- IF MAXTIM AND (BYEBDOS OR MXTOS)
- LDA MAXTOS ; Get maximum time on system
- ORA A ; If zero, this guy is a winner
- JZ SKIPEM ; (skip restrictions)
- LDA MINUTE+1 ; Is it over 255 minutes?
- ORA A
- JNZ OVERTM
- ENDIF
- ;
- IF MTL
- CALL GETTOS ; Get time on system in HL
- ENDIF
- ;
- IF MAXTIM AND BYEBDOS AND (NOT TIMEON)
- MVI C,BDGRTC ; Get time on system in A
- CALL BDOS
- MOV B,A ; Put in B
- ENDIF
- ;
- IF MAXTIM AND (BYEBDOS OR MXTOS)
- LDA MAXTOS
- INR A
- ENDIF
- ;
- IF MAXTIM AND BYEBDOS AND (NOT TIMEON)
- SUB B
- ENDIF
- ;
- IF MTL
- SUB L ; Get how much time is left
- ADI MAXMIN ; Give them MAXMIN extra
- ENDIF
- ;
- IF MAXTIM AND (BYEBDOS OR MXTOS)
- MOV B,A ; Put max time on sys in B
- LDA MINUTE ; Are we > max time on sys?
- CMP B
- JNC OVERTM
- ENDIF
- ;
- IF MAXTIM AND NOT (BYEBDOS OR MXTOS)
- LDA MINUTE+1 ; Get minute count high byte
- ORA A ; Check if zero
- JNZ OVERTM ; If not, is over 255 minutes!
- LDA MINUTE ; Get minute count
- CPI MAXMIN+1 ; Compare to MAXTIM value
- JNC OVERTM ; If greater than MAXTIM
- ENDIF
- ;
- SKIPEM: CALL ILPRT
- DB 'To cancel: Ctrl-X, pause, Ctrl-X',CR,LF,0
- RET
- ;
- IF MAXTIM
- OVERTM: CALL ILPRT
- DB CR,LF,'++ XMODEM ABORTED - send time exceeds the ',0
- ENDIF
- ;
- IF MAXTIM AND NOT (BYEBDOS OR MXTOS)
- LXI H,MAXMIN
- ENDIF
- ;
- IF MAXTIM AND BYEBDOS
- MVI C,BDGRTC
- CALL BDOS
- MOV B,A
- ENDIF
- ;
- IF MTL
- CALL GETTOS ; Get TOS back into HL
- ENDIF
- ;
- IF MAXTIM AND (BYEBDOS OR MXTOS)
- LDA MAXTOS
- ENDIF
- ;
- IF MAXTIM AND BYEBDOS
- SUB B
- ENDIF
- ;
- IF MTL
- SUB L ; Get time left
- ADI MAXMIN ; Add MAXMIN
- ENDIF
- ;
- IF MAXTIM AND (BYEBDOS OR MXTOS)
- MVI H,0
- MOV L,A
- ENDIF
- ;
- IF MAXTIM
- CALL DECOUT
- CALL ERXIT1
- DB ' minutes allowed ++$'
- ENDIF
- ;
- BTABLE: IF NOT STOPBIT ; One stop bit
- DW 5,13,19,25,30,48,85,141,210,280,0
- ENDIF
- ;
- IF STOPBIT ; Two stop bits
- DW 5,12,18,23,27,44,78,128,191,255,0
- ENDIF
- ;
- KTABLE: IF NOT STOPBIT ; One stop bit
- DW 5,14,21,27,32,53,101,190,330,525,0
- ENDIF
- ;
- IF STOPBIT ; Two stop bits
- DW 5,13,19,25,29,48,92,173,300,477,0
- ENDIF
- ;
- RECTBL: IF NOT STOPBIT ; One stop bit
- DB 192,74,51,38,32,20,11,8,5,3,0
- ENDIF
- ;
- IF STOPBIT ; Two stop bits
- DB 192,80,53,42,36,22,12,7,5,4,0
- ENDIF
- ;
- KECTBL: IF NOT STOPBIT ; One stop bit
- DB 192,69,46,36,30,18,10,5,3,2,0
- ENDIF
- ;
- IF STOPBIT ; Two stop bits
- DB 192,74,51,38,33,20,10,6,3,2,0
- ENDIF
- ;
- SPTBL: DB '110$','300$','450$','600$','710$','120$','240$'
- DB '480$','960$','1920$'
- ;
- ; Pass record count in RCNT: returns file's approximate download/upload
- ; time in minutes in BC, seconds in HL, also stuffs the # of mins/secs
- ; values in PGSIZE if LOGCAL is YES.
- ;
- FILTIM: CALL SPEED ; Get speed indicator
- MVI D,0
- MOV E,A ; Set up for table access
- LXI H,BTABLE ; Point to baud factor table
- LDA KFLAG
- CPI 'K'
- JNZ FILTI1
- LXI H,KTABLE ; The guy is using 1k file xfers
- ;
- FILTI1: DAD D ; Index to proper factor
- DAD D
- MOV E,M
- INX H
- MOV D,M
- LHLD RCNT ; Get number of records
- LDA OPTSAV
- CPI 'L' ; If not L download
- JNZ SKINCR ; Skip increment of record count
- INX H ; Increment record count
- ;
- SKINCR: CALL DVHLDE ; Divide HL by value in DE (records/min)
- PUSH H ; Save remainder
- LXI H,RECTBL ; Point to divisors for seconds calc.
- LDA KFLAG
- CPI 'K'
- JNZ FILTI2
- LXI H,KECTBL ; The guy is using 1k file transfers
- ;
- FILTI2: MVI D,0
- CALL SPEED ; Get speed indicator
- MOV E,A
- DAD D ; Index into table
- MOV A,M ; Get multiplier
- POP H ; Get remainder
- CALL MULHLA ; Multiply 'H' by 'A'
- CALL SHFTHL
- CALL SHFTHL
- CALL SHFTHL
- CALL SHFTHL
- MVI H,0 ; HL now = seconds (L=secs,H=0)
- ;
- IF LOGCAL
- MOV A,C ; Add minutes of length (to 0 or 1)
- STA PGSIZE ; Save as LSB of minutes
- MOV A,B ; Get MSB of minutes
- STA PGSIZE+1 ; Save as MSB of minutes (>255?)
- MOV A,L ; Get LSB of seconds (can't be >59)
- STA PGSIZE+2 ; Save for LOGCALL
- ENDIF
- ;
- RET ; End of FILTIM routine
- ;
- ; Divides 'HL' by value in 'DE' - upon exit: BC=quotient, HL=remainder
- ;
- DVHLDE: PUSH D ; Save divisor
- MOV A,E
- CMA ; Negate divisor
- MOV E,A
- MOV A,D
- CMA
- MOV D,A
- INX D ; 'DE' is now two's complemented
- LXI B,0 ; Init quotient
- ;
- DIVL1: DAD D ; Subtract divisor from divident
- INX B ; Bump quotient
- JC DIVL1 ; Loop until sign changes
- DCX B ; Adjust quotient
- POP D ; Retrieve divisor
- DAD D ; Readjust remainder
- RET
- ;
- ; Multiply the value in 'HL' by the value in 'A', return with answer in
- ; 'HL'.
- ;
- MULHLA: XCHG ; Multiplicand to 'DE'
- LXI H,0 ; Init product
- INR A
- ;
- MULLP: DCR A
- RZ
- DAD D
- JMP MULLP
- ;
- ; Shift the 'HL' register pair one bit to the right
- ;
- SHFTHL: MOV A,L
- RAR
- MOV L,A
- ORA A ; Clear the carry bit
- MOV A,H
- RAR
- MOV H,A
- RNC
- MVI A,128
- ORA L
- MOV L,A
- RET
- ;
- ; Closes the received file
- ;
- CLOSFIL:LXI D,FCB ; Point to file
- MVI C,CLOSE ; Get function
- CALL BDOS ; Close it
- INR A ; Close ok?
- JNZ CLSEXIT ; Yes, continue
- CALL ERXIT ; No, abort
- DB '++ Can''t close file ++$'
- ;
- CLSEXIT:
- IF SYSNEW
- LDA FCB+10 ; Set $SYS attribute
- ORI 80H
- STA FCB+10
- LXI D,FCB ; Point to file
- MVI C,SETATT ; Set attribute function
- CALL BDOS
- ENDIF
- ;
- RET
- ;
- ; Decimal output routine - call with decimal value in 'HL'
- ;
- DECOUT: PUSH B
- PUSH D
- PUSH H
- LXI B,-10
- LXI D,-1
- ;
- DECOU2: DAD B
- INX D
- JC DECOU2
- LXI B,10
- DAD B
- XCHG
- MOV A,H
- ORA L
- CNZ DECOUT
- MOV A,E
- ADI '0'
- CALL CTYPE
- POP H
- POP D
- POP B
- RET
- ;
- ; Makes sure there are enough records to send. For speed, this routine
- ; buffers up 16 records at a time.
- ;
- RDRECD: LDA KFLAG ; Check for 1024 byte records
- ORA A
- JNZ RDRECDK ; Using 1K blocks
- ;
- NOTKAY: LDA RECNBF ; Get number of records in buffer
- DCR A ; Decrement it
- JM RDBLOCK ; Exhausted? need more
- ORA A ; Otherwise, clear carry and...
- RET ; From 'RDRECD'
- ;
- RDRECDK:LDA RECNBF ; Get number of records in buffer
- ORA A ; Any records in buffer?
- JZ RDBLOCK ; Nope, get more
- SUI 8 ; Decrement count of records
- RNC ; 8 or more left
- XRA A ; Less than 8 left
- STA KFLAG ; Revert to 128 blocks
- JMP NOTKAY ; Continue with short blocks
- ;
- ; Update buffer pointers and counters AFTER sending a good block.
- ;
- UPDPTR: LDA KFLAG
- ORA A
- JNZ BIG
- LXI D,128 ; Small pointer increment
- MVI B,1 ; Small sector number
- JMP UPDPTR1
- ;
- BIG: LXI D,1024 ; Big pointer increment
- MVI B,8 ; Number of sectors in big block
- ;
- UPDPTR1:LDA RECNBF ; Update buffer sector count
- SUB B
- STA RECNBF
- LHLD RECPTR ; Get buffer address
- DAD D ; To next buffer
- SHLD RECPTR ; Save buffer address
- RET
- ;
- ; Buffer is empty - read in another block of 16
- ;
- RDBLOCK:LDA EOFLG ; Get 'EOF' flag
- CPI 1 ; Is it set?
- STC ; To show 'EOF'
- RZ ; Got 'EOF'
- MVI C,0 ; Records in block
- LXI D,DBUF ; To disk buffer
- ;
- RDRECLP:PUSH B
- PUSH D
- MVI C,SETDMA ; Set DMA address
- CALL BDOS
- LXI D,FCB
- MVI C,READ
- CALL BDOS
- POP D
- POP B
- ORA A ; Read ok?
- JZ RDRECOK ; Yes
- DCR A ; 'EOF'?
- JZ REOF ; Got 'EOF'
- ;
- ; Read error
- ;
- LERROR: CALL ERXIT
- DB '++ File read error ++$'
- ;
- RDRECOK:LXI H,128 ; Add length of one record
- DAD D ; To next buffer
- XCHG ; Buffer to 'DE'
- INR C ; More records?
- MOV A,C ; Get count
- CPI BUFSIZ*8 ; Done?
- JZ RDBFULL ; Yes, buffer is full
- JMP RDRECLP ; Read more
- ;
- REOF: MVI A,1
- STA EOFLG ; Set EOF flag
- MOV A,C
- ;
- ; Buffer is full, or got EOF
- ;
- RDBFULL:STA RECNBF ; Store record count
- LXI H,DBUF ; Init buffer pointear
- SHLD RECPTR ; Save buffer address
- LXI D,TBUF ; Reset DMA address
- MVI C,SETDMA
- CALL BDOS
- JMP RDRECD ; Pass record to caller
- ;
- ; Writes the record into a buffer. When 16 have been written, writes
- ; the block to disk.
- ;
- ; Entry point "WRBLOCK" flushes the buffer at EOF
- ;
- WRRECD: LHLD BLKSIZ ; Get length of last record
- XCHG ; Get ready for add
- LHLD RECPTR ; Get buffer address
- DAD D ; To next buffer
- SHLD RECPTR ; Save buffer address
- XCHG ; Move BLKSIZ to HL
- CALL SHFTHL ; Divide by 128 to get recors
- CALL SHFTHL
- CALL SHFTHL
- CALL SHFTHL
- CALL SHFTHL
- CALL SHFTHL
- CALL SHFTHL
- LDA RECNBF ; Bump the records number in the buffer
- ADD L
- STA RECNBF
- CPI BUFSIZ*8 ; Equal to, or past 'end' of buffer?
- RC ; No, return
- ;
- ; Writes a block to disk
- ;
- WRBLOCK:LDA RECNBF ; Number of records in the buffer
- ORA A ; 0 means end of file
- RZ ; None to write
- MOV C,A ; Save count
- LXI D,DBUF ; Point to disk buff
- ;
- DKWRLP: PUSH H
- PUSH D
- PUSH B
- MVI C,SETDMA ; Set DMA
- CALL BDOS ; To buffer
- LXI D,FCB ; Then write the block
- MVI C,WRITE
- CALL BDOS
- POP B
- POP D
- POP H
- ORA A
- JNZ WRERR ; Oops, error
- LXI H,128 ; Length of 1 record
- DAD D ; 'HL'= next buff
- XCHG ; To 'DE' for setdma
- DCR C ; More records?
- JNZ DKWRLP ; Yes, loop
- XRA A ; Get a zero
- STA RECNBF ; Reset number of records
- LXI H,DBUF ; Reset buffer buffer
- SHLD RECPTR ; Save buffer address
- ;
- RSDMA: LXI D,TBUF ; Reset DMA address
- MVI C,SETDMA
- CALL BDOS
- RET
- ;
- WRERR: CALL RSDMA ; Reset DMA to normal
- MVI C,CAN ; Cancel
- CALL SEND ; Sender
- CALL RCVSABT ; Kill receive file
- CALL ERXIT ; Exit with msg:
- DB '++ Error writing file ++$'
- ;
- ; Receive a character - timeout time is in 'B' in seconds. Entry via
- ; 'RECVDG' deletes garbage characters on the line. For example, having
- ; just sent a record calling 'RECVDG' will delete any line-noise-induced
- ; characters "long" before the ACK/NAK would be received.
- ;
- RECVDG: CALL GETCHR
- CALL GETCHR
- ;
- RECV: PUSH D ; Save 'DE' regs.
- MVI E,MHZ ; Get the clock speed
- XRA A ; Clear the 'A' reg.
- ;
- MSLOOP: ADD B ; Number of seconds
- DCR E ; One less mhz. to go
- JNZ MSLOOP ; If not zero, continue
- MOV B,A ; Put total value back into 'B'
- ;
- MSEC: IF NOT BYEBDOS
- LXI D,6600 ; 1 second DCR count
- ENDIF
- ;
- IF BYEBDOS
- LXI D,2800 ; (includes BYEBDOS overhead)
- ENDIF
- ;
- MWTI: CALL RCVRDY ; Input from modem ready
- JZ MCHAR ; Got the character
- DCR E ; Count down for timeout
- JNZ MWTI
- DCR D
- JNZ MWTI
- DCR B ; More seconds?
- JNZ MSEC ; Yes, wait
- ;
- ; Test for the presence of carrier - if none, go to 'CARCK' and continue
- ; testing for specified time. If carrier returns, continue. If it does
- ; not return, exit.
- ;
- CALL CAROK ; Is carrier still on?
- CNZ CARCK ; If not, test for 15 seconds
- ;
- ; Modem timed out receiving - but carrier is still on.
- ;
- POP D ; Restore 'DE'
- STC ; Carry shows timeout
- RET
- ;
- ; Get character from modem.
- ;
- MCHAR: CALL MDIN ; Get data byte from modem
- POP D ; Restore 'DE'
- ;
- ; Calculate checksum and CRC
- ;
- PUSH PSW ; Save the character
- CALL UPDCRC ; Calculate CRC
- ADD C ; Add to checksum
- MOV C,A ; Save checksum
- POP PSW ; Restore the character
- ORA A ; Carry off: no error
- RET ; From 'RECV'
- ;
- ; Common carrier test for receive and send. If carrier returns within
- ; TIMOUT seconds, normal program execution continues. Else, it will
- ; abort to CP/M via EXIT.
- ;
- CARCK: MVI E,TIMOUT*10 ; Value for 15 second delay
- ;
- CARCK1: CALL DELAY ; Kill .1 seconds
- CALL CAROK ; Is carrier still on?
- RZ ; Return if carrier on
- DCR E ; Has 15 seconds expired?
- JNZ CARCK1 ; If not, continue testing
- ;
- ; See if got a local console, and report if so.
- ;
- IF NOT (USECON OR BYEBDOS)
- LHLD CONOUT+1 ; Get conout address
- MOV A,H ; Zero if no local console
- ORA L
- JZ CARCK2
- ENDIF
- ;
- MVI A,1 ; Print local only
- STA CONONL
- CALL ILPRT ; Report loss of carrier
- DB CR,LF,'++ Carrier lost in XMODEM ++',CR,LF,0
- ;
- CARCK2: LDA OPTSAV ; Get option
- CPI 'R' ; If not receive
- JNZ EXIT ; Then abort now, else
- CALL DELFILE ; Get rid of the junk first
- JMP EXIT ; Else, abort to CP/M
- ;
- ; Delay - 100 millisecond delay.
- ;
- DELAY: PUSH B ; Save 'BC'
- LXI B,MHZ*4167 ; Value for 100 ms. delay
- ;
- DELAY2: DCX B ; Update count
- MOV A,B ; Get MSP byte
- ORA C ; Count = zero?
- JNZ DELAY2 ; If not, continue
- POP B ; Restore 'BC'
- RET ; Return to CARCK1
- ;
- ;-----------------------------------------------------------------------
- ;
- ; Tells user to add description of an uploaded file
- ;
- IF DESCRIB
- ASK: LDA OPTSAV ; Get the option
- CPI 'R'
- RNZ ; If not receiving a file, exit
- LDA PRVTFL ; Sending to "private area"?
- ORA A
- RNZ ; If yes, do not ask for description
- ENDIF
- ;
- IF DESCRIB AND ZCPR2 AND (NOT ASKSYS)
- LDA WHEEL
- ORA A
- RNZ
- ENDIF
- ;
- IF DESCRIB
- MVI B,2 ; Short delay to wait for an input char.
- CALL RECV
- ENDIF
- ;
- IF DESCRIB AND ASKIND
- ASK1: CALL DELAY
- CALL SHONM ; Show the file name
- CALL DILPRT
- DB ' - this file is for:',CR,LF,CR,LF,0
- MVI C,PRINT ; Display the file descriptors
- LXI D,KIND0
- CALL BDOS
- CALL DILPRT
- DB CR,LF,'Select one: ',0
- CALL INPUT ; Get a character
- CALL TYPE
- CPI '0'
- JC ASK1
- CPI '9'+1
- JNC ASK1
- STA KIND
- ENDIF
- ;
- IF DESCRIB AND (NOT ASKIND)
- ASK1: CALL DELAY
- CALL SHONM
- ENDIF
- ;
- IF DESCRIB
- ASK2: LXI H,0
- SHLD OUTPTR ; Initialize the output pointers
- CALL DILPRT
- DB CR,LF,CR,LF
- DB 'Please describe this file (7 lines or less). Tell '
- DB 'what equipment can use',CR,LF,'it and what the '
- DB 'program does. Extra RET to quit.',CR,LF,CR,LF,0
- CALL SENBEL
- ;
- ; Get the file name from FCB, skip any blanks
- ;
- LXI H,HLINE
- CALL DSTOR1
- MVI B,8 ; Get FILENAME
- LXI D,FCB+1
- LXI H,OLINE
- CALL LOPFCB
- MVI M,'.'
- MOV A,M ; Separate FILENAME and EXTENT
- CALL TYPE
- INX H
- MVI B,3 ; Get EXTENT name
- CALL LOPFCB
- ENDIF
- ;
- IF DESCRIB AND ASKIND
- AFIND1: LDA KIND
- CPI '0' ; File category 0
- LXI D,KIND0+4
- CZ DKIND ; File category 1
- CPI '1'
- LXI D,KIND1+4
- CZ DKIND ; File category 1
- CPI '2'
- LXI D,KIND2+4
- CZ DKIND ; File category 2
- CPI '3'
- LXI D,KIND3+4
- CZ DKIND ; File category 3
- CPI '4'
- LXI D,KIND4+4
- CZ DKIND ; File category 4
- CPI '5'
- LXI D,KIND5+4
- CZ DKIND ; File category 5
- CPI '6'
- LXI D,KIND6+4
- CZ DKIND ; File category 6
- CPI '7'
- LXI D,KIND7+4
- CZ DKIND ; File category 7
- CPI '8'
- LXI D,KIND8+4
- CZ DKIND ; File category 8
- CPI '9'
- LXI D,KIND9+4
- CZ DKIND ; File category 9
- ENDIF ; DESCRIB AND ASKIND
- ;
- IF DESCRIB AND (NOT ASKIND)
- MVI M,CR
- INX H
- MVI M,LF
- ENDIF
- ;
- IF DESCRIB
- CALL DSTOR ; Put FILENAME line into memory
- CALL DILPRT
- DB CR,LF,CR,LF,'0: ---------1---------2---------3'
- DB '---------4---------5---------6---------',CR,LF,0
- XRA A
- STA ANYET ; Reset the flag for no information yet
- MVI C,'0'
- ;
- EXPLN: INR C
- MOV A,C
- CPI '7'+1
- JNC EXPL1
- CALL TYPE
- MVI A,' '
- CALL OUTCHR
- CALL OUTCHR
- CALL OUTCHR
- CALL DILPRT
- DB ': ',0
- CALL DESC ; Get a line of information
- CALL DSTOR
- JMP EXPLN
- ;
- EXPL1:
- MVI A,CR ; All finished, put in an extra CR-LF
- CALL OUTCHR
- MVI A,LF
- CALL OUTCHR
- MVI A,'$'
- CALL OUTCHR
- CALL DILPRT
- DB ' Repeating to verify:',CR,LF,CR,LF,0
- LHLD OUTADR
- XCHG
- MVI C,PRINT
- CALL BDOS
- LHLD OUTPTR
- DCX H
- SHLD OUTPTR
- ;
- EXPL2: CALL DILPRT
- DB CR,LF,'Is this ok (Y/N)? ',0
- CALL INPUT
- CALL TYPE ; Display answer
- ANI 5FH ; Change to upper case
- CPI 'N'
- JZ ASK1 ; If not, do it over
- CPI 'Y'
- JNZ EXPL2 ; If yes, finish up, else ask again
- ;
- ; Now open the file and put this at the beginning
- ;
- EXPL3: LDA 0004H ; Get current drive/user
- STA DRUSER ; Store
- ;
- ; Set drive/user to the area listed above
- ;
- MVI E,USER ; Set user to WHATSFOR.TXT area
- MVI C,SETUSR
- CALL BDOS
- MVI A,DRIVE ; Set drive to WHATSFOR.TXT area
- SUI 41H
- MOV E,A
- MVI C,SELDSK
- CALL BDOS
- ;
- ; Open source file
- ;
- CALL DILPRT
- DB CR,LF,0
- LXI D,FILE ; Open WHATSFOR.TXT file
- MVI C,OPEN
- CALL BDOS
- INR A ; Check for no open
- JNZ OFILE ; File exists, exit
- MVI C,MAKE ; None exists, make a new file
- LXI D,FILE
- CALL BDOS
- INR A
- JZ NOROOM ; Exit if cannot open new file
- ;
- OFILE: LXI H,FILE ; Otherwise use same filename
- LXI D,DEST ; With .$$$ extent for now
- MVI B,9
- CALL MOVE
- ;
- ; Open the destination file
- ;
- XRA A
- STA DEST+12
- STA DEST+32
- LXI H,BSIZE ; Get Buffer allocated size
- SHLD OUTSIZ ; Set for comparison
- MVI C,DELET ; Delete any existing file that name
- LXI D,DEST
- CALL BDOS
- MVI C,MAKE ; Now make a new file that name
- LXI D,DEST
- CALL BDOS
- INR A
- JZ NOROOM ; Cannot open file, no directory room
- CALL DILPRT
- DB CR,LF,'Wait a moment...',0
- ;
- ; Read sector from source file
- ;
- READLP: LXI D,TBUF
- MVI C,SETDMA
- CALL BDOS
- LXI D,FILE ; Read from WHATSFOR.TXT
- MVI C,READ
- CALL BDOS
- ORA A ; Read ok?
- JNZ RERROR
- LXI H,TBUF ; Read buffer address
- ;
- ; Write sector to output file (with buffering)
- ;
- WRDLOP: MOV A,M ; Get byte from read buffer
- ANI 7FH ; Strip parity bit
- CPI 7FH ; Del (rubout)?
- JZ NEXT ; Yes, ignore it
- CPI EOF ; End of file marker?
- JZ TDONE ; Transfer done, close, exit
- CALL OUTCHR
- ;
- NEXT: INR L ; Done with sector?
- JZ READLP ; If yes get another sector
- JMP WRDLOP ; No, get another byte
- ;
- ; Handle a backspace character while entering a character string
- ;
- BCKSP: CALL TYPE
- MOV A,B ; Get position on line
- ORA A
- JNZ BCKSP1 ; Exit if at initial column
- CALL SENBEL ; Send a bell to the modem
- MVI A,' ' ; Delete the character
- JMP BCKSP3
- ;
- BCKSP1: DCR B ; Show one less column used
- DCX H ; Decrease buffer location
- MVI A,' '
- MOV M,A ; Clear memory at this point
- CALL TYPE ; Backspace the "CRT"
- ;
- BCKSP2: MVI A,BS ; Reset the "CRT" again
- ;
- BCKSP3: CALL TYPE ; Write to the "CRT"
- RET
- ;
- ; Asks for line of information
- ;
- DESC: MVI B,0
- LXI H,OLINE
- ;
- DESC1: CALL INPUT ; Get keyboard character
- CPI CR
- JZ DESC4
- CPI TAB
- JZ DESC6
- CPI BS
- JNZ DESC2
- CALL BCKSP
- JMP DESC1 ; Get the next character
- ;
- DESC2: CPI ' '
- JC DESC1 ; If non-printing character, ignore
- JZ DESC3 ; If a space, continue
- STA ANYET ; Show a character has been sent now
- ;
- DESC3: MOV M,A
- CALL TYPE ; Display the character
- INX H
- INR B
- MOV A,B
- CPI 70 ; Do not exceed line length
- JC DESC1
- CALL SENBEL ; Send a bell to the modem
- CALL BCKSP2
- CALL BCKSP1 ; Do not allow a too-long line
- JMP DESC1
- ;
- DESC4: LDA ANYET ; Any text typed on first line yet?
- ORA A
- JNZ DESC5 ; If yes, exit
- POP H
- JMP ASK1 ; Ask again for a description
- ;
- DESC5: MVI M,CR
- MOV A,M
- CALL TYPE
- INX H ; Ready for next character
- MVI M,LF
- MOV A,M
- CALL TYPE ; Display the line feed
- INX H
- MOV A,B ; See if at first of line
- ORA A
- RNZ ; If not, ask for next line
- POP H ; Clear "CALL" from stack
- JMP EXPL1
- ;
- DESC6: MOV A,B ; At end of line now?
- CPI 68
- JNC DESC1 ; If yes, disregard
- MVI M,' '
- MOV A,M
- CALL TYPE
- INX H
- INR B
- MOV A,B
- ANI 7
- JNZ DESC6
- JMP DESC1 ; Ask for next character
- ;
- DSTOR: LXI H,OLINE
- ;
- DSTOR1: MOV A,M
- CALL OUTCHR
- CPI LF
- RZ
- INX H
- JMP DSTOR1
- ;
- ; Print message then exit to CP/M
- ;
- DEXIT: POP D ; Get message address
- MVI C,PRINT ; Print message
- CALL BDOS
- CALL RESET ; Reset the drive/user
- JMP EXIT ; all done
- ;
- ; Inline print routine - prints string pointed to by stack until a zero
- ; is found. Returns to caller at the next address after the zero ter-
- ; minator.
- ;
- DILPRT: XTHL ; Save hl, get message address
- ;
- DILPLP: MOV A,M ; Get char
- CALL TYPE ; Output it
- INX H ; Point to next
- MOV A,M ; Test
- ORA A ; For end
- JNZ DILPLP
- XTHL ; Restore hl, ret address
- RET ; Return past the end of the message
- ;
- ;
- ; Disk is full, save original file, erase others.
- ;
- FULL: MVI C,DELET
- LXI D,DEST
- CALL BDOS
- CALL DEXIT
- DB CR,LF,'++ DISK FULL, ABORTING, SAVING ORIGINAL FILE','$'
- ;
- ; Get a character, if none ready wait up to 3 minutes, then abort pgm
- ;
- INPUT: PUSH H ; Save current values
- PUSH D
- PUSH B
- ;
- INPUT1: LXI D,1200 ; Outer loop count (about 2 minutes)
- ;
- INPUT2: LXI B,MHZ*100 ; Roughly 100 ms.
- ;
- INPUT3: PUSH D ; Save the outer delay count
- PUSH B ; Save the inner delay count
- MVI E,0FFH
- MVI C,DIRCON ; Get console status
- CALL BDOS
- ANI 7FH
- POP B ; Restore the inner delay count
- POP D ; Restore the outer delay count
- ORA A ; Have a character yet?
- JNZ INPUT4 ; If yes, exit and get it
- DCX B
- MOV A,C ; See if inner loop is finished
- ORA B
- JNZ INPUT3 ; If not loop again
- DCX D
- MOV A,E
- ORA D
- JNZ INPUT2 ; If not reset inner loop and go again
- MVI A,CR
- CALL OUTCHR
- MVI A,LF
- CALL OUTCHR
- LXI SP,STACK ; Restore the stack
- CALL EXPL3 ; Finish appending previous information
- JMP EXIT ; Finished
- ;
- INPUT4: POP B
- POP D
- POP H
- RET
- ;
- ; Stores the Filename/extent in the buffer temporarily
- ;
- LOPFCB: LDAX D ; Get FCB FILENAME/EXT character
- CPI ' '+1
- JC LOPF1
- MOV M,A ; Store in OLINE area
- CALL TYPE ; Display on CRT
- INX H ; Next OLINE position
- ;
- LOPF1: INX D ; Next FCB position
- DCR B ; One less to go
- JNZ LOPFCB ; If not done, get next one
- RET
- ;
- ; No room to open a new file
- ;
- NOROOM: CALL DEXIT
- DB CR,LF,'++ No DIR space: output ++$'
- ;
- ; Output error - cannot close destination file
- ;
- OERROR: CALL DEXIT
- DB CR,LF,'++ Cannot close output ++$'
- ;
- ; Output a character to the new file buffer - first, see if there is
- ; room in the buffer for this character.
- ;
- OUTCHR: PUSH H
- PUSH PSW ; Store the character for now
- LHLD OUTSIZ ; Get buffer size
- XCHG ; Put in 'DE'
- LHLD OUTPTR ; Now get the buffer pointers
- MOV A,L ; Check to see if room in buffer
- SUB E
- MOV A,H
- SBB D
- JC OUT3 ; If room, go store the character
- LXI H,0 ; Otherwise reset the pointers
- SHLD OUTPTR ; Store the new pointer address
- ;
- OUT1: XCHG ; Put pointer address into 'DE'
- LHLD OUTSIZ ; Get the buffer size into 'HL'
- MOV A,E ; See if buffer is max. length yet
- SUB L ; By subtracting 'HL' from 'DE'
- MOV A,D
- SBB H
- JNC OUT2 ; If less, exit and keep going
- ;
- ; No more room in buffer, stop and transfer to destination file
- ;
- LHLD OUTADR ; Get the buffer address
- DAD D ; Add pointer value
- XCHG ; Put into 'DE'
- MVI C,SETDMA
- CALL BDOS
- LXI D,DEST
- MVI C,WRITE
- CALL BDOS
- ORA A
- JNZ FULL ; Exit with error, if disk is full now
- LXI D,RLEN
- LHLD OUTPTR
- DAD D
- SHLD OUTPTR
- JMP OUT1
- ;
- OUT2: LXI D,TBUF
- MVI C,SETDMA
- CALL BDOS
- LXI H,0
- SHLD OUTPTR
- ;
- OUT3: XCHG
- LHLD OUTADR
- DAD D
- XCHG
- POP PSW ; Get the character back
- STAX D ; Store the character
- LHLD OUTPTR ; Get the buffer pointer
- INX H ; Increment them
- SHLD OUTPTR ; Store the new pointer address
- POP H
- RET
- ;
- RERROR: CPI 1 ; File finished?
- JZ TDONE ; Exit, then
- MVI C,DELET ; Erase destination file, keep original
- LXI D,DEST
- CALL BDOS
- CALL DEXIT
- DB '++ Source file read error ++$'
- ;
- ; Reset the Drive/User to original, then back to original caller
- ;
- RESET: LDA DRUSER ; Get original drive/user area back
- RAR
- RAR
- RAR
- RAR
- ANI 0FH ; Just look at the user area
- MOV E,A
- MVI C,SETUSR ; Restore original user area
- CALL BDOS
- LDA DRUSER ; Get the original drive/user back
- ANI 0FH ; Just look at the drive for now
- MOV E,A
- MVI C,SELDSK ; Restore original drive
- CALL BDOS
- CALL DILPRT ; Print CRLF before quitting
- DB CR,LF,0
- RET ; Return to caller (Not JMP EXIT1)
- ;
- ; Send a bell just to the modem
- ;
- SENBEL: CALL SNDRDY ; Is modem ready for another character?
- JNZ SENBEL ; If not, wait
- MVI A,7
- PUSH PSW ; Overlay has the "POP PSW"
- JMP SENDR ; Send to the modem only
- ;
- ;.....
- ;
- ;
- ; Shows the Filename/extent
- ;
- SHONM: CALL DILPRT
- DB CR,LF,CR,LF,0
- LXI H,FCB+1
- MVI B,8 ; Maximum size of file name
- CALL SHONM1
- MOV A,M ; Get the next character
- CPI ' ' ; Any file extent?
- RZ ; If not, finished
- MVI A,'.'
- CALL TYPE
- MVI B,3 ; Maximum size of file extent
- ;
- SHONM1: MOV A,M ; Get FCB FILENAME/EXT character
- CPI ' '+1 ; Skip any blanks
- JC $+6
- CALL TYPE ; Display on CRT
- INX H ; Next FCB position
- DCR B ; One less to go
- JNZ SHONM1 ; If not done, get next one
- RET
- ;.....
- ;
- ; Transfer is done - close destination file
- ;
- TDONE: LHLD OUTPTR
- MOV A,L
- ANI RLEN-1
- JNZ TDONE1
- SHLD OUTSIZ
- ;
- TDONE1: MVI A,EOF ; Fill remainder of record with ^Z's
- PUSH PSW
- CALL OUTCHR
- POP PSW
- JNZ TDONE
- MVI C,CLOSE ; Close WHATSFOR.TXT file
- LXI D,FILE
- CALL BDOS
- MVI C,CLOSE ; Close WHATSFOR.$$$ file
- LXI D,DEST
- CALL BDOS
- INR A
- JZ OERROR
- ;
- ; Rename both files as no destination file name was specified
- ;
- LXI H,FILE+1 ; Prepare to rename old file to new
- LXI D,DEST+17
- MVI B,16
- CALL MOVE
- MVI C,DELET ; Delete original WHATSFOR.TXT file
- LXI D,FILE
- CALL BDOS
- LXI D,DEST ; Rename WHATSFOR.$$$ to WHATSFOR.TXT
- MVI C,RENAME
- CALL BDOS
- JMP RESET ; Reset the drive/user, back to caller
- ;
- TYPE: PUSH B
- PUSH D
- PUSH H
- PUSH PSW
- MOV E,A ; Character to 'E' for CP/M
- MVI C,WRCON ; Write to console
- CALL BDOS
- POP PSW
- POP H
- POP D
- POP B
- RET
- ENDIF ; DESCRIB
- ;
- IF DESCRIB AND ASKIND
- DKIND: LDAX D ; Get the character from the string
- CALL TYPE ; Otherwise display the character
- MOV M,A ; Put in the buffer
- CPI LF ; Done yet?
- JZ DKIND1 ; Exit if a LF, done
- INX D ; Next position in the string
- INX H ; Next postion in the buffer
- JMP DKIND ; Keep going until a LF
- ;
- DKIND1: LDA KIND ; Get the kind of file back
- RET ; Finished
- ENDIF
- ;.....
- ;
- ;-----------------------------------------------------------------------
- ;
- ; Send a character to the modem
- ;
- SEND: PUSH PSW ; Save the character
- CALL UPDCRC ; Calculate CRC
- ADD C ; Calcculate checksum
- MOV C,A ; Save cksum
- ;
- SENDW: CALL SNDRDY ; Is transmit ready
- JZ SENDR ; Yes, go send
- ;
- ; Xmit status not ready, so test for carrier before looping - if lost,
- ; go to CARCK and give it up to 15 seconds to return. If it doesn't,
- ; return abort via EXIT.
- ;
- PUSH D ; Save 'DE'
- CALL CAROK ; Is carrier still on?
- CNZ CARCK ; If not, continue testing it
- POP D ; Restore 'DE'
- JMP SENDW ; Else, wait for xmit ready
- ;
- ; Waits for initial NAK - to ensure no data is sent until the receiving
- ; program is ready, this routine waits for the first timeout-nak or the
- ; letter 'C' for CRC from the receiver. If CRC is in effect then Cyclic
- ; Redundancy Checks are used instead of checksums. 'E' contains the
- ; number of seconds to wait. If the first character received is a CAN
- ; (CTL-X) then the send will be aborted as though it had timed out.
- ; Since 1K extensions require CRC, KFLAG is set to NULL if the receiver
- ; requests checksum
- ;
- WAITNAK: IF CONFUN ; Check for Sysop function key?
- CALL FUNCHK ; Yeah, go ahead.. Twit?
- ENDIF
- ;
- IF CONFUN AND SYSABT
- LDA SYSABF ; If SYSABT option, check
- ORA A ; to see if Abort
- JNZ ABORT ; If so, bail out now...
- ENDIF
- ;
- MVI B,1 ; Timeout delay
- CALL RECV ; Did we get
- CPI 'K' ; Did he send a "K" first?
- JZ SET1KX
- CPI CRC ; 'CRC' indicated?
- JZ SET1K ; Yes, send block
- CPI NAK ; A 'NAK' indicating checksum?
- JZ SETNAK ; Yes go put checksum in effect
- CPI CAN ; Was it a cancel (CTL-X)?
- JZ ABORT ; Yes, abort
- DCR E ; Finished yet?
- JZ ABORT ; Yes, abort
- JMP WAITNAK ; No, loop
- ;
- ; Turn on checksum flag
- ;
- SETNAK: XRA A
- STA KFLAG ; Make sure transfer uses small blocks
- MVI A,'C' ; Change to checksum
- STA CRCFLG
- RET
- ;
- ; Turn on 1k flag
- ;
- SET1K: MVI B,1 ; Wait up to 1 second to get "K"
- CALL RECV
- CPI 'K' ; Did we get a "K" or something else
- RNZ ; (or nothing)
- ;
- SET1KX: LDA MSPEED
- CPI 5
- RC
- MVI A,'K'
- STA KFLAG ; Set 1k flag
- RET
- ;
- ; This routine moves the filename from the default command line buffer
- ; to the file control block (FCB).
- ;
- MOVEFCB:LHLD SAVEHL ; Get position on command line
- CALL GETB ; Get numeric position
- LXI D,FCB+1
- CALL MOVENAM ; Move name to FCB
- XRA A
- STA FCBRNO ; Zero record number
- STA FCBEXT ; Zero extent
- LDA OPTSAV ; This going to be a library file?
- CPI 'L'
- RNZ ; If not, finished
- ;
- ; Handles library entries, first checks for proper .LBR extent. If no
- ; extent was included, it adds one itself.
- ;
- SHLD SAVEHL
- LXI H,FCB+9 ; 1st extent character
- MOV A,M
- CPI ' '
- JZ NOEXT ; No extent, make one
- CPI 'L' ; Check 1st character in extent
- JNZ LBRERR
- INX H
- MOV A,M
- CPI 'B' ; Check 2nd character in extent
- JNZ LBRERR
- INX H
- MOV A,M
- CPI 'R' ; Check 3rd character in extent
- JNZ LBRERR
- ;
- ; Get the name of the desired file in the library
- ;
- MOVEF1: LHLD SAVEHL ; Get current position on command line
- CALL CHKMSP ; See if valid library member file name
- INR B ; Increment for move name
- LXI D,MEMFCB ; Store member name in special buffer
- JMP MOVENAM ; Move from command line to buffer, done
- ;
- ; Check for any spaces prior to library member file name, if none (or
- ; only spaces remaining), no name.
- ;
- CHKMSP: DCR B
- JZ MEMERR
- MOV A,M
- CPI ' '+1
- RNC
- INX H
- JMP CHKMSP
- ;
- ; Gets the count of characters remaining on the command line
- ;
- GETB: MOV A,L
- SUI TBUF+2 ; Start location of 1st command
- MOV B,A ; Store for now
- LDA TBUF ; Find length of command line
- SUB B ; Subtract those already used
- MOV B,A ; Now have number of bytes remaining
- RET
- ;
- LBRERR: CALL ERXIT
- DB '++ Invalid library name ++$'
- ;
- MEMERR: CALL ILPRT
- DB CR,LF,'++ No library member file requested ++',CR,LF,0
- JMP OPTERR
- ;
- ; Add .LBR extent to the library file name
- ;
- NOEXT: LXI H,FCB+9 ; Location of extent
- MVI M,'L'
- INX H
- MVI M,'B'
- INX H
- MVI M,'R'
- JMP MOVEF1 ; Now get the library member name
- ;
- ; Move a file name from the 'TBUF' command line buffer into FCB
- ;
- MOVENAM:MVI C,1
- ;
- MOVEN1: MOV A,M
- CPI ' '+1 ; Name ends with space or return
- JC FILLSP ; Fill with spaces if needed
- CPI '.'
- JZ CHKFIL ; File name might be less than 8 chars.
- STAX D ; Store
- INX D ; Next position to store the character
- INR C ; One less to go
- MOV A,C
- CPI 12+1
- JNC NONAME ; 11 chars. maximum filename plus extent
- ;
- MOVEN2: INX H ; Next char. in file name
- DCR B
- JZ OPTERR ; End of name, see if done yet
- JMP MOVEN1
- ;
- ; See if any spaces needed between file name and .ext
- ;
- CHKFIL: CALL FILLSP ; Fill with spaces
- JMP MOVEN2
- ;
- FILLSP: MOV A,C
- CPI 9
- RNC ; Up to 1st character in .ext now
- MVI A,' ' ; Be sure there is a blank there now
- STAX D
- INR C
- INX D
- JMP FILLSP ; Go do another
- ;
- CTYPE: PUSH B ; Save all registers
- PUSH D
- PUSH H
- MOV E,A ; Character to 'E' in case BDOS (normal)
- LDA CONONL ; Want to bypass 'BYE' output to modem?
- ORA A
- JNZ CTYPEL ; Yes, go directly to CRT, then
- MVI C,WRCON ; BDOS console output, to CRT and modem
- CALL BDOS ; Since 'BYE' intercepts the char.
- POP H ; Restore all registers
- POP D
- POP B
- RET
- ;
- CTYPEL: MOV C,E ; BIOS needs it in 'C'
- CALL CONOUT ; BIOS console output routine, not BDOS
- POP H ; Restore all registers saved by 'CTYPE'
- POP D
- POP B
- RET
- ;
- HEXO: PUSH PSW ; Save for right digit
- RAR ; Right justify the left digit
- RAR
- RAR
- RAR
- CALL NIBBL ; Print left digit
- POP PSW ; Restore right
- ;
- NIBBL: ANI 0FH ; Isolate digit
- ADI 90H
- DAA
- ACI 40H
- DAA
- JMP CTYPE ; Type it
- ;
- ; Inline print of message, terminates with a 0
- ;
- ILPRT: XTHL ; Save HL, get HL=message
- ;
- ILPLP: MOV A,M ; Get the character
- INX H ; To next character
- ORA A ; End of message?
- JZ ILPRET ; Yes, return
- CALL CTYPE ; Type the message
- JMP ILPLP ; Loop
- ;
- ILPRET: XTHL ; Restore HL
- RET ; Past message
- ;
- ; Exit printing message following call
- ;
- ERXIT: CALL ILPRT
- DB CR,LF,0
- XRA A
- STA OPTSAV ; Reset option to zero for TELL
- ;
- ERXIT1: MVI C,DIRCON ; Use BDOS Direct
- MVI E,0FFH ; Console input function
- CALL BDOS ; To check for abort
- CPI 'C'-40H ; CTL-C
- JZ ERXITX ; Abort msg
- CPI 'K'-40H ; CTL-K
- JZ ERXITX ; Abort msg
- POP H ; Get address of next char
- MOV A,M ; Get char
- INX H ; Increment to next char
- PUSH H ; Save address
- CPI '$' ; End of message?
- JZ EXITXL ; If '$' is end of message
- CALL CTYPE ; Else print char on console
- JMP ERXIT1 ; And repeat until abort/end
- ;
- EXITXL: CALL ILPRT
- DB CR,LF,0
- ;
- ERXITX: POP H ; Restore stack
- JMP EXIT ; Get out of here
- ;
- ; Restore the old user area and drive from a received file
- ;
- RECAREA:CALL RECDRV ; Ok set the drive to its place
- LDA PRVTFL ; Private area wanted?
- ORA A
- LDA XPRUSR ; Yes, set to private area
- JNZ RECARE
- LDA XUSR ; Ok now set the user area
- ;
- RECARE: MOV E,A ; Stuff it in E
- MVI C,SETUSR ; Tell BDOS what we want to do
- CALL BDOS ; Now do it
- RET
- ;
- RECDRV: LDA PRVTFL
- ORA A
- LDA XPRDRV ; Get private upload drive
- JNZ RECDR1
- LDA XDRV ; Or forced upload drive
- ;
- RECDR1: SUI 'A' ; Adjust it
- ;
- RECDRX: MOV E,A ; Stuff it in E
- MVI C,SELDSK ; Tell BDOS
- CALL BDOS
- RET
- ;
- MOVE: MOV A,M ; Get a character
- STAX D ; Store it
- INX H ; To next 'from'
- INX D ; To next 'to'
- DCR B ; More?
- JNZ MOVE ; Yes, loop
- RET
- ;
- ;-----------------------------------------------------------------------
- ;
- ; CRC SUBROUTINES
- ;
- ;-----------------------------------------------------------------------
- ;
- CHKCRC: PUSH H ; Check 'CRC' bytes of received message
- LHLD CRCVAL
- MOV A,H
- ORA L
- POP H
- RZ
- MVI A,0FFH
- RET
- ;
- CLRCRC: PUSH H ; Reset 'CRC' store for a new message
- LXI H,0
- SHLD CRCVAL
- POP H
- RET
- ;
- FINCRC: PUSH PSW ; Finish 'CRC' calculation
- XRA A
- CALL UPDCRC
- CALL UPDCRC
- PUSH H
- LHLD CRCVAL
- MOV D,H
- MOV E,L
- POP H
- POP PSW
- RET
- ;
- UPDCRC: PUSH PSW ; Update 'CRC' store with byte in 'A'
- PUSH B
- PUSH H
- MVI B,8
- MOV C,A
- LHLD CRCVAL
- ;
- UPDLOOP:MOV A,C
- RLC
- MOV C,A
- MOV A,L
- RAL
- MOV L,A
- MOV A,H
- RAL
- MOV H,A
- JNC SKIPIT
- MOV A,H ; The generator is x^16 + x^12 + x^5 + 1
- XRI 10H
- MOV H,A
- MOV A,L
- XRI 21H
- MOV L,A
- ;
- SKIPIT: DCR B
- JNZ UPDLOOP
- SHLD CRCVAL
- POP H
- POP B
- POP PSW
- RET
- ;
- ; end of CRC routines
- ;-----------------------------------------------------------------------
- ; start of LOGCAL routines
- ;
- ; The following allocations are used by the LOGCALL routines
- ;
- IF LOGCAL
- PGSIZE: DB 0,0,0 ; Program length in minutes and seconds
- LOGOPT: DB '?' ; Primary option stored here
- DEFAULT$DISK:
- DB 0 ; Disk for open stored here
- DEFAULT$USER:
- DB 0 ; User for open stored here
- FCBCALLER:
- DB 0,'LASTCALR???' ; Last caller file FCB
- DB 0,0,0,0,0,0,0,0,0,0,0,0
- DB 0,0,0,0,0,0,0,0,0,0,0
- CALLERPTR:
- DW LOGBUF
- FCBLOG: DB 0 ; Log file FCB
- ENDIF
- ;
- IF LOGCAL AND NOT (LOGSYS OR KNET)
- DB 'XMODEM '
- DB 'L','O'+80H,'G' ; (the +80H makes this a $SYS file)
- ENDIF
- ;
- IF LOGCAL AND LOGSYS AND NOT KNET
- DB 'LOG '
- DB 'S','Y'+80H,'S'
- ENDIF
- ;
- IF LOGCAL AND KNET AND NOT LOGSYS
- DB 'XMODEM '
- DB 'T','X'+80H,'#'
- ENDIF
- ;
- IF LOGCAL
- DB 0,0,0,0,0,0,0,0,0,0,0,0
- DB 0,0,0,0,0,0,0,0,0,0,0,0
- LOGPTR: DW DBUF
- LOGCNT: DB 0
- LOGK: DB 'k '
- ENDIF
- ;
- IF LOGCAL OR MBFMSG OR MBDESC
- DSKSAV: DB 0 ; Up/download disk saved here
- USRSAV: DB 0 ; Up/download user saved here
- ENDIF
- ;
- IF LOGCAL AND (RTC OR B3RTC OR BYEBDOS)
- YYSAV: DB 0
- MMSAV: DB 0
- DDSAV: DB 0
- MNSAV: DB 0
- ENDIF
- ;
- ; Main log file routine, adds record to log file
- ;
- IF LOGCAL OR MBDESC OR MBFMSG
- LOGCALL:
- MVI C,CURDRV ; Get current disk
- CALL BDOS ; (where down/upload occurred)
- STA DSKSAV ; And save it...
- MVI C,SETUSR ; Get current user area
- MVI E,0FFH ; (where down/upload occurred)
- CALL BDOS
- STA USRSAV ; And save it...
- ENDIF
- ;
- IF (MBDESC OR MBFMSG) AND (NOT LOGCAL)
- RET ; Skip logging if no log
- ENDIF
- ;
- IF LOGCAL
- XRA A
- STA FCBCALLER+12
- STA FCBCALLER+32
- MVI A,LASTDRV-'A'
- STA DEFAULT$DISK
- MVI A,LASTUSR
- STA DEFAULT$USER
- LXI D,FCBCALLER
- CALL OPENF ; Open LASTCALR file
- JNZ LOGC1
- CALL ERXIT
- DB '++ No last caller file found +++$'
- ;
- LOGC1: MVI C,SETRRD ; Get random record #
- LXI D,FCBCALLER ; (for first record in file)
- CALL BDOS
- LXI D,DBUF ; Set DMA to DBUF
- MVI C,SETDMA
- CALL BDOS
- LXI D,FCBCALLER ; Read first (& only) record
- MVI C,RRDM
- CALL BDOS
- ENDIF ;LOGCAL
- ;
- IF LOGCAL AND NOT (MBBS AND (RTC OR B3RTC OR BYEBDOS))
- LXI H,DBUF ; Set pointer to beginning of record
- ENDIF
- ;
- IF LOGCAL AND (MBBS AND (RTC OR B3RTC OR BYEBDOS))
- LXI H,DBUF+11 ; Set pointer to skip log on date
- ENDIF
- ;
- IF LOGCAL
- SHLD CALLERPTR
- LXI D,LOGBUF ; Set DMA address to LOGBUF
- MVI C,SETDMA
- CALL BDOS
- XRA A
- STA FCBLOG+12
- STA FCBLOG+32
- MVI A,LOGDRV-'A'
- STA DEFAULT$DISK
- MVI A,LOGUSR
- STA DEFAULT$USER
- LXI D,FCBLOG
- CALL OPENF ; Open log file
- JNZ LOGC4 ; If file exists, skip create
- LXI D,FCBLOG
- MVI C,MAKE ; Create a new file if needed
- CALL BDOS
- INR A
- JNZ LOGC2 ; No error, cont.
- CALL ERXIT ; File create error
- DB '++ No dir space: log ++$'
- ;
- LOGC2: MVI C,SETRRD ; Set random record #
- LXI D,FCBLOG ; (for first record in file)
- CALL BDOS
- ;
- LOGC3: MVI A,EOF
- STA LOGBUF
- JMP LOGC4B
- ;
- LOGC4: MVI C,CFSIZE ; Get file length
- LXI D,FCBLOG
- CALL BDOS ; (end+1)
- LHLD FCBLOG+33 ; Back up to last record
- MOV A,L
- ORA H
- JZ LOGC3 ; Unless zero length file
- DCX H
- SHLD FCBLOG+33
- LXI D,FCBLOG
- MVI C,RRDM ; And read it
- CALL BDOS
- ;
- LOGC4B: CALL RSTLP ; Initialize LOGPTR and LOGCNT
- ;
- LOGC6: CALL GETLOG ; Get characters out of last record
- CPI EOF
- JNZ LOGC6 ; Until EOF
- LDA LOGCNT ; Then backup one character
- DCR A
- STA LOGCNT
- LHLD LOGPTR
- DCX H
- SHLD LOGPTR
- LDA LOGOPT ; Get option back and put in file
- CALL PUTLOG
- CALL SPEED ; Get speed factor
- ADI 30H
- CALL PUTLOG
- CALL PUTSP ; Blank
- LDA PGSIZE ; Now the program size in minutes..
- CALL PNDEC ; Of transfer time (mins)
- MVI A,':'
- CALL PUTLOG ; ':'
- LDA PGSIZE+2
- CALL PNDEC ; And secs..
- CALL PUTSP ; Blank
- ;
- ; Log the drive and user area as a prompt
- ;
- LDA FCB
- ORA A
- JNZ WDRV
- LDA DSKSAV
- INR A
- ;
- WDRV: ADI 'A'-1
- CALL PUTLOG
- LDA USRSAV
- CALL PNDEC
- MVI A,'>' ; Make it look like a prompt
- CALL PUTLOG
- LDA OPTSAV
- CPI 'L'
- JNZ WDRV1
- LXI H,MEMFCB ; Name of file in library
- MVI B,11
- CALL PUTSTR
- CALL PUTSP ; ' '
- ;
- WDRV1: LXI H,FCB+1 ; Now the name of the file
- MVI B,11
- CALL PUTSTR
- LDA OPTSAV
- CPI 'L'
- JNZ WDRV2
- MVI C,1
- JMP SPLOOP
- ;
- WDRV2: MVI C,13
- ;
- SPLOOP: PUSH B
- CALL PUTSP ; Put ' '
- POP B
- DCR C
- JNZ SPLOOP
- LHLD VRECNO ; Get VIRTUAL record count
- LXI D,8 ; Divide record count by 8
- CALL DVHLDE ; To get # of 1024 byte blocks
- MOV A,H
- ORA L ; Check if remainder
- MOV H,B ; Get quotient
- MOV L,C
- JZ EXKB2 ; If 0 remainder, exact kb
- INX H ; Else increment to next kb
- ;
- EXKB2: CALL PNDEC3 ; Print to log file (right just xxxk)
- LXI H,LOGK ; 'k '
- MVI B,2
- CALL PUTSTR
- ENDIF
- ;
- IF LOGCAL AND BYEBDOS
- MVI C,BDSTOS ; Set max time to 0 so BYE won't
- MVI E,0 ; hang up when doing BYEBDOS calls
- CALL BDOS ; when getting time/date
- ENDIF
- ;
- IF LOGCAL AND (B3RTC OR RTC OR BYEBDOS)
- CALL GETDATE ; IF RTC, get current date
- PUSH B ; (save DD/YY)
- CALL PNDEC ; Print MM
- MVI A,'/' ; '/'
- CALL PUTLOG
- POP PSW ; Get DD/YY
- PUSH PSW ; Save YY
- CALL PNDEC ; Print DD
- MVI A,'/' ; '/'
- CALL PUTLOG
- POP B ; Get YY
- MOV A,C
- CALL PNDEC ; Print YY
- CALL PUTSP ; ' '
- CALL GETTIME ; IF RTC, get current time
- STA MNSAV ; Save min
- MOV A,B ; Get current hour
- CALL PNDEC ; Print hr to file
- MVI A,':' ; With ':'
- CALL PUTLOG ; Between HH:MM
- LDA MNSAV ; Get min
- CALL PNDEC ; And print min
- CALL PUTSP ; Print a space
- ENDIF
- ;
- IF LOGCAL AND BYEBDOS
- LDA MAXTOS ; Reset time on system
- MOV E,A ; So BYE will hang up
- MVI C,BDSTOS ; If caller is over time limit
- CALL BDOS
- ENDIF
- ;
- IF LOGCAL AND OXGATE AND (B3RTC OR RTC OR BYEBDOS)
- XRA A
- STA CMMACNT ; Clear comma count
- ENDIF
- ;
- IF LOGCAL
- CLOOP: CALL GETCALLER ; And the caller
- CPI EOF
- JZ QUIT
- CPI CR ; Do not print 2nd line of 'LASTCALR'
- JNZ CLOP1
- CALL PUTLOG
- MVI A,LF
- CALL PUTLOG ; And add a LF
- JMP QUIT
- ;
- CLOP1: CPI ',' ; Do not print the ',' between names
- JNZ CLOP2
- ENDIF ; LOGCAL
- ;
- IF LOGCAL AND OXGATE AND (B3RTC OR RTC OR BYEBDOS)
- LDA CMMACNT ; Get comma count
- INR A
- STA CMMACNT
- CPI 2 ; If reached second comma, do CRLF exit
- JZ CLOPX
- ENDIF
- ;
- IF LOGCAL
- MVI A,' ' ; Instead send a ' '
- CLOP2: CALL PUTLOG
- JMP CLOOP
- ENDIF
- ;
- IF LOGCAL AND OXGATE AND (B3RTC OR RTC OR BYEBDOS)
- CLOPX: MVI A,CR ; Cloop exit... do a CRLF and finish up.
- CALL PUTLOG
- MVI A,LF
- CALL PUTLOG
- ENDIF
- ;
- IF LOGCAL
- QUIT: MVI A,EOF ; Put in EOF
- CALL PUTLOG
- LDA LOGCNT ; Check count of chars in buffer
- CPI 1
- JNZ QUIT ; Fill last buffer & write it
- LXI D,FCBCALLER ; Close lastcaller file
- MVI C,CLOSE
- CALL BDOS
- INR A
- JZ QUIT1
- LHLD FCBLOG+33 ; Move pointer back to show
- DCX H ; Actual file size
- SHLD FCBLOG+33
- LXI D,FCBLOG ; Close log file
- MVI C,CLOSE
- CALL BDOS
- INR A
- RNZ ; If OK, return now...
- ;
- QUIT1: CALL ERXIT ; If error, oops
- DB '++ Cannot close log ++$'
- ENDIF ; LOGCAL
- ;
- ;-----------------------------------------------------------------------
- ;
- ; Support routines for LOGCAL
- ;
- ; Gets a single byte from DBUF
- ;
- IF LOGCAL
- GETCALLER:
- LHLD CALLERPTR
- MOV A,M
- INX H
- SHLD CALLERPTR
- RET
- ;
- ; Gets a single byte from log file
- ;
- GETLOG: LDA LOGCNT
- INR A
- STA LOGCNT
- CPI 129
- JZ EOLF
- LHLD LOGPTR
- MOV A,M
- INX H
- SHLD LOGPTR
- RET
- ;
- EOLF: LHLD FCBLOG+33
- INX H
- SHLD FCBLOG+33
- LXI H,LOGBUF+1
- SHLD LOGPTR
- MVI A,1
- STA LOGCNT
- MVI A,EOF
- RET
- ;
- ; Open file with FCB pointed to by DE (disk/user passed in DEFAULT$DISK
- ; and DEFAULT$USER)
- ;
- OPENF: PUSH D ; Save FCB address
- LDA DEFAULT$DISK ; Get disk for file
- CALL RECDRX ; Log into it
- LDA DEFAULT$USER ; Get default user
- CALL RECARE ; Log into it
- POP D ; Get FCB address
- MVI C,OPEN ; Open file
- CALL BDOS
- CPI 255 ; Not present?
- RET ; Return to caller
- ;
- ; Write character to log file
- ;
- PUTLOG: LHLD LOGPTR ; Get pointer
- ANI 7FH ; Mask off any high bits
- MOV M,A ; Put data
- INX H ; Increment pointer
- SHLD LOGPTR ; Update pointer
- MOV B,A ; Save character in B
- LDA LOGCNT ; Get count
- INR A ; Increment it
- STA LOGCNT ; Update count
- CPI 129 ; Check it
- RNZ ; If not EOB, return
- PUSH B ; Save character
- LXI D,FCBLOG ; Else, write this sector
- MVI C,WRDM
- CALL BDOS
- ORA A
- JZ ADVRCP ; If ok, cont.
- CALL ERXIT
- DB '++ Disk full - cannot add to log ++$'
- ;
- ADVRCP: LHLD FCBLOG+33 ; Advance record number
- INX H
- SHLD FCBLOG+33
- CALL RSTLP ; Reset buffer pointers
- POP PSW ; Get saved character
- JMP PUTLOG ; Put it in buffer and return
- ;
- RSTLP: LXI H,LOGBUF ; Reset pointers
- SHLD LOGPTR ; And return
- MVI A,0
- STA LOGCNT
- RET
- ;
- ; Print number in decimal format (into log file)
- ; IN: HL=binary number
- ; OUT: nnn=right justified with spaces
- ;
- PNDEC3: MOV A,H ; Check high byte
- ORA A
- JNZ DECOT ; If on, is at least 3 digits
- MOV A,L ; Else, check low byte
- CPI 100
- JNC TEN
- CALL PUTSP
- ;
- TEN: CPI 10
- JNC DECOT
- CALL PUTSP
- JMP DECOT
- ;
- ; Puts a single space in log file, saves PSW/HL
- ;
- PUTSP: PUSH PSW
- PUSH H
- MVI A,' '
- CALL PUTLOG
- POP H
- POP PSW
- RET
- ;
- ; Print number in decimal format (into log file)
- ;
- PNDEC: CPI 10 ; Two column decimal format routine
- JC ONE ; One or two digits to area number?
- JMP TWO
- ;
- ONE: PUSH PSW
- MVI A,'0'
- CALL PUTLOG
- POP PSW
- ;
- TWO: MVI H,0
- MOV L,A
- ;
- DECOT: PUSH B
- PUSH D
- PUSH H
- LXI B,-10
- LXI D,-1
- ;
- DECOT2: DAD B
- INX D
- JC DECOT2
- LXI B,10
- DAD B
- XCHG
- MOV A,H
- ORA L
- CNZ DECOT
- MOV A,E
- ADI '0'
- CALL PUTLOG
- POP H
- POP D
- POP B
- RET
- ;
- ; Put string to log file
- ;
- PUTSTR: MOV A,M
- PUSH H
- PUSH B
- CALL PUTLOG
- POP B
- POP H
- INX H
- DCR B
- JNZ PUTSTR
- RET
- ENDIF ; LOGCAL
- ;
- ; end of LOGCAL routine
- ;-----------------------------------------------------------------------
- ; start of TIMEON routine
- ;
- ; Calculate time on system and inform user. Log him off if =>MAXMIN
- ; unless STATUS is non-zero.
- ;
- IF TIMEON
- TIME: PUSH B ; Save BC pair
- CALL GETTIME ; Get time from system's RTC
- STA CMTEMP ; Save in current-hour-temp
- MOV A,B ; Get current hour
- POP B ; Restore BC
- ENDIF
- ;
- IF TIMEON AND BYEBDOS
- PUSH PSW ; save the current hour <== BUG FIX
- PUSH B ; Lhour was safely moved to highmem
- PUSH D ; in newer versions of BYE
- MVI C,BDGRTC
- CALL BDOS
- LXI D,11 ; Get address of LHOUR
- DAD D
- POP D
- POP B
- POP PSW ; Restore current hour...BDOS killed it
- ENDIF
- ;
- IF TIMEON AND NOT BYEBDOS
- LXI H,LHOUR ; Point to log-on hour (in low memory)
- ENDIF
- ;
- IF TIMEON
- CMP M ; Equal?
- INX H ; Point to logon minutes
- JNZ TIME1 ; No
- MOV D,M
- LDA CMTEMP ; Current minutes
- SUB D
- STA TON ; Store total time on
- JMP TIME2
- ;
- TIME1: MOV D,M ; Get logon minutes
- MVI A,03CH ; 60 min into A
- SUB D
- LXI H,CMTEMP ; Point at current min
- ADD M ; Add current minutes
- STA TON
- ENDIF
- ;
- TIME2: IF ZCPR2 AND TIMEON
- LDA WHEEL ; Check wheel status if ZCPR
- ORA A ; Is it zero
- JNZ TIME3 ; If not then this is a special user
- ENDIF
- ;
- IF TIMEON
- LDA MAXTOS
- ORA A ; If maxtos is zero, guy is superuser
- JZ TIME3
- ENDIF
- ;
- IF TIMEON AND NOT BYEBDOS ; BYEBDOS doesn't use status byte
- ORA A ; Special user?
- JNZ TIME3 ; Yes, skip log off check
- LDA TON
- SUI MAXMIN ; Subtract max time allowed
- ENDIF
- ;
- IF TIMEON AND BYEBDOS
- LDA MAXTOS
- MOV B,A
- LDA TON
- SUB B
- ENDIF
- ;
- IF TIMEON
- JC TIME3 ; Still time left
- CALL TIMEUP ; Time is up, inform user
- MVI A,0CDH ; Alter jump vector
- STA 0 ; At zero
- JMP 0000H ; And log him off
- ;
- TIME3: LXI H,MSG1+015H ; Point at message insert bytes
- LDA TON ; Convert to ASCII
- MVI B,0FFH
- ;
- TIME4: INR B
- SUI 0AH ; Subtract 10
- JNC TIME4 ; Until done
- ADI 0AH
- ORI '0' ; Make ASCII
- MOV M,A
- DCX H
- MVI A,'0'
- ADD B
- MOV M,A
- CALL ILPRT
- ;
- MSG1: DB CR,LF,'Time on system is 00 minutes',CR,LF,0
- ENDIF
- ;
- IF TIMEON AND NOT BYEBDOS
- LDA STATUS ; Check user status
- ORA A ; Special user?
- JNZ TIME5 ; Yes, reset TON
- ENDIF
- ;
- IF TIMEON
- RET
- ENDIF
- ;
- IF TIMEON AND NOT BYEBDOS
- TIME5: MVI A,0 ; Reset timeout for good guys
- STA TON
- RET
- ENDIF
- ;
- IF TIMEON
- TIMEUP: CALL ILPRT
- DB CR,LF,CR,LF
- DB 'Your time is up - wait 24 hours to call back',CR,LF,0
- RET
- ;
- TON: DB 0 ; Storage for time on system
- CMTEMP: DB 0 ; Storage for current minute value
- ENDIF
- ;
- ; Get caller's time on system from BYE3 or MBYE and display on console.
- ;
- IF B3RTC AND B3TOS
- TIME: CALL ILPRT
- DB CR,LF,'Time on system is ',0
- CALL GETTOS ; Get Time On System from MBYE's RTC
- CALL DECOUT ; Print it on the screen
- CALL ILPRT
- DB ' minutes',CR,LF,0
- RET
- ENDIF
- ;
- ; Get caller's time on system (returned in HL).
- ;
- IF B3RTC AND (NOT BYEBDOS)
- GETTOS: LHLD RTCBUF ; Get RTCBUF addr
- MOV A,H
- ORA L
- RZ ; If 0000H, BYE not running so TOS=0
- MOV A,M ; If hours = 99
- CPI 099H
- LXI H,0
- RZ ; Return with TOS=0
- LHLD RTCBUF
- LXI D,B3CMOS ; Get offset to TOS word
- DAD D ; (addr in HL)
- MOV E,M ; Get minutes on system
- INX H
- MOV D,M ; Stuff into DE
- XCHG ; Swap into HL
- RET
- ENDIF
- ;
- IF BYEBDOS OR MXTOS
- MAXTOS: DB 0 ; Maximum time on system
- ENDIF
- ;
- ; end of TIMEON routine
- ;-----------------------------------------------------------------------
- ;
- GETDATE: IF (RTC AND LOGCAL) AND NOT (CPM3 OR BYEBDOS)
- LDA 45H ; Get the binary day number
- MOV B,A ; Set to return binary day # B reg.
- LDA 46H ; Get the binary year number
- MOV C,A ; Set to return binary year # in C reg.
- LDA 44H ; Get the binary month number
- RET
- ENDIF
- ;
- ;-----------------------------------------------------------------------
- ; start of CPM+ date routine
-
- IF RTC AND LOGCAL AND CPM3
- MVI C,GETTIM ; BDOS function to get date and time
- LXI D,TIMEPB ; Get address of 4-byte data structure
- CALL BDOS ; Transfer the current date/time
- LHLD TIMEPB
- MVI B,78 ; Set years counter
- ;
- LOOP: CALL CKLEAP
- LXI D,-365 ; Set up for subtract
- JNZ NOLPY ; Skip if no leap year
- DCX D ; Set for leap year
- ;
- NOLPY: DAD D ; Subtract
- JNC YDONE ; Continue if years done
- MOV A,H
- ORA L
- JZ YDONE
- SHLD TIMEPB ; Else save days count
- INR B ; Increment years count
- JMP LOOP ; And do again
- ;
- ; The years are now finished, the years count is in 'B' and TIMEPB holds
- ; the days (HL is invalid)
- ;
- YDONE: MOV A,B
- STA YEAR
- CALL CKLEAP ; Check if leap year
- MVI A,-28
- JNZ FEBNO ; February not 29 days
- MVI A,-29 ; Leap year
- ;
- FEBNO: STA FEB ; Set february
- LHLD TIMEPB ; Get days count
- LXI D,MTABLE ; Point to months table
- MVI B,0FFH ; Set up 'B' for subtract
- MVI A,0 ; Set a for # of months
- ;
- MLOOP: PUSH PSW
- LDAX D ; Get month
- MOV C,A ; Put in 'C' for subtract
- POP PSW
- SHLD TIMEPB ; Save days count
- DAD B ; Subtract
- INX D ; Increment months counter
- INR A
- JC MLOOP ; Loop for next month
- ;
- ; The months are finished, days count is on stack. First, calculate
- ; the month.
- ;
- MDONE: MOV B,A ; Save months
- LHLD TIMEPB
- MOV A,H
- ORA L
- JNZ NZD
- DCX D
- DCX D
- LDAX D
- CMA
- INR A
- MOV L,A
- DCR B
- ;
- NZD: MOV A,B
- STA MONTH
- MOV A,L
- STA DAY
- LDA YEAR
- MOV C,A
- LDA DAY
- MOV B,A
- LDA MONTH
- RET
- ;
- ; This routine checks for leap years.
- ;
- CKLEAP: MOV A,B
- ANI 0FCH
- CMP B
- RET
- ;
- ; This is the month's table
- ;
- MTABLE: DB -31 ; January
- FEB: DB -28 ; February
- DB -31,-30,-31,-30 ; Mar-Jun
- DB -31,-31,-30 ; Jul-Sep
- DB -31,-30,-31 ; Oct-Dec
- ;
- YEAR: DB 0
- MONTH: DB 0
- DAY: DB 0
- ENDIF ; RTC AND LOGCAL AND CPM3
- ;
- ; end of CPM+ date routine
- ;-----------------------------------------------------------------------
- ;
- IF LOGCAL AND B3RTC AND NOT BYEBDOS
- CALL BYECHK ; See if BYE is running
- JZ GETBDAT ; If so, get date from buffer & convert
- MVI A,0 ; Else, return 00/00/00
- MOV B,A
- MOV C,A
- RET
- ENDIF
- ;
- IF LOGCAL AND B3RTC AND (NOT BYEBDOS)
- GETBDAT:LHLD RTCBUF ; Get RTC buffer in HL
- ENDIF
- ;
- IF LOGCAL AND BYEBDOS AND (NOT B3RTC)
- MVI C,BDGRTC ; Get RTC buffer in HL
- CALL BDOS
- ENDIF
- ;
- IF LOGCAL AND (BYEBDOS OR B3RTC)
- LXI D,4 ; Offset to YY
- DAD D ; HL=YY Address
- MOV A,M ; Get YY
- CALL BCDBIN ; Make it binary
- STA YYSAV ; Save YY
- INX H ; Point to MM
- MOV A,M ; Get MM
- CALL BCDBIN ; Convert BCD to binary
- STA MMSAV ; Save it
- INX H ; Point to DD
- MOV A,M ; Get DAY
- CALL BCDBIN ; Convert it to binary
- MOV B,A ; Stuff DD in B
- LDA YYSAV ; Get YY
- MOV C,A ; Put YY in C
- LDA MMSAV ; Get MM in A
- RET ; And return
- ENDIF
- ;
- ;
- ; The routine here should read your real-time clock and return with the
- ; following information:
- ;
- ; register: A - current minute (0-59)
- ; B - current hour (0-23)
- ;
- GETTIME: IF (TIMEON OR RTC) AND NOT (B3RTC OR CPM3 OR BYEBDOS)
- ;
- ;; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- ;; (this example is for the Serria SBC-100)
- ;;
- ;;SBCHR EQU 040H ; Low memory area where stored
- ;;SBCMN EQU 041H
- ;;
- ;; LDA SBCHR ; Get hour from BIOS memory-clock
- ;; MOV B,A
- ;; LDA SBCMN ; Get minute from BIOS memory-clock
- ;; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- ;
- ;; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- ;; (this example is for Don Brown's computer)
- ;;
- ;; LDA 43h ; Get the current binary hour number
- ;; MOV B,A ; Set to return binary hour number in Reg. B
- ;; LDA 42h ; Get the current binary minute number
- ;; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- ;
- RET
- ENDIF
- ;
- ; The following code is for CP/M Plus
- ;
- IF (TIMEON OR RTC) AND CPM3
- MVI C,GETTIM ; BDOS function to get date and time
- LXI D,TIMEPB ; Get address of 4-byte data structure
- CALL BDOS ; Transfer the current date/time
- LDA TIMEPB+2 ; Get current hour
- CALL BCDBIN ; Convert BCD hour to binary
- MOV B,A ; Position hour for return
- PUSH B ; Save the binary hour
- LDA TIMEPB+3 ; Get current minute
- CALL BCDBIN ; Convert BCD minute to binary
- POP B ; Restore the binary hour
- RET
- ENDIF
- ;
- IF LOGCAL AND B3RTC AND (NOT BYEBDOS)
- CALL BYECHK ; See if BYE is running
- JZ GETBTIM ; If so, get time from buffer & convert
- MVI A,0 ; Else, return 00:00
- MOV B,A
- RET
- ;
- GETBTIM:LHLD RTCBUF ; Get RTC buffer address
- ENDIF
- ;
- IF LOGCAL AND BYEBDOS AND (NOT B3RTC)
- MVI C,BDGRTC ; Get RTC buffer address
- CALL BDOS
- ENDIF
- ;
- IF LOGCAL AND (B3RTC OR BYEBDOS)
- MOV A,M ; Get hours on system
- CALL BCDBIN ; Convert BCD value to binary
- PUSH PSW ; Save hr on stack
- INX H ; Point to minute
- MOV A,M ; Get min
- CALL BCDBIN ; Convert BCD to binary
- POP B ; Get hr in B (min in A)
- RET ; And return
- ENDIF
- ;
- ; Convert BCD value in A to binary in A
- ;
- IF LOGCAL AND (B3RTC OR CPM3 OR BYEBDOS)
- BCDBIN: PUSH PSW ; Save A
- ANI 0F0H ; Mask high nibble
- RRC ; Move to low nibble
- RRC
- RRC
- RRC
- MOV C,A ; And stuff in C (C=A)
- MVI B,9 ; X10 (*9)
- ;
- BCDBL: ADD C ; Add orig value to A
- DCR B ; Decrement B
- JNZ BCDBL ; Loop nine times (A+(C*9)=A*10)
- MOV B,A ; Save result in B
- POP PSW ; Get original value
- ANI 0FH ; Mask low nibble
- ADD B ; +B gives binary value of BCD digit A
- RET ; Return
- ENDIF
- ;
- ; Check to see that HL register is at least 8 records. If it not, make
- ; sure 1K blocks are turned off
- ;
- CKKSIZ: MOV A,H ; Get high order byte
- ORA A ; Something there?
- RNZ ; Yes, certainly more than 8
- MOV A,L ; Get low order byte
- CPI 8 ; Looking for at least this many records
- RNC ; Not Carry means 8 or more records
- XRA A ; Get nothing
- STA KFLAG ; Turn off 1K blocks
- RET
- ;
- ;-----------------------------------------------------------------------
- ;
- ; BYEBDOS access routines
- ;
- ;-----------------------------------------------------------------------
- ;
- IF BYEBDOS
- CONOUT: MOV E,C ; Get character into E
- MVI C,BDCONO ; Console output (local only)
- JMP BDOS ; Go to it...
- ;
- MINIT:
- UNINIT: RET ; Modem's already initialized
- ;
- SENDR: POP PSW ; Needed by specifications
- PUSH B
- PUSH D
- PUSH H
- MOV E,A ; Put character in E
- MVI C,BDMOUT
- CALL BDOS
- POP H
- POP D
- POP B
- RET
- ;
- GETCHR:
- MDIN: PUSH B
- PUSH D
- PUSH H
- MVI C,BDMINP
- CALL BDOS
- POP H
- POP D
- POP B
- RET
- ;
- ; The following 3 routines operate in differently than BYE does, so we
- ; must make things "backwards"
- ;
- CAROK: PUSH B
- PUSH D
- PUSH H
- MVI C,BDCSTA
- CALL BDOS
- JMP BKWDS
- ;
- RCVRDY: PUSH B
- PUSH D
- PUSH H
- MVI C,BDMIST
- CALL BDOS
- JMP BKWDS
- ;
- SNDRDY: PUSH B
- PUSH D
- PUSH H
- MVI C,BDMOST
- CALL BDOS
- ;
- ; Flip around bytes, if A>0 then make A zero & set flags
- ; if A=0 then make A =255 & set flags
- BKWDS: ORA A
- MVI A,255
- JZ NOSIG
- XRA A
- ;
- NOSIG: ORA A
- POP H
- POP D
- POP B
- RET
- ;
- SPEED: LDA MSPEED
- RET
- ENDIF
- ;
- ;-----------------------------------------------------------------------
- ;
- ; Temporary storage area
- ;
- ;-----------------------------------------------------------------------
- ;
- IF DESCRIB
- FILE: DB 0,'WHATSFORTXT',0,0,0,0,0,0,0
- DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0
- DEST: DB 0,' $$$',0,0,0,0,0,0,0
- DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0
- ENDIF
- ;
- ; Put this ram stuff in the RAM section at the end
- ;
- LZFLG: DB 0 ; For the free space printer
- BLKSHF: DB 0
- BLKMAX: DB 0,0
- ;
- IF B3RTC AND NOT BYEBDOS ; If BYE3/MBYE real-time clock
- RTCBUF: DW 0 ; Address of RTCBUF saved here
- ENDIF
- ;
- IF B3RTC AND NOT (MBMXT OR BYEBDOS)
- TOSSAV: DW 0
- ENDIF
- ;
- IF LOGCAL AND OXGATE AND (B3RTC OR RTC OR BYEBDOS)
- CMMACNT:DB 0 ; Comma counter
- ENDIF
- ;
- IF TIMEON AND CPM3
- TIMEPB: DS 4 ; Storage for the system date/time
- ENDIF
- ;
- MINUTE: DW 0 ; Transfer time in mins for MAXTIM
- MEMFCB: DB ' ' ; Library name (16 bytes required)
- ANYET: DB 0 ; Any description typed yet?
- BLKSIZ: DW 0 ; Number of bytes, 128 or 1024
- CONONL: DB 0 ; CTYPE console-only flag
- CRCFLG: DB 0 ; Sets to 'C' if checksum requested
- CRCVAL: DW 0 ; Current CRC value
- DIRSZ: DW 0 ; Directory size
- DRUSER: DB 0 ; Original drive/user, for return
- DUD: DB 0 ; Specified disk
- DUSAVE: DB 0,0,0,0 ; Buffer for drive/user
- DUU: DB 0 ; Specified user
- ERRCT: DB 0 ; Error count
- FRSTIM: DB 0 ; Turned on after first 'SOH' received
- INDEX: DW 0 ; Index into directory
- KFLAG: DB 0 ; Non-zero if sending 1K blocks
- OUTPTR: DW 0
- RCNT: DW 0 ; Record count
- RCVDRV: DB 0 ; Requested drive number
- RCVRNO: DB 0 ; Record number received
- RCVUSR: DB 0 ; Requested user number
- RECDNO: DW 0 ; Current record number
- KIND: DB 0 ; Asks what kind of file this is
- OLDDRV: DB 0 ; Save the original drive number
- OLDUSR: DB 0 ; Save the original user number
- OPTSAV: DB 0 ; Save option here for carrier loss
- PRVTFL: DB 0 ; Private user area option flag
- MSGFLG: DB 0 ; Message upload flag
- SAVEHL: DW 0 ; Saves TBUF command line address
- TOTERR: DW 0 ; Total errors for transmission attempt
- VRECNO: DW 0 ; Virtual record # in 128 byte records
- ;
- EOFLG: DB 0 ; 'EOF' flag (1=yes)
- EOFCTR: DB 0 ; EOF send counter
- OUTADR: DW LOGBUF
- OUTSIZ: DW BSIZE
- RECPTR: DW DBUF
- RECNBF: DW 0 ; Number of records in the buffer
- ;
- IF CONFUN AND SYSABT
- SYSABF: DB 0 ; set if sysop uses ^X to abort
- ENDIF
- ;
- IF (DESCRIB OR MBDESC) AND NDESC
- NDSCFL: DB 0 ; Used to store "RN" option
- ENDIF ; to bypass upload descriptions
- ;
- IF DESCRIB
- HLINE: DB '-------------------',CR,LF
- OLINE: DS 80 ; Temporary buffer to store line
- ENDIF
- ;
- DS 80 ; Minimum stack area
- ;
- ; Disk buffer
- ;
- ORG ($+127)/128*128
- ;
- DBUF EQU $ ; 16-record disk buffer
- STACK EQU DBUF-2 ; Save original stack address
- LOGBUF EQU DBUF+128 ; For use with LOGCAL
- ;
- ;-----------------------------------------------------------------------
- ;
- ; BDOS equates
- ;
- ;-----------------------------------------------------------------------
- ;
- RDCON EQU 1 ; Get character from console
- WRCON EQU 2 ; Output to console
- DIRCON EQU 6 ; Direct console output
- PRINT EQU 9 ; Print string function
- VERNO EQU 12 ; Get CP/M version number
- SELDSK EQU 14 ; Select drive
- OPEN EQU 15 ; 0FFH = not found
- CLOSE EQU 16 ; " "
- SRCHF EQU 17 ; " "
- SRCHN EQU 18 ; " "
- DELET EQU 19 ; Delete file
- READ EQU 20 ; 0=OK, 1=EOF
- WRITE EQU 21 ; 0=OK, 1=ERR, 2=?, 0FFH=no dir. space
- MAKE EQU 22 ; 0FFH=bad
- RENAME EQU 23 ; Rename a file
- CURDRV EQU 25 ; Get current drive
- SETDMA EQU 26 ; Set DMA
- SETATT EQU 30 ; Set file attributes
- SETUSR EQU 32 ; Set user area to receive file
- RRDM EQU 33 ; Read random
- WRDM EQU 34 ; Write random
- CFSIZE EQU 35 ; Compute file size
- SETRRD EQU 36 ; Set random record
- GETTIM EQU 105 ; CP/M Plus get date/time
- BDOS EQU 0005H
- TBUF EQU 0080H ; Default DMA address
- FCB EQU 005CH ; System FCB
- FCBEXT EQU FCB+12 ; File extent
- FCBRNO EQU FCB+32 ; Record number
- RANDOM EQU FCB+33 ; Random record field
- ;
- ; Extended BYEBDOS equates
- ;
- IF BYEBDOS
- BDMIST EQU 61 ; Modem raw input status
- BDMOST EQU 62 ; Modem raw output status
- BDMOUT EQU 63 ; Modem output 8 bit char
- BDMINP EQU 64 ; Modem input 8 bit char
- BDCSTA EQU 65 ; Modem carrier status
- BDCONS EQU 66 ; Local console input status
- BDCONI EQU 67 ; Local console input char
- BDCONO EQU 68 ; Local console output char
- BDMXDR EQU 69 ; Set/get maximum drive
- BDMXUS EQU 70 ; Set/get maximum user area
- BDNULL EQU 72 ; Set/get nulls
- BDTOUT EQU 71 ; Set/get idle timeout
- BDULCS EQU 73 ; Set/get upperlowercase switch
- BDLFMS EQU 74 ; Set/get line-feed mask
- BDHRDL EQU 76 ; Set/get hardlog
- BDWRTL EQU 75 ; Set/get writeloc
- BDMDMO EQU 77 ; Set/get mdmoff flag
- BDBELL EQU 78 ; Set/get bell mask flag
- BDGRTC EQU 79 ; Get address of rtc buffer
- BDGLCB EQU 80 ; Get address of lc buffer
- BDSTOS EQU 81 ; Maximum time on system
- BDSLGT EQU 82 ; Set login time
- BDPTOS EQU 83 ; Print Time on System
- ENDIF ; BYEBDOS
- ;
- END