;V6.7	(Revised 2/17/81)
;
;REMOTE CONSOLE PROGRAM FOR CP/M
;BASED ON AN ORIGINAL PROGRAM WRITTEN
;BY DAVE JAFFE, JANUARY 1979
;
;Rewritten for PMMI modem
;by Ward Christensen, February 1979
;
;I'd also like to give credit to Bill Precht
;	for the "label + offset" idea allowing
;	this program to relocate itself
;	without using DDT to initially set it up
;
;2/17/81   Added check for extraneous control characters in
;	   hardcopy log.  (Formfeed seems to be a common "hit").
;	   Changed local startup test to directly test for carrier
;	   instead of calling CARCK, to avoid 15 second delay.
;	   <BRR>
;
;2/15/81   Removed dependance on DC Hayes hardware timer so that
;          DCHAYES conditional assembly is compatible with both
;          old-style 80-103A and new-style MM100 boards.
;          Rearranged patch list to "most recent first" order.
;	   Added message for invalid-drive test.
;          Added ANI 7Fh to upper case conversion test so that
;          it's not fooled by bit 7 being set.
;          Added WELUSR equate for user # containing WELCOME file.
;          Removed PTRPORT equate and changed hardcopy logic to
;          work through the BIOS printer driver. <BRR>
;
;1/22/81   CHANGED CARRIER DETECT ROUTINE FOR DC HAYES TO WAIT FOR
;	   15 SECONDS AFTER LOSS OF CARRIER TO RETURN.  <DAVID KOZINN>
;
;1/17/81   CHANGED TIMING LOOPS TO USE DC HAYES HARDWARE TIMER
;	   IF PRESENT.   <DAVID KOZINN>
;
;1/16/81   ADDED EQUATES AND CODE FOR THE DC-HAYES 
;	   MICROMODEM 100.  <DAVID KOZINN>
;
;9/23/80  Fixed bugs that prevented "bye /a" and "bye /c" from
;	  working properly.  Also repaired several errors in
;	  conditional assembly nesting. -->Ron Fowler
;
;9/20/80  Modified status checking during ring-wait routine to
;	  use cp/m BDOS call, as suggested by Keith Petersen.
;	  This should make the program more portable.  Also
;	  added Bruce Ratoff's update to DCHBYE program (5.5),
;	  that allows the use of bye from non-zero user areas.
;	  By Ron Fowler
;
;9/19/80  Modified COM file load routine to prevent BDOS
;	  overwrite if the COM file won't fit in the TPA
;	  By Ron Fowler
;
;9/19/80  Added new '/' option C, which has the same affect as
;	  /A, except that /C loads the com file after answering
;	  the phone, while /A boots cp/m.
;	  By Ron Fowler
;
;9/19/80  Added conditional assembly to give the operator a
;	  'twit' logout key. Added conditionals for 'message
;	  from operator' and 'system down in 5 minutes' keys.
;	  Added front-panel selection of hard-copy log, remote
;	  'black-out', and password option.  Also, if cpm/2 is
;	  used, a message is printed when an unsupported user
;	  area is entered.
;	  By Ron Fowler and Dave Hardy
;
;9/19/80  Modified to prevent re-load of the com file when
;	  a voice call comes in.  Reset the DMA address back
;	  to 80h after the com file is loaded.
;	  By Ron Fowler
;
;09/16/80 Added conditional assembly to allow automatic
;	  loading of a com file instead of cp/m boot. Also
;	  added decimal usrlog counters as conditional as-
;	  sembly.
;	  By Ron Fowler
;
;09/15/80 Added conditional assembly for automatic timed
;	  log-out, drive and user number masking, lower
;	  case query at login, and cp/m 2.x.  Thanks to
;	  Bruce Ratoff for the routines (lifted from his
;	  'DCHBYE54.ASM') used to implement these functions
;	  NOTE: in order to implement the timed log-out, it
;	  was necessary to do timing in software loops.
;	  Therefore, a new equate, FASTCLK, has been added
;	  to allow for 4mhz clock speeds. Also added Bruce
;	  Ratoff's overrun/framing error checking when read-
;	  ing the modem port.
;	  By Ron Fowler
;
;07/16/80 Added "/R" command option to allow USRLOG
;	  counters to be reset upon entry.
;	  By Dave Hardy
;
;07/11/80 Added conditional assembly for password and
;	  user log routines, and routines to print USRLOG
;	  information on console after program exit.
;	  By Dave Hardy
;
;07/10/80 Added code to allow auto-answer after first
;	  or second ring for more reliable auto-answer
;	  when using "ringback" option.
;	  By Dave Hardy
;
;06/29/80 Added USRLOG routines to keep track of number
;	  of callers, and display on front panel
;	  of IMSAI (i.e. output number to port FFH).
;	  By Dave Hardy
;
;06/11/80 Added 710 Baud rate selection option at sign-on.
;	  By Dave Hardy and Bruce Levison.
;
;06/11/80 Added routines to allow conditional assembly for
;	  Morrow's Discus 2D board (all Rev's) with memory
;	  mapped I/O.
;	  By Dave Hardy
;
;01/24/80 Added routines to preserve registers when calling
;	  the user's CBIOS.  Added conditional assembly for
;	  callback feature.  Increased stack space to 60.
;	  By Keith Petersen.
;
;09/24/79 Added routines to allow automatic multiple baud
;	  rate selection, exit to CP/M from local console,
;	  echo nr. of nulls selected. By Keith Petersen,
;	  with thanks to Bob Mathias for suggestions.
;
;05/06/79 Added routine to allow "callback" operation so modem
;	  does not answer normal voice calls.  By Robbin Hough
;	  and Keith Petersen, W8SDZ.
;
;
;------------------------------------------------
;	SYSTEM EQUATES
FALSE	EQU	0
TRUE	EQU	NOT FALSE
BDOS	EQU	5
CR	EQU	0DH
LF	EQU	0AH
MINUTES	EQU	20*60	;CONSTANT FOR 1 MIN TIM DLY
;
;CHANGE THE FOLLOWING EQUATE TO AN AREA IN YOUR
;HI MEMORY WHERE THIS PROGRAM MAY PATCH ITSELF IN.
;APPROX MEMORY REQUIREMENTS: UP TO xxxx BYTES.
;
DEST	EQU	0F800H	;RUNNING LOCATION OF CODE
;
;
;CHANGE THE FOLLOWING TO SPECIFY EITHER DCHAYES OR PMMI
;MODEMS. BE SURE TO CHANGE EITHER TPORT FOR PMMI OR DATA
;FOR DCHAYES IF THEY ARE NOT AT THE STANDARD LOCATIONS.
;
DCHAYES	EQU	TRUE	;TRUE FOR D.C. HAYES MODEM
PMMI	EQU	FALSE	;TRUE FOR PMMI MODEM
;
	IF	DCHAYES
;CHANGE THE FOLLOWING IF YOU HAVE A DC HAYES MODEM THAT IS
;NOT BASED AT 80H. ALL OTHER PORT EQUATES ARE BASED ON THIS.
;
DATA	EQU	80H	;D.C. HAYES DATA PORT
	ENDIF
	IF	PMMI
;CHANGE THE FOLLOWING IF YOUR PMMI IS NOT AT 0C0H
;(THE OTHER PORT EQUATES ARE BASED ON THIS VALUE)
;
TPORT	EQU	0C0H	;UART CONTROL/STATUS PORT
	ENDIF
