; BYE339 - REMOTE CONSOLE PROGRAM FOR CP/M 2 AND MODEM - 10/21/85 ; Not for CP/M 3--use BYE+3nn ; ASEG ; Needed for M80, disregard error if using MAC. ; ; This program allows modem callers to use a CP/M system just as if they ; were seated at the system console. Special assembly-time options al- ; low limiting the caller's access by password and/or access to only a ; message-service program. A number of external inserts are available ; to adapt this program to various computers, clocks and modems. It ; may be assembled with ASM, LASM, MAC or M80. If the ZCPR3 equate is ; set YES, a macro assembler such as MAC or M80 will be required. If ; the program will not assemble correctly with M80, check the insert ; that was added, it likely is not configured properly. ; ; There are spinoffs of the BYE program (notably MBYE and BYE5), we've ; tried to incorporate any "features" of these programs so that users need ; not use a spinoff but instead use the real BYE program. ; ; BYE3 is placed in the public domain. It may be updated or altered for ; your personal use. I'd like to try and consolodate any new releases, so ; we can avoid another MODEM7 fiasco. If you have changes that you feel ; should be included in future releases, please forward them to: ; Saratoga OxGate - 408/354-5934 (pst) ; ;======================================================================= ; (Put only the current update comments here, move the previous one down ; with the others. Will assist those who want to see "what is new".) ; ; ----------------------------------------------------------------------- ; ; v339 Added my improved BIN2BCD and BCD2BIN routines. ; 10/21/85 Added Mike DeWeese's call-back routines (note: to use call-back, ; you must have a Hayes compatible modem that can handle "ATA".) ; Printer was not working when going through BDOS calls. ; Now the MDRING stuff should work properly. ; Changed time routines so system only checks time-on after ever CR. ; (Will speed things up for slow clock users). ; Added "ULTIME" key to give a user "unlimited time" on the system. ; Modded RSX handler very slightly so multiple RSX's are trackable ; using CBF's RSX handling routines. ; pst ; ;======================================================================= ; ; BYE uses a special loader that is built into the program to automatically ; move itself below CCP. This does not require any alteration in the location ; of CP/M by using MOVCPM. In this case, all you need to do is: (1) choose ; the desired options, (2) patch in the insert for your computer in the special ; area near the start marked "+++ Install your I/O port insert here +++", (3) ; patch in the insert for your clock at label TIME (if RTC is YES) and ; (4) then finish editing, assemble, load and use. ; ; This program does the following: ; ; If you type BYE E, BYE will load and execute as though it has ; a valid carrier or caller. Handy for debug--otherwise bye will: ; ; 1) Hangs up the phone ; 2) Awaits ring if B3IM is YES, (or carrier detect if B3IM is NO), ; allows exit to CP/M if local KEYB types CTL-C ; 3) Answers the phone and outputs carrier ; 4) Awaits incoming carrier. If none found in 30 seconds, hangs ; up the phone and goes to step 1 ; 5) Detects the speed of caller and sets local cpu to that speed ; 6) Asks number of nulls (0-9) ; 7) Sets the log-in time (if TIMEON is YES) ; 8) Types the "WELCOME" file from disk, (optional) allowing ; CTL-C to skip it ; 9) Asks for a password (optional), allowing 3 tries to get ; it right. When entered drops into CP/M ; 10) Caller can leave by hanging up, (any time carrier is ; lost, it waits then goes back to step 1) or the caller ; may type the program name (BYE). ; ;======================================================================= ; ; v338 Re-installed code for modems that require ring signals (such as ; 08/08/85 PMMI, Hayes MM100 & MM][, AppleCat][), which was brutally removed ; by the author of Bye335. Changed documentation which had some ; BYEBDOS calls backwards. Changed format of two BYEBDOS calls. ; Bye was loading in ~256 bytes lower than necessary-- fixed it. ; Shortened stack space from 60 to 40 bytes. ; Added "ASKNULL" equate to disable asking for nulls. ; Added "MDMRNG" equate for PMMI type modems that need ring/answer. ; Fixed bug introduced in v335 re: COM files on other drives. ; Fixed bug introduced in v337 re: NO25TH / lastcaller reading. ; pst ; ; v337a Added additional conditionals to take more assembly time ; 07/27/85 advantage of HS300, HS1200, HS2400, B3IM & IMODEM. Moved the ; end marker for the B3IM routine to just above IMHANG so to avoid ; the inadvertant deletion of some lines of code that belong with ; BYE instead of with the B3IM routines. Included BYE337.FIX. ; -- Don Brown ; ; v337 *All BYE dependant routines may be accessed through BDOS calls ; 07/24/85 now. BYE intercepted the BDOS vector anyway, so I figured we ; might as well do something with it. BYEBDOS calls start at ; 80 decimal. See BYE337.DOC for more information. ; *Striped out many comments, because I've written and included ; a comprehensive BYE manual. ; *Added fixes for: Anchor modems, MBBS disconnect, and ; function keys generating nulls. ; *Removed BYELOW equate...you MUST to run BYE low now. Sorry. ; *If you're not using the NO25TH option, the LCDATA buffer will ; be a single entry (a 0) so your BBS can sense you're not using ; the NO25TH deal and not overrwrite BYE. ; *Removed manditory NO25TH when using OxGate, as OxGate's now ; smart enough to sense that you don't have the buffer (see above). ; *Added NEEDLC. If yes, then will include code to read lastcaller. ; *If you have your own modem overlay, please remove the "ANI 7FH" ; or "ANI 127"'s that are in it. This will allow 8-bit I/O for ; programs like XMODEM. ; *Removed low-memory bytes LHOUR/LMIN-- XModem and BBS can ; access them by looking at RTCBUF+7 and RTCBUF+8 ; *Made the two subroutines: BCDBIN and BINBCD deleteable. If you ; need them, then set BIN2BCD and/or BCD2BIN to "YES", otherwise ; they won't be assembled into the code. ; *If TIMEON is yes, you should make sure your clock insert pokes ; not only CHOUR and CMIN with the binary hour/min, but that it ; pokes the RTCbuf with the BCD values. This way BBSs and XMODEM ; can get the time and date from BYE. ; *No longer uses STATUS byte in low-memory. ; *No longer patches punch and reader devices to modem. ; pst ; ;======================================================================= ; MAIN EQU 3 VERS EQU 39 MONTH EQU 10 DAY EQU 21 YEAR EQU 85 ; ; System equates ; NO EQU 0 YES EQU NOT NO ; For conditional assembly ; ; You will likely also want to change the password, located below at ; label 'PASSWD', 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 ; ;*********************************************************************** ; ; BYE3 Operating System Configuration ; CCPL EQU 8 ; Number of sectors for CCP size (norm=8) ; LOCMD EQU 61 ; Start of BYERSX commands HICMD EQU LOCMD+22 ; End of BYERSX commands ; ; Modem type ; MDMRNG EQU NO ; Yes, for board-modem requiring ring signal IMODEM EQU NO ; Yes, for intelligent modem, including Hayes B3IM EQU NO ; Yes, your modem uses AT protocol, like Hayes ; ; Set one (and only one) of the following HS equates to YES ; HS2400 EQU NO ; Yes if your modem's high speed is 2400 baud. HS1200 EQU NO ; Yes if your modem's high speed is 1200 baud. HS300 EQU NO ; Yes if your modem's high speed is 300 baud. ; ; The next 4 equates are only used if B3IM is YES ; ECHO EQU YES ; Yes, if modem echos commads CALBAK EQU NO ; Yes, if you want to use call-back feature ANCHOR EQU NO ; Yes, if you have a Mark XII NODTR EQU NO ; Yes, modem or computer does not support DTR NOATA EQU NO ; Yes, if you have an older Password, or S100 ; ; BBS type ; ; Set only one, or none of the following BBS equates to YES. ; OXGATE EQU NO ; Yes, running OxGate BBS system MBBS EQU NO ; Yes, running MBBS BBS system MINICK EQU NO ; Yes, running MINICBBS METAL EQU NO ; Yes, running METAL BBS system. Note: METAL ; Requires a patch to use the NO25TH feature. ; See the METAL.FIX file in this LBR. RBBSCK EQU NO ; Yes, running RBBS, sets/resets 'WRTLOC' flag IOVAL EQU 0 ; Initial value for IOBYTE (if MINICK YES) ; ; Clock/Time equates ; ; RTC - tells BYE that you have a real-time clock that pokes ; CHOUR and CMIN with binary hour/minutes, and pokes ; RTCBUF with the BCD time and date. See the RTC reader ; code for more info. ; ; TIMEON - if RTC = yes, will bump users if they are online longer ; then MAXMIN minutes (default=60). ; TOSWB - if RTC = yes and TIMEON = yes, will print time on system ; on every warm-boot. ; ; RSPEED - if RTC = yes, will not allow low-speed (300 baud) users ; online during prime-time hours. ; HOUR1 - start of prime time (default = 7pm) ; HOUR2 - end of prime time (default = 11pm) ; OKSPD - anything this fast, or faster is ok (default = 1200 baud) ; ; BCD2BIN- your reader routine needs our BCD -> BINary converter ; BIN2BCD- your reader routine needs our BINary -> BCD converter ; RTC EQU NO ; YES = we have RTC reader TIMEON EQU NO ; YES = keep track of time-on-system TOSWB EQU NO ; YES = print TOS on warm-boot RSPEED EQU NO ; YES = restrict baud rates ; BCD2BIN EQU NO ; YES = include BCD->BIN routine "BCDBIN" BIN2BCD EQU NO ; YES = include BIN->BCD routine "BINBCD" ; IF RTC AND TIMEON MAXMIN EQU 60 ; 0= no restrictions ENDIF ; RTC AND TIMEON ; IF RTC AND RSPEED ; Restrict low speed people HOUR1 EQU 19 ; Start of prime-time HOUR2 EQU 23 ; End of prime-time OKSPD EQU 5 ; Minimum speed accepted (5=1200 baud) ; See OFFMSG to match your time & baud rate ENDIF ; RTC AND RSPEED ; ; General Equates ; HARDLOG EQU NO ; Yes, echo remote input to printer PRINTER EQU YES ; Yes, printer available & online ; COMFILE EQU NO ; Yes, chain to a .COM file on carrier detect COMDRV EQU 'A' ; Drive to look for .COM file on COMUSR EQU 14 ; User# of .COM file to be called after answer ; EXFILE EQU NO ; Yes, chain a .COM file upon loss of carrier EXDRV EQU 'A' ; Drive to look for exit .COM file on EXUSR EQU 14 ; User # of .COM file to be called upon exit ; NO25TH EQU NO ; Yes, you wish to display lastcalr data (^W) NEEDLC EQU NO ; Yes, read the name from lastcalr file LCDRV EQU 'A' ; Drive to find last-caller file LCUSR EQU 14 ; User # of last-caller file ; WELFILE EQU NO ; Yes, to send a welcome file WELDRV EQU 'A' ; Drive to look for welcome file WELUSR EQU 14 ; User number of welcome file ; CLRSCR EQU NO ; Yes, to auto-clear local crt screen between CLRB4 EQU NO ; Clear before printing user-log summary ; CLRCH1 EQU 1BH ; Set these for your clear screen sequence CLRCH2 EQU '*' ; 1B is escape and ESC : clears my screen CLRCH3 EQU 0 ; (Byte 3 if you need it). CLRCH4 EQU 0 ; Six bytes allowed for clear screen sequence CLRCH5 EQU 0 ; And you can also clear CLRCH6 EQU 0 ; Your 25th line if desired. ; ASKNULL EQU YES ; Yes, ask the "Nulls" question MNULLS EQU 6 ; Max times to ask "Nulls, if needed" question PRGRSS EQU YES ; Yes, for helpful progress reports on crt PRNTGB EQU YES ; Yes, print "Goodbye..." message PRNTWB EQU NO ; Yes, print a string for each warm boot PWRQD EQU NO ; Yes, password needed for CP/M access TOVALUE EQU 5 ; Minutes of no-activity allowed. 255 max. WBRTN EQU NO ; Yes, do function each time system warm boots ; ; System and Hardware dependent options ; CLOSS EQU 1 ; If carrier dies, wait 1 sec. then hang up CFRST EQU 25 ; Wait 25 seconds for carrier (IF MDMRNG) CTRLC EQU 'K'-'@' ; Map ^C to this character DOWNMIN EQU 2 ; Number of min after Sysop types ^^O to logout LOSER EQU NO ; Yes, warm boot overwrites part of the BIOS MHZ EQU 4 ; Processor clock in MHz ; ; Function Keys ; ATTNCH EQU '^'-'@' ; Attention character to type first (^^ now) BLNKKEY EQU 'B' ; Key to toggle remote terminal on/off SYSDKEY EQU 'O' ; Char. to print "System going down in n min.." TWITKEY EQU 'N' ; Keycode to hangup modem manually MSGKEY EQU 'Q' ; Keycode to print "Message from SYSOP: " BELLKEY EQU 'G' ; Key to toggle bells on console TIMEKEY EQU 'T' ; Key for sysop to display time (if TIMEON) ULTMKEY EQU 'U' ; Key to grant unlimited time (if TIMEON) WHOKEY EQU 'W' ; Key to display LASTCALR if NO25TH is YES. ZCREEN EQU 'Z' ; Key to manually clear your screen b/t calls. ; ; CCP options ; ZCPR2 EQU NO ; Yes, if running ZCPR2, ZCMD1/2 or NZCPR ZCPR3 EQU NO ; Yes, if running ZCPR3 (set ZCPR2 = no) ; ; NOTE: requires MAC.COM to assemble if ZCPR3 set YES ; IF ZCPR3 MACLIB Z3BASE ; Requires MAC to assemble...otherwise enter ; Constants directly..see label DOZ3 for ; For required EQU's ENDIF ; ZCPR3 ; USEZCPR EQU NO ; Yes, if using ZCPR/NZCPR/ZCMD to set bytes MAXDRIV EQU 003DH ; ZCPR lolcation of MAXDRIV byte WHEEL EQU 003EH ; Location of ZCPR's wheel flag MAXUSER EQU 003FH ; ZCPR location of MAXUSR byte MAXDRV EQU 'D'-'@' ; Highest drive supported MAXUSR EQU 9 ; Highest user area SYSDRV EQU 'F'-'@' ; Highest local drive supported SYSUSR EQU 15 ; Highest local user area (0-15) ; CHGPATH EQU NO ; Yes, if changing ZCPR's external path EXTPATH EQU 0040H ; ZCPR external path default location ; ; MSPEED values ; MSPEED EQU 003CH ; Baud rate pointer 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 baud BP2400 EQU 6 ; 2400 baud BP4800 EQU 7 ; 4800 baud BP9600 EQU 8 ; 9600 baud BP19200 EQU 9 ; 19200 baud ; ; If using LOSER ; ; There are some cases where warm boot overwrites the initial BIOS jump ; table. This problem was solved for the Superbrain 3.0 bios by find- ; ing a warmboot call to HIGH in the BIOS. This call is then patched by ; BYE. The form of the call is: WBCALL CALL WMSTRT ; IF LOSER WBCALL EQU 0E260H ; Check this in your BIOS ; ; The following location is called ; WMSTRT EQU 0E566H ; Check this in your BIOS ENDIF ; LOSER ; ;----------------------------------------------------------------------- ; ; END OF OPTION CONFIGURATION SECTION FOR BYE3 ; ;----------------------------------------------------------------------- ; ORG 100H ; ;-------------------- Special Loader Routine --------------------------- ; START: LXI SP,ISTACK ; Set stack for initialization routine LHLD 0000H+1 ; Point to warm boot DCX H ; If BYE is active, MOV D,M ; Pick up pointer to BYE variables DCX H MOV E,M LXI H,HDROFF ; Calculate address of BYE tag DAD D MOV A,M ; Get letter CPI 'B' ; Try to match 'BYE' (or 'Bye') JNZ STARTA ; Relocate if BYE not active INX H MOV A,M CPI 'Y' ; Relocate if BYE not active JNZ STARTA INX H MOV A,M CPI 'E' ; Relocate if BYE not active JNZ STARTA ; ; Ok, we're sure that BYE's already there ; LHLD BDOS+1 ; Load BDOS vector INX H ; Compute start of BYE3 INX H INX H PCHL ; Go execute already loaded code ; STARTA: LHLD BDOS+1 ; Load BDOS vector LXI D,-(CCPL*256)-8 ; 2k bytes in CCP plus offset DAD D ; Make room for the CCP ; ; HL now contains the destination address of BYE3 ; LXI D,OBJEND-1 ; Set up the source pointer LXI B,OBJEND-BEGOBJ ; Set up byte counter ; BLOCK: LDAX D ; Get program byte MOV M,A ; Move program byte MOV A,B ; Get byte count ORA C ; Finished block transfer? JZ UPDATE ; Yes, check on the opcode values DCX D ; No, set source pointer DCX H ; Set destination pointer DCX B ; Set byte counter JMP BLOCK ; Continue block transfer until finished ; UPDATE: XCHG ; Move the source addrress into 'HL' CALL NEGHL ; Prepare value for subtraction DAD D ; Form the program offset SHLD OFFSET ; Save the program offset XCHG ; Set up the offset register LXI H,ENDOBJ ; Get the ending addr of the prgm code DAD D ; Form new ending addr (new location) SHLD ENDRNG ; Save the ending addr of the prgm code LXI H,BEGOBJ ; Get the start address of program code DAD D ; Form new beginning addr (new location) ; ; The following code determines whether or not an address is within the ; BYE prgm and sets it to the new address if it is - otherwise it will ; not disturb the code. ; DCX H ; Set up the source pointer for the ; Modification routine entry MODIFY: INX H ; Point to the next (hopefully) instr. DB LXID ; Get the address of the end of 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 number of elements in the table LXI D,INST3 ; Set up the 3-byte opcodes table ptr ; THRBYT: LDAX D ; Get opcode byte from table CMP M ; Is this byte a 3-byte opcode? JZ CHANGE ; Change the 2nd and 3rd bytes if needed INX D ; No, advance table pointer DCR B ; End of 3-byte table? JNZ THRBYT ; No, keep looking ; ; Skip all the 2-byte opcodes - this keeps the transfer program from ; trying to figure out what the second byte is. ; MVI B,INST2E-INST2 ; Get the number of table elements LXI D,INST2 ; Set up the 2-byte-opcodes-table ptr ; TWOBYT: LDAX D ; Get opcode byte from table CMP M ; Is this byte a 2-byte opcode? JZ SKIP ; Yes, skip it and continue DCR B ; No, end of 2-byte table? INX D ; Advance table pointer JNZ TWOBYT ; No, keep looking JMP MODIFY ; Yes, a one-byte opcode, keep going ; SKIP: INX H ; Advance object code pointera JMP MODIFY ; Continue search ; CHANGE: LXI D,OBJEND ; Set up end of range pointer LXI B,BEGOBJ ; Set up beginning of range pointer ; ; See if the address is above the range ; INX H ; Advance pointer to the LSB of the addr MOV A,E SUB M INX H ; Advance pointer to the MSB of the addr MOV A,D SBB M JC MODIFY ; ; See if the address is below the range ; DCX H ; Set ptr back to the LSB of the addr MOV A,M SUB C INX H ; Advance pointer to the MSB of the addr MOV A,M SBB B JC MODIFY ; ; Update the value of this address by adding the offset to it ; DCX H ; Set ptra back to LSB of the address DB LXID ; Load DE with the offset value ; OFFSET: DW 0 MOV A,M ; Get base address ADD E ; Change LSB to new address MOV M,A ; Update memory INX H ; Advance pointer to the MSB of the addr MOV A,M ; Get the MSB of the base addr ADC D ; Change LSB to new address MOV M,A ; Update memory JMP MODIFY ; Take care of the next instruction ; ; Small subroutine to negate the contents of HL ; NEGHL: MOV A,H CMA MOV H,A ; Get the complement of the MSB MOV A,L CMA MOV L,A ; Get the complement of the LSBb INX H ; Make 'HL' totally negative RET ; ; Prepare to branch to the BYE3 program ; BEGIN: LHLD BDOS+1 PUSH H LXI D,BEGOBJ LHLD OFFSET ; Get prgram offset DAD D ; Form address of new BDOS address SHLD BDOS+1 ; Update BDOS vector INX H POP D MOV M,E INX H MOV M,D INX H PCHL ; Jump to relocated BYE3 program ; ; The following table defines the 3-byte load instructions used in the ; 8080 instruction set. ; INST3: DB 001H,011H,021H,022H,02AH,031H,032H,03AH,0C2H DB 0C3H,0C4H,0CAH,0CCH,0CDH,0D2H,0D4H,0DAH,0DCH DB 0E2H,0E4H,0EAH,0ECH,0F2H,0F4H,0FAH,0FCH INST3E EQU $ ; End of 3 byte op codes ; ; ; The following table is the listing of the 2-byte opcodes used in the ; 8080 instruction code set. ; INST2: DB 006H,00EH,016H,01EH,026H,02EH,036H,03EH,0C6H DB 0CEH,0D3H,0D6H,0DBH,0DEH,0E6H,0EEH,0F6H,0FEH INST2E EQU $ ; End of 2 byte op codes ; ; Set aside space for the stack region ; DS 40 ISTACK: DW 0 ; Top of stack ; ; ;----------------------------------------------------------------------- ; ; THE FOLLOWING CODE GETS MOVED ; TO HIGH RAM BY THE LOADER ; PROGRAM, WHERE IT IS EXECUTED. ; ;----------------------------------------------------------------------- ; BEGOBJ: JMP 0 ; Filled by BEGIN BGOBJ2: JMP START0 ; Hop over fixed vectors ; MCBOOT: JMP MBOOT ; Off to warm boot JMP PRNLOG ; Go print out items of interest ; ; Variables follow in a predefined order that can be manipulated by a ; passworded or other program to give special users different capabili- ; ties. ; ;----------------------------------------------------------------------- ; ; Here is a quickie handy reference table to use so we do not get mixed ; up. Please do not change the order of it in any future changes. ; ; |mxusr |mxdrv |toval |nulls |ulcsw |lfeeds|wrtloc|hardon|mdmoff|covect | ; |1 byte|1 byte|1 byte|1 byte|1 byte|1 byte|1 byte|1 byte|1 byte|2 bytes| ; ; |hdroff |bellon|lcptr |lcdata |mxtme |rtcbuf | ; |3 bytes|1 byte|1 byte|2 bytes|1 byte|2 bytes| ;----------------------------------------------------------------------- ; MXUSR: DB MAXUSR ; Runtime maximum user area available MXDRV: DB MAXDRV ; Runtime maximum drive available TOVAL: DB TOVALUE ; Number of mins. to wait before timeout NULLS: DB 0 ; Number of nulls after ULCSW: DB 0 ; Upper case only switch (32=upper case) LFEEDS: DB 0 ; Line feed mask (0=don't mask) WRTLOC: DB 0 ; Location RBBS pokes so BYE won't hang HARDON: DB 0FFH ; If 0, hardlog is deactivated MDMOFF: DB 0 ; If 0FFH, do not output to console COVECT: DW 0 ; Console output vector for XMODEM HDROFF EQU $-MCBOOT ; Offset to 'BYE' that follows DB 'BYE' ; Tells XMODEM that BYE is being used BELLON: DB 0FFH ; If 0FFH, ^G ok to send to console LCPTR: JMP LCDATA ; First byte is user access data for MBBS ; Next 2 bytes point to lastcalr data buffer MXTIME: JMP RTCBUF ; First bye holds maximum time allowed ; Next 2 bytes point at clock buffer ; ;*********************************************************************** ; ; THIS IS THE OFFICIAL START OF THE BYE PROGRAM ; ;*********************************************************************** ; ; +++ Insert your serial port driver here +++ ; ;*********************************************************************** ; ; (IF IMODEM AND (NOT B3IM) ; +++ Insert your intelligent modem driver here +++ ; (not necessary if B3IM is YES) ; ;*********************************************************************** ; ; ; If you have a clock please replace this code with your clock read code. ; Use as many instructions as you need but make sure you store binary-not ; BCD values in CCHOUR and CCMIN. ; ; Two subroutines are availble if you set the "xxx2yyy" equates: ; BINBCD - converts binary to BCD -- set BIN2BCD = YES ; BCDBIN - converts BCD to binary -- set BCD2BIN = YES ; ; Make sure you also store the full time and date in RTCBUF so your BBS ; and XMODEM can get the time and date. ; ; (IF RTC) ; +++ Insert your clock reader here +++ ; ;************************************************************************* ; ; This code is for programming the "Hayes Compatible" intelligent ; modems. If you have a "dumb" modem, then it doesn't apply to you. ; If you have an intelligent modem that is not "Hayes Compatible" then ; You should have inserted your own modem-driver above. ; Example: Cermetek I212A = B3CM+1.INS ; IF B3IM IMRING: CALL MDINST ; Character ready from modem? RZ ; No CALL MDINP ; Get the modem response code ANI 7FH ; Strip parity ENDIF ; B3IM ; IF B3IM AND PRGRSS CALL RCDISP ; Display RC for local sysop PUSH PSW LXI H,LFMSG CALL PRINTL ; Turn up a line on crt POP PSW ENDIF ; B3IM AND PRGRSS ; IF B3IM CPI CR RZ CPI LF RZ CPI '2' ; Ring? JNZ REDOIT ; No, something wrong, start over ENDIF ; B3IM ; IF B3IM AND CALBAK AND PRGRSS LXI H,CALMSG1 CALL PRINTL ; Print "Waiting for 2nd ring..." ENDIF ; IF B3IM AND CALBAK LXI B,8000 ; Look for 8 seconds for 2nd ring RCLOOP: CALL MDINST ; Anything available? JNZ RING2 ; Yes, check it out CALL KDELAY ; Wait 1ms DCX B ; Decrement counter MOV A,B ORA C JNZ RCLOOP JMP CALL2 ; Now check for second call ; RING2: CALL MDINP ; Get character ANI 127 CALL RCDISP ; Show it on screen CPI '2' JNZ RCLOOP ; Not another ring, so we're OK for now ENDIF ; IF B3IM AND CALBAK AND PRGRSS LXI H,CALMSG3 ; Print "Timing out from voice call..." CALL PRINTL ENDIF ; IF B3IM AND CALBAK LXI B,20 ; Voice call -- wait 20 secs to timeout TOTLP: CALL DELAY ; Time-out loop DCX B MOV A,B ORA C JNZ TOTLP JMP REDOIT ; Re-init modem ENDIF ; CALL2 EQU $ ; Wait for second call ; IF B3IM AND CALBAK AND PRGRSS LXI H,CALMSG2 ; Print "Waiting 45 seconds for call" CALL PRINTL ENDIF ; IF B3IM AND CALBAK CALL EATALL ; Eat anything in the buffer LXI B,45000 ; Wait up to 45 seconds for call back C2LOOP: CALL MDINST JNZ ISRING CALL KDELAY ; Wait 1ms DCX B MOV A,B ORA C JNZ C2LOOP JMP REDOIT ; All timed out -- no 2nd ring, re-init ; ISRING: CALL MDINP ; Do we have second ring? ANI 127 CALL RCDISP ; Display result code CPI '2' CZ IMINT2 ; Print CRLF and set zero flag JNZ REDOIT ; Not a ring, so re-init, else answer phone ENDIF ;B3IM AND CALBAK ; IF B3IM AND (NOT NOATA) IMRIN1: MVI B,22 ; Must let the phone quit ringing first CALL DLP1 ; Usually takes from 1.4 to 3.7 seconds CALL EATALL ; Swallow c/r or lf from result code LXI H,B3ATA CALL IMSEND ; Send ATA to modem ENDIF ; B3IM AND (NOT NOATA) ; IF B3IM LXI B,30000 ; We will check for RC every 1 ms for 30 secs ; MDR1: CALL MDINST JZ RCHEK ; And wait for response CALL MDINP ; Then fetch it ANI 07FH ; And strip parity ENDIF ; B3IM ; IF B3IM AND PRGRSS CALL RCDISP ; And show results code (RC) ENDIF ; B3IM AND PRGRSS ; IF B3IM CPI CR JZ MDR1 CPI LF JZ MDR1 CPI '3' ; Carrier wait timeout? JZ REDOIT ; Yep, timeout (voice call maybe) CPI '4' ; Error? JZ REDOIT ; Start over ENDIF ; B3IM ; IF B3IM AND (HS1200 OR HS2400) CPI '1' ; 300 baud or 2400 bps? JNZ MDR2 ; No, check for 1200 bps ENDIF ; B3IM AND (HS1200 OR HS2400) ; ; Get next character if first was a '1' (and HS2400 is YES) ; IF B3IM AND HS2400 CALL CHECK1 ; Let's see if it's a 1, 10 or 11 ENDIF ; B3IM AND HS2400 ; IF B3IM AND PRGRSS CALL RCDISP ; Show RC to local terminal ENDIF ; B3IM AND PRGRSS ; IF B3IM AND HS2400 CPI '0' JZ SET24 ; For Vadic and Hayes, 10 means 2400 bps CPI '1' ; For some, 11 means 2400 bps JZ SET24 ENDIF ; B3IM AND HS2400 ; IF B3IM JMP SET3 ; Was 1 (300 baud) ENDIF ; B3IM ; IF B3IM AND (HS1200 OR HS2400) MDR2: CPI '5' ; 1200 bps? JZ SET12 ; Yes ENDIF ; B3IM AND (HS1200 OR HS2400) ; IF B3IM AND HS2400 CPI '6' ; 2400 bps? (preproduction only) JZ SET24 ENDIF ; B3IM AND HS2400 ; IF B3IM AND ANCHOR JMP SET3 ; If it wasn't a 3 or 5 it means the Anchor ; Connected at 300 but sent RC at wrong speed ENDIF ; B3IM AND ANCHOR ; IF B3IM JMP MDR1 ; Wait 30 seconds for valid response ; RCHEK: CALL KDELAY ; Wait 1 millisecond DCX B MOV A,C ORA B ; Time up? JNZ MDR1 ; No, Keep trying ; REDOIT: POP H ; Go reset if none of these responses LXI H,VCNUM ; Update the voice call INR M ; Counter LXI H,LFMSG CALL PRINTL ; Turn up a line on crt JMP HANGUP1 ENDIF ; B3IM ; IF B3IM AND PRGRSS RCDISP: PUSH B PUSH H PUSH PSW ; Save A STA RCSHOW LXI H,RCSHOW ; And show results code (RC) CALL PRINTL POP PSW PUSH PSW CPI CR JNZ RCDIS1 MVI A,LF STA RCSHOW ; Force a LF after a CR LXI H,RCSHOW CALL PRINTL RCDIS1: POP PSW POP H POP B RET ENDIF ; B3IM AND PRGRSS ; ; IF B3IM CHECK1: LXI B,500 ; Try for 500 ms CHECK2: CALL KDELAY DCX B MOV A,B ORA C JZ CHECK3 ; 500 ms is up CALL MDINST ; Character ready? JZ CHECK2 ; No, keep waiting CALL MDINP ; Yes, fetch it ANI 07FH ; And strip parity RET ; And return ; CHECK3: MVI A,0FFH ; Set error code RET ; And return ENDIF ; B3IM ; IF B3IM AND HS2400 SET24: CALL SET2400 ; Set port to 2400 bps MVI A,BP2400 STA MSPEED ; Set speed indicator JMP FINISH ENDIF ; B3IM AND HS2400 ; IF B3IM SET3: CALL SET300 ; Set port to 300 baud MVI A,BP300 STA MSPEED ; Set speed indicator JMP FINISH ENDIF ; B3IM ; IF B3IM AND (HS1200 OR HS2400) SET12: CALL SET1200 ; Set port to 1200 bps MVI A,BP1200 STA MSPEED ; And speed indicator ENDIF ; B3IM AND (HS1200 OR HS2400) ; IF B3IM FINISH: POP H ; Reset CALL on the stack CALL PATCH ; Patch the jump table MVI B,15 CALL DLP1 ; Wait 1.5 sec for user to enter terminal mode CALL EATALL ; Clear input port and JMP ANSW ; Greet the user at his speed ; ; ; Initialize the modem. First, disable the auto-answer to prevent any ; problems if somebody phones while you are resetting the registers. ; Then reset the registers for normal unattended operation. ; IMINIT: CALL DLP CALL EATALL ; LXI H,B3ATZ ; Reset the modem CALL IMSEND CALL DLP CALL EATALL ; Swallow the response ; LXI H,B3INIT CALL IMSEND ; Go initialize the modem ENDIF ; B3IM ; IF B3IM AND PRGRSS IMINT1: CALL CHECK1 CPI 255 ; Didn't come back in 500ms? JZ IMERRX CPI '0' CZ RCDISP ; Display result code JZ IMINT2 CPI '4' CZ RCDISP JNZ IMINT1 ; Wait for a zero or four IMERRX: LXI H,CMDERR CALL PRINTL ; Inform sysop of problem RET ENDIF ; B3IM AND PRGRSS ; IF B3IM IMINT2: LXI H,LFMSG CALL PRINTL ; Turn up a line on crt CALL DLP CALL EATALL ; Get any garble from the modem RET ; ; ; Delay about one second to let modem get stabilized before or after a ; command string. ; DLP: MVI B,10 ; DLP1: CALL DELAY DCR B JNZ DLP1 RET ; EATALL: CALL CHECK1 CPI 0FFH ; All characters eaten? JNZ EATALL ; No, keep eating RET ; ; De-initiaize the modem. When the operator uses CTL-C followed by any- ; thing but "R", this call will return the modem to default settings. ; IMQUIT: LXI H,LFMSG CALL PRINTL ; Turn up a line on crt LXI H,B3ATZ CALL IMSEND ; Send ATZ message to modem CALL DLP CALL EATALL LXI H,B3USR CALL IMSEND ; Send ATS0=0 to modem CALL EATALL ; Clear mdm input RET ; ; ; Send a command string to the modem. (If ECHO) Verify, reset the modem ; and resend string if echo fails. ; IMSEND: PUSH B ; Save 'BC' registers SHLD ADDSTR ; Save start of command string ; IMSEN1: CALL MDOUTST ; Modem ready for character? JZ IMSEN1 ; No, go check again MOV A,M ; Get the character CALL MDOUTP ; Send the character ENDIF ; B3IM ; IF B3IM AND PRGRSS CALL RCDISP ; Display the command string ENDIF ; B3IM AND PRGRSS ; IF B3IM AND ECHO ; Hayes needs echo checking CALL CHECK1 ; Get the echo character CMP M ; Same? JNZ NOECHO ; No, let's resend entire command string ENDIF ; B3IM AND ECHO ; IF B3IM INX H ; Point to next MOV A,M ; Get next character ORA A ; Has all been sent JNZ IMSEN1 ; No, go send another character POP B ; Restore the BC registers RET ; Return past end of message ENDIF ; B3IM ; NOECHO: IF B3IM AND ECHO AND PRGRSS LXI H,NOEMSG CALL PRINTL ; Inform sysop of echo error ENDIF ; B3IM AND ECHO AND PRGRSS ; IF B3IM AND ECHO CALL MDOUTST ; Wait for modem ready JZ NOECHO MVI A,CR CALL MDOUTP ; Force a c/r to end command string CALL DLP ; Let modem settle CALL EATALL ; Make sure input is clear LHLD ADDSTR ; Restore address of command string JMP IMSEN1 ; And send it again ENDIF ; B3IM AND ECHO ; ; A hangup routine for those people who don't have DTR control ; over their modems. ; IF B3IM AND NODTR IMDROP: CALL EATALL MVI B,15 CALL DLP1 ; This routine will hang up the phone LXI H,B3ESC ; Using +++ATH CALL IMSEND CALL EATALL MVI B,15 CALL DLP1 LXI H,B3ATH CALL IMSEND ; For modems without DTR support CALL DLP RET ENDIF ; B3IM AND NODTR ; ; End of B3IM ;*********************************************************************** ; IMHANG: CALL MDCARCK ; Carrier? RZ ; Carrier gone, return ; IF B3IM AND NODTR CALL IMDROP ; Send +++ATH ENDIF ; B3IM AND NODTR ; IF NOT NODTR CALL MDSTOP ; Drop DTR-***This is a new label just after ; MDQUIT that drops dtr and returns. ENDIF ; NOT NODTR (see BYE3-INS.LBR for new insert) ; JMP IMHANG ; Keep looping RET ; ;----------------------------------------------------------------------------- ; ; If the carrier is lost - hang up, await ring. Otherwise, say goodbye, ; and hang-up. ; START0: LHLD BDOS+1 ; Get beginning address of BYE3 program SHLD BDADDR ; Save address of BYE3 start ; ; Patch in BYE interceptor ; 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 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 thinks RSX = BDOS ; NORPTC: XRA A ; A=0 STA ULCSW ; Reset upper/lower case flag STA LFEEDS ; And line feed flag STA WRTLOC ; And write-in-progress flag ; IF RTC AND TIMEON STA MXTIME ; Show clock hasn't been read yet ENDIF ; RTC AND TIMEON ; LHLD VCONOUT+1 SHLD COVECT ; So xmodem can make direct BIOS calls ; ; Set MINICK to 'YES' if you use MINICBBS and want to take advantage of ; its feature which can prevent the modem from hanging up if the caller ; should happen to disconnect during a file update. MINICBBS sets the ; high-order bit of IOBYTE (address 0003H) to indicate a file update is ; in progress. ; IF MINICK MVI A,IOVAL ; Get proper initial value STA IOBYTE ; Set it in IOBYTE ENDIF ; MINICK ; IF MBBS LXI SP,STACK CALL MDCARCK JZ START1 ; No carrier, skip this LDA LCDATA CPI ' ' ; User logged in? JZ GOODBY ; No, carry on XRA A STA 0 ; Prep mbbs MVI A,0FFH STA WRTLOC ; To prevent hangup LDA FCB+1 CPI 'C' ; Comments requested? JZ MBBSC ; Yes, do comments ENDIF ; MBBS ; IF MBBS AND PRNTGB LXI H,GBMSG CALL PRINTB ; Say goodbye to user ENDIF ; MBBS AND PRNTGB ; IF MBBS MBBS01: CALL MDHANG ; Drop carrier and fix so phone won't answer CALL LODCOM ; Load mbbs for logoff JMP MBBSNC ; And tell sysop ; MBBSC: LXI H,MBBS1 CALL PRINTB ; Wait for mbbs to load CALL LODCOM ; Load mbbs CALL MDCARCK ; Did user wait for all this? JZ MBBSNC ; No, tell mbbs MVI A,0CDH STA 0 ; So mbbs will ask for comments CALL 100H ; Now do it ; MBBSNC: LXI H,MBBS2 CALL PRINTL ; Tell sysop about log off MVI A,0FFH STA MDMOFF ; So bye will handle rest of this MVI A,'E' STA OPTION ; So bye will trap mbbs return CALL 100H ; Let mbbs finish user stats ENDIF ; MBBS ; CALL MDCARCK ; Call modem carrier check routine JNZ GOODBY ; We have carrier, so say bye bye... ; START1: IF COMFILE LDA FCB+1 STA OPTION ; So remote cannot type BYE E MVI A,' ' STA FCB+1 ENDIF ; COMFILE ; ; Identify version of program ; CALL PATCH ; Copies vectors for PRINTL CALL UNPATCH LXI H,VMSG ; Signon message CALL PRINTL JMP HANGUP ; We know it is local, so skip call to ; Carrier check ; NOSLASH:CALL CARCK ; Signed off with this program? JC HANGUP ; Nobody there ; GOODBY: IF PRNTGB LXI H,GBMSG ; Goodbye message CALL PRINTB ; Print this message ENDIF ; PRNTGB ; CALL IMHANG ; Hang up the phone before doing this CALL UNPATCH ; Undo BIOS patches ; ; Nobody there, or we are done. ; HANGUP: LXI SP,STACK ; Set up local stack CALL IMHANG ; Hangup phone (from twitdrop) XRA A ; Force next warmboot to user 0 STA 0004H ; And drive a: ; IF COMFILE CALL LODCOM ; Load the .COM file ENDIF ; ; ; Give summary and initialize for next call ; HANGUP1: IF CLRSCR AND CLRB4 LXI H,CLRSEQ CALL PRINTL ; Clear local crt screen ENDIF ; IF NO25TH OR MBBS LXI H,LFMSG CALL PRINTL LXI H,LCDATA CALL PRINTL ; Show sysop who was just on LXI H,LCFILL LXI D,LCDATA MVI B,78 CALL MOVE ; Put filler msg into lastcalr for now ENDIF ; IF TIMEON AND RTC AND NO25TH LXI H,TONMSG CALL PRINTL ; Show him how long last guy was on MVI A,' ' STA TONMSD STA TONMSD+1 STA TONMSD+2 ; Reset time buffer to spaces ENDIF ; CALL CALSUM ; Give sysop call summary ; IF CLRSCR AND (NOT CLRB4) LXI H,CLRSEQ CALL PRINTL ENDIF ; IF B3IM AND HS2400 CALL SET2400 ; Talk to the modem at its highest speed ENDIF ; IF B3IM AND HS1200 CALL SET1200 ENDIF ; IF B3IM AND HS300 CALL SET300 ENDIF ; CALL MDINIT ; Call modem initialization routine ; MVI A,0C3H ; Clear any traps left from .COM file STA 0 XRA A ; Clear any emulation modes STA MDMOFF ; Turn modem on STA WRTLOC ; Turn write flag off ; IF COMFILE LDA OPTION CPI 'E' ; Execute comfile locally? JNZ RINGWT ; No, continue CALL MDQUIT ; Fix modem so won't answer phone MVI A,0FFH STA MDMOFF ; Turn modem off STA WRTLOC ; And write flag JMP ANSW ; Skip this ENDIF ; ; Await ringing - check local keyboard for CTL-C exit request. Note: ; Must do input via BDOS because CBIOS patches are not done until the ; call comes in. ; RINGWT: CALL UCSTS ANI 7FH ; Strip parity bit CPI 'C'-40H ; CTL-C? CZ USRCHK ; Check for exit CALL CKFUNC ; Check for function keys ; IF MDMRNG AND NOT B3IM CALL MDRING ; Have a modem that MUST have ring signal JZ RINGWT CALL MDANSW ; Answer phone ; MVI B,CFRST*10 ; Set for 'CFRST' seconds WTCLP: CALL DELAY ; Wait .1 second CALL MDCARCK ; Check for carrier JNZ GOTCR ; We got carrier DCR B JNZ WTCLP ; Is our time up? (no..wait) JMP HANGUP ; Yes, time is up..go wait for another ring ; GOTCR EQU $ ; Carrier present ENDIF ; IF B3IM CALL IMRING ; Check for ring, answer phone, etc. JZ RINGWT ENDIF ; IF NOT (B3IM OR MDMRNG) CALL MDCARCK ; Modem has no ring signal, check for carrier JZ RINGWT ; Nope, loop ENDIF ; ;----------------------------------------------------------------------- ; ; Answer routine ; ANSW: CALL BDCHEK ; IF ZCPR2 OR ZCPR3 ; Only when using ZCPR w/secure mode XRA A ; When running ZCPR for your CCP. STA WHEEL ; Answer the phone in non-wheel mode ENDIF ; ZCPR OR ZCPR3 ; IF (NOT USEZCPR) AND (ZCPR2 OR ZCPR3) MVI A,MAXUSR ; Reset maximum user area STA MXUSR ; Set it in bye INR A ; Bump it STA MAXUSER ; Set it in ZCPR MVI A,MAXDRV ; Reset maximum drive STA MXDRV DCR A STA MAXDRIV ENDIF ; (NOT USEZCPR) AND (ZCPR2 OR ZCPR3) ; IF CHGPATH ; If external ZCPR path LXI H,REMPATH ; Source=remote path LXI D,EXTPATH ; Dest=external path at 0040H MVI B,LREMP ; Length of remote path CALL MOVE ENDIF ; CHGPATH ; XRA A ; Make sure line feeds are on again STA LFEEDS STA NULLS ; Set nulls to 0 before asking question STA MXTIME ; Turn off time check STA NULTRY ; Reset Nulls question counter STA CDOFF ; Limit for waiting for c/r STA FKATTN ; Reset attention character ; MVI A,TOVALUE ; Reset timeout count STA TOVAL ; IF NO25TH OR MBBS MVI A,' ' ; Clear the LC buffer STA LCDATA ENDIF ; IF NOT (NO25TH OR MBBS) XRA A ; Tell the system there's no LC buffer STA LCDATA ENDIF ; IF COMFILE LDA OPTION CPI 'E' JZ WELCOME ; Skip this if running local ENDIF ; LXI H,CWCAR ; Get # of attempts INR M ; And add one ; IF B3IM JMP WELCOME ; Skip the old fashion CR detect method ENDIF ; IF NOT B3IM ANSWA: CALL SET300 MVI A,BP300 ; Poke in MSPEED value STA MSPEED CALL MDINP ; Clear garbage characters CALL MDINP ; ; Now test input for baud rate - FIRST, check for 300 baud ; ANSWB: CALL PATCH ; Patch jump table ENDIF ; IF PRGRSS AND (NOT B3IM) LXI H,MSG30 CALL PRINTL ; Print locally ENDIF ; IF NOT B3IM CALL TSTBAUD ; See if 300 baud JZ WELCOME ; Yes, exit ENDIF ; ; ; Now check for 1200 bps ; IF PRGRSS AND (NOT B3IM) AND (HS1200 OR HS2400) LXI H,MSG12 CALL PRINTL ; Print locally ENDIF ; IF (NOT B3IM) AND (HS1200 OR HS2400) CALL SET1200 ; Now check 1200 bps JNZ ANS0 MVI A,BP1200 ; Set the MSPEED pointer STA MSPEED CALL MDINP ; Clear garbage CALL TSTBAUD ; Check baud rate JZ WELCOME ENDIF ; ANS0: IF PRGRSS AND (NOT B3IM) AND HS2400 LXI H,MSG24 CALL PRINTL ; Print locally ENDIF ; IF (NOT B3IM) AND HS2400 CALL SET2400 ; Check for 2400 baud JNZ BADDO ; Start over MVI A,BP2400 ; Set speed indicator STA MSPEED CALL MDINP ; Clear garbage CALL TSTBAUD ; Check it JZ WELCOME ENDIF ; IF (NOT B3IM) BADDO: CALL UNPATCH ; Restore original jump table JMP ANSWA ; Test more - invalid baud rate ENDIF ; ; end of answer routine ;----------------------------------------------------------------------- ; ; Fix BDOS vector to point to BYE ; BDCHEK: PUSH H ; To make truly universal, this DB LXIH ; Program always re-stores the BDOS ; BDADDR: DW 0000H ; Pointer at 6 and 7 set up location for SHLD 6 ; Beginning address of BYE POP H ; At every chance. RET ; ;----------------------------------------------------------------------- ; ; Common routine to check for carrier lost - called from console out ; CHECK: IF MINICK LDA IOBYTE ; Get IOBYTE ANI 80H ; Test for disk update RNZ ; Busy, wait until done ENDIF ; IF RBBSCK OR MBBS LDA WRTLOC ; Get write in progress flag ORA A RNZ ; Busy, wait until done ENDIF ; LDA MDMOFF ORA A ; Know modem off? RNZ ; Yes, skip this CALL CARCK ; See if carrier still on RNC ; All ok ; ; Carrier is lost. Type message so local console shows the reason. ; Come here on bad password. ; BADPASS:LXI SP,STACK ; Ensure valid stack MVI A,0FFH ; Turn off modem I/O STA MDMOFF LXI H,CLMSG ; Carrier lost message CALL PRINTL ; Send this Message ; DROPCAR:LXI SP,STACK CALL UNPATCH ; Restore original BIOS jump table XRA A ; Clear out carrier lost flag STA MDMOFF STA MXTIME ; Reset time ; IF EXFILE MVI C,SETUSR ; Select user area for EXITFILE MVI E,EXUSR CALL BDOS MVI C,SELDSK ; Select default drive for EXITFILE MVI E,EXDRV-'A' CALL BDOS CALL LODEX CPI '*' ; Test that file was really loaded JNZ 100H ; EXITFIL was't loaded, so run it ENDIF ; CALL UNPATCH JMP HANGUP ; ; ;----------------------------------------------------------------------- ; ; Function key routines ; CKFUNC: PUSH PSW XRA A STA FKATTN ; We're doing the function key now... POP PSW CPI ATTNCH ; Is it attention character? RZ ; Return with it in buffer ANI 01FH ; Make key control-code ORI 040H ; Make key upper case letter ; IF NO25TH OR MBBS CPI WHOKEY JZ WHOSIT ; Display last caller data ENDIF ; IF TIMEON AND RTC CPI TIMEKEY JZ DTIME ; Case running local, allow debug CPI ULTMKEY ; Set unlimited time-on system JZ UTIME ENDIF ; CPI ZCREEN JZ CLEARIT ; Sysop wants to clear his screen ; CPI BELLKEY JZ BELLTOG ; Toggle bell on/off ; MOV B,A PUSH B CALL MDCARCK ; See if carrier is on, because POP B MOV A,B RZ ; The following keys are useless without it. ; CPI BLNKKEY ; Turn off caller's output for a moment? JZ BLNKTOG ; (this is a toggle) CPI SYSDKEY JZ SYSDOWN ; Tell caller system is going down CPI TWITKEY JZ DROPCAR ; Hang up on the twit CPI MSGKEY RNZ ; ; Message from Sysop ; LXI H,MFSMSG ; SYSOP message CALL PRINTB ; Tell caller you want to say something ; SYSML: CALL VCONIN ; Get key from sysop CPI 'C'-'@' ; If ^C, exit loop JZ SYSMX MOV C,A ; Else echo to console and modem PUSH PSW CALL MOUTPUT POP PSW CPI 'H'-'@' ; If BS, do BS/SP/BS JZ SYSMBS CPI CR ; If CR, do CRLF JZ SYSMCR JMP SYSML ; SYSMCR: MVI C,LF ; Do linefeed after CR JMP SYSECH ; SYSMBS: MVI C,' ' CALL MOUTPUT MVI C,'H'-'@' ; SYSECH: CALL MOUTPUT JMP SYSML ; SYSMX: MVI C,CR ; Do crlf CALL MOUTPUT MVI C,LF CALL MOUTPUT MVI A,'H'-'@' ; Return with bs for buffer RET ; ; System Going down ; SYSDOWN:LXI H,SGDMSG ; System going down message CALL PRINTB ; Send this message ; IF TIMEON AND RTC CALL TCHECK ; Calculate current time-on-system LDA TON ; Fetch it ADI DOWNMIN ; Give him this much longer STA MXTIME ; And BYE will log him off ENDIF ; TIMEON AND RTC ; MVI A,'H'-'@' ; Return with bs for buffer RET ; ; Toggle bell ; BELLTOG:LDA BELLON ; Get bell status ORA A MVI A,0FFH ; Prepare for on LXI H,BELMON JZ BELT1 ; Go turn bell on XRA A ; Else turn bell off LXI H,BELMOFF ; BELT1: STA BELLON CALL PRINTL ; Print status message locally MVI A,'H'-'@' ; Return with bs for buffer RET ; ; Toggle blankout ; BLNKTOG:LDA MDMOFF ORA A ; If zero, make 0FFH MVI A,0FFH ; (we do not use CMA, because MDMOFF LXI H,SCRMOFF JZ BLNKT1 ; Could equal a different value like 1) XRA A ; If not zero, make it zero LXI H,SCRMON BLNKT1: STA MDMOFF CALL PRINTL MVI A,'H'-'@' ; Return with bs for buffer RET ; ; Who's on the system? ; IF NO25TH OR MBBS WHOSIT: LXI H,CRMSG ; Turn up a fresh line CALL PRINTL LXI H,LCDATA CALL PRINTL ; Show sysop lastcaller data LXI H,CRMSG CALL PRINTL ; New line for neatness MVI A,'H'-'@' ; Return with bs for buffer RET ENDIF ; ; Display time ; IF TIMEON AND RTC DTIME: CALL TCHECK LXI H,LFMSG CALL PRINTL LXI H,TONMSG CALL PRINTL ; Print time on LXI H,LFMSG CALL PRINTL MVI A,'H'-'@' ; Return with bs for buffer RET ; ; Set unlimited time on system ; UTIME: XRA A ; Set MAXTIME to 0 STA MXTIME LXI H,UTIMEM ; Print message CALL PRINTL MVI A,'H'-'@' RET ENDIF ; ; Clear local screen ; CLEARIT:LXI H,CLRSEQ CALL PRINTL ; Clear local screen MVI A,'H'-'@' RET ; BS for buffer ; ;----------------------------------------------------------------------- ; ; BYE RSX interceptor ; REALBD: JMP 0 ; Will be filled in to point to REAL bdos ; BYERSX: MVI A,HICMD ; [trackable by CBF RSX handler] CMP C ; > than HICMD? JC REALBD ; Yes, go to real-BDOS MVI A,SETUSR ; BDOS user code? CMP C JZ TSTUSR ; Yes, so do our special thing MVI A,LOCMD-1 ; Less than lowest RSX command? CMP C JNC REALBD ; Go do standard BDOS call ; ; Ok, it's one of our commands, sigh let's get to work ; MOV A,C SUI LOCMD ;commands now range from 0..hicmd-locmd 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 ;modem input status 61 JMP MDOUTST ;modem output status 62 JMP MDOUTP ;modem output character (raw) 63 JMP MDINP ;modem input character (raw) 64 JMP MDCARCK ;modem carrier check 65 JMP VCONSTAT ;console input status 66 JMP CONIN ;console input character (loop) 67 JMP RCONOT ;console output character (loop) 68 JMP RMXDRV ;set maximum drive 69 JMP RMXUSR ;set maximum user area 70 JMP RMTOUT ;set timeout value 71 JMP RMNULL ;set nulls 72 JMP RMULC ;set upper/lower case flag 73 JMP RMLFM ;set line feed mask 74 JMP RMWRT ;set writeloc 75 JMP RMHDR ;set hardlog copy flag 76 JMP RMOFF ;set modemoff flag 77 JMP RMBELL ;set console bell flag 78 JMP RMRTC ;return RTC buffer area 79 JMP RMLCBF ;return LC buffer area 80 JMP RMMXT ;set maxmimum time on system 81 JMP RMLTIM ;set login time 82 JMP RMTOS ;print tos message (on both consoles) 83 ; ; BYE existance test ; TSTUSR: MOV A,E ;Get E register value CPI 241 ;Was E = 241? JNZ REALBD ;nope, was for BDOS MVI A,77 ;was for us, say we're alive RET ; RCONOT: MOV C,E ;Get byte to send JMP VCONOUT ; RMXDRV: LXI H,MXDRV ;Set/get maximum drive JMP SETGET1 ; RMXUSR: LXI H,MXUSR ;Set/get maximum user area JMP SETGET1 ; RMNULL: LXI H,NULLS ;Set/get nulls JMP SETGET1 ; RMTOUT: LXI H,TOVAL ;Set/get timeout value JMP SETGET1 ; RMULC: LXI H,ULCSW ;Set/get upper-lowercase flag JMP SETGET1 ; RMLFM: LXI H,LFEEDS ;Set/get line-feed mask JMP SETGET2 ; RMHDR: LXI H,HARDON ;Set/get hard-log JMP SETGET2 ; RMWRT: LXI H,WRTLOC ;Set/get RBBS WRTLOC flag JMP SETGET2 ; RMOFF: LXI H,MDMOFF ;Set/get modem-off flag JMP SETGET2 ; RMBELL: LXI H,BELLON ;Set/get console-bell flag JMP SETGET2 ; RMRTC: IF TIMEON AND RTC CALL TCHECK ; Set time on system & rtc buffer ENDIF ; IF RTC AND NOT TIMEON ; Set rtc buffer CALL TIME ENDIF ; LXI H,RTCBUF ;return address of RTC buffer LDA TON ;and time on system in A RET ; RMLCBF: LXI H,LCDATA ;return address of LC data buffer RET ; RMMXT: LXI H,MXTIME ;Set/get maximum time online JMP SETGET1 ; RMLTIM: STA LMIN ;Set login time MOV A,D STA LHOUR RET ; RMTOS: IF TIMEON AND RTC ;Only do this if we can..otherwise RET CALL TCHECK ;Set time in message LXI H,TONMSG CALL PRINTB ;Print it ENDIF ; TIMEON AND RTC 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 SGET2 ;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 ; SGET2: MOV A,M ;return with current value in A RET ; ;----------------------------------------------------------------------- ; CONIN: PUSH B PUSH D PUSH H CALL VCONIN ; CPI ATTNCH JNZ CON1 ; If not attention character LDA FKATTN ORA A MVI A,ATTNCH JNZ CON2 ; MVI A,0FFH ; Set special flag STA FKATTN MVI A,'H'-'@' ; Return a ^H JMP CON2 ; CON1: MOV B,A ; Save character in B LDA FKATTN ; If special key last sent, then check fkeys ORA A MOV A,B ; restore character CNZ CKFUNC ; CON2: POP H POP D POP B RET ; ;----------------------------------------------------------------------- ; CONOUT: PUSH B PUSH D PUSH H CALL VCONOUT POP H POP D POP B RET ; ;----------------------------------------------------------------------- ; CONSTAT:PUSH B PUSH D PUSH H CALL VCONSTAT POP H POP D POP B RET ; ;----------------------------------------------------------------------- ; ; .1 sec delay routine ; DELAY: PUSH B LXI B,4167*MHZ ; Timing constant * clock MHz ; DELAY1: DCX B MOV A,B ORA C JNZ DELAY1 POP B RET ; ; 1 millisecond delay routine ; KDELAY: PUSH B LXI B,42*MHZ ; Timing constant * clock MHz JMP DELAY1 ; ;----------------------------------------------------------------------- ; ; Here to exit to CP/M, first reset the Port/Modem to default status ; EXCPM: CALL MDQUIT ; Return Port/Modem to default settings ; LHLD REALBD+1 ; Get real bdos vector SHLD 6 ; Save it so CP/M doen't crash ; IF ZCPR2 OR ZCPR3 MVI A,0FFH STA WHEEL ; Restore wheel byte for SYSOP MVI A,SYSUSR+1 STA MAXUSER ; And MAXUSR MVI A,SYSDRV-1 STA MAXDRIV ; And MAXDRIV ENDIF ; ZCPR2 OR ZCPR3 ; IF CHGPATH ; If external zcpr path LXI H,SYSPATH ; Source=SYSOP's path LXI D,EXTPATH ; Dest=external path at 0040H MVI B,LSYSP ; Length of new path CALL MOVE ENDIF ; CHGPATH ; IF ZCPR3 CALL DOZ3 ; ZCPR3 re-initialization ENDIF ; ZCPR3 ; LHLD BEGOBJ+1 SHLD BDOS+1 ; Some systems do not restore this on warmboot JMP 0000H ; Warm boot CP/M ; ; ZCPR3 command line buffer, shell stack, TCAP stuff ; IF ZCPR3 DOZ3: LHLD Z3CL ; Z3CL is the address of the MCLB MVI M,0 ; ; Command line done, now do shell stack ; LXI H,SHSTK ; SHSTK is the addr of the Shell Stack CALL ZERO128 ; ; Now initialize TCAP ; ; LXI H,Z3ENV+128 ; Z3ENV is the address of the Environ- ; CALL ZERO128 ; Ment Descriptor...the TCAP is the ; Second 128 bytes ; ; Also clean up message buffers ; LXI H,Z3MSG ; Z3MSG is the addr of the msg buffers MVI B,80 CALL ZEROM RET ; ; Routine to zero memory blocks ; ZERO128:MVI B,128 ; ZEROM: MVI M,0 INX H DCR B JNZ ZEROM RET ENDIF ; ZCPR3 ; ;----------------------------------------------------------------------- ; ; Loss of carrier test and drive/user validation ; CARCK: LDA MDMOFF ORA A ; Known loss? JNZ CARCK2 ; Yes, allow d/u check locally CALL MDCARCK ; Carrier there? JNZ CARCK2 ; Yep, go onto other checks... PUSH B ; Preserve so we can use it MVI B,CLOSS*10 ; Set for 'CLOSS' seconds ; CARLP: CALL DELAY ; Wait .1 seconds CALL MDCARCK ; Check for carrier MOV A,B ; Get count back in a POP B ; Fix stack in case all is ok JNZ CARCK2 ; Got carrier, continue on DCR A ; Count time down STC ; In case this is the end of 'time' RZ ; Return if timed out PUSH B ; Preserve 'BC' MOV B,A ; Get counter value in 'B' JMP CARLP ; Keep checking ; ; Now test drive #'s and (if CP/M 2.x) user #'s to insure that maximums ; are not exceeded. ; CARCK2: IF USEZCPR AND (ZCPR2 OR ZCPR3) LDA MAXDRIV INR A STA MXDRV LDA MAXUSER ; Get it from ZCPR/ZCMD DCR A ; Drop it one STA MXUSR ; Save it in bye ENDIF ; USEZCPR AND (ZCPR2 OR ZCPR3) ; IF (NOT USEZCPR) AND (ZCPR2 OR ZCPR3) LDA MXDRV ; Older versions did not do this if DCR A ; Wheel was set -- BAD KARMA STA MAXDRIV LDA MXUSR ; Get it from BYE INR A ; Bump it STA MAXUSER ; Save it in ZCPR ENDIF ; (NOT USEZCPR) AND (ZCPR2 OR ZCPR3) ; LDA 0004H ; Check disk/user # ANI 0FH ; Isolate drive PUSH H ; Save 'HL' LXI H,MXDRV ; Point to allowed # of drives CMP M ; Valid drive? JC CARCK3 ; Yes, skip this junk LDA 0004H ; Get whole login byte ANI 0F0H ; Retain user # & force drive to A: STA 0004H ; Update login byte LXI H,IDMSG ; Incorrect Drive Message CALL PRINTB ; Tell user what he did JMP 0000H ; Warm boot ; ; Drives were ok, check user areas ; CARCK3: LDA 0004H ; Get login byte ANI 0F0H ; Isolate user # RRC ; Move to low bits RRC RRC RRC LXI H,MXUSR ; Point to maximum user number CMP M ; Valid user #? JC CARCK4 ; Yes, don't change JZ CARCK4 LDA 0004H ; Get login byte again ANI 0FH ; Keep drive, zero user area STA 0004H ; Update login byte LXI H,IUMSG ; Invalid User message CALL PRINTB ; Tell him what happened JMP 0000H ; Warm boot ; CARCK4: POP H ; Restore 'HL' ORA A RET ; ;----------------------------------------------------------------------- ; ; print routines ; ; The following code has been modified to accomodate the automatic ; loader. (The loader may modify a constant, so all messages have been ; place been placed at the end of the program and just moved to high ; memory.) ; ; Print on both consoles ** USE ONLY IF IN PATCHED MODE ** ; PRINTB: PUSH B ; Save BC PUSH PSW ; And status regs PRBL: MOV C,M ; Get character CALL MOUTPUT ; Output it INX H ; Point to next character MOV A,M ; Test for end of message ORA A JNZ PRBL POP PSW ; Restore status regs POP B ; Restore BC RET ; ; Print locally only ; PRINTL: PUSH B ; Save BC PUSH PSW ; And status regs PRLL: MOV C,M ; Get character CALL CONOUT ; Output it INX H ; Point to next character MOV A,M ; Test for end of message ORA A JNZ PRLL POP PSW ; Restore status regs POP B ; Restore BC RET ; ;----------------------------------------------------------------------- ; LISTOUT:PUSH B PUSH D PUSH H PUSH PSW CALL VLISTOUT POP PSW POP H POP D POP B RET ; ;----------------------------------------------------------------------- ; .COM file routine ; ; Routine to load the .COM file ; LODCOM: IF COMFILE MVI C,SELDSK MVI E,COMDRV-'A' ; Select drive with .COM file on CALL BDOS MVI C,SETUSR ; Set CP/M user area function MVI E,COMUSR ; Location of our COMFILE CALL BDOS LXI H,COMFCB SHLD CURRFCB XRA A ; Initialize FCB STA COMFCB LXI H,COMFCB+12 MVI B,21 CALL ZLOOP LXI D,COMFCB CALL OPENFIL JZ ABORT JMP LOADFIL ENDIF ; COMFILE ; LODEX: IF EXFILE LXI H,EXITFCB SHLD CURRFCB LXI H,EXITFCB+12 MVI B,21 CALL ZLOOP LXI D,EXITFCB CALL OPENFIL MVI A,'*' ; Do not try to run unloaded file RZ ; Cannot open file, finish BYE hangup ENDIF ; EXFILE ; ; Now load the file ; IF COMFILE OR EXFILE LOADFIL: LHLD 6 ; Get top of memory LXI D,-80H DAD D PUSH H ; Save on stack LXI D,80H ; TPA-80H LXI B,0 ; Keep a record counter PUSH B ; Save counter PUSH D ; And load address ; GLOOP: POP D ; Get TPA address LXI H,80H ; Point to next address to read to DAD D ; HL has the address POP B ; Increment the counter ; ; Check for load past top-of-memory ; POP D ; Get (top-of-memory) PUSH D ; Resave for next time MOV A,E ; Subtract: (top) - (address) SUB L MOV A,D ; Only the carry needed SBB H JNC SIZEOK ; CY=better MOVCPM LXI H,PTSMSG JMP ERRXIT ; SIZEOK: INX B PUSH B PUSH H ; Save TPA address XCHG ; Align registers MVI C,STDMA ; Tell BDOS where to put record CALL BDOS LHLD CURRFCB ; Point to aprropriate FCB XCHG MVI C,READ CALL BDOS ORA A JZ GLOOP ; A=0 if more to read POP B ; Unjunk stack POP B ; This is our counter POP H ; More junk on stack MOV A,B ; Check for zero ORA C JZ ABORT ; We should have read something LXI D,80H ; We did, reset DMA to 80H MVI C,STDMA CALL BDOS LXI H,CFLMSG CALL PRINTL RET ; 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 PRINTL JMP EXCPM ; Warm boot ENDIF ; COMFILE OR EXFILE ; ; end of .COM file routine ;----------------------------------------------------------------------- ; ; Boot trap - becomes disconnect if JMP at 0 has been altered ; MBOOT: IF COMFILE LDA OPTION CPI 'E' ; Return from local test? JNZ MBOOT1 ; No, continue MVI A,' ' STA FCB+1 ; Fool system CALL UNPATCH ; Yes, restore JMP START0 ; And start fresh MBOOT1: ENDIF ; COMFILE ; LDA 0 ; Look at opcode CPI 0C3H ; Is it still a jmp? JNZ NOSLASH ; No, so say bye bye... CALL BDCHEK ; IF (NO25TH OR MBBS) AND NEEDLC LDA LCDATA ; See if lastcalr has been read CPI ' ' ; Or data poked by a BBS, like MBBS JNZ NO25EX ; Yes, skip this XRA A ; Else, let's pick up the lastcalr file STA FCBRNO ; Prepare FCB for lastcalr LXI H,LCNAME LXI D,FCB MVI B,13 CALL MOVE ; Move rest of FCB MVI C,0DH ; Reset disk and CALL BDOS ; Set for default buffer MVI C,SELDSK MVI E,LCDRV-'A' CALL BDOS ; Set drive MVI C,SETUSR MVI E,LCUSR CALL BDOS ; And user LXI D,FCB CALL OPENFIL ; Open it LXI H,LCMSG1 CZ PRINTL ; Error msg JZ NO25EX ; No file available, exit LXI D,FCB MVI C,READ CALL BDOS ; Read 1 record max LXI H,LCMSG1 ORA A CNZ PRINTL ; Say error LXI H,80H LXI D,LCDATA MVI B,78 CALL MOVE ; Move data into bye's internal buffer MVI B,78 ; We will display 78 chars max LXI H,LCDATA NO25RD: MOV A,M CPI 'Z'-'@' ; EOF? JZ NO25ZD CPI ',' CZ NO25SP ; Convert commas and semicolons to spaces CPI ';' CZ NO25SP CPI CR CZ NO25SP ; CRLF's become spaces too. CPI LF CZ NO25SP DCR B INX H ; Get next byte JMP NO25RD NO25ZD: XRA A MOV M,A ; Set terminator for print routine STA 0004H ; Reset drive/user area to 0 ENDIF ; (NO25TH OR MBBS) AND NEEDLC ; IF NO25TH OR MBBS NO25EX: CALL WHOSIT ; Some BBSs will always poke the buffer ENDIF ; ; Special warm-boot routine - print a message or something - even run a ; program if you want to!!! ; WMBMSGPRT: IF WBRTN PUSH B PUSH D PUSH H ENDIF ; IF PRNTWB LXI H,WBMSG CALL PRINTB ; Print the following message: ENDIF ; IF WBRTN POP H POP D POP B ENDIF ; IF RTC AND TIMEON AND TOSWB AND (ZCPR2 OR ZCPR3) LDA WHEEL ; Don't print message if guy is wheel ORA A JNZ VWARMBT ; No, go do warm boot ENDIF ; IF RTC AND TIMEON AND TOSWB CALL TCHECK LXI H,TONMSG CALL PRINTB ; Display timeon ENDIF ; JMP VWARMBT ; Go do a warm boot ; ; Reset lastcaller buffer to nil ; IF NO25TH OR MBBS NO25SP: MVI A,' ' ; Space MOV M,A ; To lcdata RET ENDIF ; ;----------------------------------------------------------------------- ; ; Modem input function, checks local console first ; MINPUT: CALL BDCHEK LDA TOVAL ; Get # of minutes before timeout ; MINP0: STA TOCNTM ; Set minutes counter PUSH H LXI H,42000 ; Initialize one minute timeout counter SHLD TOCNT POP H ; MINP1: CALL MSTAT ; Anything? ORA A JNZ MINP2 CALL KDELAY ; Wait 1 ms PUSH H LHLD TOCNT ; Knock down timeout counter DCX H SHLD TOCNT MOV A,H ORA L POP H JNZ MINP1 ; Still time left, keep trying LDA TOCNTM ; Count off last minute DCR A JNZ MINP0 ; Go back if time left ; TMOUT: LXI H,ITOMSG CALL PRINTB JMP NOSLASH ; MINP2: CALL CONSTAT ; Check local console ORA A ; Character? JNZ CONIN ; Yes, read it & return ; ; Local console wasn't ready, so read modem ; CALL MDINP ANI 07Fh ; Delete parity ; MOV B,A ; Save it LDA MDMOFF ORA A ; Is remote blanked? MVI A,0 ; Null, just in case RNZ MOV A,B ; Restore character ; IF ZCPR2 OR ZCPR3 MOV B,A ; Save byte in B LDA WHEEL ORA A MOV A,B ; Get character back JNZ MINP2A ; It's a wheel, don't trap ^P ENDIF ; ZCPR2 OR ZCPR3 ; CPI 'P'-'@' ; Is it a ^P? JNZ MINP2A ; No, don't do anything MVI A,'H'-'@' ; Make it a bs ; MINP2A: 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 MINP3 CPI CR JNZ NOLOG ; MINP3: MOV C,A ; Move to reg "C" CALL LISTOUT ; Echo on printer CPI CR JNZ NOLOG ; Return needs linefeed MVI C,LF CALL LISTOUT ; So send it MVI A,CR ; Get back CR ENDIF ; HARDLOG ; NOLOG: CPI 'C'-'@' ; Is it ^C? RNZ ; No, pass it through LDA 0 ; See if warm boot disabled CPI 0C3H ; Jump means warm boot ok MVI A,3 ; So return with a ^C RZ MVI A,CTRLC ; Else convert to different character RET ; ;----------------------------------------------------------------------- ; ; Modem output function ; MOUTPUT:CALL BDCHEK ; IF RTC MOV A,C ; Only update time buffer when we send a CR. CPI CR ; so it speeds things up. JNZ NOTCHK ENDIF ; IF RTC AND (NOT TIMEON) CALL TIME ; Just update time buffer if no autologout ENDIF ; RTC AND (NOT TIMEON) ; IF TIMEON AND RTC CALL TCHECK ; Update/check clock and timeon ENDIF ; TIMEON AND RTC ; ; If we already know carrier is lost, do not check for it again or loop ; trying to output. ; NOTCHK: LDA MDMOFF ; Known loss of carrier? ORA A PUSH PSW CNZ CONOUT ; Output to local only POP PSW RNZ ; Then exit ; MOUTA: CALL CHECK ; Carrier still on? CALL MDOUTST ; Check modem output status JZ MOUTA MOV A,C ; Get character ANI 7FH ; Strip parity bit ; CPI 60H ; Check for lower case JC MOUTP2 ; Skip if not lower case CPI 7FH ; Check for rubout JZ MOUTP2 PUSH H LXI H,ULCSW ; Subtract either 20H or nothing SUB M POP H MOV C,A ; Force on local as well as remote ; MOUTP2: CPI LF ; We have a toggle for line feeds JNZ MOUTP3 ; Nope, not a LF LDA LFEEDS ; Yes, see if we can send it... ORA A ; Set flags MVI A,0 ; Prepare with a null JNZ MOUTP3 ; Nope, don't (instead, send a null) MVI A,LF ; Yes, it's ok to send the line feed ; MOUTP3: CALL MDOUTP ; Output character to modem PUSH PSW ; Save character CPI 'G'-'@' ; Is it a bell? JNZ NOTBEL LDA BELLON ; Get flag ORA A JZ ISBELL ; NOTBEL: CALL CONOUT ; Send to regular BIOS ISBELL: POP PSW ; Get character again ; ; Check for nulls ; CPI LF ; Time for nulls? RNZ ; No, return ; ; Send nulls if requested ; LDA NULLS ; Get count ORA A ; Any? RZ ; No PUSH B MOV B,A ; Save count ; NULLP: CALL MDOUTST ; Modem ready? JZ NULLP XRA A ; 0 is a null CALL MDOUTP ; Type a null DCR B ; Another? JNZ NULLP ; Yes, loop POP B RET ; ;----------------------------------------------------------------------- ; ; Move (HL) to (DE), length in (B) ; MOVE: MOV A,M ; Get a byte STAX D ; Put at new home INX D ; Bump pointers INX H DCR B ; Decrement byte count JNZ MOVE ; If more, do it RET ; If not, return ; ;----------------------------------------------------------------------- ; ; Keyboard/modem status test routine ; MSTAT: CALL BDCHEK ; Set 6 to safety CALL CHECK ; Check for carrier lost CALL CONSTAT ; Get local status ORA A RNZ ; Return if local character CALL MDINST ; Get modem input status RET ; ;----------------------------------------------------------------------- ; ; This is the jmp table which is copied on top of the one pointed to by ; location 1 in CP/M. ; NEWJTBL:JMP MCBOOT ; Cold boot JMP MBOOT ; Warm boot JMP MSTAT ; Modem status test JMP MINPUT ; Modem input routine JMP MOUTPUT ; Modem output routine ; IF NOT (HARDLOG OR PRINTER) JMP MOUTPUT ; Modem = list device ENDIF ; NOT (HARDLOG OR PRINTER) ; IF HARDLOG OR PRINTER JMP LISTOUT ; Jump to list output routine ENDIF ; HARDLOG OR PRINTER ; ;----------------------------------------------------------------------- ; NWBCALL: IF LOSER CALL WMSTRT ; Warm boot disk read CALL PATCH ; Fix BIOS again after WMSTRT ENDIF ; LOSER ; CALL BDCHEK RET ; ;----------------------------------------------------------------------- ; ; Patch in the new JMP table (saving the old) ; PATCH: LDA PTFLAG ORA A JNZ SKPTH ; Save the original jump table only once CALL TBLADDR ; HL= CP/M BIOS jump table LXI D,VCOLDBT ; Point to save location CALL MOVE ; Move it LHLD VCONOUT+1 ; Get the original CONOUT address SHLD COVECT ; Store for use with XMODEM programs ; ; Now move the new JMP table to CP/M ; SKPTH: CALL TBLADDR ; HL= CP/M BIOS jump table XCHG ; Move it to 'DE' LXI H,NEWJTBL ; Point to new jump table CALL MOVE ; Move it MVI A,255 STA PTFLAG ; IF LOSER LXI H,NWBCALL ; Set new warm boot call SHLD WBCALL+1 ; Store the new address ENDIF ; LOSER ; 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 MVI B,18 ; Move all jumps RET ; ;----------------------------------------------------------------------- ; ; PRNLOG is called to print out the BYE version # and USRLOG info. It ; can be called from outside the program, using the vector after MCBOOT. ; PRNLOG: LXI H,VMSG CALL PRINTL CALL CALSUM RET ; CALSUM: LDA CWCAR ; Get 8 bit number LXI H,ATMSN ; Address to store ascii CALL DEC8 ; And convert to ascii CALL MDCARCK ; If carrier is on, wheel byte (sysop) calling LXI H,ATMSG ; Print Callers with carrier detected CNZ PRINTB ; To both if sysop is on other end CZ PRINTL ; Or just local if between calls ; IF B3IM ; Print # of voice calls LDA VCNUM LXI H,VCMSN ; Put ascii here CALL DEC8 CALL MDCARCK LXI H,VCMSG CNZ PRINTB CZ PRINTL ENDIF ; B3IM ; IF PWRQD LDA NWPWD ; 8 bit counter LXI H,NWMSD ; Put ascii here CALL DEC8 CALL MDCARCK LXI H,NWMSG ; Print callers who knew password CNZ PRINTB CZ PRINTL ENDIF ; PWRQD ; LXI H,LFMSG CALL PRINTL ; Turn up a line RET ; End of call summary ; ;----------------------------------------------------------------------- ; ; Readbyte routine - used to read the welcome file ; IF WELFILE RDBYTE: MOV A,H ; Time to read? ORA A ; If at 100H, no read required JZ NORD ; ; Have to read a sector ; LXI D,FCB MVI C,READ CALL BDOS ORA A ; Ok? MVI A,1AH ; Fake up EOF RNZ ; Return EOF if bad LXI H,80H ; NORD: MOV A,M ; Get character INX H ; Point to next byte RET ENDIF ; WELFILE ; ;----------------------------------------------------------------------- ; ; TSTBAUD attempts to read a CR, LF or CTL-C and returns with zero flag ; if the character read is one of these three. ; IF NOT B3IM TSTBAUD:CALL MDCARCK ; Check carrier first JZ BADPASS ; Carrier is gone, start over LDA CDOFF INR A STA CDOFF CPI 60 ; Allow 1 minute for c/r detect JZ TMOUT ; Log him off MVI D,20 ; Check for 2 sec for current baud rate ; TSTB1: MVI B,1 ; At .1 sec intervals PUSH D CALL DELAY CALL MDINST ; See if character available ORA A JZ TSTB2 ; None yet CALL MDINP ; Yes, read the character ANI 7FH POP D ; Restore the stack JMP TSTB3 ; And see if it is right character ; TSTB2: POP D ; Restore DE DCR D ; And decrement the count MOV A,D ORA A ; 2 sec's up?? JNZ TSTB1 ; No, try again MVI A,0FFH ; Dummy character ; TSTB3: CPI CR ; If a CR RZ CPI LF ; If a LF RZ CPI 'C'-40H ; If a CTL-C RET ; Return with proper flags set ENDIF ; NOT B3IM ; ;----------------------------------------------------------------------- ; ; Get the console status when unpatched ; UCSTS: MVI C,DRECTIO ; Direct I/O call MVI E,255 ; Ask for input CALL BDOS ; A=0 if no character waiting RET ; ;----------------------------------------------------------------------- ; UNPATCH:CALL TBLADDR ; HL= CP/M BIOS jump table XCHG ; Move to DE LXI H,VCOLDBT ; Get saved table CALL MOVE ; Move original table back ; IF LOSER LXI H,WMSTRT ; Load old call location SHLD WBCALL+1 ; Restore old call ENDIF ; LOSER ; RET ; ;----------------------------------------------------------------------- ; USRCHK: CALL PRNLOG ; Give info LXI H,RS1MSG CALL PRINTL ; Prompt to resume waiting for ring ; PRNREL: CALL UCSTS ; Get reply ORA A JZ PRNREL ; Wait until answered ANI 05FH ; Make uppercase CPI 'E' ; Execute com file? JZ USRUN ; Yes CPI 'R' ; Is answer "r", for resume? JZ PRNRES ; Go do it if so JMP EXCPM ; PRNRES: LXI H,RS2MSG JMP PRINTL ; Resume via BDOS after message ; USRUN: MVI A,'E' STA FCB+1 ; Fake it JMP START0 ; For sysop ; ;----------------------------------------------------------------------- ; WELCOME routine (note no extent used) ; ; Welcome to the system ; WELCOME: IF ASKNULL AND NOT OXGATE LDA NULTRY ; How many times have we tried this? INR A STA NULTRY DCR A CPI MNULLS ; Exceeded his limit? JZ NULOFF ; Yes, log the turkey off LXI H,NULMSG ; Nulls message CALL PRINTB ; Send this message CALL MINPUT ; Get value MOV C,A ; To 'C' for output CALL MOUTPUT ; Echo character MOV A,C ; Restore value CPI '0' JC WELCOME ; Bad, retry CPI '9'+1 JNC WELCOME ; Bad, retry SUI '0' ; Make binary STA NULLS ; Save count ENDIF ; GETULC: LXI H,CRMSG ; Carriage Return, Line Feed CALL PRINTB ; Send this message ; IF RTC AND RSPEED XRA A ; Clear status LDA MSPEED ; See what speed the user is at SUI OKSPD ; Is it acceptable? JNC SPDOK ; Yes, continue CALL TIME ; Get current time MVI A,HOUR1 ; Start of prime-time ; SPD01: LXI H,CCHOUR ; Point at current hour CMP M ; Equal? JZ LOGOFF ; Yes, dump him INR A ; Check for CPI HOUR2 ; End of prime-time JZ SPDOK ; Not prime-time so let him on CPI 24 ; Past midnight? JNZ SPD01 ; No, continue XRA A ; Yes set to 00 hour JMP SPD01 ; And continue ; LOGOFF: LXI H,OFFMSG ; Point at logoff message CALL PRINTB ; And tell him why CALL DELAY ; Let message finish CALL DELAY ; Before dumping him JMP NOSLASH ; Then dump him off SPDOK: ENDIF ; IF RTC CALL TIME ; Read current time ENDIF ; IF RTC AND TIMEON LDA CCHOUR ; And set STA LHOUR ; The users LDA CCMIN ; Login STA LMIN ; Time for later use MVI A,MAXMIN ; Set number of minutes STA MXTIME ; So we know it's ok to check time ENDIF ; ; Print the welcome file ; IF WELFILE LXI H,WELFILN ; Source LXI D,FCB ; Destination MVI B,13 ; Length CALL MOVE ; Move the name LXI D,80H ; Set DMA address to 80H MVI C,STDMA CALL BDOS MVI C,SETUSR ; Set user number for WELCOME file MVI E,WELUSR CALL BDOS ; ; Open the WELCOME file ; MVI C,SELDSK ; Select default drive for WELCOME file MVI E,WELDRV-'A' CALL BDOS LXI D,FCB MVI C,OPEN ; Open file 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 ; WELTYPE:CALL RDBYTE ; Get a byte CPI 'Z'-'@' ; EOF? JZ PASSINT ; Yes, done MOV C,A ; Setup for type CALL MOUTPUT ; Type the character CALL MSTAT ; Check for character typed ORA A JZ WELTYPE ; No, loop CALL MINPUT ; Yes, get character ANI 01FH ; Make it a control character CPI 'C'-'@' ; Did user type a CTL-C to end listing? JZ PASSINT CPI 'K'-'@' ; CTL-K to end listing? JZ PASSINT CPI 'S'-'@' ; CTL-S to delay listing? JNZ WELTYPE ; No, loop until EOF ; WAIT: CALL MSTAT ORA A ; Has another char been typed? JZ WAIT ; No, wait CALL MINPUT ; Yes, check character ANI 01FH ; Make it a control character CPI 'C'-'@' ; Did user type a CTL-C to end listing? JZ PASSINT CPI 'K'-'@' ; CTL-K to end listing? JNZ WELTYPE ; None of these, loop until EOF ENDIF ; WELFILE ; ; Get the password ; PASSINT: IF PWRQD MVI D,3 ; 3 tries at password PASSINP:LXI H,PWMSG ; Password message CALL PRINTB ; Send this message LXI H,PASSWD ; Point to password MVI E,0 ; No missed letters ; PWMLP: CALL MINPUT ; Get a character CPI 60H ; Lower case? JC NOTLC ; No, ANI 5FH ; Make upper case alpha ; NOTLC: PUSH PSW ; Save character input CPI 20H ; Is character a control code? JNC PWDIS ; Pass if displayable MVI C,'^' ; 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 PRINTB ; Send this message DCR D ; More tries? JNZ PASSINP ; Yes JMP NOSLASH ; No, go hang up ; ; Character matched in password ; PWMAT: INX H ; To next character CPI CR ; End? JNZ PWMLP ; No, loop ; ; End of password, any missed characters? ; MOV A,E ; Get flag ORA A JNZ PWNMAT ; Not right ; LXI H,NWPWD ; Get last value INR M ; And add one ENDIF ; PWRQD ; IF COMFILE MVI C,SELDSK ; Switch to .COM file drive MVI E,COMDRV-'A' CALL BDOS MVI C,SETUSR MVI E,COMUSR ; Switch to .COM file user area CALL BDOS MVI A,' ' ; Fool the system so that the .COM file STA FCB+1 ; Will see a space at FCB+1 for default JMP RUNCOM ; Execute the COM file ENDIF ; ; Everyone else gets .COM file ; RUNCOM: IF ZCPR3 AND COMFILE CALL DOZ3 ; ZCPR3 re-initialization ENDIF ; ZCPR3 and COMFILE ; IF COMFILE LDA OPTION CPI 'E' ; Executing locally? CNZ 100H ; No, skip this CALL PATCH ; So we run under bye CALL 100H ; Execute com file ENDIF ; COMFILE ; JMP 0000H ; Warm boot now for "normal" CP/M use ; NULOFF: LXI H,NOMSG ; Tell the turkey he failed CALL PRINTB JMP NOSLASH ; And log him off ; ; end of WELCOME routine ;----------------------------------------------------------------------- ; calculate user's elapsed time ; ; Calculate time on system. Log him off if =>MAXMIN unless WHEEL is on, ; or MXTIME=0. ; IF RTC AND TIMEON TCHECK: PUSH B PUSH D PUSH H CALL TIME ; Get current time LDA LHOUR ; (LHOUR)=log-in hour 0-23 CALL TCX60 ; Convert to minutes, results in (HL) LDA LMIN ; (LMIN)=log-in minutes, 0-59 LXI D,0 ; Clear (DE) MOV E,A ; (LMIN) to (DE) DAD D ; (HL)+(DE)=(HL) PUSH H ; Save log-in minutes on stack LDA CCHOUR ; (CCHOUR)=current hour, 0-23 LXI H,LHOUR ; Let's see if we crossed midnight SUB M JNC TCOK ; No, we're ok LDA CCHOUR ; Yes, let's add 24 ADI 24 STA CCHOUR ; Now we're ok TCOK: LDA CCHOUR ; (CCHOUR) is now bigger than (LHOUR) CALL TCX60 ; Convert it to minutes LDA CCMIN ; Current minutes, 0-59 LXI D,0 ; Clear (DE) MOV E,A ; CCMIN to (DE) DAD D ; (HL) now has current time in minutes POP D ; (DE) now has log-in time CALL TCDIF ; Get the difference, (HL)-(DE)=(HL) MVI A,' ' ; Clear out time buffer STA TONMSD STA TONMSD+1 STA TONMSD+2 MOV A,L ; Only save LSB, 0-255 is plenty STA TON ; And save it ; LXI H,TONMSD ; (A)=TON, (HL)=address to store ascii CALL DEC8 ; Convert timeon to ascii POP H POP D POP B LDA WHEEL ORA A ; Maybe he typed his password for user RNZ LDA MXTIME ; Get maximum time allowed ORA A ; If zero, MBBS says it's ok RZ ; For unlimited time on PUSH B MOV B,A ; Move it to 'B' LDA TON SUB B ; Subtract max time allowed POP B RC ; Still time left XRA A STA MXTIME ; Reset time flag LXI H,TIMEUP ; Time is up, inform user CALL PRINTB CALL DELAY ; Wait for msg to finish CALL DELAY JMP NOSLASH ; And log him off ; ; TCX60 will multiply (A)x60, results in (HL). ; TCX60: LXI H,0 ; (HL)=0 ORA A RZ ; If (A)=0, no x60 needed LXI D,60 ; Multiplier TCX61: DAD D ; X60 DCR A ; Done? JNZ TCX61 ; No RET ; ; TCDIF will subtract (DE) from (HL), results in (HL). ; (HL) normally has the larger number ; TCDIF: MOV A,L ; LSB of (HL) SUB E ; LSB of (DE) MOV L,A ; Back to L MOV A,H ; MSB of (HL) SBB D ; MSB of (DE) and carry flag MOV H,A ; (HL) now has difference RET ENDIF ; RTC AND TIMEON ; ; BCDBIN - convert BCD number to binary number ; Entry: A = BCD number ; Exit: A = binary number ; Destroys: nothing ; IF RTC AND BCD2BIN BCDBIN: PUSH D MOV E,A ; Save original byte ANI 15 MOV D,A ; Save low nibble MOV A,E ANI 240 ; Mask LSN RRC ; x2 MOV E,A RRC ; x4 RRC ; x8 ADD E ; x10 ADD D ; low nibble POP D RET ENDIF ; ; BINBCD - convert binary number to BCD ; Entry: A = binary number ; Exit: A = BCD number ; Destroys: nothing ; IF RTC AND BIN2BCD BINBCD: PUSH D MVI E,255 ; -1 BLP: INR E ; Increment tens counter SUI 10 ; Subtract 10 each pass JNC BLP ADI 10 ; Get back number MOV D,A MOV A,E RLC ; Shift over to MSN RLC RLC RLC ADD D ; Add in ones position POP D RET ENDIF ; ;----------------------------------------------------------------------- ; ; DEC8 will convert an 8 bit binary number in A to 3 ASCII bytes. ; HL points to the MSB location where the ASCII bytes will be stored. ; Leading zeros are suppressed, so store spaces in your buffer before calling. ; DEC8: PUSH B PUSH D MVI E,0 ; Leading zero flag MVI D,100 DEC81: MVI C,'0'-1 DEC82: INR C SUB D ; 100 or 10 JNC DEC82 ; Still + ADD D ; Now add it back MOV B,A ; Remainder MOV A,C ; Get 100/10 CPI '1' ; Zero? JNC DEC84 ; Yes MOV A,E ; Check flag ORA A ; Reset? MOV A,C ; Restore byte JZ DEC85 ; Leading zeros are skipped DEC84: MOV M,A ; Store it in buffer pointed at by HL INX H ; Increment storage location MVI E,0FFH ; Set zero flag DEC85: MOV A,D SUI 90 ; 100 to 10 MOV D,A MOV A,B ; Remainder JNC DEC81 ; Do it again ADI '0' ; Make ascii MOV M,A ; And store it POP D POP B RET ; ENDOBJ EQU $ ; end of main body of program ;----------------------------------------------------------------------- ; ; ------------------------------------------------ ; START B3IM COMMANDS (Set B3IM EQU YES to use this) ; ------------------------------------------------ ; IF B3IM B3ATA: DB 'ATA',CR,0 ; Answer the phone B3ATZ: DB 'ATZ',CR,0 ; Reset modem B3ESC: DB '+++',0 ; Escape sequence for command mode B3ATH: DB 'ATH',CR,0 ; Hangup phone ; ADDSTR: DW 0 ; Address of command string VCMSG: DB CR,LF,'Voice or no carrier calls: ' VCMSN: DB ' ',0 VCNUM: DB 0 ; Counter for voice calls ENDIF ; B3IM ; IF B3IM AND PRGRSS RCSHOW: DB '_',0 ; Will be stored by PRGRSS NOEMSG: DB CR,LF,'Echo error--will try again...',CR,LF,0 CMDERR: DB '--ERROR--your modem cannot execute the above command string-' DB '--Find out why..',CR,LF,0 ENDIF ; B3IM AND PRGRSS ; IF B3IM AND PRGRSS AND CALBAK CALMSG1:DB 'Now checking for voice or computer call...',0 CALMSG2:DB 'Waiting for call-back...',CR,LF,0 CALMSG3:DB CR,LF,'Timing out from voice call...',CR,LF,0 ENDIF ; IF B3IM B3INIT: DB 'AT' ; Attention ENDIF ; IF B3IM AND ECHO DB 'E1' ; Echo back characters sent to modem ENDIF ; IF B3IM AND (NOT ECHO) DB 'E0' ; Only Hayes needs echo verification ENDIF ; IF B3IM DB 'Q0' ; Send result codes DB 'V0' ; Terse mode ENDIF ; IF B3IM AND (NOT NOATA) DB 'S0=0' ; No auto-answer (we will use 'ATA') ENDIF ; IF B3IM AND NOATA DB 'S0=1' ; Will answer on first ring ENDIF ; IF B3IM AND (NOT ANCHOR) OR (NOT NODTR) DB 'S2=128' ; Non-printing ASCII vs "+++" ENDIF ; IF B3IM AND (NOT ANCHOR) DB 'M0' ; Speaker off DB 'S10=25' ; 2 1/2 sec wait after carrier loss to hang up ENDIF ; IF B3IM AND (NOT HS300) AND (NOT ANCHOR) DB 'X1' ; Extended response codes beyond '4' ENDIF ; IF B3IM DB CR,0 ; CR finishes command string B3USR: DB 'ATS0=0',CR,0 ; This helps the Password and S-100 ENDIF ; ; End of B3IM command strings ; --------------------------- ; ; messages ; IF PRGRSS AND (NOT B3IM) MSG30: DB '300 baud test',CR,LF,0 MSG12: DB '1200 baud test',CR,LF,0 MSG24: DB '2400 baud test',CR,LF,0 ENDIF ; ; ; Program version number message ; VMSG: DB CR,LF,'BYE',MAIN+'0' DB VERS/10+'0',VERS MOD 10+'0',' - ' DB MONTH/10+'0',MONTH MOD 10+'0','/' DB DAY/10+'0',DAY MOD 10+'0','/' DB YEAR/10+'0',YEAR MOD 10+'0',CR,LF,0 ; CLRSEQ: DB CLRCH1,CLRCH2,CLRCH3,CLRCH4,CLRCH5,CLRCH6,0 ; CDOFF: DB 0 OPTION: DB 0 ; IF RTC AND RSPEED OFFMSG: DB CR,LF,'Sorry! 1200 or 2400 baud only allowed 7PM-11PM' DB CR,LF,CR,LF,' Call back before/after 7-11PM Pacific' DB CR,LF,0 ENDIF ; IF RTC AND TIMEON TIMEUP: DB 7,7,CR,LF,CR,LF DB ' Your time is up - wait 24 hours to call back',CR,LF,0 TONMSG: DB CR,LF,'Time on system is ' TONMSD: DB ' minutes',CR,LF,0 ENDIF ; ; Real-Time clock buffer. ; Store BCD values into this area if RTC is YES. ; ; (NOTE: 99:99:99 INDICATES CLOCK IS NOT RUNNING OR NOT AVAILABLE) ; RTCBUF: DB 99H,99H,99H ; HH:MM:SS (BCD 24hr time) 00:00:00-23:59:59 DB 19H,85H,02H,31H ; YYYY/MM/DD (BCD ISO date) TON: DB 0 ; Time on system DB 0 ; Reserved for use with MBBS only CCHOUR: DB 0 ; Current hour (binary) CCMIN: DB 0 ; Current minute (binary) LHOUR: DB 0 ; Login hour LMIN: DB 0 ; Login minute ; ; Other Messages ; IF ASKNULL AND NOT OXGATE NULMSG: DB CR,LF,CR,CR,CR,CR,'Nulls, if needed, (0-9)? ',0 ENDIF ; CRMSG: DB CR,LF,CR,LF,0 NULTRY: DB 0 NOMSG: DB CR,LF,LF,'You have flunked the 0-9 IQ test...',CR,LF,LF DB 0 PTFLAG: DB 0 ; IF PRNTGB GBMSG: DB CR,LF,CR,CR,'Goodbye, call again...',CR,LF,CR,LF,0 ENDIF ; RS1MSG: IF COMFILE DB CR,LF,'Type "E" to execute COM file locally,' ENDIF ; DB CR,LF,'Type "R" to resume, anything else to warm boot: ' DB 0 ; RS2MSG: DB ' Resuming...',CR,LF,0 ; ATMSG: DB CR,LF,'Total calls with carrier: ' ATMSN: DB ' ',0 CWCAR: DB 0 ; Counter for carrier detected calls ; ; Access password (ends in carriage return) - keep password here ; IF PWRQD PASSWD: DB 'DDT' ; The password itself DB CR ; End of password, CR-only to erase it ; ; ; (Allow room for larger password to be entered, up to 10 characters) ; DB 0,0,0,0,0,0,0 ; PWMSG: DB CR,LF,'Enter Password: ',0 WRGMSG: DB 'Incorrect password',CR,LF,0 NWMSG: DB CR,LF,'Callers with correct password: ' NWMSD: DB ' ',0 NWPWD: DB 0 ; Counter for correct password callers ENDIF ; IF COMFILE LSMSG: DB 'Loading system...',CR,LF,0 ENDIF ; IDMSG: DB '> [Invalid drive, returning to A:]',0 IUMSG: DB '> [Invalid user number, returning to 0]',0 CLMSG: DB CR,LF,'[Carrier lost]',CR,LF,0 ITOMSG: DB '[Input timed out]',7,0 SCRMON: DB '[Remote screen enabled]',CR,LF,0 SCRMOFF:DB '[Remote screen disabled]',CR,LF,0 BELMON: DB '[Console bell enabled]',CR,LF,0 BELMOFF:DB '[Console bell disabled]',CR,LF,0 MFSMSG: DB 'Message from Sysop: ',0 SGDMSG: DB 'System is going down, you have ',DOWNMIN+'0' DB ' minute(s) to logout.',0 ; IF TIMEON AND RTC UTIMEM: DB '[Unlimited time on system granted]',CR,LF,0 ENDIF ; LFMSG: DB CR,LF,0 ; IF PRNTWB WBMSG: DB CR,LF,'Booting CP/M...',CR,LF DB 0 ENDIF ; IF COMFILE OR EXFILE PTSMSG: DB '++ Program area too small ++',0 CNFMSG: DB CR,LF,'++ Cannot find .COM file ++',0 CFLMSG: DB CR,LF,'[.COM file loaded]',CR,LF,0 ENDIF ; IF WELFILE WELFILN:DB 0,'WELCOME ???' ; WELCOME file name, must be 11 chars. DB 0 ; WELCOME or WELCOME.TXT will work ENDIF ; COMFCB: IF COMFILE AND (NOT OXGATE) AND (NOT METAL) AND (NOT MBBS) DB 0,'RBBS COM' ; COM file name, must be 11 characters DS 21 ; Rest of .COM FCB ENDIF ; IF COMFILE AND OXGATE DB 0,'OXENTR COM' ; OxGate entry module DS 21 ; Rest of FCB ENDIF ; IF COMFILE AND METAL DB 0,'MENTR COM' ; Metal entry file DS 21 ; Rest of FCB ENDIF ; IF COMFILE AND MBBS DB 0,'MBBS COM' ; Mbbs entry file DS 21 ; Rest of FCB ENDIF ; EXITFCB: IF EXFILE AND (NOT OXGATE) AND (NOT METAL) DB 0,' COM' ; Exit filename, must be 11 characters DS 21 ; Rest of exit FCB ENDIF ; IF EXFILE AND OXGATE DB 0,'OXEXIT COM' ; Exit filename, must be 11 characters DS 21 ; Rest of exit FCB ENDIF ; IF EXFILE AND METAL DB 0,'MEXIT COM' ; Exit filename, must be 11 characters DS 21 ; Rest of exit FCB ENDIF ; LCNAME: IF NO25TH OR MBBS DB 0,'LASTCALR???' ; LASTCALR OR LASTCALR.DAT will be used DB 0 ENDIF ; IF NO25TH OR MBBS LCDATA: DB ' ',0 DS 78 LCFILL: DB ' Last caller data has not been loaded, wait for first W/B' DB ' to CP/M',0,0,0,0,0,0,0 LCMSG1: DB '*** ERROR *** No last-caller data found',CR,LF,0 ENDIF ; IF NOT (NO25TH OR MBBS) LCDATA: DB 0 ; If BBS sees a null here, it won't overwrite ; a non-existant buffer. ENDIF ; IF MBBS MBBS1: DB CR,LF,'Loading MBBS for logoff...please wait...',CR,LF,LF,0 MBBS2: DB CR,LF,'[Logging off user]',CR,LF,0 ENDIF ; ;----------------------------------------------------------------------- ; ZCPR external paths ; ; ZCPR's external paths available. (ZCPR will always do the current ; drive/current user area) ; ; Command path available for SYSOP ; IF CHGPATH SYSPATH:DB 1,0 ; A0: DB 1,15 ; A15: DB 0 ; End of path LSYSP EQU $-SYSPATH ; ; Command path available for remote user ; REMPATH:DB 1,0 ; A0: DB 0 ; End of path LREMP EQU $-REMPATH ENDIF ; ; end of ZCPR external paths ;----------------------------------------------------------------------- ; ; These areas are not initialized ; PEND EQU $ ; The following area is not initialized ; IF COMFILE OR EXFILE CURRFCB:DS 2 ENDIF ; TOCNTM: DS 1 TOCNT: DS 2 FKATTN: DS 1 ; ; Save the CP/M jump table here ; VCOLDBT: DS 3 VWARMBT: DS 3 VCONSTAT: DS 3 VCONIN: DS 3 VCONOUT: DS 3 VLISTOUT: DS 3 ; ;---------------------------------------------------------------- ; ; ASCII Equates ; CR EQU 0DH ; ASCII carriage return LF EQU 0AH ; ASCII line feed ; LXID EQU 11H ; Define byte of LIX D,nnnn to fake loader LXIH EQU 21H ; Define byte of LXI H,nnnn to fake loader IOBYTE EQU 0003H ; Location of CP/M IOBYTE FCB EQU 005CH FCBRNO EQU FCB+32 ; ; BDOS equates ; BDOS EQU 0005H CI EQU 1 WRCON EQU 2 DRECTIO EQU 6 PRINTF EQU 9 CSTS EQU 11 SELDSK EQU 14 OPEN EQU 15 READ EQU 20 STDMA EQU 26 SETUSR EQU 32 ; DS 40 STACK EQU $ ; Local stack OBJEND EQU $ ; END