; >>> MBYE -- Version 4.5 -- 07/13/86 -- by Kim Levitt & Lavern Ogden <<< ; ; MBYE (MODULAR 'BYE') ; REMOTE CONSOLE PROGRAM FOR CP/M AND MODEM ; (includes optional support for MBBS(tm) msg system) ; ; 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. This is based on a program written by Dave ; Jaffe in January, 1979. A number of external routines are available ; to adapt this program to various computers. It may be assembled with ; ASM, LASM, MAC, SLRMAC, or M80. If you use M80 uncomment the line ; containing the pseudo-op ASEG. ; ; MBYE is placed in the public domain. It may be updated or altered but ; should again be placed in the public domain. Send a copy of any new ; changes to the MBBS Headquarters RCP/M at (213) 653-6398 (300/1200/2400 ; bps, 24 hrs). (Many changes are planned, so central coordination of ; updates/fixes and new overlays will be useful.) ; ; NOTE: Equates in this version (as released) are set for a typical RCPM ; system using MBBS and XMODEM version 11.8 or higher. Customization and ; changes will still be needed in many cases however: READ ALL COMMENTS ; next to the equates and set them carefully. Also note that you must ; include overlay(s) for your equipment and customize code at the end of ; this program as well. ; ;======================================================================= ; ; (Put only the current update comments here, move the previous one ; with the others in the MBYE41.HIS modification history file. This ; will assist those who want to see "what is new" and keep the size ; of the main source down to a reasonable size.) ; ; 07/13/86 Restored Kim and Lavern's names as the rightful authors ; MBYE-45 (Note to P.D. Smith - fixing one ENDIF does not make you ; the author). Installed most of the modifications in ; MBYE41.FIX and MBYE&K10.DOC (improves TOPDSP and LINE25 ; operation and fixes conditional assembly bugs). Corrected ; many nested IF-ENDIF statements (would not assemble correctly ; with ASM.COM). Eliminated Televideo-specific equate and ; code. Changed BYE5RSX equate to BYEBDOS to be consistent ; with other programs such as CHAT and XMODEM. Added notes ; to BYELOW and BYEBDOS equates to prevent possible system ; crash caused by setting BYEBDOS to YES and BYELOW to NO. ; - Murray Simsolo ; ;======================================================================= ; ; ASEG ;Uncomment this line if using M80 ; ;======================================================================= ; ; If the option BYELOW is set 'NO' it automatically locates itself above ; the BIOS at top of memory. Otherwise it sits just below CCP, not re- ; quiring any alteration in the location of CP/M via MOVCPM. ; ; MBYE Notes: This update of BYE contains a special loader routine ; which will compute the proper offset with which to relocate BYE. The ; loader routine is based on a routine used in the Consolx (tm) program ; sold by Hawkeye Grafix. This loader, greatly modified and enhanced, ; will load MBYE below the CCP or above the BIOS as desired. All you ; need to do is: (1) choose the desired options, (2) patch in the file ; for your computer/modem in the +++ area, (3) finish editing then as- ; semble, load and use. ; ; NOTE: EARLIER VERSIONS OF BYE REQUIRED A LOT OF EXTRA WORK TO USE THE ; BYELOW OPTION. THIS VERSION REQUIRES NO ADDITIONAL WORK OR IN- ; FORMATION TO BE SUPPLIED. IT WILL LIKELY REPLACE ALL VERSIONS ; USED IN HIGH RAM (ABOVE BIOS) SINCE NO EXTRA WORK IS REQUIRED. ; >> NOTE HOWEVER, THAT SOME PROGRAMS, (SUCH AS SD, FOR INSTANCE), ; MAY REQUIRE YOU TO DIRECTLY SPECIFY THE LOCATION OF THE BDOS ; IF YOU ARE RUNNING BYELOW. OTHER PROGRAMS MAY ALSO HAVE PROBLEMS ; RUNNING UNDER BYE IF THEY USE THE LOCATION AT 0006H TO DETERMINE ; THE LOCATION OF THE BDOS, CCP OR BIOS.. (THEREFORE THE PREFERRED ; METHOD IS STILL TO REGENERATE YOUR SYSTEM, (IF NECESSARY), SO ; THAT BYE CAN RUN IN HIGH RAM...) ; ;======================================================================= ; ; (NOTE: You MUST use an MBYE overlay and patch it in the area below ; designated with four plus signs "+".) (If you use an RTC, you will ; also need an overlay with the CLOCK routine which should be included ; in the file right after the modem routines.) See the MBYEOVL2.DQC ; file in the MBYEOVL2.LBR library file for more information on avail- ; able MBYE overlays to support various systems. ; ; Most users of this program will have an auto-answer modem such as the ; Hayes 300 or 1200, the U.S. Robotics or Rixon. A routine that supports ; these modems has been included. Set the appropriate equate to 'YES' ; if you have one of these modems, all no if another type of auto-answer ; modem such as the PMMI, Bell 212A, etc. is being used. ; ; NOTE: Do NOT try to use standard BYE3 overlays as-is with MBYE, elimi- ; nate the MDQUIT, and make MDINIT leave DTR off, MDANSW raise it. ; Set SMODEM EQU YES if you are using a Hayes Smartmodem, see be- ; low for recommended switch settings. ; ; NOTE: The correct routine would be inserted very near the end, in the ; area marked "+++ INSTALL YOUR MODEM ROUTINES HERE +++". Then ; edit the options, reassemble, load and it will be ready to use. ; (Look for four "+"'s in a row to find it quickly...) ; ;======================================================================= ; ; Current MBYE revision number ; MBVERS EQU 4 ; MBYE version MBINT EQU 5 ; MBYE interium version VMONTH EQU 07 ; Version month VDAY EQU 13 ; Version day VYEAR EQU 86 ; Version year ; ;======================================================================= ; ; System equates ; NO EQU 0 ; For conditional assembly YES EQU NOT NO ; (= 0FFFFH usually, not 0FFH) ; OFF EQU 0 ; For single byte flags ON EQU 0FFH ; CR EQU 0DH ; ASCII carriage return LF EQU 0AH ; ASCII line feed BS EQU 08H ; ASCII backspace ESC EQU 1BH ; ASCII escape ; IOBYTE EQU 0003H ; Location of CP/M iobyte FCB EQU 005CH FCBRNO EQU FCB+32 ; ; ; BDOS equates ; BDOS EQU 0005H SELDSK EQU 14 OPEN EQU 15 READ EQU 20 STDMA EQU 26 SETUSR EQU 32 ; ; ; You will likely also want to change the password, located below at ; label 'PASSWD', and the messages printed at label 'WELCOME' and just ; above label 'HANGUP'. The names of the welcome and .com files are at ; labels 'WELFIN' and 'COMFCB' respectively. ; ;*********************************************************************** ; ; OPTION CONFIGURATION SECTION ; ;*********************************************************************** ; ;----------------------- general options ------------------------------- ; BYELOW EQU YES ; Yes, running BYE3 below CCP; no for ; ; above BIOS ; ; NOTE THAT BYELOW MUST BE SET TO YES IF BYEBDOS IS SET TO YES!!! ; ; IF YOU SET BYELOW EQU YES, DON'T WORRY ABOUT THESE NEXT TWO EQUATES. ; ; IF YOU SET BYELOW EQU NO, HOWEVER, CHECK THESE FOR YOUR PARTICULAR ; SYSTEM. SOME SYSTEMS HAVE SCRATCH RAM AT THE TOP USED BY THE BIOS, ; SO RAMTOP MAY NOT EQUAL 0FFFFH ON A 64K RAM SYSTEM. BIOSEND SHOULD BE ; SET TO EQUAL THE LAST ADDRESS USED BY YOUR BIOS OR XBIOS, AND IS USED ; TO MAKE SURE THAT BYE WILL NOT STOMP ON YOUR SYSTEM IMAGE WHEN LOADED. ; IF NOT BYELOW ; BIOSEND EQU 0EFFFH ; END of BIOS/XBIOS, BIOSEND+1 = first ; ; available RAM ; ; ^ (IF RUNNING BYE ABOVE THE BIOS IT MUST FIT BETWEEN THESE TWO ; v ADDRESSES) ; RAMTOP EQU 0FBFFH ; Last available RAM if BYELOW is 'NO' ; ENDIF ; ; Set BYEBDOS to YES if you want to run a program such as KMD which requires ; the extended BDOS calls used in BYE5, NUBYE, and BYE339. Note that you ; MUST run BYELOW if you choose this option. ; BYEBDOS EQU NO ; Include BYE5 type RSX bdos calling routine ; BYELOW MUST BE YES IF BYEBDOS IS YES!!! LOCMD EQU 61 ; BYEs lowest rsx extended bdos call HICMD EQU LOCMD+24; BYEs highest rsx extended bdos call ; ; Code is included in this version of BYE to support the Hayes Smart- ; modems (300 and 1200), you must also include an overlay for your ; particular UART or serial I/O board, in addition to setting the ; SMODEM or SM1200 equates below. Set SMODEM to YES if you have a ; Smartmodem 300, SM1200 to YES if you have a Smartmodem 1200, or both ; to NO if you are using an external modem which doesn't require com- ; mands. (External modems which will answer an incoming call if DTR is ; raised and will hang up if DTR is lowered should work with this pro- ; gram if SMODEM and SM1200 are no.) ; ; (NOTE: If you have an Anchor Signalman Mark XII or a U.S. Robotics ; 212A or Password, do NOT set SMODEM or SM1200, just the appropriate ; ANCHOR or USR equates respectively.) ; ; Pick ONE of the below equates if you have an external "Smart" modem. ; Also be sure to set NORING EQU YES, (even if your computer can detect ; rings), and set the appropriate baud rate S110-S2400 and SINGLE equ's ; for your particular modem. ; SMODEM EQU NO ; Yes if Smartmodem 300 SM1200 EQU YES ; Yes if Smartmodem 1200 USR2400 EQU NO ; Yes if USR Courier 2400 ANCHOR EQU NO ; Yes if Anchor Signalman Mk XII USR EQU NO ; Yes if US Robotics 212A or Password ; ;----------------------------------------------------------------------- ; IOVAL EQU 0 ; Initial value for IOBYTE (only if MINICK 'YES') MINICK EQU NO ; Yes, running MINICBBS MBBS EQU YES ; Yes, running MBBS message/mail system (tm) MBLOG EQU YES ; Yes, running MBBS4.0 & up / Login (MLOGIN) MBFMSG EQU YES ; Yes, running MBBS and MFMSG for mail uploads OXGATE EQU NO ; Yes, running OXGATE RCPM-BBS system RBBSCK EQU NO ; Yes, running RBBS - sets/resets 'WRTLOC' flag ; ;----------------------------------------------------------------------- ; ; Set only ONE of the below to equ YES, (usually NODEV) (or all NO). ; If you set all to NO, the LST:, RDR: and PUN: devices will not be ; patched during remote operation. Note that patching the LST: device ; does not interfere with the HARDLOG option. ; ALLDEV EQU NO ; Yes, patch PUN:, RDR: & LST: devices to modem NODEV EQU YES ; Yes, make PUN:, RDR: & LST: dummy calls PRINTER EQU NO ; Yes, patch LST: to modem, retain RDR: & LST: ; ; ; Miscellaneous options: ; CHKDSK EQU YES ; Yes, check for valid disk drive CHKUSR EQU YES ; Yes, check for valid user number COMFILE EQU YES ; Yes, chain a .COM file upon carrier reception DECIMAL EQU YES ; Yes, decimal value for userlog DOWNMIN EQU 2 ; # of mins before timeup logoff for warning (if RTC) EXFILE EQU NO ; Yes, chain a .COM file upon loss of carrier HARDLOG EQU NO ; Yes, echo remote input to printer INITBEL EQU NO ; Yes, console bell initially is on (sysop home) LGONMSG EQU NO ; Yes, print message before "how many nulls" msg PRNTGB EQU YES ; Yes, print "Goodbye..." message PRNTWB EQU NO ; Yes, print a string each time system warm boots PWRQD EQU NO ; Yes, password needed to login REENTR EQU YES ; Yes, .COM file code re-entrant (avoids reloads) TIMEOUT EQU YES ; Yes, auto logout for sleepy callers (NO RTC NEEDED) TIMEUP EQU NO ; Yes, RTC and time limit desired (MXML) TOMINS EQU 2 ; Minutes to auto logout (if TIMEOUT) TRAPCC EQU NO ; Yes, trap ctrl-C's if location 0 <> C3H TRAPCP EQU YES ; Yes, trap ctrl-P's TRAPLC EQU NO ; Yes, ask if lower case ok/make upper case if not USRLOG EQU NO ; Yes, count number of users WBRTN EQU NO ; Yes, do function each time system warm boots DISWT EQU NO ; Yes, to display 'waiting for call' message on ; local screen while waiting for action ; ; ;---------- local console special function keys ---------------- ; AWHL EQU NO ; A key to toggle the wheel only. LKEY EQU YES ; Include the "GO LOCAL AFTER CALL" key UTKEY EQU NO ; Include the Unlimited time key AWHLKEY EQU 'A'-40H ; Key to toggle the wheel (& change path if ZCPR3) BLNKKEY EQU 'B'-40H ; Key to "blank out" remote terminal SYSDKEY EQU 'D'-40H ; Key to print "System going down soon..." BELKEY EQU 'G'-40H ; Key to toggle console bell on/off LCKEY EQU 'L'-40H ; Key to get system after current caller is through TWITKEY EQU 'N'-40H ; Key to hangup modem immediately (Nurdkey) MSGKEY EQU 'O'-40H ; Key to enter "Message from SYSOP: " routine ULTKEY EQU 'U'-40H ; Key to grant caller unlimited time (sets ACFL) CALKEY EQU 'W'-40H ; Key to show current caller/status on console CLRKEY EQU 'Z'-40H ; Key to clear screen (waiting for call mode only) ; ; ;---------- system and hardware dependent options -------------- ; ; BLKOUT EQU YES ; Turn off remote send (ctrl-B function) CLOSS EQU 1 ; If carrier dies, wait 1 sec. before hanging up HOMEDSK EQU 'A' ; "Home" disk for extend and reset after du error HOMEUSR EQU 0 ; "Home" user for extend and reset after du error COMDSK EQU 'A' ; Disk for .COM file.. COMUSR EQU 0 ; User # of .COM file to be called after answer MFMDSK EQU 'A' ; Disk for MFMSG.COM MFMUSR EQU 14 ; User # of MFMSG.COM (called for msg uploads) MLGDSK EQU 'A' ; Disk for LOGIN.COM file.. MLGUSR EQU 14 ; User # of LOGIN.COM file to be called after answer CPM2 EQU YES ; Yes, using CP/M 2.2 CTRLC EQU 'K'-40H ; Map ^C to this if 0000H<>C3H CWAIT EQU 20 ; Wait up to 20 seconds for carrier at first EXDSK EQU 'A' ; Disk for EXIT.COM EXUSR EQU 14 ; User # of EXIT.COM file to be called upon exit INULLS EQU 5 ; Initial number of nulls LOSER EQU NO ; Yes, warm boot overwrites part of the BIOS LXID EQU 11H ; Define byte of LXI D,nnnn to fake loader LXIH EQU 21H ; Define byte of LXI H,nnnn to fake loader MHZ EQU 40 ; Processor speed MHz * 10 (2.5MHz=25, 5MHz=50, etc.) NORING EQU YES ; Yes, UART ring indicator NOT avail (or Smartmodem) NULSPRT EQU NO ; Yes, nulls print on console, filter out (Kaypro2) NZCPR EQU NO ; Yes, if running NEWZCPR under secure mode RTC EQU NO ; Yes, if RTC (include CLOCK routine, see RTCBUF:) MXLT EQU 10 ; Maximum minutes allowed for log on if RTC YES SMAXDRV EQU 3 ; Number of drives available to SYSOP (0-15) SMAXUSR EQU 15 ; Maximum user area available to SYSOP (0-15) SPDBYTE EQU YES ; Yes, set speed value in MSPEED location TMINS EQU ((TOMINS*MHZ)+5)/10 ; (Don't change this one...) WELFILE EQU NO ; Yes, to send a WELCOME file WELDSK EQU 'A' ; Disk for WELCOME file WELUSR EQU 14 ; User # of WELCOME file ZCPR2 EQU NO ; Yes, if running ZCPR2/3 with wheel byte ZILOG EQU NO ; Yes, using a Z-80 or Z-800 ZMCMDB EQU NO ; Yes, if ZCPR2 multiple command line buffer ZPATH EQU NO ; Yes, if ZCPR path (set base address in PATHADR) ZSHELL EQU NO ; Yes, if ZCPR3 shell stack to clear ZTCP EQU NO ; Yes, if ZCPR3 TCP area to clear ZMSGB EQU NO ; Yes, if ZCPR3 message buffer to clear MCMDBA EQU 0F200H ; Multi-cmd buffer base address if ZMCMDB true MCMDBS EQU 200 ; Multi-cmd buffer size in bytes if ZMCMDB true PATHADR EQU 0040H ; ZPATH, set base addr here and setup DEFPATH below Z3ENV EQU 0EF00H ; Enviornment descriptors SHSTK EQU 0F000H ; ZCPR3 shell stack SHSTKS EQU 4 ; Number of SHSIZE-byte shell stack entries SHSIZE EQU 32 ; Size of a shell stack entry ; (Stack size = SHSTKS * SHSIZE) Z3MSG EQU 0F080H ; ZCPR3 message buffer ; ; ; Special Option Configuration Section ; AULOGOFF EQU NO ; If yes then SYSDOWN key automatically logs off EXTEND EQU NO ; If using EXTEND D/U feature MBYETOS EQU NO ; If YES, page zero location stuff with TOS MNULL EQU YES ; Adds number of NULL question tries b/f logoff MNULLS EQU 9 ; Number of MNULL question tries before logoff SDMCL EQU NO ; If YES, page zero column byte for SD is set SDMCI EQU 4 ; Initial value to put into MCL if SDMCL EQU YES MCL EQU 4DH ; Location of page zero column byte for SD TOS EQU 4EH ; Location of page zero TOS word if MBYETOS TLEFT EQU YES ; Display time left with ^T MTDISP EQU YES ; Display maximum time allowed in user display ; ; ;----------------------------------------------------------------- ; ; MBBS current user display options (pick ONE): ; ; NORMAL - Current user info printed on local console ; when ^W pressed on local console keyboard. ; ; TOPDSP - Current user info displayed on top two lines ; of console screen. Your console must be a ; CRT capable of direct cursor addressing and ; (ideally) a delete line (NOT erase to end of ; line) function. ; ; LINE25 - If your terminal supports a special 25th line, ; select this option. ; ; If you select TOPDSP or LINE25, you MUST find out the proper escape ; sequences for your terminal and set up the areas designated in the ; USRMSG: area near the bottom of this program. See below for more in- ; formation. If you pick TOPDSP, set TOPDEL to YES if your terminal ; supports the delete line function, no if it doesn't. Also, set TOPEOL ; if your terminal supports erase to end of line or not. DON'T FORGET ; TO SET UP THE ESCAPE SEQUENCES. When using TOPDSP or LINE25, the ^W ; key will toggle the user display on and off. You may want to enable ; the NODSP24 option if you notice a considerable delay during linefeeds ; at 2400 baud. ; ; NOTE: If your terminal is memory mapped or is very slow, you may have ; a noticeable delay during linefeeds. You can enable the "NODSP24" ; equate if you wish the current user display to be turned off when ; 2400 baud calls come in. ; NORMAL EQU YES ; Just CR/LF's at start and end.. TOPDSP EQU NO ; Show on top two lines of screen TOPDEL EQU YES ; Terminal supports DELETE LINE TOPEOL EQU YES ; Terminal supports ERASE TO END OF LINE TOPWRP EQU YES ; Terminal auto wraps after 80 chars NODSP24 EQU NO ; If yes, don't show if 2400 baud LINE25 EQU NO ; Show one line only on line 25 USERDSP EQU NO ; If yes, USER display initially is on ; ; SET UP ESCAPE SEQUENCES AT USRMSG: AREA AT END OF THIS FILE ; ;---------------------------------------------------------------- ; ; Set these equates to indicate which baud rates your modem is capable ; of supporting and you wish to allow. This will save some unnecessary ; code and if you select SINGLE (if you only support a single baud rate) ; it will save time during initial connect. (It will also prevent log- ; ons at a slow speed if you specify NO for the speeds you do not wish ; to support.) ; SINGLE EQU NO ; Yes if only one of the below supported & allowed S300 EQU YES ; Yes, " " 300 " S1200 EQU YES ; Yes, " " 1200 " S2400 EQU NO ; Yes, " " 2400 " ; ; ; If USEZCPR is YES, MBYE will poke the page zero locations MAXDRIV and ; MAXUSER to control the max drive and user in ZCPR or a modified ZCPR2 ; or ZCPR3. Even if you don't use ZCPR, you can use the page zero lo- ; cations to control other programs such as SD and XMODEM when you have ; MBBS to set the user's max drive and user. ; ; If USEZCPR is NO, MBYE uses the values you insert for MAXDRV ; and MAXUSR. ; USEZCPR EQU NO ; Yes, if using NZCPR to set max drive and user # MAXDRV EQU 2 ; Highest drive supported (1=A:,2=B:...) MAXUSR EQU 5 ; Highest user area (0-16) ; ; ; Page zero locations used by MBYE: ; KILBEL EQU 003BH ; Console bell disable flag MSPEED EQU 003CH ; Baud rate pointer (if SPDBYTE true) MAXDRIV EQU 003DH ; ZCPR location of MAXDRIV byte (if USEZCPR true) WHEEL EQU 003EH ; Location of wheel flag (if NZCPR/ZCPR2 true) MAXUSER EQU 003FH ; ZCPR location of MAXUSR byte (if USEZCPR true) ; ;----------------------------------------------------------------------- ; BP110 EQU 0 ; 110 baud - baud rate pointers 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 bps BP2400 EQU 6 ; 2400 bps BP4800 EQU 7 ; 4800 bps BP9600 EQU 8 ; 9600 bps BP19200 EQU 9 ; 19200 bps ; BPLOCAL EQU BP9600 ; SET your "local" baud rate value here ; ;----------------------------------------------------------------------- ; ; 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 0DE00H ; Check this in your BIOS ; ; ; The following location is called ; WMSTRT EQU 0EE00H ; Check this in your BIOS ENDIF ; LOSER ; ;*********************************************************************** ; ; END OF OPTION CONFIGURATION SECTION FOR BYE3 ; ;*********************************************************************** ; ; ORG 0100H ; ; ;----------------------- Special Loader Routine ------------------------ ; START: LXI SP,STACK ; Set stack for initialization routine ; IF BYEBDOS MVI C,32 ; See if MBYE is already running MVI E,241 CALL BDOS CPI 77 JNZ MOVBYE ; If not, relocate it ENDIF ; BYEBDOS ; IF BYELOW LHLD BDOS+1 ; If MBYE running, BDOS+1 = BEGOBJ ENDIF ; BYELOW ; IF NOT BYELOW LXI H,RAMTOP-(OBJEND-BEGOBJ)+1 ; = BEGOBJ relocated ENDIF ; NOT BYELOW ; IF NOT BYEBDOS PUSH H ; Save BEGOBJ address (should be) LXI D,YESITS-BEGOBJ ; (should = 'BYE') DAD D MOV A,M ; Check to see if MBYE already relocated CPI 'B' JNZ MOVBYE INX H MOV A,M CPI 'Y' JNZ MOVBYE INX H MOV A,M CPI 'E' JNZ MOVBYE POP H ; If relocated, get start address ENDIF ; NOT BYEBDOS ; PUSH H ; Save it LXI D,OPTION-BEGOBJ DAD D XRA A MOV M,A ; Clear OPTION POP H INX H INX H INX H ; Skip initial JMP (JMP BDOS if BYELOW) PCHL ; Execute already relocated code ; MOVBYE: IF NOT BYEBDOS POP H ; Restore HL (BYELOW BDOS location) ENDIF ; NOT BYEBDOS ; IF BYEBDOS LHLD BDOS+1 ; Get BDOS vector ENDIF ; BYEBDOS ; IF BYELOW ; BDOS-(2k CCP+6 byte S/N+(BYE scratch)) LXI D,-(2048+6+(OBJEND-PEND)) DAD D ; Make room for CCP, serial#, MBYE scratch ENDIF ; BYELOW ; IF NOT BYELOW ; RAMTOP-(BYE scratch) LXI H,RAMTOP-(OBJEND-PEND) ENDIF ; NOT BYELOW ; ; ; HL now contains the destination address of BYE3 (end of BYE) ; LXI D,PEND-1 ; Set up the source pointer LXI B,PEND-BEGOBJ ; Set up byte counter ; ; ; This is the long version for 8080s and 8085s ; IF NOT ZILOG 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 ENDIF ; NOT ZILOG ; ; ; The following is for the Zilog Z-80 or Z-800. ; IF ZILOG XCHG ; Reverse source and destination for lddr DB 0EDH,0B8H ; These are the codes for lddr ENDIF ; ZILOG ; UPDATE: IF NOT ZILOG XCHG ; Move the source addrress into 'HL' ENDIF ; NOT ZILOG ; 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 addr of the 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 sourc pointer for the modi- ; Fication routine entry MODIFY: INX H ; Point to the next (hopefully) instr. DB LXID ; Get the address of the end of BYE3 ; 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 the number of elements in the table LXI D,INST3 ; Set up the 3-byte opcodes table pointer ; 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 elements in the table LXI D,INST2 ; Set up the 2-byte-opcodes-table pointer ; 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, it's a one-byte opcode, keep going ; SKIP: INX H ; Advance object code pointera JMP MODIFY ; Continue search ; CHANGE: LXI D,OBJEND ; Set up end of range pointer LXI B,BEGOBJ ; Set up beginning of range pointer ; ; ; See if the address is above the range ; INX H ; Advance pointer to the LSB of the addr MOV A,E SUB M INX H ; Advance pointer to the MSB of the addr MOV A,D SBB M JC MODIFY ; ; ; See if the address is below the range ; DCX H ; Set back pointer 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 back pointer to the LSB of the addr 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 LSB INX H ; Make 'HL' totally negative RET ; ; ; Prepare to branch to the MBYE program ; ; Initialize internal copy of BIOS jump table. (Previously done ; every time PATCH run, when only needs to be done once.) ; BEGIN: LXI D,VCOLDBT ; BIOS save table LHLD OFFSET ; +OFFSET DAD D XCHG ; Result in DE CALL TBLADDR ; Get BIOS table addr in HL MVI B,24 ; Save all vectors CALL MOVE ; IF COMFILE AND REENTR LXI D,COMFLG ; Clear COMFLG LHLD OFFSET ; To force intial load DAD D XRA A MOV M,A ENDIF ; COMFILE AND REENTR ; LXI D,OPTION LHLD OFFSET DAD D LDA FCB+2 ; GET /A/C/Z MOV M,A ; Save in OPTION LHLD 1 ; JMP WARMBOOT address LXI D,10 ; +10 = CONOUT address DAD D ; Patch TPA copy of jump table MVI A,0C3H STA VCONOUT ; With JMP CONOUT MOV A,M STA VCONOUT+1 ; So that LCLPRT routine will work INX H MOV A,M STA VCONOUT+2 ; IF MBBS AND (TOPDSP OR LINE25) LXI D,DSPUSF ; Point to display user flag LHLD OFFSET DAD D MVI A,USERDSP AND 0FFH ; Get user display flag MOV M,A ; Set USER Display flag either on or off ENDIF ; MBBS ; IF MBBS AND NODSP24 LXI D,DSPUSX LHLD OFFSET DAD D MVI A,ON ; Set DSPUSX also if NODSP24 option MOV M,A ENDIF ; MBBS AND NODSP24 ; CALL CLRSCRN ; Clear screen LXI H,VMSG ; Signon message CALL LCLPRT MVI A,INITBEL AND 0FFH ; Get INITBEL to see if STA KILBEL ; Bell should be initially on or off CALL TOGBEL ; Toggle it and display status LXI H,INITMSG ; Tell user what's up... CALL LCLPRT CALL MDINIT ; Initialize modem ; IF SMODEM OR USR2400 OR SM1200 OR ANCHOR OR USR CALL MDANSW ; Raise DTR/RTS now.. ENDIF ; IF USR2400 CALL SET2400 ; Set 2400 baud if 2400 ENDIF ; IF SM1200 OR ANCHOR OR USR CALL SET1200 ; Set 1200 baud if 1200 ENDIF ; IF SMODEM CALL SET300 ; Set 300 baud if 300 ENDIF ; IF SMODEM OR USR2400 OR SM1200 OR ANCHOR OR USR MVI B,5 CALL SMDLP1 ; Wait a bit for modem to settle LXI H,SM1MSG ; Make sure modem at right baud rate CALL SMDMPRT CALL SMDLAY ; Wait a sec... LXI H,SMIMSG ; Initialize smartmodem CALL SMDMPRT ENDIF ; IF BYELOW 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 INX H POP D MOV M,E INX H MOV M,D INX H ENDIF ; BYELOW ; IF NOT BYELOW LXI D,BEGOBJ2 ; Start of BYE3 code LHLD OFFSET DAD D ; 'HL' >start of relocated code ENDIF ; NOT BYELOW ; PCHL ; Jump to relocated BYE3 program ; ; The following table defines the 3-byte load instructions used in the ; 8080 instruction set. ; INST3: DB 01H DB 11H DB 21H DB 22H DB 2AH DB 31H DB 32H DB 3AH DB 0C2H DB 0C3H DB 0C4H DB 0CAH DB 0CCH DB 0CDH DB 0D2H DB 0D4H DB 0DAH DB 0DCH DB 0E2H DB 0E4H DB 0EAH DB 0ECH DB 0F2H DB 0F4H DB 0FAH DB 0FCH ; INST3E: ; 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 06H DB 0EH DB 16H DB 1EH DB 26H DB 2EH DB 36H DB 3EH DB 0C6H DB 0CEH DB 0D3H DB 0D6H DB 0DBH DB 0DEH DB 0E6H DB 0EEH DB 0F6H DB 0FEH ; INST2E: ; End of 2 byte op codes ; INITMSG:DB CR,LF,'[Initializing modem]',CR,LF,0 ; IF SMODEM OR USR2400 OR SM1200 OR ANCHOR OR USR SM1MSG: DB 'AT',CR,80H ; SMIMSG: DB 'ATE0' ENDIF ; IF SMODEM OR USR2400 OR SM1200 DB 'Q0V0S10=20' ENDIF ; IF ANCHOR OR USR DB 'Q1S0=0' ENDIF ; IF SMODEM OR SM1200 OR USR2400 OR USR DB 'M0' ENDIF ; IF SM1200 OR USR2400 DB 'X1' ENDIF ; IF SMODEM OR SM1200 DB 'S4=255S5=255' ENDIF ; IF SMODEM OR USR2400 OR SM1200 OR ANCHOR OR USR DB 'S2=3' DB CR,80H ENDIF ; ; ;----------------------------------------------------------------------- ; ; THE FOLLOWING CODE GETS MOVED ; TO HIGH RAM BY THE LOADER ; PROGRAM, WHERE IT IS EXECUTED ; ;----------------------------------------------------------------------- ; BEGOBJ: JMP 0 ; Filled by begin if BYELOW BEGOBJ2: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 update it in any future changes. ; ;; MXUSR - 1 byte ;; MXDRV - 1 byte ;; TOVAL - 1 byte ;; NULLS - 1 byte ;; ULCSW - 1 byte ;; LFEEDS - 1 byte ;; WRTLOC - 1 byte ;; HARDON - 1 byte ;; LOSTFLG - 1 byte ;; COVECT - 2 bytes ;; 'BYE' - 3 bytes (check here to confirm MBYE is running) ;; COMFLG - 1 byte ;; JMP - 1 byte (changed to ACFL access flag after log on) ;; CURUSR - 2 bytes ;; JMP - 1 byte (changed to MXML max. minutes after log on) ;; RTCBUF - 2 bytes ;; EFLAG - 1 byte (used for EXTEND option, 0=off, 0ffh=on) ;; EMAP - 1 byte (used for EXTEND option, alternate du: or 0ffh) ; ;*********************************************************************** ; ; The flags below are initialized in the ANSWER routine, they should ; be left as '0' in the source to avoid possible problems with the ; relocation routine. (0FFH is also ok, so some flags can be ON.) ; ; Runtime maximum user area (unused under CP/M 1.4) ; MXUSR: DB 0 ; ; Runtime maximum drive available ; MXDRV: DB 0 ; ; Number of minutes to wait before timeout ; TOVAL: DB 0 ; ; Number of nulls to put after a carriage return ; NULLS: DB 0 ; ; Upper-case only switch, 32 for uppercase, 0 for upper/lowercase ; ULCSW: DB 0 ; ; Line-feed masking bit (non-zero= mask line feeds) ; LFEEDS: DB NO ; ; Location RBBS pokes so modem does not hang-up during disk writes ; WRTLOC: DB NO ; ; Switch to let SYSOP turn on/off the hard log (so his work remotely ; will not show up on the hardlog and waste all that paper) if HARDLOG ; is set 'NO', this is ignored, but takes up space so that smart pro- ; grams will not screw stuff up when they change these locations. ; HARDON: DB ON ; ; LOSTFLAG has been moved up here, so that we can make BYE hang-up the ; the phone without the "goodbye" message (like if we kill a twit). ; LOSTFLG:DB NO ; ; Console output vector which points to the "local console" output rou- ; tine. This address is used by external XMODEM programs to set their ; CONOUT address automatically if their USECON equate is set to YES. ; (Initialized by START0, leave as 0 in source code.) ; COVECT: DW 0 ; Used by XMODEM programs to find CONOUT ; ; Check these three bytes to insure that BYE is running before using ; any functions dependent on BYE. (No problem to relocator, leave as ; upper case only.) ; YESITS: DB 'BYE' ; Tells XMODEM that BYE3 is being used ; ; COMFLG is 0 if .COM file is not loaded in TPA, 0FFH if .COM file is ; loaded. This flag is used to avoid unecessary reloading of the .COM ; file (as, for instance, when a user hangs up during the "HOW MANY ; NULLS?" question). ; COMFLG: DB NO ; 0 = .COM file not loaded ; ; CURUSR is relocated, (hence the reason for the JMP instruction), and ; is used by MBBS to determine where the current user buffer is located. ; ACFL: USRMSL: JMP CURUSR ; (address of data, not code) ; ; RTCBUF is relocated, (hence the need for JMP), and is used by MBBS to ; determine the location in memory of the real-time clock buffer. ; (7 BCD bytes representing HHMMSS (time) and YYYYMMDD (date) and ; followed by a two-byte (binary integer format, LSB first) value ; giving total mins on system.) If you don't have a real-time clock ; available, set time to all nines (999999H). If an RTC is available, ; CLOCK is called during all modem I/O. During this routine, get RTC ; data and format (if necessary) and copy to RTCBUF, increment # of ; mins on system every 60 secs., check # of mins. on vs. max. allowed, ; and if max. reached or exceeded, JMP to DROPCAR (after time up msg). ; if WRTLOC is set, wait till it clears before JMP DROPCAR... (NOTE that ; if MXML is zero, the user is allowed an infinite amount of time on.) ; MXML: RTCBFL: JMP RTCBUF ; (address of 9 byte BCD buffer) ; ; The following two bytes are used to support Lavern Ogden's "XTO" ; program which allows a system to have users restricted to a particular ; disk/user area instead of having access to A0: - MAXDSK/MAXUSR ; EFLAG: DB NO ; When toggled on, maxdisk/user is only ; Allowed area unless EMAP<>0FFH ; EMAP: DB 0FFH ; If 0FFH, only max disk/user allowed if ; EFLAG set, else, is alternate disk/user ; (disk in lower four bits (0-15), user ; In upper four bits) ; ;*********************************************************************** ; ; THIS IS THE OFFICIAL START OF THE BYE PROGRAM ; ;*********************************************************************** ; ; If the carrier is lost - hang up, await ring. Otherwise, say goodbye, ; and hang-up. ; START0: LXI SP,STACK ; Reset stack pointer ; IF BYELOW LHLD BDOS+1 ; Get beginning address of BYE3 program SHLD BDADDR ; Save address of BYE3 start ENDIF ; ; ; Patch in BYE's BDOS interceptor ; IF BYEBDOS LHLD BEGOBJ+1 ; Get real BDOS call 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 SHLD BEGOBJ+1 ; Save it so it goes through our ex- ; tended BDOS NORPTC: ENDIF ; BYEBDOS ; XRA A ; A=0 STA LOSTFLG ; Show no carrier lost LHLD VCONOUT+1 ; Get console output vector SHLD COVECT ; Save it for XMODEM ; ; ; 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 USRLOG LDA USRFLG ; Check to see if USRLOG flags CPI 0AAH ; Have been initialized CNZ RSTULC ; If not, DO it LDA USRFLG+1 CPI 055H CNZ RSTULC ENDIF ; USRLOG ; ; ; If carrier present, assume we have a remote user ; CALL MDCARCK ; Remote user? JNZ GOODBY ; If so, bye bye... JMP HANGUP2 ; Make sure it's hung up and then reset ; BYEBYE: IF PRNTGB ; Say Goodbye (if PRNTGB is YES) LXI H,GBMSG ; Good-bye message CALL CONPRT ; Print this message ENDIF ; RET ; GOODBY: IF MBBS LDA FCB+1 ; Check logoff option CPI 'C' ; 'C'? (for comments) JNZ WEGONE ; Nope, hang it up... MVI A,0CDH ; Else set warm boot jump to call for STA 0000H ; Comments on exit JMP HANGUP0 ; Go run .COM file before exit ENDIF ; MBBS ; WEGONE: CALL MDCARCK ; Check if they're still there JZ HANGUP ; Nope, forget it CALL BYEBYE ; Else, say bye... ; ; ; Nobody there, or we are done, so hang up ; HANGUP: XRA A STA OPTION ; Clear option CALL MDMHANG ; Hang up modem ; IF MBBS AND TOPDSP AND NODSP24 LDA DSPUSX STA DSPUSF ENDIF ; IF MBBS XRA A ; If MBBS, set up for logoff STA 0000H ENDIF ; MBBS ; HANGUP0:LXI SP,STACK ; Set up local stack ; ; ; (In case of disconnect when LUX running) ; CALL PATCH ; Make sure we're patched in ; IF MBBS LDA CURUSR ; Check if user logged in CPI ' ' ; If not, JZ HANGUP1A ; Skip logoff MVI A,ON ; Set STA WRTLOC ; WRTLOC in case carrier loss CALL MDCARCK ; Carrier? JZ LOADIT ; Nope, skip "Please wait..." LXI H,WAITMSG CALL CONPRT ; Else, ask 'em to hang around ENDIF ; MBBS ; LOADIT: IF MBBS AND (MBLOG OR MBFMSG) LDA 0000H ; Was this BYE C or BYE? ENDIF ; IF MBBS AND MBLOG CPI 0CDH JZ ISBYEC ; BYEC CPI 0CAH JZ ISBYEC ; Upload description ENDIF ; MBBS AND MBLOG ; IF MBBS AND MBFMSG CPI 0C2H ; Message upload JNZ LGLOD CALL LODFMS ; Load MFMSG MVI A,0C3H STA 0000H JMP WASBYE ENDIF ; MBBS AND MBFMSG ; LGLOD: IF MBBS AND MBLOG CALL LODLOG ; Else is logoff XRA A STA 0000H JMP WASBYE ENDIF ; IF MBBS ISBYEC: CALL LODCOM ; Load .COM file ; WASBYE: CALL MDCARCK ; Still there?? JNZ COMRUN ; Yep? then run .COM file for exit/msg LXI H,OFFMSG ; Tell sysop what's up CALL LCLPRT MVI A,ON ; Show loss of carrier STA LOSTFLG ENDIF ; IF MBBS AND MBLOG LDA 0000H ORA A CNZ LODLOG ; If we lost 'em, switch files now ENDIF ; IF MBBS XRA A ; Loss of carrier logoff STA 0000H ; COMRUN: CALL 0100H ; Let MBBS.COM do log off ENDIF ; HANGUP1:CALL MDCARCK ; Anybody still there? CNZ BYEBYE ; If so, say goodbye ; HANGUP1A: XRA A ; Clear OPTION STA OPTION ; HANGUP2:LXI SP,STACK ; Set up local stack CALL UNPATCH ; Unpatch BIOS XRA A ; Force next warmboot to user 0 STA 0004H ; And drive a: STA MSGMOD ; Clear MSGMOD flag in case set ; IF MBBS OR RBBSCK STA WRTLOC ; Clear WRTLOC in case set ENDIF ; IF MNULL STA NULTRY ; Clear NULTRY if we count tries.. ENDIF ; IF EXTEND STA EFLAG ; Make sure EFLAG is cleared ENDIF ; CALL MDMHANG ; Hang up the phone MVI A,0C3H ; Clear any traps left from .COM file STA 0 ; IF MBBS MVI A,64 ; If MBBS, clear "current user" buffer ENDIF ; IF MBBS AND MTDISP ADI 3 ; Add 3 for extended buffer length ENDIF ; IF MBBS MOV B,A LXI H,CURUSR CALL BLKBUF ENDIF ; MBBS ; IF MBBS AND LINE25 LXI H,CLR25 ; If we show current user on #25 CALL LCLPRT ; Clear it out now.. ENDIF ; IF ZMCMDB LXI H,MCMDBA+4 ; If ZCPR2 multi-cmd buffer, clear it SHLD MCMDBA XRA A STA MCMDBA+4 ENDIF ; IF ZSHELL LXI H,SHSTK ; If ZCPR3 shell stack, clear it MVI B,SHSTKS*SHSIZE CALL Z3BUFC ENDIF ; IF ZTCP LXI H,Z3ENV+128 ; If ZCPR3 term cap, clear it MVI B,128 CALL Z3BUFC ENDIF ; IF ZMSGB LXI H,Z3MSG+1 ; If ZCPR3 message buffer, clear it.. MVI B,15 CALL Z3BUFC LXI H,Z3MSG+24 ; (but don't remove error handler if there) MVI B,56 CALL Z3BUFC ENDIF ; IF ZPATH CALL UPATH ; Set up path for users ENDIF ; IF TIMEOUT LXI H,0 ; If TIMEOUT, clear it SHLD TOCNT ENDIF ; IF MBYETOS ; If TOS is in low memory LXI H,0 SHLD TOS ENDIF ; IF TIMEOUT AND NOT RTC MVI A,TMINS ; Fake clock counter STA TOVAL ENDIF ; IF RTC LXI H,0 ; If Real-Time Clock, SHLD RTCBUF+7 ; Clear total minutes on system MVI A,MXLT ; Set maximum minutes for logon STA MXML ENDIF ; IF RTC AND NOT TLEFT MVI B,5 LXI H,MINMSM ; Clear minutes on system message CALL BLKBUF ENDIF ; IF RTC AND TLEFT CALL BLK2MG ENDIF ; IF RTC AND TIMEUP XRA A STA RTCFLG ; CLEAR RTCFLG ENDIF ; IF SDMCL MVI A,SDMCI ; If SD with low memory column number STA MCL ; initialize it ENDIF ; IF LKEY LDA LCDFLG ; Does sysop need system after caller? ORA A JNZ BEXCPM ; Yes, exit to CP/M ENDIF ; ; ; Check for /E/A/C/Z option on command line ; LDA OPTION ; Check for /A/C/Z option CPI 'A' ; Answer immediately? JZ ANSW0 ; Skip to answer routine ; IF COMFILE CPI 'C' ; Answer and do comfile? JZ ANSW0 ; Skip to answer routine CPI 'E' ; Execute .COM file locally? JZ EXCPM ; If so, do it now ENDIF ; COMFILE ; IF USRLOG ; Check for reset of counters CPI 'Z' CZ RSTULC ENDIF ; IF COMFILE AND NOT MBLOG CALL LODCOM ; Load the .COM file ENDIF ; IF COMFILE AND MBLOG CALL LODLOG ; Load the LOGIN.COM file ENDIF ; START1: LXI SP,STACK ; IF NORING AND NOT (SMODEM OR SM1200 OR USR2400 OR ANCHOR OR USR) CALL MDANSW ; Raise DTR/RTS for auto answer ENDIF ; IF (ANCHOR OR USR) LXI H,SMAMSA ; Send AT S0=2 command to CALL SMDMPRT ; Set modem in auto-answer mode ENDIF ; IF SMODEM OR SM1200 OR USR2400 CALL MDINP CALL MDINP ; Clear any previous rings... ENDIF ; CALL CLRSCRN ; Clear the local console screen ; START2: XRA A ; Clear OPTION flag STA OPTION ; ; ; Initialize counters for delay loops to be used for 'call waiting' ; displays (flased on crt while waiting for a call) ; IF DISWT CALL CURSW ; Turn off cursor ; LOOP: LXI B,MHZ*200 ; Counter for printing the 'waiting' msg LXI D,(MHZ*400)-1 ; Counter for eraseing the 'waiting' msg LXI H,MSGWT2 ; Print the msg CALL LCLPRT ; Gotta use DE & BC cuz #s big ENDIF ; ; ; Await ringing - check local keyboard for CTL-C exit request, ; CTL-G bell toggle or CTL-Z screen clear. ; ; Actual delay for printing messages occurs here. This does not ; cause more than a few nanoseconds delay in the regular scanning ; of the console (CONSTAT) and the modem (MDINST or MDCARCK) ports. ; RINGWT: IF DISWT DCX B ; Decrement BC MOV A,B ; Put B in A, OR it with C ORA C ; 0 yet? yes=one second has elasped JZ WAITMS ; Erase the message DCX D ; Decrement DE MOV A,D ; Put D in A, OR it with E ORA E ; 0 yet? yes=another second has elasped JZ LOOP ; Re-print the message ; THERE: CALL CONSTAT ; Check if console key ready ENDIF ; IF NOT DISWT CALL VCONSTAT ; Check if console key ready ENDIF ; ORA A JZ RNGWT1 ; Nope, check for ring/carrier ; IF DISWT PUSH B ; Must save registers PUSH D ENDIF ; CALL VCONIN ; Yep, get console key ; IF DISWT POP D ; Now restore'em POP B ENDIF ; CPI BELKEY ; Bell key? CZ TOGBEL ; If so, toggle console bell on/off ; IF MBBS AND (TOPDSP OR LINE25) CPI CALKEY ; Show user key? CZ TOGUSR ; Toggle user display key ENDIF ; CPI CLRKEY ; Clear screen char? CZ CLRSCRN ; If so clear the screen CPI 'C'-40H ; CTL-C? JZ USRCHK ; Check for exit ; RNGWT1: IF NORING AND NOT (SMODEM OR SM1200 OR USR2400) CALL MDCARCK ; Check for carrier JNZ ANSWER ; We have carrier, let's say hello. JMP RINGWT ; Nope, loop ENDIF ; IF SMODEM OR SM1200 OR USR2400 CALL MDINST ; Check for data available JZ RINGWT ; Nope, keep waiting CALL MDINP ; Yep, get data (CR) CPI CR ; If CR, JZ RINGWT ; Ignore it CPI LF ; Ignore LF's too JZ RINGWT CPI '2' ; 'RING?' JZ ANSWSM ; Yes, answer the phone CPI '3' ; 'NO CARRIER?' JZ START2 ; Yes, clear OPTION flag, cont. ENDIF ; IF SM1200 OR USR2400 CPI '5' ; '1200 CONNECT?' JZ SET12 ; if yes, set 1200 bps ENDIF ; IF SMODEM OR SM1200 OR USR2400 CPI '1' ; 300 or 1200? JNZ RINGWT ; If neither, not interested ENDIF ; IF USR2400 CHK24: CALL MDINST ; Check for CR or 0 or 1 after 1 JZ CHK24 ; Wait for character CALL MDINP ; Get it CPI '0' JZ SET24 ; If 10 CPI '1' JZ SET24 ; Or 11, is 2400 CPI CR JNZ RINGWT ; If NOT 10 or 11 or 1 is garbage ENDIF ; SET3: IF SMODEM OR SM1200 OR USR2400 CALL SET300 ; Else is 300 ENDIF ; IF (SMODEM OR SM1200 OR USR2400) AND SPDBYTE MVI A,BP300 STA MSPEED ENDIF ; IF (SM1200 OR USR2400) AND NOT S300 JMP HANGUP1A ; If not allowing 300 baud, hang up ENDIF ; IF SMODEM OR SM1200 OR USR2400 JMP SMCLR ENDIF ; SET24: IF USR2400 CALL SET2400 ENDIF ; IF USR2400 AND SPDBYTE MVI A,BP2400 STA MSPEED ENDIF ; IF MBBS AND TOPDSP AND NODSP24 LDA DSPUSF STA DSPUSX XRA A STA DSPUSF ENDIF ; IF USR2400 JMP SMCLR ENDIF ; SET12: IF SM1200 OR USR2400 CALL SET1200 ENDIF ; IF (SM1200 OR USR2400) AND SPDBYTE MVI A,BP1200 STA MSPEED ENDIF ; IF USR2400 AND NOT S1200 JMP HANGUP1A ; If not allowing 1200 baud, hang up ENDIF ; IF SMODEM OR SM1200 OR USR2400 SMCLR: MVI B,5 CALL SMDLP1 ; Wait 1/2 second for line to settle CALL MDINP ; Clear CR, garbage characters CALL MDINP JMP ANSWER ; Go for it... ENDIF ; ANSWSM: IF (SMODEM OR SM1200 OR USR2400) AND USRLOG LXI H,OLDUSR ; Count this as "attempted log on" CALL BOPLOG ENDIF ; IF SMODEM OR SM1200 OR USR2400 OR ANCHOR OR USR ANSWS2: CALL MDINST ; Check for data available JZ ANSWS2 ; Nope, keep waiting CALL MDINP ; Yep, get data (CR) CALL DELAY ; Wait 1/10 sec to send ATA ; ANSWS3: LXI H,SMAMSG ; Send "ATA", CALL SMDMPRT JMP RINGWT ; Wait for response code ENDIF ;..... ; ; ; This routine is used by the 'waiting for ring' routine to ; clear the displays screen ; IF DISWT WAITMS: CALL CLRSCRN ; Clear local screen LXI B,MHZ*400 ; Delay the print msg JMP THERE ; CURSW: LXI H,CURMSG CALL LCLPRT RET ENDIF ;..... ; ; IF NOT NORING RINGW2: CALL MDRING ; Call ring-check routine JZ RINGWT ; Not ringing... ; ; ; The phone may be ringing. Wait .1 sec and look again to make sure it ; is not just relay bounce ; CALL DELAY ; 1 sec delay for debounce CALL MDRING ; Modem ringing? JZ RINGWT ; No, must have been a relay bounce ; ; ; The phone is definitely ringing, now wait until ring is finished ; ENDRING:CALL DELAY ; 1 sec delay for debounce CALL MDRING JNZ ENDRING ; Wait until ring is finished ENDIF ; IF NOT NORING JMP ANSWER ; If no callback, answer now... ENDIF ; ; ; Modem setup ; ANSW0: IF ANCHOR OR USR OR SMODEM OR SM1200 OR USR2400 CALL SMDLAY ; Wait a sec if arriving after init ENDIF ; ANSWER0: IF DISWT CALL CURSW ; Cursor off ENDIF ; CALL CLRSCRN ; Make sure local console screen is clear ; IF ANCHOR OR USR LXI H,SMAMSA ; Send AT S0=2 command to CALL SMDMPRT ; Set modem in auto-answer mode CALL SMDLAY ENDIF ; (commands may be ignored if line ringing) ; IF SMODEM OR SM1200 OR USR2400 OR USR OR ANCHOR JMP ANSWS3 ; If it's "Smart", tell it to answer.. ENDIF ; (& wait for it to say connect/no connect) ; IF NORING AND NOT (SMODEM OR SM1200 OR USR2400 OR USR OR ANCHOR) CALL MDANSW ; Raise DTR/RTS for auto answer JMP RINGWT ; Wait for carrier ENDIF ; ANSWER: IF DISWT ; Set up the MODEM2 CALL CURSW ; Cursor on when answered ENDIF ; IF BYELOW CALL BDCHEK ENDIF ; XRA A ; Clear STA LOSTFLG ; Carrier lost flag STA SAVFLG ; Clear saved byte flag ; IF NZCPR OR ZCPR2 ; If using NEWZCPR/ZCPR2 w/secure mode STA WHEEL ; Answer the phone in non-wheel mode ENDIF ; IF USRLOG AND NOT (SMODEM OR SM1200 OR USR2400) ; Count attempt LXI H,OLDUSR ; Get # of attempts CALL BOPLOG ; Call routine to add one ENDIF ; CALL PATCH ; Patch BIOS table ; IF CPM2 AND NOT USEZCPR MVI A,MAXUSR ; Reset maximum user area STA MXUSR ENDIF ; IF CPM2 AND USEZCPR MVI A,MAXUSR+1 STA MAXUSER ENDIF ; IF NOT USEZCPR MVI A,MAXDRV ; Reset maximum drive STA MXDRV ENDIF ; IF USEZCPR MVI A,MAXDRV-1 STA MAXDRIV ENDIF ; XRA A ; Make sure line feeds are on again STA LFEEDS MVI A,INULLS ; Assume this many nulls in case of error STA NULLS ; IF TRAPLC MVI A,20H ; Force lower case to upper initially STA ULCSW ENDIF ; MVI A,ON ; Set STA MDMFLG ; MDMFLG XRA A STA SGDFLG ; IF NOT NORING CALL MDANSW ; Set up for answer ENDIF ; IF SMODEM OR SM1200 OR USR2400 CALL FRSTCR ; Check for initial carrier JC HANGUP1A ; No carrier, forget it... JMP WELCOME ; Else, let's say Howdy ENDIF ; IF NOT (SMODEM OR SM1200 OR USR2400) ANSWERA:CALL SET300 ; Set speed initially at 300 CALL MDINP ; Clear garbage characters CALL MDINP CALL FRSTCR ; Check for carrier the first time JC HANGUP1A ; Wasn't a voice call ENDIF ; ; ; Now test input for baud rate - FIRST, check for 300 bps. ; IF (NOT (SMODEM OR SM1200 OR USR2400)) AND S300 CALL SET300 ; Set speed at 300 JNZ ANS1 ENDIF ; IF (NOT (SMODEM OR SM1200 OR USR2400)) AND SPDBYTE AND S300 MVI A,BP300 ; Set MSPEED value STA MSPEED ENDIF ; IF (NOT (SMODEM OR SM1200 OR USR2400)) AND S300 CALL TSTBAUD ; See if bps=300 JZ WELCOME ; Yes, exit ENDIF ; ; ; Check for 2400 bps ; ANS1: IF (NOT USR2400) AND S2400 CALL SET2400 ; Now check 2400 bps JNZ ANS2 ENDIF ; IF (NOT USR2400) AND SPDBYTE AND S2400 MVI A,BP2400 ; Set the MSPEED pointer STA MSPEED ENDIF ; IF (NOT USR2400) AND S2400 CALL TSTBAUD ; Check baud rate JZ WELCOME ENDIF ; ; ; Now check for 1200 bps ; ANS2: IF (NOT (SM1200 OR USR2400)) AND S1200 CALL SET1200 ; Now check 1200 bps JNZ ANS3 ENDIF ; IF (NOT (SM1200 OR USR2400)) AND SPDBYTE AND S1200 MVI A,BP1200 ; Set the MSPEED pointer STA MSPEED ENDIF ; IF (NOT (SM1200 OR USR2400)) AND S1200 CALL TSTBAUD ; Check baud rate JZ WELCOME ENDIF ; ANS3: IF NOT (SMODEM OR SM1200 OR USR2400) JMP ANSWERA ; If not, try again... ENDIF ; IF ZPATH ; UPATH: PUSH H LXI H,DEFPATH ; User path beginning at DEFPATH JMP CPATH ; SPATH: PUSH H LXI H,SYSPATH ; Sysop path beginning at SYSPATH ; CPATH: PUSH D LXI D,PATHADR ; If ZCPR, reset part to default ; ZPCLR: MOV A,M STAX D INX H INX D ORA A JZ ZPCLRX MOV A,M STAX D INX H INX D JMP ZPCLR ; ZPCLRX: POP D POP H RET ENDIF ; CLRSCRN:LXI H,CLRSMSG ; Clear screen CALL LCLPRT RET ;..... ; ; ; Following are the usrlog routines ; IF USRLOG ; Reset all logon counters RSTULC: LXI H,55AAH ; Set USRLOG initialization flags SHLD USRFLG ; To be sure LXI H,0 ; Clear SHLD OLDUSR ; Attempt counter SHLD NEWUSR ; Logon counter RET ENDIF ; ; ; 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 ; Print out program version number CALL LCLPRT ; IF USRLOG ; Print # of logon attempts LXI H,ATMSG CALL LCLPRT LXI H,OLDUSR+1 ; Point to high byte CALL HXOUT LXI H,SUMSG CALL LCLPRT LXI H,NEWUSR+1 ; Print # of callers CALL HXOUT LXI H,LFMSG ; Finish off with CR/LF CALL LCLPRT ENDIF ; RET ; If no log, null PRNLOG routine ; USRCHK: IF SMODEM OR SM1200 OR USR2400 OR ANCHOR OR USR CALL MDOUTST ; Check output status JZ USRCHK ; Not ok to send yet MVI A,20H ; Ok to send CALL MDOUTP ; Send space to make sure hung up CALL DELAY ; Give a chance to send before DTR off ENDIF ; CALL MDMHANG ; Lower DTR, hang up modem ; IF ANCHOR OR USR LXI H,SMZMSG ; Send AT S0=0 to disable CALL SMDMPRT ; Auto-answer mode ENDIF ; IF DISWT CALL CURSW ; Cursor on ENDIF ; PRNIT: CALL CLRSCRN ; Clear screen CALL PRNLOG ; Give info LXI H,RS1MSG CALL LCLPRT ; Prompt to resume waiting for ring ; PRNREL: CALL VCONIN ; Get reply CPI 60H ; Lower case? JC PRNSAV ; Nope, ok.. SBI 20H ; If yes, make upper ; PRNSAV: STA OPTION ; Save reply for later CPI 'A' ; Is answer requested JZ ANSWER0 ; Go to answer routine ; IF COMFILE CPI 'C' ; Answer/run .COM file? JZ ANSWER0 ; Also go answer... CPI 'E' ; Execute .COM file locally? JZ EXCPM ; Set up for local exit ENDIF ; CPI 'R' ; "R" for resume? JZ START1 ; Go do it if so ; IF USRLOG CPI 'Z' ; "Z" for zero counters? JNZ EXCPM ; If not, exit to cpm CALL RSTULC ; Else, reset 'em JMP PRNIT ; And show result.. ENDIF ;..... ; ; ; Here for Ssysop to exit to CP/M ; IF LKEY BEXCPM: LXI H,BELMSG ; Inform Sysop what we're doing CALL LCLPRT JMP EXEX ; Now close up shop ENDIF ;..... ; ; ; Here to exit to CP/M, first reset the modem to default status ; EXCPM: IF COMFILE LDA OPTION CPI 'E' ; If not "E" option JNZ EXEX ; Exit direct to CP/M ENDIF ; IF COMFILE AND NOT MBLOG CALL LODCOM ; Else, make sure .COM file loaded ENDIF ; IF COMFILE AND MBLOG CALL LODLOG ; (Load LOGIN.COM first if MBLOG) ENDIF ; IF MBBS AND RTC CALL PATCH ; If MBBS, run with BYE patched XRA A ; In so RTC will work... STA MDMFLG ; (but with MDMFLG cleared) ENDIF ; IF MBBS AND RTC AND SPDBYTE MVI A,'L'-30H ; This way, speed will be "L" STA MSPEED ; For sysop executing locally.. ENDIF ; IF COMFILE CALL 0100H ; Execute .COM file locally ENDIF ; EXEX: IF SMODEM OR SM1200 OR USR2400 OR ANCHOR OR USR LXI H,SMQMSG ; Send "ATZ" CALL SMDMPRT ENDIF ; IF ANCHOR OR USR CALL SET1200 ; If 1200, ATZ = 1200 baud CALL SMDLAY ; Wait a bit... LXI H,SMZMSG CALL SMDMPRT ; Send "AT S0=0" ENDIF ; IF ZCPR2 OR NZCPR MVI A,ON STA WHEEL ; Restore wheel byte for Sysop ENDIF ; IF ZPATH CALL SPATH ; Set up Sysop path ENDIF ; IF USEZCPR MVI A,SMAXUSR+1 STA MAXUSER ; And MAXUSR MVI A,SMAXDRV-1 STA MAXDRIV ; And MAXDRIV ENDIF ; IF MBBS AND RTC CALL UNPATCH ENDIF ; IF SPDBYTE MVI A,BPLOCAL ; Set "local" baud rate STA MSPEED ; For KMD/XMODEM, etc. if run locally ENDIF ; MVI A,' ' ; Clear STA YESITS ; 'B' in 'BYE' to force reload ; JMP VWARMBT ; Warm boot to unpatched CP/M ; ; ; BOPLOG increments the 16 bit counter pointer at by HL. If the decimal ; option is n use, the number is kept as 4 BCD digits. ; IF USRLOG BOPLOG: MOV A,M ; Get low byte INR A ; Increment ENDIF ; IF USRLOG AND DECIMAL DAA ; Decimal adjust ENDIF ; IF USRLOG MOV M,A ; Replace low order byte RNC ; If no carry, done bopping INX H ; Else carry to high order byte MOV A,M ; Get high order byte INR A ; And bop it ENDIF ; IF USRLOG AND DECIMAL DAA ; Decimal adjust ENDIF ; IF USRLOG MOV M,A ; Replace high order byte RET ENDIF ; IF USRLOG HXOUT: PUSH H ; Save pointer CALL HXHAF ; Do high order half of # POP H ; Restore pointer DCX H ; Point to low, then do low half ; HXHAF: MOV A,M ; Get half # in a MOV B,A ; Save number RAR ; Rotate right 4 bits RAR ; To move MS byte RAR ; To LS byte position RAR CALL ONEOUT ; Output MSB to console MOV A,B ; Get number back ; ONEOUT: ANI 0FH ; Get LS byte for output ADI 30H ; Convert to ASCII MOV C,A ; (if DECIMAL, is BCD already CALL CONOUT ; So no need for adjust on display) RET ENDIF ;..... ; ; ; Welcome to the system ; WELCOME: IF LGONMSG LXI H,LOGMSG ; Msg before "HOW MANY NULLS?" CALL CONPRT ENDIF ; GETNULL: IF MNULL ; Limiting # of times we ask? LDA NULTRY CPI MNULLS ; Up to limit? JZ HANGUP1A ; If so hangup now.. INR A STA NULTRY ; Nope, increment it ENDIF ; LXI H,NULMSG ; Nulls message CALL CONPRT ; Send this message CALL MINPUT ; Get value MVI C,'0' ; Default value is zero CPI CR ; Is response line empty? JZ NUL1 ; Yep use default MOV C,A ; To 'C' for output ; NUL1: CALL MOUTPUT ; Echo character MOV A,C ; Restore value CPI '0' JC GETNULL ; Bad, retry CPI '9'+1 JNC GETNULL ; Bad, retry SUI '0' ; Make binary STA NULLS ; Save count ; IF TRAPLC GETULC: LXI H,LOWMSG ; Lower case? CALL CONPRT CALL MINPUT ; Ask 'em MVI C,'Y' ; Default is yes CPI CR ; Is response empty? JZ GETUL1 ; Yep use default MOV C,A ; GETUL1: CALL MOUTPUT ; Echo answer MOV A,C CPI 60H ; Lower case JC GETUL2 ANI 5FH ; Make upper ; GETUL2: CPI 'N' ; No? JZ PRNWEL ; We're already in UC only mode CPI 'Y' JNZ GETULC ; If not 'Y', ask again... XRA A ; Else, clear STA ULCSW ; Lower to upper case conversion ENDIF ; ; ; Print the welcome file ; PRNWEL: LXI H,LFMSG CALL CONPRT ; CR/LF after NULLS/ULC questions ; 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 E,WELDSK-'A' ; Select WELCOME file disk MVI C,SELDSK CALL BDOS ENDIF ; IF CPM2 AND WELFILE MVI E,WELUSR MVI C,SETUSR ; Set user number for welcome file CALL BDOS ENDIF ; ; ; Open the welcome file ; IF WELFILE LXI D,FCB MVI C,OPEN CALL BDOS ; ; ; Did it exist? ; INR A ; A=> 0 means "no" 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 ; WELTYP: CALL RDBYTE ; Get a byte CPI 1AH ; 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 WELTYP ; No, loop ; WT1: CALL MINPUT ; Yes, get character CPI 60H ; Lower case? JC WT1A ANI 5FH ; If so, make upper ; WT1A: CPI 'C'-40H ; CTL-C to end listing? JZ PASSINT CPI 'C' ; C or c also aborts JZ PASSINT CPI 'K'-40H ; Ctrl-K, K or k also aborts JZ PASSINT CPI 'K' JZ PASSINT CPI 'S'-40H ; CTL-S to delay listing? JZ WT1 ; Yes, wait until another character CPI 'S' JZ WT1 JMP WELTYP ; No, loop until EOF ENDIF ;..... ; ; ; Get the password ; PASSINT: IF PWRQD MVI D,3 ; 3 tries at password ; PASSINP:LXI H,PWMSG ; Password message CALL CONPRT ; 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,'^' ; If control map to up arrow then display 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 CONPRT ; Send this message DCR D ; More tries? JNZ PASSINP ; Yes JMP BADPASS ; 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 ENDIF ; NOPASS: IF USRLOG ; Count number of successful logins LXI H,NEWUSR ; Get last value CALL BOPLOG ; Call routine to add one ENDIF ; IF COMFILE MVI A,20H ; Fool the system so that the .COM file STA FCB+1 ; Will see a space at FCB+1 for default LDA OPTION ; Purposes. CPI 'A' ; SYSOP can bypass .COM file by typing JZ 0000H ; BYE /A ENDIF ; IF COMFILE AND NOT MBLOG CALL LODCOM ENDIF ; IF COMFILE AND MBLOG CALL LODLOG ENDIF ; ; ; Everyone else gets .COM file ; RUNCOM: IF COMFILE CALL 0100H ENDIF ; JMP MBOOT ; Warm boot now for "normal" CP/M use ; IF NOT (SMODEM OR SM1200 OR USR2400) ; ; ; TSTBAUD attempts to read a CR, LF or CTL-C and returns with zero flag ; if the character read is one of these three. ; TSTBAUD:CALL MDINP ; Clear any garbage CALL MDINP ENDIF ; IF (NOT (SMODEM OR SM1200 OR USR2400)) AND SINGLE XRA A ; If only a single baud rate RET ; Skip checking for CR/LF/^C ENDIF ; IF NOT (SMODEM OR SM1200 OR USR2400) CALL MINPUT ; Get character from modem CPI CR ; If a CR RZ CPI LF ; If a LF RZ CPI 'C'-40H ; If a CTL-C RET ; Return with proper flags set ENDIF ; MDMHANG: IF SMODEM OR SM1200 OR USR2400 OR ANCHOR OR USR CALL MDCARCK ; Check carrier first RZ ; If gone, skip the rest ENDIF ; CALL MDINIT ; Lower DTR to hangup MVI B,10 ; Check carrier 10 times ; HNGLP: CALL DELAY ; Every 10th sec CALL MDCARCK ; Check carrier JZ HUNG ; If gone, we're hung up DCR B JNZ HNGLP ; IF NOT (SMODEM OR SM1200 OR USR2400 OR ANCHOR OR USR) JMP MDMHANG ; Still there? try again ENDIF ; IF SMODEM OR SM1200 OR USR2400 OR ANCHOR OR USR CALL MDANSW ; Raise DTR CALL MDCARCK ; Check carrier again RZ ; Hung up now? CALL SMDLAY ; Wait a sec LXI H,SMEMSG ; Send ^C^C^C CALL SMDMPRT CALL SMDLAY ; Wait a sec or so again LXI H,SMHMSG ; Send 'AT H0' message CALL SMDMPRT CALL SMDLAY CALL MDINP CALL MDINP ; Clear out garbage JMP MDMHANG ENDIF ; HUNG: IF SMODEM OR SM1200 OR USR2400 OR ANCHOR OR USR CALL MDANSW ; Make sure DTR/RTS are on... ENDIF ; RET ; All done... ;..... ; ; ; Routine to fill a buffer pointed to by HL with B blanks ; BLKBUF: MVI A,' ' ; BLANKL: MOV M,A INX H DCR B JNZ BLANKL RET ;..... ; ; IF RTC AND TLEFT BLK2MG: MVI B,5 LXI H,MINMSM ; Clear mins on system message CALL BLKBUF ENDIF ; IF RTC AND TIMEUP AND TLEFT MVI B,5 LXI H,MINMSX ; Clear MTOS message CALL BLKBUF ENDIF ; IF RTC AND TLEFT RET ENDIF ;..... ; ; ; Test to see if carrier is there. If after CWAIT seconds, no carrier, ; then return, saying so. This routine is only called just after we as- ; swered the phone. ; FRSTCR: CALL MDCARCK ; Carrier there? JNZ CARCK2 ; Yes, jump to regular routine PUSH B ; Save BC MVI B,CWAIT*10 ; Set for "cwait" seconds JMP CARLP ; From here on, same as other routine ; ; ; Loss of connection test ; CARCK: 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, restore B if all well JNZ CARCK2 ; Got carrier, continue on DCR A ; Count time down STC ; In case this is the end of 'time' RZ ; Return w/ carry set 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 ZCPR2 OR NZCPR ; If ZCPR2 or NZCPR LDA WHEEL ; WHEEL byte set, ORA A ; Clr carry flag RNZ ; And return (allow all disk/user areas) ENDIF ; PUSH H ; Save HL ; IF EXTEND LDA EFLAG ; Get extend flag ORA A ; Set flag reg. JZ EXCON2 ; Do normal D/U tests if not set ENDIF ; IF USEZCPR AND EXTEND MVI A,SMAXUSR+1 STA MAXUSER MVI A,SMAXDRV-1 STA MAXDRIV ENDIF ; IF EXTEND LDA 0004H ; Get current DU CPI (HOMEUSR*16)+(HOMEDSK-'A') JZ EXCON1 ; If A0:, go on our way LDA EMAP ; Get DU map LXI H,0004H ; Active DU CMP M ; Are they the same JZ CARCK4 ; Yes, jump to remaining tests STA 0004H ; Reset active DU to EMAP JMP MBOOT ; Warm boot ; EXCON1: MVI A,0 STA EFLAG ; Re-set EFLAG, we aen't under it any more ; EXCON2: ENDIF ; IF USEZCPR LDA MXDRV ; Get max drive from MBYE DCR A ; Drop it one STA MAXDRIV ; Stuff it in MBYE ENDIF ; IF CPM2 AND USEZCPR LDA MXUSR ; Get max user from MBYE INR A ; Bump it one STA MAXUSER ENDIF ; IF (NOT USEZCPR) AND CHKDSK LDA 0004H ; Check disk/user # ANI 0FH ; Isolate drive 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 # ADI (HOMEDSK-'A') ; Force to home disk STA 0004H ; Update login byte JMP BADDU ; Say bad du and boot ENDIF ; CARCK3: IF CPM2 AND (NOT USEZCPR) AND CHKUSR 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 ADI (HOMEUSR*16) ; Force to home user area STA 0004H ; Update login byte MVI E,HOMEUSR ; And reset user # MVI C,SETUSR ; Via CALL BDOS ; Call to BDOS ENDIF ; IF (NOT USEZCPR) AND (CHKDSK OR CHKUSR) BADDU: LXI H,IDUMSG ; Invalid disk/user message CALL CONPRT ; Tell him what happened JMP MBOOT ; Warm boot ENDIF ; CARCK4: IF RTC AND TIMEUP LDA RTCFLG ; RTCFLG set? ORA A JNZ CARCK5 ; Avoid loop if so ENDIF ; LDA SGDFLG ; Else, check if system going down soon.. ORA A JZ CHKTUP ; If not, check if this is it XRA A STA SGDFLG ; Else, reset flag so we don't loop LXI H,SGDMSG ; Warn 'em.. CALL CONPRT JMP CARCK5 ; And then continue.. ; CHKTUP: IF RTC AND TIMEUP LDA MXML ; Else, check max time allowed on ORA A JZ CARCK5 ; If infinite, skip ot check LXI H,RTCBUF+7 ; Else, SUB M ; Check max-mins JNC CARCK5 ; If max>=mins, times not up.. ; TIMUP: MVI A,ON ; Set STA RTCFLG ; RTCFLG to avoid loop LXI H,TIMUPM ; Tell 'em what happened CALL CONPRT XRA A STA RTCFLG JMP HANGUP ; And hang up... ENDIF ;... ; ; CARCK5: POP H ; Restore 'HL' ORA A ; Clear carry flag if all ok RET ;..... ; ; IF ZSHELL OR ZTCP OR ZMSGB Z3BUFC: MVI M,0 INX H DCR B JNZ Z3BUFC RET ENDIF ;..... ; ; ; .1 sec delay routine ; DELAY: PUSH B LXI B,(4167*(MHZ/10))+(417*(MHZ MOD 10)) ; Constant * MHz10x ; DELAY1: DCX B MOV A,B ORA C JNZ DELAY1 POP B RET ;..... ; ; ; Patch in remote BIOS JMP table ; PATCH: 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 JMP PATEXIT ; ; ; Restore BIOS JMP table to original values ; 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 ; PATEXIT: IF LOSER LXI H,WMSTRT ; Load old call location SHLD WBCALL+1 ; Restore old call ENDIF ; RET ;..... ; ; ; 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 (NOT PRINTER) AND (NOT ALLDEV) AND (NOT NODEV) MVI B,18 ; # of bytes to move ENDIF ; IF PRINTER ; Patch list device? MVI B,15 ; Don't patch RDR: & PUN: ENDIF ; IF ALLDEV OR NODEV ; Patch all devices MVI B,24 ; Move all jumps ENDIF ; RET ;..... ; ; ;------------------------------------------------------------------------ ; IF BYEBDOS ; ; MBYE's BDOS interceptor routine ; REALBD: JMP 0 ; Will be filled in to pnt to REAL BDOS ; BYERSX: 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 ; Yep.. pass it through CPI HICMD+1 ; Is it higher than the highest BYE5 cmd? JNC REALBD ; Yep.. pass it through ; ; ; Ok, it's one of our commands, so 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 adr 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 RET ; Use these three bytes for your own 84 NOP ; user defined subroutine NOP JMP RMXLCP ; Set/get LCPTR. When a user is 85 ; logged in, LCPTR is a bit-mapped ; status register. If no user is ; logged in, LCPTR contains previous ; caller's Timeon ; ; ; 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,LOSTFLG ; Set/get modem-off flag JMP SETGET2 ; RMBELL: LXI H,KILBEL ; Set/get console-bell flag JMP SETGET2 ENDIF ; RMRTC: IF BYEBDOS AND RTC AND TIMEUP CALL TCHECK ; Calculate TOS & set message ENDIF ; IF BYEBDOS AND RTC AND (NOT TIMEUP) CALL CLOCK ; Just calculate time ENDIF ; IF BYEBDOS LDA TOS ; Return time on system and LXI H,RTCBUF ; Return address of RTC buffer RET ; RMXLCP: LXI H,USRMSL ; Address of ACFL and CURUSR data INR A ; If (255), return current user data JZ SGET1 ; So do it MOV M,D ; If (A)<>255, store (D) in ACFL (0-255) RET ; ; RMLCBF: LXI H,CURUSR ; Return address of LastCalr data buffer RET ; ; RMMXT: LXI H,MXML ; Set/get maximum time allowed on system JMP SETGET1 ; RMLTIM: ; Don't use logon time in MBYE ;; STA LMIN ; Set login time here ;; MOV A,D ;; STA LHOUR RET ENDIF ; RMTOS: IF BYEBDOS AND RTC AND TIMEUP ; Only do this if we can.. CALL TCHECK ; Compute time ENDIF ; IF BYEBDOS AND RTC PUSH H ; Save h CALL BLK2MG ; Clear buffer before display ENDIF ; IF BYEBDOS AND RTC LXI H,MINMSM+4 ; Stuff minutes on system here SHLD DPTR LHLD RTCBUF+7 ; Minutes on system binary value CALL DOUT ; Convert to ASCII LXI H,MINMSG ; Tell them how long they've been on CALL CONPRT ENDIF ; IF BYEBDOS AND RTC AND ZCPR2 LXI H,MNMSG2 ; Check if system wheeled LDA WHEEL ORA A JZ FINPRT ; Nope.. skip unlimited msg CALL CONPRT ; Print unlimited time message LXI H,MNMSG3 ; Now print closing bracket CALL CONPRT JMP SKPLBK ; Skip left bracket ENDIF ; IF BYEBDOS AND RTC FINPRT: LXI H,MNMSG3 ; Point to left bracket CALL CONPRT ; Send it ; SKPLBK: POP H ; Restore h ENDIF ; IF BYEBDOS 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 ; ENDIF ; BYEBDOS ;..... ; ; ;----------------------------------------------------------------------- ; ; 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 ; ; IF LOSER NWBCALL:CALL WMSTRT ; Warm boot disk read CALL PATCH ; Fix BIOS again after WMSTRT RET ENDIF ;..... ; ; ; Common routine to check for carrier lost - called from console out ; CHECK: IF MINICK ; Check for carrier lost LDA IOBYTE ; Get IOBYTE ANI 80H ; Test for disk update RNZ ; Busy, wait until done ENDIF ; IF RBBSCK OR MBBS LDA WRTLOC ; Get write in progress flag ORA A RNZ ; Busy, wait until done ENDIF ; LDA MDMFLG ; Modem I/O in progress? ORA A RZ ; Forget it if no.. ; CALL CARCK ; See if carrier/drive/user ok RNC ; All ok ; ; ; Carrier is lost. Type message so local console shows the reason. ; Come come here on bad password. ; BADPASS:LDA LOSTFLG ; Check carrier lost flag ORA A JNZ DROPCAR ; So we don't repeat ourselves MVI A,1 ; Show carrier lost - do not check again STA LOSTFLG LXI SP,STACK ; Ensure valid stack LXI H,CLMSG ; Carrier lost message CALL LCLPRT ; Send this Message ; DROPCAR:LXI SP,STACK ; IF EXFILE AND CPM2 MVI E,EXUSR ; Switch to exit .COM file user area MVI C,SETUSR CALL BDOS ENDIF ; IF EXFILE CALL LODEX CPI '*' ; Test that file was really loaded JNZ 0100H ; EXITFIL was't loaded, so run it ENDIF ; JMP HANGUP ; ; ; Read byte 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 ; ; ; Keyboard/modem status test routine ; MSTAT: IF BYELOW CALL BDCHEK ENDIF ; CALL CHECK ; CHECK FOR CARRIER LOST/ETC ; IF RTC LDA RTCBUF+1 ; Get minutes CALL CLOCK ; Update date/time PUSH H ; Save HL CPI 99H ; Was clock started? JZ MSTATC ; If not, skip increment LXI H,RTCBUF+1 ; Else, check if mins. CMP M ; Has changed JZ MSTATC ; If not, skip incr LHLD RTCBUF+7 ; Else increment mins on system INX H SHLD RTCBUF+7 ENDIF ; IF MBYETOS AND RTC SHLD TOS ; If MBYETOS, stuff in page zero ENDIF ; Also for lazy programs to read.. ; IF (MBBS OR RBBSCK) AND (TIMEOUT AND RTC) LDA WRTLOC ; If WRTLOC set, don't ORA A ; Increment TOCNT JNZ MSTATC1 ENDIF ; IF TIMEOUT AND RTC LHLD TOCNT INX H SHLD TOCNT ; MSTATC1: ENDIF ; IF (RTC AND TIMEUP) LDA MXML ; Get max time allowed LXI H,RTCBUF+7 SUB M ; Minus mins on = remaining time CPI DOWNMIN ; DOWNMIN minutes remaining? JNZ MSTATC ; Nope, cont. MVI A,ON STA SGDFLG ; Else, set flag for Sys Going Down msg ENDIF ; IF RTC MSTATC: POP H ENDIF ; LDA SAVFLG ORA A JZ CHKNOW ; If no data, see if now there is data, LDA MSTATF ; but who is it from? ORA A JZ NOCTRLT ; If MSTATF = 0, it's from the Sysop ; CHKNOW: CALL CONSTAT ; Get local status ORA A JZ MSTAT0 ; No character contained CALL CONIN ; If a function key, get character ORA A ; Check it out JZ MSTAT0 ; Ignore if if fucntion key STA SAVBYT ; Else save itT MVI A,ON ; Set SAVFLG STA SAVFLG ; Say we got one... ; MST1: MVI A,0 ; MSTATF = 0 from keyboard STA MSTATF JMP MSTAT1 ; MSTAT0: LDA MDMFLG ; Check for modem I/O flag ORA A ; If not set, ignore modem dataq RZ ; CALL CHECK ; Check for carrier loss ; IF RBBSCK OR MBBS LDA WRTLOC ORA A ; Ignore modem data if WRTLOC set JNZ NDATA2 ENDIF ; LDA MSGMOD ; Are we in MSG FROM SYSOP mode? ORA A JNZ NDATA2 ; If so, we ignore modem data ; LDA SAVFLG ORA A JNZ NOCTRLT ; CALL MDINST ; If carrier, check modem input status JNZ MSTAT1A ; We got a character? ; IF TIMEOUT AND NOT RTC PUSH H ; Save HL LXI H,TOCNT ; No data, increment the timeout counter INR M JNZ NDATA ; Don't timeout, yet INX H INR M ; Next byte of counter JNZ NDATA LXI H,TOVAL ; 1 "minute" and no data DCR M JNZ NDATA ; Still not timed out ENDIF ; IF TIMEOUT AND RTC PUSH H LXI H,TOCNT+1 MOV A,M ORA A JNZ TURKEY DCX H MVI A,TOMINS CMP M JNC NDATA ; TURKEY: LXI H,0 ; Clear TOCNT so we don't loop SHLD TOCNT ENDIF ; IF TIMEOUT AND RTC AND (MBBS OR RBBSCK) LDA WRTLOC ORA A JNZ NDATA ; If WRTLOC set, don't timeout ENDIF ; IF TIMEOUT LXI H,ITOMSG CALL CONPRT JMP HANGUP ; Finally timed out ; NDATA: POP H ; Restore HL ENDIF ; NDATA2: XRA A ; Say no data and return RET ; MSTAT1A: IF RTC CALL MDINP ; We must check characters if RTC STA SAVBYT MVI A,ON STA SAVFLG ENDIF ; MVI A,1 STA MSTATF ; MSTAT1: IF TIMEOUT XRA A ; Data available? Clear timeout STA TOCNT STA TOCNT+1 ENDIF ; IF TIMEOUT AND NOT RTC MVI A,TMINS STA TOVAL ENDIF ; IF RTC LDA SAVBYT CPI 'T'-40H JNZ NOCTRLT PUSH H ; Else, save HL ENDIF ; IF RTC AND TLEFT CALL BLK2MG ; Clear buffer before display ENDIF ; IF RTC LXI H,MINMSM+4 ; Stuff minutes on system here SHLD DPTR LHLD RTCBUF+7 ; Minutes on system binary value CALL DOUT ; Convert to ASCII LXI H,MINMSG ; Tell them how long they've been on CALL CONPRT ENDIF ; IF RTC AND TIMEUP AND TLEFT LDA MXML ; Maximum minutes allowed here ORA A ; Mtos=0? LXI H,MNMSG2 ; If so, unlimited time JZ T00B ; Print it LXI H,MINMSX+4 ; Stuff minutes left here SHLD DPTR LXI H,RTCBUF+7 SUB M MOV L,A MVI H,0 CALL DOUT ; Convert to ASCII LXI H,MNMSG1 ; Tell them how long they have left ; T00B: CALL CONPRT ENDIF ; IF RTC POP H ; Restore HL MVI A,0 ; CLEAR SAVFLG STA SAVFLG JMP NDATA2 ; And say no data ENDIF ; NOCTRLT:ORI ON ; Show ready now RET ;..... ; ; ;Modem input function, checks local console first ; MINPUT: CALL MSTAT ; Chek local and/or remote input status JZ MINPUT ; Keep doing it until they type something ; IF RTC MVI A,0 STA SAVFLG LDA MSTATF ORA A LDA SAVBYT RZ ENDIF ; IF NOT RTC LDA MSTATF ; See where it's at ORA A JZ MINP2B CALL MDINP ENDIF ; MINP2A: CPI 0 JZ MINPUT ; Ignore nulls ; 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 MINPUT3 CPI CR JNZ NOLOG ; MINPUT3: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 ; NOLOG: IF TRAPCP ; CTRL-P TRAPPING? CPI 'P'-40H ; IS IT CTRL-P? JNZ CKCC ; NOPE, CHK ^C'S XRA A ; YES, CONVERT TO NULL RET ; ; CKCC: ENDIF ; IF TRAPCC ; CTRL-C TRAPPING? CPI 'C'-40H ; IS IT CONTROL-C? RNZ ; NO, PASS IT THRU LDA 0 ; SEE IF WARM BOOT DISABLED CPI 0C3H ; JMP MEANS WARM BOOT OK MVI A,3 ; SO RETURN CONTROL-C RZ MVI A,CTRLC ; ELSE CONVERT TO CTRLC VALUE ENDIF ; RET ; ; MINP2B: IF NOT RTC MVI A,OFF ; Clear savflg STA SAVFLG LDA SAVBYT ; Get saved data RET ENDIF ;..... ; ; ; Modem output function ; ; If we already know carrier is lost, don't check ; for it again or loop trying to output. ; MOUTPUT:LDA LOSTFLG ; Known loss of carrier? ORA A JNZ SILENT ; Avoid loop in case carrier lost LDA MDMFLG ; OK to output to modem? ORA A JZ SILENT ; Nope ; IF TIMEOUT AND RTC XRA A STA TOCNT STA TOCNT+1 ENDIF ; CALL MSTAT ; Carrier still on? or function key? CALL MDOUTST JZ MOUTPUT ; Loop if not ready ; IF TIMEOUT XRA A ; Ready? clear timeout STA TOCNT STA TOCNT+1 ENDIF ; IF TIMEOUT AND NOT RTC MVI A,TMINS STA TOVAL ENDIF ; MOV A,C ; Get character ANI 7FH ; Strip parity bit ; IF TRAPLC 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 0 SUB M POP H MOV C,A ; Force on local as well as remote ENDIF ; MOUTP2: IF OXGATE CPI LF ; We have a toggle for line feeds JNZ MOUTP3 ; Nope, not a LF 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: ENDIF ; CALL MDOUTP ; Output to modem ; SILENT: MOV A,C CPI 7 JNZ SILEN2 PUSH PSW LDA KILBEL ORA A JZ SENBEL POP PSW RET ; ; SENBEL: POP PSW ; SILEN2: IF NULSPRT CPI 0 ; Check if null RZ ; If so, skip display on Kaypro screen ENDIF ; PUSH PSW ; IF MBBS AND (TOPDSP OR LINE25) CPI LF JNZ OKCONO LDA DSPUSF ORA A JZ OKCONO LDA CURUSR CPI ' ' JZ OKCONO PUSH H CALL USRDSP POP H ENDIF ; IF MBBS AND TOPDSP JMP NOKCON ENDIF ; OKCONO: CALL CONOUT ; Send to regular BIOS ; NOKCON: POP PSW ; Get character again ; ; ;Check for nulls ; CPI LF ; Time for nulls? RNZ ; No, return ; ; ;Send nulls if required ; LDA NULLS ; Get count ORA A ; Any? RZ ; No PUSH B MOV B,A ; Save count MVI C,0 ; 0 is a null ; NULLP: CALL MOUTPUT ; Type a null DCR B ; More? JNZ NULLP ; Yes, loop POP B MVI C,LF ; Restore LF RET ;..... ; ; ; Warm Boot, checks location 0 to determine if ok to warm boot or not. ; If location is a C3H (JMP), warm boot permitted, else, there is an ; immediate disconnect. ; MBOOT: LXI SP,STACK ; Reset stack to be sure... ; IF BYELOW CALL BDCHEK ; Check JMP BDOS... ENDIF ; LDA 0000H ; Look at JMP from JMP WARMBOOT in page zero ; IF MBBS AND MBLOG CPI 0CAH ; If a JZ, this is upload descript JZ LOADIT ; Load MBBS and run it.. ENDIF ; IF MBBS AND MBFMSG CPI 0C2H ; If a JNZ, this is a message upload JZ LOADIT ; Load MFMSG and run it... ENDIF ; CPI 0C3H ; Still a JMP instruction? JNZ WEGONE ; If not, say goodbye immediately ; IF REENTR XRA A ; Else, STA COMFLG ; Clear .COM file loaded flag... ENDIF ; ; ; Special warm-boot routine - print a message or something ; WMBMSGPRT:IF WBRTN PUSH PSW PUSH B PUSH D PUSH H ENDIF ; IF RTC AND MBBS LDA OPTION ; If patched locally, CPI 'E' ; Time to unpatch JZ EXEX ; And exit to CP/M ENDIF ; IF PRNTWB LDA MDMFLG ; If modem I/O enabled, ORA A JZ WBFIN ENDIF ; IF PRNTWB LXI H,WBMSG CALL MDMPRT ; Print "Warm Boot" massage ENDIF ; WBFIN: IF WBRTN POP H POP D POP B POP PSW ENDIF ; JMP VWARMBT ; Go do a warm boot ;..... ; ; ; Console print routine ; ; 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.) ; CONPRT: PUSH B ; Save BC ; CONPLP: 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 CONPLP POP B ; Restore BC RET ; Return ;..... ; ; LODLOG: IF COMFILE AND MBLOG AND REENTR LDA COMFLG ; Check COMFLG ORA A RNZ ; Skip load if already loaded MVI A,ON STA COMFLG ; Else set it ENDIF ; IF COMFILE AND MBLOG LXI H,MLGFCB JMP LDCM2 ENDIF ;..... ; ; ; Routine to load the MFMSG.COM file ; LODFMS: IF MBBS AND MBFMSG LXI H,MFMFCB JMP LDCM2 ENDIF ;..... ; ; ; Load a special EXIT program ; LODEX: IF EXFILE LXI H,EXFCB ENDIF ; IF EXFILE AND REENTR XRA A ; Clear STA COMFLG ; COMFLG to indicate .COM file not loaded ENDIF ; IF EXFILE JMP LDCM2 ENDIF ;..... ; ; ; Routine to load the .COM file ; LODCOM: IF COMFILE AND REENTR AND NOT MBLOG LDA COMFLG ; Check COMFLG ORA A RNZ ; Skip load if already loaded MVI A,ON ; Else STA COMFLG ; Turn it on ENDIF ; IF COMFILE LXI H,COMFCB ; Set .COM as current FCB ENDIF ; IF MBLOG AND REENTR XRA A ; Clear .COM file loaded STA COMFLG ; If need LOGIN.COM ENDIF ; IF COMFILE OR EXFILE OR MBLOG OR MBFMSG LDCM2: LXI D,CURRFCB-1 ; Copy user/disk/filename to FCB MVI B,13 ; (13 chars) CALL MOVE LXI H,LSMSG CALL LCLPRT ; Tell sysop what's up LDA CURRFCB MOV E,A ; Get disk DCR E MVI C,SELDSK CALL BDOS ; Select .COM file drive ENDIF ; IF (COMFILE OR EXFILE OR MBLOG OR MBFMSG) AND CPM2 LDA CURRFCB-1 MOV E,A MVI C,SETUSR CALL BDOS ENDIF ; IF COMFILE OR EXFILE OR MBLOG OR MBFMSG LXI H,CURRFCB+12 MVI B,21 CALL ZLOOP LXI D,CURRFCB CALL OPENFIL JZ ABORT ; If can't load file.. ; 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 LXI D,CURRFCB ; Point to FCB 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 RET ; All done... ;.... ; ; ZLOOP: MVI M,0 INX H DCR B JNZ ZLOOP RET ;..... ; ; OPENFIL:MVI C,OPEN ; Open file pointed to by 'DE' CALL BDOS INR A RET ;..... ; ; ABORT: LXI H,CNFMSG ; ERRXIT: CALL LCLPRT ; Print the abort message JMP EXCPM ; Warm boot ENDIF ;..... ; ; ; This area is used for vectoring calls to the user's CBIOS, but saving ; the registers first in case they are destroyed. ; CONSTAT:PUSH B PUSH D PUSH H CALL VCONSTAT POP H POP D POP B RET ;..... ; ; CONIN: PUSH B PUSH D PUSH H CALL VCONIN CALL CKFUNC POP H POP D POP B RET ;... ; ; CKFUNC: IF ZCPR2 AND AWHL CPI AWHLKEY ; Wheel re/set JZ AWHLTOG ; Toggle? ENDIF ; IF LKEY CPI LCKEY ; Sysop need system after caller? JZ LCDOIT ; Yes, set flag ENDIF ; IF UTKEY CPI ULTKEY ; Give caller unlimited time? JZ ULTIME ; Yes, set acfl and mxml ENDIF ; CPI BLNKKEY ; Blank out remote caller JZ BLNKTOG ; Toggle? CPI SYSDKEY ; System going down? JZ SYSDOWN ; Tell caller to leave CPI TWITKEY ; Caller a twit JZ HANGUP ; Make caller leave CPI BELKEY ; CTL-G for bell? JZ TOGBEL ; Then toggle bell flag ; IF MBBS CPI CALKEY ; CTL-W ? JZ TOGUSR ; Then toggle dspusf ENDIF ; CPI MSGKEY RNZ ; If not msgkey, ret MVI A,ON ; Else, set msgmod flag STA MSGMOD LXI H,MFSMSG CALL CONPRT ; Send caller a message ; SYSMSGL:CALL VCONIN ; Input message (while paused) CPI 3 ; If ctrl-c JZ SYSMSGX ; Exit msg from sysop mode... MOV C,A ; Else PUSH PSW CALL MOUTPUT ; Send to sysop/user POP PSW CPI BS ; If backspace JZ SYSMBS ; Echo sp/bs after bs CPI CR ; If cr JZ SYSMCR ; Echo lf after cr JMP SYSMSGL ; If none of above, cont. ; SYSMSGX:MVI C,CR ; Ctrl-c exit, send cr CALL MOUTPUT MVI C,LF ; Lf CALL MOUTPUT XRA A ; Flag to ignore this key STA MSGMOD ; Clear msgmod STA SAVFLG ; And savflg RET ; And return ; SYSMCR: MVI C,LF ; After cr, echo lf JMP SYSECH ; SYSMBS: MVI C,' ' ; If backspace, echo bs/sp/bs CALL MOUTPUT MVI C,BS ; SYSECH: CALL MOUTPUT JMP SYSMSGL ; SYSDOWN: IF AULOGOFF LDA RTCBUF+7 ADI DOWNMIN STA MXML ENDIF ; MVI A,ON STA SGDFLG ; Set flag for sys going down msg MVI A,0 RET ;..... ; ; TOGUSR: IF MBBS AND (TOPDSP OR LINE25) LDA DSPUSF ORA A JZ SETUDO ; XRA A ; Turn off user display STA DSPUSF ENDIF ; IF MBBS AND NODSP24 STA DSPUSX ENDIF ; IF MBBS AND LINE25 LDA CURUSR CPI ' ' JZ UDOFF LXI H,CLR25 JMP FKEX ENDIF ; IF MBBS AND (TOPDSP OR LINE25) UDOFF: LXI H,USROFF JMP FKEX ; SETUDO: MVI A,ON STA DSPUSF ENDIF ; IF MBBS AND NODSP24 STA DSPUSX ENDIF ; IF MBBS AND (TOPDSP OR LINE25) LDA CURUSR CPI ' ' JNZ USRDSP LXI H,USRON JMP FKEX ENDIF ; IF MBBS USRDSP: LXI H,CURUSR+35 SHLD DPTR LHLD RTCBUF+7 CALL DOUT ENDIF ; IF MBBS AND MTDISP MVI B,3 LXI H,MTOS-2 CALL BLKBUF LXI H,MTOS SHLD DPTR LDA MXML ; Get max tos MOV L,A MVI H,0 CALL DOUT ENDIF ; IF MBBS LXI H,USRMSG JMP FKEX ENDIF ; BLNKTOG:LDA MDMFLG ORA A ; If zero, make 0ffh ; IF (ZCPR2 OR NZCPR) STA WHEEL ; Set/reset wheel appropriate ENDIF ; JZ BLNKT1 XRA A ; If not zero, make it zero STA MDMFLG ; IF CPM2 AND USEZCPR MVI A,SMAXUSR+1 STA MAXUSER ENDIF ; IF USEZCPR MVI A,SMAXDRV-1 STA MAXDRIV ENDIF ; IF ZPATH CALL SPATH ; Set up Sysop path ENDIF ; LDA ACFL ; Save current access flags STA ACFSAV MVI A,ON STA ACFL ; And set all flags on... ; LXI H,UOFMSG JMP FKEX ; BLNKT1: MVI A,ON STA MDMFLG ; IF ZPATH CALL UPATH ; Set up user path ENDIF ; LDA ACFSAV STA ACFL ; Restore access flags ; LXI H,UONMSG JMP FKEX ; IF ZCPR2 AND AWHL AWHLTOG:LDA WHEEL CMA ; Ones complement STA WHEEL ; Re/set wheel appropiately ORA A ; Set flags JZ AWHL1 ENDIF ; IF AWHL AND ZPATH CALL SPATH ; Set up sysop path ENDIF ; IF ZCPR2 AND AWHL LDA ACFL ; Save current access flags STA ACFSAV MVI A,ON STA ACFL ; And set all flags on... LXI H,WONMSG JMP FKEX ; AWHL1: ENDIF ; IF AWHL AND ZPATH CALL UPATH ; Set up user path ENDIF ; IF ZCPR2 AND AWHL LDA ACFSAV STA ACFL ; Restore access flags LXI H,WOFMSG JMP FKEX ENDIF ; TOGBEL: LDA KILBEL ; Check kilbel flag ORA A JZ BELOFF ; If off, turn on (bell off) XRA A STA KILBEL LXI H,BONMSG ; If on, turn off (bell on) JMP FKEX ; BELOFF: MVI A,ON ; If off, turn on STA KILBEL LXI H,BOFMSG IF LKEY OR UTKEY JMP FKEX ENDIF ; IF LKEY LCDOIT: MVI A,0FFH ; Set local access flag STA LCDFLG LXI H,LCDMSG ; Tell sysop ENDIF ; IF UTKEY JMP FKEX ; ULTIME: XRA A ; Give caller unlimited time STA MXML CMA ; Also enable all flag bits STA ACFL LXI H,ULTMSG ; Now tell sysop ENDIF ; FKEX: CALL LCLPRT MVI A,0 RET ;..... ; ; ; Decimal output (conversion) routine: ; ; HL should hold binary integer to be converted to ASCII ; DPTR should point to where ones digit will go (last byte) ; IF MBBS OR RTC DOUT: SHLD DSTK-2 ; Save HL in DSTK (temporarily) LXI H,0 ; since 8080's can't LD (nn),sp DAD SP SHLD DSTK ; We have to do this marlarky LXI SP,DSTK ; So we can use our own stack LHLD DSTK-2 ; Get hl back CALL DOUTL ; Now we can call doutl LHLD DSTK ; When done, we have to SPHL ; Restore saved sp RET ; And then return to caller... ; DOUTL: PUSH B ; Decimal output routine, PUSH D ; Converts binary integer (2 bytes) PUSH H ; Pointed to by hl to ascii decimal LXI B,-10 ; Value stored right justified in LXI D,-1 ; Buffer pointed to by dptr. ; DOUT2: DAD B INX D JC DOUT2 LXI B,10 DAD B XCHG MOV A,H ORA L JZ DOUT3 PUSH H LHLD DPTR DCX H SHLD DPTR POP H CALL DOUTL ; DOUT3: MOV A,E ADI '0' LHLD DPTR MOV M,A INX H SHLD DPTR POP H POP D POP B RET ENDIF ;..... ; ; CONOUT: PUSH B PUSH D PUSH H CALL VCONOUT POP H POP D POP B RET ; IF HARDLOG LISTOUT: PUSH B PUSH D PUSH H PUSH PSW ENDIF ; IF HARDLOG AND BYELOW CALL BDCHEK ENDIF ; IF HARDLOG MOV C,A CALL VLISTOUT POP PSW POP H POP D POP B RET ENDIF ; IF BYELOW BDCHEK: PUSH H ; To make truly universal, (???) this DB LXIH ; Program always re-stores the bdos ; BDADDR: DW 0000H ; Pointer at 6&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 ;..... ; ; ; 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 PRINTER RET ; Dummy list device (retain RDR:,PUN:) NOP NOP ENDIF ; IF ALLDEV ; Lst:, rdr: & pun: to modem JMP MOUTPUT ; Modem list device JMP MOUTPUT ; Modem punch device JMP MINPUT ; Modem reader device ENDIF ; IF NODEV ; No LST:, RDR: or PUN: RET ; Dummy LST NOP NOP ; RET ; Dummy RDR: NOP NOP ; RET ; Dummy PUN: NOP NOP ENDIF ; NODEV ;..... ; ; ;*********************************************************************** ; ; ; SWITCH SETTINGS: ; 1 2 3 4 5 6 7 8 9 ; USR Courier 2400 -- UP UP DN UP DN UP UP DN DN ; ; HAYES Smartmodem 300/1200 -- UP UP DN UP DN UP UP DN ; ; RNG 8HI BAL DTR ; USR Password -- OFF OFF OFF OFF ; ; ; Delay about 2 seconds to let modem get stabilized before or after a ; command string. ; IF SMODEM OR SM1200 OR USR2400 OR ANCHOR OR USR SMDLAY: MVI B,20 ; Wait about 2.0 seconds to "be sure" ; SMDLP1: CALL DELAY DCR B JNZ SMDLP1 RET ;..... ; ; ; Send a string to the Smartmodem (at 10 chars/sec) ; SMDMPRT: CALL MDOUTST ; Modem ready for character? JZ SMDMPRT ; No, go check again CALL DELAY ; Wait 1/10 sec MOV A,M ; Get the character CALL MDOUTP ; Send it INX H ; Point to next MOV A,M ; Get next character CPI 80H ; Has all been sent JNZ SMDMPRT ; No, go send another character CALL DELAY ; Wait 1/10 sec after done RET ; Return ENDIF ;..... ; ; ; Send a string to the modem (similar to CONPRT) ; IF PRNTWB MDMPRT: CALL MDOUTST ; Modem ready for character? JZ MDMPRT ; No, go check again MOV A,M ; Get the character CALL MDOUTP ; Send it INX H ; Point to next MOV A,M ; Get next character CPI 80H ; Has all been sent JNZ MDMPRT ; No, go send another character RET ; Return ENDIF ; PRNTWB ; LCLPRT: PUSH B ; Save 'bc' registers ; LCPLP: MOV C,M ; Get the character CALL CONOUT ; Send it INX H ; Point to next MOV A,M ; Get next character ORA A ; Has all been sent JNZ LCPLP ; No, go send another character POP B ; Restore the bc registers RET ; Return ;..... ; ; ;----------------------------------------------------------------------- ; ; This area contains the time check routine for KMD and other programs ; which use the extend BYE5 type BDOS calls. ; IF BYEBDOS AND RTC TCHECK: PUSH B ; Save registers PUSH D PUSH H ENDIF ; IF BYEBDOS AND RTC LDA RTCBUF+1 ; Get mins CALL CLOCK ; Update date/time CPI 99H ; Was clock started? JZ NOINC ; If not, skip increment LXI H,RTCBUF+1 ; Else, check if mins. CMP M ; Has changed JZ NOINC ; If not, skip incr LHLD RTCBUF+7 ; Else increment mins on system INX H SHLD RTCBUF+7 ENDIF ; IF BYEBDOS AND MBYETOS AND RTC SHLD TOS ; If mbyetos, stuff in page zero ENDIF ; Also for lazy programs to read.. ; ; IF BYEBDOS AND RTC NOINC: POP H ; Restore registers POP D POP B RET ENDIF ; BYEBDOS ;..... ; ; ;*********************************************************************** ; ; ++++ INSTALL YOUR PORT DEPENDENT ROUTINES HERE ++++ ; ;*********************************************************************** ; ; ++++ INSTALL YOUR REAL TIME CLOCK ROUTINE HERE ++++ ; ;*********************************************************************** ; ENDOBJ: ; End of object code for relocation ; ;----------------------------------------------------------------------- ; ; Program version number message. ; VMSG: DB CR,LF,'MBYE v' DB MBVERS+'0','.',MBINT+'0' DB ' ',VMONTH/10+'0',VMONTH MOD 10+'0','/' DB VDAY/10+'0',VDAY MOD 10+'0','/' DB VYEAR/10+'0',VYEAR MOD 10+'0',CR,LF DB CR,LF,0 ; ; ; 'Waiting for ring' message display strings ; IF DISWT MSGWT2: DB CR,'[Awaiting call]',CR,0 ; CURMSG: DB ESC,'.',0 ENDIF ; ; ; Clear screen string ; CLRSMSG:DB 'Z'-40H ; Escape sequence here, end with 0 DB 0 ; IF LGONMSG LOGMSG: DB CR,LF,'YOUR SYSTEM NAME GOES HERE' DB CR,LF,0 ENDIF ; IF ZPATH ; ZCPR2/ZPCR3/ZCMD search path DEFPATH:DB 1,0 ; Set up default path to a0 DB 0 ; SYSPATH:DB 1,15 ; Sysop path (set on exit from bye) DB 1,0 DB 0 ENDIF ; IF MBBS WAITMSG:DB CR,LF,'Loading MBBS, please wait...',CR,LF,LF,0 OFFMSG: DB CR,LF,'[Logoff]',CR,LF,0 ENDIF ; NULMSG: DB CR,LF,'How many nulls? (0-9)? ',0 ; IF TRAPLC LOWMSG: DB CR,LF,'Lower case OK? (Y/N) ',0 ENDIF ; IF PRNTGB GBMSG: DB CR,LF,'Good-bye, call again...' DB CR,LF,LF,0 ENDIF ; RS1MSG: DB CR,LF,'Ans, ' ; IF COMFILE DB 'Com, Exec, ' ENDIF ; DB 'Resume, ' ; IF USRLOG DB 'Zero, ' ENDIF ; DB '(ret=exit)? ',0 ; IF USRLOG ATMSG: DB CR,LF,'Logon attempts: ',0 SUMSG: DB CR,LF,' Total logons: ',0 ENDIF ; ; ; 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 patched in) ; DB 0,0,0,0,0,0,0,0,0,0,0,0,0 ; PWMSG: DB CR,LF,'Enter password: ',0 WRGMSG: DB CR,LF,'Incorrect password',CR,LF,0 ENDIF ; PWRQD ; IF COMFILE LSMSG: DB CR,LF,'[Loading]',CR,LF,0 ENDIF ; IF (NOT USEZCPR) AND (CHKDSK OR CHKUSR) IDUMSG: DB CR,LF,'[Drive/user error]',0 ENDIF ; CLMSG: DB CR,LF,'[No carrier]',CR,LF,0 ; IF TIMEOUT ITOMSG: DB CR,LF,'[Timeout]',CR,LF,7,0 ENDIF ; IF RTC AND TIMEUP TIMUPM: DB CR,LF,'[Time exceeded, call back tomorrow]',CR,LF,7,0 ENDIF ; IF RTC MINMSG: DB CR,LF,'[mins on: ' MINMSM: DB 'NNNNN' ENDIF ; IF RTC AND TIMEUP AND TLEFT DB 0 MNMSG1: DB ', ','mins left: ' MINMSX: DB 'NNNNN]',CR,LF,0 MNMSG2: DB ', ','no time limit' ENDIF ; IF RTC MNMSG3: DB ']',CR,LF,0 RTCFLG: DB 0 ENDIF ; SGDFLG: DB 0 SGDMSG: DB CR,LF,7,'System going down, please finish up.',CR,LF,7,0 MFSMSG: DB CR,LF,'Msg from Sysop: ',0 MSGMOD: DB 0 ; When non-zero, users can't talk back (msg from sysop) BONMSG: DB CR,LF,'[Bell]',CR,LF,0 BOFMSG: DB CR,LF,'[Quiet]',CR,LF,0 UONMSG: DB CR,LF,'[Remote]',CR,LF,0 UOFMSG: DB CR,LF,'[Local]',CR,LF,0 ; IF LKEY LCDFLG: DB 0 LCDMSG: DB CR,LF,'[Last Call]',CR,LF,0 BELMSG: DB CR,LF,7,7,'[MBYE Terminated]',CR,LF,0 ENDIF ; IF UTKEY ULTMSG: DB CR,LF,'[Unlimited Time]',CR,LF,0 ENDIF ; IF AWHL WONMSG: DB CR,LF,'[Wheel is on]',CR,LF,0 WOFMSG: DB CR,LF,'[Wheel is off]',CR,LF,0 ENDIF ; IF MBBS AND (LINE25 OR TOPDSP) USRON: DB CR,LF,'[User on]',CR,LF,0 USROFF: DB CR,LF,'[User off]',CR,LF,0 ENDIF ; ;------------------------------------------------------------------ ; ; MBBS USER DISPLAY OPTIONS: ; ; To make the USER message appear at the top of your screen on your ; console terminal, be sure to patch these escape sequences as needed ; for your system, the ESC sequences shown here are for the Kaypro 2, ; (ADM-31). (Except for LINE25 stuff which is for Televideo 950) ; IF MBBS AND LINE25 CLR25: DB ESC,'f',CR,ESC,'g',0 ; For Televideo 950 ENDIF ; USRMSG: IF MBBS AND NORMAL DB CR,LF ENDIF ; IF MBBS AND TOPDSP AND (NOT TOPDEL) DB ESC,'=',23+' ',0+' ' ; Bottom line (Kaypro 2) DB LF ; And linefeed (scrollup) ENDIF ; IF MBBS AND TOPDSP DB ESC,'=',0+' ',0+' ' ; Home cursor (Kaypro 2) ENDIF ; IF MBBS AND (TOPDSP OR NORMAL) DB '[ Who/Where ' DB 'Mins Usr# Date Logons Msg# ' ENDIF ; IF MBBS AND (TOPDSP OR NORMAL) AND MTDISP DB 'Maxt' ENDIF ; IF MBBS AND (TOPDSP OR NORMAL) DB ' ]' ENDIF ; IF MBBS AND TOPDSP AND TOPEOL DB 'X'-40H,CR,LF ; Erase to end of line/cr/lf (Kaypro 2) ENDIF ; IF MBBS AND TOPDSP AND (NOT TOPEOL) AND (NOT MTDISP) DB ' ' ENDIF ; IF MBBS AND TOPDSP AND (NOT TOPEOL) AND MTDISP DB ' ' ENDIF ; IF MBBS AND TOPDSP AND (NOT TOPEOL) AND (NOT TOPWRP) DB CR,LF ENDIF ; IF MBBS AND LINE25 DB ESC,'f' ; Load user line (TV-950) ENDIF ; IF MBBS AND NORMAL DB CR,LF ENDIF ; IF MBBS DB '[ ' CURUSR: DB ' ' ; 64 byte buffer poked DB ' ' ; By MLOGIN or MBBS ENDIF ; MBBS ; IF MBBS AND MTDISP MTOS: DB ' ' ENDIF ; IF MBBS DB ']' ENDIF ; IF MBBS AND NORMAL DB CR,LF,0 ENDIF ; IF MBBS AND TOPDSP AND TOPEOL DB 'X'-40H,CR,LF ; Erase to end of line/cr/lf (Kaypro 2) ENDIF ; IF MBBS AND TOPDSP AND (NOT TOPEOL) AND (NOT MTDISP) DB ' ' ENDIF ; IF MBBS AND TOPDSP AND (NOT TOPEOL) AND MTDISP DB ' ' ENDIF ; IF MBBS AND TOPDSP AND (NOT TOPEOL) AND (NOT TOPWRP) DB CR,LF ENDIF ; IF MBBS AND TOPDSP AND TOPDEL DB ESC,'R' ; Delete line (Kaypro 2) ENDIF ; IF MBBS AND TOPDSP DB ESC,'=',23+' ',0+' ',0 ; Bottom line, col 1 (Kaypro 2) ENDIF ; IF MBBS AND LINE25 DB CR,0 ; End of user line (TV-950) ENDIF ; ; ; NOTE: If you don't have a delete line function, MBYE puts the cursor ; on line 24, does a line feed, then homes cursor, displays and puts ; cursor back on 24,1. It's cleaner looking if you use a delete line ; (NOT ERASE to end of line, that's different) if you terminal can sup- ; port it.. (TOPDEL EQU YES if you have a delete line function.) If ; your terminal's cursor can be turned off, you may want to do that if ; the cursor flying around the screen is bothersome.. On a memory-mapped ; terminal, I the cursor can't be seen even with it on but on a serial ; terminal running at 4800 or less, it might be noticed. The lines are ; only updated at every linefeed, however, so it doesn't slow down file ; transfers (which bypass console output function) or affect speed very ; much. ; ;-------------------------------------------------------------------- ; IF NOT MBBS CURUSR: DS 0 ; To avoid undefined label if not mbbs, ENDIF ; Can be expanded and used by another bbs ; System, if you wish ; LFMSG: DB CR,LF,0 ; IF PRNTWB WBMSG: DB '?' ; Put your warm boot message here DB 80H ; Ending character = 80h ENDIF ; ; ; Smartmodem command strings ; IF SMODEM OR SM1200 OR USR2400 OR ANCHOR OR USR SMEMSG: DB 3,3,3,80H SMAMSG: DB 'ATA',CR,80H SMHMSG: DB 'ATH0',CR,80H SMQMSG: DB 'ATZ',CR,80H ENDIF ; IF ANCHOR OR USR SMZMSG: DB 'ATS0=0',CR,80H SMAMSA: DB 'ATS0=1',CR,80H ENDIF ; IF COMFILE OR EXFILE PTSMSG: DB '[Small TPA]',7,0 CNFMSG: DB CR,LF DB '[NO .COM?]',7,0 ENDIF ; IF WELFILE WELFILN:DB 0,'WELCOME ' ; Welcome file name, must be 11 chars. DB 0 ENDIF ; IF COMFILE AND NOT MBBS COMFCB: DB COMUSR DB COMDSK-'@' DB 'RBBS COM' ; Com file name, must be 11 chars. ENDIF ; Comfile ; IF MBBS COMFCB: DB COMUSR DB COMDSK-'@' DB 'MBBS COM' ; Com file if mbbs ENDIF ; IF MBLOG MLGFCB: DB MLGUSR DB MLGDSK-'@' DB 'LOGIN COM' ; Login.com file if mbbs ENDIF ; IF MBFMSG MFMFCB: DB MFMUSR DB MFMDSK-'@' DB 'MFMSG COM' ; Mfmsg.com file ENDIF ; IF EXFILE EXFCB: DB EXUSR DB EXDSK-'@' DB 'EXIT COM' ; Exit filename, must be 11 chars. ENDIF ; Exfile ;..... ; ; ; Real-Time clock buffer - convert (if necessary) and poke the proper ; BCD values into this area in your CLOCK routine if you have an RTC. ; (Do not set total mins on system, MBYE does that, just maintain the ; BCD values for time and date.) ; ; (NOTE: 99:99:99 INDICATES CLOCK IS NOT RUNNING OR NO RTC IS AVAILABLE) ; RTCBUF: IF RTC OR MBBS DB 99H,99H,99H ; Hh:mm:ss (bcd 24hr time) 00:00:00-23:59:59 DB 19H,85H,11H,02H ; Yyyy/mm/dd (bcd iso date) DW 0000H ; (total mins on system) (binary integer) ENDIF ; IF MBBS OR RTC DPTR: DW 0 ; Pointer stored here for dout routine DS 30 ; Local stack used by dout (it uses stack) DSTK: DW 0 ; Old sp saved here ENDIF ; ; ; These areas are not initialized ; PEND: IF COMFILE OR EXFILE OR MBLOG OR MBFMSG DS 1 ; User ; CURRFCB:DS 1 ; Disk DS 11 ; Filename DS 21 ; Rest of fcb ENDIF ; IF MNULL NULTRY: DS 1 ; No. of "How many nulls?" stuffed here ENDIF ; IF ((NOT USEZCPR) AND (CHKDSK OR CHKUSR)) OR EXTEND RBOOT: DS 1 ; "reboot" flag stored here ENDIF ; OPTION: DS 1 ; Save bye /option here ACFSAV: DS 1 ; Save user access flags here during ^b MSTATF: DS 1 ; 0 if data from console, 1 if from modem MDMFLG: DS 1 ; 0 if modem i/o disabled SAVFLG: DS 1 ; 1 if data saved below SAVBYT: DS 1 ; 1 byte "buffer" for console input ; IF MBBS DSPUSF: DS 1 ; Display user if non-zero, user shown at top ENDIF ; IF MBBS AND NODSP24 DSPUSX: DS 1 ENDIF ; IF TIMEOUT TOCNT: DS 2 ENDIF ; ; 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 ; ; Since these areas are not initialized, the following counters will not ; be changed by subsequent loads of this program ; IF USRLOG USRFLG: DS 2 ; = '*u' (dw 55aah) if initialized OLDUSR: DS 2 NEWUSR: DS 2 ENDIF ; DS 50 ; Stack depth STACK: DS 2 ; Local stack OBJEND: ; IF BYELOW OOPS EQU NO ; Don't worry bout below if byelow ENDIF ; IF NOT BYELOW ; ; ; This should trap any problems... You can select fewer BYE options or ; move your system up some more if you get the message below at assembly ; time... (THIS CODE IS ONLY FOR BYE RUNNING ABOVE THE BIOS, (BYELOW NO)) ; BYESIZE EQU OBJEND-BEGOBJ ; (used below to trap dangerous BYESTRT EQU RAMTOP-BYESIZE+1 ; Stomp on the bios condition...) GAP EQU BYESTRT-BIOSEND ; If gap is negative, OOPS EQU (GAP AND 8000H) SHR 15 ; Then oops will equ 1 (true) ENDIF ; IF OOPS ORG BIOSEND-BYESTRT ; So we know how much too big LDA UNDEF ; DANGER, BIOS stomper ; !^^^ ADDRESS of line above indicates # of bytes too big ^^^! ; !! Choose Fewer options and try reassembling !! ENDIF ; OOPS ;..... ; ; END