;
;
;YOU WILL LIKELY ALSO WANT TO CHANGE THE PASSWORD,
;LOCATED BELOW AT LABEL "PASSWD", AND THE MESSAGES
;PRINTED AT LABEL "WELCOME" AND JUST ABOVE LABEL
;"HANGUP"
;
;------------------------------------------------
;
;THIS PROGRAM RUNS UP IN HIGH RAM.  IT GETS THERE
;BY BEING MOVED THERE WHEN 'BYE' IS TYPED.
;
;THE PROGRAM IN HI RAM DOES THE FOLLOWING:
;
;	1.	HANGS UP THE PHONE
;	2.	AWAITS RING DETECT, ALLOWS EXIT
;		TO CP/M IF LOCAL KBD TYPES CTL-C
;	3.	OUTPUTS CARRIER (SEE CALLBACK ROUTINES)
;	4.	AWAITS INCOMING CARRIER
;		GOING TO STEP 1 IF NONE
;		FOUND IN 15 SECONDS
;	5.	ASKS NUMBER OF NULLS (0-9)
;	6.	TYPES THE FILE "WELCOME" FROM
;		DISK, ALLOWING CTL-C TO SKIP IT
;	7.	ASKS FOR A PASSWORD, ALLOWING
;		5 TRIES TO GET IT RIGHT.
;	8.	WHEN PASSWORD ENTERED, IF USED, DROPS
;		INTO CP/M.
;	9.	CALLER CAN LEAVE BY HANGING UP,
;		(ANY TIME CARRIER IS LOST, IT
;		WAITS 15 SECONDS, THEN GOES
;		BACK TO STEP 1), OR THE CALLER
;		MAY TYPE THE PROGRAM NAME (BYE)
;
;
;****************************************************
;*	    OPTION CONFIGURATION SECTION	    *
;****************************************************
;
PRINTER EQU	FALSE	;WANT TO RETAIN LIST DEVICE?
DUAL$IO EQU	TRUE	;WANT CONSOLE & MODEM?
CALLBAK EQU	FALSE	;WANT CALLBACK FEATURE?
PWRQD	EQU	FALSE	;WANT TO USE PASSWORD?
USRLOG	EQU	TRUE	;WANT TO COUNT NUMBER OF USERS?
IMSAI	EQU	TRUE 	;ADDS VARIOUS OPIONS W/SENSE SW'S
CPM2	EQU	TRUE	;USING CP/M 2.X?
MAX$USER EQU	3	;SET TO 0 FOR CP/M 1.X
MAX$DRIVE EQU	3	;HIGHEST DRIVE SUPPORTED
FASTCLK EQU	TRUE	;SET TRUE FOR 4 MHZ CLOCK
TIMEOUT EQU	TRUE	;WANT AUTO LOG-OFF FOR SLEEPY CALLERS?
TOVALUE EQU	7	;THIS IS 7 MINUTES TO AUTO LOGOUT
WELUSR	EQU	0	;USER # THAT WELCOME FILE IS KEPT IN
COMFILE EQU	TRUE	;WANT TO AUTOBOOT A COM FILE?
COMUSR	EQU	3	;USER # THAT COMFILE IS KEPT IN
DECIMAL EQU	TRUE	;WANT DECIMAL VALUES FOR LOGS?
CK$LWC	EQU	TRUE	;WANT TO TRAP LOWER CASE?
;
; SPECIAL KEYS FOR SPECIAL FUNCTIONS
;
FKEYS	EQU	TRUE	;WANT SPECIAL FUNCTION KEYS?
;
;ASSIGN FUNCTION KEYS TO THE FOLLOWING CONTROL CODES (IF USED):
;
TWITKEY EQU	'N'-40H ;KEYCODE TO LOG-OUT A CREEP
MSGKEY	EQU	'Q'-40H ;KEYCODE TO PRINT 'MESG FROM OPER:'
SYSDKEY EQU	'O'-40H ;KEYCODE TO PRINT SYS DOWN MSG
;
;	FRONT-PANEL SELECTION OPTIONS
;
SENSE	EQU	0FFH	;SENSE SWITCH PORT NUMBER
;
BLACKOUT EQU	TRUE	;SWITCH TO TURN OFF REMOTE SEND
HARDLOG EQU	TRUE	;SWITCH TO ECHO REMOTE KBD TO PRINTER
SELPASS EQU	TRUE 	;SWITCH TO REQUIRE A PASSWORD
;
;	ASSIGNMENT OF FRONT-PANEL OPTIONS TO SWITCHES:
;
LOGSW	EQU	01H	;TURN ON FOR HARDCOPY
PWDSW	EQU	02H	;TURN ON FOR 'PASSWORD' MODE
BLACKSW EQU	04H	;TURN ON TO BLACK OUT REMOTE END
ENABLF	EQU	08H	;TURN ON TO ENABLE SPL FUNC KEYS
;
;****************************************************
;*	 END OF OPTION CONFIGURATION SECTION	    *
;****************************************************
	IF	DCHAYES
;************ D.C. HAYES MODEM I/O AREA ************

;ALL MODEM I/O AND CONTROL ARE HERE.


;	PORT EQUATES

DPORT	EQU	DATA	;DATA PORT
STATUS	EQU	DATA+1
RPORT	EQU	STATUS	;MODEM STATUS PORT
CR1	EQU	DATA+1
CR2	EQU	DATA+2
CR3	EQU	DATA+3

;	BIT FUNCTIONS
;STATUS REGISTER

RRF	EQU	1	;RECIEVE REGISTER FULL
TRE	EQU	2	;TRANSMITTER HOLDING REGISTER EMPTY
PE	EQU	4	;PARITY ERROR
FE	EQU	8	;FRAMING ERROR
OE	EQU	10H	;OVERRUN ERROR
TMR	EQU	20H	;TIMER STATUS (MM100 ONLY)
CD	EQU	40H	;CARRIER PRESENT
RI	EQU	80H	;NOT RING INDICATOR (LOW TRUE)
P2RDET	EQU	RI	;SAME AS ABOVE

;CONTROL REGISTER 1  (CR1)

EPE	EQU	1	;EVEN PARITY ENABLE
LS1	EQU	2	;WORD LENGTH SELECT BIT 1
LS2	EQU	4	;WORD LENGTH SELECT BIT 2
SBS	EQU	8	;STOP BITS
PI	EQU	10H	;PARITY INHIBIT
TMIE	EQU	20H	;TIMER INTERRUPTS ENABLE (MM100 ONLY)


;CONTROL REGISTER 2  (CR2)

BRS	EQU	1	;BAUD RATE CONTROL
TXE	EQU	2	;TRANSMIT CARRIER ENABLE
MS	EQU	4	;MODE (0=ANSWER 1=ORIGINATE)
BRK	EQU	8	;SEND BREAK
ST	EQU	10H	;SELF TEST
TIE	EQU	20H	;TRANSMITTER INTERRUPT ENABLE
RIE	EQU	40H	;RECIEVER INTERRUPT ENABLE (MM100 ONLY)
OH	EQU	80H	;OFF-HOOK
;
	ENDIF
;
;
	IF	PMMI
;	PMMI MODEM PORT ASSIGNMENTS:
;
;PMMI MODEM PORT EQUATES (TPORT PREVIOUSLY DONE)
;
DPORT	EQU	TPORT+1 ;DATA PORT
RPORT	EQU	TPORT+2 ;RATE GEN/MODEM STATUS
CPORT	EQU	TPORT+3 ;MODEM CONTROL
;
;MODEM CONTROL COMMAND WORDS
;
P3CLEAR EQU	3FH	;IDLE MODE
;
;SET FOLLOWING TO 5FH FOR >300 BAUD
;
P3TODTR EQU	5FH	;Turn On DTR
;
;SWITCH HOOK AND MODEM COMMANDS,
;	OUTPUT TO TPORT (PORT 0)
;
P0BYE	EQU	0	;ON HOOK, OR DIALING BREAK
P0ORIG	EQU	1	;OFF HOOK, ORIG.
P0ANSW	EQU	2	;ANSWER PHONE
P08BIT	EQU	0CH	;8 DATA BITS
P0NOPY	EQU	10H	;NO PARITY
P0EPS	EQU	20H	;EVEN PARITY SELECT
P0TSB	EQU	40H	;2 STOP BITS
P0EI	EQU	80H	;ENABLE INTERRUPTS
P0NORM	EQU	P08BIT+P0NOPY ;I USE 8 BITS, NO PARITY
P0110	EQU	P08BIT+P0NOPY+P0TSB ;SAME W/2 STOP BITS
;
;MODEM STATUS, INPUT ON RPORT (PORT 3)
;
P2DTD	EQU	1	;DIAL TONE DETECT
P2RDET	EQU	2	;RING DETECT
P2CTS	EQU	4	;CTS (CARRIER DETECT)
P2RXBRK EQU	8	;RECEIVE BREAK
P2CONN	EQU	10H	;CONNECTED? (0=YES,
;			 1=MODEM CHIP HUNG UP)
P2TMPUL EQU	80H	;TIMER PULSES (40% UP CYCLE)
;
;TIMER RATE SELECTION
;
TRATE	EQU	250	;VALUE FOR .1 SEC
;
;PMMI MODEM STATUS MASKS
;
P0TBMT	EQU	1	;XMIT BUFF EMPTY
P0DAV	EQU	2	;DATA AVAILABLE
P0TEOC	EQU	4	;TEST END OF CHAR
P0RPE	EQU	8	;REC'D PARITY ERR
P0ORUN	EQU	10H	;OVERRUN
P0FERR	EQU	20H	;FRAMING ERROR
;
;BAUD RATE DIVISORS
;
B110	EQU	142	;110 BAUD
B300	EQU	52	;300 BAUD
B450	EQU	35	;450 BAUD
B600	EQU	26	;600 BAUD
B710	EQU	22	;710 BAUD
	ENDIF
