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