; BYE510H - REMOTE CONSOLE PROGRAM FOR CP/M AND MODEM - 03/17/87 ; ; ; *** SPECIAL HBBS VERSION FOR MIDNIGHT MAINTENANCE - 03/15/87 **** ; (Set EXFIL1 to YES if using HSAVE.COM to backup files ; (Set EXFIL2 to YES if using HMNT.COM to rehash and re- ; number messages.) ; ; (Put your I/O and clock inserts at ++++) ; ; For use with CP/M 2 or CP/M 3 ; ; NOTE: Read the BYE5.HIS in this .LBR to review ; update history and to see changes imple- ; mented by this version. ; ; ; BYE5 replaces all previous BYE2, BYE3, BYE4, BYE+, and MBYE series and ; also supports the latest available technology for RCP/M systems. BYE5 ; will work with KMD04 and XMODEM-116 or later revisions. ; ;======================================================================= ; ; NOTE: This program is copyrighted (c) 1986 by Irv Hoff, Wayne Masters ; and George Peace. All rights reserved. Users are hereby ; granted a limited license to copy this program for personal use ; only. The program may be distributed unmodified to all inter- ; ested parties. No fee or other consideration shall be accepted ; by any party or parties. In accordance with the copyright law ; of 1978, form TX has been sent to the U.S. Government Copyright ; Office. ; ; = = = = = = = = ; ; If you have changes that you would like to see in a forthcoming ; general release, please forward them for consideration. This ; seems to be the only way to control the modifications that have ; run rampant in previous versions of public domain programs. It ; has taken many hours to correct problems some of these changes ; have caused, particularly when used with assemblers that have ; characteristics different from the one being currently used or ; if other equates are selected. ; ; Send/call any suggestions or requests for help to: ; ; Wayne Masters Irv Hoff, W6FFC George Peace ; (408) 378-3798 voice (415) 948-2166 voice (717) 657-0285 voice ; ; Potpourri RCPM CP/M-3 George Peace ; (408) 378-7474 (717) 657-8699 ; ; = = = = = = = = ; ; If using M80, remove the ";" at the beginning of the ASEG line. ; ASEG ; Needed for M80, but RMAC can't handle it ; ; This program allows modem callers to use a CP/M system just as if they ; were seated at the system console. Special assembly-time options al- ; low limiting the caller's access by password and/or access to only a ; message-service program. A number of external inserts are available ; to adapt this program to various computers, clocks and modems. It ; may be assembled with ASM, LASM, MAC, RMAC, SLRMAC or M80. If the ; ZCPR3 equate is YES, a macro assembler such as MAC, M80 or SLRMAC ; will be required. If the program will not assemble correctly with ; M80, check the insert that was added, it likely is not configured ; properly. ; ; BYE5 will continue supporting what the Sysop's organizations have re- ; quested, not personal preferences. ; - Wayne Masters ; ;======================================================================= ; ; The following files are inside this library to assist you in installa- ; tion: ; ; BYE5.DOC For general installation and extended BDOS functions ; B5-CPM3.DOC Specific instructions for CP/M 3 installation ; BYE5.HIS BYE5 update history (read this to see latest features) ; BYE5-INS.INF Computer-specific inserts currently available (CP/M 2 & 3) ; B5-TIME.INF Clock inserts currently available (CP/M 2 & 3) ; B5IM-1.DOC Intelligent (smart) modem configuration information ; BYE5nnC.AQM Condensed version of BYE5 for small floppy based systems ; ;======================================================================= ; ; If the CPM3 equate is YES, BYE5 uses an RSX loader to attach itself to ; your operating system (see B5-CPM3.DOC). For CP/M-2 users, (CPM3 NO), ; BYE5 uses a special loader that is built into the program to automati- ; cally move itself below CCP. This does not require any alteration in ; the location of CP/M by using MOVECPM. All you need to do is: (1) ; choose the desired options, (2) patch in the insert for your computer ; in the special area near the start marked "+++ Install your I/O port ; insert here +++", (3) patch in the insert for your clock at label TIME ; (if CLOCK is YES), (4) then finish editing, assemble, load and use. ; ; Most users of this program will have a modem such as an Anchor, Hayes, ; ProModem, U.S.Robotics, or Racal Vadic Maxwell. All these types are ; "intelligent" modems. If using this type of modem, set the IMODEM ; and B5IM equates to 'YES'. Otherwise leave them set to 'NO' and BYE ; assumes you have a "dumb" auto-answer modem, (such as a Bell 212A). ; This readily adapts the program to a wide variety of modems and I/O ; serial types. ; ; NOTE: Two support libraries exist for BYE5... ; BYE5-INS.LBR contains all available computer-specific inserts ; B5-CLOCK.LBR contains all available clock inserts. ; ; Be sure to check Potpourri for the latest version of these inserts. ; Many have been corrected and/or updated by users of BYE5 and the one(s) ; you have may not be the latest version. ; ; The program does the following: ; ; If you type BYE E, BYE will load and execute as though it has ; a valid carrier or caller. Handy for debug, else it: ; ; 1) Hangs up the phone ; 2) Awaits ring if B5IM is YES, (or carrier detect if B5IM is NO) ; allows exit to CP/M if local KEYB types CTL-C ; 3) Answers the phone and outputs carrier ; 4) Awaits incoming carrier. If none found in 30 seconds goes ; back to step 1 ; 5) Detects the speed of caller and sets local cpu to that speed ; 6) Asks number of nulls (0-9) (optional) ; 7) Sets the log-in time (if TIMEON is YES) ; 8) Types the "WELCOME" file from disk, (optional) allowing ; CTL-C to skip it ; 9) Asks for a password (optional), allowing 3 tries to get ; it right. When entered drops into CP/M ; 10) Caller can leave by hanging up, (any time carrier is ; lost, it waits then goes back to step 1) or the caller ; may type the program name (BYE). ; - Notes by Wayne Masters ; ;======================================================================= ; MAIN EQU 5 VERS EQU 10 MONTH EQU 08 DAY EQU 01 YEAR EQU 86 ; ; ; System equates ; YES EQU 0FFH NO EQU 0 ; ; ; You will likely also want to change the password, located below at ; label 'PASSWD' (if you set PWRQD YES). If you are using a BBS.COM ; file then PWRQD is normally left NO. ; ;*********************************************************************** ; ; OPTION CONFIGURATION SECTION ; ;*********************************************************************** ; ;----------------------------------------------------------------------- ; BYE5 configuration ; ; LOCMD EQU 61 ; BYE's lowest extended BDOS call HICMD EQU LOCMD+27 ; BYE's highest extended BDOS call CCPL EQU 8 ; Number of sectors for CCP size (8 is ; normal for 2k. Apples with Micro- ; soft CP/M v2.23 use 9. Systems with ; Trantor WL BIOS, set to 0 and set ; TRANWL YES. For older versions of ; Trantor BIOS start with 24 and work ; down until it stops working (typi- ; cally 24 or 16). An updated Trantor ; (WL) BIOS is advised for RCP/M use ; if running a large BBS program. ; CP/M-3 does not use this or TRANWL ; equates. ; ;----------------------------------------------------------------------- ; Modem Type ; IMODEM EQU YES ; Yes, for intelligent modem, including ; Hayes B5IM EQU YES ; Yes, your modem uses AT protocol, like ; Hayes ; ; ; Set one (and only one) of the following HS equates to YES ; HS9600 EQU NO ; Yes, if modem's high speed is 9600 bps HS4800 EQU NO ; Yes, if modem's high speed is 4800 bps HS2400 EQU NO ; Yes, if modem's high speed is 2400 bps HS1200 EQU YES ; Yes, if modem's high speed is 1200 bps HS300 EQU NO ; Yes, if modem's high speed is 300 bps ; ; ; The next 7 equates are only used if B5IM is YES ; DOATZ EQU NO ; Yes to do ATZ between calls. If your ; modem reverts to auto-answer after ; ATZ, set this NO. It speeds up the ; turnaround between calls AND pre- ; vents modem from answering while ; BYE5 is trying to reinitialize for ; the next call. Most modems (Hayes ; and clones) don't need it. ECHO EQU YES ; Yes for Hayes, ProModem, Courier, R-V ; Maxwell, NO for all others (USR, ; Anchor, etc.) ANCHOR EQU NO ; Yes, if you have a Mark XII NODTR EQU NO ; Yes, modem or computer does not sup- ; port DTR such as Anchor Mark XII or ; some Osborne-1's. NOTE OS-1 users.. ; BYE5 can handle your NODTR problem, ; but will NOT work unless you install ; the hardware mod to fix the carrier ; detect logic. The same mod also ; fixes the DTR problem, so you should ; install the whole mother board modi- ; fication kit and set this NO NOATA EQU NO ; Yes, if you have an older Password, ; 212A or S-100 that will not execute ; the ATA command after ring is de- ; tected. Newer firmware works. OFFHK EQU NO ; Yes, if you want BYE to put your phone ; off-hook (ATH1) when running locally ; (E) or exiting to CP/M (instead of ; Using ATS0=0) SHORTB EQU NO ; Yes, for modems that that can't accept ; a 30 character CMD string, like the ; MultiModem. ; ;----------------------------------------------------------------------- ; General Equates ; HARDLOG EQU NO ; Yes, echo remote input to printer PRINTER EQU NO ; Yes, if your bbs uses printer for er- ; ror msgs. or if you use ^P remotely. ; QBBS users say YES if QENTER is set ; to print callers data. NOTE, if you ; use your printer I/O drivers for ; for your modem, then say YES to this COMFILE EQU NO ; Yes, chain to a .COM file on carrier ; detect COMDRV EQU 'A' ; Drive to look for .COM file on COMUSR EQU 0 ; User# of .COM file to be called after ; answer DISKLOG EQU NO ;*Yes, echo remote input to disk file ; Warning..this code requires approxi- ; mately 1200 bytes extra. Large BBS ; program may have enough room if this ; feature is selected. LOGUSR EQU 14 ; User number of SYS.LOG file LOGDRV EQU 'A' ; Drive for SYS.LOG file EXFILE EQU NO ; Yes, chain to a .COM file when BYE ; logs off a caller (even when he ; types BYE). Your EXIT.COM file must ; preserve the stack and do a RETURN ; (not warmboot) to reenter BYE cor- ; rectly or use the EXRET method below ; CPM3 or HBBS users must say YES to ; this. QBBS users must say NO, MBBS ; NO if CP/M 2 or MBBS YES with CPM3. ; ; = = = = = = = = = = = = = = = = = = = = = = = = ; special HBBS maintenance options ; EXFIL1 EQU NO ;*Backs up HBBS message files with HSAVE EXFIL2 EQU NO ;*Packs and renumbers HBBS message files ; with HMNT ANYLOS EQU NO ; Want a backup after any carrier loss? ; (preferred if using volataive RAMDISK) RAMDSK EQU NO ; Yes if using RAMDISK and want message ; rehash to be done on backup drive ; ; ; Following two only used if RAMDSK is set YES, so files may be copied ; back to original drive/user via auxiliary program called HSAVE.COM. ; BCKUPDR EQU 'B' ; Drive used for message backup BCKUPUS EQU 14 ; User area for message backup ; ; end of special HBBS maintenance options ; = = = = = = = = = = = = = = = = = = = = = = = = ; EXRET EQU NO ; YES, if your exit file can't preserve ; the stack and do a normal RETURN. ; MBASIC, "C", and some Pascal pro- ; grams can't do the stack save-return ; easily. Simply POKE FCB+1 (5DH) ; with 'r' (small r) and dDo a warm- ; boot (SYSTEM) and BYE5 will handle ; your exit file return correctly. BYHANG EQU NO ;*Yes, for BYE5 to say goodbye and dis- ; connect the phone BEFORE calling ; your EXIT file. METAL, & OxGate ; users must say YES. HBBS say NO. EXDRV EQU 'A' ; Drive to look for exit .COM file on EXUSR EQU 14 ; User # of .COM file to be called upon ; exit MSGFIL EQU NO ; Yes, if your BBS system allows mes- ; sages to be uploaded by KMD, NUKMD ; or MBKMD. These programs set a flag ; that will cause your MSG.COM file to ; be executed. The .COM file must be ; on the same D/U as COMFILE. Your ; MSG.COM file can append (then erase) ; the uploaded message(s) to your mes- ; sage file. Your MSG.COM file must ; preserve the stack and do a RETURN ; (not warmboot) to renter BYE. You ; can select the name of MSG.COM at ; label MSGFCB: (default name is ; MFMSG.COM) NO25TH EQU NO ; Yes, you wish to display LASTCALR data ; (^W). You may also print a header ; above the LC data. Put your custom- ; ized header at label LCHEAD: MBBS, ; HBBS, QBBS users must say YES NO25BF EQU 78 ; Size (bytes) of lc buffer needed by ; your BBS. MBBS, QBBS = 65, METAL, ; HBBS, OXGATE =78 READLC EQU NO ; Yes, to have BYE read your LASTCALR ; file, No if your BBS pokes LASTCALR ; into BYE. MBBS, HBBS, QBBS, METAL, ; and OxGate users say NO LCDRV EQU 'A' ; Drive to find LASTCALR or LASTCALR.DAT LCUSR EQU 14 ; User # of LASTCALR or LASTCALR.DAT file ; SKTERM EQU NO ;*Yes, to skip the code that waits for ; the caller to get his modem program ; into terminal mode. Caution...The ; caller may miss your opening welcome ; text if you set this equate yes. If ; your BBS program has code built in ; to make sure the caller is ready AND ; in terminal mode, set to yes WBDRIV EQU 'A'-41H ; Drive to log to on first warmboot to cp/m ; Some add-on hard disk systems want C ; WELFILE EQU YES ; Yes, to send a WELCOME file WELDRV EQU 'A' ; Drive to look for WELCOME??? file WELUSR EQU 0 ; User number of WELCOME??? file ; CLRSCR EQU NO ; Yes, to auto-clear local CRT screen ; between calls. No, will still allow ; you to use ^Z to manually clear it. ; you are allowed a 6 byte sequence ; below. The example is for an : ; if you use a ctrl-key (example, ^Z), ; set CLRCH1 EQU 'Z'-40H. Set all ; unused bytes 0. Leave this NO until ; everything is working CLRCH1 EQU 1BH ; Set these for your clear screen sequence CLRCH2 EQU ':' ; 1B is escape and ESC : clears my screen CLRCH3 EQU 0 ; (Byte 3 if you need it). CLRCH4 EQU 0 ; Six bytes allowed for clear screen CLRCH5 EQU 0 ; Sequence and you can also clear your CLRCH6 EQU 0 ; 25th line if desired. ; PRGRSS EQU YES ; Yes, for helpful progress reports on ; CRT. Leave this YES until every- ; thing is working PRNTGB EQU YES ; Yes, print "Goodbye..." message PRNTWB EQU NO ; Yes, print a string for each warm boot PWRQD EQU YES ; Yes, password needed for CP/M access ; TOVALUE EQU 5 ; Minutes of no-activity allowed. 255 max. ;----------------------------------------------------------------------- ; RVIDEO EQU NO ; Yes, display local messages in reverse ; Video when caller is online. (Set ; your on/off sequence below). This ; also works with half intensity in- ; stead of reverse video. RVON1 EQU 1BH ; Set your reverse-on sequence in these 4 RVON2 EQU 'G' ; Bytes. Set unused bytes to nulls (0). RVON3 EQU '4' ; 1BH is escape, ESC G4 is reverse video RVON4 EQU 0 ; ON for the Televideo 925 terminal ; RVOFF1 EQU 1BH ; Now set the reverse-off sequence as above RVOFF2 EQU 'G' ; ESC G0 is reverse video OFF for the 925 RVOFF3 EQU '0' RVOFF4 EQU 0 ; Set unused bytes to 0 ; ; ;----------------------------------------------------------------------- ; System and Hardware dependent options ; CPM3 EQU NO ; Yes, installing with CP/M 3.0, see ; B5-CPM3.DOC ; ; ; The next six equates are only for CPM3 users ; CCPPLUS EQU NO ; Yes, CCP+ installed. ; HISTRSX EQU NO ; Yes, clear command line HISTory if ; HIST+ RSX is installed SDRV1 EQU 1 ; Set these 4 equates to the default SDRV2 EQU 0FFH ; Drive search chain. SDRV3 EQU 0FFH ; 0 = current, 0FFH = end of chain. SDRV4 EQU 0FFH ; 1 = A, 2 = B, etc. ; ; End of CPM3 only ; CLOSS EQU 1 ; If carrier dies, wait 1 second, then ; hang up CTRLC EQU 'K'-'@' ; Map ^C to this character DOWNMIN EQU 2 ; Number of min after Sysop types ^O to ; logout LOSER EQU NO ; Yes, warm boot overwrites part of the ; BIOS MHZ EQU 4 ; Processor clock in MHz MOTOR EQU NO ; Yes power up/down drives between calls TRANWL EQU NO ; Yes if running Trantor WL BIOS system ; ;----------------------------------------------------------------------- ; Filtered characters ; BYE5 filters incoming modem noise by ignoring those characters most ; frequently generated by noisy modems or marginal phone connections. ; Also, some incoming characters may cause your local terminal to do ; strange (and sometimes undocumented) things. The most common char- ; acters generated by noisy modem connections are the left brace ({), ; the delete character (07F) and nulls (00H). An example of problem ; characters for the TRS-80 is the backward slash (\). You may select ; any 4 characters below for BYE5 to filter from the incoming modem. ; Set any, or all, to nulls (00H) if you choose not to use the modem ; filter code. ; FILT1 EQU 7BH ; Left brace FILT2 EQU 7FH ; Delete character FILT3 EQU 60H ; Backward slash (TRS-80 problem) FILT4 EQU 00H ; Null ; ;----------------------------------------------------------------------- ; Function Keys ; LEADIN EQU YES ;*Yes, to use lead-in character for ; F-keys instead of single CTL chars. ; IF LEADIN LEADKY EQU '\' ; Key to use for lead-in. Choose a sel- ; dom used key. ENDIF ; LEADIN ; ; ; If LEADIN is YES, you must type the LEADKY first, then the character ; inside the ' ' below. If LEADIN is NO, the following characters are ; used as a single control key. Select only your character preference ; inside the ' ', and leave the -40H alone. Either option will accept ; upper and lower case. ; ANSKEY EQU 'A'-40H ; Key to force modem to answer the phone BLNKKEY EQU 'B'-40H ; Key to toggle remote terminal on/off LOGKEY EQU 'D'-40H ; Key to flip disk log file save. BELLKEY EQU 'G'-40H ; Key to toggle bells on console LCKEY EQU 'L'-40H ; Key to force return to local CP/M af- ; ter current caller logs off (and ; alert Sysop) TWITKEY EQU 'N'-40H ; Keycode to hangup modem manually SYSDKEY EQU 'O'-40H ; Key to print "System going down in ; N min.." MSGKEY EQU 'Q'-40H ; Keycode to print "Message from SYSOP:" TIMEKEY EQU 'T'-40H ; Key for Sysop to display time (if ; TIMEON) ULTKEY EQU 'U'-40H ; Key to grant current caller unlimited ; time. Also enables all the flag ; bits in LCPTR WHOKEY EQU 'W'-40H ; Key to display LASTCALR if NO25TH is ; Yes XITKEY EQU 'X'-40H ; Key to exit from "Message from Sysop" ; loop ZCREEN EQU 'Z'-40H ; Key to manually clear your screen ; ;----------------------------------------------------------------------- ; RBBS Type ; ; Set only one, or none of the following BBS equates to YES. If COMFILE ; YES and none of the below are selected you will have an undefined label ; COMFCB during assembly. ; METAL EQU NO ; Yes, running METAL BBS system. ; MBBS EQU NO ; Yes, running MBBS4n BBS system MBSDRV EQU 'A' ; Drive where you keep MBBS.COM MBSUSR EQU 0 ; User area for MBBS.COM - LOGIN.COM and ; MFGMSG.COM must both be on COMDRV ; and COMUSR selected above ; MINICK EQU NO ; Yes, running MINICBBS..you must also ; create your COMFCB label ; OXGATE EQU NO ; Yes, running OxGate BBS system HBBS EQU NO ; Yes, running HBBS system QBBS EQU NO ; Yes, running QBBS system RBBS EQU NO ; Yes, running RBBS, sets/resets ; 'WRTLOC' flag IOVAL EQU 0 ; Initial value for IOBYTE (if MINICK ; is YES) LMBELL EQU NO ; Yes, your bbs uses a low-memory bell ; flag, Yes for MBBS and RBBS users. KILBEL EQU 03BH ; Byte for low memory bell toggle flag ; ; ; Some BBS systems require a flag to be reset to allow reentry to the ; BBS from CP/M (older versions of RBBS do). If you run a BBS that uses ; this technique, then set RTOK to YES, and define the byte to reset at ; RTOKFG. BYE5 will reset this byte to zero between calls. ; RTOK EQU NO ; Yes, to reset the following byte be- RTOKFG EQU 020H ; Tween calls. HBBS users should say ; Yes, and set RTOKFG EQU to your REENTR ; Byte, normally 20H. ; ;----------------------------------------------------------------------- ; Clock/Time Equates ; ; NOTE... Be sure to set the CLOCK and TIMEON equates the same way in ; both BYE5 and KMD. ; CLOCK EQU NO ; If YES, add your clock reader code at ; the start of label TIME: and store ; binary values in CCHOUR and CCMIN ; HBBS and QBBS users must say YES BCD2BIN EQU NO ; Yes, your clock routine calls BCDBIN BIN2BCD EQU NO ; Yes, your clock routine calls BINBCD TIMEON EQU NO ; Yes, if you want BYE5 to keep track of ; time-on-system and log off user ; after MAXMIN. This works without a ; clock if you use KMD MAXMIN EQU 60 ; Minutes for maximum time allowed on ; system. Recommend 60 if CLOCK and ; TIMEON are YES, and 45 if CLOCK is ; NO and TIMEON YES. (255 minutes ; maximum). 0= No restrictions. ; ; NOTE, the previous callers timeon is preserved for your exit or login ; program to access in BYE's fixed lookup table at label LCPTR. You may ; choose to store that data in low memory, or elsewhere by changing the ; LCTON equate to a new address. LCTON is found just after BYE's fixed ; lookup table. ; PRNTOS EQU NO ; Yes, print Time-left-on-system on ; warmboots. If WHEEL is on or if ; MXTIME=0, this will print the time ; on system rather than time left. RSPEED EQU NO ; Yes, restricting prime time to a min- ; imum speed (a clock read routine is ; required if YES - see CLOCK). ; IF RSPEED ; 24 hour clock, 00=midnight, 23=11PM HOUR1 EQU 19 ; Start of prime-time (19=7:00 PM) HOUR2 EQU 23 ; End of prime-time (23=11:00 PM) SPEED EQU 5 ; Minimum speed accepted (5=1200 baud). ; Change OFFMSG to match your times, ; baud rate and time zone. OFFMSG is ; a message at end of the source code. ENDIF ; RSPEED ; ;----------------------------------------------------------------------- ; CCP Options ; ZCPR2 EQU NO ; Yes, if running ZCPR2 or ZCMD29 or ; if using CP/M 3 with wheel byte ZCPR3 EQU NO ; Yes, if running ZCPR3 ; ; ; NOTE: requires MAC.COM to assemble if ZCPR3 set YES ; IF ZCPR3 MACLIB Z3BASE ; Requires MAC to assemble...otherwise ; enter constants directly..see label ; DOZ3 for required EQU's ENDIF ; ZCPR3 ; ; ; NZCPR/ZCMD/ZCPR all use bytes (at 3DH/3EH/3FH) to store the maximum ; drive, wheel status, and maximum user area. Some BBS systems poke ; these low memory bytes to reset these (for Sysop, etc.) Other BBS ; systems (like OxGate) poke the bytes in BYE that do the same thing. ; The equate USEZCPR allows you to select where you want to poke things. ; For OxGate, set it to NO, for RBBS, you probably want it set to YES. ; If you are NOT using NZCPR/ZCMD/ZCPR then set USEZCPR to NO. ; USEZCPR EQU NO ; Yes, if using ZCPR/NZCPR/ZCMD to set ; bytes CHEKDU EQU NO ; Yes, if you want BYE to police MAXDRIV ; and MAXUSER. No, if your CCP can do ; that (saves a lot of code). In ; either case, BYE keeps correct ; values in these low memory bytes MAXDRIV EQU 003DH ; ZCPR lolcation of MAXDRIV byte WHEEL EQU 003EH ; Location of ZCPR's wheel flag MAXUSER EQU 003FH ; ZCPR location of MAXUSR byte MAXDRV EQU 'B'-'@' ; Highest drive supported MAXUSR EQU 15 ; Highest user area SYSDRV EQU 'B'-'@' ; Highest local drive supported SYSUSR EQU 15 ; Highest local user area (0-15) ; ; If CHGPATH is YES, BYE automagically will change the .COM path to suit ; which mode it is in. An example of this is: when remote, the path is ; $$:, A0: -- when local, MY path is $$:, A0:, A15: which allows keeping ; PIP and FORMAT and other nasties up in A15: -- See REMPATH and SYSPATH ; DB's at end of program for current paths. If the Sysop uses the ^B to ; blank the remote console, the Wheel byte is set and SYSPATH is setup ; for the Sysop. The wheel byte is reset and REMPATH setup when ^B is ; used the second time to turn the remote back on. ; CHGPATH EQU NO ; Yes, if changing ZCPR's external path EXTPATH EQU 0040H ; ZCPR external path default location ; ;----------------------------------------------------------------------- ; MSPEED values ; MSPEED EQU 03CH ; Baud rate pointer BP110 EQU 0 ; 110 baud - baud rate pntrs for MSPEED BP300 EQU 1 ; 300 baud BP450 EQU 2 ; 450 baud BP600 EQU 3 ; 600 baud BP710 EQU 4 ; 710 baud BP1200 EQU 5 ; 1200 baud BP2400 EQU 6 ; 2400 baud BP4800 EQU 7 ; 4800 baud BP9600 EQU 8 ; 9600 baud BP19200 EQU 9 ; 19200 baud ; ;----------------------------------------------------------------------- ; Motor controlled drives ; ; These values suit a Compupro/Viasyn Disk1A with YE-DATA 180 20cm ; drives. Alter to suit your needs if your disk controller supports ; motor control. ; IF MOTOR DISK EQU 0C3H ; Disk control port DISKON EQU 080H ; Motors on DISKOFF EQU 000H ; Motors off ENDIF ; MOTOR ; ;----------------------------------------------------------------------- ; if using LOSER ; ; There are some cases where warm boot overwrites the initial BIOS jump ; table. This problem was solved for the Superbrain 3.0 bios by find- ; ing a warmboot call to HIGH in the BIOS. This call is then patched by ; BYE. The form of the call is: WBCALL CALL WMSTRT ; IF LOSER WBCALL EQU 0E260H ; Check this in your BIOS ; ; ; The following location is called ; WMSTRT EQU 0E566H ; Check this in your BIOS ENDIF ; LOSER ; ;----------------------------------------------------------------------- ; ; END OF OPTION CONFIGURATION SECTION FOR BYE5 ; ;----------------------------------------------------------------------- ; IF NOT CPM3 ORG 100H ; ;-------------------- Special Loader Routine --------------------------- ; START: LXI SP,ISTACK ; Set stack for initialization routine MVI C,32 MVI E,241 CALL BDOS ; See if BYE is running CPI 77 ; Yes, if (A)=77 JNZ STARTA ; No, we must relocate code ; ; ; Ok, we're sure that BYE's already there ; LHLD BDOS+1 ; Load BDOS vector INX H ; Compute start of BYE5 INX H INX H PCHL ; Go execute already loaded code ENDIF ; NOT CPM3 ; STARTA: IF COMFILE AND (NOT CPM3) LXI H,COMFCB+1 ; BBS com filename LXI D,ENTMSG ; Display buffer MVI B,8 ; Length of filename ; STAR1: MOV A,M ; Move it to display buffer CPI ' ' ; Stop on first space JZ STAR2 STAX D INX D INX H DCR B JNZ STAR1 ; Loop until space or 8 chars found ; STAR2: XRA A STAX D ; Store 0 as print terminator ENDIF ; COMFILE AND NOT CPM3 ; IF EXFILE AND (NOT CPM3) LXI H,EXITFCB+1 ; Exit com filename LXI D,EXTMSG ; Display buffer MVI B,8 ; Length of filename ; STAR3: MOV A,M ; Move it to display buffer CPI ' ' ; Stop on first space JZ STAR4 STAX D INX D INX H DCR B JNZ STAR3 ; Loop until space or 8 chars found ; STAR4: XRA A STAX D ; Store 0 as print terminator ENDIF ; EXFILE AND NOT CPM3 ; IF MSGFIL AND (NOT CPM3) LXI H,MSGFCB+1 ; Message com filename LXI D,MSGMSG ; Display buffer MVI B,8 ; Length of filename ; STAR5: MOV A,M ; Move it to display buffer CPI ' ' ; Stop on first space JZ STAR6 STAX D INX D INX H DCR B JNZ STAR5 ; Loop until space or 8 chars found ; STAR6: XRA A STAX D ; Store 0 as print terminator ENDIF ; MSGFIL AND NOT CPM3 ; IF LMBELL AND (NOT CPM3) LDA BELLON CMA STA KILBEL ; Prep the low memory bell flag ENDIF ; LMBELL AND NOT CPM3 ; IF NOT CPM3 LHLD BDOS+1 ; Load BDOS vector LXI D,-(CCPL*256)-8 ; 2k btyes in CCP plus offset DAD D ; Make room for the CCP ; ; ; HL now contains the destination address of BYE5 ; LXI D,OBJEND-1 ; Set up the source pointer LXI B,OBJEND-BEGOBJ ; Set up byte counter ; BLOCK: LDAX D ; Get program byte MOV M,A ; Move program byte MOV A,B ; Get byte count ORA C ; Finished block transfer? JZ UPDATE ; Yes, check on the opcode values DCX D ; No, set source pointer DCX H ; Set destination pointer DCX B ; Set byte counter JMP BLOCK ; Continue block transfer until finished ; UPDATE: XCHG ; Move the source addrress into 'HL' CALL NEGHL ; Prepare value for subtraction DAD D ; Form the program offset SHLD OFFSET ; Save the program offset XCHG ; Set up the offset register LXI H,ENDOBJ ; Get the ending addr of the prgm code DAD D ; Form new ending addr (new location) SHLD ENDRNG ; Save the ending addr of the prgm code LXI H,BEGOBJ ; Get the start address of program code DAD D ; Form new beginning addr (new location) ; ; ; The following code determines whether or not an address is within the ; BYE prgm and sets it to the new address if it is - otherwise it will ; not disturb the code. ; DCX H ; Set up the source pointer for the ; Modification routine entry MODIFY: INX H ; Point to the next (hopefully) instr. DB LXID ; Get the address of the end of BYE5 ; ENDRNG: DW 0 MOV A,E SUB L MOV A,D SBB H ; Have we finished moving this block? JC BEGIN ; Yes, we can begin now. ; ; ; Here is where we test for the 3-byte opcodes ; MVI B,INST3E-INST3 ; Get number of elements in the table LXI D,INST3 ; Set up the 3-byte opcodes table ptr ; THRBYT: LDAX D ; Get opcode byte from table CMP M ; Is this byte a 3-byte opcode? JZ CHANGE ; Change the 2nd and 3rd bytes if needed INX D ; No, advance table pointer DCR B ; End of 3-byte table? JNZ THRBYT ; No, keep looking ; ; ; Skip all the 2-byte opcodes - this keeps the transfer program from ; trying to figure out what the second byte is. ; MVI B,INST2E-INST2 ; Get the number of table elements LXI D,INST2 ; Set up the 2-byte-opcodes-table ptr ; TWOBYT: LDAX D ; Get opcode byte from table CMP M ; Is this byte a 2-byte opcode? JZ SKIP ; Yes, skip it and continue DCR B ; No, end of 2-byte table? INX D ; Advance table pointer JNZ TWOBYT ; No, keep looking JMP MODIFY ; Yes, a one-byte opcode, keep going ; SKIP: INX H ; Advance object code pointera JMP MODIFY ; Continue search ; CHANGE: LXI D,OBJEND ; Set up end of range pointer LXI B,BEGOBJ ; Set up beginning of range pointer ; ; ; See if the address is above the range ; INX H ; Advance pointer to the LSB of the addr MOV A,E SUB M INX H ; Advance pointer to the MSB of the addr MOV A,D SBB M JC MODIFY ; ; ; See if the address is below the range ; DCX H ; Set ptr back to the LSB of the addr MOV A,M SUB C INX H ; Advance pointer to the MSB of the addr MOV A,M SBB B JC MODIFY ; ; ; Update the value of this address by adding the offset to it ; DCX H ; Set ptra back to LSB of the address DB LXID ; Load DE with the offset value ; OFFSET: DW 0 MOV A,M ; Get base address ADD E ; Change LSB to new address MOV M,A ; Update memory INX H ; Advance pointer to the MSB of the addr MOV A,M ; Get the MSB of the base addr ADC D ; Change LSB to new address MOV M,A ; Update memory JMP MODIFY ; Take care of the next instruction ; ; ; Small subroutine to negate the contents of HL ; NEGHL: MOV A,H CMA MOV H,A ; Get the complement of the MSB MOV A,L CMA MOV L,A ; Get the complement of the LSBb INX H ; Make 'HL' totally negative RET ;..... ; ; ; Prepare to branch to the BYE5 program ; BEGIN: LHLD BDOS+1 PUSH H LXI D,BEGOBJ LHLD OFFSET ; Get prgram offset DAD D ; Form address of new BDOS address SHLD BDOS+1 ; Update BDOS vector ENDIF ; NOT CPM3 ; IF TRANWL AND (NOT CPM3) PUSH H ; Find where it's at CALL FNDWL POP D JC NOWL MOV M,E INX H MOV M,D ; NOWL: XCHG ENDIF ; TRANWL AND NOT CPM3 ; IF NOT CPM3 INX H POP D MOV M,E INX H MOV M,D INX H PCHL ; Jump to relocated BYE5 program ENDIF ; NOT CPM3 ; IF TRANWL AND (NOT CPM3) HHSIG EQU 12 HSSIG EQU 14 HHSHL EQU 16 HLSHL EQU 18 HBSHL EQU 36 HDRVR EQU 22 HPCT EQU 25 PCMGR EQU 4*2 WWHSIG EQU 'W' WWLSIG EQU 'H' SIGWBT EQU 'B' SIGUB EQU 'L' SIGSD EQU 'S' ; ; ; FNDWL....... ; Input: none: ; Output: ; CY set. Trantor Universal Bios is not loaded ; CY clr. HL -> var where adrs of lowest shell has to ; be stored. ; BC -> lowest shell. ; DE is preserved. ; FNDWL: PUSH D ; ; Scan downwards from High memory trying to find ; any WW shell. ; LXI B,0FF06H ; ASHELL: LXI H,HHSIG DAD B MOV A,M CPI WWHSIG JNZ NSHELL INX H MOV A,M CPI WWLSIG JZ WWLINK ; NSHELL: DCR B LDA 7 DCR A CMP B JC ASHELL STC POP D RET ;..... ; ; ; Locate the Warm boot shell ; WWLINK: LXI H,HSSIG DAD B MOV A,M CPI SIGWBT JZ WBFND LXI H,HHSHL DAD B MOV C,M INX H MOV B,M JMP WWLINK ; ; ; Build pointer to wb.lowestshell ; WBFND: LXI H,HBSHL DAD B ORA A ; WLEXIT: POP D RET ENDIF ; TRANWL AND NOT CPM3 ; ;..... ; ; IF NOT CPM3 ; ; The following table defines the 3-byte load instructions used in the ; 8080 instruction set. ; INST3: DB 001H,011H,021H,022H,02AH,031H,032H,03AH,0C2H DB 0C3H,0C4H,0CAH,0CCH,0CDH,0D2H,0D4H,0DAH,0DCH DB 0E2H,0E4H,0EAH,0ECH,0F2H,0F4H,0FAH,0FCH INST3E EQU $ ; End of 3 byte op codes ; ; ; The following table is the listing of the 2-byte opcodes used in the ; 8080 instruction code set. ; INST2: DB 006H,00EH,016H,01EH,026H,02EH,036H,03EH,0C6H DB 0CEH,0D3H,0D6H,0DBH,0DEH,0E6H,0EEH,0F6H,0FEH INST2E EQU $ ; End of 2 byte op codes ENDIF ; NOT CPM3 ; ; This is a Resident System Extension (RSX) intended to run under CP/M ; Plus. The RSX is called via BDOS function 60 (in register C) with ; register pair DE pointing to the RSX parameter block. ; IF CPM3 ; Loader for CP/M 3.0 ; ; RSX Prefix Structure ; SERIAL: DB 0,0,0,0,0,0 ; Room to insert serial number STARTX: JMP FTEST ; Beginning of program NEXT: DB 0C3H ; Jump instruction op-code DW 0 ; Next module in line (or BDOS) PREV: DW 0 ; Previous module REMOV: DB 0FFH ; Remove flag initially set NONBNK: DB 0 ; >0 to load only in non-banked CP/M RSXNAM: DB 'BYE5 ' ; The name of this RSX LOADER: DB 0 ; Loader flag DB 0,0 ; Reserved ; ; ; BDOS function 60 sub-functions used by this RSX ; ; 4 Bye test for CCP+ ; 7 Return address of BYE control block (address of MXUSR) ; 11 Remove any RSX's below BYE. This is an immediate ; removal via a call to the CPM3 LOADER. I am hoping ; for future KMD support of this function so that any ; uploads will not go into a library currently opend ; by LD in the upload area. ; 101 Initialize function code ; 102 Terminate function code ; ; ; Miscellaneous data/constants ; INIFLG: DB NOTINIT ; If not reset, all operations rejected INIT EQU 00 ; Initialized NOTINIT EQU 0FFH ; Not initialized ; ; ;----------------------------------------------------------------------- ; Entry point to the RSX ;----------------------------------------------------------------------- ; FTEST: MOV A,C ; Get BDOS function CPI 60 ; Could this one be for us? JNZ NEXT ; Nope - ignore this function ; LDAX D ; Get the sub-function ENDIF ; CPM3 ; IF CPM3 AND CCPPLUS CPI 4 ; Is it bye test for CCP+? JZ TSTBYE ENDIF ; CPM3 AND CCPPLUS ; IF CPM3 CPI 7 ; Is it return Variables address JZ GMXUSR CPI 11 ; Is it remove lower RSX's ? JZ DELRSX CPI 101 ; Is it initialize? JZ RSXINT CPI 102 ; Is it terminate? JZ RSXTRM JMP NEXT ; No match, try next RSX ; ;----------------------------------------------------------------------- ; RSX control functions ;----------------------------------------------------------------------- ; ; Initialize the RSX environment for subsequent calls ; ; This routine establishes the environment for all other calls to the ; RSX. The operation is completed only if the RSX is not in an initial- ; ized state. If the RSX is already initialized, the function is ; bypassed and an error status is passed back to the caller. ; RSXINT: LDA INIFLG ; Get the initialize indicator CPI NOTINIT ; Is this a clean copy? JNZ RSXIN2 ; No - can't reinitialize, use RESET XRA A ; Get a zero STA REMOV ; Mark the RSX resident STA INIFLG ; And mark this RSX as open for business ENDIF ; CPM3 ; IF COMFILE AND CPM3 LXI H,COMFCB+1 ; BBS com filename LXI D,ENTMSG ; Display buffer MVI B,8 ; Length of filename ; STAR1: MOV A,M ; Move it to display buffer CPI ' ' ; Stop on first space JZ STAR2 STAX D INX D INX H DCR B JNZ STAR1 ; Loop until space or 8 chars found ; STAR2: XRA A STAX D ; Store 0 as print terminator ENDIF ; COMFILE AND CPM3 ; IF EXFILE AND CPM3 LXI H,EXITFCB+1 ; Exit .COM filename LXI D,EXTMSG ; Display buffer MVI B,8 ; Length of filename ; STAR3: MOV A,M ; Move it to display buffer CPI ' ' ; Stop on first space JZ STAR4 STAX D INX D INX H DCR B JNZ STAR3 ; Loop until space or 8 chars found ; STAR4: XRA A STAX D ; Store 0 as print terminator ENDIF ; EXFILE AND CPM3 ; IF MSGFIL AND CPM3 LXI H,MSGFCB+1 ; Message com filename LXI D,MSGMSG ; Display buffer MVI B,8 ; Length of filename ; STAR5: MOV A,M ; Move it to display buffer CPI ' ' ; Stop on first space JZ STAR6 STAX D INX D INX H DCR B JNZ STAR5 ; Loop until space or 8 chars found ; STAR6: XRA A STAX D ; Store 0 as print terminator ENDIF ; MSGFIL AND CPM3 ; IF LMBELL AND CPM3 LDA BELLON CMA STA KILBEL ; Prep the low memory bell flag ENDIF ; LMBELL AND CPM3 ; IF CPM3 JMP BGOBJ2 ; Go fire it up ; RSXIN2: MVI A,0FFH ; Get an error code ; RSXIN9: RET ; All done - return to caller ;..... ; ; ; Disengage this RSX ; RSXTRM: CALL MDCARCK ; Check for caller still logged on JNZ START0 ; Have carrier - log caller off, reset CALL UNPATCH ; Remove BIOS overrides JMP BGOBJ2 ; Clean up and restart this program ; RSXCLR: MVI A,0FFH STA INIFLG ; Reset the initializaton flag to pre- ; Vent further access STA REMOV ; Flag to drop this RSX on next warm boot XRA A ; Get a zero RET ENDIF ; CPM3 ; IF CPM3 AND CCPPLUS ;........ ; ;Bye present test for CCP+ ; TSTBYE: XRA A ; Say that we are here RET ENDIF ; CPM3 AND CCPPLUS ; IF CPM3 ;....... ; ;Return address of bye control block ; GMXUSR: LXI H,MXUSR RET ENDIF ; CPM3 ; ;....... ; ;Delete any RSX's below bye ; DELRSX: IF CPM3 AND HISTRSX MVI C,60 ; BDOS function to call an RSX LXI D,RSXCL ; Parameter passed to RSX CALL NEXT ENDIF ; CPM3 AND HISTRSX ; IF CPM3 LHLD PREV ; Get address of previous RSX MVI L,0EH ; Point to remove flag MVI C,59 ; So that the loader will LXI D,0 ; Remove the RSX's DELLP: MOV A,H ORA A ; At base page? JZ NEXT ; All done. Let loader do it. MVI M,0FFH ; Set remove flag DCR L MOV H,M ; Get previous RSX page INR L ; Back to remove flag JMP DELLP ENDIF ; CPM3 ;..... ; ; ; Set aside space for the stack region ; DS 40 ISTACK: DW 0 ; Top of stack ; ; ;----------------------------------------------------------------------- ; ; THE FOLLOWING CODE GETS MOVED ; TO HIGH RAM BY THE LOADER OR RSX ; PROGRAM, WHERE IT IS EXECUTED. ; ;----------------------------------------------------------------------- ; IF NOT CPM3 BEGOBJ: JMP 0 ; Filled by BEGIN ENDIF ; NOT CPM3 ; BGOBJ2: JMP START0 ; Hop over fixed vectors ; MCBOOT: JMP MBOOT ; Off to warm boot JMP PRNLOG ; Go print out items of interest ;..... ; ; ; Variables follow in a predefined order that can be manipulated by a ; passworded or other program to give special users different capabili- ; ties. ; ;----------------------------------------------------------------------- ; ; Here is a quickie handy reference table to use so we do not get mixed ; up. Please do not change the order of it in any future changes. ; ; |mxusr|mxdrv|toval|nulls|ulcsw|lfeeds|wrtloc|hardon|lostflg|covect| ; |1 byt|1 byt|1 byt|1 byt|1 byt|1 byte|1 byte|1 byte|1 byte |2 byes| ; ; |BYE |bell |stat |lcbuf|mxtme|rtcbuf| ; |3 byt|1 byt|1 byt|2 byt|1 byt|2 byte| ;----------------------------------------------------------------------- ; MXUSR: DB MAXUSR ; Runtime maximum user area available MXDRV: DB MAXDRV ; Runtime maximum drive available TOVAL: DB TOVALUE ; Number of mins. to wait before timeout NULLS: DB 0 ; Number of nulls after ULCSW: DB 0 ; Upper case only switch (32=upper case) LFEEDS: DB 0 ; Line feed mask (0=don't mask) WRTLOC: DB 0 ; Location RBBS pokes so BYE won't hang HARDON: DB 0FFH ; If 0, hardlog is deactivated MDMOFF: DB 0 ; If 0FFH, do not output to modem COVECT: DW 0 ; Console output vector for XMODEM HDROFF EQU $-MCBOOT ; Offset to 'BYE' that follows DB 'BYE' ; Tells XMODEM that BYE is being used BELLON: DB 0FFH ; If 0FFH ok to send bell (Chat) to con- ; Sole, 00H=belloff. This only affects ; Your initial default choice LCPTR: JMP LCDATA ; First byte is user access restrictions ; And flags while user is logged on, ; Used for his total time-on after ; Logoff. LCDATA is address of buffer ; For NO25TH data, NO25BF in length MXTIME: JMP RTCBUF ; First bye holds maximum time allowed ; Next 2 bytes point to the real time ; Clock buffer ; ; ; end of BYE5's fixed lookup table ;----------------------------------------------------------------------- ; LCTON EQU LCPTR ; Byte to store last caller's time-on- ; System value (in binary). You may ; Equate this to a low-memory byte or ; Use this byte in the BYE fixed var- ; Iable table...can then be used by ; Your entry/exit program to determine ; How long the previous caller was on. ; ;----------------------------------------------------------------------- ; ; THIS IS THE OFFICIAL START OF THE BYE PROGRAM ; ;----------------------------------------------------------------------- ; ; ++++ Install your user defined subroutines here ++++ ; ; You may install a subroutine here that has the label SRUDEF ; that can be called from a transient program like your entry/ ; exit .com file. To access it, MVI C,84 CALL BDOS from your ; program. Make sure this subroutine has a RET at the end. ; The transient program making a BDOS 84 call may pass data to ; this subroutine in any register(s) except A and C. This routine ; can return data to the calling program in any register(s). ; SRUDEF: RET ; SubRoutine U DEFine for BDOS call 84 ; ;----------------------------------------------------------------------- ; ; B5KP-1.INS - Kaypro insert for BYE5 - 07/17/85 ; ; Z80-SIO and 8116 baudrate generator ; by Irv Hoff ; ; ; Note: This is an insert, not an overlay. ; ; ; MODEM=DCE COMPUTER=DTE ; ; TXD 2 --> 2 RXD received data ; RXD 3 <-- 3 TXD tranmitted data ; SG 7 --- 7 SG signal ground ; DCD 8 --> 8 DCD carrier detect ; DTR 20 <-- 20 DTR data terminal ready ; ; - Notes by Irv Hoff ; ; = = = = = = = = = = = = = = = = = = ; ; 07/17/85 Written for use with BYE5 - Irv Hoff ; ; = = = = = = = = = = = = = = = = = = ; ; PORT EQU 04H ; Data port MDCTL1 EQU PORT+2 ; Modem control port BRPORT EQU 00H ; Baud rate generator port ; MDRCV EQU 1 ; Modem receive ready bit MDSND EQU 4 ; Modem send ready bit MDDCD EQU 8 ; Data carrier detect ; ; ; Divisors for the 8116 baudrate generator ; BD300 EQU 5 ; 300 baud BD1200 EQU 7 ; 1200 bps BD2400 EQU 10 ; 2400 bps ; ; ;----------------------------------------------------------------------- ; ; See if we still have a carrier - if not, return with the zero flat set ; MDCARCK:MVI A,10H ; Reset status OUT MDCTL1 IN MDCTL1 ; Get status ANI MDDCD ; Check for carrier RET ;..... ; ; ; Disconnect and wait for an incoming call ; MDINIT: MVI A,0 ; Setup to write register 0 OUT MDCTL1 MVI A,18H ; Reset channel OUT MDCTL1 ; MVI A,4 ; Setup to write register 4 OUT MDCTL1 MVI A,44H ; Set 16x, 1 stop bit, no parity OUT MDCTL1 ; MVI A,3 ; Setup to write register 3 OUT MDCTL1 MVI A,0C1H ; 8 bits, Rx enable OUT MDCTL1 ; MVI A,5 ; Setup to write register 5 OUT MDCTL1 MVI A,68H ; DTR off OUT MDCTL1 ; PUSH B ; Save in case it's being used elsewhere MVI B,20 ; 2 second delay to drop any carrier ; OFFTI: CALL DELAY ; 1 second delay DCR B JNZ OFFTI ; Keep looping until finished POP B ; Restore 'BC' ; MVI A,5 ; Setup to write register 5 OUT MDCTL1 MVI A,0E8H ; Turn DTR back on OUT MDCTL1 ; IF IMODEM ; If using an intellegent modem CALL IMINIT ; Go initialize it now ENDIF ; IMODEM ; RET ;..... ; ; ; Input a character from the modem port ; MDINP: IN PORT ; Get character RET ;..... ; ; ; Check the status to see if a character is available. If not, return ; with the zero flag set. If yes, use 0FFH to clear the flag. ; MDINST: IN MDCTL1 ; Get status ANI MDRCV ; Got a character RZ ; Return if none ORI 0FFH ; Otherwise set the proper flag RET ;..... ; ; ; Send a character to the modem ; MDOUTP: OUT PORT ; Send it RET ;..... ; ; ; See if the output is ready for another character ; MDOUTST:IN MDCTL1 ; Get status ANI MDSND ; Ready for a character? RET ;..... ; ; ; Reinitialize the modem and hang up the phone by dropping DTR and ; leaving it inactive. ; MDQUIT: IF IMODEM CALL IMQUIT ENDIF ; IMODEM ; ; ; Called by the main program after caller types BYE ; MDSTOP: MVI A,5 ; Setup to write register 5 OUT MDCTL1 MVI A,68H ; Turn off DTR until next time OUT MDCTL1 RET ;..... ; ; ; The following routine sets the baud rate. BYE5 asks for the maximum ; speed you have available. ; SETINV: ORI 0FFH ; Make sure zero flag is not set RET ;..... ; ; SET300: MVI A,BD300 JMP SETBAUD ; SET1200:MVI A,BD1200 JMP SETBAUD ; SET2400:MVI A,BD2400 ; ; ; Sets the baudrate ; SETBAUD:OUT BRPORT XRA A ; Say baudrate is ok RET ;..... ; ; end ;----------------------------------------------------------------------: ; ; ++++ Install your Modem dependent insert here ++++ ; (If B5IM is YES you don't need one) ; ;----------------------------------------------------------------------- ; ; ++++ Install your TIME routine here ++++ ; ; If you have a clock and wish to use TIMEON or RSPEED, please replace ; the following code with your clock read code. Use as many instruc- ; tions as you need but make sure you store binary, not BCD values in ; CCHOUR and CCMIN. Use RTCBUF to store BCD clock data, then use BCDBIN ; to convert it to binary for CCHOUR and CCMIN. See B5C-QXnn.INS as an ; example of handling a BCD clock, or B5C-SDS.INS for a BIOS interrupt- ; driven clock that runs in binary (hex). All registers are saved before ; TIME is called, so you don't have to save them. ; ; NOTE... Set BCD2BIN to YES if your clock routine calls BCDBIN ; Set BIN2BCD to YES if your clock routine calls BINBCD ; TIME: RET ; end of clock routine ;----------------------------------------------------------------------- ; start B5IM code ; IF B5IM IMRING: CALL MDINST ; Character ready from modem? RZ ; No CALL MDINP ; Get the modem response code ANI 7FH ; Strip parity ENDIF ; B5IM ; IF B5IM AND PRGRSS CALL RCDISP ; Display RC for local Sysop PUSH PSW LXI H,LFMSG CALL PRINTL ; Turn up a line on CRT POP PSW ENDIF ; PRGRSS ; IF B5IM CPI CR RZ CPI LF RZ CPI '2' ; Ring? JNZ REDOIT ; No, something wrong, start over ENDIF ; B5IM ; IMRIN1: IF B5IM AND (NOT NOATA) MVI B,5 ; Must let the phone quit ringing first CALL DLP1 ; Usually takes from 1.4 to 3.7 seconds CALL EATALL ; Swallow c/r or lf from result code ; IMRIN2: LXI H,B5ATA CALL IMSEND ; Send ATA to modem ENDIF ; B5IM AND NOT NOATA ; IF B5IM LXI B,30000 ; Check for RC every 1 ms for 30 secs ; MDR1: CALL MDINST JZ RCHEK ; And wait for response CALL MDINP ; Then fetch it ANI 07FH ; And strip parity ENDIF ; B5IM ; IF B5IM AND PRGRSS CALL RCDISP ; And show results code (RC) ENDIF ; B5IM AND PRGRSS ; IF B5IM CPI CR JZ MDR1 CPI LF JZ MDR1 CPI '2' ; Missed ring indicator? JZ IMRIN1 ; Answer again CPI '3' ; Carrier wait timeout? JZ REDOIT ; Yep, timeout (voice call maybe) CPI '4' ; Error? JZ REDOIT ; Start over CPI '1' ; 300 baud or 2400 bps? JNZ MDR2 ; No, check for 1200 bps ; ; ; Get next character if first was a '1' ; CALL CHECK1 ; Let's see if it's a 1, 10 or 11 ENDIF ; B5IM ; IF B5IM AND PRGRSS CALL RCDISP ; Show RC to local terminal ENDIF ; B5IM AND PRGRSS ; IF B5IM CPI '0' JZ SET24 ; For Vadic and Hayes, 10 means 2400 bps ; JMP SET3 ; Was 1 (300 baud) ; MDR2: CPI '5' ; 1200 bps? JZ SET12 ; Yes CPI '6' ; Some modems use 6 JZ SET24 CPI '9' ; Or 9 JZ SET24 ; For Connect-2400 ENDIF ; B5IM ; IF B5IM AND ANCHOR JMP SET3 ; If it wasn't a 3 or 5 it means the ; Anchor connected at 300 but sent RC ; At wrong speed ENDIF ; B5IM AND ANCHOR ; IF B5IM JMP MDR1 ; Wait 30 seconds for valid response ; RCHEK: CALL KDELAY ; Wait 1 millisecond DCX B MOV A,C ORA B ; Time up? JNZ MDR1 ; No, Keep trying ; REDOIT: POP H ; Go reset if none of these responses LXI H,VCNUM ; Update the voice call INR M ; Counter ENDIF ; B5IM ; IF B5IM AND DISKLOG CALL OPENLOG ; Make sure log file is on LXI H,VOCMSG CALL WRTMSG ; Put voice call message into log MVI E,0 CALL TSTHRD ; Close the log file ENDIF ; B5IM AND DISKLOG ; IF B5IM LXI H,LFMSG CALL PRINTL ; Turn up a line on crt CALL MDSTOP ; Turn dtr off while we reset JMP HANGUP1 ENDIF ; B5IM ; IF B5IM AND PRGRSS RCDISP: PUSH B PUSH H PUSH PSW ; Save A STA RCSHOW LXI H,RCSHOW ; And show results code (RC) CALL PRINTL POP PSW PUSH PSW CPI CR JNZ RCDIS1 MVI A,LF STA RCSHOW ; Force a LF after a CR LXI H,RCSHOW CALL PRINTL ; RCDIS1: POP PSW POP H POP B RET ENDIF ; B5IM AND PRGRSS ;..... ; ; IF B5IM CHECK1: LXI B,500 ; Try up to 500 ms ; CHECK2: CALL KDELAY DCX B MOV A,B ORA C JZ CHECK3 ; 500 ms is up CALL MDINST ; Character ready? JZ CHECK2 ; No, keep waiting CALL MDINP ; Yes, fetch it ANI 07FH ; And strip parity RET ; And return ; CHECK3: MVI A,0FFH ; Set error code RET ; And return ;..... ; ; SET24: CALL DLP ; 1 sec delay CALL SET2400 ; Set port to 2400 bps MVI A,BP2400 STA MSPEED ; Set speed indicator JMP FINISH ; SET3: CALL DLP CALL SET300 ; Set port to 300 baud MVI A,BP300 STA MSPEED ; Set speed indicator JMP FINISH ; SET12: CALL DLP CALL SET1200 ; Set port to 1200 bps MVI A,BP1200 STA MSPEED ; And speed indicator ; FINISH: CALL MDCARCK ; Still have carrier? JZ REDOIT ; No, reset modem POP H ; Reset CALL on the stack CALL PATCH ; Patch the jump table MVI B,1 ; 0.1 sec more CALL DLP1 ; Wait to enter terminal mode JMP ANSW ; And greet the user at his speed ;..... ; ; ; Initialize the modem for normal unattended operation. ; IMINIT: CALL DLP CALL EATALL ENDIF ; IF B5IM AND DOATZ LXI H,B5ATZ ; Reset the modem CALL IMSEND CALL DLP CALL EATALL ; Swallow the response ENDIF ; B5IM AND DOATZ ; IF B5IM LXI H,B5INIT CALL IMSEND ; Go initialize the modem ENDIF ; B5IM ; IF B5IM AND SHORTB CALL DLP CALL EATALL LXI H,B5INT1 CALL IMSEND ; Use 2 strings for short buff. modems ENDIF ; B5IM AND SHORTB ; IF B5IM AND PRGRSS IMINT1: CALL CHECK1 CPI 0FFH ; No result code? JZ IMINT2 ; Yes, inform Sysop and retry CPI '0' ; Executed ok? CZ RCDISP ; Display result code JZ IMINT3 ; And continue CPI '4' ; Modem error? CZ RCDISP JNZ IMINT1 ; Wait for a zero or four or 0FFH ; IMINT2: LXI H,CMDERR ; We have a 4 or 0FFH CALL PRINTL ; Inform Sysop of problem JMP IMINIT ; Try it again ENDIF ; B5IM AND PRGRSS AND NOT ANCHOR ; IF B5IM IMINT3: LXI H,LFMSG CALL PRINTL ; Turn up a line on crt CALL DLP CALL EATALL ; Get any garble from the modem RET ;..... ; ; ; Delay about one second to let modem get stabilized before or after a ; command string. ; DLP: MVI B,10 ; DLP1: CALL DELAY DCR B JNZ DLP1 RET ; EATALL: CALL CHECK1 CPI 0FFH ; All characters eaten? JNZ EATALL ; No, keep eating RET ;..... ; ; ; De-initiaize the modem. When the operator uses CTL-C followed by any- ; thing but "R", this call will return the modem to default settings. ; IMQUIT: LXI H,LFMSG CALL PRINTL ; Turn up a line on crt ENDIF ; B5IM ; IF B5IM AND DOATZ CALL DLP CALL EATALL LXI H,B5ATZ CALL IMSEND ; Send ATZ message to modem ENDIF ; B5IM AND DOATZ ; IF B5IM CALL DLP CALL EATALL ENDIF ; B5IM ; IF B5IM AND (NOT OFFHK) LXI H,B5USR CALL IMSEND ; Send ATS0=0 to modem CALL EATALL ENDIF ; B5IM AND NOT OFFHK ; IF B5IM AND OFFHK LXI H,B5ATH1 ; Send ATH1 to the modem CALL IMSEND ENDIF ; B5IM AND OFFHK ; IF B5IM RET ;..... ; ; ; Send a command string to the modem. (If ECHO) Verify, reset the modem ; and resend string if echo fails. ; IMSEND: PUSH B ; Save 'BC' registers SHLD ADDSTR ; Save start of command string ; IMSEN1: CALL MDOUTST ; Modem ready for character? JZ IMSEN1 ; No, go check again MOV A,M ; Get the character PUSH PSW CALL MDOUTP ; Send the character POP PSW ENDIF ; B5IM ; IF B5IM AND PRGRSS CALL RCDISP ; Display the command string ENDIF ; B5IM AND PRGRSS ; IF B5IM AND ECHO ; Hayes needs echo checking CALL CHECK1 ; Get the echo character CMP M ; Same? JNZ NOECHO ; No, let's resend entire command string ENDIF ; B5IM AND ECHO ; IF B5IM INX H ; Point to next MOV A,M ; Get next character ORA A ; Has all been sent JNZ IMSEN1 ; No, go send another character POP B ; Restore the BC registers RET ; Return past end of message ENDIF ; B5IM ; NOECHO: IF B5IM AND ECHO AND PRGRSS LXI H,NOEMSG CALL PRINTL ; Inform Sysop of echo error ENDIF ; B5IM AND ECHO AND PRGRSS ; IF B5IM AND ECHO CALL MDOUTST ; Wait for modem ready JZ NOECHO MVI A,CR CALL MDOUTP ; Force a c/r to end command string CALL DLP ; Let modem settle CALL EATALL ; Make sure input is clear LHLD ADDSTR ; Restore address of command string JMP IMSEN1 ; And send it again ENDIF ; B5IM AND ECHO ;..... ; ; IF B5IM AND NODTR IMHANG: CALL EATALL MVI B,30 ; Some modems need 3 sec, doesn't hurt ; Others CALL DLP1 ; This routine will hang up the phone LXI H,B5ESC ; Using +++ATH CALL IMSEND CALL EATALL MVI B,15 CALL DLP1 LXI H,B5ATH CALL IMSEND ; For modems without DTR support CALL DLP RET ENDIF ; B5IM AND NODTR ;..... ; ; end of B5IM code ;----------------------------------------------------------------------- ; IMDONE: CALL DELAY ; IF NOT NODTR CALL MDSTOP ; Drop DTR-***This is a new label just ; After MDQUIT that drops DTR and ; Returns. ENDIF ; NOT NODTR ; CALL MDCARCK ; Carrier? RZ ; Carrier gone, return ; IF B5IM AND NODTR CALL IMHANG ; Send +++ATH ENDIF ; B5IM AND NODTR ; JMP IMDONE ; Keep looping ; ;----------------------------------------------------------------------- ; ; If the carrier is lost - hang up, await ring. Otherwise, say goodbye, ; and hang-up. ; START0: IF TIMEON LDA TON STA LCTON ; Preserve last callers time-on for ; Entry pgm ENDIF ; TIMEON ; IF NOT CPM3 LHLD BDOS+1 ; Get beginning address of BYE5 program SHLD BDADDR ; Save address of BYE5 start ENDIF ; NOT CPM3 ; ; ; ; Patch in BYE's BDOS interceptor ; IF CPM3 LHLD STARTX+1 ENDIF ; CPM3 ; IF NOT CPM3 LHLD BEGOBJ+1 ; Get real bdos call ENDIF ; NOT CPM3 ; MOV A,H ; Get high address byte LXI D,BYERSX ; Have to do it this way to fool the ; Relocator CMP D ; Already pointed to BYERSX? JZ NORPTC ; Then don't patch again SHLD REALBD+1 ; Save it in the interceptor routine LXI H,BYERSX ; Get address of interceptor routine ; IF CPM3 SHLD STARTX+1 ; So we intercept BDOS calls ENDIF ; CPM3 ; IF NOT CPM3 SHLD BEGOBJ+1 ; Save it so it goes through our ex- ; Tended BDOS ENDIF ; NOT CPM3 ; NORPTC: XRA A ; A=0 STA MDMOFF ; Show no carrier lost STA ULCSW ; Reset upper/lower case flag STA LFEEDS ; And line feed flag STA WRTLOC ; And write-in-progress flag STA OPTION ; And option flag ; IF TIMEON AND CLOCK AND (NOT EXFILE) CALL MDCARCK CNZ RMTOS ; Report final time-on-system ENDIF ; TIMEON AND CLOCK ; ; ; Set MINICK to 'YES' if you use MINICBBS and want to take advantage of ; its feature which can prevent the modem from hanging up if the caller ; should happen to disconnect during a file update. MINICBBS sets the ; high-order bit of IOBYTE (address 0003H) to indicate a file update is ; in progress. ; IF MINICK MVI A,IOVAL ; Get proper initial value STA IOBYTE ; Set it in IOBYTE ENDIF ; MINICK ; IF MBBS LXI SP,STACK CALL MDCARCK JZ START1 ; No carrier, skip this LDA LCDATA CPI ' ' ; User logged in? JZ GOODBY ; No, carry on XRA A STA 0 ; Prep mbbs MVI A,0FFH STA WRTLOC ; To prevent hangup LDA FCB+1 CPI 'C' ; Comments requested? JZ MBBSC ; Yes, do comments ENDIF ; MBBS ; IF MBBS AND PRNTGB LXI H,GBMSG CALL PRINTB ; Say goodbye to user ENDIF ; MBBS AND PRNTGB ; IF MBBS MBBS01: CALL IMDONE ; Drop carrier and fix so phone won't JMP MBBSNC ; Answer and tell Sysop ; MBBSC: STA OPTION ; So we know to load MBBS or login LXI H,MBBS1 CALL PRINTB ; Wait for MBBS to load CALL LODCOM ; Load mbbs for comments CALL MDCARCK ; Did user wait for all this? JZ MBBSNC ; No, tell Sysop and load login MVI A,0CDH STA 0 ; So MBBS will ask for comments CALL 100H ; Now do it ; MBBSNC: LXI H,MBBS2 CALL PRINTL ; Tell Sysop about log off MVI A,0FFH STA MDMOFF ; So BYE5 will handle rest of this MVI A,'E' STA OPTION ; So BYE5 will trap MBBS return CALL LODCOM ; Load login CALL 100H ; Let login finish user stats ENDIF ; MBBS ; CALL MDCARCK ; Call modem carrier check routine JNZ GOODBY ; We have carrier, so say bye bye... ; START1: IF COMFILE LDA FCB+1 STA OPTION ; So remote cannot type BYE E MVI A,' ' STA FCB+1 ENDIF ; COMFILE ; ; ; Get the System Parameter Block address, common memory base page, ; BDOS base page for use in main program or overlays. ; IF CPM3 MVI C,GTSCB ; Return base page of SCB LXI D,SCBPB CALL BDOS SHLD SCBBASE ; Save SCB address MVI L,SCBCOM ; 0FAH = common memory base page MOV A,M STA MEMBASE ; Save common memory base page MVI L,SCBBDOS ; 99H = base page of BDOS MOV A,M STA BDOSBASE ; Save base page of BDOS system ENDIF ; CPM3 ; ; ; Identify version of program ; CALL PATCH ; Copies vectors for PRINTL CALL UNPATCH LXI H,VMSG ; Signon message CALL PRINTL ; JMP HANGUP ; We know it is local, so prepare for ; Next caller ; GOODBY: IF EXFILE JMP LOGOFF ; Run the exit file ENDIF ; EXFILE ; IF PRNTGB AND (NOT EXFILE) LXI H,GBMSG ; Goodbye message CALL PRINTB ; Print this message ENDIF ; PRNTGB AND NOT EXFILE ; IF NOT EXFILE CALL IMDONE ; Hang up the phone before doing this CALL UNPATCH ; Undo BIOS patches ENDIF ; NOT EXFILE ; ;..... ; IF DISKLOG AND (NOT EXFILE) LXI H,DSCMSG ; Disconnect message CALL WRTMSG ; Put it into log file ENDIF ; DISKLOG AND NOT EXFILE ; ; ; Nobody there, or we are done. ; HANGUP: LXI SP,STACK ; Set up local stack ; IF DISKLOG XRA A STA BDOSFL STA LOGTOG MOV E,A CALL TSTHRD ; This will close log file ENDIF ; IF CPM3 CALL DELRSX ; Remove any RSX's below BYE LXI D,DEFPW MVI C,DEFPAS CALL REALBD ; Set default password to blanks ENDIF ; CPM3 ; IF COMFILE LXI H,ENTMSG CALL PRINTL ; Show it's the entry file CALL LODCOM ; Load the .COM file ENDIF ; COMFILE ; ; ; Set drive/user, then give summary and initialize for next call ; HANGUP1:MVI A,WBDRIV ; Force next warmboot to user 0 STA 0004H ; And drive wbdriv ; IF CPM3 CALL SETDRIVE ; Set to wbdriv XRA A CALL SETUSER ; Set user to zero ENDIF ; CPM3 ; XRA A STA MDMOFF ; Clear modem status STA WRTLOC ; And wrtloc STA TON ; Reset time-on-system STA MSFLAG ; Reset status for no-activity timer ; IF RTOK STA RTOKFG ; So RBBS can be re-entered ENDIF ; RTOK ; IF CPM3 LHLD SCBBASE ; Get address of SCB MVI L,0D4H MOV M,A ; Reset ^P mode MVI L,0CAH MOV M,A ; Set CTL-H mode INR L DCR A MOV M,A ; Set RUB/DEL mode ENDIF ; CPM3 ; IF CPM3 AND CCPPLUS MVI L,0A4H MOV A,M ORI 80H ; Turn on directory name display MOV M,A ENDIF ; CPM3 AND CCPPLUS ; IF CPM3 MOV D,H MVI E,0E8H ; Point to drive search chain LXI H,DRVSRC MVI B,4 CALL MOVE ; Set the drive search chain ENDIF ; IF NO25TH OR MBBS LXI H,LFMSG CALL PRINTL LXI H,LCDATA CALL PRINTL ; Show Sysop who was just on ENDIF ; NO25TH ; IF NO25TH OR MBBS LXI H,LCDATA MVI B,NO25BF CALL ZEROM ; Fill with zeros for PRINTL LXI H,LCFILL LXI D,LCDATA MVI B,15 CALL MOVE ; Put filler msg into LASTCALR for now ENDIF ; NO25TH OR MBBS ; IF TIMEON LXI H,TONMSG CALL PRINTL ; Show him how long he was on XRA A LXI H,TONMSD CALL DEC8 ; So next message will be 0 ENDIF ; TIMEON ; IF TIMEON OR CLOCK MVI A,255 STA TCHKFG ; Show clock not read ENDIF ; TIMEON OR CLOCK ; CALL CALSUM ; Give Sysop call summary ; IF B5IM AND HS9600 CALL SET9600 ENDIF ; B5IM AND HS9600 ; IF B5IM AND HS4800 CALL SET4800 ENDIF ; B5IM AND HS4800 ; IF B5IM AND HS2400 CALL SET2400 ; Talk to the modem at its highest speed ENDIF ; B5IM AND HS2400 ; IF B5IM AND HS1200 CALL SET1200 ENDIF ; B5IM AND HS1200 ; IF B5IM AND HS300 CALL SET300 ENDIF ; B5IM AND HS300 ; CALL MDINIT ; Call modem initialization routine ; MVI A,0C3H ; Clear any traps left from .COM file STA 0 ; IF ZCPR3 MVI A,MAXDRV STA 0FE2CH ; For ZCPR3 use MVI A,MAXUSR STA 0FE2DH ; For ZCPR3 use ENDIF ; ZCPR3 ; LDA LCDFLG ORA A ; Sysop want the system? JNZ BEXCPM ; Yes, exit with bells ; IF CLRSCR CALL CLEARIT ; Clear local crt screen ENDIF ; CLRSCR ; IF COMFILE LDA OPTION CPI 'E' ; Execute comfile locally? JNZ MOTOFF ; No, continue ENDIF ; COMFILE ; ERUN: IF COMFILE AND B5IM CALL IMQUIT ENDIF ; COMFILE AND B5IM ; IF COMFILE AND (NOT B5IM) CALL MDQUIT ; Fix modem so won't answer phone ENDIF ; COMFILE AND NOT B5IM ; IF COMFILE MVI A,0FFH STA MDMOFF ; Turn modem off STA WRTLOC ; And write flag MVI A,'L'-30H STA MSPEED ; Some BBS's need this, rest don't care JMP ANSW ; Skip this ENDIF ; COMFILE ; MOTOFF: IF MOTOR CALL DSKOFF ; Turn off drives ENDIF ; MOTOR ;..... ; ; ; Await ringing - check local keyboard for CTL-C exit request. Note: ; Must do input via BDOS because CBIOS patches are not done until the ; call comes in. ; RINGWT: CALL CONSTAT ORA A JZ RINGW1 CALL VCONIN ; Character typed ANI 7FH ; Strip parity bit CPI 'C'-40H ; CTL-C? CZ USRCHK ; Check for exit CALL CKFUNC ; Check for function keys RINGW1: IF B5IM CALL IMRING ; This routine does it all JZ RINGWT ENDIF ; B5IM ; IF NOT B5IM CALL MDCARCK ; Carrier? JZ RINGWT ; No, keep looping ENDIF ; NOT B5IM ; ; ;----------------------------------------------------------------------- ; answer routine ; ANSW: IF NOT CPM3 CALL BDCHEK ENDIF ; NOT CPM3 ; IF MOTOR CALL DSKON ; Turn on drives ENDIF ; MOTOR ; IF (NOT USEZCPR) AND (ZCPR2 OR ZCPR3) MVI A,MAXUSR ; Reset maximum user area STA MXUSR ; Set it in bye INR A ; Bump it STA MAXUSER ; Set it in ZCPR MVI A,MAXDRV ; Reset maximum drive STA MXDRV DCR A STA MAXDRIV ENDIF ; ZCPR2 OR ZCPR3 AND NOT USEZCPR ; IF CHGPATH ; If external ZCPR path CALL REMPAT ; Set up the secure path for caller ENDIF ; CHGPATH ; XRA A ; Make sure line feeds are on again STA LFEEDS STA CDOFF ; Limit for waiting for c/r STA FKFLAG ; F-key lead-in flag ; IF ZCPR2 OR ZCPR3 ; Only when using ZCPR w/secure mode STA WHEEL ; Answer the phone in non-wheel mode ENDIF ; ZCPR ; MVI A,TOVALUE ; Reset timeout count STA TOVAL ; IF COMFILE LDA OPTION CPI 'E' JZ WELCOME ; Skip this if running local ENDIF ; COMFILE ; LXI H,CWCAR ; Get # of attempts INR M ; And add one ; IF B5IM JMP WELCOME ; Skip the old fashion CR detect method ENDIF ; B5IM ; IF NOT B5IM ANSWA: CALL SET300 MVI A,BP300 ; Poke in MSPEED value STA MSPEED CALL MDINP ; Clear garbage characters CALL MDINP ; ; ; Now test input for baud rate - FIRST, check for 300 baud ; ANSWB: CALL PATCH ; Patch jump table ENDIF ; NOT B5IM ; IF PRGRSS AND (NOT B5IM) LXI H,MSG30 CALL PRINTL ; Print locally ENDIF ; PRGRSS AND NOT B5IM ; IF NOT B5IM CALL TSTBAUD ; See if 300 baud JZ WELCOME ; Yes, exit ENDIF ; NOT B5IM ; ; ; Now check for 1200 bps ; IF PRGRSS AND (NOT B5IM) AND (HS1200 OR HS2400) LXI H,MSG12 CALL PRINTL ; Print locally ENDIF ; PRGRSS AND NOT B5IM ; IF (NOT B5IM) AND (HS1200 OR HS2400) CALL SET1200 ; Now check 1200 bps JNZ ANS0 MVI A,BP1200 ; Set the MSPEED pointer STA MSPEED CALL MDINP ; Clear garbage CALL TSTBAUD ; Check baud rate JZ WELCOME ENDIF ; NOT B5IM ; ANS0: IF PRGRSS AND (NOT B5IM) AND HS2400 LXI H,MSG24 CALL PRINTL ; Print locally ENDIF ; PRGRSS AND NOT B5IM ; IF (NOT B5IM) AND HS2400 CALL SET2400 ; Check for 2400 baud JNZ BADDO ; Start over MVI A,BP2400 ; Set speed indicator STA MSPEED CALL MDINP ; Clear garbage CALL TSTBAUD ; Check it JZ WELCOME ENDIF ; NOT B5IM AND HS2400 ; IF NOT B5IM BADDO: CALL UNPATCH ; Restore original jump table JMP ANSWA ; Test more - invalid baud rate ENDIF ; NOT B5IM ;..... ; IF CPM3 DRVSRC: DB SDRV1,SDRV2,SDRV3,SDRV4 ; Default drive search chain DEFPW: DB ' ' ; Default password RSXCL: DB 56 ; Subfunction to clear command line ; History from HIST RSX ENDIF ; CPM3 ; ; end of answer routine ;----------------------------------------------------------------------- ; IF NOT CPM3 BDCHEK: PUSH H ; To make truly universal, (???) this DB LXIH ; Program always re-stores the BDOS ; BDADDR: DW 0000H ; Pointer at 6 and 7 set up location for SHLD 6 ; Beginning address of CONSOLX CTL POP H ; At every chance. This replaces the RET ; WMLOCK & OLDBD as in BYE2 AND BYE3 ENDIF ; NOT CPM3 ;..... ; ; ;----------------------------------------------------------------------- ; ; Common routine to check for carrier lost - called from console out ; CHECK: IF MINICK LDA IOBYTE ; Get IOBYTE ANI 80H ; Test for disk update RNZ ; Busy, wait until done ENDIF ; MINICK ; IF HBBS OR MBBS OR QBBS OR RBBS LDA WRTLOC ; Get write in progress flag ORA A RNZ ; Busy, wait until done ENDIF ; HBBS OR MBBS OR QBBS OR RBBS ; LDA MDMOFF ORA A ; Know modem off? RNZ ; Yes, skip this CALL CARCK ; See if carrier still on RNC ; All ok ; ; ; Carrier is lost, inform Sysop ; LXI SP,STACK ; Insure valid stack LXI H,CLMSG ; Carrier lost message CALL PRINTL ; Send this Message ; IF DISKLOG XRA A STA BDOSFL LXI H,CARMSG CALL WRTMSG ; Put carrier lost msg in SYS.LOG JMP LOGOFF ; DROPIT: LXI SP,STACK ; Insure valid stack XRA A STA BDOSFL LXI H,DRPMSG CALL WRTMSG ; Put dropped message into log ENDIF ; DISKLOG ; ; ; Come here to log off a user ; LOGOFF: LXI SP,STACK ; Ensure valid stack ; IF NOT CPM3 CALL BDCHEK ; In case carrier lost in LUX ENDIF ; NOT CPM3 ; CALL PATCH ; We need this so bye is in the loop ; IF TIMEON LDA TON STA LCTON ; Preserve caller's time-on for ; Entry/exit pgm ENDIF ; TIMEON ; CALL MDCARCK JZ LOGOF1 ; Skip over goodby data ; IF NOT BYHANG JMP LOGOF2 ; Skip goodbye and hangup ENDIF ; NOT BYHANG ; IF TIMEON AND CLOCK CALL RMTOS ; Report users final timeon ENDIF ; TIMEON AND CLOCK ; IF PRNTGB LXI H,GBMSG CALL PRINTB ; Say goodbye ENDIF ; PRNTGB ; LOGOF1: MVI A,255 STA MDMOFF ; Show known loss of carrier STA TCHKFG ; Reset time flag CALL IMDONE ; Make sure phone is disconnected ; LOGOF2: IF MBBS XRA A STA FCB+1 ; Prepare to exit thru MBBS STA 0 STA MXTIME LDA LCDATA ; If user was logged in CPI ' ' JNZ MBBS01 ; User logged in so exit thru MBBS ENDIF ; MBBS ; IF EXFILE LXI H,EXTMSG CALL PRINTL ; So Sysop knows exit file is executing MVI C,SETUSR ; Select user area for EXITFILE MVI E,EXUSR CALL BDOS MVI C,SELDSK ; Select default drive for EXITFILE MVI E,EXDRV-'A' CALL BDOS CALL LODEX CALL 100H ; EXITFIL was loaded ok, so run it ENDIF ; EXFILE ; IF EXFILE AND (NOT BYHANG) CALL MDCARCK ; Still have carrier after EXFILE ran? JZ LOGOF3 ; No, skip this ENDIF ; EXFILE AND NOT BYHANG ; IF CLOCK AND TIMEON AND EXFILE AND (NOT BYHANG) CALL RMTOS ; Print time data ENDIF ; CLOCK..... ; IF PRNTGB AND EXFILE AND (NOT BYHANG) LXI H,GBMSG CALL PRINTB ; Pring goodbye ENDIF ; PRNTGB... ; LOGOF3: IF EXFIL1 OR EXFIL2 LDA MSPEED ; Flag set by HBBS ENDIF ; EXFIL1 OR EXFIL2 ; IF ANYLOS AND (EXFIL1 OR EXFIL2) CPI 44H ; Time to just backup the files? JZ ARCIVE ; Yes, go do it ENDIF ; ANYLOS AND (EXFILE1 OR EXFIL2) ; IF EXFIL1 OR EXFIL2 CPI 66H ; Time to archive?? JZ ARCIVE ; Yes, go do it ENDIF ; EXFIL1 OR EXFIL2 ; JMP PREOFF ; Prepare for next caller ; IF EXFIL1 OR EXFIL2 ARCIVE: CALL MDINIT ; Hang up and initialize modem CALL IMQUIT ; Set offhook among other things MVI A,0FFH STA MDMOFF ; Blank the modem for now ENDIF ; EXFIL1 OR EXFIL2 ; ARCIVE1: IF EXFIL1 LXI H,EX1MSG CALL PRINTL ; So Sysop knows exit file 1 is executing LXI SP,STACK ; Insure valid stack CALL SETDU CALL LODEX1 CALL 100H ; Exit file 2 was loaded ok, so run it ENDIF ; EXFIL1 ; IF EXFIL2 LDA MSPEED ENDIF ; EXFIL2 ; IF EXFIL2 AND ANYLOS CPI 44H ; Just doing a backup this time? JZ ARCIVE2 ; If yes, exit ENDIF ; EXFIL2 AND ANYLOS ; IF EXFIL2 LXI H,EX2MSG CALL PRINTL LXI SP,STACK ; Insure valid stack ENDIF ; EXFIL2 ; IF EXFIL2 AND NOT RAMDSK CALL LODEX2 JNZ ARCIVE2 CALL 100H ENDIF ; EXFIL2 AND NOT RAMDSK ; IF EXFIL2 AND RAMDSK CALL SETDU1 CALL LODEX2 JNZ ARCIVE2 CALL 100H LXI H,EX3MSG CALL PRINTL LXI SP,STACK ; Insure valid stack CALL LODEX3 ; Copy files back to the original D/U CALL 100H ENDIF ; EXFIL2 AND RAMDSK ; ARCIVE2:MVI A,07FH ; Reset the flag for no maintenance STA MSPEED JMP PREOFF ; Prepare for next caller ;..... ; ; IF EXFIL1 SETDU: MVI C,SETUSR ; Select set user BDOS call MVI E,EXUSR ; Select user area same as for EXIT file CALL BDOS MVI C,SELDSK ; Select set drive BDOS call MVI E,EXDRV-'A' ; Select drive same as for EXIT file CALL BDOS RET ENDIF ; EXFIL1 ;..... ; ; IF EXFIL2 AND RAMDSK SETDU1: MVI C,SETUSR ; Select set user BDOS call MVI E,BCKUPUS ; <<== user area for backup files CALL BDOS MVI C,SELDSK ; Select drive used for backup files MVI E,BCKUPDR-'A' ; <<== drive for backup files CALL BDOS RET ENDIF ; EXFIL2 AND RAMDSK ;..... ; ; ;----------------------------------------------------------------------- ; ; Function key routines ; CKFUNC: IF LEADIN PUSH PSW ; Save character CPI LEADKY ; Lead-in key typed? JNZ FKEY1 ; No, see if already typed MVI A,0FFH ; Yes, set the lead-in flag STA FKFLAG POP PSW ; Reset stack MVI A,07FH ; DEL for buffer RET ; FKEY1: LDA FKFLAG ORA A ; Lead-in already typed? JZ FKEXIT ; No, exit XRA A ; Yes, reset the flag STA FKFLAG POP PSW ; Get char back ANI 1FH ; Make it a ctrl character ENDIF ; LEADIN ; IF B5IM AND (NOT NOATA) MOV B,A PUSH B ; Save the character CALL MDCARCK ; Carrier? POP B MOV A,B JNZ ANSKNO ; Can't do this with carrier CPI ANSKEY ; Sysop wants BYE to answer the phone CZ IMRIN2 ; So do it, IMRIN2 will restore the call ; ANSKNO: ENDIF ; B5IM AND NOT NOATA ; IF NO25TH OR MBBS CPI WHOKEY JZ WHOSIT ; Display last caller data ENDIF ; NO25TH OR MBBS ; IF TIMEON CPI TIMEKEY JZ DTIME ; Case running local, allow debug ENDIF ; TIMEON ; CPI ZCREEN JZ CLEARIT ; Sysop wants to clear his screen CPI BELLKEY JZ BELLTOG ; Toggle bell on/off ; IF DISKLOG CPI LOGKEY JZ LOGFLP ; Toggle disk log on/off ENDIF ; DISKLOG MOV B,A PUSH B CALL MDCARCK ; See if carrier is on, because POP B MOV A,B RZ ; The following keys are useless without ; It. CPI LCKEY JZ LCDOIT ; Sysop wants the system when caller is thru CPI ULTKEY JZ ULTIME ; Give current user unlimited timeon CPI BLNKKEY ; Turn off caller's output for a moment? JZ BLNKTOG ; (this is a toggle) CPI SYSDKEY JZ SYSDOWN ; Tell caller system is going down CPI TWITKEY PUSH PSW CZ IMDONE ; Hang up on the twit POP PSW ; IF NOT DISKLOG JZ LOGOFF ; Then check for exit file ENDIF ; NOT DISKLOG ; IF DISKLOG JZ DROPIT ; Hang up on the twit ENDIF ; DISKLOG ; CPI MSGKEY RNZ ; ; ; Message from Sysop ; LXI H,MFSMSG ; SYSOP message CALL PRINTB ; Tell caller you want to say something ; SYSML: CALL VCONIN ; Get key from Sysop CPI XITKEY ; If exit key, exit loop JZ SYSMX MOV C,A ; Else echo to console and modem PUSH PSW CALL MOUTPUT POP PSW CPI 'H'-'@' ; If BS, do BS/SP/BS JZ SYSMBS CPI CR ; If CR, do CRLF JZ SYSMCR JMP SYSML ; SYSMCR: MVI C,LF ; Do linefeed after CR JMP SYSECH ; SYSMBS: MVI C,' ' CALL MOUTPUT MVI C,'H'-'@' ; SYSECH: CALL MOUTPUT JMP SYSML ; SYSMX: MVI C,CR ; Do crlf CALL MOUTPUT MVI C,LF CALL MOUTPUT CALL MDINP CALL MDINP ; Clear caller junk first MVI A,CR ; Return with c/r for buffer RET ;..... ; ; ; System Going down ; SYSDOWN:LXI H,SGDMSG ; System going down message CALL PRINTB ; Send this message ; IF TIMEON CALL TCHECK ; Calculate current time-on-system LDA TON ; Fetch it ADI DOWNMIN ; Give him this much longer STA MXTIME ; And BYE will log him off ENDIF ; TIMEON ; MVI A,CR ; Return with CR for buffer RET ;..... ; LCDOIT: LXI H,LCDMSG CALL PRINTL ; Show sysop it's flagged MVI A,07FH STA LCDFLG ; Set the flag RET ; ; ; Toggle bell ; BELLTOG:LDA BELLON ; Get bell status ORA A MVI A,0FFH ; Prepare for on LXI H,BELMON JZ BELLT1 ; Go turn bell on XRA A ; Else turn bell off LXI H,BELMOFF ; BELLT1: STA BELLON ; IF LMBELL ORA A JZ BELLT2 ; We will toggle whatever we just stored XRA A JMP BELLT3 BELLT2: MVI A,0FFH ; BELLT3: STA KILBEL ; For MBBS/RBBS etal ENDIF ; LMBELL ; CALL PRINTL ; Print status message locally MVI A,07FH ; DEL for buffer RET ;..... ; ; ULTIME: XRA A STA MXTIME ; Give current caller unlimited time MVI A,0FFH STA LCPTR ; Also enable all the flag bits LXI H,ULTMSG CALL PRINTL ; So Sysop will know MVI A,CR ; C/R for buffer RET ; ; ; Toggle blankout ; BLNKTOG:LDA MDMOFF ORA A ; If zero, make 0FFH ; IF ZCPR2 OR ZCPR3 JZ DUSET ; Store Sysops d/u values CALL RETDU ; Restore normal d/u values ENDIF ; ZCPR2 OR ZCPR3 ; IF (NOT ZCPR2) AND (NOT ZCPR3) MVI A,0FFH ; (we do not use CMA, because MDMOFF LXI H,SCRMOFF JZ BLNKT1 ; Could equal a different value like 1) XRA A ; If not zero, make it zero LXI H,SCRMON ENDIF ; NOT ZCPR2 AND NOT ZCPR3 ; BLNKT1: STA MDMOFF ; IF ZCPR2 OR ZCPR3 STA WHEEL ; Set wheel for Sysop ENDIF ; ZCPR2 OR ZCPR3 ; CALL PRINTL MVI A,CR ; Return with cr for buffer RET ;..... ; ; DUSET: IF ZCPR3 MVI A,SYSUSR ; Sysops maxuser STA 0FE2DH ; To low memory MVI A,SYSDRV ; Sysops maxdriv STA 0FE2CH ; To low memory ENDIF ; ZCPR3 ; IF ZCPR2 OR ZCPR3 LDA LCPTR STA CDOFF ; Save flag register ENDIF ; ZCPR2 OR ZCPR3 ; IF CHGPATH CALL SYSPAT ; Setup Sysops path ENDIF ; CHGPATH ; IF ZCPR2 OR ZCPR3 MVI A,0FFH ; Wheel on, modem off STA LCPTR ; Enable all options LXI H,SCRMOFF ; Correct message JMP BLNKT1 ; RETDU: LDA MXUSR ; Callers allowed maxuser INR A STA MAXUSER ; To low memory LDA MXDRV ; Callers allowed maxdriv DCR A STA MAXDRIV ; To low memory LDA CDOFF STA LCPTR ; Restore flag register ENDIF ; ZCPR2 OR ZCPR3 ; IF CHGPATH CALL REMPAT ; Setup remote users path ENDIF ; CHGPATH ; IF ZCPR2 OR ZCPR3 XRA A ; Wheel off, modem on LXI H,SCRMON ; Correct message RET ENDIF ; ZCPR2 OR ZCPR3 ; IF NO25TH OR MBBS WHOSIT: LXI H,CRMSG ; Turn up a fresh line CALL PRINTL LXI H,LCHEAD ; Print customized header (if any) CALL PRINTL LXI H,LCDATA CALL PRINTL ; Show Sysop lastcaller data LXI H,CRMSG CALL PRINTL ; New line for neatness MVI A,07FH ; DEL for buffer RET ENDIF ; NO25TH OR MBBS ;..... ; ; IF TIMEON DTIME: CALL TCHECK ; Read time LXI H,LFMSG CALL PRINTL LDA MXTIME ORA A JZ DTIME1 ; Unlimited time LXI H,TLNMSG ; Else print time-left... ENDIF ; TIMEON ; IF TIMEON AND (ZCPR2 OR ZCPR3) LDA WHEEL ORA A JNZ DTIME1 ; Unlimited time ENDIF ; TIMEON AND ZCPR2 OR ZCPR3 ; IF TIMEON JMP DTIME2 DTIME1: LXI H,TONMSG DTIME2: CALL PRINTL ; Print time-on or time-left-on system LXI H,LFMSG CALL PRINTL MVI A,07FH ; DEL for buffer RET ENDIF ; TIMEON ;..... ; ; CLEARIT:LXI H,CLRSEQ CALL PRINTL ; Clear local screen MVI A,LF RET ; LF for buffer ; IF LEADIN FKEXIT: POP PSW RET ENDIF ; LEADIN ;..... ; ; end of function key routines ;------------------------------------------------------------------------ ; ; BYE's BDOS interceptor (See BYE5.DOC for more information) ; REALBD: JMP 0 ; Will be filled in to pnt to REAL BDOS ; BYERSX: ; IF DISKLOG MOV A,C CPI 15 ; Is it file open? JNZ NOT15B LDA LOGTOG ; Are we to toggle log file? ORA A JZ NOT15 PUSH D CALL LOGFLP ; Open/close log file POP D XRA A STA LOGTOG ; Reset toggle JMP NOT15A NOT15: LDA DSKLOG ; Get log status ORA A JZ NOT15A ; Skip if not open PUSH D ; Save callers FCB address CALL SETLUS ; Set up the log environment LXI D,LOGFCB MVI C,16 CALL REALBD ; Update directory for log file CALL CLRLUS ; Back to normal environment POP D ; Restore callers FCB address NOT15A: MVI C,15 ; Restore open function code NOT15B: CALL STBDOS ; Set bdos call in progress flag LDA DSKLOG ORA A ; Is log on? MOV A,C ; Get the function JZ NOLOGTEST ; Skip tests if log is off ENDIF ; DISKLOG ; IF DISKLOG AND CPM3 CPI 98 ; Is it free blocks (only called by CCP) JNZ NOT98 CALL SETLUS ; Set up log file environment LXI D,LOGFCB MVI C,16 CALL REALBD ; Update directory entry for file CALL CLRLUS ; Return to normal environment MVI C,98 JMP REALBD ; And on to BDOS NOT98: CPI 13 ; Is it disk reset? JNZ NOT13 LXI D,80H MVI C,26 CALL REALBD ; First set DMA to default MVI E,0 MVI C,14 CALL REALBD ; Next select disk A: LXI D,0FFFFH ; Reset all drives MVI C,37 MOV A,C NOT13: CPI 37 ; Is it reset drives? JNZ NOT37 MOV A,E ANI 0FEH ; Do not reset drive A: MOV E,A JMP REALBD NOT37: ENDIF ; DISKLOG AND CPM3 ; IF DISKLOG AND (NOT CPM3) CPI 13 ; Is it Disk reset? JNZ NOT13 CALL SETLUS ; Set up log file environment LXI D,LOGFCB MVI C,16 CALL REALBD ; Update directory entry for file CALL CLRLUS ; Return to normal environment MVI C,13 JMP REALBD ; And on to BDOS NOT13: ENDIF ; DISKLOG AND NOT CPM3 ; IF DISKLOG CPI 1 ; Console input? JNZ NOT1 CALL REALBD ; Get the char JMP HARDWR ; And on to log write routine NOT1: CPI 6 ; Direct console I/O? JNZ NOT6 MOV A,E ; Get direct console I/O function INR A ; Only intercept 0FFh JNZ REALBD CALL REALBD ; Get the char ORA A ; Anything there? RZ ; Back to caller if nothing ; HARDWR: ; Save char in log file CALL STKNEW ; Switch to local stack PUSH PSW ANI 7FH CALL WRBYTE ; Write the character CPI CR ; Is it return? JNZ HARRET MVI A,LF ; If CR, must also put LF in log file CALL WRBYTE HARRET: POP PSW ; Restore original character RET ; NOT6: CPI 10 ; Is it input console buffer? JNZ NOLOGTEST PUSH D ; Save address of buffer CALL REALBD ; Fill the buffer POP H INX H ; Point to length MOV A,M ; Get length ORA A RZ ; Return if nothing there CALL STKNEW ; Switch to local stack PUSH H CALL WRTTIM ; Time stamp the line POP H MOV B,M ; Get length INX H B10LOP: ; Loop to write the log file MOV A,M CALL WRBYTE ; Send a byte to log INX H DCR B JNZ B10LOP JMP WRCRLF ; Exit with final CRLF ; NOLOGTEST: ENDIF ; DISKLOG ; IF DISKLOG AND (NOT CPM3) CPI 26 ; Is it set DMA? JNZ NOTDMA XCHG SHLD OLDDMA ; Keep a copy of current DMA XCHG JMP REALBD NOTDMA: ENDIF ; DISKLOG AND NOT CPM3 ; MOV A,C ; BDOS doesn't care if we use 'A' CPI 32 ; Is it USER command? JZ TSTUSR CPI LOCMD ; Is it less than lowest BYE command? JC REALBD CPI HICMD+1 ; Is it higher than the highest BYE ; Command? JNC REALBD ; ; ; Ok, it's one of our commands, Let's handle it ; SUI LOCMD ; Commands now range from 0..highcommand PUSH D MOV E,A ; Save copy of command in A ADD A ; A=2*A ADD E ; A=3*A 3x offset for each vector MOV E,A ; Make command offset 16-bits MVI D,0 ; DE = offset into table LXI H,RSXTBL DAD D ; HL points to entry in RSXTBL now POP D MOV A,E ; Generalized movement of input data PCHL ; Jump to entry in rsx table ; RSXTBL: JMP MDINST ; Get modem input status 61 JMP MDOUTST ; Get modem output status 62 JMP MDOUTP ; Output character to modem 63 JMP MDINP ; Input character from modem 64 JMP MDCARCK ; Get modem carrier status 65 JMP CONSTAT ; Get console input status 66 JMP CONIN ; Get console input character 67 JMP RCONOT ; Send character to console 68 JMP RMXDRV ; Set/get maximum drive 69 JMP RMXUSR ; Set/get maximum user area 70 JMP RMTOUT ; Set/get timeout value 71 JMP RMNULL ; Set/get nulls 72 JMP RMULC ; Set upper/lower case flag 73 JMP RMLFM ; Set line feed mask 74 JMP RMWRT ; Set/get wrtloc flag 75 JMP RMHDR ; Set/get hardon flag 76 JMP RMOFF ; Set/get mdmoff flag 77 JMP RMBELL ; Set/get console bell flag 78 JMP RMRTC ; Call TCHECK & return TON & RTC address 79 JMP RMLCBF ; Return LC buffer address 80 JMP RMMXT ; Set/get maximum time on system 81 JMP RMLTIM ; Set login time 82 JMP RMTOS ; Print TOS message to caller/Sysop 83 JMP SRUDEF ; SubRoutine U, the user DEFines 84 JMP RMXLCP ; Set/get LCPTR. When a user is logged 85 ; In, LCPTR is a bit mapped status ; Register. If no user is logged in, ; LCPTR contains previous callers Timeon JMP LOGSTAT ; Set/get log open status 86 JMP LOGPUT ; Write a string into log file 87 JMP IMDONE ; Hangup phone and return to calling pgm 88 ; ; ; BYE existance test ; TSTUSR: MOV A,E ; Get E register value CPI 241 ; Special call for extended BDOS? JNZ REALBD ; No, was for normal BDOS MVI A,77 ; Was for us, say we're here RET ; RCONOT: MOV C,E ; Get byte to send JMP VCONOUT ; RMXDRV: LXI H,MXDRV ; Set/get maximum drive ;;;;&&&&&&&&&&&&&&&&&&&&&&&&&&&&& shld 0010h JMP SETGET1 ; RMXUSR: LXI H,MXUSR ; Set/get maximum user area ;;;;&&&&&&&&&&&&&&&&&&&&&&&&&&&&& shld 0012h JMP SETGET1 ; RMNULL: LXI H,NULLS ; Set/get nulls JMP SETGET1 ; RMTOUT: LXI H,TOVAL ; Set/get timeout value JMP SETGET1 ; RMULC: LXI H,ULCSW ; Set/get upper-lowercase flag JMP SETGET1 ; RMLFM: LXI H,LFEEDS ; Set/get line-feed mask JMP SETGET2 ; RMHDR: LXI H,HARDON ; Set/get hard-log JMP SETGET2 ; RMWRT: LXI H,WRTLOC ; Set/get RBBS WRTLOC flag JMP SETGET2 ; RMOFF: LXI H,MDMOFF ; Set/get modem-off flag JMP SETGET2 ; RMBELL: LXI H,BELLON ; Set/get console-bell flag JMP SETGET2 ; RMRTC: IF TIMEON CALL TCHECK ; TCHECK returns TON with/without clock ENDIF ; TIMEON ; IF CLOCK AND (NOT TIMEON) CALL TIME ; In case caller just wants time ENDIF ; CLOCK AND NOT TIMEON ; LDA TON LXI H,RTCBUF ; Return address of RTC buffer RET ; RMXLCP: LXI H,LCPTR ; Address of LCPTR INR A ; If (255), return current value JZ SGET1 ; So do it MOV M,D ; If (A)<>255, store (D) in LCPTR (0-255) RET ; RMLCBF: LXI H,LCDATA ; Return address of LC data buffer RET ; RMMXT: LXI H,MXTIME ; Set/get maximum time allowed on system JMP SETGET1 ; RMLTIM: STA LMIN ; Set login time MOV A,D STA LHOUR RET ; RMTOS: IF TIMEON ; Only do this if we can..otherwise RET CALL TCHECK ; Set time in message LDA MXTIME ORA A JZ RMTOS1 ; Unlimited time LXI H,TLNMSG ; Else print time-left... ENDIF ; TIMEON ; IF TIMEON AND (ZCPR2 OR ZCPR3) LDA WHEEL ORA A JNZ RMTOS1 ; Unlimited time ENDIF ; TIMEON AND ZCPR2 OR ZCPR3 ; IF TIMEON JMP RMTOS2 RMTOS1: LXI H,TONMSG RMTOS2: CALL PRINTB ; Print it ENDIF ; TIMEON RET ;..... ; ; ; SETGET1 - if A=0..254 then poke value with A ; - if A=255 then return with current value ; SETGET1:INR A ; If A was 255, Z flag will now be set JZ SGET1 ; We want to get current value DCR A MOV M,A ; No, set current value ;;;;&&&&&&&&&&&&&&&&&&&&&&&&&&&&& sta 0014h RET ; SGET1: MOV A,M ; Return with current value in A ;;;;&&&&&&&&&&&&&&&&&&&&&&&&&&&&& sta 0015h RET ;..... ; ; ; SETGET2 - if A=0 then poke value with 0 ; - if A=1 then poke value with 255 ; - if A=255 then return with current value ; SETGET2:INR A ; If A was 255, Z flag will now be set JZ SGET1 ; We want to get current value DCR A ; If it's zero, then poke a zero JZ SGET2W MVI A,255 ; Else poke a 255 ; SGET2W: MOV M,A RET ;..... ; ; ;----------------------------------------------------------------------- ; CONIN: PUSH B PUSH D PUSH H CALL VCONIN CALL CKFUNC POP H POP D POP B RET ;..... ; ; ;----------------------------------------------------------------------- ; CONOUT: PUSH B PUSH D PUSH H MOV A,C ANI 07FH CNZ VCONOUT ; Don't send nulls to local console POP H POP D POP B RET ;..... ; ; ;----------------------------------------------------------------------- ; CONSTAT:PUSH B PUSH D PUSH H CALL VCONSTAT POP H POP D POP B RET ;..... ; ; ;----------------------------------------------------------------------- ; ; .1 sec delay routine ; DELAY: PUSH B LXI B,4167*MHZ ; Timing constant * clock MHz ; DELAY1: DCX B MOV A,B ORA C JNZ DELAY1 POP B RET ;..... ; ; ; 1 millisecond delay routine ; KDELAY: PUSH B LXI B,42*MHZ ; Timing constant * clock MHz JMP DELAY1 ;..... ; ; ;----------------------------------------------------------------------- ; ; Here to exit to CP/M, first reset the Port/Modem to default status ; BEXCPM: LXI H,BELMSG ; Sysop typed LCKEY so alert him that CALL PRINTL ; The system is his ; EXCPM: IF B5IM CALL IMQUIT ; Send ATS0=0 or ATH1M0 but keep DTR high ENDIF ; B5IM ; IF NOT B5IM CALL MDQUIT ; Exit with DTR low ENDIF ; NOT B5IM ; IF MOTOR CALL DSKON ; Turn on drives ENDIF ; MOTOR ; IF DISKLOG MVI E,0 CALL TSTHRD ; Make sure log file is closed ENDIF ; DISKLOG ; LHLD REALBD+1 ; Get real bdos vector ; IF CPM3 SHLD STARTX+1 ; Restore for cpm3 exit ENDIF ; CPM3 ; IF NOT CPM3 SHLD BDOS+1 ; Save it so CP/M doesn't crash ENDIF ; NOT CPM3 ; IF ZCPR2 OR ZCPR3 MVI A,0FFH STA WHEEL ; Restore wheel byte for SYSOP ENDIF ; ZCPR2 OR ZCPR3 ; IF ZCPR3 MVI A,SYSUSR STA 0FE2DH ; And MAXUSR MVI A,SYSDRV STA 0FE2CH ; And MAXDRIV ENDIF ; ZCPR3 ; IF CHGPATH ; If external zcpr path CALL SYSPAT ; Setup Sysop's path ENDIF ; CHGPATH ; IF ZCPR3 CALL DOZ3 ; ZCPR3 re-initialization ENDIF ; ZCPR3 ; IF CPM3 CALL RSXCLR ; Unload this RSX ENDIF ; CPM3 ; CALL UNPATCH ; And then... MVI A,0C3H STA 000H ; Reset in case running local JMP 0000H ; Warm boot CP/M ;..... ; ; ; ZCPR3 command line buffer, shell stack, TCAP stuff ; IF ZCPR3 DOZ3: LHLD Z3CL ; Z3CL is the address of the MCLB MVI M,0 ; ; ; Command line done, now do shell stack ; LXI H,SHSTK ; SHSTK is the addr of the Shell Stack CALL ZERO128 ; ; ; Now initialize TCAP ; LXI H,Z3ENV+128 ; Z3ENV is the address of the Environ- CALL ZERO128 ; Ment Descriptor...the TCAP is the ; Second 128 bytes ; ; ; Also clean up message buffers ; LXI H,Z3MSG ; Z3MSG is the addr of the msg buffers MVI B,80 CALL ZEROM RET ;..... ; ; ; Routine to zero memory blocks ; ZERO128:MVI B,128 ENDIF ; ZCPR3 ; ZEROM: MVI M,0 INX H DCR B JNZ ZEROM RET ;..... ; ; ;----------------------------------------------------------------------- ; ; Loss of carrier test and drive/user validation ; CARCK: IF LMBELL LDA KILBEL CMA STA BELLON ; Counteract MBBS foolishness ENDIF ; LMBELL ; LDA MDMOFF ORA A ; Known loss? JNZ CARCK2 ; Yes, allow d/u check locally ; IF EXFIL1 OR EXFIL2 LDA MSPEED ; Check for archiving on ENDIF ; EXFIL1 OR EXFIL2 ; IF ANYLOS AND (EXFIL1 OR EXFIL2) CPI 44H ; Just backing up files? RZ ; Yes, skip carrier check for now ENDIF ; ANYLOS AND (EXFIL1 OR EXFIL2) ; IF EXFIL1 OR EXFIL2 CPI 66H ; Backing up files plus updating? RZ ; Yes, skip carrier check for now ENDIF ; EXFIL1 OR EXFIL2 ; CALL MDCARCK ; Carrier there? JNZ CARCK2 ; Yep, go onto other checks... PUSH B ; Preserve so we can use it MVI B,CLOSS*10 ; Set for 'CLOSS' seconds ; CARLP: CALL DELAY ; Wait .1 seconds CALL MDCARCK ; Check for carrier MOV A,B ; Get count back in a POP B ; Fix stack in case all is ok JNZ CARCK2 ; Got carrier, continue on DCR A ; Count time down STC ; In case this is the end of 'time' RZ ; Return if timed out ; PUSH B ; Preserve 'BC' MOV B,A ; Get counter value in 'B' JMP CARLP ; Keep checking ; ; ; Now test drive #'s and (if CP/M 2.x) user #'s to insure that maximums ; are not exceeded. ; CARCK2: IF USEZCPR AND (ZCPR2 OR ZCPR3) LDA MAXDRIV INR A STA MXDRV LDA MAXUSER ; Get it from ZCPR/ZCMD DCR A ; Drop it one STA MXUSR ; Save it in bye ENDIF ; USEZCPR ; IF (NOT USEZCPR) AND (ZCPR2 OR ZCPR3) LDA MXDRV ; Older versions did not do this if DCR A ; Wheel was set -- BAD KARMA STA MAXDRIV LDA MXUSR ; Get it from BYE INR A ; Bump it STA MAXUSER ; Save it in ZCPR ENDIF ; NOT USEZCPR ; IF CHEKDU LDA 0004H ; Check disk/user # ANI 0FH ; Isolate drive PUSH H ; Save 'HL' LXI H,MXDRV ; Point to allowed # of drives CMP M ; Valid drive? JC CARCK3 ; Yes, skip this junk LDA 0004H ; Get whole login byte ANI 0F0H ; Retain user # ORI WBDRIV ; And force drive to wbdriv STA 0004H ; Update login byte ENDIF ; CHEKDU ; IF CPM3 AND CHEKDU MVI A,WBDRIV ; Zero drive message CALL SETDRIVE ENDIF ; CPM3 AND CHEKDU ; IF CHEKDU LXI H,IDMSG ; Incorrect Drive Message CALL PRINTB ; Tell user what he did JMP 0000H ; Warm boot ;... ; ; CARCK3: LDA 0004H ; Get login byte ANI 0F0H ; Isolate user # RRC ; Move to low bits RRC RRC RRC LXI H,MXUSR ; Point to maximum user number CMP M ; Valid user #? JC CARCK4 ; Yes, don't change JZ CARCK4 LDA 0004H ; Get login byte again ANI 0FH ; Keep drive, zero user area STA 0004H ; Update login byte ENDIF ; CHEKDU ; IF CPM3 AND CHEKDU XRA A ; Zero user request CALL SETUSER ENDIF ; CPM3 AND CHEKDU ; IF CHEKDU LXI H,IUMSG ; Invalid User message CALL PRINTB ; Tell him what happened JMP 0000H ; Warm boot ;... ; ; CARCK4: POP H ; Restore 'HL' ENDIF ; CHEKDU ; ORA A RET ;..... ; ; ;----------------------------------------------------------------------- ; print routines ; ; The following code has been modified to accomodate the automatic ; loader. (The loader may modify a constant, so all messages have been ; placed at the end of the program and just moved to high memory.) ; ; Print on both consoles ** USE ONLY IF IN PATCHED MODE ** ; PRINTB: PUSH B ; Save BC PUSH PSW ; And status regs ; PRBL: MOV C,M ; Get character CALL MOUTPUT ; Output it INX H ; Point to next character MOV A,M ; Test for end of message ORA A JNZ PRBL POP PSW ; Restore status regs POP B ; Restore BC RET ;..... ; ; ; Print locally only ; PRINTL: PUSH B ; Save BC PUSH PSW ; And status regs ; IF RVIDEO CALL MDCARCK ; Carrier on? JZ PRLL ; No, skip reverse video sequence PUSH H ; Save original string address LXI H,RVIDON CALL PRTREV ; Print reverse-on sequence POP H ; Restore original string ENDIF ; RVIDEO ; PRLL: MOV C,M ; Get character CALL CONOUT ; Output it INX H ; Point to next character MOV A,M ; Test for end of message ORA A JNZ PRLL ; IF RVIDEO CALL MDCARCK ; Carrier on? LXI H,RVIDOFF CNZ PRTREV ; Yes, send the reverse-off sequence ENDIF ; RVIDEO ; POP PSW ; Restore status regs POP B ; Restore BC RET ; IF RVIDEO PRTREV: MOV C,M CALL CONOUT ; Send the character INX H MOV A,M ORA A ; End of string? RZ ; Yes, exit JMP PRTREV ; Else keep sending ENDIF ; RVIDEO ; ;..... ; ; ;----------------------------------------------------------------------- ; LISTOUT:PUSH B PUSH D PUSH H PUSH PSW ; IF NOT CPM3 CALL BDCHEK ENDIF ; NOT CPM3 ; MOV C,A CALL VLISTOUT POP PSW POP H POP D POP B RET ;..... ; ; ;--------------------------------------------------------------------------- IF DISKLOG ; ; ; Toggle disk log on/off ; ; LOGFLP: LDA BDOSFL ORA A ; Are we in BDOS function? JZ LOGFLP1 ; Ok to proceed if not STA LOGTOG ; Otherwise, save toggle flag MVI A,07FH ; DEL for buffer RET ; And exit LOGFLP1: CALL STKNEW ; Switch to local stack LXI H,DSKLOG MOV A,M ORA A ; What is the status? JZ OPENLOG XRA A JP CLSHRD ; Go and close it OPENLOG: LXI H,DSKLOG OPNHRD: INR M DCR M MVI A,07FH RNZ ; Return if already open ORI 0FFH MOV M,A ; Set the flag CALL OPNLOG ; Open the log file LXI H,OPNMSG CALL PRINTL ; Tell sysop log file is open MVI A,07FH ; DEL for buffer RET TSTHRD: ; Close/open request via BDOS MOV A,E ; Get request state LXI H,DSKLOG ORA M ; Both zero? RZ ; Return if already closed CALL STKNEW ; Switch to local stack MOV A,E ORA A JNZ OPNHRD ; Jump if to open CLSHRD: MOV M,A ; Reset log flag CALL WRCRLF ; Write final cr,lf CALL CLSLOG ; Close the log file LXI H,CLSMSG CALL PRINTL ; Tell sysop log file is closed MVI A,07FH ; DEL for buffer RET ;..... ; ; ; Log file routines ; CLSLOG: ; Close the log file MVI A,26 CALL WRBY ; Put EOF into log file CALL WRITE ; Write the last sector CALL SETLUS ; Set to log user LXI D,LOGFCB MVI C,16 CALL REALBD ; Close the log file JMP CLRLUS ; Reset current user number ; OPNLOG: ; Open the log file CALL SETLUS ; Set to log user XRA A STA WOFFSET ; Init log write offset LXI H,LOGFCB+12 LXI D,LOGFCB+13 MVI M,0 MVI B,23 CALL MOVE ; Clear SYS.LOG FCB to zeros LXI D,LOGFCB MVI C,15 CALL REALBD ; Attempt to open SYS.LOG file INR A ; Any errors ? JNZ NOLOGMAKE ; No need to create new file if exists LXI D,LOGFCB MVI C,22 CALL REALBD ; Create new SYS.LOG file NOLOGMAKE: LXI D,LOGFCB MVI C,35 CALL REALBD ; Determine SYS.LOG file size LHLD LOGFCB+33 ; Get the file size MOV A,H ORA L ; Is it zero? JZ CLRLUS ; All set up if empty DCX H ; Point to last record SHLD LOGFCB+33 ; Put it back LXI D,LOGFCB MVI C,33 CALL REALBD ; Read the last record LXI B,128 ; Init offset and counter MVI A,26 ; Just a CTRL-Z (eof marker) LXI H,RECORD ; Point to start of record FINDEOF: CMP M ; Is it EOF? JZ FOUNDEOF INX H INR B DCR C JNZ FINDEOF ; Loop through last record DCR B ; If not found, assume end of record FOUNDEOF: LXI H,WOFFSET ; Point to SYS.LOG write offset MOV M,B ; Save write offset JMP CLRLUS ENDIF ; DISKLOG ; IF DISKLOG AND CPM3 SETLUS: ; Set to log file user LHLD SCBBASE MVI L,0E0H MOV A,M ; Get current user number LXI D,OLDLUS STAX D ; Save it MVI M,LOGUSR ; Set to log user MVI L,0E6H INX D MOV A,M ; Get current multi-sector count MVI M,1 ; Set multi-sector count to 1 STAX D ; Save old multi-sector count MVI L,0D8H ; Point to current DMA INX D MOV A,M ; Get low DMA STAX D INR L INX D MOV A,M ; Get high DMA STAX D LXI D,RECORD MVI C,26 JMP REALBD ; Set DMA and return via BDOS ; CLRLUS: ; Return to current user # LHLD SCBBASE MVI L,0E0H LXI D,OLDLUS ; Point to save area LDAX D ; Get old user # MOV M,A ; Restore it MVI L,0E6H INX D LDAX D ; Get old multi-sector count MOV M,A ; Restore it INX D XCHG MOV E,M ; Get old DMA low INX H MOV D,M ; Get old DMA high MVI C,26 JMP REALBD ; Set old DMA and return via BDOS ENDIF ; DISKLOG AND CPM3 ; IF DISKLOG AND (NOT CPM3) SETLUS: ; Set up Log file environment MVI E,255 MVI C,32 CALL REALBD ; Get current user number STA OLDLUS ; Save it MVI E,LOGUSR MVI C,32 CALL REALBD LXI D,RECORD MVI C,26 JMP REALBD ; Set the DMA and return via BDOS ; CLRLUS: ; Restore current environment LDA OLDLUS ; Get old user number MOV E,A MVI C,32 CALL REALBD ; Restore old user number LHLD OLDDMA ; Get old DMA address XCHG MVI C,26 JMP REALBD ; Set the old DMA and return via BDOS ENDIF ; DISKLOG AND NOT CPM3 ; IF DISKLOG ADDHLA: ADD L MOV L,A RNC INR H RET ; WRBYTE: ; Write a byte to log file PUSH H PUSH D PUSH B PUSH PSW CPI ' ' ; Is it printable? JNC WROK ; Jump if ok CPI CR ; CR ? JZ WROK CPI LF ; LF ? JZ WROK CPI 8 ; BACK SPACE ? JZ WROK MVI A,'^' CALL WRBY ; Write control char prefix POP PSW PUSH PSW ADI 40H ; Make it printable WROK: CALL WRBY POP PSW POP B POP D POP H RET ; WRBY: PUSH PSW LDA WOFFSET ; Get write offset LXI H,RECORD CALL ADDHLA ; Form address POP PSW ; Restore char MOV M,A ; Put it in buffer LXI H,WOFFSET MOV A,M INR A ; Bump offset CM WRITE ; Write it out if buffer full MOV M,A ; Save offset RET ; WRITE: ; Write a sector to log file LDA WOFFSET ORA A ; Is it empty? RZ ; Return if nothing to write PUSH H CALL SETLUS ; Set up log file environment LXI D,LOGFCB MVI C,21 CALL REALBD ; Write the sector CALL CLRLUS ; Restore environment XRA A ; Set offset to 0 POP H RET ; WRCRLF: ; Write a cr, lf to log file MVI A,CR CALL WRBYTE MVI A,LF JMP WRBYTE ; WRTMSG: ; Write message at [HL] to log file LDA DSKLOG ORA A RZ ; Do nothing if no log PUSH H CALL WRTTIM ; Time stamp the message POP H WRTMS1: MOV A,M ORA A JZ WRCRLF ; If at end, exit through crlf CALL WRBYTE ; Write the byte INX H JMP WRTMS1 ; WRTTIM: ; Time stamp the log file ENDIF ; DISKLOG ; IF DISKLOG AND CLOCK CALL TIME ; Update the time ENDIF ; DISKLOG AND CLOCK ; IF DISKLOG LXI H,RTCBUF ; Point to hour CALL WRTA MVI A,':' CALL WRBYTE INX H ; Point to minute CALL WRTA MVI A,' ' JMP WRBYTE ; Write final space ; WRTA: ; Write time (BCD) to log file MOV A,M RAR RAR RAR RAR CALL WRTHEX ; Write first BCD digit MOV A,M WRTHEX: ANI 0FH ; Isolate digit ADI '0' ; Convert to ascii JMP WRBYTE ; Exit through write byte ;.... ; ; Set the BDOS call in progress flag so that bios calls do not write to ; log file as well. ; STBDOS: MVI A,0FFH STA BDOSFL ; Set bdos call in progress flag POP H ; Retrieve return address SHLD CALLIN+1 ; Modify call instruction CALLIN: CALL 0 ; Return to caller PUSH PSW ; Return from caller gets us here XRA A STA BDOSFL ; Reset bdos call in progress flag POP PSW RET ; STKNEW: ; Switch to local stack for log write SHLD HLSAVE ; Save HL POP H ; Retrieve return address SHLD USRCAL+1 ; Modify call instruction LXI H,0 DAD SP SHLD OLDSP ; Save old stack LXI SP,NEWSTK ; Set up new stack LHLD HLSAVE ; Restore HL USRCAL: CALL 0 ; Back to caller LXI SP,0 ; Restore old stack OLDSP EQU $-2 RET ;..... ; ; Function 86 - LOGSTAT ; E = 0FFH Return log status in A ; E = 1 Turn log on ; E = 0 Turn log off ; If the equate DISKLOG is NO, A = 77 on return from this call ; LOGSTAT: MOV A,E INR A ; Test for FFH JNZ TSTHRD ; Go turn log on/off LDA DSKLOG ; Get log status ORA A RZ ORI 0FFH RET ;..... ; ; Function 87 - LOGPUT Write a string at [DE] to log file ; LOGPUT: CALL STKNEW ; Switch to local stack XCHG ; String address into HL JMP WRTMSG ; And go write it out ENDIF ; DISKLOG ; IF NOT DISKLOG LOGSTAT: LOGPUT: MVI A,77 ; Say disklog doesn't exist RET ENDIF ; NOT DISKLOG ; IF DISKLOG PUTSL: MVI A,'/' STAX D INX D RET ; DATEMSG: MOV A,M RAR RAR RAR RAR CALL PUTDATE MOV A,M INX H PUTDATE: ANI 0FH ADI '0' STAX D INX D RET ENDIF ; DISKLOG ; ;.... ; ;----------------------------------------------------------------------- ; .COM file routine ; ; Routine to load the .COM file ; LODCOM: IF COMFILE MVI C,SELDSK MVI E,COMDRV-'A' ; Select drive with .COM file on CALL BDOS MVI C,SETUSR ; Set CP/M user area function MVI E,COMUSR ; Location of our COMFILE CALL BDOS ENDIF ; COMFILE ; IF MSGFIL ; Routine to load message file handler LDA 000H CPI 0C2H ; Flag that says KMD RM'ed a file JNZ NOMSGF ; No message file uploaded XRA A STA MSGFCB ; Prep the fcb LXI H,MSGFCB SHLD CURRFCB LXI H,MSGFCB+12 MVI B,21 CALL ZEROM LXI D,MSGFCB ; Ready to load it now JMP LODCM2 ; So do it ; NOMSGF: ENDIF ; MSGFIL ; IF MBBS LDA OPTION CPI 'C' ; MBBS for comments, login otherwise JNZ LODCM1 ; Load login MVI C,SELDSK MVI E,MBSDRV-'A' CALL BDOS ; Select mbbs.com drive MVI C,SETUSR MVI E,MBSUSR CALL BDOS ; Select mbbs.com user XRA A STA OPTION ; Clear option flag STA FCB+1 ; And FCB to avoid loop STA CM2FCB LXI H,CM2FCB ; MBBS fcb SHLD CURRFCB LXI H,CM2FCB+12 MVI B,21 CALL ZEROM ; Clear rest of fcb LXI D,CM2FCB JMP LODCM2 ; Load MBBS ENDIF ; MBBS ; IF COMFILE LODCM1: LXI H,COMFCB SHLD CURRFCB XRA A ; Initialize FCB STA COMFCB LXI H,COMFCB+12 MVI B,21 CALL ZEROM LXI D,COMFCB ; LODCM2: CALL OPENFIL JZ ABORT JMP LOADFIL ENDIF ; COMFILE ; LODEX: IF EXFILE LXI H,EXITFCB SHLD CURRFCB LXI H,EXITFCB+12 MVI B,21 CALL ZEROM LXI D,EXITFCB CALL OPENFIL JZ ABORT ; Cannot open file, finish BYE hangup JMP LOADFIL ENDIF ; EXFILE ; LODEX1: IF EXFIL1 LXI H,EX1FCB SHLD CURRFCB LXI H,EX1FCB+12 MVI B,21 CALL ZEROM LXI D,EX1FCB CALL OPENFIL JZ ABORT ; Cannot open file, finish BYE hangup JMP LOADFIL ENDIF ; EXFILE1 ; LODEX2: IF EXFIL2 LXI H,EX2FCB SHLD CURRFCB LXI H,EX2FCB+12 MVI B,21 CALL ZEROM LXI D,EX2FCB CALL OPENFIL JZ ABORT ; Cannot open file, finish BYE hangup JMP LOADFIL ENDIF ; EXFIL2 ; LODEX3: IF EXFIL2 AND RAMDSK LXI H,EX3FCB SHLD CURRFCB LXI H,EX3FCB+12 MVI B,21 CALL ZEROM LXI D,EX3FCB CALL OPENFIL JZ ABORT ENDIF ; EXFIL2 AND RAMDSK ; ; ; Now load the file ; IF COMFILE OR EXFILE LOADFIL:LHLD 6 ; Get top of memory LXI D,-80H DAD D PUSH H ; Save on stack LXI D,80H ; TPA-80H LXI B,0 ; Keep a record counter PUSH B ; Save counter PUSH D ; And load address ; GLOOP: POP D ; Get TPA address LXI H,80H ; Point to next address to read to DAD D ; HL has the address POP B ; Increment the counter ; ; ; Check for load past top-of-memory ; POP D ; Get (top-of-memory) PUSH D ; Resave for next time MOV A,E ; Subtract: (top) - (address) SUB L MOV A,D ; Only the carry needed SBB H JNC SIZEOK ; CY=better MOVCPM LXI H,PTSMSG JMP ERRXIT ; SIZEOK: INX B PUSH B PUSH H ; Save TPA address XCHG ; Align registers MVI C,STDMA ; Tell BDOS where to put record CALL BDOS LHLD CURRFCB ; Point to aprropriate FCB XCHG MVI C,READ CALL BDOS ORA A JZ GLOOP ; A=0 if more to read POP B ; Unjunk stack POP B ; This is our counter POP H ; More junk on stack MOV A,B ; Check for zero ORA C JZ ABORT ; We should have read something LXI D,80H ; We did, reset DMA to 80H MVI C,STDMA CALL BDOS LXI H,CFLMSG CALL PRINTL RET ;..... ; ; ABORT: LXI H,CNFMSG ; ERRXIT: CALL PRINTL MVI A,0CDH ; Force logoff STA 000H ; And system reset JMP 000H ; Via warm boot trap ENDIF ; COMFILE OR EXFILE ;..... ; ; OPENFIL: IF CPM3 PUSH D ; Save FCB address LXI D,0080H MVI C,STDMA CALL BDOS ; Set DMA to 0080H POP D ; Get back pointer to FCB PUSH D ; Save FCB pointer again MVI C,SEARCH ; Search for first match CALL BDOS INR A ; Did a file match? POP D RZ ; No, return PUSH D DCR A ; A=directory code (0-3) ADD A ; *2 ADD A ; *4 ADD A ; *8 ADD A ; *16 ADD A ; *32 MOV E,A MVI D,0 LXI H,0080H ; Add (32*dir code) to default DMA DAD D ; To find first match filename POP D ; DE=FCB PUSH D ; Save DE again INX H ; Move HL past user # byte in buffer INX D ; Move DE past drive # in FCB MVI B,11 CALL MOVE ; Move name found to FCB POP D ; And continue with the open ENDIF ; CPM3 ; MVI C,OPEN ; Open file pointed to by 'DE' CALL BDOS INR A RET ;..... ; ; end of .COM file routine ;----------------------------------------------------------------------- ; ; Boot trap - becomes disconnect if JMP at 0 has been altered ; MBOOT: LDA OPTION CPI 0FFH ; Local cp/m with BYE5 running? JZ VWARMBT ; Yes, skip this check ; LXI SP,STACK ; Ensure good stack ; IF EXRET LDA FCB+1 CPI 'r' ; Returning from an exit file? JZ PREOFF ; Then prepare for next call ENDIF ; EXRET ; IF EXFIL2 LDA MSPEED CPI 07FH ; Returning from ARCIVE? JZ PREOFF ; Yes, skip to next call ENDIF ; EXFIL2 ; IF MSGFIL ; See if KMD RM'ed a file LDA 0000H CPI 0C2H ; Flag left by KMD? JNZ MBOOT1 ; No, continue LXI H,MSGMSG ; Let Sysop know what file is sought CALL PRINTL CALL LODCOM ; Try to load it MVI A,0C3H ; Reset the flag STA 000H CALL 0100H ; Now run the message file handler LXI SP,STACK ; Restore the stack ; MBOOT1: ENDIF ; MSGFIL ; IF CPM3 MVI B,0B3H ; Offset to CHAIN PROGRAM flag in SCB CALL GETSCB ; Get byte from SCB ANI 080H ; In the middle of a CHAIN PROGRAM now? JNZ VWARMBT ; Yes, skip checks ENDIF ; CPM3 ; IF (COMFILE OR EXFILE) AND (NOT HBBS) LDA OPTION CPI 'E' ; Return from local test? JNZ MBOOT2 ; No, continue MVI A,' ' STA FCB+1 ; Fool system STA OPTION CALL UNPATCH ; Yes, restore ENDIF ; COMFILE OR EXFILE AND NOT HBBS ; IF EXFILE AND (NOT HBBS) AND (NOT MBBS) JMP LOGOFF ; Run exit file locally ENDIF ; EXFILE AND NOT HBBS/MBBS ; IF COMFILE AND (NOT HBBS) JMP START0 ; And start fresh ENDIF ; COMFILE AND NOT HBBS ; MBOOT2: LDA 0 ; Look at opcode CPI 0C3H ; Is it still a jmp? ; IF MBBS JNZ NORPTC ; Let login take over ENDIF ; MBBS ; IF NOT MBBS JNZ LOGOFF ; Check for exit file ENDIF ; NOT MBBS ; IF NOT CPM3 CALL BDCHEK ENDIF ; NOT CPM3 ; IF (NO25TH OR MBBS) AND READLC LDA LCDATA ; See if lastcalr has been read CPI ' ' ; Or data poked by a BBS, like MBBS JNZ NO25EX ; Yes, skip this XRA A ; Else, let's pick up the lastcalr file STA FCBRNO ; Prepare FCB for lastcalr LXI H,LCNAME LXI D,FCB MVI B,13 CALL MOVE ; Move rest of FCB MVI C,0DH ; Reset disk and CALL BDOS ; Set for default buffer MVI C,SELDSK MVI E,LCDRV-'A' CALL BDOS ; Set drive MVI C,SETUSR MVI E,LCUSR CALL BDOS ; And user LXI D,FCB CALL OPENFIL ; Open it LXI H,LCMSG1 CZ PRINTL ; Error msg JZ NO25EX ; No file available, exit LXI D,FCB MVI C,READ CALL BDOS ; Read 1 record max LXI H,LCMSG1 ORA A CNZ PRINTL ; Say error LXI H,80H LXI D,LCDATA MVI B,NO25BF ; Size of buffer CALL MOVE ; Move data into bye's internal buffer MVI B,NO25BF ; Max we will display LXI H,LCDATA ; NO25RD: MOV A,M CPI 'Z'-'@' ; EOF? JZ NO25ZD CPI ',' CZ NO25SP ; Change commas and semicolons to spaces CPI ';' CZ NO25SP CPI CR CZ NO25SP ; Convert cr's and lf's to spaces CPI LF CZ NO25SP DCR B JZ NO25ZD INX H ; Get next byte JMP NO25RD ; NO25ZD: XRA A MOV M,A ; Set terminator for print routine STA 04H ENDIF ; READLC ; IF NO25TH OR MBBS NO25EX: CALL WHOSIT ENDIF ; NO25TH OR MBBS ; IF PRNTWB LXI H,WBMSG CALL PRINTB ; Print the following message: ENDIF ; PRNTWB ; IF TIMEON AND CLOCK AND PRNTOS CALL RMTOS ; Display timeon ENDIF ; TIMEON ; JMP VWARMBT ; Go do a warm boot ; IF (NO25TH OR MBBS) AND READLC NO25SP: MVI A,' ' ; Space MOV M,A ; To lcdata RET ENDIF ; NO25TH OR MBBS ;..... ; ; ;----------------------------------------------------------------------- ; ; Modem input function, checks local console first ; MINPUT: IF NOT CPM3 CALL BDCHEK ENDIF ; CPM3 ; XRA A ; Reset MSTAT no-activity flag STA MSFLAG MINP2: CALL MSTAT ; Nope, check for modem input ORA A ; Got modem input? JZ MINP2 ; Nope, loop again CALL CONSTAT ORA A JNZ CONIN MINP3: CALL MDINP ; Yep, get modem character ANI 7FH ; Strip off any high bits CPI FILT4 ; Ignore nulls JZ MINP2 CPI FILT1 ; Ignore left braces JZ MINP2 CPI FILT2 ; Was it a delete? JZ MINP2 ; Filter this too CPI FILT3 ; "`" causes TRS-80 glitch JZ MINP2 ; So filter it too ; IF ZCPR2 OR ZCPR3 MOV B,A ; Save byte in B LDA WHEEL ORA A MOV A,B ; Get character back JNZ MINP4 ; It's a wheel, don't trap ^P ENDIF ; ZCPR2 OR ZCPR3 ; CPI 'P'-'@' ; Is it a ^P? JZ MINP2 ; Ignore CTL-P unless wheel is set ; MINP4: IF HARDLOG PUSH B MOV B,A ; Put a copy of the character in B LDA HARDON ; If HARDON=0 then turn HARDLOG off (so ORA A ; SYSOP does not waste paper while he MOV A,B ; Playing ZORK from work.) POP B JZ NOLOG CPI 20H JNC MINP5 CPI CR JNZ NOLOG ; MINP5: CALL LISTOUT ; Echo on printer CPI CR JNZ NOLOG ; Return needs linefeed MVI A,LF CALL LISTOUT ; So send it MVI A,CR ; Get back CR ENDIF ; HARDLOG ; NOLOG: IF DISKLOG MOV C,A LDA DSKLOG ORA A ; Is disk log on? JZ NOHARD LDA BDOSFL ORA A ; Are we in a BDOS function call? JNZ NOHARD CALL STKNEW ; Switch to local stack PUSH H PUSH B LDA TIMSFL ; Should we time stamp the log file? ORA A CNZ WRTTIM POP B POP H MOV A,C CALL WRBYTE ; Write out the byte CPI CR ; Is it CR? MVI A,LF CZ WRBYTE ; Send LF if CR. MVI A,0 JNZ HRDL1 DCR A ; Say that we have to time stamp next time HRDL1: STA TIMSFL NOHARD: MOV A,C ENDIF ; DISKLOG ; CPI 'C'-'@' ; Is it ^C? RNZ ; No, pass it through LDA 0 ; See if warm boot disabled CPI 0C3H ; Jump means warm boot ok MVI A,3 ; So return with a ^C RZ MVI A,CTRLC ; Else convert to different character RET ;..... ; ; ;----------------------------------------------------------------------- ; ; Modem output function ; MOUTPUT: IF NOT CPM3 CALL BDCHEK ENDIF ; NOT CPM3 ; XRA A STA MSFLAG ; Reset no-activity flag ; ; If we already know carrier is lost, do not check for it again or loop ; trying to output. ; IF COMFILE AND TIMEON AND CLOCK LDA OPTION CPI 'E' ; Running locally? JNZ MONOTE ; No, continue MOV A,C ; Check character CPI LF ; One check per line CZ TCHECK ; Keep clock updated, TCHECK saves ; Registers MONOTE: ENDIF ; COMFILE AND TIMEON AND CLOCK ; LDA MDMOFF ; Known loss of carrier? ORA A PUSH PSW CNZ CONOUT ; Output to local only POP PSW RNZ ; Then exit ; MOUTA: CALL CHECK ; Carrier still on? CALL MDOUTST ; Check modem output status JZ MOUTA MOV A,C ; Get character ANI 7FH ; Strip parity bit RZ ; Don't output DEL to remote CPI 60H ; Check for lower case JC MOUTP2 ; Skip if not lower case CPI 7FH ; Check for rubout JZ MOUTP2 PUSH H LXI H,ULCSW ; Subtract either 20H or nothing SUB M POP H MOV C,A ; Force on local as well as remote ; MOUTP2: CPI LF ; We have a toggle for line feeds JNZ MOUTP3 ; Nope, not a LF ; IF TIMEON CALL TCHECK ; Update/check clock and timeon ENDIF ; TIMEON ; LDA LFEEDS ; Yes, see if we can send it... ORA A ; Set flags MVI A,0 ; Prepare with a null JNZ MOUTP3 ; Nope, don't (instead, send a null) MVI A,LF ; Yes, it's ok to send the line feed ; MOUTP3: CALL MDOUTP ; Output character to modem ; PUSH PSW ; Save character CPI 'G'-'@' ; Is it a bell? JNZ NOTBEL LDA BELLON ; Get flag ORA A JZ ISBELL ; NOTBEL: CALL CONOUT ; Send to regular BIOS ; ISBELL: POP PSW ; Get character again ; ; ; Check for nulls ; CPI LF ; Time for nulls? RNZ ; No, return ; ; ; Send nulls if requested ; LDA NULLS ; Get count ORA A ; Any? RZ ; No PUSH B MOV B,A ; Save count ; NULLP: CALL MDOUTST ; Modem ready? JZ NULLP XRA A ; 00H is a null CALL MDOUTP ; Send a null DCR B ; Another? JNZ NULLP ; Yes, loop POP B RET ;..... ; ; ;----------------------------------------------------------------------- ; ; Move (HL) to (DE), length in (B) ; MOVE: MOV A,M ; Get a byte STAX D ; Put at new home INX D ; Bump pointers INX H DCR B ; Decrement byte count JNZ MOVE ; If more, do it RET ; If not, return ;..... ; ; ;----------------------------------------------------------------------- ; ; Modem status test and no-activity timer routine ; MSTAT: IF NOT CPM3 CALL BDCHEK ; Set 6 to safety ENDIF ; NOT CPM3 ; CALL CONSTAT ORA A JNZ MSTAT0 LDA MDMOFF ORA A MVI A,0 RNZ ; Don't let remote input while modem is ; Muted CALL CHECK ; Check for carrier lost CALL MDINST ; Get modem input status ORA A ; Character available? JZ MSTAT1 ; Nope MSTAT0: PUSH PSW ; Yep, save return status XRA A ; Clear no-activity flag STA MSFLAG POP PSW ; Restore return status RET ; And return ; MSTAT1: LDA MSFLAG ; Get the no-activity flag ORA A ; First time here? MVI A,0FFH ; Reset virgin flag in all cases STA MSFLAG JNZ MSTAT3 ; Nope LDA TOVAL ; Yep, get number of minutes to wait MSTAT2: STA TOCNTM ; Initialize minutes counter PUSH H ; Save registers LXI H,42000 ; Initialize loop counter SHLD TOCNT POP H ; Restore registers MSTAT3: CALL KDELAY ; Wait a millisecond PUSH H ; Save registers LHLD TOCNT ; Get the loop counter DCX H ; Bump down SHLD TOCNT ; And save MOV A,H ; Done this loop? ORA L POP H ; Restore registers JZ MSTAT4 ; Yep XRA A ; Nope, clear return status RET ; And return MSTAT4: MVI A,'G'-'@' ; Beep the user CALL MDOUTP LDA TOCNTM ; Bump down minutes counter DCR A ; Done? JNZ MSTAT2 ; Nope ; TMOUT: LXI H,ITOMSG ; Yep, caller time-out LXI SP,STACK ; Restore stack CALL PRINTB CALL PATCH ; In case LUX was running ; IF DISKLOG XRA A STA BDOSFL LXI H,TMOMSG CALL WRTMSG ; Put input timeout into log file ENDIF ; DISKLOG ; IF MBBS JMP NORPTC ; Let mbbs/login log him off ENDIF ; MBBS ; IF NOT MBBS JMP LOGOFF ; Check for exit file ENDIF ; NOT MBBS ;..... ; ; ;----------------------------------------------------------------------- ; ; This is the jmp table which is copied on top of the one pointed to by ; location 1 in CP/M. ; NEWJTBL:JMP MCBOOT ; Cold boot JMP MBOOT ; Warm boot JMP MSTAT ; Modem status test JMP MINPUT ; Modem input routine JMP MOUTPUT ; Modem output routine ; IF (NOT HARDLOG) AND (NOT PRINTER) RET ; Modem list device NOP NOP RET ; Modem punch device NOP NOP RET ; Modem reader device NOP NOP ENDIF ; NOT HARDLOG AND NOT PRINTER ;..... ; ;----------------------------------------------------------------------- ; IF MOTOR DSKON: PUSH PSW ; Save 'A' and flags MVI A,DISKON ; Turn on motors OUT DISK PUSH H ; Now, wait a long time LXI H,0000 ; DSKLP: XTHL XTHL DCX H ; Count loop MOV A,H ; Check if done? ORA L JNZ DSKLP POP H ; Restore HL POP PSW ; And 'A' and flags RET ; DSKOFF: PUSH PSW ; Save 'A' and flags MVI A,DISKOFF ; Turn motors off OUT DISK POP PSW RET ENDIF ; MOTOR ;..... ; ; ;----------------------------------------------------------------------- ; NWBCALL: IF LOSER CALL WMSTRT ; Warm boot disk read CALL PATCH ; Fix BIOS again after WMSTRT ENDIF ; LOSER ; IF NOT CPM3 CALL BDCHEK ENDIF ; NOT CPM3 ; RET ;..... ; ; ;----------------------------------------------------------------------- ; ; Patch in the new JMP table (saving the old) ; PATCH: LDA PTFLAG ORA A JNZ SKPTH ; Save the original jump table only once ; CALL TBLADDR ; HL= CP/M BIOS jump table LXI D,VCOLDBT ; Point to save location MVI B,24 ; Save all vectors CALL MOVE ; Move it LHLD VCONOUT+1 ; Get the original CONOUT address SHLD COVECT ; Store for use with XMODEM programs ; ; ; Now move the new JMP table to CP/M ; SKPTH: CALL TBLADDR ; HL= CP/M BIOS jump table XCHG ; Move it to 'DE' LXI H,NEWJTBL ; Point to new jump table CALL MOVE ; Move it MVI A,0FFH STA PTFLAG ; IF LOSER LXI H,NWBCALL ; Set new warm boot call SHLD WBCALL+1 ; Store the new address ENDIF ; LOSER ; RET ;..... ; ; ;----------------------------------------------------------------------- ; ; PRNLOG is called to print out the BYE version # and USRLOG info. It ; can be called from outside the program, using the vector after MCBOOT. ; PRNLOG: LXI H,VMSG CALL PRINTL CALL CALSUM RET ; CALSUM: LDA CWCAR ; Get 8 bit number LXI H,ATMSN ; Address to store ascii CALL DEC8 ; And convert to ascii LXI H,ATMSG ; Print Callers with carrier detected CALL PRINTL ; To local crt ; IF B5IM ; Print # of voice calls LDA VCNUM LXI H,VCMSN ; Put ascii here CALL DEC8 LXI H,VCMSG CALL PRINTL ENDIF ; B5IM ; IF PWRQD LDA NWPWD ; 8 bit counter LXI H,NWMSD ; Put ascii here CALL DEC8 LXI H,NWMSG ; Print callers who knew password CALL PRINTL ENDIF ; PWRQD ; LXI H,LFMSG CALL PRINTL ; Turn up a line RET ; End of call summary ;..... ; ; ;----------------------------------------------------------------------- ; ; Readbyte routine - used to read the welcome file ; IF WELFILE RDBYTE: MOV A,H ; Time to read? ORA A ; If at 100H, no read required JZ NORD ; ; ; Have to read a sector ; LXI D,FCB MVI C,READ CALL BDOS ORA A ; Ok? MVI A,1AH ; Fake up EOF RNZ ; Return EOF if bad LXI H,80H ; NORD: MOV A,M ; Get character INX H ; Point to next byte RET ENDIF ; WELFILE ;..... ; ; ;----------------------------------------------------------------------- ; ; Calculate HL=CP/M's jump table, B=length ; TBLADDR:LHLD 1 ; Get BIOS pointer DCX H ; Skip to cold boot DCX H DCX H ; IF HARDLOG OR PRINTER ; Retain list device? MVI B,15 ; Don't move lister jump ENDIF ; HARDLOG ; IF (NOT HARDLOG) AND (NOT PRINTER) MVI B,24 ; Move all jumps ENDIF ; NOT HARDLOG ; RET ;..... ; ; ;----------------------------------------------------------------------- ; ; TSTBAUD attempts to read a CR, LF or CTL-C and returns with zero flag ; if the character read is one of these three. ; IF NOT B5IM TSTBAUD:CALL MDCARCK ; Check carrier first JZ PREOFF ; Carrier is gone, start over LDA CDOFF INR A STA CDOFF CPI 60 ; Allow 1 minute for c/r detect JZ PREOFF ; Hangup and start over MVI D,20 ; Check for 2 sec for current baud rate ; TSTB1: MVI B,1 ; At .1 sec intervals PUSH D CALL DELAY CALL MDINST ; See if character available ORA A JZ TSTB2 ; None yet CALL MDINP ; Yes, read the character ANI 7FH POP D ; Restore the stack JMP TSTB3 ; And see if it is right character ; TSTB2: POP D ; Restore DE DCR D ; And decrement the count MOV A,D ORA A ; 2 sec's up?? JNZ TSTB1 ; No, try again MVI A,0FFH ; Dummy character ; TSTB3: CPI CR ; If a CR RZ CPI LF ; If a LF RZ CPI 'C'-40H ; If a CTL-C RET ; Return with proper flags set ENDIF ; NOT B5IM ;..... ; ; ;----------------------------------------------------------------------- ; UNPATCH:CALL TBLADDR ; HL= CP/M BIOS jump table XCHG ; Move to DE LXI H,VCOLDBT ; Get saved table CALL MOVE ; Move original table back ; IF LOSER LXI H,WMSTRT ; Load old call location SHLD WBCALL+1 ; Restore old call ENDIF ; LOSER ; RET ;..... ; ; ;----------------------------------------------------------------------- ; USRCHK: CALL PRNLOG ; Give info LXI H,RS1MSG CALL PRINTL ; Prompt to resume waiting for ring ; PRNREL: CALL CONSTAT ; Reply? ORA A JZ PRNREL ; Wait until answered CALL VCONIN ; Then get it CPI 60H ; Lower case? JC $+5 ; Skip conversion SBI 20H ; Else make upper case CPI 'E' ; Execute com file? JZ USRUN ; Yes CPI 'J' ; Jump to cp/m with BYE5 patched? JZ JMPCPM ; Yes, exit to cp/m with BYE5 patched CPI 'R' ; Is answer resume? JZ PRNRES ; Go do it if so LXI H,CRMSG CALL PRINTL ; Turn up a fresh line JNZ EXCPM ; And warm boot CP/M ; PRNRES: LXI H,RS2MSG CALL PRINTL ; Resume via BDOS after message ; IF CLRSCR CALL CLEARIT ; Clear the screen ENDIF ; CLRSCR ; RET ; USRUN: MVI A,'E' STA OPTION ; Fake it JMP ERUN ; For Sysop ; JMPCPM: IF B5IM CALL IMQUIT ; Fix modem so it won't answer ENDIF ; B5IM ; IF NOT B5IM CALL MDQUIT ENDIF ; NOT B5IM ; CALL PATCH ; Leave BYE5 attached MVI A,0C3H STA 000H ; Restore JMP instruction MVI A,0FFH ; And set all the right flags STA MDMOFF STA OPTION STA WRTLOC ; IF ZCPR2 OR ZCPR3 STA WHEEL ; Including wheel byte for sysop ENDIF ; ZCPR ; JMP 000H ; Warmboot with BYE5 attached ;..... ; ; ;----------------------------------------------------------------------- ; WELCOME routine (note no extent used) ; ; Welcome to the system ; WELCOME: IF CLOCK CALL TIME ; Read current time LDA CCHOUR ; And set STA LHOUR ; The users LDA CCMIN ; Login STA LMIN ; Time for later use ENDIF ; CLOCK ; IF DISKLOG CALL OPENLOG ; Make sure the log file is on LXI H,RTCBUF+5 LXI D,CDAY CALL DATEMSG ; Put month into message CALL PUTSL ; Put a slash CALL DATEMSG ; Put day into message CALL PUTSL LXI H,RTCBUF+4 CALL DATEMSG ; Put year into message LDA MSPEED ; Get speed ADI '0' ; Make it ascii STA CONMS1 ; Stuff it into message LXI H,CONMSG CALL WRTMSG ; Put connect message into log file ENDIF ; DISKLOG ; IF TIMEON OR CLOCK MVI A,MAXMIN ; Set number of minutes STA MXTIME ; Into mxtime XRA A STA TCHKFG ; Show it's ok to check time ENDIF ; TIMEON OR CLOCK ; IF COMFILE LDA OPTION CPI 'E' MVI A,0 ; Prepare default nulls in case STA NULLS JZ WELC1 ; Skip this if running locally ENDIF ; COMFILE ; LDA MSPEED ADI 3 ; Value for nulls until BBS resets it STA NULLS ; LXI H,TERMSG CALL PRINTB ; Let sysop/caller know you're online CALL MDINP CALL MDINP ; Clear garbage from modem input ; IF NOT SKTERM CALL MINPUT ; Accept any character, then proceed ENDIF ; NOT SKTERM ; ; WELC1: LXI H,CRMSG ; Carriage Return, Line Feed CALL PRINTB ; Send this message ; IF RSPEED LDA OPTION CPI 'E' ; Running locally? JZ SPDOK ; Yes, skip this XRA A ; Clear status LDA MSPEED ; See what speed the user is at SUI SPEED ; Is it acceptable? JNC SPDOK ; Yes, continue CALL TIME ; Get current time MVI A,HOUR1 ; Start of prime-time ; SPD01: LXI H,CCHOUR ; Point at current hour CMP M ; Equal? JZ SPDOFF ; Yes, dump him INR A ; Check for CPI HOUR2 ; End of prime-time JZ SPDOK ; Not prime-time so let him on CPI 24 ; Past midnight? JNZ SPD01 ; No, continue XRA A ; Yes set to 00 hour JMP SPD01 ; And continue ; SPDOFF: LXI H,OFFMSG ; Point at logoff message CALL PRINTB ; And tell him why JMP PREOFF ; Then log him off ENDIF ; RSPEED ; ; ; Print the welcome file ; SPDOK: IF WELFILE LXI H,WELFILN ; Source LXI D,FCB ; Destination MVI B,13 ; Length CALL MOVE ; Move the name LXI D,80H ; Set DMA address to 80H MVI C,STDMA CALL BDOS MVI C,SETUSR ; Set user number for WELCOME file MVI E,WELUSR CALL BDOS ; ; ; Open the WELCOME file ; MVI C,SELDSK ; Select default drive for WELCOME file MVI E,WELDRV-'A' CALL BDOS LXI D,FCB CALL OPENFIL ; ; ; Did it exist? ; JZ PASSINT ; No WELCOME file ; ; ; Got a file, type it ; XRA A ; A=0 STA FCBRNO ; Zero record number LXI H,100H ; Get initial buffer pointer ; ; ; Type the WELCOME file ; WELTYPE:CALL RDBYTE ; Get a byte CPI 'Z'-'@' ; EOF? JZ PASSINT ; Yes, done MOV C,A ; Setup for type CALL MOUTPUT ; Type the character CALL CONSTAT ORA A JZ WELT1 CALL CONIN JMP WELT2 WELT1: CALL MSTAT ; Check for character typed ORA A JZ WELTYPE ; No, loop CALL MINPUT ; Yes, get character WELT2: CPI 'C'-'@' ; Did user type a CTL-C to end listing? JZ PASSINT CPI 'K'-'@' ; CTL-K to end listing? JZ PASSINT CPI 'K' ; Capital-K to end listing? JZ PASSINT CPI 'k' ; Small-k to end listing? JZ PASSINT CPI 'S'-'@' ; CTL-S to delay listing? JNZ WELTYPE ; No, loop until EOF ; WAIT: CALL CONSTAT ORA A JZ WAIT1 CALL CONIN JMP WAIT2 ; WAIT1: CALL MSTAT ORA A ; Has another char been typed? JZ WAIT ; No, wait CALL MINPUT ; Yes, check character ; WAIT2: CPI 'C'-'@' ; Did user type a CTL-C to end listing? JZ PASSINT CPI 'K'-'@' ; CTL-K to end listing? JZ PASSINT CPI 'K' ; Capital-K to end listing? JZ PASSINT CPI 'k' ; Small-k to end listing? JNZ WELTYPE ; None of these, loop until EOF ENDIF ; WELFILE ; ; ; Get the password ; PASSINT: IF PWRQD MVI D,3 ; 3 tries at password ; PASSINP:LXI H,PWMSG ; Password message CALL PRINTB ; Send this message LXI H,PASSWD ; Point to password MVI E,0 ; No missed letters ; PWMLP: CALL MINPUT ; Get a character CPI 60H ; Lower case? JC NOTLC ; No, ANI 5FH ; Make upper case alpha ; NOTLC: PUSH PSW ; Save character input CPI 20H ; Is character a control code? JNC PWDIS ; Pass if displayable MVI C,'^' ; Dislay if control map to up arrow CALL CONOUT POP PSW PUSH PSW ADI 40H ; PWDIS: MOV C,A CALL CONOUT ; Output character locally POP PSW ; Restore 'A' reg. CPI 'U'-40H ; CTL-U? JZ PASSINP ; Yes, abort, and retry CMP M ; Match password? JZ PWMAT MVI E,1 ; No, show miss CPI CR ; CR? JNZ PWMLP ; No, wait for CR ; ; ; Password did not match ; PWNMAT: LXI H,WRGMSG ; Wrong password message CALL PRINTB ; Send this message DCR D ; More tries? JNZ PASSINP ; Yes JMP PREOFF ; No, go hang up ; ; ; Character matched in password ; PWMAT: INX H ; To next character CPI CR ; End? JNZ PWMLP ; No, loop ; ; ; End of password, any missed characters? ; MOV A,E ; Get flag ORA A JNZ PWNMAT ; Not right ; LXI H,NWPWD ; Get last value INR M ; And add one ENDIF ; PWRQD ; IF COMFILE MVI C,SETUSR MVI E,COMUSR ; Switch to .COM file user area CALL BDOS MVI C,SELDSK ; In case welcome MVI E,COMDRV-'A' ; Is on different drive CALL BDOS ; Than com file MVI A,' ' ; Fool the system so that the .COM file STA FCB+1 ; Will see a space at FCB+1 for default ENDIF ; COMFILE ; ; Either run the COM file or warmboot to cp/m ; IF ZCPR3 AND COMFILE CALL DOZ3 ; ZCPR3 re-initialization ENDIF ; ZCPR3 and COMFILE ; IF COMFILE CALL PATCH ; Run under bye if running "E" option CALL 100H ; Execute com file ENDIF ; COMFILE ; JMP 0000H ; Warm boot now for "normal" CP/M use ;...... ; PREOFF: LXI SP,STACK ; Insure valid stack CALL IMDONE ; Hangup the phone CALL UNPATCH XRA A STA OPTION ; Reset the local "E" option ; IF DISKLOG LXI H,DSCMSG CALL WRTMSG ; Put disconnect msg into SYS.LOG ENDIF ; DISKLOG ; JMP HANGUP ; And prep for next call ;..... ; ;----------------------------------------------------------------------- ; calculate user's elapsed time ; ; Calculate time on system. Log him off if =>MAXMIN unless WHEEL is ; on, or MXTIME=0. If MXTIME = 255, user not logged in. ; IF TIMEON OR CLOCK TCHECK: LDA TCHKFG INR A RZ ; If mxtime was 255, user not logged in PUSH B PUSH D PUSH H ENDIF ; TIMEON OR CLOCK ; IF TIMEON AND (NOT CLOCK) LDA TON JMP TCNCLK ENDIF ; NOT CLOCK ; IF TIMEON AND CLOCK CALL TIME ; Get current time LDA LHOUR ; (LHOUR)=log-in hour 0-23 CALL TCX60 ; Convert to minutes, results in (HL) LDA LMIN ; (LMIN)=log-in minutes, 0-59 LXI D,0 ; Clear (DE) MOV E,A ; (LMIN) to (DE) DAD D ; (HL)+(DE)=(HL) PUSH H ; Save log-in minutes on stack LDA CCHOUR ; (CCHOUR)=current hour, 0-23 LXI H,LHOUR ; Let's see if we crossed midnight SUB M JNC TCOK ; No, we're ok LDA CCHOUR ; Yes, let's add 24 ADI 24 STA CCHOUR ; Now we're ok ; TCOK: LDA CCHOUR ; (CCHOUR) is now => than (LHOUR) CALL TCX60 ; Convert it to minutes LDA CCMIN ; Current minutes, 0-59 LXI D,0 ; Clear (DE) MOV E,A ; CCMIN to (DE) DAD D ; (HL) now has current time in minutes POP D ; (DE) now has log-in time CALL TCDIF ; Get the difference, (HL)-(DE)=(HL) MOV A,L ; Only save LSB, 0-255 is plenty STA TON ; And save it ENDIF ; TIMEON AND CLOCK ; IF TIMEON TCNCLK: LXI H,TONMSD ; (A)=TON, (HL)=address to store ascii CALL DEC8 ; Convert timeon to ascii LDA TON MOV B,A LDA MXTIME SUB B ; Calculate time-left LXI H,TLNMSD CALL DEC8 ; And save it as ascii POP H POP D POP B ENDIF ; TIMEON ; IF TIMEON AND (ZCPR2 OR ZCPR3) LDA WHEEL ORA A ; Maybe he typed his password for user RNZ ENDIF ; TIMEON AND ZCPR ; IF TIMEON LDA MXTIME ORA A ; Special user? RZ ; Yes, exit PUSH B ; Else, check his timeon MOV B,A ; Move it to 'B' LDA TON SUB B ; Subtract max time allowed POP B RC ; Still time left LXI SP,STACK ; Insure valid stack MVI A,255 STA TCHKFG ; Reset time flag XRA A LXI H,TLNMSD CALL DEC8 ; Make sure time-left =0 LXI H,TIMEUP ; Time is up, inform user CALL PRINTB CALL PATCH ; In case LUX was running ENDIF ; TIMEON ; IF DISKLOG AND TIMEON XRA A STA BDOSFL LXI H,TLMMSG CALL WRTMSG ; Put time limit message into log file ENDIF ; DISKLOG AND TIMEON ; IF MBBS AND TIMEON XRA A STA MXTIME JMP NORPTC ; Let login do it ENDIF ; MBBS AND TIMEON ; IF TIMEON AND (NOT MBBS) JMP LOGOFF ; Check for exit file ENDIF ; TIMEON AND NOT MBBS ;..... ; ; TCX60 will multiply (A)x60, results in (HL). ; IF CLOCK TCX60: LXI H,0 ; (HL)=0 ORA A RZ ; If (A)=0, no x60 needed LXI D,60 ; Multiplier ; TCX61: DAD D ; X60 DCR A ; Done? JNZ TCX61 ; No RET ;..... ; ; ; TCDIF will subtract (DE) from (HL), results in (HL). ; (HL) normally has the larger number ; TCDIF: MOV A,L ; LSB of (HL) SUB E ; LSB of (DE) MOV L,A ; Back to L MOV A,H ; MSB of (HL) SBB D ; MSB of (DE) and carry flag MOV H,A ; (HL) now has difference RET ENDIF ; CLOCK ; ;----------------------------------------------------------------------- ; BCD to Binary converter ; ; This routine will convert an 8 bit BCD number (0-99) to binary. ; ; To use: ; LDA BCDNUMBER ; CALL BCDBIN ; ; The routine returns with the binary number in the 'A' register. ; IF BCD2BIN BCDBIN: PUSH D MOV E,A ; Save original byte ANI 15 MOV D,A ; Save low nibble MOV A,E ANI 240 ; Mask LSN RRC ; X2 MOV E,A RRC ; X4 RRC ; X8 ADD E ; X10 ADD D ; Low nibble POP D RET ; ENDIF ; BCD2BIN ;..... ; ; ; BINBCD will convert a 0-99 binary number to 0-99 BCD number. Call ; with (A)=binary number 0-99. (A)=0-99 BCD on exit ; IF BIN2BCD BINBCD: PUSH D MVI E,255 ; -1 ; BLP: INR E ; Increment tens counter SUI 10 ; Subtract 10 each pass JNC BLP ADI 10 ; Get back number MOV D,A MOV A,E RLC ; Shift over to MSN RLC RLC RLC ADD D ; Add in ones position POP D RET ENDIF ; BIN2BCD ;..... ; ; ;----------------------------------------------------------------------- ; ; DEC8 will convert an 8 bit binary number in A to 3 ASCII bytes. ; HL points to the MSB location where the ASCII bytes will be stored. ; Leading zeros are suppressed and spaces are stored in unused bytes. ; DEC8: PUSH PSW PUSH H MVI A,' ' MOV M,A ; Clear destination with spaces INX H MOV M,A INX H MOV M,A POP H POP PSW PUSH B PUSH D MVI E,0 ; Leading zero flag MVI D,100 ; DEC81: MVI C,'0'-1 ; DEC82: INR C SUB D ; 100 or 10 JNC DEC82 ; Still + ADD D ; Now add it back MOV B,A ; Remainder MOV A,C ; Get 100/10 CPI '1' ; Zero? JNC DEC84 ; Yes MOV A,E ; Check flag ORA A ; Reset? MOV A,C ; Restore byte JZ DEC85 ; Leading zeros are skipped ; DEC84: MOV M,A ; Store it in buffer pointed at by HL INX H ; Increment storage location MVI E,0FFH ; Set zero flag ; DEC85: MOV A,D SUI 90 ; 100 to 10 MOV D,A MOV A,B ; Remainder JNC DEC81 ; Do it again ADI '0' ; Make ascii MOV M,A ; And store it POP D POP B RET ;..... ; ; ;----------------------------------------------------------------------- ; IF CHGPATH ; To alter path REMPAT: LXI H,REMPATH ; Source=remote path LXI D,EXTPATH ; Dest=external path at 0040H MVI B,LREMP ; Length of remote path CALL MOVE RET ; SYSPAT: LXI H,SYSPATH ; Source=SYSOP's path LXI D,EXTPATH ; Dest=external path at 0040H MVI B,LSYSP ; Length of new path CALL MOVE RET ENDIF ; CHGPATH ;..... ; ; ;----------------------------------------------------------------------- ; SCB manipulation for CP/M Plus ; ; Set SCB byte at offset in [B] to value in [A] ; IF CPM3 SETSCB: LHLD SCBBASE ; Get SCB pointer MOV L,B ; Set the offset MOV M,A ; Save the byte RET ; ; ; Get SCB byte at offset in [B] to [A] ; GETSCB: LHLD SCBBASE ; Get SCB pointer MOV L,B ; Set the offset MOV A,M ; Get the byte RET ; ; ; Set user number to value in [A] ; SETUSER:MVI B,0B0H ; B0 = CCP user number CALL SETSCB ; Set CCP user number MVI B,0E0H ; E0 = BDOS user number JMP SETSCB ; Set BDOS user number ; ; ; Set drive to value in [B] ; SETDRIVE: MVI B,0AFH ; AF = CCP drive CALL SETSCB ; Set CCP drive MVI B,0DAH ; DA = BDOS drive JMP SETSCB ; Set BDOS drive ENDIF ; CPM3 ;..... ; ; End of SCB manipulation routines ;----------------------------------------------------------------------- ; IF NOT CPM3 ENDOBJ EQU $ ENDIF ; NOT CPM3 ; ; end of main body of program ;----------------------------------------------------------------------- ; ; ------------------------------------------------ ; START B5IM COMMANDS (Set B5IM EQU YES to use this) ; ------------------------------------------------ ; IF B5IM AND DOATZ B5ATZ: DB 'ATZ',CR,0 ; Reset modem ENDIF ; B5IM AND DOATZ ; IF B5IM AND NODTR B5ESC: DB '+++',0 ; Escape sequence for command mode B5ATH: DB 'ATH',CR,0 ; Hangup phone ENDIF ; B5IM AND NODTR ; IF B5IM AND OFFHK B5ATH1: DB 'ATH1' ; Take phone off-hook ENDIF ; B5IM AND OFFHK ; IF B5IM AND OFFHK AND (NOT ANCHOR) DB 'M0' ; Make sure speaker is off ENDIF ; OFFHK AND NOT ANCHOR ; IF B5IM AND OFFHK DB CR,0 ; End the command line ENDIF ; B5IM AND OFFHK ; IF B5IM B5ATA: DB 'ATA',CR,0 ; Answer the phone ADDSTR: DW 0 ; Address of command string VCMSG: DB CR,LF,'Voice calls: ' VCMSN: DB ' ',0 VCNUM: DB 0 ; Counter for voice calls ENDIF ; B5IM ; IF B5IM AND PRGRSS RCSHOW: DB '_',0 ; Will be stored by PRGRSS NOEMSG: DB CR,LF,'Echo error',CR,LF,0 CMDERR: DB 'Modem error',CR,LF,0 ENDIF ; B5IM AND PRGRSS ; IF B5IM B5INIT: DB 'AT' ; Attention ENDIF ; B5IM ; IF B5IM AND ECHO DB 'E1' ; Echo back characters sent to modem ENDIF ; B5IM AND ECHO ; IF B5IM AND (NOT ECHO) DB 'E0' ; Don't do echo verification ENDIF ; B5IM AND NOT ECHO ; IF B5IM DB 'Q0' ; Send result codes DB 'V0' ; Terse mode DB 'S2=128' ; Change + to different character ENDIF ; B5IM ; IF B5IM AND (NOT NOATA) DB 'S0=0' ; No auto-answer (we will use 'ATA') ENDIF ; B5IM AND NOT NOATA ; IF B5IM AND NOATA DB 'S0=1' ; Will answer on first ring ENDIF ; B5IM AND NOATA ; IF B5IM AND SHORTB DB CR,0 B5INT1: DB 'AT' ENDIF ; B5IM AND SHORTB ; IF B5IM AND (NOT ANCHOR) DB 'M0' ; Speaker off DB 'S10=25' ; 2 1/2 sec wait after carrier loss to ; Hang up ENDIF ; B5IM AND NOT ANCHOR ; IF B5IM AND (NOT HS300) AND (NOT ANCHOR) DB 'X1' ; Extended response codes beyond '4' ENDIF ; B5IM AND NOT HS300 AND NOT ANCHOR ; IF B5IM DB 'H0' ; Put modem on-hook DB CR,0 ; CR finishes command string ENDIF ; B5IM ; IF B5IM AND (NOT OFFHK) B5USR: DB 'ATS0=0',CR,0 ; This helps the Password and S-100 ENDIF ; B5IM ;..... ; ; end of B5IM command strings ;----------------------------------------------------------------------- ; messages ; IF PRGRSS AND (NOT B5IM) MSG30: DB '300 baud test',CR,LF,0 MSG12: DB '1200 baud test',CR,LF,0 MSG24: DB '2400 baud test',CR,LF,0 ENDIF ; PRGRSS AND (NOT B5IM) ; ; ; Program version number message ; VMSG: DB CR,LF,'BYE',MAIN+'0' DB VERS/10+'0',VERS MOD 10+'0',' - ' DB MONTH/10+'0',MONTH MOD 10+'0','/' DB DAY/10+'0',DAY MOD 10+'0','/' DB YEAR/10+'0',YEAR MOD 10+'0',CR,LF,LF,0 ; CLRSEQ: DB CLRCH1,CLRCH2,CLRCH3,CLRCH4,CLRCH5,CLRCH6,0 ; IF RVIDEO RVIDON: DB RVON1,RVON2,RVON3,RVON4,0 RVIDOFF:DB RVOFF1,RVOFF2,RVOFF3,RVOFF4,0 ENDIF ; RVIDEO ; BELMSG: DB 7,7,0 ; Alert sysop that system is available CDOFF: DB 0 OPTION: DB 0 ; IF RSPEED OFFMSG: DB CR,LF,'Sorry, only 1200 or 2400 bps allowed from ' DB '7PM-11PM' DB CR,LF,CR,LF,' Call back before/after 7-11PM Pacific' DB CR,LF,0 ENDIF ; RSPEED ; IF TIMEON TIMEUP: DB 7,CR,LF,CR,LF DB ' Your time is up - Please call back tomorrow..' DB CR,LF,7,0 TONMSG: DB CR,LF,'Minutes on system: ' TONMSD: DB '0 ',CR,LF,0 TLNMSG: DB CR,LF,'Minutes left.... ' TLNMSD: DB '0 ',CR,LF,0 ENDIF ; TIMEON ; ; ; Real-Time clock buffer. Store BCD values into this area if TIMEON ; is YES and your clock is read as BCD values for time and date. Use ; BCDBIN to convert HH and MM to binary and store those values in ; CCHOUR and CCMIN. ; ; (NOTE: 99:99:99 INDICATES CLOCK IS NOT RUNNING OR NOT AVAILABLE) ; RTCBUF: DB 99H,99H,99H ; HH:MM:SS (BCD 24hr time) ; 00:00:00-23:59:59 DB 19H,85H,02H,18H ; YYYY/MM/DD (BCD ISO date) ; TON: DB 0,0 ; (Total time on system-binary integer) CCHOUR: DB 0 ; Current clock hour in binary CCMIN: DB 0 ; Current clock minute in binary LHOUR: DB 0 ; Login hour in binary LMIN: DB 0 ; Login minutes in binary TCHKFG: DB 0 ; Tcheck flag, 0 = OK, 255 = not OK to ; Check ; CRMSG: DB CR,LF,CR,LF,0 ; TERMSG: DB CR,LF,'BYE5', VERS/10+'0',VERS MOD 10+'0',' (c)' ; IF NOT SKTERM DB ' - any key to continue: ' ENDIF ; NOT SKTERM ; DB 0 ; End of message ; FKFLAG: DB 0 PTFLAG: DB 0 ; IF PRNTGB GBMSG: DB CR,LF,' Goodbye, call again...',CR,LF,' ' DB CR,LF,0 ENDIF ; PRNTGB ; LDMSG: DB CR,LF,'Load Successful...' DB CR,LF,0 ; RS1MSG: IF COMFILE DB CR,LF,'xecute .COM file,' ENDIF ; COMFILE ; DB CR,LF,'esume BYE,' DB CR,LF,'ump to CP/M with BYE5 attached,' DB CR,LF,' for normal unpatched CP/M: ',0 ; RS2MSG: DB ' Resuming...',CR,LF,0 ATMSG: DB CR,LF,'Modem calls: ' ATMSN: DB ' ',0 CWCAR: DB 0 ; Counter for carrier detected calls ; ; ; Access password (ends in carriage return) - keep password here ; IF PWRQD PASSWD: DB 'DDT' ; The password itself DB CR ; End of password, CR-only to erase it ; ; ; (Allow room for larger password to be entered, up to 10 characters) ; DB 0,0,0,0,0,0,0 ; PWMSG: DB CR,LF,'Enter Password: ',0 WRGMSG: DB 'Incorrect password',CR,LF,0 NWMSG: DB CR,LF,'Passwords: ' NWMSD: DB ' ',0 NWPWD: DB 0 ; Counter for correct password callers ENDIF ; PWRQD ; IF CHEKDU IDMSG: DB '> [Invalid drive]',0 IUMSG: DB '> [Invalid user#]',0 ENDIF ; CHEKDU ; CLMSG: DB CR,LF,LF,'[Carrier lost]',CR,LF,0 ITOMSG: DB CR,LF,LF,'[Input timed out]',7,CR,LF,0 LCDMSG: DB CR,LF,LF,'[Last call]',CR,LF,0 ULTMSG: DB CR,LF,'[Unlimited Time]',CR,LF,0 SCRMON: DB CR,LF,'[Remote on]',CR,LF,0 SCRMOFF:DB CR,LF,'[Remote off]',CR,LF,0 BELMON: DB CR,LF,'[Bell on]',CR,LF,LF,0 BELMOFF:DB CR,LF,'[Bell off]',CR,LF,LF,0 MFSMSG: DB CR,LF,'Message from Sysop: ',CR,LF,0 SGDMSG: DB CR,LF,'Going down in ',DOWNMIN+'0' DB ' min.',CR,LF,0 LFMSG: DB CR,LF,0 LCDFLG: DB 0 ; IF PRNTWB WBMSG: DB CR,LF,'Booting CP/M...',CR,LF DB 0 ENDIF ; PRNTWB ; IF CPM3 SCBPB: DB 3AH,0 ; Parameter block for extracting SCB ; Start address ENDIF ; CPM3 ; IF COMFILE OR EXFILE PTSMSG: DB '++ TPA too small ++',0 CNFMSG: DB '.COM ++ Not found-abort ++',CR,LF,0 ENTMSG: DB 'Entry ',0 ; Filled by loader CFLMSG: DB '.COM loaded',CR,LF,LF,0 ENDIF ; COMFILE OR EXFILE ; IF EXFILE EXTMSG: DB 'Exit ',0 ; Filled by loader ENDIF ; EXFILE ; IF EXFIL1 EX1MSG: DB 'HSAVE',0 ENDIF ; EXFIL1 ; IF EXFIL2 EX2MSG: DB 'HMNT',0 ENDIF ; EXFIL2 ; IF EXFIL2 AND RAMDSK EX3MSG: DB 'BSAVE',0 ENDIF ; EXFIL2 AND RAMDSK ; IF MSGFIL MSGFCB: DB 0,'MFMSG COM' ; Put name of your message handler here DB 0,0,0,0,0,0,0 ; 21 for rest of FCB DB 0,0,0,0,0,0,0 DB 0,0,0,0,0,0,0 MSGMSG: DB 'MSGNAME ',0 ; Filled by loader ENDIF ; MSGFIL ; IF WELFILE WELFILN:DB 0,'WELCOME ???' ; WELCOME file name, must be 11 chars. DB 0 ; WELCOME or WELCOME.TXT will work ENDIF ; WELFILE ; CM2FCB: IF MBBS DB 0,'MBBS COM' ; For mbbs4n DB 0,0,0,0,0,0,0 ; 21 for rest of FCB DB 0,0,0,0,0,0,0 DB 0,0,0,0,0,0,0 ENDIF ; MBBS ; IF COMFILE AND RBBS COMFCB: DB 0,'RBBS COM' ; COM file name, must be 11 characters DB 0,0,0,0,0,0,0 ; 21 for rest of FCB DB 0,0,0,0,0,0,0 DB 0,0,0,0,0,0,0 ENDIF ; COMFILE AND RBBS ; IF COMFILE AND OXGATE COMFCB: DB 0,'OXENTR COM' ; OxGate entry module DB 0,0,0,0,0,0,0 ; 21 for rest of FCB DB 0,0,0,0,0,0,0 DB 0,0,0,0,0,0,0 ENDIF ; COMFILE AND OXGATE ; IF COMFILE AND METAL COMFCB: DB 0,'MENTR COM' ; Metal entry file DB 0,0,0,0,0,0,0 ; 21 for rest of FCB DB 0,0,0,0,0,0,0 DB 0,0,0,0,0,0,0 ENDIF ; COMFILE AND METAL ; IF COMFILE AND MBBS COMFCB: DB 0,'LOGIN COM' ; Mbbs entry file DB 0,0,0,0,0,0,0 ; 21 for rest of FCB DB 0,0,0,0,0,0,0 DB 0,0,0,0,0,0,0 ENDIF ; COMFILE AND MBBS ; IF COMFILE AND HBBS COMFCB: DB 0,'BBS COM' ; PBBS entry file DB 0,0,0,0,0,0,0 ; 21 more for fcb DB 0,0,0,0,0,0,0 DB 0,0,0,0,0,0,0 ENDIF ; COMFILE AND HBBS ; IF COMFILE AND QBBS COMFCB: DB 0,'QENTER COM' ; QBBS entry module DB 0,0,0,0,0,0,0 ; 21 for rest of FCB DB 0,0,0,0,0,0,0 DB 0,0,0,0,0,0,0 ENDIF ; COMFILE AND QBBS ; EXITFCB: IF EXFILE AND QBBS DB 0,'QEXIT COM' ; Exit filename, must be 11 characters DB 0,0,0,0,0,0,0 ; 21 for rest of FCB DB 0,0,0,0,0,0,0 DB 0,0,0,0,0,0,0 ENDIF ; EXFILE AND QBBS ; IF EXFILE AND OXGATE DB 0,'OXEXIT COM' ; Exit filename, must be 11 characters DB 0,0,0,0,0,0,0 ; 21 for rest of FCB DB 0,0,0,0,0,0,0 DB 0,0,0,0,0,0,0 ENDIF ; EXFILE AND OXGATE ; IF EXFILE AND METAL DB 0,'MEXIT COM' ; Exit filename, must be 11 characters DB 0,0,0,0,0,0,0 ; 21 for rest of FCB DB 0,0,0,0,0,0,0 DB 0,0,0,0,0,0,0 ENDIF ; EXFILE AND METAL ; IF EXFILE AND HBBS DB 0,'HBYE COM' ; Exit filename, must be 11 characters DB 0,0,0,0,0,0,0 ; 21 for rest of FCB DB 0,0,0,0,0,0,0 DB 0,0,0,0,0,0,0 ENDIF ; EXFILE AND HBBS ; EX1FCB: IF EXFIL1 AND HBBS DB 0,'HSAVE COM' ; Exit filename, must be 11 characters DB 0,'$S',0,0,0,0 ; 21 for rest of FCB DB 0,0,0,0,0,0,0 DB 0,0,0,0,0,0,0 ENDIF ; EXFIL1 AND HBBS ; EX2FCB: IF EXFIL2 AND HBBS DB 0,'HMNT COM' ; Exit filename, must be 11 characters DB 0,'$S',0,0,0,0 ; 21 for rest of FCB DB 0,0,0,0,0,0,0 DB 0,0,0,0,0,0,0 ENDIF ; EXFIL2 AND HBBS ; EX3FCB: IF EXFIL2 AND HBBS AND RAMDSK DB 0,'BSAVE COM' ; Exit filename, must be 11 characters DB 0,'$S',0,0,0,0 ; 21 for rest of FCB DB 0,0,0,0,0,0,0 DB 0,0,0,0,0,0,0 ENDIF ; EXFIL2 AND HBBS AND RAMDSK ; LCNAME: IF NO25TH OR MBBS DB 0,'LASTCALR???' ; LASTCALR OR LASTCALR.DAT will be used DB 0 ENDIF ; NO25TH OR MBBS ; LCDATA: IF NO25TH OR MBBS DB ' ',0 DS NO25BF-2 ; Size of buffer LCFILL: DB ' L/C data N/A',0 LCHEAD: DB CR,0 ; Put your customized header here, ; Terminate with a ,0 ENDIF ; IF (NO25TH OR MBBS) AND READLC LCMSG1: DB 'No L/C file',CR,LF,0 ENDIF ; NO25TH OR MBBS ; IF MBBS MBBS1: DB CR,LF,'Loading for COMMENT before exiting...',CR,LF,LF,0 MBBS2: DB CR,LF,'[ Updating ]',CR,LF,0 ENDIF ; MBBS ; ; IF DISKLOG DSKLOG: DB 0 ; Disk log open status OPNMSG: DB CR,LF,'[Log on]',CR,LF,0 ; Function key message CLSMSG: DB CR,LF,'[Log off]',CR,LF,0 ; Function key message DSCMSG: DB '**DISCONNECT**',0 ; Log disconnect msg CONMSG: DB '**CONNECT ' ; Connect message CONMS1: DB ' on ' CDAY: DS 8 DB '**',0 ENDIF ; DISKLOG ; IF DISKLOG AND TIMEON TLMMSG: DB '**TIME LIMIT**',0 ; Time limit message ENDIF ; DISKLOG AND TIMEON ; IF DISKLOG CARMSG: DB '**CARRIER LOST**',0 ; Carrier lost msg TMOMSG: DB '**INPUT TIMEOUT**',0 ; Timout msg DRPMSG: DB '**DROPPED**',0 ; Twit key message VOCMSG: DB '**VOICE CALL**',0 ; Voice call msg LOGFCB: DB LOGDRV-40H,'SYS LOG' ; Log file fcb DS 24 WOFFSET:DB 0 ; Current write offset for log OLDDMA: DW 80H ; Current DMA address BDOSFL: DB 0 ; BDOS call in progress flag TIMSFL: DB 0 ; Time stamp flag LOGTOG: DB 0 ; Log open toggle flag OLDLUS: DS 4 ; Old environment save area RECORD: DS 128 ; Log file buffer HLSAVE: DS 2 ; Temp HL save DS 40 ; Stack area for log routines NEWSTK: DS 0 ENDIF ; DISKLOG ;..... ; ; ;----------------------------------------------------------------------- ; ZCPR external paths ; ; ZCPR's external paths available. (ZCPR will always do the current ; drive/current user area) ; ; Command path available for SYSOP ; IF CHGPATH SYSPATH:DB 1,0 ; Then do A0: DB 1,15 : THEN DO A15: DB 4,15 ; Then do D15: DB 0 ; End of path ; LSYSP EQU $-SYSPATH ; ; ; Command path available for remote user ; REMPATH:DB 1,0 ; Then do A0: (don't do A15:) DB 0 ; End of path LREMP EQU $-REMPATH ENDIF ; CHGPATH ;..... ; ; end of ZCPR external paths ;----------------------------------------------------------------------- ; ; These areas are not initialized ; IF NOT CPM3 PEND EQU $ ; The following area is not initialized ENDIF ; NOT CPM3 ; IF COMFILE OR EXFILE CURRFCB:DS 2 ENDIF ; COMFILE OR EXFILE ; TOCNTM: DS 1 TOCNT: DS 2 MSFLAG: DS 1 ; ; ; Save the CP/M jump table here ; VCOLDBT:DS 3 VWARMBT:DS 3 VCONSTAT: DS 3 VCONIN: DS 3 VCONOUT:DS 3 VLISTOUT: DS 3 VPUNCH: DS 3 VREADER:DS 3 ; ; ; System addresses initialized at program startup ; IF CPM3 SCBBASE:DW 0 ; Base address of the CP/M Plus SCB MEMBASE:DB 0 ; Base page of common memory BDOSBASE: DB 0 ; Base page of BDOS ENDIF ; CPM3 ;..... ; ; ;---------------------------------------------------------------- ; ; ASCII Equates ; CR EQU 0DH ; ASCII carriage return LF EQU 0AH ; ASCII line feed ; LXID EQU 11H ; Define byte of LIX D,nnnn to fake loader LXIH EQU 21H ; Define byte of LXI H,nnnn to fake loader IOBYTE EQU 0003H ; Location of CP/M IOBYTE FCB EQU 005CH FCBRNO EQU FCB+32 ; ; ; CP/M Plus system variable offsets ; IF CPM3 SCBDAT EQU 00F4H ; Offset of date into SCB SCBTIM EQU 00F6H ; Offset of time into SCB SCBCOM EQU 00FAH ; Offset of common memory base page in SCB SCBBDOS EQU 0099H ; Offset of base page of BDOS in SCB ENDIF ; CPM3 ; ; ; BDOS equates ; IF CPM3 BDOS EQU NEXT ENDIF ; CPM3 ; IF NOT CPM3 BDOS EQU 0005H ENDIF ; NOT CPM3 ; CI EQU 1 WRCON EQU 2 DRECTIO EQU 6 PRINTF EQU 9 CSTS EQU 11 SELDSK EQU 14 OPEN EQU 15 SEARCH EQU 17 READ EQU 20 STDMA EQU 26 SETUSR EQU 32 CHAINP EQU 47 GTSCB EQU 49 DEFPAS EQU 106 ; Set default password BDOS function ; DS 40 STACK EQU $ ; Local stack ; IF NOT CPM3 OBJEND EQU $ ENDIF ; NOT CPM3 ;..... ; ; END