;
	ORG	100H
;
;MOVE THE MODEM INTERFACE PROGRAM UP TO HI RAM
;AND JUMP TO IT.
;
MOVEUP	LXI	B,PEND-START+1	;NUMBER OF BYTES TO MOVE
	LXI	H,DEST+PEND-START+1 ;END OF MOVED CODE
	LXI	D,SOURCE+PEND-START	;END OF SOURCE CODE
MVLP	LDAX	D	;GET BYTE
	DCX	H	;BUMP POINTERS
	MOV	M,A	;NEW HOME
	DCX	D
	DCX	B	;BUMP BYTE COUNT
	MOV	A,B	;CHECK IF ZERO
	ORA	C
	JNZ	MVLP	;IF NOT, DO SOME MORE
	PUSH	H	;SAVE FOR LATER JUMP
	MVI	A,0C3H	;CLEAR ANY TRAPS SO SYSOP..
	STA	0	;CAN USER "BYE /A"
	XRA	A	;NEXT WARMBOOT TO USR0/DRV A
	STA	4
	MVI	C,14	;MAKE DRIVE A DEFAULT
	MOV	E,A	;LOG-IN DRIVE CP/M FUNCTION
	CALL	BDOS
;
	IF	CPM2	;SET USER 0
	MVI	C,32	;GET/SET USR CP/M FUNCTION
	MVI	E,WELUSR
	CALL	BDOS
	ENDIF
;
	RET		;TO ADRS PUSHED ABOVE
;
;
SOURCE	EQU	$	;BOUNDARY MEMORY MARKER
;
OFFSET	EQU	DEST-SOURCE ;RELOC AMOUNT
;-----------------------------------------------;
;	THE FOLLOWING CODE GETS MOVED		;
;	 TO HI RAM LOCATED AT "DEST",		;
;	    WHERE IT IS EXECUTED.		;
;-----------------------------------------------;
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
;XX   C A U T I O N :  IF MODIFYING ANYTHING	XX
;XX	IN THIS PROGRAM FROM HERE ON:		XX
;XX	A-L-L  LABELS MUST BE OF THE FORM:	XX
;XX	label	EQU	$+OFFSET		XX
;XX	IN ORDER THAT THE RELOCATION TO HI RAM	XX
;XX	WORK SUCCESSFULLY.  FORGETTING TO	XX
;XX	SPECIFY '$+OFFSET' WILL CAUSE THE PRO-	XX
;XX	GRAM TO JMP INTO WHATEVER IS CURRENTLY	XX
;XX	IN LOW MEMORY, WITH UNPREDICTABLE	XX
;XX	RESULTS.  BE CAREFUL....		XX
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
;
;	IF CARRIER LOST, HANG UP, AWAIT RING.
;	OTHERWISE, SAY GOODBYE, AND HANG UP
;
START	EQU	$+OFFSET
;
	XRA	A	;GET 0
	STA	LOSTFLG ;SHOW NO CARR. LOST
;
;	DON'T ALLOW A REMOTE USER TO DO 'BYE /A'
;
	IF	DCHAYES
	IN	STATUS
	ANI	CD	;CHECK CARRIER DETECT
	JNZ	GOODBY	;SAY GOODBYE IF REMOTE
	ENDIF
;
	IF	PMMI
	IN	RPORT	;AS ABOVE, FOR PMMI MODEM
	ANI	P2CTS	;CD DEDUCED FROM CTS
	JZ	GOODBY
	ENDIF
;
;CHECK FOR /A OPTION ON COMMAND - REQUEST TO
;GO IMMEDIATELY INTO ANSWER MODE
;
	LXI	H,FCB+1 ;TO OPTION
	MOV	A,M
	CPI	'/'	;OPTION?
	JNZ	HANGUP
;GOT AN OPTION - VALIDATE IT
	INX	H	;TO OPTION BYTE
	MOV	A,M	;GET IT
	STA	OPTION	;MIGHT NEED LATER
	CPI	'A'	;ANSWER?
	JZ	ANSWER
;
	IF	COMFILE
	CPI	'C'
	JZ	ANSWER
	ENDIF
;
	IF	USRLOG	;CHECK FOR RESET OF COUNTERS
	CPI	'R'
	CZ	RESET
	ENDIF
;
	JMP	HANGUP	;WE KNOW IT'S LOCAL, SO SKIP CALL TO CARCK

;NO OPTION, OR INVALID ONE
NOSLASH EQU	$+OFFSET
	CALL	CARCK	;SIGNED OFF W/THIS PROG?
	JC	HANGUP	;NOBODY THERE
;
GOODBY	EQU	$+OFFSET
	CALL	ILPRT	;PRINT THIS MSG:
	DB	CR,LF,'GOOD BYE, CALL AGAIN'
	DB	CR,LF,CR,LF,0
	CALL	UNPATCH ;UNDO BIOS PATCHES
;
;	NOBODY THERE, OR WE ARE DONE, SO HANG UP
;
HANGUP	EQU	$+OFFSET
	LXI	SP,STACK ;SET UP LOCAL STACK
	XRA	A	 ;FORCE NEXT WARMBOOT TO USER 0
	STA	4	 ;AND DRIVE A
	MVI	C,14	 ;MAKE DRIVE A DEFAULT
	MOV	E,A
	CALL	BDOS
	MVI	A,' '	 ;DON'T ALLOW OPTIONS..
	STA	OPTION	 ;..AFTER 1 "BYE / <ANYTHING>"
;
	IF	CPM2 AND COMFILE
	MVI	C,32	 ;GET/SET USER CODE
	MVI	E,COMUSR ;LOCATION OF OUR COMFILE
	CALL	BDOS
	ENDIF
;
	IF	COMFILE
	CALL	LODCOM	;LOAD THE COM FILE
	ENDIF
;
;
HANGUP2 EQU	$+OFFSET
;
;CLEAR DTR CAUSING PHONE TO HANG UP
	IF	DCHAYES
	XRA	A	;GET A ZERO
	OUT	CR2	;WRITE TO CR2, CAUSING HANGUP
	ENDIF
	IF	PMMI
	MVI	A,P3CLEAR ;CLEAR..
	OUT	CPORT	;..DTR
	ENDIF
	MVI	A,0C3H	;CLEAR ANY TRAPS..
	STA	0	;..LEFT FROM COM FILE
;
;	AWAIT RINGING
;
RINGWT	EQU	$+OFFSET
;CHECK LOCAL KEYBOARD FOR CTL-C EXIT REQUEST.
;NOTE: MUST DO DIRECT INPUT BECAUSE CBIOS PATCHES
;ARE NOT DONE UNTIL CALL COMES IN.
;
	CALL	UCSTS
;
	ANI	7FH	;STRIP PARITY BIT
	CPI	'C'-40H ;CONTROL C?
;
	IF	NOT USRLOG
	JZ	0	;YES, --EXIT-- TO CP/M
	ENDIF
;
	IF	USRLOG	;PRINT OUT USER INFO
	JZ	PRNLOG
	ENDIF
;
RINGW2	EQU	$+OFFSET
	IN	RPORT	;GET THE STATUS
	ANI	P2RDET	;RINGING?
	JNZ	RINGWT	;NO, WAIT
;
;THE PHONE IS RINGING, NOW WAIT UNTIL RING IS FINISHED
ENDRING EQU	$+OFFSET
	CALL	DELAY	;.1 SEC DELAY FOR DEBOUNCE
	IN	RPORT	;GET STATUS
	ANI	P2RDET	;STILL RINGING?
	JZ	ENDRING ;WAIT UNTIL RING FINISHED
;
	IF	CALLBAK ;NEXT ROUTINES IMPLEMENT CALLBACK
;
;      THIS ROUTINE MINIMIZES THE COMPUTER'S INTERFERENCE
;      WITH NORMAL HOUSEHOLD PHONE USE BY HAVING COMPUTER
;      FOLK DIAL, LET THE PHONE RING ONCE, HANG UP AND 
;      THEN DIAL AGAIN.  WHEN THE PHONE RINGS ONLY ONCE IT
;      ALERTS THE COMPUTER WHICH THEN WAITS FOR AND ANSWERS
;      ANY RING WHICH OCCURS WITHIN THE NEXT 40 SECONDS.
;
	MVI	L,45	;DELAY 4.5 SECONDS FOR NEXT RING
