; BYE520 - REMOTE CONSOLE PROGRAM FOR CP/M AND MODEM - 01/20/89 ; ; 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 Wayne Masters, Irv Hoff, ; 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 interested 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. ; ; TABBY changes incorportated by Marc Newman, The Black Box DRBBS/TABBY ; 713-480-2686 BBS, FIDONET node 1:106/601 on 1/17/89. Many thanks to ; George, Irv and Wayne, Jack Winslade, and Philip Hansford for all the ; help and encouragement. ; = = = = = = = = ; ; 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 20 MONTH EQU 01 DAY EQU 20 YEAR EQU 89 ; ; ; System equates ; NO EQU 0 YES EQU NOT NO ; For conditional assembly ; ; ; 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+28 ; BYE's highest extended BDOS call CCPL EQU 8 ; Number of sectors for CCP size (norm ; Is 8. Apples with Micrsoft CP/M ; V2.23+ use 9. Systems w/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 (typically 24 or 16). ; An updated Trantor (WL) BIOS is ad- ; Vised for RCP/M use if running a ; Large BBS program. CP/M-3 does not ; Use this or TRANWL equates. ; ;----------------------------------------------------------------------- ; COMPUTER TYPE ; ATR EQU NO ; MEANS KAYPRO ; ;----------------------------------------------------------------------- ; Modem Type ; IMODEM EQU NO ; Yes, for intelligent modem, including ; Hayes B5IM EQU NO ; 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 NO ; Yes for Hayes, ProModem, Courier, RV- ; 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 your modem, then say YES to this COMFILE EQU Yes ; 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 appx 1024 bytes ; Large BBS programs may not work on cp/m 2.2 ; if you use this. LOGUSR EQU 15 ; 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 re-enter BYE cor- ; Rectly or use the EXRET method below ; CPM3 or PBBS users must say YES to this ; QBBS users must say NO, MBBS NO if CP/M 2 ; MBBS YES if using CPM3. DRBBS says no. ; EXRET EQU no ; YES, if your exit file can't preserve the ; Stack and do a normal RETURN. MBASIC, ; "C", and some Pascal programs can't do ; The stack save-return easily. Simply ; POKE FCB+1 (5DH) with 'r' (small r) and ; Do a warmboot (SYSTEM) and BYE5 will ; Handle your exit file return correctly BYHANG EQU NO ; Yes, for BYE5 to say goodbye and hangup ; The phone BEFORE calling your EXIT file ; METAL, & OxGate users must say YES ; PBBS v2.n YES, PBBS 3.0 or > NO ; PBBS v2.n must change EXITFCB to BYE.COM ; Instead of PBYE.COM. DRBBS says YES EXDRV EQU 'A' ; Drive to look for exit .COM file on EXUSR EQU 0 ; User # of .COM file to be called upon ; Exit MSGFIL EQU no ; Yes, if your BBS system allows mes- ; Sages to be uploaded by KMD11 and ; Later with the RM option. KMD11 ; Sets 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 message file.w ; 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 Yes ; 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, PBBS, QBBS users must say YES NO25BF EQU 78 ; Size (bytes) of lc buffer needed by ; Your BBS. MBBS, QBBS = 65 ; METAL, PBBS, OXGATE =78 READLC EQU yes ; Yes, to have BYE read your LASTCALR ; File, No if your BBS pokes LASTCALR ; Into BYE. MBBS, PBBS, QBBS, METAL, ; And OxGate users say NO. DRBBS says yes LCDRV EQU 'A' ; Drive to find LASTCALR or LASTCALR.DAT LCUSR EQU 0 ; User # of LASTCALR or LASTCALR.DAT file ; SKTERM EQU YES ; 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 ; TABBY EQU YES ; If you are running TABBY, and want RECMAIL ; to be run upon receipt of a TSYNC, set this. TSYNC EQU 0AEH ; TSYNC character for TABBY ESC EQU 01BH ; Escape character for TABBY TABCNT EQU 150 ; Wait about 15 seconds NNHOUR EQU 3 ; Define your National Netmail Hour here TBYUSER EQU 0 ; User area for Tabby DISPATCH.COM TBYDRV EQU 'A' ; Drive for Tabby DISPATCH.COm ; WBDRIV EQU 'A'-41H ; Drive to log to on first warmboot to cp/m ; Some add-on hard disk systems want C ; WELFILE EQU NO ; Yes, to send a WELCOME file WELDRV EQU 'A' ; Drive to look for WELCOME??? file WELUSR EQU 14 ; 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 NO ; Yes, for helpful progress reports on ; CRT. Leave this YES until every- ; Thing is working PRNTGB EQU NO ; Yes, print "Goodbye..." message PRNTWB EQU NO ; Yes, print a string for each warm boot PWRQD EQU NO ; Yes, password needed for CP/M access 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 instead of reverse v. RVON1 EQU 1BH ; Set your reverse-on sequence in these 4 RVON2 EQU 0b0h ; Bytes. Set unused bytes to nulls (0). RVON3 EQU 0 ; 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 0c0h ; ESC G0 is reverse video OFF for the 925 RVOFF3 EQU 0 RVOFF4 EQU 0 ; Set unused bytes to 0 ; TOVALUE EQU 5 ; Minutes of no-activity allowed. 255 max. ; ;----------------------------------------------------------------------- ; 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 5 ; 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 after ; Current caller logs off (& 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 YES ; Yes, running MINICBBS..you must also create ; Your COMFCB label ; OXGATE EQU NO ; Yes, running OxGate BBS system PBBS EQU NO ; Yes, running PBBS system QBBS EQU NO ; Yes, running QBBS system RBBS EQU NO ; Yes, running RBBS, sets/resets ; 'WRTLOC' flag DRBBS EQU YES ; Yes, running DRBBS IOVAL EQU 1 ; Initial value for IOBYTE (if MINICK ; YES) LMBELL EQU NO ; Yes, your bbs uses a low-memory bell flag ; MBBS and RBBS users must say YES 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 YES ; Yes, to reset the following byte be- RTOKFG EQU 020H ; Tween calls. PBBS 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 YES ; If YES, add your clock reader code at ; The start of label TIME: and store ; Binary values in CCHOUR and CCMIN ; PBBS and QBBS users must say YES BCD2BIN EQU YES ; Yes, your clock routine calls BCDBIN BIN2BCD EQU YES ; Yes, your clock routine calls BINBCD TIMEON EQU YES ; 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. CLKDSP EQU no ; Do you want a real time clock displayed? ; ; 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 MXTIME=0, this will print ; Time-on-system rather than Time-left... RSPEED EQU NO ; Yes, if you want to limit speeds during ; prime time ; Speed (a clock read routine is re- ; Quired 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 code end. ENDIF ; RSPEED ; ;----------------------------------------------------------------------- ; CCP Options ; ZCPR2 EQU Yes ; Yes, if running ZCPR1/2, ZCMD1/2 or ; NZCPR1/2 ; Yes, 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 14 ; Highest user area SYSDRV EQU 'C'-'@' ; 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 pointers 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|beeps| ; |3 byt|1 byt|1 byt|2 byt|1 byt|2 byte|1 byt| ;----------------------------------------------------------------------- ; 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 BEEPFL: DB 0 ; Flag to enable/disable inactivity beep ; so we don't affect Zmodem transfers ; 0 = beeps enabled, 0FFH = beeps off ; ; 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 ; ;----------------------------------------------------------------------- ; ; ++++ Install your I/O port insert here ++++ ; or select one from the BYE5-INS.LBR IF ATR ; B5AT-1.INS - SWP ATR8000 insert for BYE5 - 11/2/88 ; ; Using ATR8000 ROM and DTR/CTS signals ; by Marc Newman ; The Black Box BBS ; 713-480-2686 ; ; ; Note: This is an insert, not an overlay. ; ; = = = = = = = = = = = = = = = = = = ; ; 11/02/88 Written for use with BYE5 - Marc Newman ; ; = = = = = = = = = = = = = = = = = = ; ; ; ; ; Divisors for the baudrate generator ; BD300 EQU 034a0h ; 300 baud BD450 EQU 027a0h ; 450 bps BD1200 EQU 00da0h ; 1200 bps bd2400 equ 06850h ; 2400 bps ; cominit equ 0f7efh ;atr8000 baud rate routine comout equ 0f79ah ;atr8000 modem output routine cominp equ 0f738h ;atr8000 modem input routine comstat equ 0f715h ;atr8000 modem status routine ; ctsprt equ 50h ;carrier detect port ctsmsk equ 02h ;carrier detect mask ; dtrprt equ 55h ;data terminal ready port dtrmsk equ 01h ;mask for terminal ready port ; rngprt equ 50h ;ring signal port rngmsk equ 04h ;ring signal mask ; ; ;----------------------------------------------------------------------- ; ; See if we still have a carrier - if not, return with the zero flag set ; MDCARCK:in ctsprt ; get carrier status ani ctsmsk ; Check for carrier JZ MDCRCK1 ; GOT IT XRA A ; RETURN ZERO (FALSE) RET MDCRCK1:ORI 0FFH ; RETURN FF (TRUE) RET ;..... ; ; ; Disconnect and wait for an incoming call ; MDINIT: MVI A,DTRMSK ;TURN DTR OFF out dtrprt ;hang up the phone ; PUSH B ; Save in case it's being used elsewhere MVI B,10 ; 1 second delay to drop any carrier ; OFFTI: CALL DELAY ; 1 second delay DCR B JNZ OFFTI ; Keep looping until finished ; XRA A ; Setup to turn DTR back on OUT DTRPRT mvi b,10 OFFTI1: call delay ; 1 second delay dcr b jnz offti1 ; IF IMODEM ; If using an intellegent modem CALL IMINIT ; Go initialize it now ENDIF ; IMODEM ; POP B ; RESTORE BC ; RET ;..... ; ; ; Input a character from the modem port ; MDINP: push b push d push h call cominp ; Get character pop h pop d pop b 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: push b push d push h call comstat ; Get status ORA A ; restore registers jz mdinst1 ori 0ffh jmp mdinst2 mdinst1:xra a ; Otherwise set the proper flag mdinst2:pop h pop d pop b RET ;..... ; ; ; Send a character to the modem ; MDOUTP: PUSH PSW push b push d push h mov c,a call comout ; Send it pop h pop d pop b POP PSW RET ;..... ; ; ; See if the output is ready for another character ; MDOUTST:ORI 0FFH ; ATR8000 is a bitbanger, RET ; so it is always ready for output ;..... ; ; ; Reinitialize the modem and hang up the phone by dropping DTR and ; leaving it inactive. ; MDQUIT: mvi a,dtrmsk out dtrprt IF IMODEM CALL IMQUIT ENDIF ; IMODEM ; ; ; Called by the main program after caller types BYE ; MDSTOP: mvi a,dtrmsk ; Hang up the modem OUT dtrprt RET ;..... ; ; ; The following routine sets the baud rate. BYE5 asks for the maximum ; speed you have available. ; ; SET300: lxi b,BD300 JMP SETBAUD ; SET1200:lxé b,BD1200 JMP SETBAUD ; SET2400:lxi b,BD2400 ; ; ; Sets the baudrate ; SETBAUD:call cominit ;call ATR8000 baud rate routine XRA A ; Say baudrate is ok RET ;..... ENDIF ;ATR ; IF NOT ATR ; 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. ; ; = = = = = = = = = = = = = = = = = = ; ; 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 ;------------------------------------------------------------------------ ENDIF ;NOT ATR ; ; 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 ; ; ; (Replace the following code with your own clock subroutine) ; IF (CLOCK OR RSPEED) AND ATR ; ; B5C-KCT1.INS ; 07/17/85 A TIME insert for BYE500 and up ; Wayne Masters ; Potpourri, 408-378-7474 ; ; This insert is for the Z80 piggyback clock chip from: ; Kenmore Computer Technology ; 20 Londers Rd. ; Kenmore, N.Y. ; (716) 877-0617 ; ; If your computer uses a Z80 chip and does not have a clock ; then this is the clock for you. It installs in minutes. ; Just remove your Z80 chip, install this chip and reinstall ; your Z80 on top. Use an external program to initialize this ; clock prior to loading BYE. (See Z-TIMEn.LBR for this initialization ; program). ; ; ; RTCBUF will have HH, MM, SS, YY, YY, MM, DD as BCD values (see label) ; CCMIN is address for storing current minutes in binary ; CCHOUR is address for current hour in binary. ; ;*********************************************************************** ZPORT EQU 060H ; Board shipped with this as default address ; Change address if you change address jumpers CENTURY EQU 019H ; Change this in year 2000 ; TIME: IN ZPORT+2 ; Seconds STA RTCBUF+2 IN ZPORT+3 ; Get BCD value for minutes STA RTCBUF+1 CALL BCDBIN ; Convert BCD minutes to binary STA CCMIN ; Update the current minute IN ZPORT+4 ; Get BCD value for hour STA RTCBUF CALL BCDBIN ; Convert BCD hour to binary STA CCHOUR ; Update the current hour IN ZPORT+6 ; Day of month STA RTCBUF+6 IN ZPORT+7 ; Month of year STA RTCBUF+5 IN ZPORT+9 ; Year of century STA RTCBUF+4 MVI A,CENTURY ; Set to 19 now STA RTCBUF+3 RET ; Return ; ; End of TIME routine for BYE500 and up. ;------------------------------------------------------------------------ ; ENDIF ; CLOCK OR RSPEED ; IF (CLOCK OR RSPEED) AND (NOT ATR) ; NUC-ADV.INS - KayPro 2/4/10 with Advent Products RTC - 06/17/86 ; ; Note: This is an insert, not an overlay. ; ; ======== ; 06/17/86 First version based on NUC-KP4.INS and time routine found in ; M80CLK.MAC provided with Advent clock - Murray Simsolo ; ======== ; ; Use the program CLK.COM supplied by Advent to initialize your clock with ; correct date/time prior to running NUBYE. ; ; CENTURY EQU 19H ; 19h = 19 bcd, reset this every 100 years RTCA EQU 90H ; Clock I/O port address YRREG EQU 9 ; Year register of Advent clock ; TIME: MVI C,RTCA ; Get port address in C RETRY: LXI H,LOCBUF ; Point to time save area MVI B,2 ; Start with seconds DB 0EDH,078H ; IN A,(C) Read seconds in A MVI B,YRREG ; Set up to read the year DB 0EDH,0A2H ; INI Save in temp buffer DCR B ; Skip to register 7 MVI E,6 ; Set up loop ; BURST: DB 0EDH,0A2H ; INI Get the clock data DCR E ; Count down one JNZ BURST ; Go get more data ; ; See if the clock rolled over during the reads. ; DCX H ; Point to temporary buffer CMP M ; Did clock roll? JNZ RETRY ; Yes, go read again ; ; Format the date and time for bye's realtime clock buffer ; LDA LOCBUF+6 ; BCD seconds STA RTCBUF+2 ; LDA LOCBUF+5 ; BCD minutes STA RTCBUF+1 CALL BCDBIN STA CCMIN ; LDA LOCBUF+4 ; BCD hours STA RTCBUF CALL BCDBIN STA CCHOUR ; LDA LOCBUF+2 ; BCD day of month STA RTCBUF+6 ; LDA LOCBUF+1 ; BCD month STA RTCBUF+5 ; MVI A,CENTURY STA RTCBUF+3 LDA LOCBUF ; BCD year STA RTCBUF+4 RET ; All done ; LOCBUF: DB 0,0,0,0,0,0,0 ; Year, Month, Day of Month, Day of Week, ; Hour, Minute, Second ; ; ; end of insert ; ;----------------------------------------------------------------------- ENDIF ; ; 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,22 ; 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,400 ; Try for 400 ms ; CHECK2: CALL KDELAY DCX B MOV A,B ORA C JZ CHECK3 ; 600 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,6 ; 6 sec more with 1 sec already ; Used= 1.6 sec CALL DLP1 ; Wait to enter terminal mode CALL EATALL ; Clear input port (takes .4 sec more) 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 OR TABBY)) 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 OR TABBY JMP LOGOFF ; Run the exit file ENDIF ; EXFILE OR TABBY ; IF PRNTGB AND (NOT (EXFILE OR TABBY)) LXI H,GBMSG ; Goodbye message CALL PRINTB ; Print this message ENDIF ; PRNTGB AND NOT EXFILE OR TABBY ; IF NOT (EXFILE OR TABBY) CALL IMDONE ; Hang up the phone before doing this CALL UNPATCH ; Undo BIOS patches ENDIF ; NOT EXFILE OR TABBY ; ;..... ; IF DISKLOG AND (NOT (EXFILE OR TABBY)) LXI H,DSCMSG ; Disconnect message CALL WRTMSG ; Put it into log file ENDIF ; DISKLOG AND NOT EXFILE OR TABBY ; ; ; 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 TABBY ; Makes TABBY output more readable LXI H,CRMSG CALL PRINTL ENDIF ; TABBY ; 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 ; 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: IF TABBY CALL GETNXE ; Find NXTEVENT file and read ENDIF ; TABBY ; IF TABBY AND (NOT CLKDSP) LDA NXTHR CALL BCDBIN LXI H,EVENHR CALL DEC8 ; LDA NXTMN CALL BCDBIN LXI H,EVENMN CALL DEC8 LXI H,TIMESG CALL PRINTL ENDIF ;TABBY AND NOT CLKDSP ; RINGW: IF CLKDSP OR TABBY CALL TIME ; Update time buffer ENDIF ; CLKDSP OR TABBY ; IF CLKDSP ; ; Format the date and time for bye's realtime clock buffer ; LDA RTCBUF+2 ; BCD seconds CALL BCDBIN LXI H,TIMESG+17 CALL DEC8 ; LDA RTCBUF+1 ; BCD minutes CALL BCDBIN ; Convert to binary LXI H,TIMESG+14 CALL DEC8 ; LDA RTCBUF ; BCD hours CALL BCDBIN ; Convert to binary LXI H,TIMESG+11 CALL DEC8 ; LDA RTCBUF+6 ;BCD day CALL BCDBIN LXI H,TIMESG+8 CALL DEC8 ; LDA RTCBUF+5 ; BCD month CALL BCDBIN LXI H,TIMESG+5 CALL DEC8 ; LDA RTCBUF+4 ; BCD year CALL BCDBIN LXI H,TIMESG+2 CALL DEC8 ENDIF ; CLKDSP ; IF CLKDSP AND TABBY LDA NXTHR CALL BCDBIN LXI H,EVENHR CALL DEC8 ; LDA NXTMN CALL BCDBIN LXI H,EVENMN CALL DEC8 LXI H,TIMESG CALL PRINTL ENDIF ; CLKDSP AND TABBY ; ; IF TABBY LDA NXTHR ; Hour of next event for Tabby LXI H,RTCBUF CMP M ; Right hour? JNZ RINGW0 ; Nope ; LDA NXTMN ; Minute of next event for Tabby LXI H,RTCBUF+1 ; Address of minutes CMP M ; Right minute? JNZ RINGW0 ; Nope JMP TBYEXIT ENDIF ; TABBY ; RINGW0: 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 RINGW ENDIF ; B5IM ; IF NOT B5IM CALL MDCARCK ; Carrier? JZ RINGW ; 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 ENDIF ; NOT B5IM ; IF NOT TABBY CALL MDINP ; Clear garbage characters CALL MDINP ENDIF ; NOT TABBY ; IF NOT B5IM ; ; ; 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 (MKN111788) 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 RBBS OR MBBS OR PBBS OR QBBS OR DRBBS LDA WRTLOC ; Get write in progress flag ORA A RNZ ; Busy, wait until done ENDIF ; RBBS OR MBBS OR PBBS OR QBBS OR DRBBS ; 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 ENDIF ; EXFILE ; IF (TABBY OR EXFILE) AND (NOT BYHANG) CALL MDCARCK ; Still have carrier after exfile ran? JZ TBYEXIT ; No, skip this ENDIF ; EXFILE AND NOT BYHANG ; IF CLOCK AND TIMEON AND (EXFILE OR TABBY) AND (NOT BYHANG) CALL RMTOS ; Print time data ENDIF ; CLOCK..... ; IF PRNTGB AND (EXFILE OR TABBY) AND (NOT BYHANG) LXI H,GBMSG CALL PRINTB ; Pring goodbye ENDIF ; PRNTGB... ; TBYEXIT: IF TABBY CALL UNPATCH LHLD REALBD+1 SHLD BDOS+1 ; RESTORE REAL BDOS MVI C,SETUSR MVI E,TBYUSER CALL BDOS MVI C,SELDSK MVI E,TBYDRV-'A' CALL BDOS LXI H,CRMSG CALL PRINTL LXI H,DSPMSG CALL PRINTL CALL LODTBY CALL MDQUIT ; Make sure no caller left online MVI A,TBYUSER*010H+TBYDRV-'A' ;This makes SURE we are on STA 0004H ; the right drive and user for $$$.sub files ENDIF ; TABBY ; IF TABBY AND (ZCPR2 OR ZCPR3) MVI A,0FFH STA WHEEL ; Let the $$$.SUB file do important commands ENDIF ; TABBY AND (ZCPR2 OR ZCPR3) ; IF TABBY AND DISKLOG MVI E,0 CALL TSTHRD ; Close the disk log ENDIF ; DISKLOG ; IF TABBY MVI A,0 STA 080H ; Make SURE Tabby sees a null command tail MVI A,' ' STA 05DH ; JMP 100H ; DISPATCH does it's own return ENDIF ; TABBY ; IF NOT TABBY JMP PREOFF ; Prepare for next caller ENDIF ; NOT TABBY ;..... ; ; ;----------------------------------------------------------------------- ; ; 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 ZCPR2 OR ZCPR3 MVI A,SYSUSR+1 ; Sysops maxuser STA MAXUSER ; To low memory MVI A,SYSDRV-1 ; Sysops maxdriv STA MAXDRIV ; To low memory 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 JMP BEEPTOG ; Enable/disable inactivity beep flag ; ; ; 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 JMP SETGET1 ; RMXUSR: LXI H,MXUSR ; Set/get maximum user area 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 ; BEEPTOG: LXI H,BEEPFL ; Enable/disable inactivity beep flag JMP SETGET2 ; for ZMODEM download <6lj/rmj> ; 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 RET ; SGET1: MOV A,M ; Return with current value in A 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 MVI A,SYSUSR+1 STA MAXUSER ; And MAXUSR MVI A,SYSDRV-1 STA MAXDRIV ; And MAXDRIV ENDIF ; ZCPR2 OR 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 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 ; IF TABBY LODTBY: LXI H,TBYXFCB SHLD CURRFCB LXI H,TBYXFCB+12 MVI B,21 CALL ZEROM LXI D,TBYXFCB CALL OPENFIL JZ ABORT ; Cannot open file, finish BYE hangup ENDIF ; TABBY ; ; ; Now load the file ; IF COMFILE OR EXFILE OR TABBY 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 OR TABBY ;..... ; ; 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 MSGFIL ; See if KMD RM'ed a file LDA 0 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 OR TABBY) AND (NOT PBBS) 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 OR TABBY AND NOT PBBS ; IF (EXFILE OR TABBY) AND (NOT (MBBS OR PBBS)) JMP LOGOFF ; Run exit file locally ENDIF ; EXFILE AND NOT MBBS/PBBS ; IF COMFILE AND (NOT PBBS) JMP START0 ; And start fresh ENDIF ; COMFILE AND NOT PBBS ; 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 CONSTAT ; Check for console input (bye510.fix) ; ORA A ; Got console input? (bye510.fix) ; JNZ CONIN ; Yep, get the console character(bye510.fix) CALL MSTAT ; Nope, check for modem input ORA A ; Got modem input? JZ MINP2 ; Nope, loop again CALL CONSTAT ; Check for console input (bye510.fix) ORA A ; Got console input? (bye510.fix) JNZ conin ; Yep, get the console character (bye510.fix) 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 ; LDA MDMOFF ORA A MVI A,0 JNZ MSTAT1 ; 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: CALL CONSTAT ; Check local keyboard status (bye510.fix) ORA A ; anything there? (bye510.fix) JNZ MSTAT0 ; yep (bye510.fix) 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: LDA BEEPFL ; If beeps allowed ORA A ; JNZ MSTAT5 ; MVI A,'G'-'@' ; Beep the user CALL MDOUTP ; MSTAT5: ; 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 ; IF TABBY AND (NOT B5IM) RZ CPI ' ' ; TABBY needs to know a space, for WHACKS RZ CPI TSYNC ; Was it an early TSYNC? ENDIF ; TABBY AND NOT B5IM ; 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 ; COMMENTED OUT MARC NEWMAN 5/17/88 ; CALL MDINP ; Clear garbage from modem input ; IF NOT SKTERM CALL MINPUT ; Accept any character, then proceed ENDIF ; NOT SKTERM ; IF TABBY ; If you are running Tabby LXI B,TABCNT ; Number of tenths to check for TSYNC NOTTBY: PUSH B LDA CCHOUR CPI NNHOUR ; Is it National Netmail Hour? JNZ NOTNNH ; Nope LXI H,NNHMSG JMP PTBYMS NOTNNH: LXI H,TBYMSG ; Tell them to wait or hit PTBYMS: CALL PRINTB ; Print the message POP B WAITBY: CALL DELAY ; Wait 1/10th of a second DCX B ; Decrement counter MOV A,B ORA C JZ WELC1 ; Timed out, go run BBS CALL MDINST ; And see if a character is waiting ORA A ; See if we got anything JZ WAITBY ; Nothing yet, go wait again CALL MDINP ; Ok, let's get this character CPI TSYNC ; Is it a TSYNC? JZ GETTBY ; Time to load Tabby CPI ESC ; Is it an Esacape? JNZ NOTTBY ; No, go wait some more LDA CCHOUR CPI NNHOUR ; Is this National Netmail Hour? JZ WAITBY JMP WELC1 ; GETTBY: CALL UNPATCH ; Get rid of BYE LHLD REALBD+1 SHLD BDOS+1 ; This completely gets rid of BYE LXI H,CRMSG CALL PRINTL LXI H,RMAILNM CALL PRINTL ; Print out the name of the com file ; MVI C,SETUSR ; User area set call MVI E,TBYUSER ; Set up user area CALL BDOS MVI C,SELDSK ; Drive set call MVI E,TBYDRV-'A' ; Drive com file is on CALL BDOS MVI A,TBYUSER*010H+TBYDRV-'A' ;This makes SURE we are on STA 0004H ; the right drive and user for $$$.sub files ; LXI H,TBYFCB ; Address of RECMAIL.COM FCB SHLD CURRFCB LXI D,TBYFCB CALL OPENFIL JZ ABORT ; Error, abort CALL LOADFIL MVI A,0 STA 080H ; Make SURE Tabby sees a null command tail MVI A,' ' STA 05DH ENDIF ; Tabby ; IF TABBY AND (ZCPR2 OR ZCPR3) MVI A,0FFH ; Just in case a window opens while RECVMAIL STA WHEEL ; runs, turn the wheel on so $$$.SUB can do ; important things like ERA and REN ENDIF ; TABBY AND (ZCPR2 OR ZCPR3) ; IF TABBY AND DISKLOG MVI E,0 CALL TSTHRD ; Turn disk log off ENDIF ; DISKLOG ; IF TABBY JMP 100H ENDIF ; Tabby ; ; 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 MSTAT ; Check for character typed ORA A JZ WELTYPE ; No, loop CALL MINPUT ; Yes, get character 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 MSTAT ORA A ; Has another char been typed? JZ WAIT ; No, wait CALL MINPUT ; Yes, check character 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 ; IF TABBY ; ; Get the time (hour and minute) of the next tabby event GETNXE: MVI C,SELDSK MVI E,TBYDRV-'A' CALL BDOS ; MVI C,SETUSR MVI E,TBYUSER CALL BDOS MVI A,TBYUSER*010H+TBYDRV-'A' ;This makes SURE we are on STA 0004H ; the right drive and user for $$$.sub files ; LXI D,80H MVI C,STDMA CALL BDOS ; LXI D,EVNTFCB MVI C,OPEN CALL BDOS INR A JZ TBYEXIT ; No NXTEVENT file found, try to create one LXI D,EVNTFCB MVI C,READ CALL BDOS ; LXI D,EVNTFCB MVI C,CLOSE ; CLOSE CALL BDOS ; LDA 80H+8 ; ADDRESS OF NEXT EVENT HOUR CALL BINBCD STA NXTHR ; LDA 80H+10 ; ADDRESS OF NEXT EVENT HIMUTE CALL BINBCD STA NXTMN ; LDA 80H+14 ; NEXT EVENT LENGTH CALL BINBCD STA NXTLEN ; LDA 80H+22 ; NEXT EVENT NAME STA NXTEVN ; RET ENDIF ;TABBY ;..... ; ;----------------------------------------------------------------------- ; 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 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! 1200 or 2400 baud only allowed 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,7,CR,LF,CR,LF DB ' Your time is up - wait 24 hours to call back',CR,LF,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 ; RTCBUF: ; ; 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) ; ; 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 ' - Hit any key to continue: ' ENDIF ; NOT SKTERM ; DB CR,LF,CR,LF,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 ; 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 03AH,0 ; Parameter block for extracting SCB ; Start address ENDIF ; CPM3 ; IF COMFILE OR EXFILE OR TABBY 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 OR TABBY ; IF EXFILE EXTMSG: DB 'Exit ',0 ; Filled by loader ENDIF ; EXFILE IF TABBY NXTHR: DB 0 NXTMN: DB 0 NXTLEN: DB 0 NNHMSG: DB 'Processing mail only now -- please call back later.',CR,0 ENDIF ; TABBY ; IF CLKDSP OR TABBY TIMESG: ENDIF ; CLKDSP OR TABBY ; IF CLKDSP DB '1988/12/31 08:01:01 ' ENDIF ; CLKDSP ; IF TABBY DB ' Next TABBY event (' NXTEVN: DB 0 DB ') at ' EVENHR: DB ' :' EVENMN: DB ' ' ENDIF ; TABBY ; IF TABBY OR CLKDSP DB CR,0 ENDIF ; TABBY OR CLKDSP ; IF TABBY EVNTFCB:DB 0,'NXTEVENT ' ; 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 ENDIF ; TABBY ; 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 PBBS COMFCB: DB 0,'PBBS 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 PBBS ; IF COMFILE AND DRBBS COMFCB: DB 0,'DRBBS COM' ; DRBBS 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 DRBBS ; 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 PBBS DB 0,'PBYE 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 PBBS ; IF TABBY TBYXFCB:DB 0,'DISPATCHCOM' ; 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 DSPMSG: DB 'DISPATCH',0 ; TBYFCB: DB 0,'RECVMAILCOM' ; 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 RMAILNM:DB 'RECVMAIL',0 ENDIF ; TABBY ; 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 TABBY ; Print this message for TABBY TBYMSG: DB 'Wait a few seconds or hit ',cr,0 ENDIF ; 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 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 OR TABBY 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 CLOSE EQU 16 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 60 STACK EQU $ ; Local stack ; IF NOT CPM3 OBJEND EQU $ ENDIF ; NOT CPM3 ;..... ; ; END