home *** CD-ROM | disk | FTP | other *** search
/ ftp.barnyard.co.uk / 2015.02.ftp.barnyard.co.uk.tar / ftp.barnyard.co.uk / cpm / walnut-creek-CDROM / CPM / MODEMS / XMODEM / XMDM125.ARK / XMDM125.ASM < prev    next >
Assembly Source File  |  1986-07-15  |  142KB  |  5,714 lines

  1. ;
  2. ;    TITLE    'XMODEM ver. 12.5 - 07/13/86'
  3. ;
  4. ;    XMDM125.ASM - REMOTE CP/M FILE TRANSFER PROGRAM
  5. ;
  6. ;    Originally adapted from Ward Christensen's MODEM2
  7. ;            by Keith Petersen, W8SDZ
  8. ;
  9. ;    ASEG        ;Needed by M80 assemblers, comment out if using MAC
  10. ;
  11. ; This program allows a remote user to transfer files (to or from) RCPM
  12. ; systems running under BYE (remote console program).  It can be assem-
  13. ; bled with ASM, LASM, MAC, M80, SRLMAC and other 8080 assemblers.
  14. ;
  15. ; All comments and past revisions have been removed from this file and
  16. ; put into the XMODEM.UPD file.  Place only the current revision at the
  17. ; beginning of this file and move the one that was here to XMODEM.UPD.
  18. ;
  19. ;=======================================================================
  20. ;
  21. ;  v12.5    Fixed conditional assembly bug which caused date to
  22. ;  07/13/86    appear in log twice when MBBS and BYEBDOS were both set
  23. ;        to YES.
  24. ;        Fixed conditional assembly bug which did not allow MBFMSG
  25. ;        to be set to YES while MBDESC was set to NO.
  26. ;        Removed patch to log download before sending EOF because
  27. ;        EOF would not be sent, leaving caller's program in file
  28. ;        transfer mode, if LOGCALL routine exited with an error.
  29. ;        This problem was noticed by Keith Petersen.
  30. ;        Modified to abort any download which would result in a
  31. ;        user exceeding his time limit when BYEBDOS is YES.
  32. ;        Fixed bug which would cause caller to be logged off
  33. ;        without updating log file if transmission errors caused
  34. ;        his download to put him over time limit when BYEBDOS was
  35. ;        YES and CLOCK and TIMEON in BYE were YES (call to TCHECK
  36. ;        in BYE's extended BDOS call would hang up on caller).
  37. ;        Revised comments for some equates to make them easier to
  38. ;        understand.
  39. ;                        - Murray Simsolo
  40. ;
  41. ;========================================================================
  42. ;
  43. VERSION    EQU    1
  44. INTERM    EQU    2
  45. MODLEV    EQU    5
  46. VMONTH    EQU    07
  47. VDAY    EQU    13
  48. VYEAR    EQU    86
  49. ;
  50. NO    EQU    0
  51. YES    EQU    NOT NO
  52. ;
  53. ; Define ASCII characters used
  54. ;
  55. BS    EQU    08H    ; Backspace character
  56. ACK    EQU    06H    ; Acknowledge
  57. CAN    EQU    18H    ; CTL-X for cancel
  58. CR    EQU    0DH    ; Carriage return
  59. CRC    EQU    'C'    ; CRC request character
  60. EOF    EQU    1AH    ; End of file - ^Z
  61. EOT    EQU    04H    ; End of transmission
  62. LF    EQU    0AH    ; Line feed
  63. NAK    EQU    15H    ; Negative acknowledge
  64. RLEN    EQU    128    ; Record length
  65. TAB    EQU    09H    ; Horizontal tab
  66. SOH    EQU    01H    ; Start of header for 128-byte blocks
  67. STX    EQU    02H    ; 'Start of header' for 1024 byte blocks
  68. ;
  69. ;=======================================================================
  70. ;
  71. ; Conditional equates - change to suit your system, then assemble
  72. ;
  73. MHZ    EQU    4    ; Clock speed, use integer (2,4,5,8, etc.)
  74. CPM3    EQU    NO    ; Yes, if operating in CP/M v3.0 environment
  75. STOPBIT    EQU    NO    ; No, if using 1 stop bit, yes if using 2
  76. BYEBDOS    EQU    NO    ; Yes, if using BYE338-up, BYE501-up, or NUBYE
  77.             ; with its I/O (CLOCK in BYE must be YES)
  78.             ; No if using your own hardware overlay
  79. LUXMOD    EQU    NO    ; Set to YES if LUXMODEM version desired rather
  80.             ; than standard XMODEM with upload options.
  81. ;
  82. ;=======================================================================
  83. ;
  84. ; If OK2400 is YES, then it overrides the TAGLBR and MAXMIN restrictions
  85. ; if the current caller is operating at 2400 baud (or higher).
  86. ;
  87. OK2400    EQU    NO    ; Yes, no restrictions for 2400 bps callers
  88. ;
  89. MSPEED    EQU    3CH    ; Location of speed byte set by BYE prgm, must
  90.             ; be set for OK2400 or BYEBDOS to work
  91. ;
  92. DSPFNAM    EQU    YES    ; Set to YES if you wish XMODEM to display the
  93.             ; file name being up or downloaded for user to
  94.             ; see and verify system received name correctly.
  95. ;
  96. ; If ZCPR3 is YES, then NO filetypes of .NDR or .RCP will be received.
  97. ; This is for security if you need LDR.COM on A0: for cold starts or if
  98. ; LDR is in the defined path. (If you don't have LDR on-line or
  99. ; accessible, then this equate isn't necessary for ZCPR3 systems.)
  100. ;
  101. ZCPR3    EQU    NO    ; Yes, NO filetypes .NDR or .RCP received
  102. ;
  103. ;=======================================================================
  104. ;
  105. ; If ZCPR2 = yes, then the following will all be NO if wheel is set
  106. ; in local non-zero (0FFH) mode.  SYSOP rules...
  107. ;
  108. ZCPR2    EQU    NO    ; Yes, if using ZCPR* with WHEEL byte
  109. ;
  110. WHEEL    EQU    3EH    ; Location of wheel byte (normally 3EH)
  111. NOCOMR    EQU    YES    ; Yes, change .COM to .OBJ on receive
  112. NOCOMS    EQU    YES    ; Yes, .COM files not sent
  113. NOLBS    EQU    NO    ; Yes, .??# files not sent
  114. NOSYS    EQU    YES    ; Yes, no $SYS files sent or reported
  115. ;
  116. ;=======================================================================
  117. ;
  118. ; The following are only used by NZCPR or ZCMD systems
  119. ;
  120. USEMAX    EQU    NO    ; Yes, using NZCPR for maximum du: values
  121.             ; No, use MAXDRV and MAXUSR specified next
  122. DRIVMAX    EQU    03DH    ; Location of MAXDRIV byte
  123. USRMAX    EQU    03FH    ; Location of MAXUSER byte
  124. ;
  125. ;=======================================================================
  126. ;
  127. ; Hard-coded system maximums allowed if USEMAX above is NO
  128. ;
  129. MAXDRV    EQU    4    ; Number of disk drives used (1=A, 2=B, etc)
  130. MAXUSR    EQU    5    ; Maximum 'SEND' user allowed
  131. ;
  132. ;=======================================================================
  133. ;
  134. ; File transfer buffer size - 16k is the same buffer length used in IMP,
  135. ; MDM7 and MEX so all those modem programs as well as XMODEM would be
  136. ; transferring from the buffer simultaneously, minimizing any delays.
  137. ; Slower floppy disk drives may require the use of a smaller buffer, try
  138. ; 8k, 4k, or 2k and use largest that does not result in a time-out at
  139. ; the sending end.  Please note the requirement for the protocol to ac-
  140. ; cept any mixture of 1K and small blocks may result in effective buffer
  141. ; usage extending an additional 896 bytes (7*128) beyond the 'end' of
  142. ; the buffer defined here. (Actually, due to handshaking, the buffers
  143. ; are NOT loaded simultaneously, so the above statement is misleading,
  144. ; too large a buffer will slow things down if you have a slow disk
  145. ; drive.. Too small a buffer will really slow you down though, so
  146. ; stick with 16k...)
  147. ;
  148. BUFSIZ    EQU    16    ; File transfer buffer size in Kbytes (16k)
  149. ;
  150. ;=======================================================================
  151. ;
  152. ; DESCRIB is used to ask the uploader to give a description of the file
  153. ; he just uploaded.  If YES and ZCPR2 is YES and wheel is set, it does
  154. ; NOT ask for a description unless ASKSYS is set to YES.
  155. ; (If using on an MBBS v4.1 and up system, use MBDESC instead of
  156. ; this option.) (NDESC can be used with either DESCRIB or MBDESC.)
  157. ;
  158. DESCRIB    EQU    NO    ; Yes asks for a description of uploaded file
  159. DRIVE    EQU    'A'    ; Drive area for description of upload
  160. USER    EQU    14    ; User area for description of upload
  161. BSIZE    EQU    32*1024    ; Set for 16k, 24k or 32k as desired for DESCRIB
  162. ;
  163. NDESC    EQU    NO    ; If YES, user can add a "N" to option to skip
  164.             ; description for pre-arranged uploads or
  165.             ; for the sysop..
  166. ASKSYS    EQU    NO    ; If YES, and ZCPR2=YES, the system will ask
  167.             ; the sysop for a description of the uploaded
  168.             ; file
  169. ASKIND EQU    NO    ; IF YES, user is asked for the category of
  170.             ; the uploaded file. This category is auto-
  171.             ; matically added to the file description.
  172. ;
  173. ;=======================================================================
  174. ;
  175. ; XMODEM transfer log options
  176. ;
  177. LOGCAL    EQU    YES    ; Yes, logs XMODEM transfers
  178. LOGDRV    EQU    'A'    ; Drive to place 'XMODEM.LOG' file
  179. LOGUSR    EQU    14    ; User area to put 'XMODEM.LOG' file
  180. ;
  181. ; OxGate BBS puts the date after the caller's name.  If you are using
  182. ; either BYEBDOS or B3RTC or RTC, and have an OxGate, then set this
  183. ; equate to YES, so the date doesn't appear twice.
  184. ;
  185. OXGATE    EQU    NO    ; If yes, and B3RTC or RTC is yes, does not read
  186.             ; date in OxGate's LASTCALR file.
  187. ;
  188. KNET    EQU    NO    ; If yes, the log file is called XMODEM.TX# with
  189.             ; $SYS attr set (for K-NET 84(tm) RCP/M Systems)
  190. ;
  191. LASTDRV    EQU    'A'    ; Drive to read 'LASTCALR' file from
  192. LASTUSR    EQU    14    ; User area of 'LASTCALR' file, if 'LOGCAL' yes
  193. ;
  194. ;=======================================================================
  195. ;
  196. ; The receiving station sends an 'ACK' for each valid sector received.
  197. ; It sends a 'NAK' for each sector incorrectly received.  In poor con-
  198. ; ditions either may be garbled.  Waiting for a valid 'NAK' can slow
  199. ; things down somewhat, giving more time for the interference to quit.
  200. ;
  201. RETRY    EQU    NO    ; Yes requires a valid NAK to resend a record
  202.             ; No resends a record after any non-ACK
  203. ;
  204. ; Note that some modem programs will send a "C" instead of a NAK when
  205. ; operating in CRC mode. Therefore, RETRY EQU NO will allow XMODEM to
  206. ; work correctly with more programs.
  207. ;
  208. ;=======================================================================
  209. ;
  210. ; When sending in 1K block mode, XMODEM will downshift to 128 byte
  211. ; blocks when the ratio of successfully transmitted blocks to total
  212. ; errors falls below the ratio defined here.
  213. ;
  214. DWNSHFT    EQU    5    ; must have at least this many good blocks for
  215.             ; every error, or will downshift to size 128
  216. ;
  217. MINKSP    EQU    5    ; set this equate to the minimum MSPEED value
  218.             ; allowed to use the 1k block protocol..
  219. ;
  220. ; MSPEED values: 1=300, 5=1200, 6=2400
  221. ;
  222. ;=======================================================================
  223. ;
  224. ; Allows uploading to be done on a specified driver and user area so all
  225. ; can readily find the latest entries.
  226. ;
  227. SETAREA    EQU    YES    ; Yes, using designated du: to receive files
  228.             ; No, upload to currently logged du:
  229. SPCDU    EQU    YES    ; Yes, upload to designated du: if wheel set
  230. ;
  231. DRV    EQU    'B'    ; Drive to receive file on
  232. USR    EQU    0    ; User area to receive file in
  233. ;
  234. ASKAREA    EQU    NO    ; If YES, ask user what type of upload and
  235.             ; set area accordingly. For Multiple
  236.             ; Operating system support.
  237. ;
  238. SYSNEW    EQU    NO    ; If YES, then new uploads are made $SYS
  239.             ; to "hide" them from users until cleared...
  240. ;
  241. ;=======================================================================
  242. ;
  243. ; Selects the DU: for uploading private files with XMODEM RP option.
  244. ;
  245. PRDRV    EQU    'B'    ; Private drive for SYSOP to receive file
  246. PRUSR    EQU    14    ; Private user area for SYSOP to receive file
  247. ;
  248. ;=======================================================================
  249. ;
  250. ; Selects the DU: for private download files.  This permits Sysop
  251. ; to put file(s) in this area, then leave a private note to that
  252. ; person mentioning the name(s) of the file and its location.
  253. ;
  254. SPLDRV    EQU    'B'    ; Special drive area for downloading SYSOP files
  255. SPLUSR    EQU    14    ; Special user area for downloading SYSOP files
  256. ;
  257. ;=======================================================================
  258. ;
  259. ; Selects the DU: used for message files uploaded with the "RM" option.
  260. ; (Used only if MBFMSG option enabled)
  261. ;
  262. MSGDRV    EQU    'A'    ; Drive used to receive message files
  263. MSGUSR    EQU    15    ; User used to receive message files
  264. ;
  265. ;=======================================================================
  266. ;
  267. ; SYSOP may use NSWP or TAG and set the high bit of F1 to disallow the
  268. ; sending of large .LBR files.    If TAGLBR is YES, only LUX or the option
  269. ; XMODEM L will allow transfer of individual member files from tagged
  270. ; .LBR files.  The entire .LBR file can NOT be sent using XMODEM S NAME.
  271. ;
  272. TAGLBR    EQU    NO    ; Yes tagged .LBR files not sent
  273. ;
  274. ; Note: The OK2400 equate if YES will bypass this restriction if the
  275. ;    caller is operating at 2400 baud (or faster).
  276. ;
  277. ;=======================================================================
  278. ;
  279. ; Some modems will either go onhook immediately after carrier loss or
  280. ; can be set to lower values.  A good value with the Smartmodem is five
  281. ; seconds, since it catches all "call forwarding" breaks.  Not all is
  282. ; lost after timeout in XMODEM; BYE will still wait some more, but the
  283. ; chance of someone slipping in is less now.
  284. ;
  285. TIMOUT    EQU    2    ; Seconds to abort after carrier loss
  286. ;
  287. ;=======================================================================
  288. ;
  289. ; Count the number of up/down loads since login.  Your BBS program can
  290. ; check UPLDS and NDLDS when user logs out and update either the users
  291. ; file or another file for this purpose.
  292. ;
  293. LOGLDS    EQU    NO    ; Count number of up/down loads since login.
  294. ;
  295.      IF    LOGLDS
  296. UPLDS    EQU    054H    ; Clear these values to Zero from your BBS pro-
  297. DNLDS    EQU    055H    ;   gram when somebody logs in.  NOTE:    Clear
  298.             ;   ONLY when a user logs in.  Not when he re-
  299.             ;   enters the BBS program for CP/M.
  300.      ENDIF
  301. ;
  302. ;======================================================================
  303. ;
  304. ; Maximum file transfer time allowed.
  305. ;
  306. ; NOTE: If ZCPR2 = YES and WHEEL byte is set, send time is unlimited.
  307. ;
  308. ;         TIME    300 BPS  1200 BPS
  309. ;        ------    -------  --------
  310. ;        30 min     48.7k       180k
  311. ;        45 min     73.1k       270k
  312. ;        60 min     97.5k       360k
  313. ;
  314. MAXTIM    EQU    YES    ; Yes if limiting transmission time
  315. ;
  316. MAXMIN    EQU    60    ; Minutes for maximum file transfer time.
  317.             ;   this should be set to 60 if TIMEON is YES
  318.             ;   (99 minutes maximum.) (This is ignored if
  319.             ;   BYEBDOS is set.)
  320. ;
  321. ; Note: The OK2400 equate if YES will bypass MAXMIN limits.
  322. ;
  323. ;======================================================================
  324. ;
  325. ; The following equates need to be set ONLY if you are NOT using the
  326. ; BYE-BDOS calls supported in BYE338 and newer.
  327. ;
  328. ; Length of external patch program.  If over 128 bytes, get/set size
  329. ;
  330. LARGEIO    EQU    NO    ; Yes, if modem patch area over 128 bytes
  331. LARSIZE    EQU    0    ; If 'LARGEIO' set patch area size (bytes) here
  332. ;
  333. ;=======================================================================
  334. ;
  335. ; USECON allows XMODEM to display the record count on the local CRT
  336. ; during transfers.  All new remote console programs support this
  337. ; feature.  BYE3* and MBYE3* will tell XMODEM where to find the local
  338. ; console's output vector.
  339. ;
  340. USECON    EQU    YES    ; Yes to get CONOUT address from BYE
  341.             ; NO, get CONOUT address from the XMODEM overlay
  342. ;
  343. CONOFF    EQU    15    ; Offset to COVECT where original console output
  344.             ;   routine address is stored in BYE3/MBYE
  345.             ;   versions immediately followed by BYE as a
  346.             ;   check to insure BYE is running.
  347. ;
  348. ;=======================================================================
  349. ;            start of TIMEON area
  350. ;
  351. RTC    EQU    NO    ; If YES, add clock and date reader code at
  352.             ; start of GETTIME: and GETDATE: below
  353. ;
  354. ; The TIMEON and RTC equates should be NO if B3RTC is YES
  355. ;
  356. TIMEON    EQU    NO    ; If YES and BYEBDOS is NO, add your clock reader
  357.             ; code at the start of label GETTIME: and return
  358.             ; time in registers A & B.  Also set to YES if
  359.             ; BYEBDOS is YES and you want XMODEM to check
  360.             ; time on system (not necessary if TIMEON in BYE
  361.             ; is YES - saves unnecessary code).
  362. TOSEXIT    EQU    NO    ; If YES, time on system displayed on exit if
  363.             ; B3RTC or TIMEON or BYEBDOS set to YES
  364. ;
  365.      IF    TIMEON AND NOT CPM3
  366. LHOUR    EQU    050H    ; Set by BBS (or BYE) in binary when user logs
  367. LMIN    EQU    051H    ; on and his status
  368. STATUS    EQU    053H
  369.      ENDIF
  370. ;
  371.      IF    TIMEON AND CPM3
  372. LHOUR    EQU    022H    ; Set by BBS (or BYE) in binary when user logs
  373. LMIN    EQU    023H    ; on and his status
  374. STATUS    EQU    024H
  375.      ENDIF
  376. ;
  377. ;           end of TIMEON area
  378. ;========================================================================
  379. ;           Miscellaneous Support Bytes
  380. ;========================================================================
  381. ; Set this equate to enable access byte support.  ACBOFF specifies
  382. ; the offset from the JMP COLDBOOT instruction as above with WRTLOC.
  383. ; MBBS and some newer BBS's support this byte, therefore, it is no
  384. ; longer specific to MBBS. You must determine if your system uses this.
  385. ;
  386. ACCESS    EQU    NO    ; Yes, check flags for upload/dwnld restrictions
  387. ACBOFF    EQU    21    ; # of bytes from JMP COLDBOOT to ACCESS byte.
  388. ACWRIT    EQU    8    ; Bit to test for BBS msg write OK (1=OK,0=NOT OK)
  389. ACDNLD    EQU    32    ; Bit to test for downloads OK (1=OK,0=NOT OK)
  390. ACUPLD    EQU    64    ; Bit to test for uploads OK (1=OK,0=NOT OK)
  391. DWNTAG    EQU    NO    ; If YES, files with F3 attribute bit can be
  392.             ; downloaded regardless of access byte restrictions
  393. ;
  394. ; Access byte flag bit assignments
  395. ;
  396. ;    Bit    ; Used for
  397. ;    0    ; System access (no admittance if off)
  398. ;    1    ; BBS access (if off, dumped to CP/M)
  399. ;    2    ; Read access (if off, no "R" command allowed)
  400. ;    3    ; Write access (if off, no "E" command allowed)
  401. ;    4    ; CP/M access (if off, no admittance to CP/M)
  402. ;    5    ; Download access (if off, no downloads permitted)
  403. ;    6    ; Upload access (if off, no uploads permitted)
  404. ;    7    ; Privileged user (if on, user is "privileged")
  405. ;
  406. ; Of these bits, only 5 and 6 are used by XMODEM.  Bit numbers are
  407. ; powers of 2, bit 0 being least significant bit of byte.
  408. ;-------------------------------------------------------------------------
  409. ; The CONFUN and WRTLOC are supported by BYE339 and many BBS's require
  410. ; the WRTLOC for propoer operation. These functions are not specific to
  411. ; MBBS and therefore have been made independant of the MBBS equate.
  412. ;
  413. ; (Set CONFUN/WRTLOC YES if using with MBBS)
  414. ;
  415. CONFUN    EQU    YES    ; Yes, check local console for function keys
  416. SYSABT    EQU    YES    ; If yes, sysop can abort up/downloads with ^X
  417.             ; (CONFUN must be enabled to use this option)
  418. ;
  419. ; If you set CONFUN true, a call to the console status check routine in
  420. ; the BIOS will be done during waiting periods and when sector counts
  421. ; are displayed on the local console in order to allow MBYE and BYE339
  422. ; function keys to work.  This is for MBYE.  Other versions of BYE3
  423. ; may or may not check for console function keys during the console
  424. ; status check "MSTAT" routine.
  425. ;
  426. WRTLOC    EQU    YES    ; Yes, set/reset WRTLOC so BYE won't hang up
  427. LOCOFF    EQU    12    ; # of bytes from JMP COLDBOOT to WRTLOC byte
  428. ;
  429. ; NOTE: Code to set/reset WRTLOC assumes WRTLOC byte to be
  430. ;    located "LOCOFF" bytes from the JMP COLDBOOT instruction at
  431. ;    the beginning of the BYE3 BIOS jump table. On BYE3 versions
  432. ;    and MBYE versions, this offset is usually 12. Note:
  433. ;    TIMEON and RTC should be set to no if B3RTC is on.
  434. ;    (If BYEBDOS is enabled, the appropriate extended BDOS
  435. ;    calls are used to set and reset the WRTLOC if this
  436. ;    equate is set and LOCOFF is ignored in these cases.)
  437. ;
  438. ;           End of Miscellaneous Support Bytes
  439. ;=======================================================================
  440. ;        start of MBBS/MBYE specific information
  441. ;
  442. B3RTC    EQU    NO    ; If YES, your clock is setup in BYE3 (or MBYE)
  443.             ; set to NO if using BYEBDOS
  444. B3COFF    EQU    25    ; OFFSET from COLDBOOT: to RTCBUF address
  445. B3CMOS    EQU    7    ; OFFSET from RTCBUF: to mins on system
  446. ;
  447. MBMXT    EQU    NO    ; If YES, running MBYE with max. time on system
  448. MBMXO    EQU    24    ; OFFSET from COLDBOOT: to MXML address
  449. ;
  450. ; If B3RTC is YES and LOGCAL is YES, the log file will show
  451. ; the date and time of all up/downloads.  Note: Set RTC, TIMEON,
  452. ; and BYEBDOS to NO if using B3RTC or MBMXT.
  453. ;
  454. ; Note: Some of these equates may not be valid if you are using MBYE*
  455. ;    with another BBS program - check them carefully.
  456. ;
  457. MBBS    EQU    NO    ; Yes if running MBBS v2.9 up
  458. LOGSYS    EQU    NO    ; Set YES if running MBBS v3.1 or earlier
  459. MBDESC    EQU    NO    ; Yes if running MBBS v4.0 up for upload desc.
  460. NEWPRV    EQU    NO    ; Yes: all new uploads are private initially
  461. MBFMSG    EQU    NO    ; Yes if running MBYE v4.1 up with MFMSG
  462. ;
  463. ;
  464. ;----------------------------------------------------------------------
  465. ;
  466. ; If B3RTC is YES download time may be limited using the following
  467. ; equates instead of using MAXMIN.  MAXMIN will be the default value
  468. ; if BYE is not running.
  469. ;
  470. B3TOS    EQU    NO    ; Yes if using BYE3/MBYE and want to show time on sys
  471. ;
  472. MTOS    EQU    NO    ; Yes if using maximum time on system instead
  473.             ;   of MAXMIN to limit transmission time
  474. ;
  475.      IF    MTOS AND MBMXT    ; both must be YES
  476. MXTOS    EQU    YES    ; (leave YES)
  477.      ENDIF
  478. ;
  479.      IF    NOT (MTOS AND MBMXT) ; (if either is NO)
  480. MXTOS    EQU    NO    ; (leave NO)
  481.      ENDIF
  482. ;
  483. MXTL    EQU    NO    ; Yes if limiting transmission time to time
  484.             ;   left plus MAXMIN. MXTOS must be yes.
  485. ;
  486.      IF    MXTL AND MXTOS    ; both must be YES
  487. MTL    EQU    YES    ; (leave YES)
  488.      ENDIF
  489. ;
  490.      IF    NOT (MXTL AND MXTOS); (if either are NO)
  491. MTL    EQU    NO    ; (leave NO)
  492.      ENDIF
  493. ;
  494. ;        end of MBBS/MBYE specific information
  495. ;=======================================================================
  496. ;
  497.     ORG    100H
  498.     JMP    BEGIN
  499. ;
  500. ;-----------------------------------------------------------------------
  501. ;
  502. ; This is the I/O patch area.  Assemble the appropriate I/O patch file
  503. ; for your modem, then integrate it into this program via DDT (or SID).
  504. ; Initially, all jumps are to zero, which will cause an unpatched XMODEM
  505. ; to simply execute a warm boot.  All routines must end with RET.
  506. ;
  507.      IF    NOT BYEBDOS    ; Universal I/O
  508. CONOUT:    JMP    0        ; See 'CONOUT' discussion above
  509. MINIT:    JMP    0        ; Initialization routine (if needed)
  510. UNINIT:    JMP    0        ; Undo whatever MINIT did (or return)
  511. SENDR:    JMP    0        ; Send character (via POP PSW)
  512. CAROK:    JMP    0        ; Test for carrier
  513. MDIN:    JMP    0        ; Receive data byte
  514. GETCHR:    JMP    0        ; Get character from modem
  515. RCVRDY:    JMP    0        ; Check receive ready (A - ERRCDE)
  516. SNDRDY:    JMP    0        ; Check send ready
  517. SPEED:    JMP    0        ; Get speed value for transfer time
  518. EXTRA1:    JMP    0        ; Extra for custom routine
  519. EXTRA2:    JMP    0        ; Extra for custom routine
  520. EXTRA3:    JMP    0        ; Extra for custom routine
  521.      ENDIF
  522. ;
  523. ;-----------------------------------------------------------------------
  524. ;
  525.      IF    NOT (LARGEIO OR    BYEBDOS)
  526.     ORG    100H+80H    ; Origin plus 128 bytes for patches
  527.      ENDIF
  528. ;
  529.      IF    LARGEIO    AND NOT    BYEBDOS
  530.     ORG    100H+LARSIZE    ; I/O patch area size if over 128 bytes
  531.      ENDIF
  532. ;
  533. ; PRIVATE/SETAREA UPLOAD DISK/USER AREAS:
  534. ;
  535. ; (Here at start (usually 180H unless LARGEIO) so can be easily patched
  536. ; in .COM file using DDT without needing to reassemble.  All references
  537. ; are made to these locations in memory and not to DRV/PRDRV/USR/PRUSR
  538. ; equates directly.)
  539. ;
  540. XPRDRV:    DB    PRDRV        ; Private uploads go to this disk/user
  541. XPRUSR:    DB    PRUSR
  542. ;
  543. XDRV:    DB    DRV        ; Forced uploads (if SETAREA EQU YES)
  544. XUSR:    DB    USR        ; Go to this disk/user
  545. ;
  546.      IF    MBFMSG
  547. XMDRV:    DB    MSGDRV        ; Message uploads go to this disk/user
  548. XMUSR:    DB    MSGUSR        ; (if MBFMSG option enabled)
  549.      ENDIF
  550. ;
  551. ;-----------------------------------------------------------------------
  552. ;
  553. ; File descriptors, change as desired if this list is not suitable.
  554. ; Move the line with the terminating '$' up, if fewer descriptors are
  555. ; desired.
  556. ;
  557.     IF    ASKIND AND DESCRIB
  558. ;
  559. KIND0:    DB    '  0) - CP/M',CR,LF
  560. KIND1:    DB    '  1) - ZCPR',CR,LF
  561. KIND2:    DB    '  2) - MS-DOS/PC-DOS',CR,LF
  562. KIND3:    DB    '  3) - dBASE',CR,LF
  563. KIND4:    DB    '  4) - Basic',CR,LF
  564. KIND5:    DB    '  5) - General',CR,LF
  565. KIND6:    DB    '  6) - Modems',CR,LF
  566. KIND7:    DB    '  7) - Games',CR,LF
  567. KIND8:    DB    '  8) - Xerox/KPro',CR,LF
  568. KIND9:    DB    '  9) - RCP/M',CR,LF
  569.     DB    '$'
  570.     ENDIF
  571. ;.....
  572. ;
  573. ;----------------------------------------------------------------------
  574. ;
  575. ; If ASKAREA and SETAREA are set, then set these areas up and modify
  576. ; the message text in the FILTYP: function below if you desire a
  577. ; different choice. (As released in XMDM121, 1 = CP/M, 2 = MS/PC-DOS
  578. ; and 3 = General Interest.)
  579. ;
  580.      IF    ASKAREA    AND SETAREA
  581. ;
  582. MAXTYP    EQU    '3'        ; Set maximum type choice # here
  583. ;
  584. TYPTBL:    DB    'B',0        ; CHOICE 1 (CP/M NORMAL)
  585.     DB    'B',9        ; CHOICE 1 (CP/M PRIVATE)
  586.     DB    'B',3        ; CHOICE 2 (MS/PC-DOS NORMAL)
  587.     DB    'B',9        ; CHOICE 2 (MS/PC-DOS PRIVATE)
  588.     DB    'B',0        ; CHOICE 3 (General interest NORMAL)
  589.     DB    'B',9        ; CHOICE 3 (General interest PRIVATE)
  590. ;
  591.      ENDIF
  592. ;
  593. ;=======================================================================
  594. ;
  595. ;            PROGRAM STARTS HERE
  596. ;
  597. ;=======================================================================
  598. ;
  599. ; Save CP/M stack, initialize new one for this program
  600. ;
  601. BEGIN:    LXI    H,0
  602.     DAD    SP
  603.     SHLD    STACK
  604.     LXI    SP,STACK    ; Initialize new stack
  605. ;
  606.      IF    BYEBDOS
  607.     CALL    BYECHK
  608.     JZ    BYEOK
  609.     CALL    ILPRT
  610.     DB    'You need to be running BYEBDOS',CR,LF,0
  611.     JMP    EXIT2        ; Get stack pointer back and return
  612. ;
  613. BYEOK:    MVI    C,BDSTOS    ; Get current maximum time on system
  614.     MVI    E,255
  615.     CALL    BDOS
  616.     STA    MAXTOS
  617.      ENDIF
  618. ;
  619.      IF    B3RTC AND MXTOS    AND (NOT BYEBDOS)
  620.     CALL    BYECHK        ; If BYE not active
  621.     MVI    A,MAXMIN    ; (we'll use MAXMIN as default)
  622.     JNZ    EXTMXT        ; Skip MXML update
  623.     LHLD    0001H        ; Get JMP COLDBOOT
  624.     DCX    H
  625.     MOV    D,M
  626.     DCX    H
  627.     MOV    E,M
  628.     LXI    H,MBMXO        ; + MBMXO offset to MXML
  629.     DAD    D
  630.     MOV    A,M        ; = max time allowed on system
  631. ;
  632. EXTMXT:    STA    MAXTOS        ; Store max download time
  633.      ENDIF
  634. ;
  635. ; Get address of RTCBUF in BYE3 or MBYE
  636. ;
  637.      IF    B3RTC AND (NOT BYEBDOS)
  638.     CALL    BYECHK        ; See if BYE3/MBYE is running
  639.     JNZ    NOBYE0        ; If not, skip this junk
  640.     LHLD    0001H        ; Get COLDBOOT addr
  641.     DCX    H        ; (just before JMP WBOOT)
  642.     MOV    D,M        ; And stuff in DE
  643.     DCX    H
  644.     MOV    E,M
  645.     LXI    H,B3COFF    ; Add offset to RTCBUF address
  646.     DAD    D        ; (in HL)
  647.     MOV    E,M        ; Get RTCBUF address
  648.     INX    H        ; And
  649.     MOV    D,M        ; Stuff in DE
  650.     XCHG            ; Swap into HL
  651.     SHLD    RTCBUF        ; Save for use later
  652.      ENDIF
  653. ;
  654. NOBYE0:     IF    CONFUN        ; Console status checks to be done?
  655.     LHLD    0001H        ; If so get addr of warmboot (jmp table)
  656.     INX    H
  657.     INX    H
  658.     INX    H        ; + 3 = address of console status check
  659.     SHLD    CONCHK+1    ; Stuff after call for FUNCHK
  660.      ENDIF
  661. ;
  662.      IF    WRTLOC        ; Set WRITE LOCK?
  663.     CALL    SETLCK
  664.      ENDIF
  665. ;
  666. ; Save the current drive and user area
  667. ;
  668. NOBYE1:    MVI    E,0FFH        ; Get the current user area
  669.     MVI    C,SETUSR
  670.     CALL    BDOS
  671.     STA    OLDUSR        ; Save user number here
  672.     MVI    C,CURDRV    ; Get the current drive
  673.     CALL    BDOS
  674.     STA    OLDDRV        ; Save drive here
  675. ;
  676.      IF    B3TOS OR TIMEON
  677.     CALL    TIME        ; Get user's time status
  678.      ENDIF
  679. ;
  680.      IF    BYEBDOS    AND (NOT TIMEON)
  681.     MVI    C,BDPTOS    ; Display time on system and
  682.     CALL    BDOS        ; log off if over time limit
  683.      ENDIF
  684. ;
  685.     CALL    ILPRT
  686.     DB    CR,LF
  687. ;
  688.      IF    LUXMOD
  689.     DB    'LUX-'
  690.      ENDIF
  691. ;
  692.     DB    'XMODEM v'
  693.     DB    VERSION+'0',INTERM+'0','.',MODLEV+'0',' - '
  694.     DB    VMONTH/10+'0',VMONTH MOD 10+'0','/'
  695.     DB    VDAY/10+'0',VDAY MOD 10+'0','/'
  696.     DB    VYEAR/10+'0',VYEAR MOD 10+'0',CR,LF,0
  697. ;
  698. ; Stuff address of BIOS CONOUT vector in our routine as default.
  699. ;
  700.      IF    USECON AND NOT BYEBDOS
  701.     LHLD    0001H        ; Point to warm boot for normal BIOS
  702.     LXI    D,9
  703.     DAD    D        ; Calc addr of normal BIOS conout vector
  704.     SHLD    CONOUT+1    ; Save in case no BYE program is active
  705.     CALL    BYECHK
  706.     JNZ    NOBYE
  707.     XCHG            ; Point to the console output routine
  708.     SHLD    CONOUT+1    ; Save vector address supplied by BYE
  709.      ENDIF
  710. ;
  711. ; Get option
  712. ;
  713. NOBYE:    LXI    H,FCB+1        ; Get primary option
  714.     MOV    A,M
  715.     STA    OPTSAV        ; Save option
  716.     CPI    'R'        ; Receive file?
  717.     JZ    RECVOPT
  718. ;
  719. ; Send option processor
  720. ; Single option: "K"    - force 1k mode
  721. ;
  722.     INX    H        ; Look for a 'K'
  723.     MOV    A,M
  724.     CPI    ' '        ; Is it a space?
  725.     JZ    ALLSET        ; Then we're ready to send...
  726.     CPI    'K'
  727.     JNZ    OPTERR        ; "K" is the only setable 2nd option
  728.     LDA    MSPEED
  729.     CPI    MINKSP        ; If less than MINKSP bps, ignore 1k
  730.     JC    ALLSET        ; Request
  731.     MVI    A,'K'        ; Set 1k mode
  732.     STA    KFLAG        ; First, force us to 1K mode
  733.     CALL    ILPRT
  734.     DB    '(1k protocol selected)',CR,LF,0
  735.     JMP    ALLSET        ; That's it for send...
  736. ;
  737. ; Receive option processor
  738. ; 3 or 4 options: "X"    - disable auto-protocol select
  739. ;          "P"    - receive file in private area
  740. ;          "C"    - force checksum protocol
  741. ;          "M"    - message file upload (if MBFMSG)
  742. ;
  743. RECVOPT:MVI    A,'K'        ; First off, default to 1K mode
  744.     STA    KFLAG
  745.     MVI    A,0        ; And default to CRC mode
  746.     STA    CRCFLG
  747. ;
  748.     CALL    RCVOPC        ; Check 1st option
  749.     CALL    RCVOPC        ; Check 2nd option
  750.     CALL    RCVOPC        ; Check 3rd option
  751. ;
  752.      IF    MBFMSG
  753.     CALL    RCVOPC        ; Check 4th option
  754.      ENDIF
  755. ;
  756.      IF    NDESC
  757.     CALL    RCVOPC        ; Check 4th (or 5th) option
  758.      ENDIF
  759. ;
  760.     JMP    OPTERR        ; If 5th or 6th option, whoops!
  761. ;
  762. RCVOPC:    INX    H        ; Increment pointer to next character
  763.     MOV    A,M        ; Get option character HL points to
  764.     CPI    ' '        ; Space?
  765.     JNZ    CHK1ST        ; No, we have an option
  766.     POP    PSW        ; Else, we are done (restore stack)
  767.     JMP    ALLSET        ; Exit routine now
  768. ;
  769. CHK1ST:    CPI    'P'        ; Got a "P" option?
  770.     JNZ    CHK2ND        ; Nope
  771.     STA    PRVTFL        ; Yep, set private upload flag
  772.     RET            ; Check next option
  773. ;
  774. CHK2ND:    CPI    'C'        ; Got a "C" option?
  775.     JNZ    CHK3RD        ; Nope
  776.     STA    CRCFLG        ; Set checksum flag (crc flag="C")
  777.     CALL    ILPRT
  778.     DB    '(Checksum protocol selected)',CR,LF,0
  779.     RET
  780. ;
  781. CHK3RD:    CPI    'X'        ; Got an "X" for first option?
  782.     JNZ    CHK4TH
  783.     MVI    A,0
  784.     STA    KFLAG        ; Disable "1K" flag
  785.     CALL    ILPRT
  786.     DB    '(128 byte protocol only)',CR,LF,0
  787.     RET
  788. ;
  789. CHK4TH:
  790.      IF    MBFMSG        ; Allowing "RM" for message uploads?
  791.     CPI    'M'        ; Got an "M" for message upload?
  792.     JNZ    CHK5TH        ; If not, bad option
  793.     STA    MSGFLG        ; If "M", set MSGFLG
  794.     MVI    A,'P'        ; Also, set PRVTFL
  795.     STA    PRVTFL
  796.     LDA    XMDRV        ; And copy XMDRV
  797.     STA    XPRDRV
  798.     LDA    XMUSR        ; And XMUSR to XPRDRV / XPRUSR
  799.     STA    XPRUSR
  800.     RET
  801.      ENDIF
  802. ;
  803. CHK5TH:
  804.      IF    NDESC        ; Allowing "RN" to skip upload descript?
  805.     CPI    'N'        ; Got an 'N'?
  806.     JNZ    BADROP        ; If nope, is NG..
  807.     STA    NDSCFL        ; else set flag to skip descript phase
  808.     RET
  809.      ENDIF
  810. ;
  811. BADROP:    POP    PSW        ; Restore stack
  812.     JMP    OPTERR        ; is bad option
  813. ;
  814. ; All options have been set, gobble up garbage characters from the line
  815. ; prior to receive or send and initialize whatever has to be initialized
  816. ;
  817. ALLSET:    CALL    GETCHR
  818.     CALL    GETCHR
  819.     CALL    MINIT
  820. ;
  821. ; Jump to appropriate function
  822. ;
  823.     LDA    OPTSAV        ; Get primary option again
  824. ;
  825.      IF    LOGCAL
  826.     STA    LOGOPT        ; But save it
  827.      ENDIF
  828. ;
  829.     CPI    'L'        ; To send a file from a library?
  830.     JZ    SENDFIL
  831.     CPI    'R'        ; To receive a file?
  832.     JZ    RCVFIL
  833.     CPI    'S'
  834.     JZ    SENDFIL        ; Otherwise go send a file
  835. ;
  836. ; Invalid option
  837. ;
  838. OPTERR:
  839. ;
  840.      IF    ASKAREA    AND SETAREA
  841.     LDA    OPTSAV        ; Check 'option'
  842.     CPI    'A'        ; If 'A' (avail upload space option)
  843.     CZ    FILTYP        ;   ask type of upload...
  844.      ENDIF
  845. ;
  846.      IF    NOT (SETAREA OR    LUXMOD)
  847.     CALL    ILPRT
  848.     DB    CR,LF,'Uploads files to specified or '
  849.     DB    'current disk/user',0
  850.      ENDIF
  851. ;
  852.      IF    SETAREA    AND NOT    LUXMOD
  853.     CALL    ILPRT
  854.     DB    CR,LF,'Uploads files to ',0
  855.     LDA    XDRV
  856.     CALL    CTYPE
  857.     LDA    XUSR
  858.     MVI    H,0
  859.     MOV    L,A
  860.     CALL    DECOUT
  861.     MVI    A,':'
  862.     CALL    CTYPE
  863.     CALL    ILPRT
  864.     DB    ' (',0
  865.     LDA    XDRV
  866.     STA    KDRV
  867.     CALL    KSHOW
  868.     MVI    A,')'
  869.     CALL    CTYPE
  870.      ENDIF
  871. ;
  872.      IF    NOT LUXMOD
  873.     CALL    ILPRT
  874.     DB    CR,LF,'Private files to ',0
  875.     LDA    XPRDRV
  876.     CALL    CTYPE
  877.     LDA    XPRUSR
  878.     MVI    H,0
  879.     MOV    L,A
  880.     CALL    DECOUT
  881.     MVI    A,':'
  882.     CALL    CTYPE
  883.     LDA    XPRDRV        ; If private drive is
  884.     MOV    B,A
  885.     LDA    XDRV        ; The same as forced upload drive
  886.     SUB    B
  887.     JZ    SKSK2        ; Skip showing space available 2nd time
  888.     CALL    ILPRT
  889.     DB    ' (',0
  890.     LDA    XPRDRV        ; Else show it..
  891.     STA    KDRV
  892.     CALL    KSHOW
  893.     MVI    A,')'
  894.     CALL    CTYPE
  895. ;
  896. SKSK2:    CALL    ILPRT
  897.     DB    CR,LF,0
  898.      ENDIF
  899. ;
  900.     LDA    OPTSAV        ; Check 'option'
  901.     CPI    'A'        ; If 'A' (avail upload space option)
  902.     JZ    EXIT        ; Skip error message
  903. ;
  904.      IF    WRTLOC AND NOT BYEBDOS
  905.     CALL    RSTLCK
  906.      ENDIF
  907. ;
  908.     CALL    ERXIT        ; Exit with error
  909.     DB    '++ Examples of valid options: ++ '
  910.     DB    '(use Ctrl-C or Ctrl-K to abort)',CR,LF,LF
  911. ;
  912.      IF    NOT LUXMOD
  913.     DB    'XMODEM S HELLO.DOC         send a file to you',CR,LF
  914.     DB    'XMODEM S B1:HELLO.DOC      send from a named '
  915.     DB    'drive/area',CR,LF
  916.     DB    'XMODEM SK HELLO.DOC        send in 1k blocks',CR,LF
  917.     DB    'XMODEM L CAT.LBR CAT.COM   send a file from a library'
  918.     DB    CR,LF
  919.     DB    'XMODEM LK CAT.LBR CAT.COM  send in 1k blocks',CR,LF
  920.     DB    '   The ".LBR" file extension may be omitted',CR,LF,LF
  921.     DB    'XMODEM R HELLO.DOC         receive a file from you'
  922.     DB    CR,LF
  923.     DB    'XMODEM RP HELLO.DOC        receive in a private area'
  924.     DB    CR,LF
  925.      ENDIF
  926. ;
  927.      IF    (MBDESC    OR DESCRIB) AND    NDESC
  928.     DB    'XMODEM RN FILE.EXT         receive without description'
  929.     DB    CR,LF
  930.      ENDIF
  931. ;
  932.      IF    (NOT LUXMOD) AND MBFMSG
  933.     DB    'XMODEM RM MESSAGE.FIL      receive message for MBBS'
  934.     DB    CR,LF
  935.      ENDIF
  936. ;
  937.      IF    NOT LUXMOD
  938.     DB    '   Add "C" for forced checksum ("RC" "RPC")',CR,LF
  939.     DB    '   Add "X" for forced 128 byte protocol ("RX" "RPX")'
  940.     DB    CR,LF
  941.     DB    '   "R" switches from CRC to checksum after 5 retries'
  942.     DB    CR,LF,LF
  943.     DB    'XMODEM A                   shows areas/space for '
  944.     DB    'uploads$'
  945.      ENDIF
  946. ;
  947.      IF    LUXMOD
  948.     DB    'SEND MEMBERNAME.TYP        sends member with CRC'
  949.     DB    CR,LF
  950.     DB    'SENDK MEMBERNAME.TYP       sends using 1k packets'
  951.     DB    CR,LF,LF
  952.     DB    'XMODEM S MEMBERNAME.TYP    same as SEND command'
  953.     DB    CR,LF
  954.     DB    'XMODEM SK MEMBERNAME.TYP   same as SENDK',CR,LF,LF
  955.     DB    '(XMODEM can NOT receive while in LUX.)$'
  956.      ENDIF
  957. ;
  958. ;
  959. ;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  960. ;
  961. ; ---> SENDFIL    sends a CP/M file
  962. ;
  963. ;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  964. ;
  965. ; The CP/M file specified in the XMODEM command is transferred over the
  966. ; phone to another computer running modem with the "R" (receive) option.
  967. ; The data is sent one record at a time with headers and checksums, and
  968. ; retransmission on errors.
  969. ;
  970. SENDFIL:CALL    LOGDU        ; Check file name or drive/user option
  971.     LDA    OPTSAV
  972.     CPI    'L'        ; If library option skip 'CNREC'
  973.     CNZ    CNREC        ; Ignore if in library mode
  974.     CALL    OPENFIL        ; Open the file
  975.     MVI    E,100        ; Wait 100 sec for initial 'NAK'
  976.     CALL    WAITNAK
  977.     LHLD    RCNT        ; XMDM116.FIX
  978.     CALL    CKKSIZ        ; XMDM116.FIX -- Murray Simsolo
  979. ;
  980. SENDLP:    CALL    CHKERR        ; Check ratio of blocks to errors
  981.     CALL    RDRECD        ; Read a record
  982.     JC    SENDEOF        ; Send 'EOF' if done
  983.     CALL    INCRRNO        ; Bump record number
  984.     XRA    A        ; Initialize error count to zero
  985.     STA    ERRCT
  986. ;
  987. SENDRPT:CALL    SENDHDR        ; Send a header
  988.     CALL    SENDREC        ; Send data record
  989.     LDA    CRCFLG        ; Get 'CRC' flag
  990.     ORA    A        ; 'CRC' in effect?
  991.     CZ    SENDCRC        ; Yes, send 'CRC'
  992.     CNZ    SENDCKS        ; No, send checksum
  993.     CALL    GETACK        ; Get the 'ACK'
  994.     JC    SENDRPT        ; Repeat if no 'ACK'
  995.     CALL    UPDPTR        ; Update buffer pointers and counters
  996.     LDA    OPTSAV        ; Get the command option again
  997.     CPI    'L'
  998.     JNZ    SENDLP        ; If not library option, go ahead
  999. ;
  1000. ;
  1001. ; Check to see if done sending LBR member yet, downshift to small blocks
  1002. ; if less that 8 remaining
  1003. ;
  1004.     LHLD    RCNT
  1005.     MOV    A,H
  1006.     ORA    L        ; See if L and H both zero now
  1007.     JZ    SENDEOF        ; If finished, exit
  1008.     LDA    KFLAG        ; Was last record a 1024 byte one?
  1009.     ORA    A
  1010.     JZ    SNRPT0        ; Just handled an normal 128 byte record
  1011.     DCX    H        ; Otherwise, must have be a BIG one, so
  1012.     DCX    H        ; Seven ...
  1013.     DCX    H
  1014.     DCX    H
  1015.     DCX    H
  1016.     DCX    H
  1017.     DCX    H        ; Plus
  1018. ;
  1019. SNRPT0:    DCX    H        ; One, is either 1 or 8
  1020.     SHLD    RCNT        ; One (or eight) less to go
  1021.     CALL    CKKSIZ        ; Check to see if at least 8 left
  1022.     JMP    SENDLP        ; Loop until EOF
  1023. ;
  1024. ; File sent, send EOT's
  1025. ;
  1026. SENDEOF: IF    LOGLDS
  1027.     LDA    DNLDS        ; Get Down loads Counter
  1028.     INR    A        ; One more download since log in
  1029.     STA    DNLDS        ; And update counter
  1030.      ENDIF
  1031. ;
  1032. SNDEOFL:LDA    EOFCTR        ; Get EOF counter
  1033.     CPI    5        ; Tried five times ?
  1034.     JZ    EXITLG        ; Yes, quit trying
  1035.     MVI    A,EOT        ; Send an 'EOT'
  1036.     CALL    SEND
  1037.     LDA    EOFCTR        ; Get EOF counter
  1038.     INR    A        ; Add one
  1039.     STA    EOFCTR        ; Save new count
  1040.     CALL    GETACK        ; Get the ACK
  1041.     JC    SNDEOFL        ; Loop if no ACK
  1042.     JMP    EXITLG        ; All done
  1043. ;.....
  1044. ;
  1045. ;
  1046. ;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  1047. ;
  1048. ; ---> RCVFIL Receive a CP/M file
  1049. ;
  1050. ;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  1051. ;
  1052. ; Receives a file in block format as sent by another person doing
  1053. ; "XMODEM S FILENAME.TYP".  Can be invoked by "XMODEM R FILENAME.TYPE"
  1054. ; or by "XMODEM RC FILENAME.TYP" if checksum is to be used.
  1055. ;
  1056. RCVFIL:     IF    ACCESS
  1057.     CALL    BYECHK
  1058.     JNZ    RCVFL1
  1059.     LHLD    0001H        ; Get JMP COLDBOOT
  1060.     DCX    H
  1061.     MOV    D,M
  1062.     DCX    H
  1063.     MOV    E,M
  1064.     LXI    H,ACBOFF    ; + ACBOFF
  1065.     DAD    D
  1066.     MOV    A,M        ; = ACCESS byte address
  1067.     ANI    ACUPLD        ; Test upload access bit
  1068.     JNZ    RCVFL0        ; If bit on, uploads OK
  1069.     CALL    ERXIT
  1070.     DB    'Sorry, but you are not allowed to upload files '
  1071.     DB    'at this time...$'
  1072.      ENDIF
  1073. ;
  1074. RCVFL0:     IF    ACCESS AND MBFMSG
  1075.     LDA    MSGFLG
  1076.     ORA    A        ; Is this "RM" upload?
  1077.     JZ    RCVFL1        ; If not, skip ACWRIT check
  1078.     MOV    A,M
  1079.     ANI    ACWRIT        ; If "RM", check if WRITE access
  1080.     JNZ    RCVFL1        ; If so, ok
  1081.     CALL    ERXIT
  1082.     DB    'Sorry, but you are not allowed to enter messages '
  1083.     DB    'at this time...$'
  1084.      ENDIF
  1085. ;
  1086. RCVFL1:
  1087.     CALL    LOGDU        ; Check file name or drive/user option
  1088. ;
  1089.      IF    ZCPR2
  1090.     LDA    WHEEL        ; Let SYSOP put file wherever he wants
  1091.     ORA    A
  1092.     JZ    RCVFL5        ; If WHEEL byte not set, stay normal
  1093.     LDA    RCVDRV
  1094.     ORA    A
  1095.      ENDIF
  1096. ;
  1097. ;
  1098.      IF    ZCPR2 AND NOT SPCDU
  1099.     JZ    RCVFL2
  1100.      ENDIF
  1101. ;
  1102.      IF    ZCPR2 AND SPCDU
  1103.     JZ    RCVFL2
  1104.      ENDIF
  1105. ;
  1106.      IF    ZCPR2
  1107.     SUI    'A'        ; Convert ASCII drive to binary
  1108.     JMP    RCVFL3
  1109. ;
  1110. RCVFL2:    LDA    OLDDRV
  1111. ;
  1112. RCVFL3:    INR    A
  1113.     STA    FCB
  1114.     ADI    'A'-1        ; Convert binary to ASCII
  1115.     STA    XDRV        ; Drive
  1116.     LDA    RCVDRV        ; See if a drive was requested
  1117.     ORA    A
  1118.     LDA    OLDUSR        ; Current user
  1119.     JZ    RCVFL4        ; If not, use current user
  1120.     LDA    RCVUSR        ; Else get requested user
  1121. ;
  1122. RCVFL4:    STA    XUSR        ; User
  1123.     JMP    CONTIN
  1124.      ENDIF    ; ZCPR2
  1125. ;
  1126. RCVFL5:     IF    SETAREA
  1127.     LDA    XDRV
  1128.     SUI    40H
  1129.     STA    FCB
  1130.      ENDIF
  1131. ;
  1132.     LDA    PRVTFL        ; Receiving to a private area?
  1133.     ORA    A
  1134.     JZ    RCVFL6        ; If not, exit
  1135.     LDA    XPRDRV        ; Private area takes precedence
  1136.     SUI    40H
  1137.     STA    FCB        ; Store drive to be used
  1138. ;
  1139. RCVFL6:     IF    NOCOMR
  1140.     LXI    H,FCB+9        ; Point to filetype
  1141.     MVI    A,'C'        ; 1st letter
  1142.     CMP    M        ; Is it C ?
  1143.     JNZ    RCVFL7        ; If not, continue normally
  1144.     INX    H        ; Get 2nd letter
  1145.     MVI    A,'O'        ; 2nd letter
  1146.     CMP    M        ; Is it O ?
  1147.     JNZ    RCVFL7        ; If not, continue normally
  1148.     INX    H        ; Get 3rd letter
  1149.     MVI    A,'M'        ; 3rd letter
  1150.     CMP    M        ; Is it M ?
  1151.     JNZ    RCVFL7        ; If not, continue normally
  1152.     CALL    ILPRT        ; Print renaming message
  1153.     DB    'Auto-renaming file to ".OBJ"',CR,LF,0
  1154.     LXI    H,FCB+9
  1155.     MVI    M,'O'
  1156.     INX    H
  1157.     MVI    M,'B'
  1158.     INX    H
  1159.     MVI    M,'J'
  1160.     JMP    CONTIN
  1161.      ENDIF    ; NOCOMR
  1162. ;
  1163. RCVFL7:     IF    NOCOMR AND CPM3
  1164.     LXI    H,FCB+9        ; Point to filetype
  1165.     MVI    A,'P'        ; 1st letter
  1166.     CMP    M        ; Is it P ?
  1167.     JNZ    RCVFL8        ; If not, continue normally
  1168.     INX    H        ; Get 2nd letter
  1169.     MVI    A,'R'        ; 2nd letter
  1170.     CMP    M        ; Is it R ?
  1171.     JNZ    RCVFL8        ; If not, continue normally
  1172.     INX    H        ; Get 3rd letter
  1173.     MVI    A,'L'        ; 3rd letter
  1174.     CMP    M        ; Is it L ?
  1175.     JNZ    RCVFL8        ; If not, continue normally
  1176.     CALL    ILPRT        ; Print renaming message
  1177.     DB    'Auto-renaming file to ".OBP"',CR,LF,0
  1178.     LXI    H,FCB+9
  1179.     MVI    M,'O'
  1180.     INX    H
  1181.     MVI    M,'B'
  1182.     INX    H
  1183.     MVI    M,'P'
  1184.     JMP    CONTIN
  1185.      ENDIF    ; NOCOMR AND CPM3
  1186. ;
  1187. ; Check to see if filetype is .NDR, if so do NOT allow upload
  1188. ;
  1189. RCVFL8:     IF    ZCPR3
  1190.     LXI    H,FCB+9        ; Point to filetype
  1191.     MVI    A,'N'        ; 1st letter
  1192.     CMP    M        ; Is it N ?
  1193.     JNZ    RCVFL9        ; If not, continue normally
  1194.     INX    H        ; Get 2nd letter
  1195.     MVI    A,'D'        ; 2nd letter
  1196.     CMP    M        ; Is it D ?
  1197.     JNZ    RCVFL9        ; If not, continue normally
  1198.     INX    H        ; Get 3rd letter
  1199.     MVI    A,'R'        ; 3rd letter
  1200.     CMP    M        ; Is it R ?
  1201.     JNZ    RCVFL9        ; If not, continue normally
  1202.     CALL    ERXIT        ; Print renaming message
  1203.     DB    'Cannot receive filetype ".NDR"',CR,LF,'$'
  1204. ;
  1205. ; Check to see if filetype is .RCP, if so do NOT allow upload
  1206. ;
  1207. RCVFL9:    LXI    H,FCB+9        ; Point to filetype
  1208.     MVI    A,'R'        ; 1st letter
  1209.     CMP    M        ; Is it R ?
  1210.     JNZ    CONTIN        ; If not, continue normally
  1211.     INX    H        ; Get 2nd letter
  1212.     MVI    A,'C'        ; 2nd letter
  1213.     CMP    M        ; Is it C ?
  1214.     JNZ    CONTIN        ; If not, continue normally
  1215.     INX    H        ; Get 3rd letter
  1216.     MVI    A,'P'        ; 3rd letter
  1217.     CMP    M        ; Is it P ?
  1218.     JNZ    CONTIN        ; If not, continue normally
  1219.     CALL    ERXIT        ; Abort with error msg
  1220.     DB    'Cannot receive filetype ".RCP"',CR,LF,'$'
  1221.      ENDIF    ; ZCPR3
  1222. ;
  1223. CONTIN:
  1224.      IF    MBFMSG
  1225.     LDA    MSGFLG
  1226.     ORA    A        ; Is this "RM" upload?
  1227.     JNZ    DONT        ; If yes, skip asking what kind of upload
  1228.      ENDIF
  1229. ;
  1230.      IF    ASKAREA    AND SETAREA AND    (NOT ZCPR2)
  1231.     CALL    FILTYP        ; Ask caller what kinda beast it is
  1232.      ENDIF
  1233. ;
  1234.      IF    ASKAREA    AND SETAREA AND    ZCPR2
  1235.     LDA    WHEEL        ; Don't ask the SYSOP
  1236.     ORA    A
  1237.     JNZ    DONT        ; If WHEEL byte set, skip asking
  1238.     CALL    FILTYP        ; Ask caller what kinda beast it is
  1239.      ENDIF
  1240. ;
  1241. DONT:    CALL    ILPRT        ; Print the message
  1242. ;
  1243.      IF    NOT DSPFNAM
  1244.     DB    CR,LF,'File will be received on ',0
  1245.      ENDIF
  1246. ;
  1247.      IF    DSPFNAM
  1248.     DB    CR,LF,'Receiving: ',0
  1249.      ENDIF
  1250. ;
  1251.     LDA    PRVTFL        ; Going to store in the private area?
  1252.     ORA    A
  1253.     JZ    CONT1        ; If not, exit
  1254. ;
  1255.     LDA    XPRDRV        ; Get private drive
  1256.     JMP    CONT2        ; If yes, it takes priority
  1257. ;
  1258. CONT1:
  1259.      IF    SETAREA
  1260.     LDA    XDRV        ; Setarea uses a specified drive
  1261.      ENDIF
  1262. ;
  1263.      IF    NOT SETAREA
  1264.     LDA    OLDDRV        ; Otherwise get current drive
  1265.     ADI    'A'        ; Convert to ASCII
  1266. ;
  1267. NOTDRV:    DB    0,0        ; Filled in by 'GETDU' if requested
  1268.      ENDIF
  1269. ;
  1270. CONT2:
  1271.     STA    KDRV        ; Save drive for KSHOW
  1272.     SUI    40H        ; Convert ASCII to binary
  1273.     STA    FCB        ; Stuff in FCB
  1274.     LDA    KDRV        ; Get ASCII version back again
  1275.     CALL    CTYPE        ; Print the drive to store on
  1276.     LDA    PRVTFL        ; Going to store in the private area?
  1277.     ORA    A
  1278.     JZ    NOPRVL        ; If nope, skip ahead
  1279. ;
  1280.      IF    LOGCAL
  1281.     MVI    A,'P'        ; If private upload
  1282.     STA    LOGOPT        ; Show "P" as option
  1283.      ENDIF
  1284. ;
  1285.     LDA    XPRUSR        ; Get private user area
  1286.     JMP    CONT3        ; It takes priority
  1287. ;
  1288. NOPRVL:
  1289.      IF    SETAREA
  1290.     LDA    XUSR        ; Setarea takes next precedence
  1291.      ENDIF
  1292. ;
  1293.      IF    NOT SETAREA
  1294.     LDA    OLDUSR        ; Get current drive for default
  1295. ;
  1296. NOTUSR:    DB    0,0        ; Filled in by 'GETDU' if requested
  1297.      ENDIF
  1298. ;
  1299. CONT3:    MVI    H,0
  1300.     MOV    L,A
  1301.     CALL    DECOUT        ; Print the user area
  1302. ;
  1303.      IF    NOT DSPFNAM
  1304.     CALL    ILPRT
  1305.     DB    ':',CR,LF,0
  1306.      ENDIF
  1307. ;
  1308.      IF    DSPFNAM
  1309.     MVI    A,':'
  1310.     CALL    CTYPE        ; We showed disk/user:
  1311.     LXI    H,FCB+1        ; Now display filename
  1312.     CALL    DSPFN
  1313.     CALL    ILPRT
  1314.     DB    CR,LF,0
  1315.      ENDIF
  1316. ;
  1317.     CALL    KSHOW        ; Show available space remaining
  1318.     CALL    ILPRT
  1319.     DB    CR,LF,0
  1320.     CALL    CHEKFIL        ; See if file exists
  1321.     CALL    MAKEFIL        ; If not, start a new file
  1322.     CALL    ILPRT
  1323.     DB    'File open - ready to receive',CR,LF
  1324.     DB    'To cancel: Ctrl-X, pause, Ctrl-X',CR,LF,0
  1325. ;
  1326.      IF    B3RTC AND (NOT MBMXT OR    BYEBDOS)
  1327.     CALL    GETTOS        ; Get time on system
  1328.     SHLD    TOSSAV        ; Save it for exit
  1329.      ENDIF
  1330. ;
  1331. RCVLP:    CALL    RCVRECD        ; Get a record
  1332.     JC    RCVEOT        ; Got 'EOT'
  1333.     CALL    WRRECD        ; Write the record
  1334.     CALL    INCRRNO        ; Bump record number
  1335.     CALL    SENDACK        ; Ack the record
  1336.     JMP    RCVLP        ; Loop until 'EOF'
  1337. ;
  1338. ;
  1339. ; Got EOT on record so flush buffers then done
  1340. ;
  1341. RCVEOT:    LHLD    RECDNO        ; Check for zero length file
  1342.     MOV    A,H        ; If no records, no file
  1343.     ORA    L
  1344.     JNZ    EOT1        ; If not zero, continue, else abort
  1345.     CALL    RCVSABT        ; Abort and erase the zero length file
  1346.     JMP    EXIT        ; And exit
  1347. ;
  1348. EOT1:    CALL    WRBLOCK        ; Write the last block
  1349.     CALL    SENDACK        ; Ack the record
  1350.     CALL    CLOSFIL        ; Close the file
  1351.     XRA    A        ; Clear CTYPE's console
  1352.     STA    CONONL        ; Output only flag
  1353. ;
  1354.      IF    LOGLDS
  1355.     LDA    UPLDS        ; Get Upload Counter
  1356.     INR    A        ; One more upload since log in
  1357.     STA    UPLDS        ; Update Counter
  1358.      ENDIF
  1359. ;
  1360. ; Logging upload or crediting time on?
  1361. ;
  1362.      IF    LOGCAL
  1363.     LHLD    VRECNO        ; If yes, get virtual # of recs
  1364.     SHLD    RCNT        ; And stuff in RCNT
  1365.     CALL    FILTIM        ; Calculate appox. xfer time
  1366.      ENDIF
  1367. ;
  1368.      IF    B3RTC AND MBMXT    AND (NOT BYEBDOS)
  1369.     CALL    BYECHK        ; If BYE not active
  1370.     JNZ    EXITLG        ; Skip MXML update
  1371.     LHLD    0001H        ; Get JMP COLDBOOT
  1372.     DCX    H
  1373.     MOV    D,M
  1374.     DCX    H
  1375.     MOV    E,M
  1376.     LXI    H,MBMXO        ; + MBMXO offset to MXML
  1377.     DAD    D
  1378.     MOV    A,M        ; = max time allowed on system
  1379.     ORA    A        ; Check it (zero?)
  1380.     JZ    EXITLG        ; If unlimited time, skip update
  1381.     INR    A        ; Else, increment it (for secs)
  1382.     ADD    C        ; Add mins LSB (can't be >255)
  1383.     JC    MAK255        ; If overflow, make it max (255)
  1384.     JZ    MAK255        ; (if zero, make 255)
  1385.     MOV    M,A        ; Update it (credit them for upload)
  1386.     JMP    EXITLM
  1387. ;
  1388. MAK255:    MVI    A,255        ; If up to max, make sure they don't
  1389.     MOV    M,A        ; Get LESS than what they had..
  1390.      ENDIF
  1391. ;
  1392.      IF    B3RTC AND NOT (BYEBDOS OR MBMXT)
  1393.     CALL    BYECHK
  1394.     JNZ    EXITLG        ; SKIP this if BYE not running
  1395.     LHLD    RTCBUF        ; Get address of RTCBUF in HL
  1396.     LXI    D,B3CMOS    ; Add offset to mins on system
  1397.     DAD    D        ; (addr in HL)
  1398.     LDA    TOSSAV        ;Get saved time on system
  1399.     MOV    M,A        ; And restore it
  1400.     INX    H        ; (don't count upload time
  1401.     LDA    TOSSAV+1    ; Against them)
  1402.     MOV    M,A
  1403.      ENDIF
  1404. ;
  1405.      IF    BYEBDOS    AND (NOT B3RTC)
  1406.     LDA    MAXTOS        ; Get maximum time allowed
  1407.     ORA    A
  1408.     JZ    EXITLG        ; If zero, he's a super-guy anyway
  1409.     INR    A
  1410.     ADD    C        ; Add in upload time
  1411.     JC    MAK254        ; Make it 254 minutes if overflow
  1412.     JZ    MAK254        ; (or zero)
  1413.     CPI    255        ; (or 255)
  1414.     JNZ    MAXSTR
  1415. ;
  1416. MAK254:    MVI    A,254        ; (254 is max allowed)
  1417. ;
  1418. MAXSTR:    STA    MAXTOS        ; Save for internal use
  1419.     MOV    E,A
  1420.     MVI    C,BDSTOS    ; Set maximum time on system
  1421.     CALL    BDOS
  1422.      ENDIF
  1423. ;
  1424. EXITLM:     IF    BYEBDOS    OR (B3RTC AND MBMXT)
  1425.     CALL    ILPRT
  1426.     DB    CR,LF,'Upload time credited towards maximum timeon.'
  1427.     DB    CR,LF,0
  1428.      ENDIF
  1429. ;
  1430.     JMP    EXITLG
  1431. ;
  1432. ;-----------------------------------------------------------------------
  1433. ;
  1434. ;            SUBROUTINES
  1435. ;
  1436. ;-----------------------------------------------------------------------
  1437. ;
  1438. ;    FILTYP: Ask file type for uploads
  1439. ;
  1440.      IF    ASKAREA    AND SETAREA
  1441. ;
  1442. ; Routine to get file type for uploads (modified from XMDM10XX.ASM
  1443. ; by Russ Pencin (Dallas Connection)). (Modify MAXTYP and TYPTBL
  1444. ; near the top of the program.)
  1445. ;
  1446. FILTYR:    CALL    ILPRT
  1447.     DB    CR,LF,0
  1448. ;
  1449. FILTYP:    CALL    ILPRT        ; Modify message as needed
  1450.     DB    CR,LF,'Is file for:',CR,LF,CR,LF
  1451.     DB    '   (1) CP/M',CR,LF
  1452.     DB    '   (2) MS/PC-DOS',CR,LF
  1453.     DB    'or (3) General interest?',CR,LF,CR,LF
  1454.     DB    'Enter choice (1, 2 or 3): ',0
  1455.      ENDIF    ;ASKAREA AND SETAREA
  1456. ;
  1457.      IF    ASKAREA    AND SETAREA AND    WRTLOC
  1458.     CALL    RSTLCK        ;Turn off WRTLOC so RDCON will work
  1459.      ENDIF
  1460. ;
  1461.      IF    ASKAREA    AND SETAREA
  1462.     MVI    C,RDCON
  1463.     CALL    BDOS
  1464.     CPI    '1'        ;is it a cpm file
  1465.     JC    FILTYR        ;nope, ask again use default upload area(s)
  1466.     CPI    MAXTYP+1
  1467.     JNC    FILTYR
  1468.     SUI    '1'        ;GET OFFSET FOR TYPTBL
  1469.     RAL
  1470.     RAL
  1471.     MVI    D,0
  1472.     MOV    E,A
  1473.     LXI    H,TYPTBL
  1474.     DAD    D
  1475.     MOV    A,M
  1476.     STA    XDRV        ;set drive
  1477.     INX    H
  1478.     MOV    A,M        ;user
  1479.     STA    XUSR
  1480.     INX    H
  1481.     MOV    A,M        ;private drive
  1482.     STA    XPRDRV
  1483.     INX    H
  1484.     MOV    A,M        ;and private user values
  1485.     STA    XPRUSR
  1486.     CALL    ILPRT
  1487.     DB    CR,LF,0
  1488.      ENDIF    ;ASKAREA AND SETAREA
  1489. ;
  1490.      IF    ASKAREA    AND SETAREA AND    WRTLOC
  1491.     CALL    SETLCK        ;Turn WRTLOC back on
  1492.      ENDIF
  1493. ;
  1494.      IF    ASKAREA    AND SETAREA
  1495.     RET
  1496.      ENDIF
  1497. ;
  1498. ;---------------------------------------------------------------------
  1499. ; WRTLOC ROUTINES (SETLCK AND RSTLCK)
  1500. ;
  1501.      IF    WRTLOC AND NOT BYEBDOS
  1502. SETLCK:    CALL    BYECHK        ; Is BYE running
  1503.     RNZ            ; If not, skip this
  1504.     LHLD    0001H        ; Get JMP COLDBOOT
  1505.     DCX    H
  1506.     MOV    D,M
  1507.     DCX    H
  1508.     MOV    E,M
  1509.     LXI    H,LOCOFF    ; + LOCOFF
  1510.     DAD    D
  1511.     ORI    0FFH        ; = WRTLOC address
  1512.     MOV    M,A        ; Turn the lock on
  1513.     RET
  1514. ;
  1515. RSTLCK:    CALL    BYECHK        ; Is BYE running
  1516.     RNZ            ; Nope, don't touch a thing
  1517.     LHLD    0001H        ; If so, time to reset it
  1518.     DCX    H        ; Get JMP COLDBOOT addr.
  1519.     MOV    D,M
  1520.     DCX    H
  1521.     MOV    E,M
  1522.     LXI    H,LOCOFF    ; + LOCOFF bytes
  1523.     DAD    D        ; = WRTLOC address
  1524.     XRA    A        ; Clear it
  1525.     MOV    M,A        ; (so ctrl-C/ctrl-K work)
  1526.     RET
  1527.      ENDIF    ;WRTLOC AND NOT BYEBDOS
  1528. ;
  1529.      IF    WRTLOC AND BYEBDOS
  1530. SETLCK:    MVI    C,BDWRTL    ; Set/Get writeloc function
  1531.     MVI    E,1        ; Turn on WRTLOC flag
  1532.     CALL    BDOS
  1533.     RET
  1534. ;
  1535. RSTLCK:    MVI    C,BDWRTL    ; Set/Get writeloc function
  1536.     MVI    E,0        ; Turn off WRTLOC flag
  1537.     CALL    BDOS
  1538.     RET
  1539.      ENDIF
  1540. ;
  1541. ;---------------------------------------------------------------------
  1542. ;
  1543. ; Display file name function
  1544. ;
  1545.      IF    DSPFNAM        ; HL=FCB address
  1546. DSPFN:    MVI    B,8
  1547. ;
  1548. PRNAM:    MOV    A,M
  1549.     ANI    7FH        ; Strip any attribute bits
  1550.     CPI    ' '        ; Don't print blanks
  1551.     CNZ    CTYPE        ; Print filename
  1552.     INX    H
  1553.     DCR    B
  1554.     JNZ    PRNAM
  1555. ;
  1556. PRDOT:    MVI    A,'.'        ; After first part, print dot
  1557.     CALL    CTYPE
  1558.     MVI    B,3
  1559. ;
  1560. PRTYP:    MOV    A,M
  1561.     ANI    7FH        ; Strip any attribute bits
  1562.     CPI    ' '        ; Don't print blanks
  1563.     CNZ    CTYPE        ; Print filetype
  1564.     INX    H
  1565.     DCR    B
  1566.     JNZ    PRTYP
  1567.     RET
  1568.      ENDIF    ; DSPFNAM
  1569. ;
  1570. ; Check to see if BYE is running before getting CONOUT, checking MBBS
  1571. ; ACCESS byte or setting/resetting WRTLOC.  This routine also returns
  1572. ; the address of the original cold boot routine in DE.
  1573. ;
  1574. ; Go through a big search to see if BYE is active.
  1575. ;
  1576.      IF    BYEBDOS
  1577. BYECHK:    MVI    C,32        ; This bizarre combination determines
  1578.     MVI    E,241        ; If BYE is not there.
  1579.     CALL    BDOS
  1580.     CPI    77        ; Is it there?
  1581.     RET
  1582.      ENDIF
  1583. ;
  1584.      IF    (NOT BYEBDOS) AND (USECON OR ACCESS OR WRTLOC)
  1585. BYECHK:    LHLD    0001H        ; Point to warm boot again
  1586.     DCX    H        ; If BYE active,
  1587.     MOV    D,M        ; Pick up pointer to BYE variables
  1588.     DCX    H        ; (COVECT) followed by 'BYE'
  1589.     MOV    E,M
  1590.     LXI    H,CONOFF    ; Calculate address of BYE variable
  1591.     DAD    D        ; Where ptr to orig BIOS vector stored
  1592.     MOV    E,M        ; Load that address into DE, if BIOS
  1593.     INX    H        ; Is active, DE now points to original
  1594.     MOV    D,M        ; BIOS console output vector
  1595.     INX    H        ; Point to BYE signon message
  1596. ;
  1597. ; Note that if more BYE variables are added after the cold boot pointer,
  1598. ; extra INX may be needed.  Fix to match your BYE.
  1599. ;
  1600.     MOV    A,M        ; Get letter
  1601.     ANI    05FH        ; Convert to upper case if needed
  1602.     CPI    'B'        ; Try to match 'BYE'
  1603.     RNZ            ; Out if BYE not active
  1604.     INX    H
  1605.     MOV    A,M
  1606.     ANI    05FH        ; Convert to upper case if needed
  1607.     CPI    'Y'
  1608.     RNZ
  1609.     INX    H
  1610.     MOV    A,M
  1611.     ANI    05FH        ; Convert to upper case if needed
  1612.     CPI    'E'
  1613.     RET
  1614.      ENDIF
  1615. ;
  1616. ; Check next character to see if a space or non-space, file name error
  1617. ; if no ASCII character.
  1618. ;
  1619. CHKFSP:    DCR    B
  1620.     JZ    NFN        ; Error if end of chars.
  1621.     MOV    A,M
  1622.     CPI    ' '+1
  1623.     RNC            ; Ok if valid character so return
  1624.     INX    H
  1625.     JMP    CHKFSP        ; Look at next character
  1626. ;
  1627. ; Check next character to see if a space or non-space, go to menu if a
  1628. ; command error.
  1629. ;
  1630. CHKSP:    DCR    B
  1631.     JZ    OPTERR
  1632.     INX    H
  1633.     MOV    A,M        ; Get the char. there
  1634.     CPI    ' '        ; Space character?
  1635.     RET            ; JZ = space, JNZ = non-space
  1636. ;
  1637. ; Exit, but first write record to log file and ask for description
  1638. ;
  1639. EXITLG:
  1640. ;
  1641.      IF    LOGCAL OR MBDESC OR MBFMSG
  1642.     CALL    LOGCALL
  1643.      ENDIF
  1644. ;
  1645. ; Ask sysop for a description of the file if ASKSYS is yes
  1646. ;
  1647.      IF    DESCRIB    AND ZCPR2 AND (NOT ASKSYS)
  1648.     LDA    WHEEL        ; If its the Sysop, don't ask
  1649.     ORA    A        ; For a description because he
  1650.     JNZ    EXIT        ; Might want to batch recv files
  1651.      ENDIF
  1652. ;
  1653.      IF    DESCRIB    AND NDESC
  1654.     LDA    NDSCFL        ; If user picked "N" option
  1655.     ORA    A        ; allow them to skip upload
  1656.     JNZ    EXIT        ; descript
  1657.      ENDIF
  1658. ;
  1659.      IF    DESCRIB    AND WRTLOC
  1660.     CALL    RSTLCK        ; Clear WRTLOC before DESCRIB
  1661.      ENDIF
  1662. ;
  1663.      IF    DESCRIB
  1664.     CALL    ASK        ; If yes, ask for description of file
  1665.      ENDIF
  1666. ;
  1667. ; Finished, clean up and return to CP/M, send thank-you and timeon
  1668. ; messages if enabled.
  1669. ;
  1670. EXIT:    XRA    A
  1671.     STA    CONONL        ; Reset 'console only' flag for timeon
  1672. ;
  1673.      IF    WRTLOC
  1674.     CALL    RSTLCK        ; Clear WRTLOC
  1675.      ENDIF
  1676. ;
  1677. NOBYE2:    CALL    UNINIT        ; Reset vectors (if needed)
  1678.     LDA    OLDDRV        ; Restore the original drive
  1679.     CALL    RECDRX
  1680.     LDA    OLDUSR        ; Restore the original number
  1681.     CALL    RECARE
  1682.     LXI    D,TBUF        ; Reset to default DMA address
  1683.     MVI    C,SETDMA
  1684.     CALL    BDOS
  1685.     LDA    OPTSAV        ; If so check option flag
  1686.     CPI    'R'        ; Was it 'R' for receive
  1687.     JNZ    EXIT1        ; If not, then skip this,
  1688.     CALL    ILPRT        ; And print
  1689.     DB    CR,LF,'Thanks for the upload',CR,LF,0
  1690. ;
  1691.      IF    SYSNEW
  1692.     CALL    ILPRT
  1693.     DB    CR,LF,'(Upload set as SYS file and cannot be examined'
  1694.     DB    CR,LF,'or downloaded until released by the SYSOP....)'
  1695.     DB    CR,LF,0
  1696.      ENDIF
  1697. ;
  1698.      IF    B3RTC AND NOT (MBMXT OR    BYEBDOS)
  1699.     CALL    ILPRT        ; And print
  1700.     DB    CR,LF,'Time online is not increased during uploads'
  1701.     DB    CR,LF,0
  1702.      ENDIF
  1703. ;
  1704.      IF    MBFMSG
  1705.     LDA    MSGFLG        ; Was this a "XMODEM RM" upload?
  1706.     ORA    A
  1707.     JZ    NOTMSG
  1708.     CALL    BYECHK
  1709.     JNZ    EXIT1
  1710.     CALL    ILPRT
  1711.     DB    CR,LF
  1712.     DB    'Loading MFMSG for message input, please stand by...'
  1713.     DB    CR,LF,LF,0
  1714.     LXI    D,81H        ; Our buffer starts at 81H
  1715.     MVI    C,0        ; C=# of characters (stuff at 80H)
  1716.     CALL    MBDFIL
  1717.     STA    80H        ; Save # of chars in 80H
  1718.     MVI    A,0C2H        ; Stuff C2H (JNZ instruction)
  1719.     STA    0000H
  1720.     ORA    A        ; Make sure NZ flag set so JNZ will jump
  1721.     JMP    0000H
  1722. ;
  1723. NOTMSG:     ENDIF    ; MBFMSG
  1724. ;
  1725.      IF    MBFMSG AND NOT MBDESC
  1726.     JMP    EXIT1        ; If not message upload, exit
  1727.      ENDIF
  1728. ;
  1729. ;-----------------------------------------------------------------------
  1730. ;
  1731.      IF    MBDESC AND ZCPR2 AND (NOT ASKSYS)
  1732.     LDA    WHEEL        ; If its the Sysop, don't ask
  1733.     ORA    A        ; For a description because he
  1734.     JNZ    EXIT1        ; Might want to batch recv files
  1735.      ENDIF
  1736. ;
  1737.      IF    MBDESC AND NDESC
  1738.     LDA    NDSCFL        ; If user picked "N" option
  1739.     ORA    A        ; allow them to skip upload
  1740.     JNZ    EXIT1        ; descript
  1741.      ENDIF
  1742. ;
  1743.      IF    MBDESC
  1744.     CALL    BYECHK
  1745.     JNZ    EXIT1
  1746.     CALL    ILPRT
  1747.     DB    CR,LF
  1748.     DB    'Loading MBBS for upload description, '
  1749.     DB    'please stand by...',CR,LF,LF,0
  1750.      ENDIF
  1751. ;
  1752.      IF    MBDESC AND NEWPRV
  1753.     MVI    A,'P'        ; ALL "NEW UPLOADS:" private to start
  1754.      ENDIF
  1755. ;
  1756.      IF    MBDESC AND NOT NEWPRV
  1757.     LDA    PRVTFL        ; 80H=0 if public, "P" if private
  1758.      ENDIF
  1759. ;
  1760.      IF    MBDESC
  1761.     STA    80H        ; Stuff "private" flag in page zero
  1762.     LXI    D,82H        ; Our buffer starts at 82H
  1763.     MVI    C,0        ; C=# of characters (stuff at 81H)
  1764.     LXI    H,MBDSH        ; Heading ("NEW UPLOAD: ")
  1765. ;
  1766. MBDSHP:    MOV    A,M
  1767.     CPI    0
  1768.     JZ    MBDFS
  1769.     CALL    MBDPUT
  1770.     INX    H
  1771.     JMP    MBDSHP
  1772. ;
  1773. MBDFS:    CALL    MBDFIL
  1774.     STA    81H        ; Save # of chars in 81H
  1775.     MVI    A,0CAH        ; Stuff CAH (JZ instruction)
  1776.     STA    0000H
  1777.     XRA    A        ; Make sure Z flag set so JZ will jump
  1778.     JMP    0000H
  1779. ;
  1780. MBDSH:    DB    'NEW UPLOAD: ',0 ; Heading stuffed ahead of filename
  1781.      ENDIF    ; MBDESC
  1782. ;
  1783.      IF    MBDESC OR MBFMSG
  1784. MBDFIL:    LDA    FCB        ; Get drive code
  1785.     ORA    A        ; Check it
  1786.     JNZ    MWDRV        ; If auto login, use it
  1787.     LDA    DSKSAV        ; Else, get current disk
  1788.     INR    A
  1789. ;
  1790. MWDRV:    ADI    'A'-1
  1791.     CALL    MBDPUT        ; Stuff in command line buffer
  1792.     LDA    USRSAV        ; Get user #
  1793.     CPI    10        ; Are we 0-9 or above?
  1794.     JC    US0        ; Must be 0-9
  1795.     ORA    A        ; Clear flags
  1796.     DAA            ; Decimal adjust
  1797.     RAR            ; Shift down tens digit
  1798.     RAR
  1799.     RAR
  1800.     RAR
  1801.     ANI    0FH        ; Mask out tens digit
  1802.     ADI    '0'        ; Make it ASCII
  1803.     CALL    MBDPUT
  1804.     LDA    USRSAV
  1805.     ORA    A        ; Clear flags
  1806.     DAA            ; Decimal adjust
  1807.     ANI    0FH        ; Mask out singles digit
  1808. ;
  1809. US0:    ADI    '0'        ; Make it ASCII
  1810.     CALL    MBDPUT
  1811.     MVI    A,':'        ; Put in a colon
  1812.     CALL    MBDPUT
  1813.     LXI    H,FCB+1        ; Stuff in filename without spaces
  1814.     MVI    B,8
  1815. ;
  1816. DESNM:    MOV    A,M
  1817.     CPI    ' '
  1818.     CNZ    MBDPUT
  1819.     INX    H
  1820.     DCR    B
  1821.     JNZ    DESNM
  1822.     MVI    A,'.'
  1823.     CALL    MBDPUT
  1824.     MVI    B,3
  1825. ;
  1826. DESNM3:    MOV    A,M
  1827.     CPI    ' '
  1828.     JZ    DESGO
  1829.     CPI    0
  1830.     JZ    DESGO
  1831.     CALL    MBDPUT
  1832.     INX    H
  1833.     DCR    B
  1834.     JNZ    DESNM3
  1835. ;
  1836. DESGO:    MOV    A,C
  1837.     RET
  1838. ;
  1839. MBDPUT:    ANI    7FH        ; Strip off any high bits
  1840.     STAX    D        ; Short routine to stuff A in (DE) and
  1841.     INX    D        ; Increment pointer and character count
  1842.     INR    C
  1843.     RET
  1844.      ENDIF    ; MBDESC OR MBFMSG
  1845. ;
  1846. ;-----------------------------------------------------------------------
  1847. ;
  1848. EXIT1:     IF    (TIMEON    OR B3TOS) AND (NOT LUXMOD) AND TOSEXIT
  1849.     CALL    TIME        ; Tell user how long he's been on
  1850.      ENDIF
  1851. ;
  1852.      IF    (BYEBDOS AND (NOT TIMEON)) AND TOSEXIT AND (NOT    LUXMOD)
  1853.     MVI    C,BDPTOS    ; Print time on system
  1854.     CALL    BDOS
  1855.      ENDIF
  1856. ;
  1857. EXIT2:    XRA    A
  1858.     LHLD    STACK
  1859.     SPHL
  1860.     RET
  1861. ;
  1862. ; Check local console status in order to let BYE function keys work in
  1863. ; MBYE and possibly other BYE versions also.  (Your BYE must check for
  1864. ; console function keys in MSTAT.)
  1865. ;
  1866.      IF    CONFUN
  1867. FUNCHK:    PUSH    B        ; Save everything
  1868.     PUSH    D        ; (to be safe)
  1869.     PUSH    H
  1870.     PUSH    PSW
  1871. ;
  1872. CONCHK:    CALL    0000H        ; Address patched in by START
  1873. ;
  1874.      ENDIF
  1875. ;
  1876.      IF    CONFUN AND SYSABT
  1877.     ORA    A        ; If SYSABT set, check for
  1878.     JZ    CONDNE        ; CANCEL (^X) typed by sysop
  1879.     MVI    C,RDCON
  1880.     CALL    BDOS
  1881.     CPI    CAN
  1882.     JNZ    CONDNE
  1883.     STA    SYSABF
  1884.      ENDIF
  1885. ;
  1886. CONDNE:
  1887.      IF    CONFUN
  1888.     POP    PSW        ; For BIOS JMP CONSTAT
  1889.     POP    H
  1890.     POP    D
  1891.     POP    B        ; Restore everything
  1892.     RET            ; And return
  1893.      ENDIF
  1894. ;
  1895. ; Get Disk and User from DUSAVE and log in if valid.
  1896. ;
  1897. GETDU:    CALL    CHKFSP        ; See if a file name is included
  1898.     SHLD    SAVEHL        ; Save location of the filename
  1899.     LDA    PRVTFL        ; Uploading to a private area?
  1900.     ORA    A
  1901.     JNZ    TRAP        ; If yes, going to a specified area
  1902.     LXI    H,DUSAVE    ; Point to drive/user
  1903.     LDA    OLDDRV        ; Get current drive
  1904.     STA    DUD
  1905.     ADI    'A'
  1906.     STA    RCVDRV
  1907.     MOV    A,M        ; Get 1st character
  1908.     CPI    '0'
  1909.     JC    GETDU1
  1910.     CPI    '9'+1
  1911.     JC    NUMER1
  1912. ;
  1913. GETDU1:    STA    RCVDRV        ; Allows SYSOP to upload to any drive
  1914.     CPI    'A'-1
  1915.     JC    NUMER        ; Satisfied with current drive
  1916.     SUI    'A'
  1917.     STA    DUD
  1918. ;
  1919.      IF    ZCPR2
  1920.     LDA    WHEEL        ; SYSOP using the system?
  1921.     ORA    A
  1922.     LDA    DUD        ; Get the value back (flags stay)
  1923.     JNZ    GETDU2        ; If sysop, all things are possible
  1924.      ENDIF
  1925. ;
  1926.      IF    NOT USEMAX
  1927.     CPI    MAXDRV
  1928.     JNC    ILLDU        ; Drive selection not available
  1929.      ENDIF
  1930. ;
  1931.      IF    USEMAX
  1932.     PUSH    H
  1933.     LXI    H,DRIVMAX    ; Point to max drive byte
  1934.     INR    M
  1935.     CMP    M        ; And check it
  1936.     PUSH    PSW        ; Save flags from the CMP
  1937.     DCR    M        ; Restore max drive to normal
  1938.     POP    PSW        ; Restore flags from the CPM
  1939.     JNC    ILLDU
  1940.     POP    H
  1941.      ENDIF
  1942. ;
  1943. GETDU2:    INX    H        ; Get 2nd character
  1944. ;
  1945. NUMER:    MOV    A,M
  1946.     CPI    ':'
  1947.     JZ    OK4        ; Colon for drive only, no user number
  1948.     CALL    CKNUM        ; Check if numeric
  1949. ;
  1950. NUMER1:    SUI    '0'        ; Convert ASCII to binary
  1951.     STA    DUU        ; Save it
  1952.     INX    H        ; Get 3rd character if any
  1953.     MOV    A,M
  1954.     CPI    ':'
  1955.     JZ    OK1
  1956.     LDA    DUU
  1957.     CPI    1        ; Is first number a '1'?
  1958.     JNZ    ILLDU
  1959.     MOV    A,M
  1960.     CALL    CKNUM
  1961.     SUI    '0'-10
  1962.     STA    DUU
  1963.     INX    H        ; Get 4th (and last character) if any
  1964.     MOV    A,M
  1965.     CPI    ':'
  1966.     JNZ    ILLDU
  1967. ;
  1968. OK1:    LDA    OPTSAV        ; Get the option back
  1969.     CPI    'R'        ; Receiving a file?
  1970.     LDA    DUU        ; Get desired user area
  1971.     JZ    OK2        ; Yes, can not use special download area
  1972.     LDA    DUD        ; Get desired drive
  1973.     CPI    SPLDRV-'A'    ; Special download drive requested?
  1974.     LDA    DUU        ; Get user area requested
  1975.     JNZ    OK2        ; If none, exit
  1976.     CPI    SPLUSR        ; Special download area requested?
  1977.     JZ    OK3        ; If yes, process request
  1978. ;
  1979. OK2:     IF    ZCPR2
  1980.     LDA    WHEEL        ; SYSOP using the system?
  1981.     ORA    A
  1982.     LDA    DUU        ; Restore desired user area
  1983.     STA    RCVUSR        ; Allows SYSOP to upload anywhere
  1984.     JNZ    OK3        ; If yes, let him have all user areas
  1985.      ENDIF
  1986. ;
  1987.      IF    NOT USEMAX
  1988.     CPI    MAXUSR+1    ; Check for maximum user download area
  1989.     JNC    ILLDU        ; Error if more (and not special area)
  1990.      ENDIF
  1991. ;
  1992.      IF    USEMAX
  1993.     PUSH    H
  1994.     LXI    H,USRMAX    ; Point at maximum user byte
  1995.     CMP    M        ; And check it
  1996.     JNC    ILLDU
  1997.     POP    H
  1998.      ENDIF
  1999. ;
  2000. OK3:    MOV    E,A
  2001. ;
  2002.      IF    NOT SETAREA
  2003.     STA    NOTUSR+1    ; Store requested user area
  2004.     MVI    A,3EH        ; 'MVI A,--' instruction
  2005.     STA    NOTUSR
  2006.      ENDIF
  2007. ;
  2008.     MVI    C,SETUSR
  2009.     CALL    BDOS        ; Set to requested user area
  2010. ;
  2011. OK4:    LDA    DUD        ; Get drive
  2012.     MOV    E,A
  2013. ;
  2014.      IF    NOT SETAREA
  2015.     ADI    'A'
  2016.     STA    NOTDRV+1    ; Store requested drive
  2017.     MVI    A,3EH        ; 'MVI A,--' instruction
  2018.     STA    NOTDRV
  2019.      ENDIF
  2020. ;
  2021.     MVI    C,SELDSK
  2022.     CALL    BDOS        ; Set to requested drive
  2023. ;
  2024. XIT:    JMP    TRAP        ; Now find file selected
  2025. ;
  2026. ; Shows available space on upload disk/area.  Uses KDRV data area which
  2027. ; must be loaded before calling this routine.  (So KSHOW will work with
  2028. ; user specified disk if SETAREA equate is not set YES.)
  2029. ;
  2030. ; Print the free space remaining for the received file
  2031. ;
  2032. CPMVER    EQU    0CH
  2033. CURDPB    EQU    1FH
  2034. GALLOC    EQU    1BH
  2035. SELDSK    EQU    0EH
  2036. GETFRE    EQU    46
  2037. ;
  2038. KDRV:    DB    0        ; Drive stored here before calling KSHOW
  2039. ;
  2040. KSHOW:    LDA    KDRV        ; Get drive ('A','B','C',etc.)
  2041.     SUI    41H        ; Convert to numeric (0,1,2,etc.)
  2042.     MOV    E,A        ; Stuff in E for BDOS call
  2043.     MVI    C,SELDSK    ; Select the directory drive to retrieve
  2044.     CALL    BDOS        ; The proper allocation vector
  2045.     MVI    C,CURDPB    ; It's 2.X or MP/M...request DPB
  2046.     CALL    BDOS
  2047.     INX    H
  2048.     INX    H
  2049.     MOV    A,M        ; Get block shift
  2050.     STA    BLKSHF
  2051.     INX    H        ; Bump to block mask
  2052.     MOV    A,M
  2053.     INX    H
  2054.     INX    H
  2055.     MOV    E,M        ; Get max block #
  2056.     INX    H
  2057.     MOV    D,M
  2058.     XCHG
  2059.     SHLD    BLKMAX        ; Save it
  2060.     XCHG
  2061.     INX    H
  2062.     MOV    E,M        ; Get directory size
  2063.     INX    H
  2064.     MOV    D,M
  2065.     XCHG
  2066. ;
  2067. ; Calculate # of K free on selected drive
  2068. ;
  2069.     MVI    C,CPMVER    ; Get CP/M version number
  2070.     CALL    BDOS
  2071.     MOV    A,L        ; Get returned version number
  2072.     CPI    30H        ; 3.0?
  2073.     JC    FREE20        ; Use old method if not
  2074.     LDA    KDRV        ; Get drive #
  2075.     SBI    'A'        ; Change from ASCII to binary
  2076.     MOV    E,A        ; Use new Compute Free Space BDOS call
  2077.     MVI    C,GETFRE
  2078.     CALL    BDOS
  2079.     MVI    C,3        ; Answer is a 24-bit integer
  2080. ;
  2081. FRE3L1:    LXI    H,80H+2        ; Answer is in 1st 3 bytes of DMA adr
  2082.     MVI    B,3        ; Convert it from sectors to K
  2083.     ORA    A        ; By dividing by 8
  2084. ;
  2085. FRE3L2:    MOV    A,M
  2086.     RAR
  2087.     MOV    M,A
  2088.     DCX    H
  2089.     DCR    B
  2090.     JNZ    FRE3L2        ; Loop for 3 bytes
  2091.     DCR    C
  2092.     JNZ    FRE3L1        ; Shift 3 times
  2093.     LHLD    80H        ; Now get result in K
  2094.     JMP    SAVFRE        ; Go store it
  2095. ;
  2096. FREE20:    MVI    C,GALLOC    ; Get address of allocation vector
  2097.     CALL    BDOS
  2098.     XCHG
  2099.     LHLD    BLKMAX        ; Get its length
  2100.     INX    H
  2101.     LXI    B,0        ; Init block count to 0
  2102. ;
  2103. GSPBYT:    PUSH    D        ; Save alloc address
  2104.     LDAX    D
  2105.     MVI    E,8        ; Set to process 8 blocks
  2106. ;
  2107. GSPLUP:    RAL            ; Test bit
  2108.     JC    NOTFRE
  2109.     INX    B
  2110. ;
  2111. NOTFRE:    MOV    D,A        ; Save bits
  2112.     DCX    H        ; Count down blocks
  2113.     MOV    A,L
  2114.     ORA    H
  2115.     JZ    ENDALC        ; Quit if out of blocks
  2116.     MOV    A,D        ; Restore bits
  2117.     DCR    E        ; Count down 8 bits
  2118.     JNZ    GSPLUP        ; Do another bit
  2119.     POP    D        ; Bump to next byte..
  2120.     INX    D        ; Of alloc. vector
  2121.     JMP    GSPBYT        ; Process it
  2122. ;
  2123. ENDALC:    POP    D        ; Clear stack of allocation vector ptr.
  2124.     MOV    L,C        ; Copy block to HL
  2125.     MOV    H,B
  2126.     LDA    BLKSHF        ; Get block shift factor
  2127.     SUI    3        ; Convert from sectors to K
  2128.     JZ    SAVFRE        ; Skip shifts if 1K blocks...
  2129. ;                ; Return free in HL
  2130. FREKLP:    DAD    H        ; Multiply blocks by K/BLK
  2131.     DCR    A
  2132.     JNZ    FREKLP
  2133. ;
  2134. ; Print the amount of free space remaining on the selected drive
  2135. ;
  2136. SAVFRE:    CALL    DECOUT
  2137.     CALL    ILPRT
  2138.     DB    'k available for uploads',0
  2139.     RET
  2140. ;
  2141. ; Log into drive and user (if specified).  If none mentioned, it falls
  2142. ; through to 'TRAP' routine for normal use.
  2143. ;
  2144. LOGDU:    LXI    H,TBUF        ; Point to default buffer command line
  2145.     MOV    B,M        ; Store number of characters in command
  2146.     INR    B        ; Add in current location
  2147. ;
  2148. LOG1:    CALL    CHKSP        ; Skip spaces to find 1st command
  2149.     JZ    LOG1
  2150. ;
  2151. LOG2:    CALL    CHKSP        ; Skip 1st command (non-spaces)
  2152.     JNZ    LOG2
  2153.     INX    H
  2154.     CALL    CHKFSP        ; Skip spaces to find 2nd command
  2155.     SHLD    SAVEHL        ; Save start address of the 2nd command
  2156. ;
  2157. ; Now point to the first byte in the argument, i.e., if it was of format
  2158. ; similar to:  B6:HELLO.DOC then we point at the drive character 'B'.
  2159. ;
  2160.     LXI    D,DUSAVE
  2161.     MVI    C,4        ; Drive/user is 4 characters maximum
  2162. ;
  2163. CPLP:    MOV    A,M
  2164.     CPI    ' '+1        ; Space or return, finished
  2165.     JC    TRAP
  2166.     STAX    D
  2167.     INX    H
  2168.     INX    D
  2169.     CPI    ':'
  2170.     JZ    GETDU        ; If colon, get drive/user and log in
  2171.     DCR    B        ; One less position to check
  2172.     DCR    C        ; One less to go
  2173.     JNZ    CPLP
  2174. ;
  2175. ; Check for no file name or ambiguous name
  2176. ;
  2177. TRAP:    CALL    MOVEFCB        ; Move the filename into the file block
  2178.     LXI    H,FCB+1        ; Point to file name
  2179.     MOV    A,M        ; Get first character of file name
  2180.     CPI    ' '        ; Any there?
  2181.     JNZ    ATRAP        ; Yes, check for ambigous file name
  2182. ;
  2183. NFN:    CALL    ERXIT        ; Print message, exit
  2184.     DB    '++ No file name requested ++$'
  2185. ;
  2186. ATRAP:    MVI    B,11        ; 11 characters to check
  2187. ;
  2188. TRLOOP:    MOV    A,M        ; Get char from FCB
  2189.     CPI    '?'        ; Ambiguous?
  2190.     JZ    TRERR        ; Yes, exit with error message
  2191.     CPI    '*'        ; Even more ambiguous?
  2192.     JZ    TRERR        ; Yes, exit with error message
  2193.     INX    H        ; Point to next character
  2194.     DCR    B        ; One less to go
  2195.     JNZ    TRLOOP        ; Not done, check some more
  2196.     RET
  2197. ;
  2198. TRERR:    CALL    ERXIT        ; Print message, exit
  2199.     DB    '++ Wild-card options are not valid ++$'
  2200. ;
  2201. CKNUM:    CPI    '0'
  2202.     JC    ILLDU        ; Error if less than ascii '0'
  2203.     CPI    '9'+1
  2204.     RC            ; Error if more than ascii '9'
  2205. ;
  2206. ILLDU:    CALL    ERXIT
  2207.     DB    '++ Improper drive/user combination ++$'
  2208. ;
  2209. ; Receive a record - returns with carry bit set if EOT received
  2210. ;
  2211. RCVRECD:XRA    A        ; Initialize error count to zero
  2212.     STA    ERRCT
  2213. ;
  2214. RCVRPT:     IF    CONFUN        ; Check for function key?
  2215.     CALL    FUNCHK        ; Yeah, why not?
  2216.      ENDIF
  2217. ;
  2218.      IF    CONFUN AND SYSABT
  2219.     LDA    SYSABF        ; If SYSABT option, check
  2220.     ORA    A        ; to see if Abort
  2221.     JNZ    RCVSABT        ; If so, bail out now...
  2222.      ENDIF
  2223. ;
  2224.     MVI    B,10-1        ; 10-second timeout
  2225.     CALL    RECV        ; Get any character received
  2226.     JC    RCVSTOT        ; Timeout
  2227. ;
  2228. RCVRPTB:CPI    SOH        ; 'SOH' for a 128-byte block?
  2229.     JZ    RCVSOH        ; Yes
  2230.     CPI    STX        ; A 1024-byte block?
  2231.     JZ    RCVSTX        ;
  2232.     ORA    A        ;
  2233.     JZ    RCVRPT        ; Ignore nulls
  2234.     CPI    CRC        ; Ignore our own 'CRC' if needed
  2235.     JZ    RCVRPT
  2236.     CPI    NAK        ; Ignore our own 'NAK' if needed
  2237.     JZ    RCVRPT
  2238.     CPI    CAN        ; CANcel?
  2239.     JZ    CANRCV        ; (look for CAN CAN)
  2240.     CPI    EOT        ; End of transfer?
  2241.     STC            ; Return with carry set if 'EOT'
  2242.     RZ
  2243. ;
  2244. ; Didn't get SOH or EOT - or - didn't get valid header - purge the line,
  2245. ; then send nak
  2246. ;
  2247. RCVSERR:MVI    B,1        ; Wait for 1 second
  2248.     CALL    RECV        ; After last char. received
  2249.     JNC    RCVSERR        ; Loop until sender done
  2250.     LDA    FRSTIM        ; Is it the first time?
  2251.     ORA    A
  2252.     MVI    A,NAK
  2253.     JNZ    RCVSER2        ; If not first time, send NAK
  2254. ;
  2255. ; First time through...do crc/1k/checksum select
  2256. ;
  2257.     LDA    CRCFLG        ; Get 'CRC' flag
  2258.     ORA    A        ; 'CRC' in effect?
  2259.     MVI    A,NAK        ; Put 'NAK' in accum
  2260.     JNZ    RCVSER2        ; And go send it
  2261.     MVI    A,CRC        ; Tell sender 'CRC' is in effect
  2262.     CALL    SEND
  2263.     LDA    KFLAG        ; Did we want 1k protocol?
  2264.     ORA    A
  2265.     JZ    RCVSERX        ; No, just send the "C"
  2266.     MVI    A,'K'        ; Else send a C and a K
  2267. ;
  2268. RCVSER2:CALL    SEND        ; The 'NAK' or 'CRC' request
  2269. ;
  2270. RCVSERX:LDA    ERRCT        ; Abort if
  2271.     INR    A        ; We have reached
  2272.     STA    ERRCT        ; The error
  2273.     CPI    10        ; Limit?
  2274.     JZ    RCVSABT        ; Yes, abort
  2275.     CPI    5        ; Have we tried 5 times already?
  2276.     JNZ    RCVRPT        ; No, try again with same mode
  2277.     MVI    A,'C'        ; Else flip to checksum mode if CRC
  2278.     STA    CRCFLG
  2279.     JMP    RCVRPT        ; And try again
  2280. ;
  2281. ; Error limit exceeded, so abort
  2282. ;
  2283. CANRCV:    CALL    DELAY        ; Wait 100ms
  2284.     CALL    RCVRDY        ; Character waiting?
  2285.     JZ    RCVRPT        ; If so, no pause, skip CANcel
  2286.     MVI    B,4
  2287.     CALL    RECV        ; Else wait for 2nd character
  2288.     JC    RCVSERR        ; If no second character received, error
  2289.     CPI    CAN
  2290.     JNZ    RCVRPTB        ; If second character not CAN, check it
  2291. ;
  2292. RCVSABT:CALL    CLOSFIL        ; Close file
  2293.     CALL    ILPRT
  2294.     DB    CR,LF,CR,LF,'++ Receive cancelled ++',0
  2295.     CALL    DELFILE        ; Delete received file
  2296.     CALL    ERXIT        ; Print second half of message
  2297.     DB    '++ Partial file deleted ++$'
  2298. ;
  2299. ; Deletes the received file (used if receive aborts)
  2300. ;
  2301. DELFILE:LXI    D,FCB        ; Point to file
  2302.     MVI    C,DELET        ; Get function
  2303.     CALL    BDOS        ; Delete it
  2304.     INR    A        ; Delete ok?
  2305.     RNZ            ; Yes, return
  2306.     CALL    ERXIT        ; No, abort
  2307.     DB    '++ Can''t delete received file ++$'
  2308. ;
  2309. ; Timed out on receive
  2310. ;
  2311. RCVSTOT:JMP    RCVSERR        ; Bump error count, etc.
  2312. ;
  2313. ; Got SOH or STX - get block number, block number complemented
  2314. ;
  2315. RCVSOH:    LXI    H,128        ; 128 bytes in this block
  2316.     XRA    A        ; Zero-out KFLAG
  2317.     JMP    RCVHDR
  2318. ;        ;
  2319. RCVSTX:    MVI    A,0FFH        ; Set KFLAG true
  2320.     LXI    H,1024        ; 1024 bytes in block
  2321. ;
  2322. RCVHDR:    SHLD    BLKSIZ        ; Store block size for later
  2323.     STA    KFLAG        ; Set KFLAG as appropriate
  2324.     MVI    B,1        ; Timeout = 1 sec
  2325.     MVI    A,1        ; Need something to store at FRSTIM
  2326.     STA    FRSTIM        ; Indicate first 'SOH' received
  2327.     CALL    RECV        ; Get record
  2328.     JC    RCVSTOT        ; Got timeout
  2329.     MOV    D,A        ; D=block number
  2330.     MVI    B,1        ; Timeout = 1 sec
  2331.     CALL    RECV        ; Get complimented record number
  2332.     JC    RCVSTOT        ; Timeout
  2333.     CMA            ; Calculate the  complement
  2334.     CMP    D        ; Good record number?
  2335.     JZ    RCVDATA        ; Yes, get data
  2336. ;
  2337. ; Got bad record number
  2338. ;
  2339.     JMP    RCVSERR        ; Bump error count
  2340. ;
  2341. RCVDATA:MOV    A,D        ; Get record number
  2342.     STA    RCVRNO        ; Save it
  2343.     MVI    C,0        ; Initialize checksum
  2344.     CALL    CLRCRC        ; Clear CRC counter
  2345.     LHLD    BLKSIZ        ; Get block size,
  2346.     XCHG            ; And put in DE pair to initialize count
  2347.     LHLD    RECPTR        ; Get buffer address
  2348. ;
  2349. RCVCHR:    MVI    B,1        ; 1 sec timeout
  2350.     CALL    RECV        ; Get the character
  2351.     JC    RCVSTOT        ; Timeout
  2352.     MOV    M,A        ; Store the character
  2353.     INX    H        ; Point to next character
  2354.     DCX    D        ; Done?
  2355.     MOV    A,D
  2356.     ORA    E
  2357.     JNZ    RCVCHR        ; No, loop if <= BLKSIZ
  2358.     LDA    CRCFLG        ; Get 'CRC' flag
  2359.     ORA    A        ; 'CRC' in effect?
  2360.     JZ    RCVCRC        ; Yes, to receive 'CRC'
  2361. ;
  2362. ; Verify checksum
  2363. ;
  2364.     MOV    D,C        ; Save checksum
  2365.     MVI    B,1        ; Timeout length
  2366.     CALL    RECV        ; Get checksum
  2367.     JC    RCVSTOT        ; Timeout
  2368.     CMP    D        ; Checksum ok?
  2369.     JNZ    RCVSERR        ; No, error
  2370. ;
  2371. ; Got a record, it's a duplicate if = previous, or OK if = 1 + previous
  2372. ; record.
  2373. ;
  2374. CHKSNUM:LDA    RCVRNO        ; Get received
  2375.     MOV    B,A        ; Save it
  2376.     LDA    RECDNO        ; Get previous
  2377.     CMP    B        ; Prev repeated?
  2378.     JZ    RECVACK        ; 'ACK' to catch up
  2379.     INR    A        ; Calculate next record number
  2380.     CMP    B        ; Match?
  2381.     JNZ    ABORT        ; No match - stop sender, exit
  2382.     RET            ; Carry off - no errors
  2383. ;
  2384. ; Receive the Cyclic Redundancy Check characters (2 bytes) and see if
  2385. ; the CRC received matches the one calculated.    If they match, get next
  2386. ; record, else send a NAK requesting the record be sent again.
  2387. ;
  2388. RCVCRC:    MVI    E,2        ; Number of bytes to receive
  2389. ;
  2390. RCVCRC2:MVI    B,1        ; 1 sececond timeout
  2391.     CALL    RECV        ; Get crc byte
  2392.     JC    RCVSTOT        ; Timeout
  2393.     DCR    E        ; Decrement the number of bytes
  2394.     JNZ    RCVCRC2        ; Get both bytes
  2395.     CALL    CHKCRC        ; Check received CRC against calc'd CRC
  2396.     ORA    A        ; Is CRC okay?
  2397.     JZ    CHKSNUM        ; Yes, go check record numbers
  2398.     JMP    RCVSERR        ; Go check error limit and send NAK
  2399. ;
  2400. ; Previous record repeated, due to the last ACK being garbaged.  ACK it
  2401. ; so sender will catch up
  2402. ;
  2403. RECVACK:CALL    SENDACK        ; Send the ACK
  2404.     JMP    RCVRECD        ; Get next block
  2405. ;
  2406. ; Send an ACK for the record
  2407. ;
  2408. SENDACK:MVI    A,ACK        ; Get 'ACK'
  2409.     CALL    SEND        ; And send it
  2410.     RET
  2411. ;
  2412. ; Send the record header
  2413. ;
  2414. ; Send    [(SOH) or (STX)] (block number) (complemented block number)
  2415. ;
  2416. SENDHDR:LDA    KFLAG        ; 1k blocks enabled?
  2417.     ORA    A
  2418.     JNZ    SENDBIG        ; Yes
  2419.     MVI    A,SOH        ; 128 blocks, use SOH
  2420.     JMP    MORHDR        ; Send it
  2421. ;
  2422. SENDBIG:MVI    A,STX        ; 1024 byte block -  Start of Header
  2423. ;
  2424. MORHDR:    CALL    SEND        ; One Start of Header or another
  2425.     LDA    RECDNO        ; Then send record number
  2426.     CALL    SEND
  2427.     LDA    RECDNO        ; Then record number
  2428.     CMA            ; Complemented
  2429.     CALL    SEND        ; Record number
  2430.     RET            ; From SENDHDR
  2431. ;
  2432. ; Send the data record
  2433. ;
  2434. SENDREC:MVI    C,0        ; Initialize checksum
  2435.     CALL    CLRCRC        ; Clear the 'CRC' counter
  2436.     LDA    KFLAG        ; Are we using 1K blocks?
  2437.     ORA    A
  2438.     JNZ    SEND1        ; Yes, 1k size
  2439.     LXI    D,128        ; Initialize small count
  2440.     JMP    SEND2
  2441. ;
  2442. SEND1:    LXI    D,1024        ; Initialize big count
  2443. ;
  2444. SEND2:    LHLD    RECPTR        ; Get buffer address
  2445. ;
  2446. SENDC:    MOV    A,M        ; Get a character
  2447.     CALL    SEND        ; Send it
  2448.     INX    H        ; Point to next character
  2449.     DCX    D        ; Done?
  2450.     MOV    A,D
  2451.     ORA    E
  2452.     JNZ    SENDC        ; Loop if <=Blocksize
  2453.     RET            ; From SENDREC
  2454. ;
  2455. ; Send the checksum
  2456. ;
  2457. SENDCKS:MOV    A,C        ; Send the
  2458.     CALL    SEND        ; Checksum
  2459.     RET            ; From 'SENDCKS'
  2460. ;
  2461. ; Send the two Cyclic Redundancy Check characters.  Call FINCRC to cal-
  2462. ; culate the CRC which will be in 'DE' upon return.
  2463. ;
  2464. SENDCRC:CALL    FINCRC        ; Calculate the 'CRC' for this record
  2465.     MOV    A,D        ; Put first 'CRC' byte in accumulator
  2466.     CALL    SEND        ; Send it
  2467.     MOV    A,E        ; Put second 'CRC' byte in accumulator
  2468.     CALL    SEND        ; Send it
  2469.     XRA    A        ; Set zero return code
  2470.     RET
  2471. ;
  2472. ; Returns with carry clear if ACK received.  If an ACK is not received,
  2473. ; the error count is incremented, and if less than 10, carry is set and
  2474. ; the record is resent.  if the error count is 10, the program aborts.
  2475. ; waits 12 seconds to avoid any collision with the receiving station.
  2476. ;
  2477. GETACK:    MVI    B,10        ; Wait 10 seconds max
  2478.     CALL    RECVDG        ; Receive with garbage collect
  2479.     JC    ACKERR        ; Timed out
  2480.     CPI    ACK        ; Was it an 'ACK' character?
  2481.     RZ            ; Yes, return
  2482. ;
  2483.      IF    RETRY
  2484.     CPI    NAK        ; Was it an authentic 'NAK'?
  2485.     JNZ    GETACK        ; Ignore if neither 'ACK' nor 'NAK'
  2486.      ENDIF
  2487. ;
  2488. ; Timeout or error on ACK - bump error counters then resend the record
  2489. ; if error limit is not exceeded.
  2490. ;
  2491. ACKERR:    LDA    ERRCT        ; Get count
  2492.     INR    A        ; Bump it
  2493.     STA    ERRCT        ; Save back
  2494.     LHLD    TOTERR        ; Total errors this run
  2495.     INX    H
  2496.     SHLD    TOTERR        ; Update and put back
  2497.     CPI    10        ; At limit?
  2498.     RC            ; If not, go resend the record
  2499. ;
  2500. ; Reached error limit
  2501. ;
  2502.     CALL    ERXIT
  2503.     DB    '++ Send file cancelled ++$'
  2504. ;
  2505. CHKERR:    LDA    KFLAG
  2506.     ORA    A        ; Check to see if in 1024 mode
  2507.     RZ            ; No, so don't bother with rest
  2508.     LHLD    TOTERR        ; Check on errors to date...
  2509.     MOV    A,L        ; Skip if less than DWNSHFT error so far
  2510.     CPI    DWNSHFT
  2511.     RC            ; Not enough errors to bother with yet
  2512.     XCHG            ; Total errors to DE
  2513.     LHLD    RECDNO        ; Get records sent so far
  2514.     CALL    DVHLDE        ; Divide by errors so far
  2515.     MOV    A,C        ; Take low order byte of quotient...
  2516.     CPI    DWNSHFT        ; Compare to specified ratio...
  2517.     RNC            ; Better ratio than needed, so return
  2518.     XRA    A        ; Noisy line, let's try
  2519.     STA    KFLAG        ; 128 byte blocks
  2520.     RET
  2521. ;
  2522. ABORT:    LXI    SP,STACK
  2523. ;
  2524. ABORTL:    MVI    B,1        ; One second without characters
  2525.     CALL    RECV
  2526.     JNC    ABORTL        ; Loop until sender done
  2527.     MVI    A,CAN        ; CTL-X
  2528.     CALL    SEND        ; Stop sending end
  2529. ;
  2530. ABORTW:    MVI    B,1        ; One second without chracters
  2531.     CALL    RECV
  2532.     JNC    ABORTW        ; Loop until sender done
  2533.     MVI    A,CR        ; Get a space...
  2534.     CALL    SEND        ; To clear out CTL-X
  2535.     CALL    ERXIT        ; Exit with abort message
  2536.     DB    '++ XMODEM aborted ++$'
  2537. ;
  2538. ; Increment record number
  2539. ;
  2540. INCRRNO:PUSH    H
  2541.     LHLD    RECDNO        ; Increment record number
  2542.     INX    H
  2543.     SHLD    RECDNO
  2544.     LHLD    VRECNO        ; Update Virtual Record Number
  2545.     LDA    KFLAG        ; Was last record a 1024 byte one?
  2546.     ORA    A        ;
  2547.     JZ    INCRR1        ; Just handled an normal 128 byte record
  2548.     INX    H        ; Otherwise, must have be a BIG one, so
  2549.     INX    H        ; Seven ...
  2550.     INX    H
  2551.     INX    H
  2552.     INX    H
  2553.     INX    H
  2554.     INX    H        ; Plus
  2555. ;
  2556. INCRR1:    INX    H        ; One
  2557.     SHLD    VRECNO        ; Equals the new virtual record number
  2558. ;
  2559.      IF    NOT (USECON OR BYEBDOS)
  2560.     LHLD    CONOUT+1    ; Check to see if showing count on crt
  2561.     MOV    A,H        ; If both zero, user did not fill out
  2562.     ORA    L        ; 'CONOUT:  jmp 0000H' in patch area
  2563.     JZ    INCRN5        ; With his own console output address
  2564.      ENDIF
  2565. ;
  2566. ; Display the record count on the local CRT if "CONOUT" was filled in by
  2567. ; the implementor
  2568. ;
  2569.     MVI    A,1
  2570.     STA    CONONL        ; Set local only
  2571.     LDA    OPTSAV        ; See if receive or send mode
  2572.     CPI    'R'
  2573.     JZ    RMSG
  2574.     CALL    ILPRT
  2575.     DB    CR,'Sending # ',0
  2576.     JMP    REST
  2577. ;
  2578. RMSG:    CALL    ILPRT
  2579.     DB    CR,'Received # ',0
  2580. ;
  2581. REST:    LDA    KFLAG
  2582.     ORA    A
  2583.     JZ    REST1
  2584.     LHLD    VRECNO
  2585.     DCX    H        ; Stupid but simple way to subtract 7
  2586.     DCX    H        ; Without dying on high-byte
  2587.     DCX    H
  2588.     DCX    H
  2589.     DCX    H
  2590.     DCX    H
  2591.     DCX    H
  2592.     CALL    DECOUT
  2593.     MVI    A,'-'
  2594.     CALL    CTYPE
  2595. ;
  2596. REST1:    LHLD    VRECNO        ; Virtual record number to minimize
  2597.     CALL    DECOUT        ; Confusion between 1K and normal
  2598.     CALL    ILPRT        ; 'record' sizes (always in terms of
  2599.     DB    ' ',18H,0    ; 128-byte records)
  2600. ;
  2601.      IF    CONFUN        ; Check for sysop console function
  2602.     CALL    FUNCHK        ; Keys if CONFUN EQU YES
  2603.      ENDIF
  2604. ;
  2605. INCRN5:    POP    H        ; Here from above if no CONOUT
  2606.     RET
  2607. ;
  2608. ; See if file exists - if it exists, ask for a different name.
  2609. ;
  2610. CHEKFIL: IF    NOT SETAREA
  2611.     LDA    PRVTFL        ; Receiving in private area?
  2612.     ORA    A
  2613.     CNZ    RECAREA        ; If yes, set drive and user area
  2614.      ENDIF
  2615. ;
  2616.      IF    SETAREA
  2617.     CALL    RECAREA        ; Set the designated area up
  2618.      ENDIF
  2619. ;
  2620.     LXI    D,FCB        ; Point to control block
  2621.     MVI    C,SRCHF        ; See if it
  2622.     CALL    BDOS        ; Exists
  2623.     INR    A        ; Found?
  2624.     RZ            ; No, return
  2625.     CALL    ERXIT        ; Exit, print error message
  2626.     DB    '++ File exists, use a different name ++$'
  2627. ;
  2628. ; Makes the file to be received
  2629. ;
  2630. MAKEFIL:XRA    A        ; Set extent and record number to 0
  2631.     STA    FCBEXT
  2632.     STA    FCBRNO
  2633.     LXI    D,FCB        ; Point to FCB
  2634.     MVI    C,MAKE        ; Get BDOS FNC
  2635.     CALL    BDOS        ; To the make
  2636.     INR    A        ; 0FFH=bad?
  2637.     RNZ            ; Open ok
  2638. ;
  2639. ; Directory full - can't make file
  2640. ;
  2641.     CALL    ERXIT
  2642.     DB    '++ Error: can''t make file -'
  2643.     DB    ' directory may be full? ++$'
  2644. ;
  2645. ; Computes record count, and saves it until a successful file-open.
  2646. ;
  2647. CNREC:    MVI    C,CFSIZE    ; Computes file size
  2648.     LXI    D,FCB
  2649.     CALL    BDOS        ; Read first
  2650.     LHLD    RANDOM        ; Get the file size
  2651.     SHLD    RCNT        ; Save total record count
  2652.     MOV    A,H
  2653.     ORA    L
  2654.     RNZ            ; Return if not zero length
  2655. ;
  2656. NONAME:    CALL    ERXIT
  2657.     DB    '++ File not found, check DIR ++','$'
  2658. ;
  2659. ; Opens the file to be sent
  2660. ;
  2661. OPENFIL:XRA    A        ; Set extent and rec number to 0
  2662.     STA    FCBEXT        ; For proper open
  2663.     STA    FCBRNO
  2664.     LXI    D,FCB        ; Point to file
  2665.     MVI    C,OPEN        ; Get function
  2666.     CALL    BDOS        ; Open it
  2667.     INR    A        ; Open ok?
  2668.     JNZ    OPENOK        ; If yes, exit
  2669.     LDA    OPTSAV        ; Get command line option
  2670.     CPI    'L'        ; Want to send a library file?
  2671.     JNZ    NONAME        ; Exit, if not
  2672.     CALL    ILPRT
  2673.     DB    CR,LF,'++ Member not found, check DIR ++',CR,LF,0
  2674.     JMP    OPTERR
  2675. ;
  2676. ; Check to see if the SYSOP has tagged a .LBR file for NO SEND - if so,
  2677. ; only allow XMODEM L NAME to transfer individual files. If requested
  2678. ; file is a $SYS file or has any high bits set, disallow unless WHEEL.
  2679. ;
  2680. OPENOK:     IF    ZCPR2
  2681.     LDA    WHEEL        ; Check wheel status if ZCPR2
  2682.     ORA    A        ; Is it zero
  2683.     JNZ    OPENOK1        ; If non-zero skip all restrictions
  2684.      ENDIF
  2685. ;
  2686.      IF    DWNTAG
  2687.     LDA    FCB+3        ; Regardless of access byte?
  2688.     ANI    80H        ; If so,
  2689.     JNZ    OPENOK1        ; Allow it if F3 set regardless
  2690.      ENDIF
  2691. ;
  2692.      IF    ACCESS
  2693.     CALL    BYECHK
  2694.     JNZ    SNDFOK
  2695.     LHLD    0001H        ; Get JMP COLDBOOT
  2696.     DCX    H
  2697.     MOV    D,M
  2698.     DCX    H
  2699.     MOV    E,M
  2700.     LXI    H,ACBOFF    ; + ACBOFF
  2701.     DAD    D
  2702.     MOV    A,M        ; = ACCESS byte address
  2703.     ANI    ACDNLD        ; Test download access bit
  2704.     JNZ    SNDFOK        ; If bit on, downloads OK
  2705.     CALL    ERXIT
  2706.     DB    'Sorry, but you are not allowed to download files '
  2707.     DB    'at this time...','$'
  2708.      ENDIF
  2709. ;
  2710. SNDFOK:     IF    NOSYS AND NOT LUXMOD
  2711.     LDA    FCB+10
  2712.     ANI    80H
  2713.     JNZ    NONAME        ; If $SYS then fake a "file not found"
  2714.      ENDIF
  2715. ;
  2716.      IF    OK2400 AND TAGLBR AND NOT LUXMOD
  2717.     LDA    MSPEED        ; Check baudrate byte set by BYE
  2718.     CPI    6        ; Is caller >=2400 baud?
  2719.     JNC    OPENOK1        ; If so - let em send the file (PAT2)
  2720.      ENDIF
  2721. ;
  2722.      IF    TAGLBR AND NOT LUXMOD
  2723.     LDA    OPTSAV        ; Has SYSOP tagged a large .LBR file?
  2724.     CPI    'L'        ; Using XMODEM L?
  2725.     JZ    OPENOK1        ; Yes, skip tag test
  2726.     LDA    FCB+1        ; First char of file name
  2727.     ANI    80H        ; Check bit 7 for tag
  2728.     JZ    OPENOK1        ; If on, file cannot be sent
  2729.      ENDIF
  2730. ;
  2731.      IF    TAGLBR AND NOT LUXMOD
  2732. OPENOT:    CALL    ERXIT        ; Exit with message
  2733.     DB    '++ File is not for distribution, sorry. ++',CR,LF,CR,LF
  2734.     DB    'For large LBR files please use XMODEM L or LUX',CR,LF
  2735.     DB    'to transfer individual member files','$'
  2736.      ENDIF
  2737. ;
  2738. OPENOK1:LDA    OPTSAV
  2739.     CPI    'L'
  2740.     JNZ    OPN2
  2741.     LXI    D,TBUF
  2742.     MVI    C,SETDMA
  2743.     CALL    BDOS
  2744.     MVI    C,READ
  2745.     LXI    D,FCB
  2746.     CALL    BDOS
  2747.     ORA    A        ; Read ok?
  2748.     JNZ    LERROR
  2749.     LHLD    TBUF+14        ; Value in buffer where DIRSIZE is
  2750.     SHLD    DIRSZ
  2751.     LXI    H,TBUF
  2752.     MOV    A,M
  2753.     ORA    A
  2754.     JZ    CKDIR        ; Check directory present?
  2755. ;
  2756. NOTLBR:    CALL    ERXIT
  2757.     DB    '++ Bad .LBR directory, notify Sysop ++','$'
  2758. ;
  2759. ; Check to see if there is a .LBR file directory with that name and
  2760. ; complain if not.
  2761. ;
  2762. CKDIR:    MVI    B,11        ; Maximum length of file name
  2763.     MVI    A,' '        ; First entry must be all blanks
  2764.     INX    H
  2765. ;
  2766. CKDLP:    CMP    M
  2767.     JNZ    NOTLBR
  2768.     DCR    B
  2769.     INX    H
  2770.     JNZ    CKDLP
  2771. ;
  2772. ; The first entry in the .LBR directory is indeed blank.  Now see if the
  2773. ; directory size is more than 0.
  2774. ;
  2775.     MOV    D,M        ; Get directory starting location
  2776.     INX    H        ; Which must be 0000H...
  2777.     MOV    A,M
  2778.     ORA    D
  2779.     JNZ    NOTLBR        ; Directory does not start in record 0
  2780.     INX    H
  2781.     MOV    A,M        ; Get size of directory
  2782.     INX    H
  2783.     ORA    M
  2784.     JZ    NOTLBR        ; Directory must be >0 records!
  2785.     LXI    H,TBUF        ; Point to directory
  2786. ;
  2787. ; The next routine checks the .LBR directory for the specified member.
  2788. ; Name one sector at a time.
  2789. ;
  2790. CMLP:    MOV    A,M        ; Get member active flag
  2791.     ORA    A        ; 00=active, anything else can be...
  2792.     MVI    B,11        ; Regarded as invalid (erased or blank)
  2793.     INX    H        ; Point to member name
  2794.     JNZ    NOMTCH        ; No match if inactive entry
  2795. ;
  2796. CKLP:    LDAX    D        ; Now compare the file name specified...
  2797.     CMP    M        ; Against the member file name
  2798.     JNZ    NOMTCH        ; Exit loop if no match found
  2799.     INX    H
  2800.     INX    D
  2801.     DCR    B
  2802.     JNZ    CKLP        ; Check all 11 characters
  2803.     MOV    E,M        ; Got the file - get file address
  2804.     INX    H
  2805.     MOV    D,M
  2806.     XCHG
  2807.     SHLD    INDEX        ; Save file address in .LBR
  2808.     XCHG
  2809.     INX    H
  2810.     MOV    E,M        ; Get the file size
  2811.     INX    H
  2812.     MOV    D,M
  2813.     XCHG
  2814.     DCX    H
  2815.     SHLD    RCNT        ; Save size a # of records
  2816.     LHLD    INDEX        ; Get file address
  2817.     SHLD    RANDOM        ; Place it into random field
  2818.     XRA    A
  2819.     STA    RANDOM+2    ; Must zero the 3rd byte
  2820.     STA    FCBRNO        ; Also zero FCB record #
  2821.     LXI    D,FCB        ; Point to FCB of .LBR file
  2822.     MVI    C,RRDM        ; Read random
  2823.     CALL    BDOS
  2824.     JMP    OPENOK3        ; No need to error check
  2825. ;
  2826. ; Come here if no file name match and another sector is needed
  2827. ;
  2828. NOMTCH:    INX    H        ; Skip past the end of the file entry
  2829.     DCR    B
  2830.     JNZ    NOMTCH
  2831.     LXI    B,20        ; Point to next file entry
  2832.     DAD    B
  2833.     LXI    D,MEMFCB    ; Point to member name again
  2834.     MOV    A,H        ; See if we checked all 4 entries
  2835.     ORA    A
  2836.     JZ    CMLP        ; No, check next
  2837.     LHLD    DIRSZ        ; Get directory size
  2838.     MOV    A,H
  2839.     ORA    L
  2840.     JNZ    INLBR        ; Continue if still more to check
  2841.     CALL    ERXIT
  2842.     DB    '++ Member not found, check DIR ++$'
  2843. ;
  2844. INLBR:    DCX    H        ; Decrement dirctory size
  2845.     SHLD    DIRSZ
  2846.     MVI    C,READ        ; Read next sector of directory
  2847.     LXI    D,FCB
  2848.     CALL    BDOS
  2849.     ORA    A        ; Read ok?
  2850.     JNZ    LERROR
  2851.     LXI    H,TBUF        ; Set our pointers for compare
  2852.     LXI    D,MEMFCB
  2853.     JMP    CMLP        ; Check next sector
  2854. ;
  2855. OPN2:     IF    ZCPR2
  2856.     LDA    WHEEL        ; Check status of wheel if zcpr2
  2857.     ORA    A        ; Is it zero
  2858.     JNZ    OPENOK3        ; If not then skip the # and .com check
  2859.      ENDIF
  2860. ;
  2861.      IF    NOLBS OR NOCOMS    ; Check for send restrictions
  2862.     LXI    H,FCB+11
  2863.     MOV    A,M        ; Check for protect attr
  2864.     ANI    7FH        ; Remove CP/M 2.x attrs
  2865.      ENDIF
  2866. ;
  2867.      IF    NOLBS        ; Do not allow '#' to be sent
  2868.     CPI    '#'        ; Chk for '#' as last first
  2869.     JNZ    OPELOK        ; If '#', can not send, show why
  2870.     CALL    ERXIT
  2871.     DB    '++ File not for distribution ++$'
  2872. ;
  2873. OPELOK:     ENDIF
  2874. ;
  2875.      IF    NOCOMS        ; Do not allow '.COM' to be sent
  2876.     CPI    'M'        ; If not, check for '.COM'
  2877.     JNZ    OPENOK3        ; If not, ok to send
  2878.     DCX    H
  2879.     MOV    A,M        ; Check next character
  2880.     ANI    7FH        ; Strip attributes
  2881.     CPI    'O'        ; 'O'?
  2882.     JNZ    OPENOK3        ; If not, ok to send
  2883.     DCX    H
  2884.     MOV    A,M        ; Now check 1st character
  2885.     ANI    7FH        ; Strip attributes
  2886.     CPI    'C'        ; 'C' as in '.COM'?
  2887.     JNZ    OPENOK3        ; If not, continue
  2888.     CALL    ERXIT        ; Exit with message
  2889.     DB    '++ Sending .COM files not allowed ++$'
  2890.      ENDIF    ; NOCOMS
  2891. ;
  2892. OPENOK3: IF    NOT DSPFNAM
  2893.     CALL    ILPRT        ; Print the message
  2894.     DB    'File open: ',0
  2895.      ENDIF
  2896. ;
  2897.      IF    DSPFNAM
  2898.     CALL    ILPRT
  2899.     DB    'Sending: ',0
  2900.     LDA    OPTSAV
  2901.     CPI    'L'
  2902.     JNZ    SFNNL        ; If not L opt, just show name
  2903.     LXI    H,MEMFCB
  2904.     CALL    DSPFN
  2905.     CALL    ILPRT
  2906.     DB    ' from ',0
  2907. ;
  2908. SFNNL:    LXI    H,FCB+1
  2909.     CALL    DSPFN
  2910.     CALL    ILPRT
  2911.     DB    CR,LF,'File size: ',0
  2912.      ENDIF
  2913. ;
  2914.     LHLD    RCNT        ; Get record count
  2915.     LDA    OPTSAV
  2916.     CPI    'L'
  2917.     JNZ    OPENOK4        ; If send from library add 1 to
  2918.     INX    H        ; Show correct record count
  2919. ;
  2920. OPENOK4:CALL    CKKSIZ        ; Check to see if it is at least 1K...
  2921.     CALL    DECOUT        ; Print decimal number of records
  2922.     PUSH    H
  2923.     CALL    ILPRT
  2924.     DB    ' records (',0
  2925.     POP    H        ; Get # of 128 byte records
  2926.     LXI    D,8        ; Divide by 8
  2927.     CALL    DVHLDE        ; To get # of 1024 byte blocks
  2928.     MOV    A,H
  2929.     ORA    L        ; Check if remainder
  2930.     MOV    H,B        ; Get quotient
  2931.     MOV    L,C
  2932.     JZ    EXKB        ; If 0 remainder, exact kilobytes
  2933.     INX    H        ; Else, increment to next k
  2934. ;
  2935. EXKB:    CALL    DECOUT        ; Show # of kilobytes
  2936.     CALL    ILPRT
  2937.     DB    'k)',CR,LF,0
  2938.     CALL    ILPRT
  2939.     DB    'Send time: ',0
  2940.     CALL    FILTIM        ; Get file xfer time in mins in BC
  2941.     PUSH    H        ; Save seconds in HL
  2942. ;
  2943.      IF    ZCPR2 AND MAXTIM
  2944.     LDA    WHEEL        ; Check wheel status if zcpr2
  2945.     ORA    A        ; Is it zero
  2946.     JNZ    SKIPTIM        ; If its not then skip the limit
  2947.      ENDIF
  2948. ;
  2949.      IF    OK2400        ; No restrictions for 2400 bps callers?
  2950.     LDA    MSPEED        ; Check baudrate byte set by BYE
  2951.     CPI    6        ; Is >=2400?
  2952.     JNC    SKIPTIM        ; If so, skip time check
  2953.      ENDIF
  2954. ;
  2955.      IF    MAXTIM
  2956.     MOV    A,C        ; If limiting get length of this program
  2957.     INR    A        ; Increment to next full minute
  2958.      ENDIF
  2959. ;
  2960.      IF    MAXTIM AND TIMEON
  2961.     LXI    H,TON
  2962.     ADD    M        ; Add time on to xfer time, TON will
  2963.      ENDIF
  2964. ;
  2965.      IF    MAXTIM
  2966.     STA    MINUTE        ; Store value for later comparison
  2967.     MOV    A,B        ; Get high byte of minute if >255
  2968.     JNZ    MXTMC2        ; If no carry from increment/add
  2969.     INR    A
  2970. ;
  2971. MXTMC2:    STA    MINUTE+1
  2972.      ENDIF
  2973. ;
  2974. SKIPTIM:MOV    L,C
  2975.     MOV    H,B
  2976.     CALL    DECOUT        ; Print decimal number of minutes
  2977.     MVI    A,':'
  2978.     CALL    CTYPE        ; Output colon
  2979.     POP    H        ; Get seconds
  2980.     MOV    A,L
  2981.     CPI    10
  2982.     MVI    A,'0'        ; Needs a leading zero
  2983.     CC    CTYPE
  2984.     CALL    DECOUT        ; Print the seconds portion
  2985.     CALL    ILPRT
  2986.     DB    ' at ',0
  2987.     LXI    H,SPTBL        ; Start of baud rate speeds
  2988.     MVI    D,0        ; Zero the 'D' register
  2989.     CALL    SPEED        ; Get speed indicator
  2990.     ADD    A        ; Index into the baud rate table
  2991.     ADD    A
  2992.     MOV    E,A        ; Now have the index factor in 'DE'
  2993.     DAD    D        ; Add to 'HL'
  2994.     XCHG            ; Put address in 'DE' regs.
  2995.     MVI    C,PRINT        ; Show the baud
  2996.     CALL    BDOS
  2997.     CALL    SPEED
  2998.     CPI    5
  2999.     MVI    A,'0'        ; Adds a zero for 1200, 2400, 4800 and
  3000.     CNC    CTYPE        ; 9600 bps
  3001. ;
  3002. OPENOK5:CALL    ILPRT
  3003.     DB    ' baud',CR,LF,0
  3004. ;
  3005.      IF    ZCPR2 AND MAXTIM
  3006.     LDA    WHEEL        ; Check wheel status if zcpr2
  3007.     ORA    A        ; Is it zero
  3008.     JNZ    SKIPEM        ; If not then no time limits
  3009.      ENDIF
  3010. ;
  3011.      IF    MAXTIM AND (BYEBDOS OR MXTOS)
  3012.     LDA    MAXTOS        ; Get maximum time on system
  3013.     ORA    A        ; If zero, this guy is a winner
  3014.     JZ    SKIPEM        ; (skip restrictions)
  3015.     LDA    MINUTE+1    ; Is it over 255 minutes?
  3016.     ORA    A
  3017.     JNZ    OVERTM
  3018.      ENDIF
  3019. ;
  3020.      IF    MTL
  3021.     CALL    GETTOS        ; Get time on system in HL
  3022.      ENDIF
  3023. ;
  3024.      IF    MAXTIM AND BYEBDOS AND (NOT TIMEON)
  3025.     MVI    C,BDGRTC    ; Get time on system in A
  3026.     CALL    BDOS
  3027.     MOV    B,A        ; Put in B
  3028.      ENDIF
  3029. ;
  3030.      IF    MAXTIM AND (BYEBDOS OR MXTOS)
  3031.     LDA    MAXTOS
  3032.     INR    A
  3033.      ENDIF
  3034. ;
  3035.      IF    MAXTIM AND BYEBDOS AND (NOT TIMEON)
  3036.     SUB    B
  3037.      ENDIF
  3038. ;
  3039.      IF    MTL
  3040.     SUB    L        ; Get how much time is left
  3041.     ADI    MAXMIN        ; Give them MAXMIN extra
  3042.      ENDIF
  3043. ;
  3044.      IF    MAXTIM AND (BYEBDOS OR MXTOS)
  3045.     MOV    B,A        ; Put max time on sys in B
  3046.     LDA    MINUTE        ; Are we > max time on sys?
  3047.     CMP    B
  3048.     JNC    OVERTM
  3049.      ENDIF
  3050. ;
  3051.      IF    MAXTIM AND NOT (BYEBDOS    OR MXTOS)
  3052.     LDA    MINUTE+1    ; Get minute count high byte
  3053.     ORA    A        ; Check if zero
  3054.     JNZ    OVERTM        ; If not, is over 255 minutes!
  3055.     LDA    MINUTE        ; Get minute count
  3056.     CPI    MAXMIN+1    ; Compare to MAXTIM value
  3057.     JNC    OVERTM        ; If greater than MAXTIM
  3058.      ENDIF
  3059. ;
  3060. SKIPEM:    CALL    ILPRT
  3061.     DB    'To cancel: Ctrl-X, pause, Ctrl-X',CR,LF,0
  3062.     RET
  3063. ;
  3064.      IF    MAXTIM
  3065. OVERTM:    CALL    ILPRT
  3066.     DB    CR,LF,'++ XMODEM ABORTED - send time exceeds the ',0
  3067.      ENDIF
  3068. ;
  3069.      IF    MAXTIM AND NOT (BYEBDOS    OR MXTOS)
  3070.     LXI    H,MAXMIN
  3071.      ENDIF
  3072. ;
  3073.      IF    MAXTIM AND BYEBDOS
  3074.     MVI    C,BDGRTC
  3075.     CALL    BDOS
  3076.     MOV    B,A
  3077.      ENDIF
  3078. ;
  3079.      IF    MTL
  3080.     CALL    GETTOS        ; Get TOS back into HL
  3081.      ENDIF
  3082. ;
  3083.      IF    MAXTIM AND (BYEBDOS OR MXTOS)
  3084.     LDA    MAXTOS
  3085.      ENDIF
  3086. ;
  3087.      IF    MAXTIM AND BYEBDOS
  3088.     SUB    B
  3089.      ENDIF
  3090. ;
  3091.      IF    MTL
  3092.     SUB    L        ; Get time left
  3093.     ADI    MAXMIN        ; Add MAXMIN
  3094.      ENDIF
  3095. ;
  3096.      IF    MAXTIM AND (BYEBDOS OR MXTOS)
  3097.     MVI    H,0
  3098.     MOV    L,A
  3099.      ENDIF
  3100. ;
  3101.      IF    MAXTIM
  3102.     CALL    DECOUT
  3103.     CALL    ERXIT1
  3104.     DB    ' minutes allowed ++$'
  3105.      ENDIF
  3106. ;
  3107. BTABLE:     IF    NOT STOPBIT    ; One stop bit
  3108.     DW    5,13,19,25,30,48,85,141,210,280,0
  3109.      ENDIF
  3110. ;
  3111.      IF    STOPBIT        ; Two stop bits
  3112.     DW    5,12,18,23,27,44,78,128,191,255,0
  3113.      ENDIF
  3114. ;
  3115. KTABLE:     IF    NOT STOPBIT    ; One stop bit
  3116.     DW    5,14,21,27,32,53,101,190,330,525,0
  3117.      ENDIF
  3118. ;
  3119.      IF    STOPBIT        ; Two stop bits
  3120.     DW    5,13,19,25,29,48,92,173,300,477,0
  3121.      ENDIF
  3122. ;
  3123. RECTBL:     IF    NOT STOPBIT    ; One stop bit
  3124.     DB    192,74,51,38,32,20,11,8,5,3,0
  3125.      ENDIF
  3126. ;
  3127.      IF    STOPBIT        ; Two stop bits
  3128.     DB    192,80,53,42,36,22,12,7,5,4,0
  3129.      ENDIF
  3130. ;
  3131. KECTBL:     IF    NOT STOPBIT    ; One stop bit
  3132.     DB    192,69,46,36,30,18,10,5,3,2,0
  3133.      ENDIF
  3134. ;
  3135.      IF    STOPBIT        ; Two stop bits
  3136.     DB    192,74,51,38,33,20,10,6,3,2,0
  3137.      ENDIF
  3138. ;
  3139. SPTBL:    DB    '110$','300$','450$','600$','710$','120$','240$'
  3140.     DB    '480$','960$','1920$'
  3141. ;
  3142. ; Pass record count in RCNT: returns file's approximate download/upload
  3143. ; time in minutes in BC, seconds in HL, also stuffs the # of mins/secs
  3144. ; values in PGSIZE if LOGCAL is YES.
  3145. ;
  3146. FILTIM:    CALL    SPEED        ; Get speed indicator
  3147.     MVI    D,0
  3148.     MOV    E,A        ; Set up for table access
  3149.     LXI    H,BTABLE    ; Point to baud factor table
  3150.     LDA    KFLAG
  3151.     CPI    'K'
  3152.     JNZ    FILTI1
  3153.     LXI    H,KTABLE    ; The guy is using 1k file xfers
  3154. ;
  3155. FILTI1:    DAD    D        ; Index to proper factor
  3156.     DAD    D
  3157.     MOV    E,M
  3158.     INX    H
  3159.     MOV    D,M
  3160.     LHLD    RCNT        ; Get number of records
  3161.     LDA    OPTSAV
  3162.     CPI    'L'        ; If not L download
  3163.     JNZ    SKINCR        ; Skip increment of record count
  3164.     INX    H        ; Increment record count
  3165. ;
  3166. SKINCR:    CALL    DVHLDE        ; Divide HL by value in DE (records/min)
  3167.     PUSH    H        ; Save remainder
  3168.     LXI    H,RECTBL    ; Point to divisors for seconds calc.
  3169.     LDA    KFLAG
  3170.     CPI    'K'
  3171.     JNZ    FILTI2
  3172.     LXI    H,KECTBL    ; The guy is using 1k file transfers
  3173. ;
  3174. FILTI2:    MVI    D,0
  3175.     CALL    SPEED        ; Get speed indicator
  3176.     MOV    E,A
  3177.     DAD    D        ; Index into table
  3178.     MOV    A,M        ; Get multiplier
  3179.     POP    H        ; Get remainder
  3180.     CALL    MULHLA        ; Multiply 'H' by 'A'
  3181.     CALL    SHFTHL
  3182.     CALL    SHFTHL
  3183.     CALL    SHFTHL
  3184.     CALL    SHFTHL
  3185.     MVI    H,0        ; HL now = seconds (L=secs,H=0)
  3186. ;
  3187.      IF    LOGCAL
  3188.     MOV    A,C        ; Add minutes of length (to 0 or 1)
  3189.     STA    PGSIZE        ; Save as LSB of minutes
  3190.     MOV    A,B        ; Get MSB of minutes
  3191.     STA    PGSIZE+1    ; Save as MSB of minutes (>255?)
  3192.     MOV    A,L        ; Get LSB of seconds (can't be >59)
  3193.     STA    PGSIZE+2    ; Save for LOGCALL
  3194.      ENDIF
  3195. ;
  3196.     RET            ; End of FILTIM routine
  3197. ;
  3198. ; Divides 'HL' by value in 'DE' - upon exit: BC=quotient, HL=remainder
  3199. ;
  3200. DVHLDE:    PUSH    D        ; Save divisor
  3201.     MOV    A,E
  3202.     CMA            ; Negate divisor
  3203.     MOV    E,A
  3204.     MOV    A,D
  3205.     CMA
  3206.     MOV    D,A
  3207.     INX    D        ; 'DE' is now two's complemented
  3208.     LXI    B,0        ; Init quotient
  3209. ;
  3210. DIVL1:    DAD    D        ; Subtract divisor from divident
  3211.     INX    B        ; Bump quotient
  3212.     JC    DIVL1        ; Loop until sign changes
  3213.     DCX    B        ; Adjust quotient
  3214.     POP    D        ; Retrieve divisor
  3215.     DAD    D        ; Readjust remainder
  3216.     RET
  3217. ;
  3218. ; Multiply the value in 'HL' by the value in 'A', return with answer in
  3219. ; 'HL'.
  3220. ;
  3221. MULHLA:    XCHG            ; Multiplicand to 'DE'
  3222.     LXI    H,0        ; Init product
  3223.     INR    A
  3224. ;
  3225. MULLP:    DCR    A
  3226.     RZ
  3227.     DAD    D
  3228.     JMP    MULLP
  3229. ;
  3230. ; Shift the 'HL' register pair one bit to the right
  3231. ;
  3232. SHFTHL:    MOV    A,L
  3233.     RAR
  3234.     MOV    L,A
  3235.     ORA    A        ; Clear the carry bit
  3236.     MOV    A,H
  3237.     RAR
  3238.     MOV    H,A
  3239.     RNC
  3240.     MVI    A,128
  3241.     ORA    L
  3242.     MOV    L,A
  3243.     RET
  3244. ;
  3245. ; Closes the received file
  3246. ;
  3247. CLOSFIL:LXI    D,FCB        ; Point to file
  3248.     MVI    C,CLOSE        ; Get function
  3249.     CALL    BDOS        ; Close it
  3250.     INR    A        ; Close ok?
  3251.     JNZ    CLSEXIT        ; Yes, continue
  3252.     CALL    ERXIT        ; No, abort
  3253.     DB    '++ Can''t close file ++$'
  3254. ;
  3255. CLSEXIT:
  3256.      IF    SYSNEW
  3257.     LDA    FCB+10        ; Set $SYS attribute
  3258.     ORI    80H
  3259.     STA    FCB+10
  3260.     LXI    D,FCB        ; Point to file
  3261.     MVI    C,SETATT    ; Set attribute function
  3262.     CALL    BDOS
  3263.      ENDIF
  3264. ;
  3265.     RET
  3266. ;
  3267. ; Decimal output routine - call with decimal value in 'HL'
  3268. ;
  3269. DECOUT:    PUSH    B
  3270.     PUSH    D
  3271.     PUSH    H
  3272.     LXI    B,-10
  3273.     LXI    D,-1
  3274. ;
  3275. DECOU2:    DAD    B
  3276.     INX    D
  3277.     JC    DECOU2
  3278.     LXI    B,10
  3279.     DAD    B
  3280.     XCHG
  3281.     MOV    A,H
  3282.     ORA    L
  3283.     CNZ    DECOUT
  3284.     MOV    A,E
  3285.     ADI    '0'
  3286.     CALL    CTYPE
  3287.     POP    H
  3288.     POP    D
  3289.     POP    B
  3290.     RET
  3291. ;
  3292. ; Makes sure there are enough records to send.    For speed, this routine
  3293. ; buffers up 16 records at a time.
  3294. ;
  3295. RDRECD:    LDA    KFLAG        ; Check for 1024 byte records
  3296.     ORA    A
  3297.     JNZ    RDRECDK        ; Using 1K blocks
  3298. ;
  3299. NOTKAY:    LDA    RECNBF        ; Get number of records in buffer
  3300.     DCR    A        ; Decrement it
  3301.     JM    RDBLOCK        ; Exhausted?  need more
  3302.     ORA    A        ; Otherwise, clear carry and...
  3303.     RET            ; From 'RDRECD'
  3304. ;
  3305. RDRECDK:LDA    RECNBF        ; Get number of records in buffer
  3306.     ORA    A        ; Any records in buffer?
  3307.     JZ    RDBLOCK        ; Nope, get more
  3308.     SUI    8        ; Decrement count of records
  3309.     RNC            ; 8 or more left
  3310.     XRA    A        ; Less than 8 left
  3311.     STA    KFLAG        ; Revert to 128 blocks
  3312.     JMP    NOTKAY        ; Continue with short blocks
  3313. ;
  3314. ; Update buffer pointers and counters AFTER sending a good block.
  3315. ;
  3316. UPDPTR:    LDA    KFLAG
  3317.     ORA    A
  3318.     JNZ    BIG
  3319.     LXI    D,128        ; Small pointer increment
  3320.     MVI    B,1        ; Small sector number
  3321.     JMP    UPDPTR1
  3322. ;
  3323. BIG:    LXI    D,1024        ; Big pointer increment
  3324.     MVI    B,8        ; Number of sectors in big block
  3325. ;
  3326. UPDPTR1:LDA    RECNBF        ; Update buffer sector count
  3327.     SUB    B
  3328.     STA    RECNBF
  3329.     LHLD    RECPTR        ; Get buffer address
  3330.     DAD    D        ; To next buffer
  3331.     SHLD    RECPTR        ; Save buffer address
  3332.     RET
  3333. ;
  3334. ; Buffer is empty - read in another block of 16
  3335. ;
  3336. RDBLOCK:LDA    EOFLG        ; Get 'EOF' flag
  3337.     CPI    1        ; Is it set?
  3338.     STC            ; To show 'EOF'
  3339.     RZ            ; Got 'EOF'
  3340.     MVI    C,0        ; Records in block
  3341.     LXI    D,DBUF        ; To disk buffer
  3342. ;
  3343. RDRECLP:PUSH    B
  3344.     PUSH    D
  3345.     MVI    C,SETDMA    ; Set DMA address
  3346.     CALL    BDOS
  3347.     LXI    D,FCB
  3348.     MVI    C,READ
  3349.     CALL    BDOS
  3350.     POP    D
  3351.     POP    B
  3352.     ORA    A        ; Read ok?
  3353.     JZ    RDRECOK        ; Yes
  3354.     DCR    A        ; 'EOF'?
  3355.     JZ    REOF        ; Got 'EOF'
  3356. ;
  3357. ; Read error
  3358. ;
  3359. LERROR:    CALL    ERXIT
  3360.     DB    '++ File read error ++$'
  3361. ;
  3362. RDRECOK:LXI    H,128        ; Add length of one record
  3363.     DAD    D        ; To next buffer
  3364.     XCHG            ; Buffer to 'DE'
  3365.     INR    C        ; More records?
  3366.     MOV    A,C        ; Get count
  3367.     CPI    BUFSIZ*8    ; Done?
  3368.     JZ    RDBFULL        ; Yes, buffer is full
  3369.     JMP    RDRECLP        ; Read more
  3370. ;
  3371. REOF:    MVI    A,1
  3372.     STA    EOFLG        ; Set EOF flag
  3373.     MOV    A,C
  3374. ;
  3375. ; Buffer is full, or got EOF
  3376. ;
  3377. RDBFULL:STA    RECNBF        ; Store record count
  3378.     LXI    H,DBUF        ; Init buffer pointear
  3379.     SHLD    RECPTR        ; Save buffer address
  3380.     LXI    D,TBUF        ; Reset DMA address
  3381.     MVI    C,SETDMA
  3382.     CALL    BDOS
  3383.     JMP    RDRECD        ; Pass record to caller
  3384. ;
  3385. ; Writes the record into a buffer.  When 16 have been written, writes
  3386. ; the block to disk.
  3387. ;
  3388. ; Entry point "WRBLOCK" flushes the buffer at EOF
  3389. ;
  3390. WRRECD:    LHLD    BLKSIZ        ; Get length of last record
  3391.     XCHG            ; Get ready for add
  3392.     LHLD    RECPTR        ; Get buffer address
  3393.     DAD    D        ; To next buffer
  3394.     SHLD    RECPTR        ; Save buffer address
  3395.     XCHG            ; Move BLKSIZ to HL
  3396.     CALL    SHFTHL        ; Divide by 128 to get recors
  3397.     CALL    SHFTHL
  3398.     CALL    SHFTHL
  3399.     CALL    SHFTHL
  3400.     CALL    SHFTHL
  3401.     CALL    SHFTHL
  3402.     CALL    SHFTHL
  3403.     LDA    RECNBF        ; Bump the records number in the buffer
  3404.     ADD    L
  3405.     STA    RECNBF
  3406.     CPI    BUFSIZ*8    ; Equal to, or past 'end' of buffer?
  3407.     RC            ; No, return
  3408. ;
  3409. ; Writes a block to disk
  3410. ;
  3411. WRBLOCK:LDA    RECNBF        ; Number of records in the buffer
  3412.     ORA    A        ; 0 means end of file
  3413.     RZ            ; None to write
  3414.     MOV    C,A        ; Save count
  3415.     LXI    D,DBUF        ; Point to disk buff
  3416. ;
  3417. DKWRLP:    PUSH    H
  3418.     PUSH    D
  3419.     PUSH    B
  3420.     MVI    C,SETDMA    ; Set DMA
  3421.     CALL    BDOS        ; To buffer
  3422.     LXI    D,FCB        ; Then write the block
  3423.     MVI    C,WRITE
  3424.     CALL    BDOS
  3425.     POP    B
  3426.     POP    D
  3427.     POP    H
  3428.     ORA    A
  3429.     JNZ    WRERR        ; Oops, error
  3430.     LXI    H,128        ; Length of 1 record
  3431.     DAD    D        ; 'HL'= next buff
  3432.     XCHG            ; To 'DE' for setdma
  3433.     DCR    C        ; More records?
  3434.     JNZ    DKWRLP        ; Yes, loop
  3435.     XRA    A        ; Get a zero
  3436.     STA    RECNBF        ; Reset number of records
  3437.     LXI    H,DBUF        ; Reset buffer buffer
  3438.     SHLD    RECPTR        ; Save buffer address
  3439. ;
  3440. RSDMA:    LXI    D,TBUF        ; Reset DMA address
  3441.     MVI    C,SETDMA
  3442.     CALL    BDOS
  3443.     RET
  3444. ;
  3445. WRERR:    CALL    RSDMA        ; Reset DMA to normal
  3446.     MVI    C,CAN        ; Cancel
  3447.     CALL    SEND        ; Sender
  3448.     CALL    RCVSABT        ; Kill receive file
  3449.     CALL    ERXIT        ; Exit with msg:
  3450.     DB    '++ Error writing file ++$'
  3451. ;
  3452. ; Receive a character - timeout time is in 'B' in seconds.  Entry via
  3453. ; 'RECVDG' deletes garbage characters on the line.  For example, having
  3454. ; just sent a record calling 'RECVDG' will delete any line-noise-induced
  3455. ; characters "long" before the ACK/NAK would be received.
  3456. ;
  3457. RECVDG:    CALL    GETCHR
  3458.     CALL    GETCHR
  3459. ;
  3460. RECV:    PUSH    D        ; Save 'DE' regs.
  3461.     MVI    E,MHZ        ; Get the clock speed
  3462.     XRA    A        ; Clear the 'A' reg.
  3463. ;
  3464. MSLOOP:    ADD    B        ; Number of seconds
  3465.     DCR    E        ; One less mhz. to go
  3466.     JNZ    MSLOOP        ; If not zero, continue
  3467.     MOV    B,A        ; Put total value back into 'B'
  3468. ;
  3469. MSEC:     IF    NOT BYEBDOS
  3470.     LXI    D,6600        ; 1 second DCR count
  3471.      ENDIF
  3472. ;
  3473.      IF    BYEBDOS
  3474.     LXI    D,2800        ; (includes BYEBDOS overhead)
  3475.      ENDIF
  3476. ;
  3477. MWTI:    CALL    RCVRDY        ; Input from modem ready
  3478.     JZ    MCHAR        ; Got the character
  3479.     DCR    E        ; Count down for timeout
  3480.     JNZ    MWTI
  3481.     DCR    D
  3482.     JNZ    MWTI
  3483.     DCR    B        ; More seconds?
  3484.     JNZ    MSEC        ; Yes, wait
  3485. ;
  3486. ; Test for the presence of carrier - if none, go to 'CARCK' and continue
  3487. ; testing for specified time.  If carrier returns, continue.  If it does
  3488. ; not return, exit.
  3489. ;
  3490.     CALL    CAROK        ; Is carrier still on?
  3491.     CNZ    CARCK        ; If not, test for 15 seconds
  3492. ;
  3493. ; Modem timed out receiving - but carrier is still on.
  3494. ;
  3495.     POP    D        ; Restore 'DE'
  3496.     STC            ; Carry shows timeout
  3497.     RET
  3498. ;
  3499. ; Get character from modem.
  3500. ;
  3501. MCHAR:    CALL    MDIN        ; Get data byte from modem
  3502.     POP    D        ; Restore 'DE'
  3503. ;
  3504. ; Calculate checksum and CRC
  3505. ;
  3506.     PUSH    PSW        ; Save the character
  3507.     CALL    UPDCRC        ; Calculate CRC
  3508.     ADD    C        ; Add to checksum
  3509.     MOV    C,A        ; Save checksum
  3510.     POP    PSW        ; Restore the character
  3511.     ORA    A        ; Carry off: no error
  3512.     RET            ; From 'RECV'
  3513. ;
  3514. ; Common carrier test for receive and send.  If carrier returns within
  3515. ; TIMOUT seconds, normal program execution continues.  Else, it will
  3516. ; abort to CP/M via EXIT.
  3517. ;
  3518. CARCK:    MVI    E,TIMOUT*10    ; Value for 15 second delay
  3519. ;
  3520. CARCK1:    CALL    DELAY        ; Kill .1 seconds
  3521.     CALL    CAROK        ; Is carrier still on?
  3522.     RZ            ; Return if carrier on
  3523.     DCR    E        ; Has 15 seconds expired?
  3524.     JNZ    CARCK1        ; If not, continue testing
  3525. ;
  3526. ; See if got a local console, and report if so.
  3527. ;
  3528.      IF    NOT (USECON OR BYEBDOS)
  3529.     LHLD    CONOUT+1    ; Get conout address
  3530.     MOV    A,H        ; Zero if no local console
  3531.     ORA    L
  3532.     JZ    CARCK2
  3533.      ENDIF
  3534. ;
  3535.     MVI    A,1        ; Print local only
  3536.     STA    CONONL
  3537.     CALL    ILPRT        ; Report loss of carrier
  3538.     DB    CR,LF,'++ Carrier lost in XMODEM ++',CR,LF,0
  3539. ;
  3540. CARCK2:    LDA    OPTSAV        ; Get option
  3541.     CPI    'R'        ; If not receive
  3542.     JNZ    EXIT        ; Then abort now, else
  3543.     CALL    DELFILE        ; Get rid of the junk first
  3544.     JMP    EXIT        ; Else, abort to CP/M
  3545. ;
  3546. ; Delay - 100 millisecond delay.
  3547. ;
  3548. DELAY:    PUSH    B        ; Save 'BC'
  3549.     LXI    B,MHZ*4167    ; Value for 100 ms. delay
  3550. ;
  3551. DELAY2:    DCX    B        ; Update count
  3552.     MOV    A,B        ; Get MSP byte
  3553.     ORA    C        ; Count = zero?
  3554.     JNZ    DELAY2        ; If not, continue
  3555.     POP    B        ; Restore 'BC'
  3556.     RET            ; Return to CARCK1
  3557. ;
  3558. ;-----------------------------------------------------------------------
  3559. ;
  3560. ; Tells user to add description of an uploaded file
  3561. ;
  3562.      IF    DESCRIB
  3563. ASK:    LDA    OPTSAV        ; Get the option
  3564.     CPI    'R'
  3565.     RNZ            ; If not receiving a file, exit
  3566.     LDA    PRVTFL        ; Sending to "private area"?
  3567.     ORA    A
  3568.     RNZ            ; If yes, do not ask for description
  3569.      ENDIF
  3570. ;
  3571.      IF    DESCRIB    AND ZCPR2 AND (NOT ASKSYS)
  3572.     LDA    WHEEL
  3573.     ORA    A
  3574.     RNZ
  3575.      ENDIF
  3576. ;
  3577.      IF    DESCRIB
  3578.     MVI    B,2        ; Short delay to wait for an input char.
  3579.     CALL    RECV
  3580.      ENDIF
  3581. ;
  3582.      IF    DESCRIB    AND ASKIND
  3583. ASK1:    CALL    DELAY
  3584.     CALL    SHONM        ; Show the file name
  3585.     CALL    DILPRT
  3586.     DB    ' - this file is for:',CR,LF,CR,LF,0
  3587.     MVI    C,PRINT        ; Display the file descriptors
  3588.     LXI    D,KIND0
  3589.     CALL    BDOS
  3590.     CALL    DILPRT
  3591.     DB    CR,LF,'Select one: ',0
  3592.     CALL    INPUT        ; Get a character
  3593.     CALL    TYPE
  3594.     CPI    '0'
  3595.     JC    ASK1
  3596.     CPI    '9'+1
  3597.     JNC    ASK1
  3598.     STA    KIND
  3599.      ENDIF
  3600. ;
  3601.      IF DESCRIB AND    (NOT ASKIND)
  3602. ASK1:    CALL    DELAY
  3603.     CALL    SHONM
  3604.      ENDIF
  3605. ;
  3606.      IF    DESCRIB
  3607. ASK2:    LXI    H,0
  3608.     SHLD    OUTPTR        ; Initialize the output pointers
  3609.     CALL    DILPRT
  3610.     DB    CR,LF,CR,LF
  3611.     DB    'Please describe this file (7 lines or less).  Tell '
  3612.     DB    'what equipment can use',CR,LF,'it and what the '
  3613.     DB    'program does.  Extra RET to quit.',CR,LF,CR,LF,0
  3614.     CALL    SENBEL
  3615. ;
  3616. ; Get the file name from FCB, skip any blanks
  3617. ;
  3618.     LXI    H,HLINE
  3619.     CALL    DSTOR1
  3620.     MVI    B,8        ; Get FILENAME
  3621.     LXI    D,FCB+1
  3622.     LXI    H,OLINE
  3623.     CALL    LOPFCB
  3624.     MVI    M,'.'
  3625.     MOV    A,M        ; Separate FILENAME and EXTENT
  3626.     CALL    TYPE
  3627.     INX    H
  3628.     MVI    B,3        ; Get EXTENT name
  3629.     CALL    LOPFCB
  3630.      ENDIF
  3631. ;
  3632.     IF    DESCRIB    AND ASKIND
  3633. AFIND1:    LDA    KIND
  3634.     CPI    '0'        ; File category 0
  3635.     LXI    D,KIND0+4
  3636.     CZ    DKIND        ; File category 1
  3637.     CPI    '1'
  3638.     LXI    D,KIND1+4
  3639.     CZ    DKIND        ; File category 1
  3640.     CPI    '2'
  3641.     LXI    D,KIND2+4
  3642.     CZ    DKIND        ; File category 2
  3643.     CPI    '3'
  3644.     LXI    D,KIND3+4
  3645.     CZ    DKIND        ; File category 3
  3646.     CPI    '4'
  3647.     LXI    D,KIND4+4
  3648.     CZ    DKIND        ; File category 4
  3649.     CPI    '5'
  3650.     LXI    D,KIND5+4
  3651.     CZ    DKIND        ; File category 5
  3652.     CPI    '6'
  3653.     LXI    D,KIND6+4
  3654.     CZ    DKIND        ; File category 6
  3655.     CPI    '7'
  3656.     LXI    D,KIND7+4
  3657.     CZ    DKIND        ; File category 7
  3658.     CPI    '8'
  3659.     LXI    D,KIND8+4
  3660.     CZ    DKIND        ; File category 8
  3661.     CPI    '9'
  3662.     LXI    D,KIND9+4
  3663.     CZ    DKIND        ; File category 9
  3664.      ENDIF            ; DESCRIB AND ASKIND
  3665. ;
  3666.      IF DESCRIB AND    (NOT ASKIND)
  3667.     MVI    M,CR
  3668.     INX    H
  3669.     MVI    M,LF
  3670.      ENDIF
  3671. ;
  3672.      IF    DESCRIB
  3673.     CALL    DSTOR        ; Put FILENAME line into memory
  3674.     CALL    DILPRT
  3675.     DB    CR,LF,CR,LF,'0: ---------1---------2---------3'
  3676.     DB    '---------4---------5---------6---------',CR,LF,0
  3677.     XRA    A
  3678.     STA    ANYET        ; Reset the flag for no information yet
  3679.     MVI    C,'0'
  3680. ;
  3681. EXPLN:    INR    C
  3682.     MOV    A,C
  3683.     CPI    '7'+1
  3684.     JNC    EXPL1
  3685.     CALL    TYPE
  3686.     MVI    A,' '
  3687.     CALL    OUTCHR
  3688.     CALL    OUTCHR
  3689.     CALL    OUTCHR
  3690.     CALL    DILPRT
  3691.     DB    ': ',0
  3692.     CALL    DESC        ; Get a line of information
  3693.     CALL    DSTOR
  3694.     JMP    EXPLN
  3695. ;
  3696. EXPL1:
  3697.     MVI    A,CR        ; All finished, put in an extra CR-LF
  3698.     CALL    OUTCHR
  3699.     MVI    A,LF
  3700.     CALL    OUTCHR
  3701.     MVI    A,'$'
  3702.     CALL    OUTCHR
  3703.     CALL    DILPRT
  3704.     DB    '   Repeating to verify:',CR,LF,CR,LF,0
  3705.     LHLD    OUTADR
  3706.     XCHG
  3707.     MVI    C,PRINT
  3708.     CALL    BDOS
  3709.     LHLD    OUTPTR
  3710.     DCX    H
  3711.     SHLD    OUTPTR
  3712. ;
  3713. EXPL2:    CALL    DILPRT
  3714.     DB    CR,LF,'Is this ok (Y/N)? ',0
  3715.     CALL    INPUT
  3716.     CALL    TYPE        ; Display answer
  3717.     ANI    5FH        ; Change to upper case
  3718.     CPI    'N'
  3719.     JZ    ASK1        ; If not, do it over
  3720.     CPI    'Y'
  3721.     JNZ    EXPL2        ; If yes, finish up, else ask again
  3722. ;
  3723. ; Now open the file and put this at the beginning
  3724. ;
  3725. EXPL3:    LDA    0004H        ; Get current drive/user
  3726.     STA    DRUSER        ; Store
  3727. ;
  3728. ; Set drive/user to the area listed above
  3729. ;
  3730.     MVI    E,USER        ; Set user to WHATSFOR.TXT area
  3731.     MVI    C,SETUSR
  3732.     CALL    BDOS
  3733.     MVI    A,DRIVE        ; Set drive to WHATSFOR.TXT area
  3734.     SUI    41H
  3735.     MOV    E,A
  3736.     MVI    C,SELDSK
  3737.     CALL    BDOS
  3738. ;
  3739. ; Open source file
  3740. ;
  3741.     CALL    DILPRT
  3742.     DB    CR,LF,0
  3743.     LXI    D,FILE        ; Open WHATSFOR.TXT file
  3744.     MVI    C,OPEN
  3745.     CALL    BDOS
  3746.     INR    A        ; Check for no open
  3747.     JNZ    OFILE        ; File exists, exit
  3748.     MVI    C,MAKE        ; None exists, make a new file
  3749.     LXI    D,FILE
  3750.     CALL    BDOS
  3751.     INR    A
  3752.     JZ    NOROOM        ; Exit if cannot open new file
  3753. ;
  3754. OFILE:    LXI    H,FILE        ; Otherwise use same filename
  3755.     LXI    D,DEST        ; With .$$$ extent for now
  3756.     MVI    B,9
  3757.     CALL    MOVE
  3758. ;
  3759. ; Open the destination file
  3760. ;
  3761.     XRA    A
  3762.     STA    DEST+12
  3763.     STA    DEST+32
  3764.     LXI    H,BSIZE        ; Get Buffer allocated size
  3765.     SHLD    OUTSIZ        ; Set for comparison
  3766.     MVI    C,DELET        ; Delete any existing file that name
  3767.     LXI    D,DEST
  3768.     CALL    BDOS
  3769.     MVI    C,MAKE        ; Now make a new file that name
  3770.     LXI    D,DEST
  3771.     CALL    BDOS
  3772.     INR    A
  3773.     JZ    NOROOM        ; Cannot open file, no directory room
  3774.     CALL    DILPRT
  3775.     DB    CR,LF,'Wait a moment...',0
  3776. ;
  3777. ; Read sector from source file
  3778. ;
  3779. READLP:    LXI    D,TBUF
  3780.     MVI    C,SETDMA
  3781.     CALL    BDOS
  3782.     LXI    D,FILE        ; Read from WHATSFOR.TXT
  3783.     MVI    C,READ
  3784.     CALL    BDOS
  3785.     ORA    A        ; Read ok?
  3786.     JNZ    RERROR
  3787.     LXI    H,TBUF        ; Read buffer address
  3788. ;
  3789. ; Write sector to output file (with buffering)
  3790. ;
  3791. WRDLOP:    MOV    A,M        ; Get byte from read buffer
  3792.     ANI    7FH        ; Strip parity bit
  3793.     CPI    7FH        ; Del (rubout)?
  3794.     JZ    NEXT        ; Yes, ignore it
  3795.     CPI    EOF        ; End of file marker?
  3796.     JZ    TDONE        ; Transfer done, close, exit
  3797.     CALL    OUTCHR
  3798. ;
  3799. NEXT:    INR    L        ; Done with sector?
  3800.     JZ    READLP        ; If yes get another sector
  3801.     JMP    WRDLOP        ; No, get another byte
  3802. ;
  3803. ; Handle a backspace character while entering a character string
  3804. ;
  3805. BCKSP:    CALL    TYPE
  3806.     MOV    A,B        ; Get position on line
  3807.     ORA    A
  3808.     JNZ    BCKSP1        ; Exit if at initial column
  3809.     CALL    SENBEL        ; Send a bell to the modem
  3810.     MVI    A,' '        ; Delete the character
  3811.     JMP    BCKSP3
  3812. ;
  3813. BCKSP1:    DCR    B        ; Show one less column used
  3814.     DCX    H        ; Decrease buffer location
  3815.     MVI    A,' '
  3816.     MOV    M,A        ; Clear memory at this point
  3817.     CALL    TYPE        ; Backspace the "CRT"
  3818. ;
  3819. BCKSP2:    MVI    A,BS        ; Reset the "CRT" again
  3820. ;
  3821. BCKSP3:    CALL    TYPE        ; Write to the "CRT"
  3822.     RET
  3823. ;
  3824. ; Asks for line of information
  3825. ;
  3826. DESC:    MVI    B,0
  3827.     LXI    H,OLINE
  3828. ;
  3829. DESC1:    CALL    INPUT        ; Get keyboard character
  3830.     CPI    CR
  3831.     JZ    DESC4
  3832.     CPI    TAB
  3833.     JZ    DESC6
  3834.     CPI    BS
  3835.     JNZ    DESC2
  3836.     CALL    BCKSP
  3837.     JMP    DESC1        ; Get the next character
  3838. ;
  3839. DESC2:    CPI    ' '
  3840.     JC    DESC1        ; If non-printing character, ignore
  3841.     JZ    DESC3        ; If a space, continue
  3842.     STA    ANYET        ; Show a character has been sent now
  3843. ;
  3844. DESC3:    MOV    M,A
  3845.     CALL    TYPE        ; Display the character
  3846.     INX    H
  3847.     INR    B
  3848.     MOV    A,B
  3849.     CPI    70        ; Do not exceed line length
  3850.     JC    DESC1
  3851.     CALL    SENBEL        ; Send a bell to the modem
  3852.     CALL    BCKSP2
  3853.     CALL    BCKSP1        ; Do not allow a too-long line
  3854.     JMP    DESC1
  3855. ;
  3856. DESC4:    LDA    ANYET        ; Any text typed on first line yet?
  3857.     ORA    A
  3858.     JNZ    DESC5        ; If yes, exit
  3859.     POP    H
  3860.     JMP    ASK1        ; Ask again for a description
  3861. ;
  3862. DESC5:    MVI    M,CR
  3863.     MOV    A,M
  3864.     CALL    TYPE
  3865.     INX    H        ; Ready for next character
  3866.     MVI    M,LF
  3867.     MOV    A,M
  3868.     CALL    TYPE        ; Display the line feed
  3869.     INX    H
  3870.     MOV    A,B        ; See if at first of line
  3871.     ORA    A
  3872.     RNZ            ; If not, ask for next line
  3873.     POP    H        ; Clear "CALL" from stack
  3874.     JMP    EXPL1
  3875. ;
  3876. DESC6:    MOV    A,B        ; At end of line now?
  3877.     CPI    68
  3878.     JNC    DESC1        ; If yes, disregard
  3879.     MVI    M,' '
  3880.     MOV    A,M
  3881.     CALL    TYPE
  3882.     INX    H
  3883.     INR    B
  3884.     MOV    A,B
  3885.     ANI    7
  3886.     JNZ    DESC6
  3887.     JMP    DESC1        ; Ask for next character
  3888. ;
  3889. DSTOR:    LXI    H,OLINE
  3890. ;
  3891. DSTOR1:    MOV    A,M
  3892.     CALL    OUTCHR
  3893.     CPI    LF
  3894.     RZ
  3895.     INX    H
  3896.     JMP    DSTOR1
  3897. ;
  3898. ; Print message then exit to CP/M
  3899. ;
  3900. DEXIT:    POP    D        ; Get message address
  3901.     MVI    C,PRINT        ; Print message
  3902.     CALL    BDOS
  3903.     CALL    RESET        ; Reset the drive/user
  3904.     JMP    EXIT        ; all done
  3905. ;
  3906. ; Inline print routine - prints string pointed to by stack until a zero
  3907. ; is found.  Returns to caller at the next address after the zero ter-
  3908. ; minator.
  3909. ;
  3910. DILPRT:    XTHL            ; Save hl, get message address
  3911. ;
  3912. DILPLP:    MOV    A,M        ; Get char
  3913.     CALL    TYPE        ; Output it
  3914.     INX    H        ; Point to next
  3915.     MOV    A,M        ; Test
  3916.     ORA    A        ; For end
  3917.     JNZ    DILPLP
  3918.     XTHL            ; Restore hl, ret address
  3919.     RET            ; Return past the end of the message
  3920. ;
  3921. ;
  3922. ; Disk is full, save original file, erase others.
  3923. ;
  3924. FULL:    MVI    C,DELET
  3925.     LXI    D,DEST
  3926.     CALL    BDOS
  3927.     CALL    DEXIT
  3928.     DB    CR,LF,'++ DISK FULL, ABORTING, SAVING ORIGINAL FILE','$'
  3929. ;
  3930. ; Get a character, if none ready wait up to 3 minutes, then abort pgm
  3931. ;
  3932. INPUT:    PUSH    H        ; Save current values
  3933.     PUSH    D
  3934.     PUSH    B
  3935. ;
  3936. INPUT1:    LXI    D,1200        ; Outer loop count (about 2 minutes)
  3937. ;
  3938. INPUT2:    LXI    B,MHZ*100    ; Roughly 100 ms.
  3939. ;
  3940. INPUT3:    PUSH    D        ; Save the outer delay count
  3941.     PUSH    B        ; Save the inner delay count
  3942.     MVI    E,0FFH
  3943.     MVI    C,DIRCON    ; Get console status
  3944.     CALL    BDOS
  3945.     ANI    7FH
  3946.     POP    B        ; Restore the inner delay count
  3947.     POP    D        ; Restore the outer delay count
  3948.     ORA    A        ; Have a character yet?
  3949.     JNZ    INPUT4        ; If yes, exit and get it
  3950.     DCX    B
  3951.     MOV    A,C        ; See if inner loop is finished
  3952.     ORA    B
  3953.     JNZ    INPUT3        ; If not loop again
  3954.     DCX    D
  3955.     MOV    A,E
  3956.     ORA    D
  3957.     JNZ    INPUT2        ; If not reset inner loop and go again
  3958.     MVI    A,CR
  3959.     CALL    OUTCHR
  3960.     MVI    A,LF
  3961.     CALL    OUTCHR
  3962.     LXI    SP,STACK    ; Restore the stack
  3963.     CALL    EXPL3        ; Finish appending previous information
  3964.     JMP    EXIT        ; Finished
  3965. ;
  3966. INPUT4:    POP    B
  3967.     POP    D
  3968.     POP    H
  3969.     RET
  3970. ;
  3971. ; Stores the Filename/extent in the buffer temporarily
  3972. ;
  3973. LOPFCB:    LDAX    D        ; Get FCB FILENAME/EXT character
  3974.     CPI    ' '+1
  3975.     JC    LOPF1
  3976.     MOV    M,A        ; Store in OLINE area
  3977.     CALL    TYPE        ; Display on CRT
  3978.     INX    H        ; Next OLINE position
  3979. ;
  3980. LOPF1:    INX    D        ; Next FCB position
  3981.     DCR    B        ; One less to go
  3982.     JNZ    LOPFCB        ; If not done, get next one
  3983.     RET
  3984. ;
  3985. ; No room to open a new file
  3986. ;
  3987. NOROOM:    CALL    DEXIT
  3988.     DB    CR,LF,'++ No DIR space: output ++$'
  3989. ;
  3990. ; Output error - cannot close destination file
  3991. ;
  3992. OERROR:    CALL    DEXIT
  3993.     DB    CR,LF,'++ Cannot close output ++$'
  3994. ;
  3995. ; Output a character to the new file buffer - first, see if there is
  3996. ; room in the buffer for this character.
  3997. ;
  3998. OUTCHR:    PUSH    H
  3999.     PUSH    PSW        ; Store the character for now
  4000.     LHLD    OUTSIZ        ; Get buffer size
  4001.     XCHG            ; Put in 'DE'
  4002.     LHLD    OUTPTR        ; Now get the buffer pointers
  4003.     MOV    A,L        ; Check to see if room in buffer
  4004.     SUB    E
  4005.     MOV    A,H
  4006.     SBB    D
  4007.     JC    OUT3        ; If room, go store the character
  4008.     LXI    H,0        ; Otherwise reset the pointers
  4009.     SHLD    OUTPTR        ; Store the new pointer address
  4010. ;
  4011. OUT1:    XCHG            ; Put pointer address into 'DE'
  4012.     LHLD    OUTSIZ        ; Get the buffer size into 'HL'
  4013.     MOV    A,E        ; See if buffer is max. length yet
  4014.     SUB    L        ; By subtracting 'HL' from 'DE'
  4015.     MOV    A,D
  4016.     SBB    H
  4017.     JNC    OUT2        ; If less, exit and keep going
  4018. ;
  4019. ; No more room in buffer, stop and transfer to destination file
  4020. ;
  4021.     LHLD    OUTADR        ; Get the buffer address
  4022.     DAD    D        ; Add pointer value
  4023.     XCHG            ; Put into 'DE'
  4024.     MVI    C,SETDMA
  4025.     CALL    BDOS
  4026.     LXI    D,DEST
  4027.     MVI    C,WRITE
  4028.     CALL    BDOS
  4029.     ORA    A
  4030.     JNZ    FULL        ; Exit with error, if disk is full now
  4031.     LXI    D,RLEN
  4032.     LHLD    OUTPTR
  4033.     DAD    D
  4034.     SHLD    OUTPTR
  4035.     JMP    OUT1
  4036. ;
  4037. OUT2:    LXI    D,TBUF
  4038.     MVI    C,SETDMA
  4039.     CALL    BDOS
  4040.     LXI    H,0
  4041.     SHLD    OUTPTR
  4042. ;
  4043. OUT3:    XCHG
  4044.     LHLD    OUTADR
  4045.     DAD    D
  4046.     XCHG
  4047.     POP    PSW        ; Get the character back
  4048.     STAX    D        ; Store the character
  4049.     LHLD    OUTPTR        ; Get the buffer pointer
  4050.     INX    H        ; Increment them
  4051.     SHLD    OUTPTR        ; Store the new pointer address
  4052.     POP    H
  4053.     RET
  4054. ;
  4055. RERROR:    CPI    1        ; File finished?
  4056.     JZ    TDONE        ; Exit, then
  4057.     MVI    C,DELET        ; Erase destination file, keep original
  4058.     LXI    D,DEST
  4059.     CALL    BDOS
  4060.     CALL    DEXIT
  4061.     DB    '++ Source file read error ++$'
  4062. ;
  4063. ; Reset the Drive/User to original, then back to original caller
  4064. ;
  4065. RESET:    LDA    DRUSER        ; Get original drive/user area back
  4066.     RAR
  4067.     RAR
  4068.     RAR
  4069.     RAR
  4070.     ANI    0FH        ; Just look at the user area
  4071.     MOV    E,A
  4072.     MVI    C,SETUSR    ; Restore original user area
  4073.     CALL    BDOS
  4074.     LDA    DRUSER        ; Get the original drive/user back
  4075.     ANI    0FH        ; Just look at the drive for now
  4076.     MOV    E,A
  4077.     MVI    C,SELDSK    ; Restore original drive
  4078.     CALL    BDOS
  4079.     CALL    DILPRT        ; Print CRLF before quitting
  4080.     DB    CR,LF,0
  4081.     RET            ; Return to caller (Not JMP EXIT1)
  4082. ;
  4083. ; Send a bell just to the modem
  4084. ;
  4085. SENBEL:    CALL    SNDRDY        ; Is modem ready for another character?
  4086.     JNZ    SENBEL        ; If not, wait
  4087.     MVI    A,7
  4088.     PUSH    PSW        ; Overlay has the "POP PSW"
  4089.     JMP    SENDR        ; Send to the modem only
  4090. ;
  4091. ;.....
  4092. ;
  4093. ;
  4094. ; Shows the Filename/extent
  4095. ;
  4096. SHONM:    CALL    DILPRT
  4097.     DB    CR,LF,CR,LF,0
  4098.     LXI    H,FCB+1
  4099.     MVI    B,8        ; Maximum size of file name
  4100.     CALL    SHONM1
  4101.     MOV    A,M        ; Get the next character
  4102.     CPI    ' '        ; Any file extent?
  4103.     RZ            ; If not, finished
  4104.     MVI    A,'.'
  4105.     CALL    TYPE
  4106.     MVI    B,3        ; Maximum size of file extent
  4107. ;
  4108. SHONM1:    MOV    A,M        ; Get FCB FILENAME/EXT character
  4109.     CPI    ' '+1        ; Skip any blanks
  4110.     JC    $+6
  4111.     CALL    TYPE        ; Display on CRT
  4112.     INX    H        ; Next FCB position
  4113.     DCR    B        ; One less to go
  4114.     JNZ    SHONM1        ; If not done, get next one
  4115.     RET
  4116. ;.....
  4117. ;
  4118. ; Transfer is done - close destination file
  4119. ;
  4120. TDONE:    LHLD    OUTPTR
  4121.     MOV    A,L
  4122.     ANI    RLEN-1
  4123.     JNZ    TDONE1
  4124.     SHLD    OUTSIZ
  4125. ;
  4126. TDONE1:    MVI    A,EOF        ; Fill remainder of record with ^Z's
  4127.     PUSH    PSW
  4128.     CALL    OUTCHR
  4129.     POP    PSW
  4130.     JNZ    TDONE
  4131.     MVI    C,CLOSE        ; Close WHATSFOR.TXT file
  4132.     LXI    D,FILE
  4133.     CALL    BDOS
  4134.     MVI    C,CLOSE        ; Close WHATSFOR.$$$ file
  4135.     LXI    D,DEST
  4136.     CALL    BDOS
  4137.     INR    A
  4138.     JZ    OERROR
  4139. ;
  4140. ;  Rename both files as no destination file name was specified
  4141. ;
  4142.     LXI    H,FILE+1    ; Prepare to rename old file to new
  4143.     LXI    D,DEST+17
  4144.     MVI    B,16
  4145.     CALL    MOVE
  4146.     MVI    C,DELET        ; Delete original WHATSFOR.TXT file
  4147.     LXI    D,FILE
  4148.     CALL    BDOS
  4149.     LXI    D,DEST        ; Rename WHATSFOR.$$$ to WHATSFOR.TXT
  4150.     MVI    C,RENAME
  4151.     CALL    BDOS
  4152.     JMP    RESET        ; Reset the drive/user, back to caller
  4153. ;
  4154. TYPE:    PUSH    B
  4155.     PUSH    D
  4156.     PUSH    H
  4157.     PUSH    PSW
  4158.     MOV    E,A        ; Character to 'E' for CP/M
  4159.     MVI    C,WRCON        ; Write to console
  4160.     CALL    BDOS
  4161.     POP    PSW
  4162.     POP    H
  4163.     POP    D
  4164.     POP    B
  4165.     RET
  4166.      ENDIF    ; DESCRIB
  4167. ;
  4168.      IF    DESCRIB    AND ASKIND
  4169. DKIND:    LDAX    D        ; Get the character from the string
  4170.     CALL    TYPE        ; Otherwise display the character
  4171.     MOV    M,A        ; Put in the buffer
  4172.     CPI    LF        ; Done yet?
  4173.     JZ    DKIND1        ; Exit if a LF, done
  4174.     INX    D        ; Next position in the string
  4175.     INX    H        ; Next postion in the buffer
  4176.     JMP    DKIND        ; Keep going until a LF
  4177. ;
  4178. DKIND1:    LDA    KIND        ; Get the kind of file back
  4179.     RET            ; Finished
  4180.      ENDIF
  4181. ;.....
  4182. ;
  4183. ;-----------------------------------------------------------------------
  4184. ;
  4185. ; Send a character to the modem
  4186. ;
  4187. SEND:    PUSH    PSW        ; Save the character
  4188.     CALL    UPDCRC        ; Calculate CRC
  4189.     ADD    C        ; Calcculate checksum
  4190.     MOV    C,A        ; Save cksum
  4191. ;
  4192. SENDW:    CALL    SNDRDY        ; Is transmit ready
  4193.     JZ    SENDR        ; Yes, go send
  4194. ;
  4195. ; Xmit status not ready, so test for carrier before looping - if lost,
  4196. ; go to CARCK and give it up to 15 seconds to return.  If it doesn't,
  4197. ; return abort via EXIT.
  4198. ;
  4199.     PUSH    D        ; Save 'DE'
  4200.     CALL    CAROK        ; Is carrier still on?
  4201.     CNZ    CARCK        ; If not, continue testing it
  4202.     POP    D        ; Restore 'DE'
  4203.     JMP    SENDW        ; Else, wait for xmit ready
  4204. ;
  4205. ; Waits for initial NAK - to ensure no data is sent until the receiving
  4206. ; program is ready, this routine waits for the first timeout-nak or the
  4207. ; letter 'C' for CRC from the receiver.  If CRC is in effect then Cyclic
  4208. ; Redundancy Checks are used instead of checksums.  'E' contains the
  4209. ; number of seconds to wait.  If the first character received is a CAN
  4210. ; (CTL-X) then the send will be aborted as though it had timed out.
  4211. ; Since 1K extensions require CRC, KFLAG is set to NULL if the receiver
  4212. ; requests checksum
  4213. ;
  4214. WAITNAK: IF    CONFUN        ; Check for Sysop function key?
  4215.     CALL    FUNCHK        ; Yeah, go ahead.. Twit?
  4216.      ENDIF
  4217. ;
  4218.      IF    CONFUN AND SYSABT
  4219.     LDA    SYSABF        ; If SYSABT option, check
  4220.     ORA    A        ; to see if Abort
  4221.     JNZ    ABORT        ; If so, bail out now...
  4222.      ENDIF
  4223. ;
  4224.     MVI    B,1        ; Timeout delay
  4225.     CALL    RECV        ; Did we get
  4226.     CPI    'K'        ; Did he send a "K" first?
  4227.     JZ    SET1KX
  4228.     CPI    CRC        ; 'CRC' indicated?
  4229.     JZ    SET1K        ; Yes, send block
  4230.     CPI    NAK        ; A 'NAK' indicating checksum?
  4231.     JZ    SETNAK        ; Yes go put checksum in effect
  4232.     CPI    CAN        ; Was it a cancel (CTL-X)?
  4233.     JZ    ABORT        ; Yes, abort
  4234.     DCR    E        ; Finished yet?
  4235.     JZ    ABORT        ; Yes, abort
  4236.     JMP    WAITNAK        ; No, loop
  4237. ;
  4238. ; Turn on checksum flag
  4239. ;
  4240. SETNAK:    XRA    A
  4241.     STA    KFLAG        ; Make sure transfer uses small blocks
  4242.     MVI    A,'C'        ; Change to checksum
  4243.     STA    CRCFLG
  4244.     RET
  4245. ;
  4246. ; Turn on 1k flag
  4247. ;
  4248. SET1K:    MVI    B,1        ; Wait up to 1 second to get "K"
  4249.     CALL    RECV
  4250.     CPI    'K'        ; Did we get a "K" or something else
  4251.     RNZ            ; (or nothing)
  4252. ;
  4253. SET1KX:    LDA    MSPEED
  4254.     CPI    5
  4255.     RC
  4256.     MVI    A,'K'
  4257.     STA    KFLAG        ; Set 1k flag
  4258.     RET
  4259. ;
  4260. ; This routine moves the filename from the default command line buffer
  4261. ; to the file control block (FCB).
  4262. ;
  4263. MOVEFCB:LHLD    SAVEHL        ; Get position on command line
  4264.     CALL    GETB        ; Get numeric position
  4265.     LXI    D,FCB+1
  4266.     CALL    MOVENAM        ; Move name to FCB
  4267.     XRA    A
  4268.     STA    FCBRNO        ; Zero record number
  4269.     STA    FCBEXT        ; Zero extent
  4270.     LDA    OPTSAV        ; This going to be a library file?
  4271.     CPI    'L'
  4272.     RNZ            ; If not, finished
  4273. ;
  4274. ; Handles library entries, first checks for proper .LBR extent.  If no
  4275. ; extent was included, it adds one itself.
  4276. ;
  4277.     SHLD    SAVEHL
  4278.     LXI    H,FCB+9        ; 1st extent character
  4279.     MOV    A,M
  4280.     CPI    ' '
  4281.     JZ    NOEXT        ; No extent, make one
  4282.     CPI    'L'        ; Check 1st character in extent
  4283.     JNZ    LBRERR
  4284.     INX    H
  4285.     MOV    A,M
  4286.     CPI    'B'        ; Check 2nd character in extent
  4287.     JNZ    LBRERR
  4288.     INX    H
  4289.     MOV    A,M
  4290.     CPI    'R'        ; Check 3rd character in extent
  4291.     JNZ    LBRERR
  4292. ;
  4293. ; Get the name of the desired file in the library
  4294. ;
  4295. MOVEF1:    LHLD    SAVEHL        ; Get current position on command line
  4296.     CALL    CHKMSP        ; See if valid library member file name
  4297.     INR    B        ; Increment for move name
  4298.     LXI    D,MEMFCB    ; Store member name in special buffer
  4299.     JMP    MOVENAM        ; Move from command line to buffer, done
  4300. ;
  4301. ; Check for any spaces prior to library member file name, if none (or
  4302. ; only spaces remaining), no name.
  4303. ;
  4304. CHKMSP:    DCR    B
  4305.     JZ    MEMERR
  4306.     MOV    A,M
  4307.     CPI    ' '+1
  4308.     RNC
  4309.     INX    H
  4310.     JMP    CHKMSP
  4311. ;
  4312. ; Gets the count of characters remaining on the command line
  4313. ;
  4314. GETB:    MOV    A,L
  4315.     SUI    TBUF+2        ; Start location of 1st command
  4316.     MOV    B,A        ; Store for now
  4317.     LDA    TBUF        ; Find length of command line
  4318.     SUB    B        ; Subtract those already used
  4319.     MOV    B,A        ; Now have number of bytes remaining
  4320.     RET
  4321. ;
  4322. LBRERR:    CALL    ERXIT
  4323.     DB    '++ Invalid library name ++$'
  4324. ;
  4325. MEMERR:    CALL    ILPRT
  4326.     DB    CR,LF,'++ No library member file requested ++',CR,LF,0
  4327.     JMP    OPTERR
  4328. ;
  4329. ; Add .LBR extent to the library file name
  4330. ;
  4331. NOEXT:    LXI    H,FCB+9        ; Location of extent
  4332.     MVI    M,'L'
  4333.     INX    H
  4334.     MVI    M,'B'
  4335.     INX    H
  4336.     MVI    M,'R'
  4337.     JMP    MOVEF1        ; Now get the library member name
  4338. ;
  4339. ; Move a file name from the 'TBUF' command line buffer into FCB
  4340. ;
  4341. MOVENAM:MVI    C,1
  4342. ;
  4343. MOVEN1:    MOV    A,M
  4344.     CPI    ' '+1        ; Name ends with space or return
  4345.     JC    FILLSP        ; Fill with spaces if needed
  4346.     CPI    '.'
  4347.     JZ    CHKFIL        ; File name might be less than 8 chars.
  4348.     STAX    D        ; Store
  4349.     INX    D        ; Next position to store the character
  4350.     INR    C        ; One less to go
  4351.     MOV    A,C
  4352.     CPI    12+1
  4353.     JNC    NONAME        ; 11 chars. maximum filename plus extent
  4354. ;
  4355. MOVEN2:    INX    H        ; Next char. in file name
  4356.     DCR    B
  4357.     JZ    OPTERR        ; End of name, see if done yet
  4358.     JMP    MOVEN1
  4359. ;
  4360. ; See if any spaces needed between file name and .ext
  4361. ;
  4362. CHKFIL:    CALL    FILLSP        ; Fill with spaces
  4363.     JMP    MOVEN2
  4364. ;
  4365. FILLSP:    MOV    A,C
  4366.     CPI    9
  4367.     RNC            ; Up to 1st character in .ext now
  4368.     MVI    A,' '        ; Be sure there is a blank there now
  4369.     STAX    D
  4370.     INR    C
  4371.     INX    D
  4372.     JMP    FILLSP        ; Go do another
  4373. ;
  4374. CTYPE:    PUSH    B        ; Save all registers
  4375.     PUSH    D
  4376.     PUSH    H
  4377.     MOV    E,A        ; Character to 'E' in case BDOS (normal)
  4378.     LDA    CONONL        ; Want to bypass 'BYE' output to modem?
  4379.     ORA    A
  4380.     JNZ    CTYPEL        ; Yes, go directly to CRT, then
  4381.     MVI    C,WRCON        ; BDOS console output, to CRT and modem
  4382.     CALL    BDOS        ; Since 'BYE' intercepts the char.
  4383.     POP    H        ; Restore all registers
  4384.     POP    D
  4385.     POP    B
  4386.     RET
  4387. ;
  4388. CTYPEL:    MOV    C,E        ; BIOS needs it in 'C'
  4389.     CALL    CONOUT        ; BIOS console output routine, not BDOS
  4390.     POP    H        ; Restore all registers saved by 'CTYPE'
  4391.     POP    D
  4392.     POP    B
  4393.     RET
  4394. ;
  4395. HEXO:    PUSH    PSW        ; Save for right digit
  4396.     RAR            ; Right justify the left digit
  4397.     RAR
  4398.     RAR
  4399.     RAR
  4400.     CALL    NIBBL        ; Print left digit
  4401.     POP    PSW        ; Restore right
  4402. ;
  4403. NIBBL:    ANI    0FH        ; Isolate digit
  4404.     ADI    90H
  4405.     DAA
  4406.     ACI    40H
  4407.     DAA
  4408.     JMP    CTYPE        ; Type it
  4409. ;
  4410. ; Inline print of message, terminates with a 0
  4411. ;
  4412. ILPRT:    XTHL            ; Save HL, get HL=message
  4413. ;
  4414. ILPLP:    MOV    A,M        ; Get the character
  4415.     INX    H        ; To next character
  4416.     ORA    A        ; End of message?
  4417.     JZ    ILPRET        ; Yes, return
  4418.     CALL    CTYPE        ; Type the message
  4419.     JMP    ILPLP        ; Loop
  4420. ;
  4421. ILPRET:    XTHL            ; Restore HL
  4422.     RET            ; Past message
  4423. ;
  4424. ; Exit printing message following call
  4425. ;
  4426. ERXIT:    CALL    ILPRT
  4427.     DB    CR,LF,0
  4428.     XRA    A
  4429.     STA    OPTSAV        ; Reset option to zero for TELL
  4430. ;
  4431. ERXIT1:    MVI    C,DIRCON    ; Use BDOS Direct
  4432.     MVI    E,0FFH        ; Console input function
  4433.     CALL    BDOS        ; To check for abort
  4434.     CPI    'C'-40H        ; CTL-C
  4435.     JZ    ERXITX        ; Abort msg
  4436.     CPI    'K'-40H        ; CTL-K
  4437.     JZ    ERXITX        ; Abort msg
  4438.     POP    H        ; Get address of next char
  4439.     MOV    A,M        ; Get char
  4440.     INX    H        ; Increment to next char
  4441.     PUSH    H        ; Save address
  4442.     CPI    '$'        ; End of message?
  4443.     JZ    EXITXL        ; If '$' is end of message
  4444.     CALL    CTYPE        ; Else print char on console
  4445.     JMP    ERXIT1        ; And repeat until abort/end
  4446. ;
  4447. EXITXL:    CALL    ILPRT
  4448.     DB    CR,LF,0
  4449. ;
  4450. ERXITX:    POP    H        ; Restore stack
  4451.     JMP    EXIT        ; Get out of here
  4452. ;
  4453. ; Restore the old user area and drive from a received file
  4454. ;
  4455. RECAREA:CALL    RECDRV        ; Ok set the drive to its place
  4456.     LDA    PRVTFL        ; Private area wanted?
  4457.     ORA    A
  4458.     LDA    XPRUSR        ; Yes, set to private area
  4459.     JNZ    RECARE
  4460.     LDA    XUSR        ; Ok now set the user area
  4461. ;
  4462. RECARE:    MOV    E,A        ; Stuff it in E
  4463.     MVI    C,SETUSR    ; Tell BDOS what we want to do
  4464.     CALL    BDOS        ; Now do it
  4465.     RET
  4466. ;
  4467. RECDRV:    LDA    PRVTFL
  4468.     ORA    A
  4469.     LDA    XPRDRV        ; Get private upload drive
  4470.     JNZ    RECDR1
  4471.     LDA    XDRV        ; Or forced upload drive
  4472. ;
  4473. RECDR1:    SUI    'A'        ; Adjust it
  4474. ;
  4475. RECDRX:    MOV    E,A        ; Stuff it in E
  4476.     MVI    C,SELDSK    ; Tell BDOS
  4477.     CALL    BDOS
  4478.     RET
  4479. ;
  4480. MOVE:    MOV    A,M        ; Get a character
  4481.     STAX    D        ; Store it
  4482.     INX    H        ; To next 'from'
  4483.     INX    D        ; To next 'to'
  4484.     DCR    B        ; More?
  4485.     JNZ    MOVE        ; Yes, loop
  4486.     RET
  4487. ;
  4488. ;-----------------------------------------------------------------------
  4489. ;
  4490. ;            CRC SUBROUTINES
  4491. ;
  4492. ;-----------------------------------------------------------------------
  4493. ;
  4494. CHKCRC:    PUSH    H        ; Check 'CRC' bytes of received message
  4495.     LHLD    CRCVAL
  4496.     MOV    A,H
  4497.     ORA    L
  4498.     POP    H
  4499.     RZ
  4500.     MVI    A,0FFH
  4501.     RET
  4502. ;
  4503. CLRCRC:    PUSH    H        ; Reset 'CRC' store for a new message
  4504.     LXI    H,0
  4505.     SHLD    CRCVAL
  4506.     POP    H
  4507.     RET
  4508. ;
  4509. FINCRC:    PUSH    PSW        ; Finish 'CRC' calculation
  4510.     XRA    A
  4511.     CALL    UPDCRC
  4512.     CALL    UPDCRC
  4513.     PUSH    H
  4514.     LHLD    CRCVAL
  4515.     MOV    D,H
  4516.     MOV    E,L
  4517.     POP    H
  4518.     POP    PSW
  4519.     RET
  4520. ;
  4521. UPDCRC:    PUSH    PSW        ; Update 'CRC' store  with byte in 'A'
  4522.     PUSH    B
  4523.     PUSH    H
  4524.     MVI    B,8
  4525.     MOV    C,A
  4526.     LHLD    CRCVAL
  4527. ;
  4528. UPDLOOP:MOV    A,C
  4529.     RLC
  4530.     MOV    C,A
  4531.     MOV    A,L
  4532.     RAL
  4533.     MOV    L,A
  4534.     MOV    A,H
  4535.     RAL
  4536.     MOV    H,A
  4537.     JNC    SKIPIT
  4538.     MOV    A,H        ; The generator is x^16 + x^12 + x^5 + 1
  4539.     XRI    10H
  4540.     MOV    H,A
  4541.     MOV    A,L
  4542.     XRI    21H
  4543.     MOV    L,A
  4544. ;
  4545. SKIPIT:    DCR    B
  4546.     JNZ    UPDLOOP
  4547.     SHLD    CRCVAL
  4548.     POP    H
  4549.     POP    B
  4550.     POP    PSW
  4551.     RET
  4552. ;
  4553. ;               end of CRC routines
  4554. ;-----------------------------------------------------------------------
  4555. ;            start of LOGCAL routines
  4556. ;
  4557. ; The following allocations are used by the LOGCALL routines
  4558. ;
  4559.      IF    LOGCAL
  4560. PGSIZE:    DB    0,0,0        ; Program length in minutes and seconds
  4561. LOGOPT:    DB    '?'        ; Primary option stored here
  4562. DEFAULT$DISK:
  4563.     DB    0        ; Disk for open stored here
  4564. DEFAULT$USER:
  4565.     DB    0        ; User for open stored here
  4566. FCBCALLER:
  4567.     DB    0,'LASTCALR???'    ; Last caller file FCB
  4568.     DB    0,0,0,0,0,0,0,0,0,0,0,0
  4569.     DB    0,0,0,0,0,0,0,0,0,0,0
  4570. CALLERPTR:
  4571.     DW    LOGBUF
  4572. FCBLOG:    DB    0        ; Log file FCB
  4573.      ENDIF
  4574. ;
  4575.      IF    LOGCAL AND NOT (LOGSYS OR KNET)
  4576.     DB    'XMODEM  '
  4577.     DB    'L','O'+80H,'G'    ; (the +80H makes this a $SYS file)
  4578.      ENDIF
  4579. ;
  4580.      IF    LOGCAL AND LOGSYS AND NOT KNET
  4581.     DB    'LOG     '
  4582.     DB    'S','Y'+80H,'S'
  4583.      ENDIF
  4584. ;
  4585.      IF    LOGCAL AND KNET    AND NOT    LOGSYS
  4586.     DB    'XMODEM  '
  4587.     DB    'T','X'+80H,'#'
  4588.      ENDIF
  4589. ;
  4590.      IF    LOGCAL
  4591.     DB    0,0,0,0,0,0,0,0,0,0,0,0
  4592.     DB    0,0,0,0,0,0,0,0,0,0,0,0
  4593. LOGPTR:    DW    DBUF
  4594. LOGCNT:    DB    0
  4595. LOGK:    DB    'k '
  4596.      ENDIF
  4597. ;
  4598.      IF    LOGCAL OR MBFMSG OR MBDESC
  4599. DSKSAV:    DB    0        ; Up/download disk saved here
  4600. USRSAV:    DB    0        ; Up/download user saved here
  4601.      ENDIF
  4602. ;
  4603.      IF    LOGCAL AND (RTC    OR B3RTC OR BYEBDOS)
  4604. YYSAV:    DB    0
  4605. MMSAV:    DB    0
  4606. DDSAV:    DB    0
  4607. MNSAV:    DB    0
  4608.      ENDIF
  4609. ;
  4610. ; Main log file routine, adds record to log file
  4611. ;
  4612.      IF    LOGCAL OR MBDESC OR MBFMSG
  4613. LOGCALL:
  4614.     MVI    C,CURDRV    ; Get current disk
  4615.     CALL    BDOS        ; (where down/upload occurred)
  4616.     STA    DSKSAV        ; And save it...
  4617.     MVI    C,SETUSR    ; Get current user area
  4618.     MVI    E,0FFH        ; (where down/upload occurred)
  4619.     CALL    BDOS
  4620.     STA    USRSAV        ; And save it...
  4621.      ENDIF
  4622. ;
  4623.      IF    (MBDESC    OR MBFMSG) AND (NOT LOGCAL)
  4624.     RET            ; Skip logging if no log
  4625.      ENDIF
  4626. ;
  4627.      IF    LOGCAL
  4628.     XRA    A
  4629.     STA    FCBCALLER+12
  4630.     STA    FCBCALLER+32
  4631.     MVI    A,LASTDRV-'A'
  4632.     STA    DEFAULT$DISK
  4633.     MVI    A,LASTUSR
  4634.     STA    DEFAULT$USER
  4635.     LXI    D,FCBCALLER
  4636.     CALL    OPENF        ; Open LASTCALR file
  4637.     JNZ    LOGC1
  4638.     CALL    ERXIT
  4639.     DB    '++ No last caller file found +++$'
  4640. ;
  4641. LOGC1:    MVI    C,SETRRD    ; Get random record #
  4642.     LXI    D,FCBCALLER    ; (for first record in file)
  4643.     CALL    BDOS
  4644.     LXI    D,DBUF        ; Set DMA to DBUF
  4645.     MVI    C,SETDMA
  4646.     CALL    BDOS
  4647.     LXI    D,FCBCALLER    ; Read first (& only) record
  4648.     MVI    C,RRDM
  4649.     CALL    BDOS
  4650.      ENDIF    ;LOGCAL
  4651. ;
  4652.      IF    LOGCAL AND NOT (MBBS AND (RTC OR B3RTC OR BYEBDOS))
  4653.     LXI    H,DBUF        ; Set pointer to beginning of record
  4654.      ENDIF
  4655. ;
  4656.      IF    LOGCAL AND (MBBS AND (RTC OR B3RTC OR BYEBDOS))
  4657.     LXI    H,DBUF+11    ; Set pointer to skip log on date
  4658.      ENDIF
  4659. ;
  4660.      IF    LOGCAL
  4661.     SHLD    CALLERPTR
  4662.     LXI    D,LOGBUF    ; Set DMA address to LOGBUF
  4663.     MVI    C,SETDMA
  4664.     CALL    BDOS
  4665.     XRA    A
  4666.     STA    FCBLOG+12
  4667.     STA    FCBLOG+32
  4668.     MVI    A,LOGDRV-'A'
  4669.     STA    DEFAULT$DISK
  4670.     MVI    A,LOGUSR
  4671.     STA    DEFAULT$USER
  4672.     LXI    D,FCBLOG
  4673.     CALL    OPENF        ; Open log file
  4674.     JNZ    LOGC4        ; If file exists, skip create
  4675.     LXI    D,FCBLOG
  4676.     MVI    C,MAKE        ; Create a new file if needed
  4677.     CALL    BDOS
  4678.     INR    A
  4679.     JNZ    LOGC2        ; No error, cont.
  4680.     CALL    ERXIT        ; File create error
  4681.     DB    '++ No dir space: log ++$'
  4682. ;
  4683. LOGC2:    MVI    C,SETRRD    ; Set random record #
  4684.     LXI    D,FCBLOG    ; (for first record in file)
  4685.     CALL    BDOS
  4686. ;
  4687. LOGC3:    MVI    A,EOF
  4688.     STA    LOGBUF
  4689.     JMP    LOGC4B
  4690. ;
  4691. LOGC4:    MVI    C,CFSIZE    ; Get file length
  4692.     LXI    D,FCBLOG
  4693.     CALL    BDOS        ; (end+1)
  4694.     LHLD    FCBLOG+33    ; Back up to last record
  4695.     MOV    A,L
  4696.     ORA    H
  4697.     JZ    LOGC3        ; Unless zero length file
  4698.     DCX    H
  4699.     SHLD    FCBLOG+33
  4700.     LXI    D,FCBLOG
  4701.     MVI    C,RRDM        ; And read it
  4702.     CALL    BDOS
  4703. ;
  4704. LOGC4B:    CALL    RSTLP        ; Initialize LOGPTR and LOGCNT
  4705. ;
  4706. LOGC6:    CALL    GETLOG        ; Get characters out of last record
  4707.     CPI    EOF
  4708.     JNZ    LOGC6        ; Until EOF
  4709.     LDA    LOGCNT        ; Then backup one character
  4710.     DCR    A
  4711.     STA    LOGCNT
  4712.     LHLD    LOGPTR
  4713.     DCX    H
  4714.     SHLD    LOGPTR
  4715.     LDA    LOGOPT        ; Get option back and put in file
  4716.     CALL    PUTLOG
  4717.     CALL    SPEED        ; Get speed factor
  4718.     ADI    30H
  4719.     CALL    PUTLOG
  4720.     CALL    PUTSP        ; Blank
  4721.     LDA    PGSIZE        ; Now the program size in minutes..
  4722.     CALL    PNDEC        ; Of transfer time (mins)
  4723.     MVI    A,':'
  4724.     CALL    PUTLOG        ; ':'
  4725.     LDA    PGSIZE+2
  4726.     CALL    PNDEC        ; And secs..
  4727.     CALL    PUTSP        ; Blank
  4728. ;
  4729. ; Log the drive and user area as a prompt
  4730. ;
  4731.     LDA    FCB
  4732.     ORA    A
  4733.     JNZ    WDRV
  4734.     LDA    DSKSAV
  4735.     INR    A
  4736. ;
  4737. WDRV:    ADI    'A'-1
  4738.     CALL    PUTLOG
  4739.     LDA    USRSAV
  4740.     CALL    PNDEC
  4741.     MVI    A,'>'        ; Make it look like a prompt
  4742.     CALL    PUTLOG
  4743.     LDA    OPTSAV
  4744.     CPI    'L'
  4745.     JNZ    WDRV1
  4746.     LXI    H,MEMFCB    ; Name of file in library
  4747.     MVI    B,11
  4748.     CALL    PUTSTR
  4749.     CALL    PUTSP        ; ' '
  4750. ;
  4751. WDRV1:    LXI    H,FCB+1        ; Now the name of the file
  4752.     MVI    B,11
  4753.     CALL    PUTSTR
  4754.     LDA    OPTSAV
  4755.     CPI    'L'
  4756.     JNZ    WDRV2
  4757.     MVI    C,1
  4758.     JMP    SPLOOP
  4759. ;
  4760. WDRV2:    MVI    C,13
  4761. ;
  4762. SPLOOP:    PUSH    B
  4763.     CALL    PUTSP        ; Put ' '
  4764.     POP    B
  4765.     DCR    C
  4766.     JNZ    SPLOOP
  4767.     LHLD    VRECNO        ; Get VIRTUAL record count
  4768.     LXI    D,8        ; Divide record count by 8
  4769.     CALL    DVHLDE        ; To get # of 1024 byte blocks
  4770.     MOV    A,H
  4771.     ORA    L        ; Check if remainder
  4772.     MOV    H,B        ; Get quotient
  4773.     MOV    L,C
  4774.     JZ    EXKB2        ; If 0 remainder, exact kb
  4775.     INX    H        ; Else increment to next kb
  4776. ;
  4777. EXKB2:    CALL    PNDEC3        ; Print to log file (right just xxxk)
  4778.     LXI    H,LOGK        ; 'k '
  4779.     MVI    B,2
  4780.     CALL    PUTSTR
  4781.      ENDIF
  4782. ;
  4783.      IF    LOGCAL AND BYEBDOS
  4784.     MVI    C,BDSTOS    ; Set max time to 0 so BYE won't
  4785.     MVI    E,0        ; hang up when doing BYEBDOS calls
  4786.     CALL    BDOS        ; when getting time/date
  4787.      ENDIF
  4788. ;
  4789.      IF    LOGCAL AND (B3RTC OR RTC OR BYEBDOS)
  4790.     CALL    GETDATE        ; IF RTC, get current date
  4791.     PUSH    B        ; (save DD/YY)
  4792.     CALL    PNDEC        ; Print MM
  4793.     MVI    A,'/'        ; '/'
  4794.     CALL    PUTLOG
  4795.     POP    PSW        ; Get DD/YY
  4796.     PUSH    PSW        ; Save YY
  4797.     CALL    PNDEC        ; Print DD
  4798.     MVI    A,'/'        ; '/'
  4799.     CALL    PUTLOG
  4800.     POP    B        ; Get YY
  4801.     MOV    A,C
  4802.     CALL    PNDEC        ; Print YY
  4803.     CALL    PUTSP        ; ' '
  4804.     CALL    GETTIME        ; IF RTC, get current time
  4805.     STA    MNSAV        ; Save min
  4806.     MOV    A,B        ; Get current hour
  4807.     CALL    PNDEC        ; Print hr to file
  4808.     MVI    A,':'        ; With ':'
  4809.     CALL    PUTLOG        ; Between HH:MM
  4810.     LDA    MNSAV        ; Get min
  4811.     CALL    PNDEC        ; And print min
  4812.     CALL    PUTSP        ; Print a space
  4813.      ENDIF
  4814. ;
  4815.      IF    LOGCAL AND BYEBDOS
  4816.     LDA    MAXTOS        ; Reset time on system
  4817.     MOV    E,A        ; So BYE will hang up
  4818.     MVI    C,BDSTOS    ; If caller is over time limit
  4819.     CALL    BDOS
  4820.      ENDIF
  4821. ;
  4822.      IF    LOGCAL AND OXGATE AND (B3RTC OR    RTC OR BYEBDOS)
  4823.     XRA    A
  4824.     STA    CMMACNT        ; Clear comma count
  4825.      ENDIF
  4826. ;
  4827.      IF    LOGCAL
  4828. CLOOP:    CALL    GETCALLER    ; And the caller
  4829.     CPI    EOF
  4830.     JZ    QUIT
  4831.     CPI    CR        ; Do not print 2nd line of 'LASTCALR'
  4832.     JNZ    CLOP1
  4833.     CALL    PUTLOG
  4834.     MVI    A,LF
  4835.     CALL    PUTLOG        ; And add a LF
  4836.     JMP    QUIT
  4837. ;
  4838. CLOP1:    CPI    ','        ; Do not print the ',' between names
  4839.     JNZ    CLOP2
  4840.      ENDIF    ; LOGCAL
  4841. ;
  4842.      IF    LOGCAL AND OXGATE AND (B3RTC OR    RTC OR BYEBDOS)
  4843.     LDA    CMMACNT        ; Get comma count
  4844.     INR    A
  4845.     STA    CMMACNT
  4846.     CPI    2        ; If reached second comma, do CRLF exit
  4847.     JZ    CLOPX
  4848.      ENDIF
  4849. ;
  4850.      IF    LOGCAL
  4851.     MVI    A,' '        ; Instead send a ' '
  4852. CLOP2:    CALL    PUTLOG
  4853.     JMP    CLOOP
  4854.      ENDIF
  4855. ;
  4856.      IF    LOGCAL AND OXGATE AND (B3RTC OR    RTC OR BYEBDOS)
  4857. CLOPX:    MVI    A,CR        ; Cloop exit... do a CRLF and finish up.
  4858.     CALL    PUTLOG
  4859.     MVI    A,LF
  4860.     CALL    PUTLOG
  4861.      ENDIF
  4862. ;
  4863.      IF    LOGCAL
  4864. QUIT:    MVI    A,EOF        ; Put in EOF
  4865.     CALL    PUTLOG
  4866.     LDA    LOGCNT        ; Check count of chars in buffer
  4867.     CPI    1
  4868.     JNZ    QUIT        ; Fill last buffer & write it
  4869.     LXI    D,FCBCALLER    ; Close lastcaller file
  4870.     MVI    C,CLOSE
  4871.     CALL    BDOS
  4872.     INR    A
  4873.     JZ    QUIT1
  4874.     LHLD    FCBLOG+33    ; Move pointer back to show
  4875.     DCX    H        ; Actual file size
  4876.     SHLD    FCBLOG+33
  4877.     LXI    D,FCBLOG    ; Close log file
  4878.     MVI    C,CLOSE
  4879.     CALL    BDOS
  4880.     INR    A
  4881.     RNZ            ; If OK, return now...
  4882. ;
  4883. QUIT1:    CALL    ERXIT        ; If error, oops
  4884.     DB    '++ Cannot close log ++$'
  4885.      ENDIF    ; LOGCAL
  4886. ;
  4887. ;-----------------------------------------------------------------------
  4888. ;
  4889. ; Support routines for LOGCAL
  4890. ;
  4891. ; Gets a single byte from DBUF
  4892. ;
  4893.      IF    LOGCAL
  4894. GETCALLER:
  4895.     LHLD    CALLERPTR
  4896.     MOV    A,M
  4897.     INX    H
  4898.     SHLD    CALLERPTR
  4899.     RET
  4900. ;
  4901. ; Gets a single byte from log file
  4902. ;
  4903. GETLOG:    LDA    LOGCNT
  4904.     INR    A
  4905.     STA    LOGCNT
  4906.     CPI    129
  4907.     JZ    EOLF
  4908.     LHLD    LOGPTR
  4909.     MOV    A,M
  4910.     INX    H
  4911.     SHLD    LOGPTR
  4912.     RET
  4913. ;
  4914. EOLF:    LHLD    FCBLOG+33
  4915.     INX    H
  4916.     SHLD    FCBLOG+33
  4917.     LXI    H,LOGBUF+1
  4918.     SHLD    LOGPTR
  4919.     MVI    A,1
  4920.     STA    LOGCNT
  4921.     MVI    A,EOF
  4922.     RET
  4923. ;
  4924. ; Open file with FCB pointed to by DE (disk/user passed in DEFAULT$DISK
  4925. ; and DEFAULT$USER)
  4926. ;
  4927. OPENF:    PUSH    D        ; Save FCB address
  4928.     LDA    DEFAULT$DISK    ; Get disk for file
  4929.     CALL    RECDRX        ; Log into it
  4930.     LDA    DEFAULT$USER    ; Get default user
  4931.     CALL    RECARE        ; Log into it
  4932.     POP    D        ; Get FCB address
  4933.     MVI    C,OPEN        ; Open file
  4934.     CALL    BDOS
  4935.     CPI    255        ; Not present?
  4936.     RET            ; Return to caller
  4937. ;
  4938. ; Write character to log file
  4939. ;
  4940. PUTLOG:    LHLD    LOGPTR        ; Get pointer
  4941.     ANI    7FH        ; Mask off any high bits
  4942.     MOV    M,A        ; Put data
  4943.     INX    H        ; Increment pointer
  4944.     SHLD    LOGPTR        ; Update pointer
  4945.     MOV    B,A        ; Save character in B
  4946.     LDA    LOGCNT        ; Get count
  4947.     INR    A        ; Increment it
  4948.     STA    LOGCNT        ; Update count
  4949.     CPI    129        ; Check it
  4950.     RNZ            ; If not EOB, return
  4951.     PUSH    B        ; Save character
  4952.     LXI    D,FCBLOG    ; Else, write this sector
  4953.     MVI    C,WRDM
  4954.     CALL    BDOS
  4955.     ORA    A
  4956.     JZ    ADVRCP        ; If ok, cont.
  4957.     CALL    ERXIT
  4958.     DB    '++ Disk full - cannot add to log ++$'
  4959. ;
  4960. ADVRCP:    LHLD    FCBLOG+33    ; Advance record number
  4961.     INX    H
  4962.     SHLD    FCBLOG+33
  4963.     CALL    RSTLP        ; Reset buffer pointers
  4964.     POP    PSW        ; Get saved character
  4965.     JMP    PUTLOG        ; Put it in buffer and return
  4966. ;
  4967. RSTLP:    LXI    H,LOGBUF    ; Reset pointers
  4968.     SHLD    LOGPTR        ; And return
  4969.     MVI    A,0
  4970.     STA    LOGCNT
  4971.     RET
  4972. ;
  4973. ; Print number in decimal format (into log file)
  4974. ;    IN:  HL=binary number
  4975. ;    OUT: nnn=right justified with spaces
  4976. ;
  4977. PNDEC3:    MOV    A,H        ; Check high byte
  4978.     ORA    A
  4979.     JNZ    DECOT        ; If on, is at least 3 digits
  4980.     MOV    A,L        ; Else, check low byte
  4981.     CPI    100
  4982.     JNC    TEN
  4983.     CALL    PUTSP
  4984. ;
  4985. TEN:    CPI    10
  4986.     JNC    DECOT
  4987.     CALL    PUTSP
  4988.     JMP    DECOT
  4989. ;
  4990. ; Puts a single space in log file, saves PSW/HL
  4991. ;
  4992. PUTSP:    PUSH    PSW
  4993.     PUSH    H
  4994.     MVI    A,' '
  4995.     CALL    PUTLOG
  4996.     POP    H
  4997.     POP    PSW
  4998.     RET
  4999. ;
  5000. ; Print number in decimal format (into log file)
  5001. ;
  5002. PNDEC:    CPI    10        ; Two column decimal format routine
  5003.     JC    ONE        ; One or two digits to area number?
  5004.     JMP    TWO
  5005. ;
  5006. ONE:    PUSH    PSW
  5007.     MVI    A,'0'
  5008.     CALL    PUTLOG
  5009.     POP    PSW
  5010. ;
  5011. TWO:    MVI    H,0
  5012.     MOV    L,A
  5013. ;
  5014. DECOT:    PUSH    B
  5015.     PUSH    D
  5016.     PUSH    H
  5017.     LXI    B,-10
  5018.     LXI    D,-1
  5019. ;
  5020. DECOT2:    DAD    B
  5021.     INX    D
  5022.     JC    DECOT2
  5023.     LXI    B,10
  5024.     DAD    B
  5025.     XCHG
  5026.     MOV    A,H
  5027.     ORA    L
  5028.     CNZ    DECOT
  5029.     MOV    A,E
  5030.     ADI    '0'
  5031.     CALL    PUTLOG
  5032.     POP    H
  5033.     POP    D
  5034.     POP    B
  5035.     RET
  5036. ;
  5037. ; Put string to log file
  5038. ;
  5039. PUTSTR:    MOV    A,M
  5040.     PUSH    H
  5041.     PUSH    B
  5042.     CALL    PUTLOG
  5043.     POP    B
  5044.     POP    H
  5045.     INX    H
  5046.     DCR    B
  5047.     JNZ    PUTSTR
  5048.     RET
  5049.      ENDIF    ; LOGCAL
  5050. ;
  5051. ;              end of LOGCAL routine
  5052. ;-----------------------------------------------------------------------
  5053. ;             start of TIMEON routine
  5054. ;
  5055. ; Calculate time on system and inform user.  Log him off if =>MAXMIN
  5056. ; unless STATUS is non-zero.
  5057. ;
  5058.      IF    TIMEON
  5059. TIME:    PUSH    B        ; Save BC pair
  5060.     CALL    GETTIME        ; Get time from system's RTC
  5061.     STA    CMTEMP        ; Save in current-hour-temp
  5062.     MOV    A,B        ; Get current hour
  5063.     POP    B        ; Restore BC
  5064.      ENDIF
  5065. ;
  5066.      IF    TIMEON AND BYEBDOS
  5067.     PUSH    PSW        ; save the current hour <== BUG FIX
  5068.     PUSH    B        ; Lhour was safely moved to highmem
  5069.     PUSH    D        ; in newer versions of BYE
  5070.     MVI    C,BDGRTC
  5071.     CALL    BDOS
  5072.     LXI    D,11        ; Get address of LHOUR
  5073.     DAD    D
  5074.     POP    D
  5075.     POP    B
  5076.     POP    PSW        ; Restore current hour...BDOS killed it
  5077.      ENDIF
  5078. ;
  5079.      IF    TIMEON AND NOT BYEBDOS
  5080.     LXI    H,LHOUR        ; Point to log-on hour (in low memory)
  5081.      ENDIF
  5082. ;
  5083.      IF    TIMEON
  5084.     CMP    M        ; Equal?
  5085.     INX    H        ; Point to logon minutes
  5086.     JNZ    TIME1        ; No
  5087.     MOV    D,M
  5088.     LDA    CMTEMP        ; Current minutes
  5089.     SUB    D
  5090.     STA    TON        ; Store total time on
  5091.     JMP    TIME2
  5092. ;
  5093. TIME1:    MOV    D,M        ; Get logon minutes
  5094.     MVI    A,03CH        ; 60 min into A
  5095.     SUB    D
  5096.     LXI    H,CMTEMP    ; Point at current min
  5097.     ADD    M        ; Add current minutes
  5098.     STA    TON
  5099.      ENDIF
  5100. ;
  5101. TIME2:     IF    ZCPR2 AND TIMEON
  5102.     LDA    WHEEL        ; Check wheel status if ZCPR
  5103.     ORA    A        ; Is it zero
  5104.     JNZ    TIME3        ; If not then this is a special user
  5105.      ENDIF
  5106. ;
  5107.      IF    TIMEON
  5108.     LDA    MAXTOS
  5109.     ORA    A        ; If maxtos is zero, guy is superuser
  5110.     JZ    TIME3
  5111.      ENDIF
  5112. ;
  5113.      IF    TIMEON AND NOT BYEBDOS ; BYEBDOS doesn't use status byte
  5114.     ORA    A        ; Special user?
  5115.     JNZ    TIME3        ; Yes, skip log off check
  5116.     LDA    TON
  5117.     SUI    MAXMIN        ; Subtract max time allowed
  5118.      ENDIF
  5119. ;
  5120.      IF    TIMEON AND BYEBDOS
  5121.     LDA    MAXTOS
  5122.     MOV    B,A
  5123.     LDA    TON
  5124.     SUB    B
  5125.      ENDIF
  5126. ;
  5127.      IF    TIMEON
  5128.     JC    TIME3        ; Still time left
  5129.     CALL    TIMEUP        ; Time is up, inform user
  5130.     MVI    A,0CDH        ; Alter jump vector
  5131.     STA    0        ; At zero
  5132.     JMP    0000H        ; And log him off
  5133. ;
  5134. TIME3:    LXI    H,MSG1+015H    ; Point at message insert bytes
  5135.     LDA    TON        ; Convert to ASCII
  5136.     MVI    B,0FFH
  5137. ;
  5138. TIME4:    INR    B
  5139.     SUI    0AH        ; Subtract 10
  5140.     JNC    TIME4        ; Until done
  5141.     ADI    0AH
  5142.     ORI    '0'        ; Make ASCII
  5143.     MOV    M,A
  5144.     DCX    H
  5145.     MVI    A,'0'
  5146.     ADD    B
  5147.     MOV    M,A
  5148.     CALL    ILPRT
  5149. ;
  5150. MSG1:    DB    CR,LF,'Time on system is 00 minutes',CR,LF,0
  5151.      ENDIF
  5152. ;
  5153.      IF    TIMEON AND NOT BYEBDOS
  5154.     LDA    STATUS        ; Check user status
  5155.     ORA    A        ; Special user?
  5156.     JNZ    TIME5        ; Yes, reset TON
  5157.      ENDIF
  5158. ;
  5159.      IF    TIMEON
  5160.     RET
  5161.      ENDIF
  5162. ;
  5163.      IF    TIMEON AND NOT BYEBDOS
  5164. TIME5:    MVI    A,0        ; Reset timeout for good guys
  5165.     STA    TON
  5166.     RET
  5167.      ENDIF
  5168. ;
  5169.      IF    TIMEON
  5170. TIMEUP:    CALL    ILPRT
  5171.     DB    CR,LF,CR,LF
  5172.     DB    'Your time is up - wait 24 hours to call back',CR,LF,0
  5173.     RET
  5174. ;
  5175. TON:    DB    0        ; Storage for time on system
  5176. CMTEMP:    DB    0        ; Storage for current minute value
  5177.      ENDIF
  5178. ;
  5179. ; Get caller's time on system from BYE3 or MBYE and display on console.
  5180. ;
  5181.      IF    B3RTC AND B3TOS
  5182. TIME:    CALL    ILPRT
  5183.     DB    CR,LF,'Time on system is ',0
  5184.     CALL    GETTOS        ; Get Time On System from MBYE's RTC
  5185.     CALL    DECOUT        ; Print it on the screen
  5186.     CALL    ILPRT
  5187.     DB    ' minutes',CR,LF,0
  5188.     RET
  5189.      ENDIF
  5190. ;
  5191. ; Get caller's time on system (returned in HL).
  5192. ;
  5193.     IF    B3RTC AND (NOT BYEBDOS)
  5194. GETTOS:    LHLD    RTCBUF        ; Get RTCBUF addr
  5195.     MOV    A,H
  5196.     ORA    L
  5197.     RZ            ; If 0000H, BYE not running so TOS=0
  5198.     MOV    A,M        ; If hours = 99
  5199.     CPI    099H
  5200.     LXI    H,0
  5201.     RZ            ; Return with TOS=0
  5202.     LHLD    RTCBUF
  5203.     LXI    D,B3CMOS    ; Get offset to TOS word
  5204.     DAD    D        ; (addr in HL)
  5205.     MOV    E,M        ; Get minutes on system
  5206.     INX    H
  5207.     MOV    D,M        ; Stuff into DE
  5208.     XCHG            ; Swap into HL
  5209.     RET
  5210.     ENDIF
  5211. ;
  5212.      IF    BYEBDOS    OR MXTOS
  5213. MAXTOS:    DB    0        ; Maximum time on system
  5214.      ENDIF
  5215. ;
  5216. ;              end of TIMEON routine
  5217. ;-----------------------------------------------------------------------
  5218. ;
  5219. GETDATE: IF    (RTC AND LOGCAL) AND NOT (CPM3 OR BYEBDOS)
  5220.     LDA    45H        ; Get the binary day number
  5221.     MOV    B,A        ; Set to return binary day # B reg.
  5222.     LDA    46H        ; Get the binary year number
  5223.     MOV    C,A        ; Set to return binary year # in C reg.
  5224.     LDA    44H        ; Get the binary month number
  5225.     RET
  5226.      ENDIF
  5227. ;
  5228. ;-----------------------------------------------------------------------
  5229. ;           start of CPM+ date routine
  5230.  
  5231.      IF    RTC AND    LOGCAL AND CPM3
  5232.     MVI    C,GETTIM    ; BDOS function to get date and time
  5233.     LXI    D,TIMEPB    ; Get address of 4-byte data structure
  5234.     CALL    BDOS        ; Transfer the current date/time
  5235.     LHLD    TIMEPB
  5236.     MVI    B,78        ; Set years counter
  5237. ;
  5238. LOOP:    CALL    CKLEAP
  5239.     LXI    D,-365        ; Set up for subtract
  5240.     JNZ    NOLPY        ; Skip if no leap year
  5241.     DCX    D        ; Set for leap year
  5242. ;
  5243. NOLPY:    DAD    D        ; Subtract
  5244.     JNC    YDONE        ; Continue if years done
  5245.     MOV    A,H
  5246.     ORA    L
  5247.     JZ    YDONE
  5248.     SHLD    TIMEPB        ; Else save days count
  5249.     INR    B        ; Increment years count
  5250.     JMP    LOOP        ; And do again
  5251. ;
  5252. ; The years are now finished, the years count is in 'B' and TIMEPB holds
  5253. ; the days (HL is invalid)
  5254. ;
  5255. YDONE:    MOV    A,B
  5256.     STA    YEAR
  5257.     CALL    CKLEAP        ; Check if leap year
  5258.     MVI    A,-28
  5259.     JNZ    FEBNO        ; February not 29 days
  5260.     MVI    A,-29        ; Leap year
  5261. ;
  5262. FEBNO:    STA    FEB        ; Set february
  5263.     LHLD    TIMEPB        ; Get days count
  5264.     LXI    D,MTABLE    ; Point to months table
  5265.     MVI    B,0FFH        ; Set up 'B' for subtract
  5266.     MVI    A,0        ; Set a for # of months
  5267. ;
  5268. MLOOP:    PUSH    PSW
  5269.     LDAX    D        ; Get month
  5270.     MOV    C,A        ; Put in 'C' for subtract
  5271.     POP    PSW
  5272.     SHLD    TIMEPB        ; Save days count
  5273.     DAD    B        ; Subtract
  5274.     INX    D        ; Increment months counter
  5275.     INR    A
  5276.     JC    MLOOP        ; Loop for next month
  5277. ;
  5278. ; The months are finished, days count is on stack.  First, calculate
  5279. ; the month.
  5280. ;
  5281. MDONE:    MOV    B,A        ; Save months
  5282.     LHLD    TIMEPB
  5283.     MOV    A,H
  5284.     ORA    L
  5285.     JNZ    NZD
  5286.     DCX    D
  5287.     DCX    D
  5288.     LDAX    D
  5289.     CMA
  5290.     INR    A
  5291.     MOV    L,A
  5292.     DCR    B
  5293. ;
  5294. NZD:    MOV    A,B
  5295.     STA    MONTH
  5296.     MOV    A,L
  5297.     STA    DAY
  5298.     LDA    YEAR
  5299.     MOV    C,A
  5300.     LDA    DAY
  5301.     MOV    B,A
  5302.     LDA    MONTH
  5303.     RET
  5304. ;
  5305. ; This routine checks for leap years.
  5306. ;
  5307. CKLEAP:    MOV    A,B
  5308.     ANI    0FCH
  5309.     CMP    B
  5310.     RET
  5311. ;
  5312. ; This is the month's table
  5313. ;
  5314. MTABLE:    DB    -31        ; January
  5315. FEB:    DB    -28        ; February
  5316.     DB    -31,-30,-31,-30    ; Mar-Jun
  5317.     DB    -31,-31,-30    ; Jul-Sep
  5318.     DB    -31,-30,-31    ; Oct-Dec
  5319. ;
  5320. YEAR:    DB    0
  5321. MONTH:    DB    0
  5322. DAY:    DB    0
  5323.      ENDIF    ; RTC AND LOGCAL AND CPM3
  5324. ;
  5325. ;            end of CPM+ date routine
  5326. ;-----------------------------------------------------------------------
  5327. ;
  5328.      IF    LOGCAL AND B3RTC AND NOT BYEBDOS
  5329.     CALL    BYECHK        ; See if BYE is running
  5330.     JZ    GETBDAT        ; If so, get date from buffer & convert
  5331.     MVI    A,0        ; Else, return 00/00/00
  5332.     MOV    B,A
  5333.     MOV    C,A
  5334.     RET
  5335.      ENDIF
  5336. ;
  5337.      IF    LOGCAL AND B3RTC AND (NOT BYEBDOS)
  5338. GETBDAT:LHLD    RTCBUF        ; Get RTC buffer in HL
  5339.      ENDIF
  5340. ;
  5341.      IF    LOGCAL AND BYEBDOS AND (NOT B3RTC)
  5342.     MVI    C,BDGRTC    ; Get RTC buffer in HL
  5343.     CALL    BDOS
  5344.      ENDIF
  5345. ;
  5346.      IF    LOGCAL AND (BYEBDOS OR B3RTC)
  5347.     LXI    D,4        ; Offset to YY
  5348.     DAD    D        ; HL=YY Address
  5349.     MOV    A,M        ; Get YY
  5350.     CALL    BCDBIN        ; Make it binary
  5351.     STA    YYSAV        ; Save YY
  5352.     INX    H        ; Point to MM
  5353.     MOV    A,M        ; Get MM
  5354.     CALL    BCDBIN        ; Convert BCD to binary
  5355.     STA    MMSAV        ; Save it
  5356.     INX    H        ; Point to DD
  5357.     MOV    A,M        ; Get DAY
  5358.     CALL    BCDBIN        ; Convert it to binary
  5359.     MOV    B,A        ; Stuff DD in B
  5360.     LDA    YYSAV        ; Get YY
  5361.     MOV    C,A        ; Put YY in C
  5362.     LDA    MMSAV        ; Get MM in A
  5363.     RET            ; And return
  5364.      ENDIF
  5365. ;
  5366. ;
  5367. ; The routine here should read your real-time clock and return with the
  5368. ; following information:
  5369. ;
  5370. ; register: A - current minute (0-59)
  5371. ;        B - current hour   (0-23)
  5372. ;
  5373. GETTIME: IF    (TIMEON    OR RTC)    AND NOT    (B3RTC OR CPM3 OR BYEBDOS)
  5374. ;
  5375. ;; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  5376. ;;         (this example is for the Serria SBC-100)
  5377. ;;
  5378. ;;SBCHR EQU    040H        ; Low memory area where stored
  5379. ;;SBCMN EQU    041H
  5380. ;;
  5381. ;;    LDA    SBCHR        ; Get hour from BIOS memory-clock
  5382. ;;    MOV    B,A
  5383. ;;    LDA    SBCMN        ; Get minute from BIOS memory-clock
  5384. ;; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  5385. ;
  5386. ;; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  5387. ;;    (this example is for Don Brown's computer)
  5388. ;;
  5389. ;;    LDA    43h        ; Get the current binary hour number
  5390. ;;    MOV    B,A        ; Set to return binary hour number in Reg. B
  5391. ;;    LDA    42h        ; Get the current binary minute number
  5392. ;; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  5393. ;
  5394.     RET
  5395.      ENDIF
  5396. ;
  5397. ; The following code is for CP/M Plus
  5398. ;
  5399.      IF    (TIMEON    OR RTC)    AND CPM3
  5400.     MVI    C,GETTIM    ; BDOS function to get date and time
  5401.     LXI    D,TIMEPB    ; Get address of 4-byte data structure
  5402.     CALL    BDOS        ; Transfer the current date/time
  5403.     LDA    TIMEPB+2    ; Get current hour
  5404.     CALL    BCDBIN        ; Convert BCD hour to binary
  5405.     MOV    B,A        ; Position hour for return
  5406.     PUSH    B        ; Save the binary hour
  5407.     LDA    TIMEPB+3    ; Get current minute
  5408.     CALL    BCDBIN        ; Convert BCD minute to binary
  5409.     POP    B        ; Restore the binary hour
  5410.     RET
  5411.      ENDIF
  5412. ;
  5413.      IF    LOGCAL AND B3RTC AND (NOT BYEBDOS)
  5414.     CALL    BYECHK        ; See if BYE is running
  5415.     JZ    GETBTIM        ; If so, get time from buffer & convert
  5416.     MVI    A,0        ; Else, return 00:00
  5417.     MOV    B,A
  5418.     RET
  5419. ;
  5420. GETBTIM:LHLD    RTCBUF        ; Get RTC buffer address
  5421.      ENDIF
  5422. ;
  5423.      IF    LOGCAL AND BYEBDOS AND (NOT B3RTC)
  5424.     MVI    C,BDGRTC    ; Get RTC buffer address
  5425.     CALL    BDOS
  5426.      ENDIF
  5427. ;
  5428.      IF    LOGCAL AND (B3RTC OR BYEBDOS)
  5429.     MOV    A,M        ; Get hours on system
  5430.     CALL    BCDBIN        ; Convert BCD value to binary
  5431.     PUSH    PSW        ; Save hr on stack
  5432.     INX    H        ; Point to minute
  5433.     MOV    A,M        ; Get min
  5434.     CALL    BCDBIN        ; Convert BCD to binary
  5435.     POP    B        ; Get hr in B (min in A)
  5436.     RET            ; And return
  5437.      ENDIF
  5438. ;
  5439. ; Convert BCD value in A to binary in A
  5440. ;
  5441.      IF    LOGCAL AND (B3RTC OR CPM3 OR BYEBDOS)
  5442. BCDBIN:    PUSH    PSW        ; Save A
  5443.     ANI    0F0H        ; Mask high nibble
  5444.     RRC            ; Move to low nibble
  5445.     RRC
  5446.     RRC
  5447.     RRC
  5448.     MOV    C,A        ; And stuff in C (C=A)
  5449.     MVI    B,9        ; X10 (*9)
  5450. ;
  5451. BCDBL:    ADD    C        ; Add orig value to A
  5452.     DCR    B        ; Decrement B
  5453.     JNZ    BCDBL        ; Loop nine times (A+(C*9)=A*10)
  5454.     MOV    B,A        ; Save result in B
  5455.     POP    PSW        ; Get original value
  5456.     ANI    0FH        ; Mask low nibble
  5457.     ADD    B        ; +B gives binary value of BCD digit A
  5458.     RET            ; Return
  5459.      ENDIF
  5460. ;
  5461. ; Check to see that HL register is at least 8 records.    If it not, make
  5462. ; sure 1K blocks are turned off
  5463. ;
  5464. CKKSIZ:    MOV    A,H        ; Get high order byte
  5465.     ORA    A        ; Something there?
  5466.     RNZ            ; Yes, certainly more than 8
  5467.     MOV    A,L        ; Get low order byte
  5468.     CPI    8        ; Looking for at least this many records
  5469.     RNC            ; Not Carry means 8 or more records
  5470.     XRA    A        ; Get nothing
  5471.     STA    KFLAG        ; Turn off 1K blocks
  5472.     RET
  5473. ;
  5474. ;-----------------------------------------------------------------------
  5475. ;
  5476. ;            BYEBDOS access routines
  5477. ;
  5478. ;-----------------------------------------------------------------------
  5479. ;
  5480.      IF    BYEBDOS
  5481. CONOUT:    MOV    E,C        ; Get character into E
  5482.     MVI    C,BDCONO    ; Console output (local only)
  5483.     JMP    BDOS        ; Go to it...
  5484. ;
  5485. MINIT:
  5486. UNINIT:    RET            ; Modem's already initialized
  5487. ;
  5488. SENDR:    POP    PSW        ; Needed by specifications
  5489.     PUSH    B
  5490.     PUSH    D
  5491.     PUSH    H
  5492.     MOV    E,A        ; Put character in E
  5493.     MVI    C,BDMOUT
  5494.     CALL    BDOS
  5495.     POP    H
  5496.     POP    D
  5497.     POP    B
  5498.     RET
  5499. ;
  5500. GETCHR:
  5501. MDIN:    PUSH    B
  5502.     PUSH    D
  5503.     PUSH    H
  5504.     MVI    C,BDMINP
  5505.     CALL    BDOS
  5506.     POP    H
  5507.     POP    D
  5508.     POP    B
  5509.     RET
  5510. ;
  5511. ; The following 3 routines operate in differently than BYE does, so we
  5512. ; must make things "backwards"
  5513. ;
  5514. CAROK:    PUSH    B
  5515.     PUSH    D
  5516.     PUSH    H
  5517.     MVI    C,BDCSTA
  5518.     CALL    BDOS
  5519.     JMP    BKWDS
  5520. ;
  5521. RCVRDY:    PUSH    B
  5522.     PUSH    D
  5523.     PUSH    H
  5524.     MVI    C,BDMIST
  5525.     CALL    BDOS
  5526.     JMP    BKWDS
  5527. ;
  5528. SNDRDY:    PUSH    B
  5529.     PUSH    D
  5530.     PUSH    H
  5531.     MVI    C,BDMOST
  5532.     CALL    BDOS
  5533. ;
  5534. ; Flip around bytes, if A>0 then make A zero & set flags
  5535. ;             if A=0 then make A =255 & set flags
  5536. BKWDS:    ORA    A
  5537.     MVI    A,255
  5538.     JZ    NOSIG
  5539.     XRA    A
  5540. ;
  5541. NOSIG:    ORA    A
  5542.     POP    H
  5543.     POP    D
  5544.     POP    B
  5545.     RET
  5546. ;
  5547. SPEED:    LDA    MSPEED
  5548.     RET
  5549.      ENDIF
  5550. ;
  5551. ;-----------------------------------------------------------------------
  5552. ;
  5553. ;             Temporary storage area
  5554. ;
  5555. ;-----------------------------------------------------------------------
  5556. ;
  5557.      IF    DESCRIB
  5558. FILE:    DB    0,'WHATSFORTXT',0,0,0,0,0,0,0
  5559.     DB    0,0,0,0,0,0,0,0,0,0,0,0,0,0
  5560. DEST:    DB    0,'        $$$',0,0,0,0,0,0,0
  5561.     DB    0,0,0,0,0,0,0,0,0,0,0,0,0,0
  5562.      ENDIF
  5563. ;
  5564. ; Put this ram stuff in the RAM section at the end
  5565. ;
  5566. LZFLG:    DB    0        ; For the free space printer
  5567. BLKSHF:    DB    0
  5568. BLKMAX:    DB    0,0
  5569. ;
  5570.      IF    B3RTC AND NOT BYEBDOS    ; If BYE3/MBYE real-time clock
  5571. RTCBUF:    DW    0        ; Address of RTCBUF saved here
  5572.      ENDIF
  5573. ;
  5574.      IF    B3RTC AND NOT (MBMXT OR    BYEBDOS)
  5575. TOSSAV:    DW    0
  5576.      ENDIF
  5577. ;
  5578.      IF    LOGCAL AND OXGATE AND (B3RTC OR    RTC OR BYEBDOS)
  5579. CMMACNT:DB    0        ; Comma counter
  5580.      ENDIF
  5581. ;
  5582.      IF    TIMEON AND CPM3
  5583. TIMEPB:    DS    4        ; Storage for the system date/time
  5584.      ENDIF
  5585. ;
  5586. MINUTE:    DW    0        ; Transfer time in mins for MAXTIM
  5587. MEMFCB:    DB    '                ' ; Library name (16 bytes required)
  5588. ANYET:    DB    0        ; Any description typed yet?
  5589. BLKSIZ:    DW    0        ; Number of bytes, 128 or 1024
  5590. CONONL:    DB    0        ; CTYPE console-only flag
  5591. CRCFLG:    DB    0        ; Sets to 'C' if checksum requested
  5592. CRCVAL:    DW    0        ; Current CRC value
  5593. DIRSZ:    DW    0        ; Directory size
  5594. DRUSER:    DB    0        ; Original drive/user, for return
  5595. DUD:    DB    0        ; Specified disk
  5596. DUSAVE:    DB    0,0,0,0        ; Buffer for drive/user
  5597. DUU:    DB    0        ; Specified user
  5598. ERRCT:    DB    0        ; Error count
  5599. FRSTIM:    DB    0        ; Turned on after first 'SOH' received
  5600. INDEX:    DW    0        ; Index into directory
  5601. KFLAG:    DB    0        ; Non-zero if sending 1K blocks
  5602. OUTPTR:    DW    0
  5603. RCNT:    DW    0        ; Record count
  5604. RCVDRV:    DB    0        ; Requested drive number
  5605. RCVRNO:    DB    0        ; Record number received
  5606. RCVUSR:    DB    0        ; Requested user number
  5607. RECDNO:    DW    0        ; Current record number
  5608. KIND:    DB    0        ; Asks what kind of file this is
  5609. OLDDRV:    DB    0        ; Save the original drive number
  5610. OLDUSR:    DB    0        ; Save the original user number
  5611. OPTSAV:    DB    0        ; Save option here for carrier loss
  5612. PRVTFL:    DB    0        ; Private user area option flag
  5613. MSGFLG:    DB    0        ; Message upload flag
  5614. SAVEHL:    DW    0        ; Saves TBUF command line address
  5615. TOTERR:    DW    0        ; Total errors for transmission attempt
  5616. VRECNO:    DW    0        ; Virtual record # in 128 byte records
  5617. ;
  5618. EOFLG:    DB    0        ; 'EOF' flag (1=yes)
  5619. EOFCTR:    DB    0        ; EOF send counter
  5620. OUTADR:    DW    LOGBUF
  5621. OUTSIZ:    DW    BSIZE
  5622. RECPTR:    DW    DBUF
  5623. RECNBF:    DW    0        ; Number of records in the buffer
  5624. ;
  5625.      IF    CONFUN AND SYSABT
  5626. SYSABF:    DB    0        ; set if sysop uses ^X to abort
  5627.      ENDIF
  5628. ;
  5629.      IF    (DESCRIB OR MBDESC) AND    NDESC
  5630. NDSCFL:    DB    0        ; Used to store "RN" option
  5631.      ENDIF            ; to bypass upload descriptions
  5632. ;
  5633.      IF    DESCRIB
  5634. HLINE:    DB    '-------------------',CR,LF
  5635. OLINE:    DS    80        ; Temporary buffer to store line
  5636.      ENDIF
  5637. ;
  5638.     DS    80        ; Minimum stack area
  5639. ;
  5640. ; Disk buffer
  5641. ;
  5642.     ORG    ($+127)/128*128
  5643. ;
  5644. DBUF    EQU    $        ; 16-record disk buffer
  5645. STACK    EQU    DBUF-2        ; Save original stack address
  5646. LOGBUF    EQU    DBUF+128    ; For use with LOGCAL
  5647. ;
  5648. ;-----------------------------------------------------------------------
  5649. ;
  5650. ;              BDOS equates
  5651. ;
  5652. ;-----------------------------------------------------------------------
  5653. ;
  5654. RDCON    EQU    1        ; Get character from console
  5655. WRCON    EQU    2        ; Output to console
  5656. DIRCON    EQU    6        ; Direct console output
  5657. PRINT    EQU    9        ; Print string function
  5658. VERNO    EQU    12        ; Get CP/M version number
  5659. SELDSK    EQU    14        ; Select drive
  5660. OPEN    EQU    15        ; 0FFH = not found
  5661. CLOSE    EQU    16        ; "      "
  5662. SRCHF    EQU    17        ; "      "
  5663. SRCHN    EQU    18        ; "      "
  5664. DELET    EQU    19        ; Delete file
  5665. READ    EQU    20        ; 0=OK, 1=EOF
  5666. WRITE    EQU    21        ; 0=OK, 1=ERR, 2=?, 0FFH=no dir. space
  5667. MAKE    EQU    22        ; 0FFH=bad
  5668. RENAME    EQU    23        ; Rename a file
  5669. CURDRV    EQU    25        ; Get current drive
  5670. SETDMA    EQU    26        ; Set DMA
  5671. SETATT    EQU    30        ; Set file attributes
  5672. SETUSR    EQU    32        ; Set user area to receive file
  5673. RRDM    EQU    33        ; Read random
  5674. WRDM    EQU    34        ; Write random
  5675. CFSIZE    EQU    35        ; Compute file size
  5676. SETRRD    EQU    36        ; Set random record
  5677. GETTIM    EQU    105        ; CP/M Plus get date/time
  5678. BDOS    EQU    0005H
  5679. TBUF    EQU    0080H        ; Default DMA address
  5680. FCB    EQU    005CH        ; System FCB
  5681. FCBEXT    EQU    FCB+12        ; File extent
  5682. FCBRNO    EQU    FCB+32        ; Record number
  5683. RANDOM    EQU    FCB+33        ; Random record field
  5684. ;
  5685. ;    Extended BYEBDOS equates
  5686. ;
  5687.      IF    BYEBDOS
  5688. BDMIST    EQU    61        ; Modem raw input status
  5689. BDMOST    EQU    62        ; Modem raw output status
  5690. BDMOUT    EQU    63        ; Modem output 8 bit char
  5691. BDMINP    EQU    64        ; Modem input 8 bit char
  5692. BDCSTA    EQU    65        ; Modem carrier status
  5693. BDCONS    EQU    66        ; Local console input status
  5694. BDCONI    EQU    67        ; Local console input char
  5695. BDCONO    EQU    68        ; Local console output char
  5696. BDMXDR    EQU    69        ; Set/get maximum drive
  5697. BDMXUS    EQU    70        ; Set/get maximum user area
  5698. BDNULL    EQU    72        ; Set/get nulls
  5699. BDTOUT    EQU    71        ; Set/get idle timeout
  5700. BDULCS    EQU    73        ; Set/get upperlowercase switch
  5701. BDLFMS    EQU    74        ; Set/get line-feed mask
  5702. BDHRDL    EQU    76        ; Set/get hardlog
  5703. BDWRTL    EQU    75        ; Set/get writeloc
  5704. BDMDMO    EQU    77        ; Set/get mdmoff flag
  5705. BDBELL    EQU    78        ; Set/get bell mask flag
  5706. BDGRTC    EQU    79        ; Get address of rtc buffer
  5707. BDGLCB    EQU    80        ; Get address of lc buffer
  5708. BDSTOS    EQU    81        ; Maximum time on system
  5709. BDSLGT    EQU    82        ; Set login time
  5710. BDPTOS    EQU    83        ; Print Time on System
  5711.      ENDIF            ; BYEBDOS
  5712. ;
  5713.     END
  5714.