WAITNX	EQU	$+OFFSET
	CALL	DELAY	;WAIT .1 SECONDS
	DCR	L	;MORE TO GO?
	JNZ	WAITNX	;YES?...LOOP
	IN	RPORT	;GET THE STATUS
	ANI	P2RDET	;RINGING AGAIN?
	JNZ	EXPECT	;NO?...ITS FOR ME!
ENDRNG2 EQU	$+OFFSET	;IF SECOND RING THEN CHECK
	IN	RPORT	;FOR THIRD RING, IN CASE CALLER'S
	ANI	P2RDET	;PHONE EXCHANGE IS NOT SYNC'ED
	JZ	ENDRNG2 ;WITH COMPUTER'S.
	MVI	L,45
WAITNX2 EQU	$+OFFSET
	CALL	DELAY
	DCR	L
	JNZ	WAITNX2
	IN	RPORT
	ANI	P2RDET
	JNZ	EXPECT	;ANSWER IF NO THIRD RING
;CALL NOT FOR COMPUTER - WAIT UNTIL RINGING DONE, THEN RESET
WAITNR	EQU	$+OFFSET
	MVI	L,100	;WAIT FOR 10 SECS NO RINGING
WAITNRL EQU	$+OFFSET
	CALL	DELAY	;DELAY .1 SECONDS
	IN	RPORT	;GET THE STATUS
	ANI	P2RDET	;STILL RINGING?
	JZ	WAITNR	;YES, WAIT 10 MORE SECONDS
	DCR	L	;NO RING, MAYBE WE'RE DONE
	JNZ	WAITNRL ;NO, LOOP SOME MORE
	ENDIF
 
;
	IF	CALLBAK AND USRLOG
	LDA	NONUSR	;RECORD AS VOICE CALL
	INR	A
	ENDIF
;
	IF	CALLBAK AND USRLOG AND DECIMAL
	DAA
	ENDIF
;
	IF	CALLBAK AND USRLOG
	STA	NONUSR
	ENDIF
;
	IF	CALLBAK ;CONTINUE WITH CALLBAK ROUTINES
	JMP	HANGUP2
;
EXPECT	EQU	$+OFFSET
	LXI	H,400	;40 SECONDS TO REDIAL
RELOOK	EQU	$+OFFSET
	IN	RPORT
	ANI	P2RDET	;RINGING AGAIN?
	JZ	ANSWER
	CALL	DELAY
	DCX	H
	MOV	A,H
	ORA	L
	JNZ	RELOOK
	JMP	HANGUP2
;
	ENDIF		;END OF CALLBACK ROUTINES
;
;SETUP MODEM
ANSWER	EQU	$+OFFSET
	IF	USRLOG	;COUNT # OF LOGON ATTEMPTS
	LDA	OLDUSR	;GET # OF ATTEPMTS
	INR	A	;ADD THIS CALL
	ENDIF
;
	IF	USRLOG AND DECIMAL
	DAA
	ENDIF
;
	IF	USRLOG
	STA	OLDUSR	;SAVE # OF ATTEMPTS
	ENDIF
;
	IF	DCHAYES
	MVI	A,LS1+LS2+PI+SBS	;8 DATA BITS, NO PARITY, 2 STOP BITS
	OUT	CR1
	MVI	A,TXE+OH	;TURN ON CARRIER AND ANSWER PHONE
	OUT	CR2
	IN	DATA	;CLEAR DATA INPUT PORT
	IN	DATA	;MAKE SURE IT'S CLEAR
	CALL	CARCK	;SEE IF THERE IS A CARRIER PRESENT
	JC	HANGUP2	;YES, HANGUP AND WAIT FOR NEXT CALL
;NOW TEST INPUT FOR BAUD RATE
	CALL	PATCH	;PATCH JUMP TABLE
	CALL	TSTBAUD	;SEE IF BAUD = 110
	JZ	WELCOME	;YES, EXIT
	MVI	A,LS1+LS2+PI	;SET FOR 1 STOP BIT, 8 DATA, NO PARITY
	OUT	CR1
	MVI	A,TXE+OH+BRS	;SET FOR 300 BAUD
	OUT	CR2
	CALL	TSTBAUD	;SEE IF BAUD = 300
	JZ	WELCOME		;YES,EXIT
	ENDIF
	IF	PMMI
	MVI	A,P3TODTR ;TURN ON
	OUT	CPORT	;..DTR
	CALL	DELAY	;GIVE TIME TO TURN ON
	MVI	A,P0110+P0ANSW
	OUT	TPORT	;ANSWER PHONE
	CALL	DELAY	;GIVE TIME FOR ANSWER
	CALL	UCSTS
	IN	DPORT	;CLEAR MODEM PORT
	IN	DPORT	;MAKE SURE ITS CLEAR
	MVI	A,B110	;SELECT 110 BAUD
	OUT	RPORT	;SET BAUD RATE
;OUTPUT VALUE ALLOWING MODEM TO HANG UP ON
;LOSS OF CARRIER
	MVI	A,P0110 ;NORMAL MODE FOR 110 BAUD
	OUT	TPORT
	CALL	CARCK	;LOOK FOR CARRIER
	JC	HANGUP2 ;AWAIT ANOTHER CALLER
;NOW TEST INPUT FOR BAUD RATE
	CALL	PATCH	 ;PATCH JMP TABLE
	CALL	TSTBAUD  ;SEE IF BAUD = 110
	JZ	WELCOME  ;YES, EXIT
	MVI	A,P0NORM ;SET FOR 1 STOP BIT, ETC.
	OUT	TPORT
	MVI	A,B300	 ;SET DIVISOR
	OUT	RPORT	 ;.. TO 300 RATE
	CALL	TSTBAUD  ;SEE IF BAUD = 300
	JZ	WELCOME  ;YES, EXIT
	MVI	A,B450	 ;SET DIVISOR
	OUT	RPORT	 ;.. TO 450 RATE
	MVI	A,5FH
	OUT	CPORT	 ;SET FILTER VALUE FOR > 300
	CALL	TSTBAUD  ;SEE IF BAUD = 450
	JZ	WELCOME  ;YES, EXIT
	MVI	A,B600	 ;SET DIVISOR
	OUT	RPORT	 ;.. TO 600 RATE
	CALL	TSTBAUD  ;SEE IF BAUD = 600
	JZ	WELCOME  ;YES, EXIT
	MVI	A,B710	;SET DIVISOR
	OUT	RPORT	;.. TO 781 RATE
	CALL	TSTBAUD ;SEE IF BAUD = 710
	JZ	WELCOME ;YES, EXIT
	ENDIF
;
	CALL	UNPATCH  ;RESTORE ORIG BIOS JMP TBL
	JMP	ANSWER	 ;TEST MORE - INVALID BAUD RATE
;
;	Get the console status when unpatched
;
UCSTS	EQU	$+OFFSET
	IF	CPM2
	MVI	C,DIRECTIO ;DIRECT I/O CALL WILL RETURN
	MVI	E,0FFH	   ;ASK FOR INPUT
	CALL	BDOS	   ;A=0 IF NO CHAR WAITING
	RET
	ENDIF
;
	IF	NOT CPM2
	MVI	C,CSTS	  ;IN CPM 1.X, WE HAVE TO GET..
	CALL	BDOS	  ;..THE STATUS FIRST
	ORA	A
	RZ
	MVI	C,CI	  ;AND THEN THE CHARACTER
	CALL	BDOS
	RET
	ENDIF

;
;FOLLOWING ARE THE USRLOG ROUTINES
;
	IF	USRLOG	;INCLUDE RESET FUNCTIONS
RESET	EQU	$+OFFSET	;RESET ALL LOGON COUNTERS
	XRA	A
	ENDIF
;
	IF	USRLOG AND PWRQD
	STA	OLDUSR	;RESET ATTEMPT COUNTER
	ENDIF
;
	IF	USRLOG
	STA	NEWUSR	;RESET LOGON COUNTER
	ENDIF
;
	IF	USRLOG AND CALLBAK
	STA	NONUSR	;RESET VOICE COUNTER
	ENDIF
;
	IF	USRLOG AND IMSAI
	CMA
	OUT	SENSE	;RESET IMSAI PANEL DISPLAY
	ENDIF
;
	IF	USRLOG
	RET
	ENDIF
;
PRNLOG	EQU	$+OFFSET
;
	IF	USRLOG AND PWRQD ;PRINT # OF LOGON ATTEMPTS
	MVI	C,09H
	LXI	D,ATMSG
	CALL	BDOS
	LDA	OLDUSR
	CALL	HXOUT
	ENDIF
;
	IF	USRLOG	;PRINT # OF LOGONS
	MVI	C,09H
	LXI	D,SUMSG
	CALL	BDOS
	LDA	NEWUSR
	CALL	HXOUT
	ENDIF
