home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CP/M
/
CPM_CDROM.iso
/
cpm
/
bye3
/
bye339.lbr
/
BYE339.AQM
/
BYE339.ASM
Wrap
Assembly Source File
|
1985-12-02
|
90KB
|
3,447 lines
; 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 <cr>
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