;
	IF	USRLOG AND CALLBAK	;# OF VOICE CALLS
	MVI	C,09H
	LXI	D,VCMSG
	CALL	BDOS
	LDA	NONUSR
	CALL	HXOUT
	ENDIF
;
	IF	USRLOG
	JMP	0	;WARM-BOOT BACK TO CP/M
	ENDIF
;
	IF	USRLOG AND PWRQD
ATMSG	EQU	$+OFFSET
	DB	LF,CR,'NUMBER OF LOGON ATTEMPTS: $'
	ENDIF
;
	IF	USRLOG
SUMSG	EQU	$+OFFSET
	DB	LF,CR,'NUMBER OF LOGONS: $'
	ENDIF
;
	IF	USRLOG AND CALLBAK
VCMSG	EQU	$+OFFSET
	DB	LF,CR,'NUMBER OF VOICE CALLS: $'
	ENDIF
;
	IF	USRLOG
HXOUT	EQU	$+OFFSET
	MOV	B,A	;SAVE NUMBER
	RAR		;ROTATE RIGHT 4 BITS
	RAR		;TO MAKE AN ASCII DIGIT
	RAR
	RAR
	CALL	ONEOUT	;OUTPUT MSH TO CONSOLE
	MOV	A,B	;GET NUMBER BACK
ONEOUT	EQU	$+OFFSET
	ANI	0FH	;GET LSH FOR OUTPUT
	CPI	0AH	;CHECK IF ALPHA
	JC	NOTAL2
	ADI	07H
NOTAL2	EQU	$+OFFSET
	ADI	30H
	PUSH	B
	MVI	C,02H
	MOV	E,A	;OUTPUT THE NUMBER
	CALL	BDOS
	POP	B
	RET
	ENDIF
;
;WELCOME TO THE SYSTEM
;
WELCOME EQU	$+OFFSET
;
GETNULL EQU	$+OFFSET
	CALL	ILPRT	;PRINT THIS MSG:
	DB	CR,LF
	DB	'HOW MANY NULLS (0-9) DO YOU NEED? ',0
	CALL	MINPUT	;GET VALUE
	MOV	C,A
	CALL	MOUTPUT ;ECHO CHAR
	MOV	A,C
	CPI	'0'
	JC	GETNULL ;BAD, RETRY
	CPI	'9'+1
	JNC	GETNULL ;BAD
	SUI	'0'	;MAKE BINARY
	STA	NULLS	;SAVE COUNT
;
	IF	CK$LWC
GETULC	EQU	$+OFFSET
	CALL	ILPRT	;NOWPRINT THIS MSG:
	DB	CR,LF
	DB	'CAN YOUR TERMINAL DISPLAY LOWER CASE? ',0
	MVI	A,20H	;FORCE CASE CONVERSION FOR NOW
	STA	ULCSW
	CALL	MINPUT	;GET Y OR NO
	MOV	C,A
	CALL	MOUTPUT ;ECHO
	MOV	A,C
	CPI	'N'
	JZ	DONEOPT ;WE'RE ALREADY SET UP FOR NO LWR CASE
	CPI	'Y'
	JNZ	GETULC	;WASN'T Y OR N...ASK HIM AGAIN
	XRA	A
	STA	ULCSW	;SET FLAG FOR NO CONVERSION
DONEOPT EQU	$+OFFSET
	ENDIF
;
	CALL	ILPRT
	DB	CR,LF,0
;PRINT THE WELCOME FILE
	LXI	H,WELFILN ;SOURCE
	LXI	D,FCB	;DESTINATION
	MVI	B,13	;LENGTH
	CALL	MOVE	;MOVE THE NAME
;SET DMA ADDR TO 80H
	LXI	D,80H
	MVI	C,STDMA
	CALL	BDOS
;
	IF	CPM2
;SET USER FOR WELCOME FILE
	MVI	C,32
	MVI	E,WELUSR
	CALL	BDOS
	ENDIF
;
;OPEN THE WELCOME FILE
	LXI	D,FCB
	MVI	C,OPEN
	CALL	BDOS
;DID IT EXIST?
	INR	A	;A=> 0 MEANS "NO"
	JZ	PASSINT ;NO WELCOME FILE
;GOT A FILE, TYPE IT
	XRA	A	;GET 0
	STA	FCBRNO	;ZERO RECORD #
	LXI	H,100H	;GET INITIAL BUFF POINTER
;TYPE THE WELCOME FILE
WELTYLP EQU	$+OFFSET
	CALL	RDBYTE	;GET A BYTE
	CPI	1AH	;EOF?
	JZ	PASSINT ;YES, DONE
	MOV	C,A	;SETUP FOR TYPE
	CALL	MOUTPUT ;TYPE THE CHAR
	CALL	MSTAT	;CHECK FOR..
	ORA	A	;CHAR TYPED?
	JZ	WELTYLP ;..NO, LOOP
	CALL	MINPUT	;..YES, GET CHAR
	CPI	'C'-40H ;CTL-C?
	JNZ	WELTYLP ;..NO, LOOP UNTIL EOF
;
;GET THE PASSWORD
;
PASSINT EQU	$+OFFSET
;
;
	IF	PWRQD AND IMSAI AND SELPASS 
	IN	SENSE	;TURN THE SWITCH UP..
	ANI	PWDSW	;..TO REQUIRE THE PASSWORD
	JZ	NOPASS
	ENDIF
;
	IF	PWRQD
	MVI	D,5	;5 TRIES AT PASSWORD
PASSINP EQU	$+OFFSET
	CALL	ILPRT
	DB	CR,LF,'ENTER PASSWORD: ',0
	LXI	H,PASSWD ;POINT TO PASSWORD
	MVI	E,0	;NO MISSED LETTERS
	IN	DPORT	;CLEAR OUT GARBAGE
PWMLP	EQU	$+OFFSET
	CALL	MINPUT	;GET A CHAR
	CPI	'U'-40H ;CTL-U?
	JZ	PASSINP ;YES, RE-GET IT
	CPI	60H	;LOWER CASE?
	JC	NOTLC	;NO,
	ANI	5FH	;MAKE UPPER CASE ALPHA
NOTLC	EQU	$+OFFSET
	CMP	M	;MATCH PASSWORD?
	JZ	PWMAT	;..YES
	MVI	E,1	;..NO, SHOW MISS
	CPI	CR	;C/R?
	JNZ	PWMLP	;..NO, WAIT FOR C/R
;PASSWORD DIDN'T MATCH
PWNMAT	EQU	$+OFFSET
	CALL	ILPRT
	DB	'++INCORRECT++',CR,LF,0
	DCR	D	;MORE TRIES?
	JNZ	PASSINP ;YES
	JMP	BADPASS ;NO, GO HANG UP
;CHARACTER MATCHED IN PASSWORD
PWMAT	EQU	$+OFFSET
	INX	H	;TO NEXT CHAR
	CPI	CR	;END?
	JNZ	PWMLP	;..NO, LOOP
;END OF PASSWORD.  ANY MISSED CHARS?
	MOV	A,E	;GET FLAG
	ORA	A
	JNZ	PWNMAT	;NOT RIGHT
;PASSWORD CORRECT
	ENDIF
;
NOPASS	EQU	$+OFFSET
;
	IF	USRLOG	;COUNT # OF SUCCESSFUL LOGONS
	LDA	NEWUSR	;GET LAST VALUE
	INR	A	;INCREMENT IT
	ENDIF
;
	IF	USRLOG AND DECIMAL
	DAA
	ENDIF		;DECIMAL
;
	IF	USRLOG
	STA	NEWUSR	;SAVE NEW VALUE
	ENDIF		;USRLOG
;
	IF	IMSAI AND USRLOG	;DISPLAY ON IMSAI
	CMA
	OUT	SENSE	;DISPLAY ON IMSAI FRONT PANEL
	ENDIF
;
	CALL	ILPRT
	DB	CR,LF,'',0	;PUT BOOT-UP MSG HERE
;
	IF	COMFILE AND CPM2
	MVI	C,32
	MVI	E,COMUSR	;SWITCH TO COM FILE USER #
	CALL	BDOS
	ENDIF
;
	IF	COMFILE
	LDA	OPTION
	CPI	'A'	;SYSOP CAN BYPASS COM FILE BY..
	JZ	0	;..TYPING "BYE /A"
	CPI	'C'	;OPER CAN ALSO GO TO COM..
	JNZ	100H	;..FILE LOAD WITH "BYE /C"
	CALL	ILPRT	;PRINT THIS MESSAGE:'
	DB	'Loading system...',CR,LF,0
	CALL	LODCOM
	JMP	100H	;EVERYONE ELSE GETS COM FILE
	ENDIF
;
	IF	NOT COMFILE
	JMP	0
	ENDIF
;
;TSTBAUD ATTEMPTS TO READ A LF OR CR, RETURNS WITH
;ZERO FLAG IF THE CHARACTER READ IS ONE OF THESE TWO.
;
TSTBAUD EQU	$+OFFSET
	CALL	MINPUT	;GET CHARACTER FROM MODEM
	CPI	CR	;IF A CARRIAGE RETURN...
	RZ		;.. RETURN
	CPI	LF	;IF A LINEFEED...
	RET		;RET ZERO FLAG, ELSE NOT ZERO
;
CARCK	EQU	$+OFFSET
;	LOSS OF CONNECTION TEST
	IF	DCHAYES
;
;THE DC HAYES HAS A HARDWARE HANGUP FEATURE, BUT WE WON'T USE IT.
;INSTEAD, IF WE DETECT THAT THERE IS NO CARRIER UPON ENTRY TO
;THIS ROUTINE, WE'LL KEEP CHECKING FOR 15 SECONDS TO SEE IF THE
;CARRIER RETURNS. IF SO, WE'LL JUST CONTINUE ON. IF NOT, WE'LL
;SIGNAL THIS BY SETTING THE CARRY FLAG.
;
	IN	STATUS	;GET MODEM STATUS
	ANI	CD	;GOT A CARRIER?
	JNZ	CARCK2	;YES, GO ON WITH TESTS
	PUSH	B	;PRESERVE SO WE CAN USE IT
	MVI	B,150	;SET FOR 15 SECONDS
CARLP	EQU	$+OFFSET
	CALL	DELAY	;WAIT .1 SECONDS
	IN	STATUS	;GET MODEM STATUS
	ANI	CD	;HAS CARRIER RETURNED?
	MOV	A,B	;PRESERVE COUNTDOWN VALUE
	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 B
	MOV	B,A	;GET COUNTER VALUE IN B
	JMP	CARLP	;KEEP CHECKING
	ENDIF
;
	IF	PMMI
;
;THE PMMI MODEM AUTOMATICALLY HANGS UP THE
;PHONE AFTER 15 SECONDS OF LOSS OF CARRIER,
;PROVIDING YOU OUTPUT TO PORT 0 TO ALLOW IT.
;(WHICH THIS PROGRAM DOES)
;
;..SO, THIS ROUTINE FIRST CHECKS IF THE MODEM
;HAS HUNG UP, AND IF SO, RETURNS WITH CARRY SET.
;IF NOT, IT CHECKS FOR CARRIER, AND RETURNS
;IF CARRIER IS ON, OTHERWISE WAITS FOR CARRIER
;WHILE STILL TESTING FOR DISCONNECT
;
;IT TESTS THE PMMI "CTS" (CLEAR TO SEND) BIT
;WHICH IS 0 WHEN THERE IS CARRIER
;
	IN	RPORT	;GET STATUS
	ANI	P2CONN	;CONNECTED?
	STC		;(IN CASE NOT)
	RNZ		;HUNG UP.
;STILL CONNECTED, CHECK FOR CARRIER
	IN	RPORT	;LOOK AT STATUS
	ANI	P2CTS	;GET CARRIER DETECT BIT
	JZ	CARCK2	;CONTINUE W/TESTS
;
;LOOP UNTIL EITHER CONNECTION LOST, OR
;CARRIER RETURNS
;
	JMP	CARCK
	ENDIF
;
;	NOW TEST DRIVE #'S AND (IF CPM 2.X)
;	USER #'S TO INSURE THAT MAXIMUMS
;	ARE NOT EXCEEDED
;
CARCK2	EQU	$+OFFSET
	LDA	4		;CHECK DISK/USER #
	ANI	0FH		;ISOLATE DRIVE
	CPI	MAX$DRIVE	;VALID DRIVE?
	JC	CARCK3		;YES, SKIP THIS JUNK
	LDA	4		;RESTORE WHOLE LOGIN BYTE
	ANI	0F0H		;RETAIN USER #
	STA	4		;FORCE DRIVE TO A
	CALL	ILPRT		;TELL USER WHAT HE DID
	DB	'INVALID DRIVE - RETURNING TO A:',0
	JMP	0		;FORCE WARM BOOT
CARCK3	EQU	$+OFFSET
;
	IF	CPM2
	LDA	4		;REFRESH LOGIN BYTE AGAIN
	ANI	0F0H		;ISOLATE USER #
	CPI	MAX$USER*16+1	;VALID USER #?
	JC	CARCK4		;YES, DON'T CHANGE
	LDA	4		;GET BACK LOGIN BYTE
	ANI	0FH		;KEEP DRIVE, ZERO USER
	STA	4
	CALL	ILPRT		;TELL HIM WHAT HAPPENED
	DB	'INVALID USER NUMBER - RETURNING TO 0',0
	JMP	0		;FORCE WARM BOOT
	ENDIF
;
CARCK4	EQU	$+OFFSET
	ORA	A
	RET
;
;	.1 SEC DELAY ROUTINE
;
DELAY	EQU	$+OFFSET
	PUSH	B
;
	IF	FASTCLK
	LXI	B,16667 	;4 MHZ TIMING CONSTANT
	ENDIF
;
	IF	NOT FASTCLK
	LXI	B,8334		;2 MHZ TIMING CONSTANT
	ENDIF
;
DELAY1	EQU	$+OFFSET
	DCX	B
	MOV	A,B
	ORA	C
	JNZ	DELAY1
	POP	B
	RET
;
;	50 MS DELAY ROUTINE
;
KDELAY	EQU	$+OFFSET
	PUSH	B
;
	IF	FASTCLK
	LXI	B,8334
	ENDIF
;
	IF	NOT FASTCLK
	LXI	B,4167
	ENDIF
;
	JMP	DELAY1
;
;PATCH IN THE NEW JMP TABLE (SAVING THE OLD)
;
PATCH	EQU	$+OFFSET
	CALL	TBLADDR ;CALC HL= CP/M JMP TABLE
	LXI	D,VCOLDBT ;POINT TO SAVE LOCATION
	MVI	B,18	;ALWAYS SAVE PRINTER VECTOR
	CALL	MOVE	;MOVE IT
;NOW MOVE NEW JMP TABLE TO CP/M
	CALL	TBLADDR ;CALC HL=CP/M'S JMP TABLE
	XCHG		;MOVE TO DE
	LXI	H,NEWJTBL ;POINT TO NEW
	CALL	MOVE	;MOVE IT
	RET
;
UNPATCH EQU	$+OFFSET
	CALL	TBLADDR ;HL=CP/M'S JMP TABLE
	XCHG		;MOVE TO DE
	LXI	H,VCOLDBT  ;GET SAVED TABLE
	CALL	MOVE	;MOVE ORIG BACK
	RET			
;
;CALCULATE HL=CP/M'S JUMP TABLE, B=LENGTH
;
TBLADDR EQU	$+OFFSET
	LHLD	1	;GET BIOS POINTER
	DCX	H	;..SKIP
	DCX	H	;..TO
	DCX	H	;..COLD BOOT
;
	IF	NOT PRINTER
	MVI	B,18	;BYTES TO MOVE
	ENDIF
;
	IF	PRINTER ;RETAIN LIST DEVICE?
	MVI	B,15	;DON'T MOVE LISTER JUMP
	ENDIF
;
	RET
;
;MOVE (HL) TO (DE), LENGTH IN (B)
;
MOVE	EQU	$+OFFSET
	MOV	A,M	;GET A BYTE
	STAX	D	;PUT AT NEW HOME
	INX	D	;BUMP POINTERS
	INX	H
	DCR	B	;DEC BYTE COUNT
	JNZ	MOVE	;IF MORE, DO IT
	RET		;IF NOT,RETURN
;
;COMMON ROUTINE TO CHECK FOR CARRIER LOST,
;CALLED FROM  CONSOLE OUT
;
CHECK	EQU	$+OFFSET
	CALL	CARCK	;SEE IF CARRIER STILL ON
	RNC		;ALL OK
;CARRIER IS LOST.  TYPE MESSAGE SO LOCAL CONSOLE
;	SHOWS THE REASON
BADPASS EQU	$+OFFSET ;COME HERE ON BAD PASSWORD
	MVI	A,1	;SHOW CARRIER LOST SO
	STA	LOSTFLG ;..WE WON'T CK AGAIN
	LXI	SP,STACK ;ENSURE VALID STACK
	CALL	ILPRT
	DB	CR,LF
	DB	'++CARRIER LOST++'
	DB	CR,LF,'   ',0
	CALL	UNPATCH ;RESTORE ORIG BIOS JMP TBL
	XRA	A	;CLEAR OUT CARRIER..
	STA	LOSTFLG ;..LOST FLAG
	JMP	HANGUP
;
;READBYTE ROUTINE - USED TO READ THE
;	WELCOME FILE
;
RDBYTE	EQU	$+OFFSET
	MOV	A,H	;TIME TO READ?
	ORA	A	;..IF AT 100H
	JZ	NORD	;NO READ REQ'D
;HAVE TO READ A SECTOR
	LXI	D,FCB
	MVI	C,READ
	CALL	BDOS
	ORA	A	;OK?
	MVI	A,1AH	;FAKE UP EOF
	RNZ		;RET EOF IF BAD
	LXI	H,80H
NORD	EQU	$+OFFSET
	MOV	A,M	;GET CHAR
	INX	H	;TO NEXT
	RET
;
;KEYBOARD/MODEM STATUS TEST ROUTINE
;
MSTAT	EQU	$+OFFSET
;
	IF	DUAL$IO ;WANT LOCAL CONSOLE?
	CALL	CONSTAT ;GET LOCAL STATUS
	ORA	A
	RNZ		;RET IF LOCAL CHAR
	ENDIF
;
	IF	DCHAYES
	IN	STATUS	;GET MODEM STATUS
	ANI	RRF	;GOT A CHARACTER?
	RZ		;RETURN IF NOT
	IN	STATUS	;GET MODEM STATUS
	ANI	FE+OE	;CHECK FOR FRAMING AND OVERRUN ERROR
	JZ	MSTAT1	;NO ERROR, CHARACTER IS VALID
	IN	DATA	;SWALLOW CHARACTER (ALSO CLEAR OE & FE)
	XRA	A	;RETURN FALSE
	RET
	ENDIF
;
	IF	PMMI
	IN	TPORT	;GET STATUS
	ANI	P0DAV	;DATA AVAILABLE?
	RZ		;RETURN IF NOT READY
	IN	TPORT	;GET STATUS
	ANI	30H	;CHECK FRAMING AND OVERRUN BITS
	JZ	MSTAT1	;NO ERRORS...LEGIT CHARACTER
	IN	DPORT	;SWALLOW CHARACTER (CLEARS PODAV)
	XRA	A	;RETURN FALSE
	RET
	ENDIF
;
MSTAT1	EQU	$+OFFSET
	MVI	A,0FFH	;SHOW READY
	ORA	A
	RET
;
;MODEM INPUT FUNCTION, CHECKS LOCAL CONSOLE FIRST
;
MINPUT	EQU	$+OFFSET
;
	IF	TIMEOUT
	PUSH	H
	LXI	H,TOVALUE*MINUTES ;INITIALIZE TIMEOUT COUNTER
	SHLD	TOCNT
	POP	H
	ENDIF
;
MINPUT1 EQU	$+OFFSET
	LDA	LOSTFLG ;KNOWN LOSS..
	ORA	A	;..OF CARRIER?
	CZ	CHECK	;CARRIER STILL ON?
	CALL	MSTAT	;ANYTHING?
	ORA	A
;
	IF	NOT TIMEOUT
	JZ	MINPUT	;LOOP TILL CHAR RCD
	ENDIF
;
	IF	TIMEOUT
	JNZ	MINPUT2
	CALL	KDELAY	;KILL 50 MS
	PUSH	H
	LHLD	TOCNT	;KNOCK DOWN TIMEOUT COUNTER
	DCX	H
	SHLD	TOCNT
	MOV	A,H
	ORA	L
	POP	H
	JNZ	MINPUT1 ;STILL TIME LEFT..KEEP TRYING
	CALL	ILPRT
	DB	'+++INPUT TIMED OUT+++',7,7,0
	JMP	NOSLASH
	ENDIF
;
MINPUT2 EQU	$+OFFSET
;
	IF	DUAL$IO ;BOTH LOCAL AND REMOTE
	CALL	CONSTAT ;CHECK LOCAL CONSOLE
	ORA	A	;CHAR?
	JNZ	CONIN	;..YES, READ IT, RET.
	ENDIF
;
;	LOCAL CONSOLE WASN'T READY, SO READ MODEM
;
	IN	DPORT	;GET DATA BYTE
	ANI	7FH	;DELETE PARITY
	JZ	MINPUT	;IGNORE NULLS
;
	IF	IMSAI AND HARDLOG
	PUSH	B
	MOV	B,A
	IN	SENSE
	ANI	LOGSW
	MOV	A,B
	POP	B
	JZ	NOLOG
	ENDIF		;END OF IMSAI CONDITIONAL
;
	IF	HARDLOG
	CPI	20H
	JNC	MINPUT3
	CPI	CR
	JNZ	NOLOG
MINPUT3	EQU	$+OFFSET
	CALL	LISTOUT ;ECHO ON PRINTER
	CPI	CR
	JNZ	NOLOG	;CR NEEDS LINEFEED
	MVI	A,LF
	CALL	LISTOUT ;SO SEND IT
	MVI	A,CR	;GET BACK CR
	ENDIF		;END OF HARDLOG
;
NOLOG	EQU	$+OFFSET
;
	CPI	3	;IS IT CONTROL-C?
	RNZ		;NO, PASS IT THRU
	LDA	0	;SEE IF WARM BOOT DISABLED
	CPI	0C3H	;JMP MEANS WARM BOOT OK
	MVI	A,3	;SO RETURN CONTROL-C
	RZ
	XRA	A	;ELSE CONVERT TO NULL
	RET
;
MOUTPUT EQU	$+OFFSET
;IF WE ALREADY KNOW CARRIER IS LOST,
;DON'T CHECK FOR IT AGAIN
	LDA	LOSTFLG ;KNOWN LOSS OF CARRIER?
	ORA	A
	CZ	CHECK	;CARRIER STILL ON?
;
	IF	DCHAYES
	IN	STATUS	;GET MODEM STATUS
	ANI	TRE	;TRANSMIT REGISTER EMPTY?
	ENDIF
;
	IF	PMMI
	IN	TPORT	;READ MODEM STATUS
	ANI	P0TBMT	;XMIT BUFF EMPTY?
	ENDIF
;
	JZ	MOUTPUT ;LOOP IF NOT READY
;
	IF	IMSAI AND BLACKOUT AND DUAL$IO
	IN	SENSE	;FLIP SWITCH UP...
	ANI	BLACKSW ;..TO BLIND REMOTE USER
	JNZ	SILENT
	ENDIF
;
	MOV	A,C	;GET CHAR
;
	IF	CK$LWC
	ANI	7FH
	CPI	60H	;CHECK FOR LOWER CASE
	JC	MOUTP2	;SKIP IF NOT LC
	CPI	7FH	;CHECK FOR RUBOUT
	JZ	MOUTP2
	PUSH	H
	LXI	H,ULCSW ;SUBTRACE EITHER 20H OR 0
	SUB	M
	POP	H
	MOV	C,A	;FORCE ON LOCAL AS WELL AS REMOTE
MOUTP2	EQU	$+OFFSET
	ENDIF
;
	OUT	DPORT	;OUTPUT TO MODEM
SILENT	EQU	$+OFFSET
;
	IF	DUAL$IO ;TO LOCAL ALSO?
	CALL	CONOUT	;SEND TO REGULAR BIOS
	ENDIF
;
;CHECK FOR NULLS
;
	CPI	LF	;TIME FOR NULLS?
	RNZ		;NO, RETURN
;SEND NULLS IF REQUIRED
	LDA	NULLS	;GET COUNT
	ORA	A	;ANY?
	RZ		;..NO
	PUSH	B
	MOV	B,A	;SAVE COUNT
	MVI	C,0	;0 IS A NULL
NULLP	EQU	$+OFFSET
	CALL	MOUTPUT ;TYPE A NULL
	DCR	B	;MORE?
	JNZ	NULLP	;..YES, LOOP
	POP	B
	RET
;
;	BOOT TRAP-BECOMES DISCONNECT IF
;	JMP AT 0 HAS BEEN ALTERED
;
MBOOT	EQU	$+OFFSET
	LDA	0	;LOOK AT OPCODE
	CPI	0C3H	;IS IT STILL JMP?
	JZ	VWARMBT ;YES, ALLOW IT
	JMP	NOSLASH ;NO, DISCONNECT
;
;	INLINE PRINT ROUTINE
;	CALL ILPRT
;	DB	'MSG',0
;
ILPRT	EQU	$+OFFSET
	XTHL		;SAVE HL, GET MSG
	PUSH	B	;SAVE
ILPLP	EQU	$+OFFSET
	MOV	C,M	;GET CHAR
	CALL	MOUTPUT ;OUTPUT IT
	INX	H	;POINT TO NEXT
	MOV	A,M	;TEST
	ORA	A	;..FOR END
	JNZ	ILPLP
	POP	B	;RESTORE
	XTHL		;RESTORE HL, RET ADDR
	RET		;RET PAST MSG
;
	IF	PWRQD	;KEEP PASSWORD HERE
;ACCESS PASSWORD (ENDS IN C/R)
;
PASSWD	EQU	$+OFFSET
	DB	'RANDY' ;THE PASSWORD ITSELF
	DB	CR	;END OF PASSWORD
;ALLOW ROOM FOR BIGGER PASSWORD TO BE
;	PATCHED IN
	DB	0,0,0,0,0,0,0,0,0,0,0,0,0
	ENDIF
;
;	ROUTINE TO LOAD THE COM FILE
;
	IF	COMFILE
LODCOM	EQU	$+OFFSET
	XRA	A	;INITIALIZE FCB
	STA	COMFCB
	LXI	H,COMFCB+12
	MVI	B,21
ZLOOP	EQU	$+OFFSET
	MVI	M,0
	INX	H
	DCR	B
	JNZ	ZLOOP
	MVI	C,OPEN	;NOW OPEN THE FILE
	LXI	D,COMFCB
	CALL	BDOS
	INR	A	;SHOULD BE NON-ZERO
	JZ	ABORT	;NO FILE, ABORT
;
;	NOW LOAD THE FILE
;
	LHLD	6	;GET TOP OF MEMORY
	LXI	D,-80H	;RECORD LOADS CAN'T START..
	DAD	D	;..ABOVE (BDOS) - 80H
	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	EQU	$+OFFSET
	POP	D	;GET TPA ADRS
	LXI	H,80H	;POINT TO NXT ADRS 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	;RE-SAVE FOR NEXT TIME
;
	MOV	A,E	;SUBTRACT: (TOP) - (ADRS)
	SUB	L
	MOV	A,D	;ONLY THE CARRY NEEDED
	SBB	H
;
	JNC	SIZEOK	;CY= BETTER MOVCPM
	CALL	ERRXIT	;SO TELL THE STORY
	DB	'++ PROGRAM AREA TOO SMALL ++','$'
;
SIZEOK	EQU	$+OFFSET
	INX	B
	PUSH	B
	PUSH	H	;SAVE TPA ADRS
	XCHG		;ALIGN REGISTERS
	MVI	C,STDMA ;TELL BDOS WHERE TO PUT RECORD
	CALL	BDOS
	LXI	D,COMFCB ;NOW READ THE RECORD
	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
	CALL	LOADOK	;PRINT THIS MSG TO CONSOLE:
	DB	'++ COM FILE LOADED ++',CR,LF,'$'
LOADOK	EQU	$+OFFSET
	POP	D
	LDA	OPTION	;SEE IF THIS WAS "BYE /C"
	CPI	'C'	;IF IT WAS THEN..
	RZ		;..DON'T PRINT MESSAGE
	MVI	C,PRINTF
	CALL	BDOS
	RET
ABORT	EQU	$+OFFSET
	CALL	ERRXIT
	DB	CR,LF
	DB	'+++CANNOT FIND COM FILE.+++','$'
ERRXIT	EQU	$+OFFSET
	POP	D
	MVI	C,PRINTF
	CALL	BDOS	;PRINT THE ABORT MSG
	JMP	0	;GIVE UP
	ENDIF

;
;THIS AREA IS USED FOR VECTORING CALLS TO THE
;USER'S CBIOS, BUT SAVING THE REGISTERS FIRST
;IN CASE THEY ARE DESTROYED.
;
CONSTAT EQU	$+OFFSET
	PUSH	B
	PUSH	D
	PUSH	H
	CALL	VCONSTAT
	POP	H
	POP	D
	POP	B
	RET
;
CONIN	EQU	$+OFFSET
	PUSH	B
	PUSH	D
	PUSH	H
	CALL	VCONIN
;
	IF	FKEYS
	CALL	CKFUNC
	ENDIF
;
	POP	H
	POP	D
	POP	B
;
;
CKFUNC	EQU	$+OFFSET
;
	IF	FKEYS AND IMSAI
	PUSH	B
	MOV	B,A	;SAVE CHAR
	IN	SENSE	;READ THE SWITCHES
	ANI	ENABLF	;CHECK FKEY ENAB SW
	MOV	A,B
	POP	B
	RZ		;NO FUNCT IF SW OFF
	ENDIF
;
	IF	FKEYS
	CPI	SYSDKEY
	JZ	SYSDOWN ;TELL CALLER TO LEAVE
	CPI	TWITKEY
	JZ	GOODBY	;MAKE CALLER LEAVE
	CPI	MSGKEY
	RNZ
	CALL	ILPRT	;SEND CALLER A MESSAGE
	DB	'MESSAGE FROM OPERATOR:',0
	MVI	A,' '	;SOMETHING TO RETURN WITH
	RET
;
SYSDOWN EQU	$+OFFSET
	CALL	ILPRT
	DB	'SYSTEM DOWN IN'
	DB	' 5 MINUTES....',0
	MVI	A,' '
	RET
	ENDIF
;
CONOUT	EQU	$+OFFSET
	PUSH	B
	PUSH	D
	PUSH	H
	CALL	VCONOUT
	POP	H
	POP	D
	POP	B
	RET
;
LISTOUT	EQU	$+OFFSET
	PUSH	B
	PUSH	D
	PUSH	H
	PUSH	PSW
	MOV	C,A
	CALL	VLISTOUT
	POP	PSW
	POP	H
	POP	D
	POP	B
	RET
;
;
;
;	THIS IS THE JMP TABLE WHICH IS COPIED
;	ON TOP OF THE ONE POINTED TO BY
;	LOCATION 1 IN CP/M
;
NEWJTBL EQU	$+OFFSET
	JMP	MBOOT	;COLD BOOT
	JMP	MBOOT	;WARM BOOT
	JMP	MSTAT	;MODEM STATUS TEST
	JMP	MINPUT	;MODEM INPUT ROUTINE
	JMP	MOUTPUT ;MODEM OUTPUT ROUTINE
	RET		;DUMMY LIST DEVICE
	NOP
	NOP
;
WELFILN EQU	$+OFFSET
	DB	0,'WELCOME    ',0
;WELCOME FILE NAME ^^^^^^^^^^^
;
NULLS	EQU	$+OFFSET
	DB	5
;
COMFCB	EQU	$+OFFSET
	DB	0,'RIBBS   COM'
PEND	EQU	$+OFFSET ;END OF RELOCATED CODE
;
;	THESE AREAS ARE NOT INITIALIZED
;
	DS	21	;REST OF COM FCB
ULCSW	EQU	$+OFFSET
	DS	1
OPTION	EQU	$+OFFSET
	DS	1
TOCNT	EQU	$+OFFSET
	DS	2
;
;
;KEEP TRACK OF LOST CARRIER WHEN TYPING
;"++CARRIER LOST++" SO WE DON'T LOOP
;
LOSTFLG EQU	$+OFFSET
	DS	1
;
;SAVE THE CP/M JUMP TABLE HERE
;
VCOLDBT EQU	$+OFFSET
	DS	3
VWARMBT EQU	$+OFFSET
	DS	3
VCONSTAT EQU	$+OFFSET
	 DS	3
VCONIN	 EQU	$+OFFSET
	 DS	3
VCONOUT  EQU	$+OFFSET
	 DS	3
VLISTOUT EQU	$+OFFSET
	 DS	3
;
;	SINCE THESE AREAS ARE NOT INITIALIZED,
;	THE FOLLOWING COUNTERS WILL NOT BE CHANGED
;	BY SUBSEQUENT LOADS OF THIS PROGRAM
;
	IF	USRLOG
OLDUSR	EQU	$+OFFSET
	DS	1
NEWUSR	EQU	$+OFFSET
	DS	1
NONUSR	EQU	$+OFFSET
	DS	1
	ENDIF
;
;
	DS	60
STACK	EQU	$+OFFSET	;LOCAL STACK
;
WRCON	EQU	2
OPEN	EQU	15
READ	EQU	20
STDMA	EQU	26
PRINTF	EQU	9
DIRECTIO EQU	6
CSTS	EQU	11
CI	EQU	1
FCB	EQU	5CH 
FCBRNO	EQU	FCB+32
;
	END

