; 
;                      	     *** SMODEM53 ***
;		for the Xerox 820-II and Hayes 1200 or 300 
;
;	                 CP/M SMARTMODEM program
;	                 =========================
;	                Version 5.30 by D Howard
;			Version 5.20 by TF Buchanan
;			Version 5.10 by JP Sojak
;			Version 3.00 by W Bladey
;
;	THIS PROGRAM WAS ORIGINALLY MODEM7.MAC WRITTEN BY 
;	WARD CHRISTENSEN AND REVISED BY M.ZEIGER AND J.MILLS FOR THE 
;	PMMI MODEM BOARD.  FULL CREDITS FOR EXPERIENCE AND TALENT THAT
;	MADE THIS program POSSIBLE, BELONG SOLELY TO THESE PEOPLE.
;
;	MANY ADDITIONAL ROUTINES INCLUDED ARE COPYRIGHTED (1980) BY
;	MARK M.ZEIGER AND J.MILLS.  PERMISSION IS GRANTED TO USE
;	BUT NOT SELL THESE ROUTINES.
;
;	FOR FULL INFORMATION ON THE USE OF 'SMODEM3', PLEASE REFER TO
;	THE FILE 'SMODEM3.DOC'.
;
;******************************************************************************
;03/12/8³     Thió versioî oæ Smodeí haó beeî especiallù designed
»	foò thå Xeroø 820-II®  Aî addeä bonuó awaitó thå ne÷ owneró of
;	the DC Hayes Smartmodem 1200.  You can use both the 300 and 1200
;	baud in this program.  You can change baud by simply typing 'S3'
;	or 'S12'.  A tip of the hat goes to Chris Neal of Dallas, Tx for his
;	concept of the 300-1200 feature within this program.
»	     Thå Disconnecô featurå haó beeî correcteä tï worë 
;	properly--it never has correctly worked right beforehand.  Those
;	of you wanting to use this program with MCI or SPRINT, these features
;	have been maintained for your useage.
»	      Tï accesó thå Commanä Mode¬ simplù uså thå <DEL¾ key®  
;	Iî previouó versionó á Control-Ï waó used¬ buô thió conflictó 
;	witè Compuserve's CPMIG. 
;		The Echo mode has been reinstalled as a ctrl-E; there are some
;	people who may need this feature. Printer toggle on/off was changed
;	to an <esc> key to allow a cntrl-P with Compuserve.
»            Thå equatå SWITCÈ allowó thå internaì selectioî oæ 30° oò 120° 
;	baud®  Thoså oæ yoõ witè otheò machineó shoulä appropriatelù changeä 
;	the  information sent to your SIO registers and Baud Port--again, 
;	these are correct for the Xerox 820-II with an SIO-0 chip.
;				+++ David Howard +++
;				    Dallas, Texas
;
;2/2/83		PERSISTENT BUGS: CRC error may cause crash dur-
;		ing download.  In terminal mode, when memory
;		buffer fills automatically begins dump (normal)
;		but continues to dump memory contents over &
;		over (apparently forever).  Does not properly dial
;		typed phone numbers if alt. LD system used.    TFB
;		Renamed SMODEM52.
;Š;2/2/83		Removed modem reset on initialization because
;		ineffectual.  Changed ALTEXIT to false.  Changed
;		OFFLIN from 'O' to 'E'.  Bypassed all ECOTOG to
;		avoid conflict (Now exits term mode with '^E'
;		rather than <ESC> or '^O' for greater compatibi-
;		lity with modem programs.                  TFB
;
;1/13/83	Added modem reset on initialization.  Alternate
;		LD mode now differentiates between SPRINT, MCI,
;		etc., if 'S/' or 'M/' used as appropriate.
;		Renamed SMODEM51A.                    TFB
;
;1/8/83		Changed '~' to '-' in redial.  Changed 'S/'
;		to 'A/' for alt. LD dialing.  Incorporated
;		FASCK into modem command routines.  Added
;		supplementary 1200 baud directory.  CONINLP
;		modified to allow lower case.           TFB
;
;1/3/83		Default to expert mode following load.  Revised
;		phone directory (TYMNET & PALATINE).        TFB
;
;12/21/82	Removed UART error detection.  Altered phone
;		directory.                                TFB
;
;12/14/82	Added 8251 UART initialization, SIO 2-2 port
;		addresses, UART error detection, & removed
;		minor errors.  Changed "Sprint" to "Alternate
;		Long distance <ALTLD> & <ALTLDFLG>        TFB
;		Renamed SMODM51A.
;
;10/08/82	Added conditional for Southern Pacific Communications
;		'Sprint' service to the dialing routine. You must
;		insert your local access and Sprint account numbers
;		in the 'spntnun' and 'loclnum' labels if this
;		conditional switch is on. This feature ia accessed
;		by a S/ in the dialing routine before the library
;		or the dialed number. Tagged this version 'smodem51'.
;		Fixed the bug that would not allow the 'R' option on 
;		the phone number - (reverse org to ans mode).
;
;01/01/82	Added Osborne 1 conditional. These routines have been 
;		tested in 'smodem3', but not in 'smodem5', keep an
;		eyeout for bugs. Added conditional for selecting an
;		ascii <esc> for terminal mode exit instead of the ^E
;		
;09-28/82	Added a re-dial upon 'NO CARRIER'. Removed the exit to
;		'terminal' mode in favor of 'menu' mode after a disconnect 
;		(^D or 'dsc'). Added code to allow an ascii comma <,> to
;		pass thru on the dial routine. (The comma tells the Smodem
;		to pause.). Sorry, could not take the 'programme', changed
;		these to 'program'. Tagged this version 'smodem5.asm'.
;
;08-29/82 	Zapped a few bugs that  destroyed the smodem3 memory immage
;		when ^R was used to recieve text files, scrolled both the 
;		menues and number library off the screen. Cleaned up the Š;		code somewhat (removed last traces of M80, and refor-
;		matted the 'asm listing, deleted garbage comments, etc)
;		Added initialization for Motorola 6850 type usarts, 450
;		baud, on a TDL SMB II 'tty' port. (450 baud if you hoogie
;		the baud rate geeneerator control pin foils)
;
;								JP Sojak
;******************************************************************************
;
TRUE    EQU 0FFH
FALSE   EQU 0
CPM2 	EQU TRUE		;TRUE=CP/M 2+...FALSE=CP/M 1+
DBFSIZ	SET 16			;DISK BUFFER SIZE IN 128 BYTE SECTORS
				;CHANGE THIS TO 8 FOR A 32K SYSTEM
				; set for the Osborne 1

ERRLIM  EQU 5 			; NUMBER OF TIMES TO RETRY
                        	; SEND/RECEIVE ERRORS BEFORE QUIT

DJBRD	EQU	FALSE		; TRUE=DISK-JOCKEY CONTROLER RS232 I/O
PORTIO	EQU	TRUE		; TRUE=RS232 I/O OTHER THAN DISK-JOCKEY
INLZE	EQU	FALSE         	; TRUE=RS232 I/O PORT INITIALIZATION
SMBII	EQU	FALSE    	; TDL SMBII 6850 USARTS 
				; (port,inlze & smbII = true)
CHEK	EQU	FALSE		; TRUE=OVERRUN,FRAMING AND PARITY
				; CHECKS NEEDED...ONLY SET TO TRUE IF
				; PORTIO=TRUE.
OSBORNE	EQU	FALSE		; IS IT AN OSBORNE 1 ?
				; (all above false for osborne = true)
	
	IF  OSBORNE
	DBFSIZ  SET 10		;LEAVE GOBS OF ROOM AT THE TOP FOR I/O
	ENDIF

SWITCH	EQU	TRUE 		; ALLOWS SELECTING 300 OR 1200 BAUD IN
				; THE PROGRAM

ALTEXIT	EQU	TRUE		; CHOOSE AN <DEL> INSTEAD OF ^O TO COMMAND
ALTLD	EQU	FALSE		;USE ALTERNATE LD DIALING

PRINTR	EQU 1BH     		;  ESC = LIST DEVICE TOGGLE-ASCII ESCAPE
ECOTOG	EQU 'E'-40H		;  ^E = TERM/ECHO TOGGLE
ALTCHR	EQU 7FH			;  ^[ = ASCII DELETE
OFFLIN  EQU 'O'-40H     	;  ^O = OFFLINE WITHOUT DISCONNECT
DISCCHR EQU 'D'-40H     	;  ^D = DISCONNECT
TRANCHR EQU 'T'-40H     	;  ^T = TRANSFER CHARACTER
DIALCHR	EQU 'A'-40H		;  ^A = Re-dial	
CAN     EQU 'X'-40H     	;  ^X = CANCEL SEND/RECEIVE
EOFCHAR EQU 'Z'-40H     	;  ^Z = END OF FILE
SAVECHR EQU 'R'-40H     	;  ^Y = RECEIVE CHARACTER
XOFF    EQU 'S'-40H     	;  ^S = XOFF CHARACTER
XON     EQU 'Q'-40H     	;  ^Q = XON CHARACTER
CRC	EQU 'C'			;  CRC CHECK INSTEAD OF CHECKSUM
SOH     EQU 1           	;  START OF HEADER
EOT     EQU 4           	;  END OF TEXTŠACK     EQU 6           	;  ACKNOWLEDGE
NAK     EQU 15H         	;  NOT ACKNOWLEDGE
BDNMCH  EQU 75H         	;  BAD NAME MATCH
OKNMCH  EQU ACK         	;  OKAY NAME MATCH
LF      EQU 0AH         	;  LINEFEED
CR      EQU 0DH         	;  CARRIAGE RETURN
FF	EQU 0CH			;  FORM FEEDE
BELL    EQU 7           	;  BELL CHARACTER
YES	EQU 59H	
NO	EQU 4EH	

	ORG	0100H

        JMP 	START		; BEGINNING OF program
;
;	IF YOU HAVE ALTERNATE LD SERVICE, FILL IN THESE DEFINE BYTES
;	IF YOU WISH SMODEM5 TO DIAL THE NUMBERS FOR YOU (ONLY IF
;	THE <ALTLD> SWITCH ABOVE IS <TRUE>
;
;MODRST    DB  '+++$ATZ',CR,'$'	; MODEM INITIALIZATION RESET **DIS**

MCINUM    DB  '--------'	; PUT YOUR LOCAL ALD OFFICE PHONE NUMBER HERE
	  DB   ',,,,,'		; ADJUST THE COMMAS FOR YOUR LOCAL ALD OFFIFE
MCICOD    DB   '-----'          ;  PUT YOUR ALTERNATE LD CODE NUMBER HERE
	  DB   ',$'		; ...TERMINATOR (MUST BE HERE)

SPRNUM	  DB  '--------'	; SAME, FOR SPRINT
	  DB  ',,,,,'
SPRCOD	  DB  '------'
	  DB  ',$'

;	PHONE NUMBER LIBRARY TABLE FOR DIALING FROM LIBRARY
;	OF NUMBERS STORED IN THESE DB'S AT ASSEMBLY-TIME.
;	EACH DB MUST BE 30 CHARACTERS LONG FOR PROPER OPERATION.
;	A 'DB 0' INDICATES NO DIALING, PROGRAM WILL DISCONNECT
;	AND RETURN TO COMMAND MODE.  LAST DB MUST BE DB 0. UP TO
;	52 NUMBERS ARE ALLOWED.
;
;		'----5---10---15---20---25---30'

NUMBLIB:DB      'A= Mississauga  1-416-826-5394'        ;'A'
        DB      'B= Bruce Rs RCP 1-201-272-1874'        ;'B'
        DB      'C= Houston Xerox1-713-789-3243'        ;'C'
        DB      'D= Dave Crane         931-8274'        ;'D'
        DB      'E= Aims RCPM    1-312-789-0499'        ;'E'
        DB      'F= Compuserve THREE   761-9040'        ;'F'
        DB      'G= Compuserve TWELVE  761-0599'        ;'G'
	DB	'H= Hull Eng  011-44-482-859169'	;'H'
	DB	'I= Allentwn RCPM1-215-398-3937'	;'I'      
        DB      'J= Time & Temp        844-4444'	;'J'
        DB      'K= Kelly Smith  1-805-527-9321'        ;'K'
        DB      'L= Maxicom ONE        931-0323'        ;'L'
	DB	'M= Atlanta CBBS 1-404-394-4220'	;'M'       
	DB	'N= BHEC RCPM    1-301-661-4447'	;'N'       
	DB	'O= Tech. CBBS   1-313-846-6127'	;'O'      Š        DB      'P= CBBS               352-4147'        ;'P'
        DB      'Q= WestfallHstn 1-713-469-8893'	;'Q'
	DB	'R= Rochester NY 1-716-425-1785'	;'R'      
	DB	'S= Amrad        1-703-734-1387'	;'S'      
	DB	'T= Flanders RCPM1-201-584-9227'	;'T'
	DB	'U= NEI RCPM     1-312-949-6189'	;'U'             
	DB	'V= PalatineRCPM 1-312-359-8080'	;'V'        
	DB	'W= Toronto-A    1-416-231-9538'	;'W'
	DB	'X= Toronto-B    1-416-231-1262'	;'X'
	DB	'Y= Chicago CBBS 1-312-545-8086'	;'Y'     
	DB	'Z= CPMUG CBBS   1-312-849-1132'	;'Z'     
;		'----5---10---15---20---25---30'
	DB      'a= Superbrain   1-617-862-0781'        ;'a'   
	DB      'b= IBM-PC BBS   1-312-647-7636'        ;'b'   
	DB      'c= Mission HUG  1-913-362-9583'        ;'c'   
	DB      'd= Los Angeles  1-213-296-5927'        ;'d'   
	DB      'e= GFRN Palos V 1-213-541-2503'        ;'e'   
	DB      'f= MOG-UR HBBS  1-213-366-1238'        ;'f'   
	DB      'g= San Diego    1-619-273-4354'        ;'g'   
	DB      'h= GFRN G Grove 1-714-534-1547'        ;'h'
	DB      'i= AnaHug RCPM  1-714-774-7860'	;'i'
	DB	'j= DataTech HUG 1-415-595-0541'	;'j'
	DB	'k= Colo Springs 1-303-634-1158'	;'k'
	DB	'l= Pinecliff    1-303-642-3034'	;'l'
	DB	'm= College Sta  1-713-693-3462'	;'m'
	DB	'n= C Forsberg   1-503-621-3193'	;'n'
;	DB	'o= ...........................'	;'o'
;	DB	'p= ...........................'	;'p'
;	DB	'q= ...........................'	;'q'
;	DB	'r= ...........................'	;'r'
;	DB	's= ...........................'	;'s'
;	DB	't= ...........................'	;'t'
;	DB	'u= ...........................'	;'u'
;	DB	'v= ...........................'	;'v'
;	DB	'w= ...........................'	;'w'
;	DB	'x= ...........................'	;'x'
;	DB	'y= ...........................'	;'y'
;	DB	'z= ...........................'	;'z'
        DB      0,'$'                                   ; end
;
;	this is a supplemental number library
;
;
;		FORUM Union NJ 1201-688-7117'	;'F'
;		Tim Nicholas 1-516-698-8619R'	;'N'
;		Bruce Ratoff  1-201-272-1874'	;'R'
;		ACGNJ ABBS    1-201-968-1074'	;'S'

        DB      0,'$'                                   ; end

;	'STYLE' DEFINES THE DIALING COMMAND THAT WILL BE SENT
;	TO THE HAYES SMARTMODEM WHEN USING THE AUTO DIALING OPTION.
;	'AT'= ATTENTION...'D'= DIAL.
;	AND THE '$'= END OF COMMAND LINE (MUST BE IN PLACE).
;	COMMANDS TO HAYES MAY ALSO BE ENTERED DIRECTLY IN TERMINAL ORŠ;	ECHO MODES.  4 EXTRA BYTES ARE ALLOTED FOR LONGER COMMANDS.

STYLE:  DB 'ATDT $'		; MODEM DIALING COMMAND...ENTER A 'P'
	DS 4			; OR 'T' FOR PULSE OR TOUCH AFTER THE
				; 'D' IF DESIRED. the <sp> is reqd.

;	'OFFHK'DEFINES THE ESCAPE AND HANG-UP CODE SENT TO THE
;	SMARTMODEM.  '+++'= THE HAYES DEFAULT ESCAPE CODE TO
;	RE-ENTER THE COMMAND STATE, AND 'ATH'= THE HANG-UP COMMND.
;	THE '$'= END COMMAND LINE (MUST BE IN PLACE). 

OFFHK:  DB '+++$ATH',CR,'$'	; MODEM ESCAPE AND 
	DS 4			; HANG-UP CODE
  
FASCLK:	DB 	true		; 2 MZ OPERATION = FALSE...4 MZ = TRUE
FASCK	EQU	FALSE
BKBYTE: DB 	TRUE    	; TRUE = MAKE .BAK FILE
XPRFLG: DB 	TRUE    	; FALSE = PRINT MENU ON INITIALIZATION
LSTFLG: DB 0			; LIST DEVICE FLAG
MACFLG: DB 0			; SEND/RECEIVE OBJECT CODE FLAG
DIALFLG	DB 0			; RE-DIAL ACTIVE FLAG
CONTFLG	DB 0FFh			; CONNECT FLAG
DLYDIA	DB 0			; DELAY STORAGE FOR RE-DIAL COMMAND

; 	PRESENTLY SET FOR DJ BOARD I/O

	IF	DJBRD		; IF DISKJOCKEY BOARD
MODATP 	EQU 0D3F8H              ; MODEM DATA PORT
MOCTLP 	EQU 0D3F9H              ; MODEM CONTROL PORT
MOSNDB 	EQU 8                   ; MODEM SEND BIT 
MOSNDR 	EQU 0                   ; MODEM SEND READY
MORCVB 	EQU 4                   ; MODEM RECEIVE BIT 
MORCVR 	EQU 0                   ; MODEM RECEIVE READY

;	I/O ROUTINES FOR DJ BOARD SERIAL PORT

INCTLP: LDA	MOCTLP 		; in modem control port
	RET

OTDATP: CMA			; out modem data port
	STA	MODATP
	CMA
	RET

ANSNDB: ANI 	MOSNDB 		; bit to test/send ready
	RET

CPSNDR:	CPI 	MOSNDR 		; value send bit/ready
	RET

INDATP: LDA	MODATP 		; in modem data port
	CMA
	RET

ANRCVB: ANI 	MORCVB 		; bit test receive readyŠ	RET

CPRCVR: CPI 	MORCVR 		; value receive ready
	RET

OTCTLP: LDA	MOCTLP 		; modem output control port
	RET
	ENDIF			; DJBOARD

	IF	OSBORNE	
MODATP 	EQU 2A01h               ;  MODEM DATA PORT
MOCTLP 	EQU 2A00h               ; MODEM CONTROL PORT
MOSNDB 	EQU 2                   ; MODEM SEND BIT 
MOSNDR 	EQU 2                   ; MODEM SEND READY
MORCVB 	EQU 1                   ; MODEM RECEIVE BIT 
MORCVR 	EQU 1                   ; MODEM RECEIVE READY

;
;	I/O ROUTINES FOR OSBORNE SERIAL RS232 PORT 
;
;	'X' pins 2 & 3. use ONLY pins 1,2,3,7 else smoke
;

INCTLP: JMP	SSTAT
	DB	' INCTLP PATCH AREA'

OTDATP: JMP	SOUT
	DB	' OTDATP PATCH AREA'

ANSNDB: ANI 	MOSNDB 		; bit to test/send ready
	RET

CPSNDR:	CPI 	MOSNDR 		; value send bit/ready
	RET

INDATP: JMP	SIN
	DB	' INDATP PATCH AREA'

ANRCVB: ANI 	MORCVB 		; bit test receive ready
	RET

CPRCVR: CPI 	MORCVR 		; value receive ready
	RET

OTCTLP	JMP	SSTAT
	DB 	' OTCTLP PATCH AREA'

	ENDIF			; OSBORNE


; 
;	SET THESE THE FOLLOWING EQUATES TO MATCH YOUR SERIAL 
;	I/O ASSIGNMENTS, AND DELETE THE ONES NOT USED.
;
Š	IF	PORTIO		; IF OTHER THAN DJBOARD
	
	IF 	SMBII
PORT	EQU	70h		; BASE ADDRESS

MOCTLP	EQU	PORT		; MODEM CONTROL PORT
MOSNDB	EQU	2		; MODEM SEND READY BIT
MOSNDR	EQU	2		; VALUE WHEN MODEM SEND READY
MORCVB	EQU	1		; MODEM RECEIVE READY BIT
MORCVR	EQU	1		; VALUE WHEN MODEM RECEIVE READY
MODATP	EQU	PORT+1		; MODEM DATA PORT
BAUDRP	EQU	PORT+1		; BAUD RATE PORT
MOCTL2	EQU	PORT+1		; 2ND MODEM CONTROL PORT
	ENDIF ;SMBII

	IF NOT SMBII
;	SET THESE THE FOLLOWING EQUATES TO MATCH YOUR SERIAL 
;	I/O ASSIGNMENTS, AND DELETE THE ONES NOT USED.

PORT	EQU	06H            	; PUT YOUR PORT BASE ADDRESS HERE
MOSTAT	EQU	06H		; STATUS PORT AGAIN LISTED
MOCTLP	EQU	06H		; MODEM CONTROL PORT HERE
MOSNDB	EQU	04H            	; MODEM SEND READY BIT (MASK)
MOSNDR	EQU	04H            	; VALUE WHEN MODEM SEND READY
MORCVB	EQU	01H            	; MODEM RECEIVE READY BIT (MASK)
MORCVR	EQU	01H            	; VALUE WHEN MODEM RECEIVE READY
MODATP	EQU	04H             ; MODEM DATA PORT HERE
BAUDRP	EQU	00H            	; BAUD RATE PORT HERE 
MOCTL2	EQU	07H            	; 2ND MODEM CONTROL PORT, IF ANY, HERE 
BAUD	EQU	00H		; BAUD RATE PORT AGAIN
	ENDIF	;NOT SMBII

	IF	CHEK
FRMER	EQU	00H		; FRAMING ERROR MASK
ORUNER	EQU	00H		; OVERRUN ERROR MASK
PARER	EQU	00H		; PARITY ERROR MASK
ERRMSK  EQU	00H		; MASK TO BLOCK ALL BITS EXCEPT
	ENDIF	;CHEK

;	I/O ROUTINES FOR SERIAL PORTS OTHER THAN DJ BOARD

INCTLP: IN	MOCTLP 		; in modem control port
	RET
OTDATP: OUT	MODATP		; out modem data port
	RET
ANSNDB: ANI 	MOSNDB 		; bit to test/send ready
	RET
CPSNDR:	CPI 	MOSNDR 		; value send bit/ready
	RET
INDATP: IN	MODATP 		; in modem data port
	RET
ANRCVB: ANI 	MORCVB 		; bit test receive ready
	RET
CPRCVR: CPI 	MORCVR 		; value receive ready
	RETŠOTCTLP: IN	MOCTLP 		; modem output control port
	RET

;	IF YOUR SERIAL PORTS MUST BE INITIALIZED SET THESE EQUATES

	IF	INLZE OR SMBII	

	INITC1	EQU	00h
	INITC2	EQU	00h
	INITC3  EQU	00H

	ENDIF		; INLZE OR SMBII

; THE FOLLOWING ROUTINE ADDRESSES THE SIO-0 Z80 UART IN THE XEROX 820-II.
; IT IS SETUP FOR THE COMMUNICATIONS PORT AND ALLOWS THE CALLER TO   
; SELECTIVELY CHOOSE BETWEEN 1200 OR 300 BAUD (IF HE HAS A SMARTMODEM 1200).
; USERS WITH ONLY A 300 BAUD MODEM SHOULD SELECT ONLY "S3" IN THE COMMAND
; MODE.

	IF 	SWITCH
SET300B:
	CALL	ILPRT
	DB	'++ BAUD RATE NOW 300 ++',CR,LF,0
	MVI	A,18H			;SET Z80 SIO FOR WORD FORMAT
	OUT	MOSTAT
	MVI	A,4			;SELECT REGISTER 4
	OUT 	MOSTAT
	MVI	A,44H			
	OUT     MOSTAT			
	MVI	A,3			;SELECT REGISTER 3
	OUT     MOSTAT
	MVI	A,0E1H
	OUT	MOSTAT
	MVI	A,5			;SELECT REGISTER 5
	OUT	MOSTAT
	MVI	A,0EAH
	OUT 	MOSTAT
	MVI	A,5			;300 BAUD
	OUT	BAUD
	JMP	XPRT
	ENDIF	;SWITCH

	IF	SWITCH
SET120B:
	CALL	SETDFLT
	JMP	XPRT
	ENDIF   ;SWITCH

	IF	SWITCH
SETDFLT:
	CALL	ILPRT
	DB	'++ BAUD RATE NOW 1200 ++',CR,LF,0
	MVI	A,18H			;SET Z80 SIO FOR WORD FORMAT
	OUT	MOSTAT
	MVI	A,4			;SELECT REGISTER 4Š	OUT 	MOSTAT
	MVI	A,44H
	OUT     MOSTAT
	MVI	A,3			;SELECT REGISTER 3
	OUT     MOSTAT
	MVI	A,0E1H
	OUT	MOSTAT
	MVI	A,5			;SELECT REGISTER 5
	OUT	MOSTAT
	MVI	A,0EAH
	OUT 	MOSTAT
	MVI	A,7			;1200 BAUD
	OUT	BAUD
	RET
	ENDIF	;SWITCH

;*****************************************************************************
;    END OF USER DEFINABLE ROUTINES --ACTUAL PROGRAM IS BELOW   
;*****************************************************************************

START:  LXI 	H,0
        DAD 	SP          	; GET CP/M'S STACK
        SHLD 	STACK      	; SAVE IT
        LXI 	SP,STACK    	; START LOCAL STACK

	IF OSBORNE
	MVI	B,OLENG		; move the I/O routines up in ram
	LXI	H,0A000H
	LXI	D,OSCODE
MOVVE	LDAX	D		; Z80 where are you (this is the hard way)???
	MOV	M,A
	INX	H
	INX	D
	DCR	B
	JNZ	MOVVE
	
	call	ilprt
	db	cr,lf,'Osborne Smartmodem',cr,lf
	db	cr,lf,'Be sure the serial RS232'
	db	cr,lf,'is set at 300 baud',cr,lf
	db	cr,lf,'   (hit any key)',cr,lf,lf,0
	jmp	time0

	db 'adjust the osborne banner display time with'
	db 'the byte following the <06>, (mimimum of 01)-->'


time0	mvi	b,2
	call	time1
	ENDIF	; osborne

	MVI A,' '
	STA FCB3+1

        CALL 	START1Š
START1:	CALL 	INITDR    	; INITIALIZE ADDRESSES
        MVI 	A,TRUE      	;  0FFH
        STA 	NFLFLG
        CMA             	;  0
        STA 	SAVFLG

        CALL 	PROCOPT    	; PROCESS CONTROL OPTIONS
        LDA 	OPTION      	; GET MAIN OPTION
        CPI 	'X'         	; EXPERT FLAG?
        JNZ 	RESTAR     	; NO
        MVI 	A,TRUE      	; YES
        STA 	XPRFLG      	; MAKE EXPERT
        JMP 	MENU

RESTAR:	LDA 	OPTION      	; GET MAIN OPTION
	CPI 	' '             ; NO OPTION SPEC'D?
	JZ	MENU
        CPI 	'M'             ; MENU ASKED FOR?
        JZ 	MENU            ; YES, GO MENU
        CALL 	MOVEFCB
        MVI 	A,FALSE
        STA 	NFLFLG

        CALL 	INDATP         	; GOBBLE UP GARBAGE..
        CALL 	INDATP         	; ..CHARACTERS ON LINE

        LDA 	OPTION      	; PROCESS MAIN OPTION
	CPI	'C'
	JZ	DIALPL

        CPI 	'E'         	; ECHO MODE?
        JZ 	TRMECHO      	; YES

        CPI 	'T'         	; TERMINAL MODE?
        JZ 	DSKSAVE      	; YES

        CPI 	'S'         	; SEND A FILE?
        JZ 	SENDFIL      	; YES

        CPI 	'R'         	; RECEIVE A FILE?
        JZ 	RCVFIL       	; YES

        CPI 	'D'         	; DISCONNECT?
        JZ 	DNTCB        	; YES, DISCONNECT & GO MENU

	CPI	'K'	    	; KILL FILE?	
	JZ	KILFIL	     	; YES, KILL FILE ON DISK 
        JMP 	MENU        	; NO OPTION SPEC'D, GO MENU

;	REVISED TERMINAL ROUTINE ALLOWING MEMORY SAVE

DSKSAVE:LDA 	NFLFLG     	; NEW FILE FLAG
        CPI 	TRUE        	; OFFH? (TRUE=NORMAL TERMINAL MODE)
        JZ 	TERM         	; YESŠ        LDA 	FCB+1       	; FIRST CHAR OF FILENAME
        CPI 	' '         	; FILE SPEC'D
        JNZ 	GOODNM      	; YES, GOOD NAME
        MVI 	A,TRUE      	; 0FFH
        STA 	NFLFLG
        CMA
        STA 	SAVFLG
        JMP 	TERM  

GOODNM:	CALL	ILPRT
        DB CR,LF,'++ IS INCOMING FILE OBJECT CODE? >>',0

	LXI	D,CMDBUF
	CALL	INBUFF
	CALL	CRLF
	LDA	CMDBUF+2
	CPI	NO
	JZ	GODNM2
	CPI	YES
	JZ	GODNM1

	CALL	ILPRT
        DB CR,LF,'++ ANSWER YES OR NO ONLY PLEASE! ++',CR,LF,0
	JMP	GOODNM

GODNM1:	MVI	A,0FFH
	STA	MACFLG		; SET CODE FLAG ON	

GODNM2: CALL 	ERASFIL
        CALL 	MOVE2
        LXI 	D,FCB3
        MVI 	C,MAKE
        CALL 	BDOS
        LXI 	D,FCB3
        MVI 	C,OPEN
        CALL 	BDOS
        LXI 	H,BOTRAM
        SHLD 	HLSAVE
        MVI 	A,FALSE
        STA 	NFLFLG

TERM:   CALL 	STAT         	; KEYPRESS?
        JZ 	TERML        	; NO, CHECK LINE
        CALL 	KEYIN        	; GET CHAR FROM KBD

	CPI	ECOTOG	     	; ^E?	
	JNZ	TERM10

	CALL	ILPRT
        DB CR,LF,'++ ECHO ON ++',CR,LF,0
	JMP	TRMECHO      	; YES, GO ECHO MODE

TERM10: 
	IF NOT ALTEXIT
	CPI 	OFFLIN      	; ^O?Š        
	ELSE
	CPI	ALTCHR		; ASCII ESCAPE
	ENDIF

	JZ 	MENU         	; YES, RETURN TO MENU

	cpi	dialchr		; re-dial character?
	jz	redial		; yes, do it

        CPI 	DISCCHR      	; ^D?
        JZ 	DNTCB        	; YES, DISCONNECT & RETURN TO MENU

LST:	CPI	PRINTR	     	; esc?	
	JNZ	TERCON	     	; NO OUTPUT TO LIST DEV...CONT.
	LDA	LSTFLG       	; GET LIST DEV.TOGGLE	
	CMA		     	; MAKE TOGGLE
	STA	LSTFLG       	; SAVE IT 		
	INR	A
	JNZ	LST1

	CALL	ILPRT
        DB CR,LF,'++ PRINTER ON ++',CR,LF,0
	JMP	TERM

LST1:	CALL	ILPRT
        DB CR,LF,'++ PRINTER OFF ++',CR,LF,0
	JMP	TERM

TERCON: CPI 	TRANCHR      	; ^T TEST FOR TRANSFER REQUEST 
        CZ 	TRANSFER     	; SEND-A-FILE (BLIND SEND)
        JZ 	TERM         	; LOOP

	CPI 	SAVECHR	     	; ^R TEST FOR RECEIVE REQUEST
        JNZ 	NOTOG	     	; NO, CONT.

        LDA 	NFLFLG     	;  YES BUT, DO NOT ALLOW SAVE IF..
        CPI 	TRUE        	; ..THIS FLAG IS SET.
        JZ 	TERML
	LDA	SAVFLG       	; SAVE DATA TO DISK?	
	CMA		     	; MAKE TOGGLE
	STA	SAVFLG       	; SAVE IT 		
	INR	A
	JNZ	PRR1

	CALL	ILPRT
        DB CR,LF,'++ RECEIVE ON ++',CR,LF,0
	JMP	TERML

PRR1:	CALL	ILPRT
        DB CR,LF,'++ RECEIVE OFF ++',CR,LF,0
	JMP	TERML

redial	lda	contflg		; any change allowed ??
	ora	aŠ	jnz	terml		; no, must be 'CONNECT' or error

	lda	dialflg		; toggle the flag
	ora	a
	jz	dsdial	

ebldial	xra	a
	sta	dialflg
	call	ilprt
	db CR,LF,'++ RE-DIAL DISABLED ++',cr,lf,0
	jmp	terml	

dsdial	dcr	a		; 00-> FF
	sta	dialflg
	sta	pswtmp		; flag initial re-dial
	call	ilprt
	db CR,LF,'++ RE-DIAL ENABLED ++',cr,lf
	db 'Enter delay 0-9 (0~3 Min) ? ... ',0

getdly	mvi	c,1		; console input (dont know the 'equ' and too 
	call	bdos		; too lazy to look for it
	ani	7Fh
	cpi	'0'		; > '0'
	jc	getdly
	cpi	'9'+1		; < '9' +1
	jnc	getdly
	push	psw
	call	ilprt
	db ' ... ok',cr,lf,0
	pop	psw
	cmc
	ani	00001111B
	push	psw
	add	a		; 2x
	add	a		; 4x
	add	a		; 8x
	mov	b,a	 	; save 8x
	add	a		; 16x
	add	b		; 16x+8x=24x	
	mov	b,a		; save 24x
	pop	psw		; 1x
	add	b		; +1x+24x=25x
	ora	a
	jnz	nonzro
	mvi	a,1		; fix for zero
nonzro	sta	dlydia		; delay constant 1-255 (0-3 minutes @ 5.6 Mhz)

	mvi	a,cr		; give the modem something to abort dial
	call	otdatp
	
onemor	lxi	b,1250*40	; 4 seconds or so should do it
waitn	call	timerl		; get a character or timeout
	jz	dodial		; timed out, the modem is in command mode
	jmp	onemor		; wait for time out
Šdodial	call	ilprt
	db CR,LF,'NO CARRIER <redial>'
	db cr,lf,'(any key to abort timeout)',cr,lf,0

	lda	dlydia		; delay constant
	mov	b,a
	call	time1
	call	indatp		; gobble garbage in both buffers
	call	indatp

	jmp	dialp1		; and do a dial

;	universal delay sets zero on timeout, carry if aborted	
;	seconds in <b>, <a> crushed unless abort, then <a>=char typed

time1	push	b		; save existing <bc>
	push	h		; and <hl>

time1y	mvi	c,3		; for a 1 sec delay

time1x	lxi	h,0FFFFh	; trim here             

	time2	dcx	h
	mov	a,h
	ora	l
	jnz	time2
	push	psw
	push	b
	mvi	c,11		;  key press	
	call	0005		;  abort ??
	ora	a
	jnz	timeabt
	pop	b
	pop	psw

	dcr	c		; set up for 'c'th pass
	jnz	time1x		; do it if <c> not zero

;	1 sec has passed

	dcr	b		; <b> seconds
	jnz	time1y		; again ?

	pop	h		; nope, exit
	pop	b
	stc			; be sure it is off
	cmc
	ret
;
;	keypress abort time loop
;

timeabt	mvi	c,1		; clear the port
	call	bdos
	ani	7FhŠ	stc			; flag abort
	pop	b		; fix stack...
	pop	b		; ... ditto
	pop	h		; restore <hl>
	pop	b		; and <bc>
	ret			; exit

NOTOG:  CALL 	OTDATP

TERML:  CALL 	INCTLP
        CALL 	ANRCVB
        CALL 	CPRCVR
        JNZ 	TERM
        CALL 	INDATP

	PUSH	PSW			; SAVE ORG.CHAR.
	LDA	MACFLG			; GET MACHINE LANG.FLAG
	INR	A			; MACHINE LANG.COMING THROUGH?
	JZ	TERML9			; YES...SKIP FILTER

	POP	PSW			; SAVE ORIG.CHAR
        CPI 	00H          	; CHECK FOR NULLS
        JZ 	TERM         	; DON'T PROCESS THEM
        ANI 	7FH          	; STRIP PARITY
	PUSH	PSW			; SAVE FILTERED CHAR.

;
;	The following code in lower case is responsible for
;	the re-dial. Don't bother with the 'non-verbose'
;	mode as it is a LOT of grief. Just grab the ascii
;	and parse it for '<N>o carrier'. Abort on all else.

	lda	contflg		; reedial allowed??
	ora	a
	jnz	terml9		; not allowed, quit

	lda	dialflg		; re-dial flag set ?
	ora	a
	jz	terml9		; no, quit

	pop	psw		; look for the 1st ascii char only
	push	psw
	cpi	'N'		; was it a 'NO CARRIER' ?
	jz	doadial		; if so, do a redial

	cpi	'C'		; or a 'CONNECT' ?
	jz	killdl		; kill the redial pending

	cpi	'O'		; or an 'OK' ?? (what)
	jz	killdl

	cpi	'E'		; or an 'ERROR'
	jz	killdl		

	jmp	terml9		; none of these, echo it and get anotherŠ
killdl	xra	a
	sta	dialflg		; clear the re-dial flag
	dcr	a		; set the no redial not allowed flag
	sta	contflg
	jmp	terml9

doadial	pop	psw		; fix stack
	mvi	a,0FFh
	sta	dialflg		; reset the re-dial flag
	call	ilprt
	db cr,lf,'NO CARRIER <redial>',cr,lf,0
		
;	give the exchange time to get its act together

	lda	dlydia		; delay constant	
	mov	b,a
	call	time1
	jnc	nokill	
	mvi	a,cr		; give the modem a cr
	call	otdatp

nokill	call 	indatp		; gobble, gobble
	call	indatp
	jmp	dialp1		; redial

TERML9:	POP	PSW			; SAVE FILTERED OR ORG.CHAR. 
	PUSH	PSW			; SAVE IT AGAIN
	CALL	TYPE
	LDA	LSTFLG
	INR	A
	JNZ	PUSHON
	POP	PSW
	CALL	LISTDV
	JMP	TERM

PUSHON: LDA 	SAVFLG		;  save mode
        INR 	A
        JNZ 	NOSAVE		;  no, skip the memory write
        POP 	PSW
	lhld	hlsave		;  8-13/82 fix ^R crushing smodem3.com
        MOV 	M,A
        INX 	H
        SHLD 	HLSAVE     	; MENU COMMAND DESTROYS HL-REG..
                         	; ..GET HL WHEN ENTERING VIA 'RET' CMD.
	CPI 	LF          	; IF NO FRONT PANEL, THEN..
        JNZ 	NOCOLON     	; ..TYPE ":" AFTER EACH LINE FEED..
        MVI 	A,':'       	; ..WHEN MEMORY SAVE ACTIVE.
        CALL 	TYPE

NOCOLON:LDA 	07H           	; CHECK TO SEE IF..
        DCR 	A           	; ..PAGE BELOW BDOS HAS BEEN..
        CMP 	H           	; ..REACHED AND DISKSAVE IS NEEDED.
        CZ 	INTDSSV
Š	JMP	TERM
NOSAVE:	POP	PSW
	JMP	TERM

SAVFLG:	DB FALSE
LSTBY1:	DB 0
LSTBY2:	DB 0


INTDSSV:MVI A,XOFF      	; SEND A CTRL-S TO STOP..
        CALL OTDATP        	; ..REMOTE COMPUTER OUTPUT.

        MVI D,0         	; D IS THE BUFFER COUNT
        CALL INMODEM    	; GET LAST BYTES SENT..
        STA LSTBY1    		; ..AFTER CTRL-S.
        CALL INMODEM    	; ADD MORE CALLS TO INMODEM..
        STA LSTBY2    		; ..AND STA LASTBYT# IF YOU ARE..
                        	; ..LOSING BYTES WHEN MEMORY IS FULL.
        PUSH D
        CALL NMREC1
        CALL WRTDSK     	; WRITE THE RECORDS
        POP D

        LXI H,BOTRAM
        INR D
        DCR D           	; TEST BUFFER COUNT FOR ZERO
        JZ CTRLQ
        LDA LSTBY1    		; GET THE LAST BYTES THAT WERE..
        MOV M,A         	; ..SAVED AND PUT THEM IN..
        INX H           	;..BOTRAM.
        CALL TYPE
        DCR D
        JZ CTRLQ
        LDA LSTBY2
        MOV M,A
        INX H
        CALL TYPE

CTRLQ:  MVI A,XON       	; SEND START CHARACTER..
        CALL OTDATP        	; ..TO REMOTE COMPUTER.
        RET

;
;	THIS SUBROUTINE WILL LOOP UNTIL THE MODEM RECEIVES A CHARACTER
;	OR 100 MILLISECONDS. IF A CHARACTER IS RECEIVED, A FLAG IS SET
;	TO STORE THE CHARACTER.A MAXIMUM OF TWO CHARACTERS ARE STORED,
;	BUT MORE MAY BE STORED IF DESIRED (SEE COMMENT IN "INTDSSV"
;	ABOVE).
;

INMODEM:LXI B,1250

TIMERL: CALL INCTLP
        CALL ANRCVB
        CALL CPRCVRŠ        JZ GETBYTE
        DCX B
        MOV A,B
        ORA C
        JNZ TIMERL
        RET
GETBYTE:CALL INDATP
        INR D
        RET

NMRECS:MVI M,EOFCHAR
        INX H
        LXI D,127
        DAD D

NMREC1:LXI D,-(BOTRAM)
        DAD D
        MOV A,L         	; DIVIDE HL BY 128..
        ORA A
        RAL             	; ..TO GET THE..
        MOV L,H         	; ..NUMBER OF SECTORS
        MVI H,0
        PUSH PSW
        DAD H
        POP PSW
        MVI A,0
        ADC L
        MOV L,A         	; RETRNS WITH NUMBER OF..
        RET             	; ..128 BYTE RECORDS IN HL.

WRTDSK: LXI D,BOTRAM

NEXTWRT:MVI C,STDMA
        CALL BDOSRT
        PUSH D
        LXI D,FCB3
        MVI C,WRITE
        CALL BDOSRT
        POP D
        XCHG
        PUSH D
        LXI D,128
        DAD D
        POP D
        XCHG
        DCX H
        MOV A,H
        ORA L
        JNZ NEXTWRT
        RET

CLOSE3: LXI D,FCB3
        MVI C,CLOSE
        CALL BDOS
        RETŠ
BDOSRT: PUSH B 
	PUSH D 
	PUSH H 
	PUSH PSW
        CALL BDOS
        POP PSW 
	POP H 
	POP D 
	POP B
        RET

MOVE2:  LXI H,FCB3
        CALL INITFCB
        LXI H,FCB
        LXI D,FCB3
        MVI B,12
        CALL MOVE
        RET

;
;	 FILE TRANSFER ROUTINE - CALLED WITH 
;	CONTROL-T FROM TERMINAL ROUTINE.
;	TRANSFER MAY BE CANCELLED WHILE SENDING BY USING CONTROL-X.
;

TRANSFER:
        PUSH H 
	PUSH D 
	PUSH B 
	PUSH PSW
        LXI H,FCB4
        CALL INITFCB   		; INITIALIZES FCBS POINTED..
        LXI H,FCB+16    	;..TO BY HL REG.
        CALL INITFCB

GET:    CALL GETNAME
        LDA CMDBUF+2    	; WAS FILE ENTERED
        CPI 20H
        JZ TRNSL2
        CALL MOVE4
        CALL OPEN4
        CPI 0FFH        	; RETURN WITH 0FFH MEANS
        JNZ CONTIN      	; FILE DOES NOT EXIST

TRNSL1:CALL ILPRT
        DB CR,LF,'++ FILE DOES NOT EXIST ++',CR,LF,0

TRNSL2:CALL ILPRT
        DB '   ...TYPE ''R'' TO RETURN TO MODEM ++',CR,LF
        DB '   ...TYPE ''A'' TO RE-ENTER NAME ',CR,LF
	DB '      COMMAND >>',BELL,0

        CALL KEYIN
        CALL UCASEŠ        CALL TYPE       	; ECHO RESPONSE
        CALL CRLF
        CPI 'A'
        JZ GET
        CPI 'R'
        JZ RETURN
        JMP TRNSL2

CONTIN: LXI D,80H
        MVI C,STDMA
        CALL BDOS

READMR: CALL READ80
        CPI 1           	; END OF FILE
        JZ RETRNS
        CPI 2           	; BAD READ
        JZ RETRNU
        CALL SEND80C
        CPI EOFCHAR     	; END OF FILE - OMIT IF OBJECT..
        JZ RETRNS      		; ..CODE IS TO BE SENT.
        CPI CAN         ;CANCELLATION?
        JZ TRANCAN
        JMP READMR

RETRNS:CALL ILPRT
        DB CR,LF,'++ FILE TRANSFER COMPLETED ++',CR,LF,BELL,0

        JMP RETURN

RETRNU:CALL ILPRT
        DB CR,LF,'++ FILE TRANSFER UNSUCCESSFUL ++',CR,LF,BELL,0
        JMP RETURN

TRANCAN:CALL ILPRT
        DB CR,LF,'++ TRANSFER CANCELLED ++',CR,LF,BELL,0

RETURN: XRA A
	STA MACFLG
	POP PSW 
	POP B 
	POP D 
	POP H
        RET

	                	; ENTRY AT +2 WILL LEAVE..
INITFCB:MVI M,0         	; ..DRIVE NO. INTACT.
        INX H           	; WILL INITIALIZE AN FCB..
        MVI B,11        	; ..POINTED TO BY HL-REG. FILLS 1ST POS

LOOP10: MVI M,' '       	; ..WITH 0, NEXT 11 WITH..
        INX H           	; ..WITH BLANKS, AND LAST..
        DCR B           	; ..21 WITH NULLS.
        JNZ LOOP10
        MVI B,21
ŠLOOP11: MVI M,0
        INX H
        DCR B
        JNZ LOOP11
        RET

GETNAME:CALL ILPRT
DB  CR,LF,'++ IS OUTGOING FILE OBJECT CODE? >>',0

	LXI	D,CMDBUF
	CALL	INBUFF
	CALL	CRLF
	LDA	CMDBUF+2
	CPI	NO
	JZ	GTNAM2
	CPI	YES
	JZ	GTNAM1

	CALL	ILPRT
	DB  CR,LF,'ANSWER YES OR NO ONLY PLEASE!',CR,LF,0
	JMP	GETNAME

GTNAM1:	MVI	A,0FFH
	STA	MACFLG			; SET CODE FLAG ON	

GTNAM2: CALL ILPRT
DB CR,LF,'++ ENTER FILE NAME TO BE TRANSFERRED...C/R TO QUIT ++ ',CR,LF
DB '   COMMAND >>',0

        LXI D,CMDBUF
        CALL INBUFF
        CALL CRLF
        RET

MOVE4:  LXI D,CMDBUF
        LXI H,FCB4
        CALL CPMLINE
        RET

OPEN4:  LXI D,FCB4
        MVI C,OPEN
        CALL BDOS
        RET

READ80: LXI D,FCB4
        MVI C,READ
        CALL BDOS
        RET

SEND80C:MVI B,80H
	LXI H,80H

SENDCH1:PUSH B
	PUSH D
	PUSH HŠ	CALL INDATP
	CPI  XOFF
	JNZ  SNDCH9

TWO:	CALL STAT
	JZ   THREE
	CALL KEYIN
	CPI  CAN
	JZ   SNDCH9	

THREE:	CALL INDATP
	CPI  XON
	JNZ  TWO

SNDCH9: POP H
	POP D
	POP B
	CPI CAN
	RZ

	MOV A,M
        CALL MODOUT

	PUSH PSW
	LDA  MACFLG
	INR  A
	JZ   SNDC1	

	POP  PSW
        CPI EOFCHAR
        RZ
	PUSH PSW

SNDC1:  POP  PSW		; RESTORE STACK
	CALL STAT       	; TEST TO SEE IF
        ORA A           	; CANCELLATION REQUESTED
        JZ SKIP12
        CALL KEYIN
        CPI CAN
        RZ

SKIP12: INX H
        DCR B
        JNZ SENDCH1
        RET

MODOUT: PUSH PSW

MODOTL: CALL OTCTLP
        CALL ANSNDB
        CALL CPSNDR
        JNZ MODOTL
        POP PSW
        CALL OTDATP
        CALL TYPEŠ        RET

FCB4:   DS 33

; 	TERMINAL ECHO MODE

TRMECHO:CALL INCTLP
        CALL ANRCVB
        CALL CPRCVR
        JNZ KEYBRD

LINECHR:CALL INDATP

LINEC2:	CALL MODOUT

	PUSH PSW
	LDA  LSTFLG
	INR  A
	JNZ  KYCONT
	POP  PSW
	CALL LISTDV
	PUSH PSW

KYCONT: POP  PSW
	CPI  CR
	JNZ  TRMECHO
	MVI  A,LF
	JMP LINEC2

KEYBRD: CALL STAT
        JZ TRMECHO
        CALL KEYIN

	CPI  ECOTOG
	JNZ  KEYBR3

	CALL ILPRT
        DB CR,LF,'++ ECHO OFF ++',CR,LF,0
	JMP  TERM

KEYBR3: 
	IF NOT ALTEXIT
	CPI OFFLIN
        
	ELSE
	CPI ALTCHR
	ENDIF

	JZ MENU

	CPI DISCCHR
	JZ  DNTCB

	CPI PRINTR	     	; ^P? 	
	JNZ KEYBR2	     	; NO OUTPUT TO LIST DEV...CONT.Š	LDA LSTFLG           	; GET LIST DEV.TOGGLE	
	CMA		     	; MAKE TOGGLE
	STA LSTFLG           	; SAVE IT 		
	JMP TRMECHO

KEYBR2:	CALL MODOUT
	CPI  CR
	JNZ  TRMECHO
	MVI  A,LF
	JMP  KEYBR2
;RESET DISKS ROUTINE
NEWDSK: PUSH PSW
	PUSH B
	PUSH D
	PUSH H
	MVI  C,RCDSK
	CALL BDOS
	STA  SCDSK
	MVI  C,RESET		;RESET THE DISKS
	CALL BDOS
	LDA  SCDSK		;GET BACK ORIGINAL LOGGED DISK
	MOV  E,A
	MVI  C,SELDSK		;...LOG IT IN AGAIN
	CALL BDOS
	POP  H
	POP  D
	POP  B
	POP  PSW
	RET
;LOG DRIVE ROUTINE
LOGON:	LDA  CMDBUF+6		;GET DRIVE
	CPI  ' '		;NO DRIVE SPECIFIED
	JZ   XPRT9		;THEN LEAVE
        SUI  41H		;MAKE DRIVE #
	MOV  E,A
	MVI  C,SELDSK		;AND LOG IT
	CALL BDOS
	JMP  XPRT9
;	ERASE A FILE FROM DISK

KILFIL:	LDA FCB+1
	CPI ' '
	JZ  BLKFILE
	LXI D,FCB
	MVI C,SRCHF
	CALL BDOS
	INR A
	JNZ KILFL2

	CALL ILPRT
        DB CR,LF,'++ FILE DOES NOT EXIST ++',CR,LF,0
	JMP XPRT

KILFL2: LXI D,FCB
	MVI C,ERASEŠ	CALL BDOS
	JMP XPRT

;	SEND A CP/M FILE

SENDFIL:LDA BATCHFLG    	; CHECK IF MULTIPLE FILE..
        ORA A           	; ..MODE IS SET.
        JNZ SENDC1
        MVI A,TRUE      	; INDICATE BATCH SEND
        STA SENDFLG
        LDA FSTFLG      	; IF FIRST TIME THRU..
        ORA A           	; ..SCAN THE COMMAND LINE..
        CNZ TNMBUF      	; ..FOR MULTIPLE NAMES.
        CALL SENDFN     	; SENDS FILE NAME TO RECEIVER
        JNC SENDC2      	; CARRY SET MEANS NO MORE FILES.
        MVI A,'B'       	; STOP BATCH..
        STA BATCHFLG    	; ..MODE OPTION.
        MVI A,EOT       	; FINAL XFER END
        CALL SEND
        JMP DONE

SENDC1: LDA FCB+1
        CPI ' '
        JZ BLKFILE

SENDC2:	CALL 	CNREC
	CALL OPENFIL
        MVI E,80
        CALL WAITNAK

SENDLP: CALL RDSECT
        JC SENDEOF
        CALL INCRSNO
        XRA A
        STA ERRCT

SENDRPT:CALL SENDHDR
        CALL SENDSEC
	LDA  CRCFLG		; CRC REQUEST?
	ORA  A
	CZ   SNDCRC		; YES...SEND CRC CHECKS
	CNZ  SENDCKS		; NO...SEND CHECKSUMS
        CALL GETACK
        JC SENDRPT
        JMP SENDLP

SENDEOF:MVI A,EOT
        CALL SEND
        CALL GETACK
        JC SENDEOF
        JMP DONE

;	RECEIVE A FILE

RCVFIL: LDA BATCHFLG    	; CHECK IF MULT..Š        ORA A           	; ..FILE MODE.
        JNZ RCVC1
        MVI A,FALSE     	; FLAG WHERE TO RETURN..
        STA SENDFLG     	; ..FOR NEXT FILE TRANS.
        CALL GETFN      	; GET THE FILE NAME.
        JNC RCVC2       	; CARRY SET MEANS NO MORE FILES.
        MVI A,'B'       	; STOP BATCH..
        STA BATCHFLG    	; ..MODE OPTION.
        JMP DONE

RCVC1:  LDA FCB+1       	; MAKE SURE FILE IS NAMED
        CPI ' '
        JZ BLKFILE
        JMP RCVC3

RCVC2:  CALL CKCPM2
        CALL CKBAKUP

RCVC3:  CALL ERASFIL
        CALL MAKEFIL
        LDA QFLG
        ORA A
	JZ  RCVFST
        LDA BATCHFLG
        ORA A           	; DON'T PRINT MSSG IF..
	JZ  RCVFST		; ...IN MULTI AND QUIET MODE.

        CALL ILPRT
        DB CR,LF,'++ FILE OPEN, READY TO RECEIVE ++',CR,LF,0

RCVFST: LDA CRCFLG
	ORA A
	MVI A,NAK
	JNZ RCVFL2
	MVI A,CRC

RCVFL2: CALL SEND

RCVLP:  CALL RCVSECT
        JC RCVEOT
        CALL WRSECT
        CALL INCRSNO
        CALL SENDACK
        JMP RCVLP

RCVEOT: CALL WRBLOCK
        CALL SENDACK
        CALL CLOSFIL
        JMP DONE
        
; 	SUBROUTINES

SENDFN: LDA QFLG
        ORA A
        JZ SWNAKŠ
        CALL ILPRT
        DB CR,LF,'++ AWAITING NAME NAK ++',CR,LF,0

SWNAK:  MVI E,80
        CALL WAITNLP
        MVI A,ACK       	; GOT NAK, SEND ACK
        CALL SEND
        LXI H,FILECT
        DCR M
        JM NOMRNM
        LHLD NBSAVE     	; GET FILE NAME..
        LXI D,FCB       	; ..IN FCB
        MVI B,12
        CALL MOVE
        SHLD NBSAVE
        CALL SENDNM     	; SEND IT
        ORA A           	; CLEAR CARRY
        RET

NOMRNM: MVI A,EOT
        CALL SEND
        STC
        RET

SENDNM: PUSH H

SNDNM1: MVI D,11        	; COUNT CHARS IN NAME
        MVI C,0         	; INIT CHECKSUM
        LXI H,FCB+1     	; ADDRESS NAME

NAMLPS: MOV A,M         	; SEND NAME
        ANI 7FH         	; STRIP HIGH ORDER BIT SO CP/M 2..
        CALL SEND       	; ..WON'T SEND R/O FILE DESIGNATION.
        LDA QFLG        	; SHOW NAME IF..
        ORA A           	; ..QFLG NOT SET.
        MOV A,M
        CNZ TYPE

ACKLP:  PUSH B          	; SAVE CKSUM
        MVI B,1         	; WAIT FOR RECEIVER..
        CALL RECV       	; ..TO ACKNOWLEDGE..
        POP B           	; ..GETTING LETTER.
        JC SCKSER
        CPI ACK
        JNZ ACKLP
        INX H           	; NEXT CHAR
        DCR D
        JNZ NAMLPS
        MVI A,EOFCHAR   	; TELL RECEIVER END OF NAME
        CALL SEND
        LDA QFLG
        ORA A
        CNZ CRLF
        MOV D,C         	; SAVE CHECKSUMŠ        MVI B,1
        CALL RECV       	; GET CHECKSUM..
        CMP D           	; ..FROM RECEIVER.
        JZ NAMEOK

SCKSER: MVI A,BDNMCH    	; BAD NAME-TELL RECEIVER
        CALL SEND
        LDA QFLG
        ORA A
        JZ SKCSR1

        CALL ILPRT
        DB CR,LF,'++ CHECKSUM ERROR ++',CR,LF,0

SKCSR1:MVI E,80        		; DO HANDSHAKING OVER
        CALL WAITNLP    	; DON'T PRINT "AWAITING NAK" MSG
        MVI A,ACK
        CALL SEND
        JMP SNDNM1

NAMEOK: MVI A,OKNMCH    	; GOOD NAME-TELL RECEIVER
        CALL SEND
        POP H
        RET     

GETFN:  LXI H,FCB
        CALL INITFCB+2 		; DOES NOT INITIALIZE DRIVE
        LDA QFLG
        ORA A
        JZ GNAMELP

        CALL ILPRT
        DB CR,LF,'++ AWAITING FILE NAME ++',CR,LF,0

GNAMELP:CALL HSNAK
        JC GNAMELP
        CALL GETNM      	; GET THE NAME
        CPI EOT         	; IF EOT, THEN NO MORE FILES
        JZ NMRNMG
        ORA A           	; CLEAR CARRY
        RET

NMRNMG: STC
        RET

GETNM:  PUSH H

GETNM1: MVI C,0         	; INIT CHECKSUM
        LXI H,FCB+1

NAMELPG:MVI B,5
        CALL RECV       	; GET CHAR
        JNC GETNM3
        LDA QFLG
        ORA AŠ        JZ GETNM2

        CALL ILPRT
        DB CR,LF,'++ TIME OUT RECEIVING FILENAME ++',CR,LF,0

GETNM2: JMP GCKSER

GETNM3: CPI EOT         	; IF EOT, THEN NO MORE FILES
        JZ GNRET
        CPI EOFCHAR     	; GOT END OF NAME
        JZ ENDNAME
        MOV M,A         	; PUT NAME IN FCB
        LDA QFLG        	; TYPE IT IF NO QFLG
        ORA A
        MOV A,M
        CNZ TYPE
        PUSH B          	; SAVE CKSUM
        MVI A,ACK       	; ACK GETTING LETTER
        CALL SEND
        POP B
        INX H           	; GET NEXT CHAR
        MOV A,L         	; DON'T LET NOISE...
        CPI 7FH         	; ..CAUSE OVERFLOW..
        JZ GCKSER       	; ..INTO PROGRAM AREA.
        JMP NAMELPG

ENDNAME:LDA QFLG
        ORA A
        CNZ CRLF
        MOV A,C         	; SEND CHECKSUM
        CALL SEND
        MVI B,1
        CALL RECV       	; CHECKSUM GOOD?
        CPI OKNMCH      	; YES IF OKNMCH SENT..
        JZ GNRET        	; ..ELSE DO OVER.

GCKSER: LXI H,FCB       	; CLEAR FCB (EXCEPT DRIVE)..
        CALL INITFCB+2 		; ..SINCE IT MIGHT BE DAMAGED..
        LDA QFLG        	; ..BY TOO MANY CHARS.
        ORA A
        JZ GCKSR1

        CALL ILPRT
        DB CR,LF,'++ CHECKSUM ERROR ++',CR,LF,0

GCKSR1:CALL HSNAK      		; DO HANDSHAKING OVER
        JC GCKSR1
        JMP GETNM1

GNRET:  POP H
        RET

HSNAK:  MVI A,NAK       	; SEND NAK UNTIL..
        CALL SEND       	; ..RECEIVING ACK.
        CALL CKABORT    	; DON'T GET HUNG UP HEREŠ        MVI B,2         	; WAIT 2 SECONDS..
        CALL RECV       	; ..IN RECEIVE.

        CPI CAN         	; IF SENDER ABORTS..
        JZ ABORT        	; ..DURING NAME TRANSFER.

        CPI ACK         	; IF NAK,RETURN WITH..
        RZ              	; ..CARRY CLEAR.
        STC
        RET

TNMBUF: MVI A,FALSE     	; CALL FROM SENDFIL ONLY ONCE.
        STA FSTFLG
        STA FILECT
        CALL SCAN
        LXI H,NAMEBUF
        SHLD NBSAVE     	; SAVE ADDR OF 1ST NAME

TNLP1:  CALL TRTOBUF
        LXI H,FCB
        LXI D,FCBBUF
        CALL CPMLINE    	; PARSE NAME TO CP/M FORMAT

TNLP2:  CALL MFNAME		; SEARCH FOR NAMES (* FORMAT)

        JC NEXTNM
        LDA FCB+10      	; IF CP/M 2 $SYS FILE..
        ANI 80H         	; ..DON'T SEND
        JNZ TNLP2
        LHLD NBSAVE     	; GET NAME
        LXI D,FCB       	; MOVE IT TO FCB
        XCHG
        MVI B,12
        CALL MOVE
        XCHG
        SHLD NBSAVE     	; ADDR OF NEXT NAME
        LXI H,FILECT    	; COUNT FILES FOUND
        INR M
        JMP TNLP2

NEXTNM: LXI H,NAMECT    	; COUNT NAMES FOUND
        DCR M
	JNZ TNLP1
        LXI H,NAMEBUF   	; SAVE START OF BUFFER
        SHLD NBSAVE
        LDA FILECT
        CPI 65          	; NO MORE THAN 64 TRANSFERS
        RC
        MVI A,64        	; ONLY X'FER FIRST 64
        STA FILECT
        RET

; 	SCANS CMDBUF COUNTING NAMES AND PUTTING DELIMITER (SPACE)
;	AFTER LAST NAME
ŠSCAN:   PUSH H
        LXI H,NAMECT
        MVI M,0
        LXI H,CMDBUF+1  	; FIND END OF CMD LINE..
        MOV C,M         	; ..AND PUT SPACE THERE.
        MVI B,0
        LXI H,CMDBUF+2
        DAD B
        MVI M,20H
        LXI H,CMDBUF+1
        MOV B,M
        INR B
        INR B

SCNLP1: INX H
        DCR B
        JZ DNSCAN
        MOV A,M
        CPI 20H
        JNZ SCNLP1

SCNLP2: INX H           	; EAT EXTRA SPACES
        DCR B
        JZ DNSCAN
        MOV A,M
        CPI 20H
        JZ SCNLP2
        SHLD BGNMS      	; SAVE START OF NAMES IN CMDBUF
        INR B
        DCX H

SCNLP3: INX H
        DCR B
        JZ DNSCAN
        MOV A,M
        CPI 20H
        JNZ SCNLP3
        LDA NAMECT      	; COUNTS NAMES
        INR A
        STA NAMECT

SCNLP4: INX H           	; EAT SPACES
        DCR B
        JZ DNSCAN
        MOV A,M
        CPI 20H
        JZ SCNLP4
        JMP SCNLP3

DNSCAN: MVI M,20H       	; SPACE AFTER LAST CHAR
        POP H
        RET

	; 	PLACES NEXT NAME IN BUFFER SO CPMLINE MAY PARSE IT
ŠTRTOBUF:LHLD BGNMS
        MVI B,0
        LXI D,FCBBUF+2

TBLP:   MOV A,M
        CPI 20H
        JZ TRBFEND
        STAX D
        INX H
        INX D
        INR B           	; COUNT CHARS IN NAME
        JMP TBLP

TRBFEND:INX H
        MOV A,M         	; EAT EXTRA SPACES
        CPI 20H
        JZ TRBFEND
        SHLD BGNMS
        LXI H,FCBBUF+1  	; PUT # CHARS BEFORE NAME
        MOV M,B
        RET

; 	IN CP/M V.2, IF FILE IS R/O OR SYS, IT IS CHANGED TO 'BAK'.

CKCPM2: MVI C,12
        CALL BDOS
	MOV A,L			; TRANSFER VERSION #             W.B.
        ORA A           	; RETURN 0 MEANS CP/M 1
        RZ
        MVI C,STDMA
        LXI D,80H
        CALL BDOS
        MVI C,SRCHF     	; SEARCH FOR FILE
        LXI D,FCB
        CALL BDOS
        CPI 0FFH
        RZ
        ADD A 
	ADD A 		  	; MULT A-REG BY..
        ADD A 
	ADD A 		  	; ..32 TO FIND..
        ADD A           	; ..NAME IN DMA.
        LXI H,80H
        ADD L
        MOV L,A         	; HL POINTS TO DIR NAME
        LXI D,9
        DAD D           	; POINT TO R/O ATTRIB BYTE
        MOV A,M
        ANI 80H         	; TEST MSB
        JNZ MKCHG       	; IF SET, MAKE CHANGE
        INX H           	; CHECK SYSTEM ATTRIB BYTE
        MOV A,M
        ANI 80H
        RZ              	; NOT $SYS OR $R/O
        DCX HŠ
MKCHG:  LXI D,-8
        DAD D           	; POINT HL TO FILENAME + 1
        LXI D,FCB+1     	; MOVE DIR NAME TO FCB..
        MVI B,11        	; ..WITHOUT CHANGING DRIVE.
        CALL MOVE
        LXI H,FCB+9     	; R/O ATTRIB
        MOV A,M
        ANI 7FH         	; STRIP R/O ATTRIB
        MOV M,A
        INX H           	; SYS ATTRIB
        MOV A,M
        ANI 7FH
        MOV M,A
        LXI D,FCB
        MVI C,30        	; SET NEW ATTRIBS IN DIR
        CALL BDOS

;	 MAY BE CALLED BY CKBAKUP BELOW. ITS RETURN DONE HERE

PLANCHG:LXI H,FCB       	; CHANGE NAME TO TYPE "BAK"
        LXI D,6CH
        MVI B,9         	; MOVE DRIVE AND NAME (NOT TYPE)
        CALL MOVE
        LXI H,75H       	; START OF TYPE IN FCB2
        MVI M,'B'
        INX H
        MVI M,'A'
        INX H
        MVI M,'K'
        LXI D,6CH
        MVI C,ERASE     	; ERASE ANY PREV BACKUPS
        CALL BDOS
        LXI H,6CH       	; FCB2 DR FIELD SHOULD..
        MVI M,0         	; ..0 FOR RENAME.
        LXI D,FCB
        MVI C,23        	; RENAME
        CALL BDOS
        RET

CKBAKUP:LDA BKBYTE
        ORA A
        RZ
        MVI C,SRCHF
        LXI D,FCB
        CALL BDOS
        INR A
        RZ              	; FILE NOT FOUND
        JMP PLANCHG     	; IN "CKCPM2" - RET DONE THERE

;
;------------------------------------------------------------------------------
;	MFACCESS	MACRO ROUTINES
;
;	MFFLG1 IS NOT SET LOCAL BECAUSE IT MUST BE RESETŠ;	IN MAIN MODEM PROGRAM ON AN ABORT
;
;	MULTI-FILE ACCESS SUBROUTINE.  ALLOWS PROCESSING
;	OF MULTIPLE FILES (I.E. *.ASM) FROM DISK.  THIS
;	ROUTINE BUILDS THE PROPER NAME IN THE FCB EACH
;	TIME IT IS CALLED.  THIS COMMAND WOULD BE USED
;	IN SUCH PROGRAMS AS MODEM TRANSFER, TAPE SAVE,
;	ETC IN WHICH YOU WANT TO PROCESS SINGLE OR
;	MULTIPLE FILES.
;
;	THE FCB WILL BE SET UP WITH THE NEXT NAME, READY TO
;	DO NORMAL PROCESSING (OPEN, READ, ETC.) WHEN ROUTINE IS CALLED.
;
;	CARRY IS SET IF NO MORE NAMES CAN BE FOUND
;	DEFINE DATA MOVE MACRO

MOV1    MACRO   ?F,?T,?L,?I

        IF NOT NUL ?F
        LXI     H,?F
        ENDIF

        IF NOT NUL ?T
        LXI     D,?T
        ENDIF

        IF NOT NUL ?L
        LXI     B,?L
        ENDIF

        IF NOT NUL ?I
        LOCAL   ?N,?Z
        CALL    ?Z

?N:     DB      ?I

?Z:     POP     H       	; GET TO
        LXI     B,?Z-?N
        ENDIF

        CALL    MOVER

MF      SET     -1      	;; SHOW EXPANSION
        ENDM

; DEFINE CP/M MACRO - CPM FNC,PARM

CPM     MACRO   ?F,?P

        PUSH    B
        PUSH    D
        PUSH    H

        IF NOT NUL ?F
        MVI     C,?FŠ        ENDIF

        IF NOT NUL ?P
        LXI     D,?P
        ENDIF

        CALL    BDOS
        POP     H
        POP     D
        POP     B
        ENDM

; 
;---------------------------------------------------
;	MULTI-FILE ACCESS SUBROUTINE
;
;	THE ROUTINE IS COMMENTED IN PSEUDO CODE,
;	EACH PSEUDO CODE STATEMENT IS IN ;<<...>>
;

MFNAME  EQU $

;;	<<INIT DMA ADDR, FCB>>


CPM STDMA,80H

	XRA A 
 	STA FCBEXT

; <<IF FIRST TIME>>

	LDA MFFLG1 
 	ORA A 
 	JNZ MFN01

; <<TURN OFF 1ST TIME SW>>

	MVI A,1 
 	STA MFFLG1

; <<SAVE THE REQUESTED NAME>>

MOV1 FCB,MFREQ,12		; SAVE ORIG REQ

	LDA FCB 
 	STA MFCUR 		; SAVE DISK IN CURR FCB

; <<SRCHF REQ NAME>>

MOV1 MFREQ,FCB,12

CPM SRCHF,FCB

; <<ELSE>>Š
	JMP MFN02

MFN01  EQU $

; <<SRCHF CURR NAME>>

MOV1 MFCUR,FCB,12

CPM SRCHF,FCB

; <<SRCHN REQ NAME>>

MOV1 MFREQ,FCB,12

CPM SRCHN,FCB

; <<ENDIF>>

MFN02  EQU $

; <<RETURN CARRY IF NOT FOUND>>

	INR A 
 	STC 
 	JNZ MFFIX1 
 	STA MFFLG1 
 	RET            ;FIX BY M.Z.

MFFIX1  EQU $

; <<MOVE NAME FOUND TO CURR>>

 	DCR A 
 	ANI 3 
 	ADD A
 	ADD A 
 	ADD A 
 	ADD A 
 	ADD A
 	ADI 81H 
 	MOV L,A 
 	MVI H,0
 	PUSH H 			;  SAVE NAME POINTER

 MOV1 ,MFCUR+1,11

; <<MOVE NAME FOUND TO FCB>>

 	POP H 

 MOV1 ,FCB+1,11

; <<SETUP FCB>>
Š 	XRA A 
 	STA FCBEXT 
 	STA FCBRNO                        ;FIX BY M.Z.

; <<RETURN>>

 	RET

; MULTI-FILE ACCESS WORK AREA

MFFLG1: DB      0       ;1ST TIME SW
MFREQ:  DS      12      ;REQ NAME
MFCUR:  DS      12      ;CURR NAME
;------------------------------------------------

; MOVE SUBROUTINE

MOVER:  MOV     A,M
        STAX    D
        INX     H
        INX     D
        DCX     B
        MOV     A,B
        ORA     C
        JNZ     MOVER
        RET

; 		END OF MFACCESS ROUTINES
;--------------------------------------------------------------


RCVSECT:XRA A
        STA ERRCT

RCVRPT: XRA A			; FOR ERROR CHECK RS232
	STA ERRCDE
	LDA QFLG
        ORA A
        JZ RCVSQ

        CALL ILPRT
        DB '   AWAITING SECTOR...',0

	PUSH	H
	LHLD	SECTNO
	INX	H
	CALL	DECOUT

	CALL	ILPRT
	DB	' (',0

	CALL	DHXOUT

	CALL	ILPRT
	DB	'H)',CR,0Š
	MOV	A,L
	POP	H

RCVSQ:  MVI B,10         	; 10 IN ORIG PROG
        CALL RECV
        JC RCVSTOT

	IF	CHEK
	CALL	RCVERR		; FOR ERROR CHECK RS232
	JC	RCVDER
	ENDIF	; CHEK

        CPI CAN         	; CHECK FOR CANCEL..
        JZ ABORT        	; ..REQUEST FROM SENDER.

        CPI SOH
        JZ RCVSOH
        ORA A
        JZ RCVSQ
        CPI EOT
        STC
        RZ
        MOV B,A
        LDA VSEEFLG
        ORA A
        JZ RCVSEH
        LDA QFLG
        ORA A
        JZ RCVSERR

RCVSEH: CALL CRLF  
        MOV A,B
        CALL HEXO

        CALL ILPRT
        DB 'H RECEIVED, NOT (SOH) ++',CR,LF,0

RCVSERR:MVI B,1
        CALL RECV
        JNC RCVSERR
	LDA 	CRCFLG		; WB...REPEAT CRC REQUEST 
	ORA 	A		;      IN CASE SENDER WAS SLOW IN
	MVI 	A,NAK		;      GETTING STARTED.
	JNZ 	RCVS1
	MVI 	A,CRC
RCVS1:  CALL 	SEND

        LDA ERRCT
        INR A
        STA ERRCT
        CPI ERRLIM
        JC RCVRPT
        LDA VSEEFLG
        ORA AŠ        JZ RCVCKQ
        LDA QFLG
        ORA A
        JZ RCVSABT

RCVCKQ: CALL CKQUIT
        JZ RCVSECT

RCVSABT:CALL CLOSFIL

        CALL ERXIT
        DB CR,LF,'++ UNABLE TO RECEIVE BLOCK...ABORTING ++',CR,LF,'$'

RCVSTOT:LDA VSEEFLG
        ORA A
        JZ RCVSPT
        LDA QFLG
        ORA A
        JZ RCVSERR

RCVSPT: CALL ILPRT

        DB CR,LF,'++ TIMEOUT...',0

RCVPRN: LDA ERRCT
        CALL HEXO
        CALL CRLF
        JMP RCVSERR

; 
;	RCVERR: Checks for framing, overrun, and parity errors.
;	Parity errors cannot  be detected unless the parity option
;	has been selected.
;		1.  Error code (ERRCDE) was set in RECV routine.
;		2.  ERRCDE=0 for no errors, ERRCDE<>0 for errors.
;		3.  If there is an error this routine returns with
;	    	    carry flag set.

	IF	CHEK
RCVERR:	PUSH	PSW		; SAVE CHAR TRANSMITTED
	LDA	ERRCDE		; GET RECEIVE ERROR CODE
	ANA	A		; IS IT ZERO?
	JZ	RCVER2		; YES, NO RECEIVE ERROR
	POP	PSW		; RESTORE CHAR TRANSMITTED
	STC			; SET CARRY ON TO INDICATE AN ERROR
	RET

RCVER2: POP	PSW		; RESTORE CHAR TRANSMITTED
	RET

; RCVDER: Checks for a receive error and displays appropriate
; error message. Then goes to RCVSERR to purge the line and
; send a NAK.

RCVDER: LDA	VSEEFLG		; VIEWINGŠ	ORA	A		; ...MODE?
	JZ	RCVDEP 		; YES,..PRT MSG
	LDA	QFLG		; QUIET...
	ORA	A		; ...MODE?
	JZ	RCVSERR		; YES, NO MSG

RCVDEP: CALL ILPRT
	DB	CR,LF,0

	LDA	ERRCDE		; GET RECEIVE ERR CODE
	ANI	FRMER		; WAS THERE A FRAMING ERROR?
	JZ	RCVDE2 		; NO, GO CHECK FOR OVERRUN

	CALL	ILPRT
	DB	'++ FRAMING ERROR...',0

	CALL	RCVDE5 		; PRINT # OF ERROR

RCVDE2: LDA	ERRCDE		; GET RECEIVE ERR CODE
	ANI	ORUNER		; WAS THERE AN OVERRUN
	JZ	RCVDE3 		; NO, GO CHECK FOR PARITY ERROR

	CALL	ILPRT
	DB	LF,'++ OVERRUN ERROR...',0

	CALL	RCVDE5

RCVDE3: LDA	ERRCDE		; GET RECEIVE ERR CODE
	ANI	PARER		; WAS THERE A PARITY ERROR?
	JZ	RCVDE4 		; NO, GO PURGE LINE

	CALL	ILPRT
	DB	LF,'++ PARITY ERROR...',0
	CALL	RCVDE5

RCVDE4: JMP	RCVSERR		; GO PURGE LINE, SEND NAK

; 	Display number of error, do a carriage return and line feed.

RCVDE5: LDA	ERRCT		; GET ERROR NUMBER
	CALL	HEXO		; DISPLAY IT
	CALL	CRLF		; DO CR, LF
	RET
	ENDIF	; CHEK


RCVSOH: MVI B,1
        CALL RECV
        JC RCVSTOT

	IF	CHEK
	CALL	RCVERR		; RS232 ERROR CHECK
	JC	RCVDER
	ENDIF	; CHEK
Š        MOV D,A
        MVI B,1
        CALL RECV
        JC RCVSTOT

	IF	CHEK
	CALL	RCVERR		; RS232 ERROR CHECK
	JC	RCVDER
	ENDIF	; CHEK

        CMA
        CMP D
        JZ RCVDATA
        LDA VSEEFLG
        ORA A
        JZ RCVBSE
        LDA QFLG
        ORA A
        JZ RCVSERR

RCVBSE: CALL ILPRT

        DB CR,LF,'++ BAD SECTOR NUMBER IN HEADER ++',CR,LF,0
        JMP RCVSERR

RCVDATA:MOV A,D
        STA RCVSNO
        MVI A,1
        STA DATAFLG
        MVI C,0
	CALL	CLRCRC		; CLEAR CRC COUNTER
        LXI H,80H

RCVCHR: MVI B,1
        CALL RECV
        JC RCVSTOT

	IF	CHEK
	CALL	RCVERR		; RS232 ERROR CHECK
	JC	RCVDER	
	ENDIF	; CHEK

        MOV M,A
        INR L
        JNZ RCVCHR
	LDA	CRCFLG
	ORA	A
	JZ	RCVCRC
        MOV D,C
        XRA A
        STA DATAFLG
        MVI B,1
        CALL RECV
        JC RCVSTOT
Š	IF	CHEK
	CALL	RCVERR		; RS232 ERROR CHECK
	JC	RCVDER
	ENDIF	; CHEK

        CMP D
        JNZ RCVCERR

CHKSNM: LDA RCVSNO
        MOV B,A
        LDA SECTNO
        CMP B
        JZ RECVACK
        INR A
        CMP B
        JNZ ABORT
        RET

RCVCRC:	MVI	E,2		; NUMBER OF CRC BYTES
RCVCR2:	MVI	B,1
	CALL	RECV
	JC	RCVSTOT

	IF	CHEK
	CALL	RCVERR		; RS232 ERROR CHECK
	JC	RCVDER
	ENDIF	; CHEK

	DCR	E
	JNZ	RCVCR2
	CALL	CHKCRC
	ORA	A
	JZ	CHKSNM
	LDA	VSEEFLG
	ORA	A
	JZ	RCVCRER
	LDA	QFLG
	ORA	A
	JZ	RCVSERR

RCVCRER:CALL	ILPRT
	DB	CR,LF,'++ CRC ERROR...',0

	JMP	RCVPRN	

RCVCERR:LDA VSEEFLG
        ORA A
        JZ RCVCPR
        LDA QFLG
        ORA A
        JZ RCVSERR

RCVCPR: CALL ILPRT
        DB CR,LF,'++ CHECKSUM ERROR...',0
Š        JMP RCVPRN

RECVACK:CALL SENDACK
        JMP RCVSECT

SENDACK:MVI A,ACK
        CALL SEND
        RET

SENDHDR:LDA QFLG
        ORA A
        JZ SENDHNM

        CALL ILPRT
        DB '   SENDING SECTOR...',0

	PUSH	H
	LHLD	SECTNO
	CALL	DECOUT

	CALL	ILPRT
	DB	' (0',0

	CALL	DHXOUT

	CALL	ILPRT
	DB	'H)',CR,0

	POP	H

SENDHNM:MVI A,SOH
        CALL SEND
        LDA SECTNO
        CALL SEND
        LDA SECTNO
        CMA
        CALL SEND
        RET

SENDSEC:MVI A,1
        STA DATAFLG
        MVI C,0
	CALL	CLRCRC
        LXI H,80H

SENDC:  MOV A,M
        CALL SEND
        INR L
        JNZ SENDC
        XRA A
        STA DATAFLG
        RET

SENDCKS:MOV A,C
        CALL SENDŠ        RET

SNDCRC:	CALL	FINCRC
	MOV	A,D
	CALL	SEND
	MOV	A,E
	CALL	SEND
	XRA	A
	RET

GETACK: MVI  B,10
        CALL RECVDG
        JC GETATOT
        CPI ACK
        RZ
 	MOV B,A
 	ANI 7FH		
        CPI CAN
        JZ ABORT
        LDA QFLG
        ORA A
        JZ ACKERR
        CALL CRLF
        MOV A,B
        CALL HEXO

        CALL ILPRT
        DB 'H RECEIVED...NOT (ACK) ++',CR,LF,0

ACKERR: LDA ERRCT
        INR A
        STA ERRCT
        CPI ERRLIM
        RC

;	 REACHED ERROR LIMIT

        LDA VSEEFLG
        ORA A
        JZ GACKV
        LDA QFLG
        ORA A
        JZ CSABORT

GACKV:  CALL CKQUIT
        STC
        RZ

CSABORT:CALL ERXIT
        DB CR,LF,'++ CAN''T SEND SECTOR...ABORTING ++',CR,LF,'$'

GETATOT:LDA QFLG
        ORA A
        JZ ACKERR
        CALL ILPRTŠ
        DB CR,LF,'++ TIMEOUT ON (ACK) ++',CR,LF,0

        JMP ACKERR

CKABORT:
CKABGO: CALL STAT
        RZ
        CALL KEYIN
        CPI CAN
        RNZ

ABORT:  LXI SP,STACK

ABORTL: MVI B,1
        CALL RECV
        JNC ABORTL
        MVI A,CAN
        CALL SEND

ABORTW: MVI B,1
        CALL RECV
        JNC ABORTW
        MVI A,' '
        CALL SEND
        CALL ILPRT

        DB CR,LF,'++ ROUTINE CANCELLED ++',CR,LF,0

        MVI A,'B'               ; TURN MULTI-FILE MODE..
        STA BATCHFLG            ; ..OFF SO ROUTINE ENDS.
        JMP DNTCE

INCRSNO:PUSH	H
	LHLD	SECTNO
	INX	H
	SHLD	SECTNO
	MOV	A,L
	POP	H
	RET

ERASFIL:LDA BATCHFLG            ; DON'T ASK FOR ERASE..
        ORA A                   ; ..IN MULTI-FILE MODE,..
        JZ NOASK                ; ..JUST DO IT.
        LXI D,FCB
        MVI C,SRCHF
        CALL BDOS
        INR A
        RZ

        CALL ILPRT
        DB CR,LF,'++ FILES EXISTS, TYPE ''Y'' TO ERASE...',BELL,0

        CALL KEYIN
        PUSH PSWŠ        CALL TYPE
        POP PSW
        CALL UCASE
        CPI 'Y'
        JNZ MENU
        CALL CRLF

NOASK:  LXI D,FCB
        MVI C,ERASE
        CALL BDOS
        RET

BLKFILE:CALL ILPRT      	; ROUTINE IF NO FILE IS NAMED FOR
                        	;  "SEND" OR "RECEIVE"

        DB CR,LF,'++ NO FILE SPECIFIED ++',CR,LF,BELL,0

	LXI  B,0FFFFH
DELAY:	DCX  B
	MOV  A,B
	ORA  C
	JNZ  DELAY
        JMP MENU

MAKEFIL:LXI D,FCB
        MVI C,MAKE
        CALL BDOS
        INR A
        RNZ

        CALL ERXIT
        DB CR,LF,'++ CAN''T MAKE FILE...DIRECTORY FULL ++',CR,LF,'$'

	IF CPM2 
CNREC:	MVI	C,FILSIZ    	; COMPUTE FILE SIZE FUNC IN CP/M 2.x
	LXI	D,FCB		; POINT TO FILE CONTROL BLOCK
	CALL	BDOS
	LHLD	FCB+33		; GET RECORD COUNT
	SHLD	RCNT		; STORE IT
	LXI	H,0		; ZERO HL
	SHLD	FCB+33		; RESET RANDOM RECORD IN FCB
	RET
	ENDIF	; CPM2 

	IF NOT	CPM2 
CNREC:	MVI	A,'?'		; MATCH ALL EXTENTS
	STA	FCBEXT
	MVI	A,0FFH
	STA	MAXEXT		; INIT MAX EXT NO.
	MVI	C,SRCHF		; GET 'SEARCH FIRST' FNC
	LXI	D,FCB
	CALL	BDOS		; READ FIRST
	INR	A		; WERE THERE ANY?
	JNZ	SOME		; GOT SOME
Š	CALL	ERXIT
	DB	CR,LF,'++ FILE NOT FOUND ++',CR,LF,'$'

;	 READ MORE DIRECTORY ENTRIES

MOREDIR:MVI	C,SRCHN		; SEARCH NEXT
	LXI	D,FCB
	CALL	BDOS		; READ DIR ENTRY
	INR	A		; CHECK FOR END (0FFH)
	JNZ	SOME		; NOT END OF DIR...PROCESS EXTENT
	LDA	MAXEXT		; HIT END...GET HIGHEST EXTENT NO. SEEN
	MOV	L,A		; WHICH GIVES EXTENT COUNT -1
	MVI	H,0
	MOV	D,H
	LDA	RCNT		; GET RECORD COUNT OF MAX EXTENT SEEN
	MOV	E,A		; SAVE IT IN DE
	DAD	H
	DAD	H		; MULTIPLY # OF EXTENTS -1
	DAD	H		;  TIMES 128
	DAD	H
	DAD	H
	DAD	H
	DAD	H
	DAD	D		; ADD IN SIZE OF LAST EXTENT
	SHLD	RCNT		; SAVE TOTAL RECORD COUNT
	RET			; AND EXIT

; POINT TO DIRECTORY ENTRY

SOME:	DCR	A		; UNDO PREV 'INR A'
	ANI	3		; MAKE MODULUS 4
	ADD	A		; MULTIPLY...
	ADD	A		; ..BY 32 BECAUSE
	ADD	A		; ..EACH DIRECTORY
	ADD	A		; ..ENTRY IS 32
	ADD	A		; ..BYTES LONG
	LXI	H,80H 		; POINT TO BUFFER
	ADD	L		; POINT TO ENTRY
	ADI	15		; OFFSET TO RECORD COUNT
	MOV	L,A		; HL NOW POINTS TO REC COUNT
	MOV	B,M		; GET RECORD COUNT
	DCX	H
	DCX	H		; BACK DOWN TO EXTENT NUMBER
	DCX	H
	LDA	MAXEXT		; COMPARE WITH CURRENT MAX.
	ORA	A		; IF NO MAX YET
	JM	BIGGER		; THEN SAVE RECORD COUNT ANYWAY
	CMP	M
	JNC	MOREDIR
BIGGER:	MOV	A,B		; SAVE NEW RECORD COUNT
	STA	RCNT
	MOV	A,M		; SAVE NEW MAX. EXTENT NO.
	STA	MAXEXT
	JMP	MOREDIR		; GO FIND MORE EXTENTS
	ENDIF	; NOT CPM2 Š
OPENFIL:LXI D,FCB
        MVI C,OPEN
        CALL BDOS
        INR A
        JNZ OPENOK

        CALL ERXIT
        DB CR,LF,'++ CAN''T OPEN FILE...NOT FOUND ON DISK ++',CR,LF,'$'

OPENOK: LDA BATCHFLG
        ORA A
        JNZ OPNOK1
        LDA QFLG
        ORA A
        RZ

OPNOK1:CALL ILPRT
        DB  CR,LF,'++ FILE OPEN...SIZE: ',0

	LHLD	RCNT		; RECORD COUNT
	CALL	DECOUT		; PRINT SECTORS IN DECIMAL

	CALL	ILPRT
	DB	' (',0

	CALL	DHXOUT

	CALL	ILPRT
	DB	'H) SECTORS',CR,LF,0

	RET

CLOSFIL:LXI D,FCB
        MVI C,CLOSE
        CALL BDOS
        INR A
        RNZ

        CALL ERXIT
        DB CR,LF,'++ CAN''T CLOSE FILE...NOT FOUND ON DISK ++',CR,LF,'$'

RDSECT: LDA SECINBF
        DCR A
        STA SECINBF
        JM RDBLOCK
        LHLD SECPTR
        LXI D,80H
        CALL MOVE128
        SHLD SECPTR
        RET

RDBLOCK:LDA EOFLG
        CPI 1
        STCŠ        RZ
        MVI C,0
        LXI D,DBUF

RDSECLP:PUSH B
        PUSH D
        MVI C,STDMA
        CALL BDOS
        LXI D,FCB
        MVI C,READ
        CALL BDOS
        POP D
        POP B
        ORA A
        JZ RDSECOK
        DCR A
        JZ REOF

        CALL ERXIT
        DB CR,LF,'++ READ ERROR...END OF FILE ++',CR,LF,'$'

RDSECOK:LXI H,80H
        DAD D
        XCHG
        INR C
        MOV A,C
	CPI DBFSIZ*8		; BUFFER IN 128 BYTE SECTORS
        JZ RDBFULL
        JMP RDSECLP

REOF:   MVI A,1
        STA EOFLG
        MOV A,C

RDBFULL:STA SECINBF
        LXI H,DBUF
        SHLD SECPTR
        LXI D,80H
        MVI C,STDMA
        CALL BDOS
        JMP RDSECT

WRSECT: LHLD SECPTR
        XCHG
        LXI H,80H
        CALL MOVE128
        XCHG
        SHLD SECPTR
        LDA SECINBF
        INR A
        STA SECINBF
	CPI	DBFSIZ*8	; BUFFER IN 128 BYTE SECTORS
        RNZ

WRBLOCK:LDA SECINBFŠ        ORA A
        RZ
        MOV C,A
        LXI D,DBUF

DKWRLP: PUSH H
        PUSH D
        PUSH B
        MVI C,STDMA
        CALL BDOS
        LXI D,FCB
        MVI C,WRITE
        CALL BDOS
        POP B
        POP D
        POP H
        ORA A
        JNZ WRERR
        LXI H,80H
        DAD D
        XCHG
        DCR C
        JNZ DKWRLP
        XRA A
        STA SECINBF
        LXI H,DBUF
        SHLD SECPTR
        RET

WRERR:  MVI C,CAN
        CALL SEND

        CALL ERXIT
        DB CR,LF,'++ WRITE ERROR...DISK FULL ++',CR,LF,'$'

RECVDG  EQU $
	CALL INDATP
	CALL INDATP

RECV:   PUSH D

	LDA FASCLK		; DOUBLE UP THE LOOP COUNTER IF
	ORA A			; 4 MZ OR GREATER
	JZ MSEC
	MOV A,B
	ADD A
	MOV B,A

MSEC:   LXI D,15000             ; 60% OF ORIG 50000
	CALL CKABORT

MWTI:   CALL INCTLP
        CALL ANRCVB
        CALL CPRCVR
        JZ MCHARŠ        DCR E
        JNZ MWTI
        DCR D
        JNZ MWTI
        DCR B
        JNZ MSEC
        POP D
        STC
        RET

	IF	CHEK
MCHAR:	CALL INDATP
	ANI  ERRMSK
	STA  ERRCDE

	ELSE
MCHAR:  CALL INDATP
	ENDIF	; CHEK

	POP D
        PUSH PSW
	CALL	UPDCRC		; CALCULATE CRC
        ADD C
        MOV C,A
        LDA RSEEFLG
        ORA A
        JZ MONIN
        LDA VSEEFLG
        ORA A
        JNZ NOMONIN
        LDA DATAFLG
        ORA A
        JZ NOMONIN

MONIN:  POP PSW
        PUSH PSW
        CALL SHOW

NOMONIN:POP PSW
        ORA A
        RET

SEND:   PUSH PSW
        LDA SSEEFLG
        ORA A
        JZ MONOUT
        LDA VSEEFLG
        ORA A
        JNZ NOMONOT
        LDA DATAFLG
        ORA A
        JZ NOMONOT

MONOUT: POP PSW
        PUSH PSWŠ        CALL SHOW

NOMONOT:POP PSW
        PUSH PSW
	CALL	UPDCRC		; CALCULATE CRC
        ADD C
        MOV C,A

SENDW:  CALL OTCTLP
        CALL ANSNDB
        CALL CPSNDR
        JNZ SENDW
        POP PSW
        CALL OTDATP
        RET

WAITNAK:LDA VSEEFLG
        ORA A
        JZ WAITNPR
        LDA QFLG
        ORA A
        JZ WAITNLP

WAITNPR:CALL ILPRT
        DB CR,LF,'++ AWAITING INITIAL (NAK) ++',CR,LF,0

WAITNLP:CALL CKABORT
        MVI B,1
        CALL RECV
        CPI NAK
        RZ
	CPI	CRC
	JZ	WAITCRC
        DCR E
        JZ ABORT
        JMP WAITNLP

WAITCRC:CALL	ILPRT
	DB CR,LF,'++ (CRC) REQUEST RECEIVED ++',CR,LF,BELL,0

	XRA	A
	STA	CRCFLG
	RET

INITDR:
        LHLD 1
        LXI D,3
        DAD D
        SHLD VSTAT+1
        DAD D
        SHLD VKEYIN+1
        DAD D
        SHLD VTYPE+1
	DAD D
	SHLD VLISTD+1Š
	IF	INLZE		; ENTER WHATEVER OTHER
	MVI	A,INITC1	; INIT. ROUTINES ARE REQUIRED
	OUT	MOCTLP
	MVI	A,INITC2
	OUT	MOCTLP
	MVI	A,INITC3
	OUT	MOCTLP
	ENDIF	; INLZE

	IF	SWITCH
	CALL	SETDFLT
	ENDIF	;SWITCH
	RET

PROCOPT:LXI D,FCB+1
        LDAX D
        STA OPTION

OPTLP:  INX D
        LDAX D
        CPI ' '
        JZ ENDOPT
        LXI H,OPTBL
        MVI B,OPTBE-OPTBL

OPTCK:  CMP M
        JNZ OPTNO
        MVI M,0
        JMP OPTLP

OPTNO:  INX H
        DCR B
        JNZ OPTCK
        JMP BADOPT

ENDOPT:	LDA	CRCFLG
	ORA	A
	JNZ	ENDOP2
	LDA	OPTION
	CPI	'R'
	JNZ	BADOPT		; CRC ONLY ALLOWED IN RECEIVE MODE

ENDOP2: LDA VSEEFLG
        ORA A
        RNZ
        STA QFLG
        RET

DONE:   LDA BATCHFLG
        ORA A
        JNZ DNTCC
        LDA QFLG
        ORA A
        JZ NMSTRNSŠ        LXI H,FCB+1             ; PUT FILE NAME IN..
        LXI D,FTRNMSG           ; ..SPACES IN MESSAGE..
        MVI B,8                 ; ..BELOW.
        CALL MOVE
        INX D                   ; PUT FILE TYPE AFTER..
        MVI B,3                 ; ..SKIPPING ONE SPACE..
        CALL MOVE               ; ..BELOW.       

        CALL ILPRT
FTRNMSG:DB '              TRANSFERRED ++',CR,LF,0    	; 13 SPACES

NMSTRNS:LDA FCB                 ; SAVE DRIVE NO.
        STA DISKNO
        LXI H,FCB               ; BLANK OUT FILE CONTROL BLOCKS
        CALL INITFCB
        LDA DISKNO              ; PUT DRIVE NUMBER BACK
        STA FCB
        LXI H,RESTSN            ; RESTORE SECTORE NUMBERS..
        LXI D,SECTNB           	; ..FOR NEW FILE TRANSFER.
        MVI B,SECTNE-SECTNB   	; ROUTINE ALSO DONE IN MENU.
        CALL MOVE
        LDA SENDFLG             ; GOES TO EITHER SEND OR..
        ORA A                   ; ..RECEIVE FILE, DEPENDING..
        JNZ SENDFIL             ; ..UPON WHICH ROUTINE SET..
        JMP RCVFIL              ; ..THE FLAG IN MULTI-FILE MODE.

DNTCC:	MVI A,TRUE              ; INDICATE NO FILES BEING..
        STA FSTFLG              ; RESET MULTIFILE TRANS
        STA NFLFLG             	; ..USED IN TERMINAL ROUTINE.
        CMA
        STA SAVFLG             	; STOP MEM.SAVE IN TERM ROUTINE.
        LDA VSEEFLG
        ORA A
        JZ DONETC
        LDA QFLG
        ORA A
        JZ DNTCA

DONETC: CALL ILPRT
        DB CR,LF,'++ ALL TRANSFERS COMPLETED ++',CR,LF,BELL,BELL,BELL,0

DNTCA:	LDA     DISCFLG         ; see if disconnect when thru
        ORA     A
        JNZ     DNTCE         	; no, don't disconnect

DNTCB:	
	LXI D,80H
	MVI C,STDMA
	CALL BDOS
	CALL TIMER
	CALL TIMER
	CALL TIMER
	CALL TIMER
	CALL TIMER
	CALL TIMERŠ	CALL TIMER
	LXI	D,OFFHK
	CALL	OFF1
	JMP	OFF5

OFF1:	LDAX D
	CPI '$'
	JZ OFF2
	CALL MODOUT
	INX D
	JMP OFF1

OFF2:	MVI B,15

OFF3:	CALL TIMER
	DCR B
	JNZ OFF3
	INX D

OFF4:	LDAX D
	CPI '$'
	RZ
	CALL MODOUT
	INX D
	JMP OFF4

OFF5:	CALL TIMER
	CALL INDATP
	CALL TIMER
	CALL ILPRT
        DB   '++ DISCONNECTED ++',CR,LF,0

	JMP  menu		; used to be TERM


DNTCE:  LDA TERMFLG             ; SEE IF RETURN TO..
        ORA A                   ; ..TERMINAL MODE..
	JZ  TERM
	LDA ECHOFLG
	ORA A
        JNZ MENU                ; ..AFTER X'FER.
        JMP TRMECHO

MOVEFCB:LXI H,FCB+16
        LXI D,FCB
        MVI B,16
        CALL MOVE
        XRA A
        STA FCBSNO
        STA FCBEXT
        RET

SHOW:   CPI LF
        JZ CTYPE
        CPI CRŠ        JZ CTYPE
        CPI 9
        JZ CTYPE
        CPI ' '
        JC SHOWHEX
        CPI 7FH
        JC CTYPE

SHOWHEX:PUSH PSW
        MVI A,'('
        CALL CTYPE
        POP PSW
        CALL HEXO
        MVI A,')'
        JMP CTYPE

LISTDV: PUSH B
	PUSH D
	PUSH H
	MOV  C,A
VLISTD:	CALL $-$
	POP  H
	POP  D
	POP  B
	RET

CTYPE:  PUSH B
        PUSH D
        PUSH H
        MOV E,A
        MVI C,WRCON
        CALL BDOS
        POP H
        POP D
        POP B
        RET

CRLF:   PUSH PSW
        MVI A,CR
        CALL TYPE
        MVI A,LF
        CALL TYPE
        POP PSW
        RET

TYPE:   PUSH PSW
        PUSH B
        PUSH D
        PUSH H
        MOV C,A
VTYPE:  CALL $-$
        POP H
        POP D
        POP B
        POP PSWŠ        RET

STAT:   PUSH B
        PUSH D
        PUSH H
VSTAT:  CALL $-$
        POP H
        POP D
        POP B
        ORA A
        RET

KEYIN:  PUSH B
        PUSH D
        PUSH H
VKEYIN: CALL $-$
        POP H
        POP D
        POP B
        RET

UCASE:  CPI 61H         	; CHANGES LOWER CASE CHARACTER..
        RC              	; ..IN A-REG TO UPPER CASE.
        CPI 7BH
        RNC
        ANI 5FH
        RET

DECOUT:	PUSH	PSW
	PUSH	B
	PUSH	D
	PUSH	H
	LXI	B,-10
	LXI	D,-1
DECOT2:	DAD	B
	INX	D
	JC	DECOT2
	LXI	B,10
	DAD	B
	XCHG
	MOV	A,H
	ORA	L
	CNZ	DECOUT
	MOV	A,E
	ADI	'0'
	CALL	CTYPE
	POP	H
	POP	D
	POP	B
	POP	PSW
	RET

DHXOUT:	PUSH	H
	PUSH	PSW
	MOV	A,HŠ	CALL	HEXO
	MOV	A,L
	CALL	HEXO
	POP	PSW
	POP	H
	RET

HEXO:   PUSH PSW
        RAR
        RAR
        RAR
        RAR
        CALL NIBBL
        POP PSW
NIBBL:  ANI 0FH
        CPI 10
        JC ISNUM
        ADI 7
ISNUM:  ADI '0'
        JMP TYPE

; RETRNS W/ ZERO SET IF RETRY ASKED. IF MULTI-FILE MODE, THEN
; NO QUESTIONS ASKED, JUST QUIT

CKQUIT: LDA BATCHFLG
        ORA A
        JNZ CKQTASK     	; ASK FOR RETRY
        INR A           	; RESET ZERO FLG
        RET
CKQTASK:XRA A
        STA ERRCT

        CALL ILPRT
        DB CR,LF,'++ MULTIPLE ERRORS ENCOUNTERED',CR,LF
        DB '   ...TYPE ''Q'' TO QUIT',CR,LF
	DB '   ...TYPE ''R'' TO RETRY',CR,LF
	DB '      COMMAND >>',BELL,0

        CALL KEYIN
        PUSH PSW
        CALL CRLF
        POP PSW
        CALL UCASE      	; INSTEAD OF "ANI 5FH"
        CPI 'R'
        RZ
        CPI 'Q'
        JNZ CKQUIT
        ORA A
        RET

ILPRT:  XTHL

ILPLP:  MOV A,M
        ORA A
        JZ ILPRETŠ        CALL CTYPE
        INX H
        JMP ILPLP
ILPRET: XTHL
        RET

PRTMSG: MVI C,PRINT
        JMP BDOS

ERXIT:  POP D
        CALL PRTMSG

        CALL ILPRT
        DB BELL,0

        LDA BATCHFLG
        ORA A
        JNZ DNTCE
        MVI A,'Q'               ; RESET QFLG
        STA QFLG
        JMP ABORT               ; ABORT OTHER COMPUTER

EXIT:   LXI D,80H
        MVI C,STDMA
        CALL BDOS
        JMP 0

MOVE128:MVI B,80H
MOVE:   MOV A,M
        STAX D
        INX H
        INX D
        DCR B
        JNZ MOVE
        RET

;	 DIALING ROUTINE MODIFIED FOR HAYES SMART MODEM

DIALPL	xra	a		; allow a re-dial, a new call
	sta	contflg
	LXI     H,CMDBUF+1      ; POINT # OF CHARS IN BUFF
        MOV     A,M             ; GET # OF CHARS
        CPI     4               ; 4 OR MORE CHARS BEFORE <CR>?
        JC      ENTNM          	; NO, ASK FOR NUMBER
        LXI     H,CMDBUF+5      ; POINT TO NUMBER TO DIAL
        JMP     DIAL10          ; CHECK IF LIB #, & DIAL


;	this is all the set-up for the print at entnm2.

ENTNM:	CALL	ILPRT

DB FF
DB '                 *** PHONE DIRECTORY ***',CR,LF
DB '===============================================================',CR,LF,0Š
	mvi     c,26            	; number of lines to move
        lxi     h,numblib       	; address of source memory
        lxi     d,dbuf          	; address of target memory
        stax    d               	; +LF
        inx     d               	; and bump it

ENTNM1: mvi	b,30			; number of bytes to move
        call    move            	; move to buffer
        call    spaces          	; 2 entries + 3 spaces=63 chars.
        mvi     b,30
        call    move
        call    newline
        dcr     c               	; number of lines to print
        jz      entnm2
        jmp     entnm1

;	 puts CR-LF at memory pointed by DE

NEWLINE:mvi     a,cr            	; CR
        stax    d               	; store it
        mvi     a,lf            	; LF
        inx     d               	; bump pointer
        stax    d               	; store LF
        inx     d               	; bump pointer
        ret

SPACES: mvi     a,20H           	; space
        stax d 
	 inx d          		; 1
        stax d 
	 inx d          		; 2
        stax d 
	 inx d          		; 3
        ret

ENTNM2: mvi     a,'$'
        stax    d
        mvi     c,print
        lxi     d,dbuf  	; point to table of numbers to print
        call    bdos
        call    crlf

        CALL ILPRT
DB CR,'++ ENTER NUMBER OR LETTER '
	IF ALTLD
DB CR,LF,'(~/number or letter for Alternate LD dial) '
	ENDIF

DB '>>',0

	LXI D,CMDBUF		; get the command line
        CALL INBUFF

DIALP1:	lda	dialflg		; don't capture the redialŠ	sta	pswtmp		; don't upset stack
	xra	a		; correct 'R' reverse ans/org mode bug
	sta	nubrflg	


	if altld
	sta	altldflg
	sta	nubr1flg
	sta	nubr2flg
	endif

	LDA CMDBUF+1
        ORA A                   ; NULL MEANS <CR> WAS TYPED
        JZ MENU                 ; ABORT DIALING, RETURN TO MENU

;	THIS ROUTINE SENDS THE PROPER DIALING INITIATION 
;	COMMANDS TO THE HAYES SMARTMODEM.  IT CAN BE CHANGED BY
;	ALTERING THE 'STYLE' OPTION AT THE BEGINNING OF THIS PRGM.

	MVI A,CR
	CALL MODOUT		; give the modem a <cr>
	PUSH D
	LXI D,STYLE
ONW1:	LDAX D			; hen the 'ATDT' bs
	CPI '$'
	JZ ONW2
	CALL MODOUT
	INX D
	JMP ONW1
ONW2:	POP D
        LXI     H,CMDBUF+2      ; FIRST CHAR OF DIAL LINE

	if altld
	inx	h		; 2nd char of the buffer
	mov	a,m
	dcx	h
	cpi	'/'		; '/' ?
	jnz	dial10

	mvi	a,0FFh		; set alt LD flag active
	sta	altldflg

	mov	a,m		; 1st char of the buffer
	cpi	'M'		; MCI?
	jz	mci
	cpi	'S'		; SPRINT?
	jz	sprint
	jmp	skip

mci	lxi	h,mcinum	; dial the MCI number
	jmp	sdial

sprint	lxi	h,sprnum	; dial the SPRINT number
	jmp	sdial
Šsdial	mov	a,m
	inx	h
	cpi	'$'		; terminated ?
	jz	nxtsdl
	call	modout		; SEND IT
	jmp	sdial

nxtsdl 	call	indatp		; gobble
	call	ilprt
	db cr,lf,lf,0

skip:	lxi	h,cmdbuf+4	; one past the '/'
	endif

;  ENTER THIS ROUTINE WITH HL POINTING TO DIAL LINE

DIAL10: MVI     B,'A'           ; FIRST LETTER OF ALPHABET
        MVI     E,0             ; COUNTS NO. OF LETTERS TO MATCH
        MVI     C,52            ; NUMBER OF LETTERS IN ALPHABET
        MOV     A,M             ; GET CHAR BUFFER

DIAL11: CMP     B               ; NUMBER FROM TABLE?
        JZ      LIBSET
	PUSH	PSW		; SAVE ORIGINAL
	MOV	A,B		; MOVE ALPHABET CHAR.TO 'A'
	CPI	'Z'		; END OF UPPER CASE?
	JNZ	DL11		; NO...CONT.
	ADI	6		; YES...JUMP TO LOWER CASE CHRS.
	MOV	B,A		; PUT BACK IN 'A'
DL11:	POP	PSW
        INR     B               ; MAKE NEXT LETTER (A-Z)
        INR     E               ; COUNT UP
        DCR     C               ; COUNT DOWN
        JZ      DIALPX          ; NOT A LETTER
        JMP     DIAL11          ; LOOP


LIBSET: LXI     H,NUMBLIB       ; PHONE NUMBER LIBRARY
        LXI     B,30            ; LENGTH OF LIBRARY ENTRY
        MOV     A,E             ; NUMBER OF TIMES ADD 30 TO HL
        ORA     A               ; SET FLAGS
        JZ      DIAL13


DIAL12: MOV     A,M             ; GET FIRST CHAR OF LIB ENTRY
        ORA     A               ; SET FLAGS
        JZ      DIALP2         	; SEND BADLIB MSG
        DAD     B               ; INCREMENT HL BY 30
        DCR     E               ; COUNTDOWN
        JNZ     DIAL12          ; NOT THERE YET, LOOP


DIAL13: MVI     E,30            ; NO. OF CHAR TO GET FROM TABLE
        JMP     DIALP2
ŠDIALPX: LDA CMDBUF+1
        MOV E,A                 ; NUMBER OF CHARS IN BUFF
        LXI H,CMDBUF+2          ; POINT FIRST CHAR

	if altld
	lda	altldflg
	ora	a
	jz	dialp2		; not a alt LD dial
	dcr	e		; skip the 'S/' if it is a alt LD dial
	dcr	e
	inx	h
	inx	h
	endif

DIALP2: MOV A,M                 ; GET FIRST # FROM BUFFER

;  ROUTINE PRINT 'BADLIB' MESSAGE AND ABORT IF NULL ENCOUNTERED

        ORA     A               ; SET FLAGS
        PUSH    D               ; SAVE DE REGISTERS
        LXI     D,BADLIB        ; BAD LIBRARY NUMBER IF NULL
        MVI     C,PRINT         ; 9
        PUSH    PSW             ; SAVE A AND FLAGS
        CZ      BDOS
        POP     PSW             ; RESTORE A AND FLAGS
        POP     D               ; RESTORE DE REGISTERS
        JZ      MENU            ; ABORT

;  DIAL A DIGIT, CHECK KBD FOR ABORT

        CALL DIAL               ; DIAL IT
        CALL STAT               ; KEYPRESS?
        ORA A                   ; SET FLAGS
        CNZ KEYIN               ; YES, GO GET IT
        CPI CAN                 ; ^X?
        JZ ABORT                ; YES, ABORT
        INX H                   ; BUMP POINTER
        DCR E                   ; COUNT DOWN CHARS IN BUFF
        JNZ DIALP2             	; NOT DONE, LOOP
        JZ DIALDN               ; DIALING DONE

TIMER:	PUSH PSW		; TIME INTERVAL BETWEEN EACH
	PUSH B			; NUMBER SENT TO THE MODEM
	LXI B,5000H		;ORG. 3500H

	IF	FASCK		;DOUBLE COUNTDOWN IF 4 MHZ
	LXI	B,6A00H
	ENDIF

TIMER2: DCX B	
	MOV A,B
	ORA C
	JNZ TIMER2
	POP B
	POP PSWŠ	RET

NUBRFLG	DB	0		; SEEN A NUMBER 

	if altld
altldflg db	0		; alt LD dial flag
nubr2flg db	0
nubr1flg db 	0
	endif

; AUTO DIALER

DIAL:	CPI	','		; ALLOW A COMMA
	JZ	OK2SND
	CPI 48
        JC DIA1              	; DIGIT MUST BE AT LEAST 0..
        CPI 58
        JNC DIA1             	; ..AND NOT MORE THAN 9
	
	if altld
	mov	b,a		; save it
	lda	altldflg
	ora	a
	mov	a,b
	jz	ok2snd		; not alt LD mode

	lda	nubr1flg	; seen a number before ?
	ora	a
	mov	a,b
	jnz	ok2snd		; yes, skip the rest

	sta	nubr1flg	; set this as being the first
	cpi	'1'		; leading ascii <1> ?
	jnz	ok2snd		; nope, send it...

	jmp	type		; ...else type and kill it	

	endif

ok2snd	STA	NUBRFLG		; hmm... set the first number flag
	CALL MODOUT		; NUMBERS PRINTED IN THIS ROUTINE
	RET

DIA1:	MOV	B,A		; SAVE IT
	LDA	NUBRFLG
	ORA	A
	MOV	A,B
	JZ	TYPE		; NO NUMBER YET, TYPE AND EXIT HERE	
	CPI	'R'		; 'R' FOR REVERSE ANS/ORG MODE??
	JNZ	TYPE		; NOPE, TYPE IT AND EXIT
	JMP	MODOUT		; DONE, SEND IT echo and exit here
	 
DIALDN:	CALL ILPRT
DB CR,LF,'++ DIAL COMPLETED...NOW IN TERMINAL MODE ++',CR,LF,0
Š	MVI A,CR
	CALL MODOUT		; COMPLETE THE DIALING

	CALL INDATP		; GOBBLE GARBAGE

clrdial	lda	pswtmp		; let's see, what mode were we in?
	sta	dialflg

	JMP  TERM

pswtmp	ds	1

BADLIB: DB      CR,LF,'++ BAD LIBRARY NUMBER CALLED ++',CR,LF,'$'

; INITIALIZES CP/M FILE CONTROL BLOCKS AT 5CH AND 6CH

SETFCB: LXI D,CMDBUF
        LXI H,FCB
        CALL CPMLINE
        CALL PROCOPT

CHECKNM:LDA FCB+1       	; CHECK ON THE PRIMARY OPTION
	CPI 'C'			; RETURN IF AUTO DIALER OPTION
	RZ
        CPI 'E'         	; RETURN IF ECHO OPTION
        RZ
        CPI 'M'         	; RETURN TO MENU
        RZ
	CPI 'T'
        JZ TERMSEL
	CPI 'K'			; RETURN IF FILE ERASE OPTION
	JZ CKFILE
        CPI 'S'
        JZ CKFILE
        CPI 'R'
        JNZ BDOPT
        LDA BATCHFLG    	; IF MULT FILE MODE, THEN..
        ORA A           	; ..RECV OPT DOES NOT NEED..
        RZ              	; ..NAME.
        JMP CKFILE
BDOPT:  CALL ILPRT

        DB CR,LF,'++ BAD OPTION ++',CR,LF,0

        JMP REENT
CKFILE: LDA FCB+17      	; IF OPTION THAT NEEDS FILE NAME,..
        CPI ' '         	; ..THEN CHECK TO SEE IF NAME..
        RNZ             	; ..EXISTS. IF NOT..
REENT:  CALL ILPRT      	; ..DO EVERYTHING OVER.

        DB CR,LF,'++ RE-ENTER PRIMARY OPTION AND FILE NAME ONLY ',CR,LF
	DB 'COMMAND >>',BELL,0

        LXI D,CMDBUF
        CALL INBUFFŠ        JMP SETFCB

TERMSEL:LDA FCB+17
        CPI ' '
        JNZ SAVAGN
        MVI A,FALSE
        STA SAVFLG
        MVI A,TRUE
        STA NFLFLG
        CMA
        RET
SAVAGN: MVI A,FALSE
        STA NFLFLG
        RET


; 
;	CRCSUBS (Cyclic Redundancy Code Subroutines) version 1.20
;	These subroutines will compute and check a true 16-bit	
;	Cyclic Redundancy Code for a message of arbitrary length.  
;	The  use of this scheme will guarantee detection of all single 
;	and double bit errors, all  errors  with  an  odd number  of 
;	error bits, all burst errors of length 16 or less, 99.9969% of
;	all 17-bit error bursts, and  99.9984% of  all  possible 
;	longer  error bursts.  (Ref: Computer	Networks, Andrew S.
;	Tanenbaum, Prentiss-Hall, 1981) Designed & coded by Paul
;	Hansknecht, June 13, 1981 Copyright (c) 1981, Carpenter
;	Associates  Box 451 Bloomfield Hills, MI 48013	313/855-3074
;	This program may be freely reproduced for non-profit use.
;
;	ENTRY	CLRCRC,UPDCRC,FINCRC,CHKCRC
;

CLRCRC	EQU	$    	;  Reset CRC Accumulator for a new message.
	PUSH	H
	LXI	H,0
	SHLD	CRCVAL
	POP	H
	RET

UPDCRC	EQU	$   	;  Update CRC Accumulator using byte in (A).
	PUSH	PSW
	PUSH	B
	PUSH	H
	MVI	B,8
	MOV	C,A
	LHLD	CRCVAL

UPDLOOP:MOV	A,C
	RLC
	MOV	C,A
	MOV	A,L
	RAL
	MOV	L,A
	MOV	A,HŠ	RAL
	MOV	H,A
	JNC	SKIPIT
	MOV	A,H   	 	;  The generator is X^16 + X^12 + X^5 + 1
	XRI	10H    		;  as recommended by CCITT.
	MOV	H,A    		;  An alternate generator which is often
	MOV	A,L    		;  used in synchr. transmission protocols
	XRI	21H    		;  is X^16 + X^15 + X^2 + 1. This may be
	MOV	L,A    		;  used by subst, XOR 80H for XOR 10H and
SKIPIT:	DCR	B      		;  XOR 05H for XOR 21H in the adj, code.
	JNZ	UPDLOOP
	SHLD	CRCVAL
	POP	H
	POP	B
	POP	PSW
	RET

FINCRC	EQU	$      		;  Finish CRC calc for outbound message.
	PUSH	PSW
	XRA	A
	CALL	UPDCRC
	CALL	UPDCRC
	PUSH	H
	LHLD	CRCVAL
	MOV	D,H
	MOV	E,L
	POP	H
	POP	PSW
	RET

CHKCRC	EQU	$		;  Check CRC bytes of received message.
	PUSH	H
	LHLD	CRCVAL
	MOV	A,H
	ORA	L
	POP	H
	RZ
	MVI	A,0FFh
	RET

CRCVAL:	DW	0

BADOPT: CALL ILPRT
	DB CR,LF,'++ INVALID OPTION ++',CR,LF,BELL,0

	LXI B,0FFFFH
DELAY2: DCX B	
	MOV A,B
	ORA C
	JNZ DELAY2

MENU:   LXI H,RESTSN            ; RESTORE SECTORE NUMBERS..
        LXI D,SECTNB           	; ..FOR NEW FILE TRANSFER.
        MVI B,SECTNE-SECTNB
        CALL MOVEŠ        LXI H,RESTROPT          ; RESTORE OPTION TABLE
        LXI D,OPTBL
        MVI B,OPTBE-OPTBL
        CALL MOVE
        MVI A,0
     
	STA MFFLG1              ;  RESET MFACCESS ROUTINE..
	STA LSTFLG
	STA MACFLG
	sta dialflg		; be sure the redial flag is reset        
	CMA                     ; ..AND MULTI TRANS IN CASE..
        STA FSTFLG              ; ..OF ABORT.

MENU1:  LDA XPRFLG              ; TEST IF MENU SHOULD BE SHOWN
        ORA A
        JNZ XPRT1
        CALL ILPRT

DB FF,CR	
DB '==  Commands in Menu Mode ========  Secondary Options  ========',cr,lf
DB 'WRT - Write informal file    | ...B - Batch file mode',cr,lf
DB 'DEL - Erase informal file    | ...S - show as Sent',cr,lf
DB 'DSC - Disconnect phone       | ...R - show as Received',cr,lf
DB 'LOG - Login new disk drive   | ...V - View as sent/recd',cr,lf
DB 'CAL - Autodial from direct.  | ...Q - Quiet, no messages',cr,lf
DB 'XPR - Expert mode (on/off)   | ...T - return to Terminal mode',cr,lf
DB 'DIR - Disk directory <drive> | ...E - return to Echo mode',cr,lf
DB 'CPM - Exit to CP/M           | ...D - Disconnect phone',cr,lf
DB 'K   - Kill disk file [fn.ext]| ...C - CRC check/not checksum',cr,lf
DB 'S...- Send file [fn.ext]     |        (receive option only)',cr,lf
DB 'R...- Receive file [fn.ext]  |   S3 - 300 Baud to the Modem',cr,lf    
DB 'T   - Terminal mode [fn.ext] |  S12 - 1200 Baud to the Modem',cr,lf
DB 'E   - Terminal modem w/echo  |   ^C -  Reset the Drives',cr,lf
DB '==============   Commands in Terminal Mode   ================',cr,lf
DB '<DEL>-Off line/return to menu|   ^Z  - END of file',cr,lf
DB '^S  - XOFF character         |   ^Q  - XON character',cr,lf
DB '^D  - Disconnect phone       |  <ESC>- Printer (on/off-rcv mode)',cr,lf
DB '^T  - Transmit informal file |   ^R  - Receive Informal File',cr,lf
DB '^X  - Cancel send/receive    |   ^E  - Terminal/Echo (on/off)',cr,lf
DB '^A  - Re-dial (toggle on/off)|',cr,lf,0

	CALL ILPRT
	DB CR,LF,0
	JMP XPRT9

XPRT1:  CALL ILPRT
	DB FF,0

XPRT:   CALL ILPRT
        DB CR,LF,0

XPRT9:	MVI C,25        	;  CURRENT DISK FUNCTION
        CALL BDOS
        ADI 41H         	;  MAKE ASCII
        CALL TYPEŠ        CALL ILPRT

        DB ': PRIMARY OPTION >>',0

GETCMD: LXI D,CMDBUF            ; ENTER COMMAND
        CALL INBUFF
        CALL CRLF
        LXI D,CMDBUF+2          ; POINT TO COMMAND

	CALL ILCOMP
	DB 'DSC',0
	JNC DNTCB

        CALL ILCOMP
        DB 'CPM',0
        JNC EXIT

        CALL ILCOMP
        DB 'DIR',0
        JNC DIR

	IF   SWITCH
	CALL ILCOMP
	DB 'S3',0
	JNC SET300B

	CALL ILCOMP
	DB 'S12',0
	JNC SET120B
	ENDIF; SWITCH

        CALL ILCOMP
        DB 'RET',0
        JC NXTOPT1              ; CARRY SET = NO MATCH
        LHLD HLSAVE             ; RETURN TO TERMINAL..
        JMP TERM                ; ..MODE WITH SAVE OPTION..
                                ; ..IF PREVIOUSLY ENABLED.
NXTOPT1:CALL ILCOMP
        DB 'WRT',0
        JNC WRTFIL

        CALL ILCOMP
        DB 'XPR',0
        JNC XPRMODE

	CALL ILCOMP
	DB 'LOG',0
	JNC LOGON 

        CALL ILCOMP
        DB 'DEL',0
        JNC NEWFILE

	CALL ILCOMP
	DB 'CAL',0Š	JC NXTPT2
	MVI A,1
	STA CMDBUF+1
	JMP DOOPT

NXTPT2: PUSH H
        LDA CMDBUF+2
        LXI H,COMPLIST
        CALL COMPARE 	   	; COMPARES LIST POINTED TO BY HL..
        POP H              	; ..TO CHAR IN A-REG.
        JC MENU1           	; CARRY SET = NO MATCH

DOOPT:  PUSH H             	; LOAD ORIGINAL FCB WITH TRANSFER..
        CALL SETFCB        	; ..CMDS AND GO TO BEGINNING OF..
        POP H              	; ..PROGRAM. WILL FOLLOW SAME LOGIC..
        JMP RESTAR        	; ..AS IF PROGRAM WERE CALLED WITH..

DIR:    CALL DIRLST
        JMP XPRT

NEWFILE:LDA FCB3+1
        CPI ' '
        JZ MENU1        	; IF NO FILE, DON'T ERASE
        LXI D,FCB3
        MVI C,ERASE
        CALL BDOSRT
        MVI A,TRUE      	; DO NOT ALLOW TERMINAL..
        STA NFLFLG     		;..SAVE SINCE NO FILE..
        CMA             	;..SPECIFIED.
        STA SAVFLG
        LXI H,FCB3
        CALL INITFCB
        JMP MENU1

WRTFIL: LDA NFLFLG
        CPI TRUE
        JZ MENU1
        LDA FCB3+1      	; CHECK THAT FILE WAS REQUESTED
        CPI ' '
        JZ MENU1
        LHLD HLSAVE
        CALL NMRECS    		; DISK WRITE ROUTINE AS USED IN..
        CALL WRTDSK     	; ..IN THE INTDSSV ROUTINE.
        CALL CLOSE3
        MVI A,TRUE
        STA NFLFLG
        CMA
	STA MACFLG		; RESET OBLECT FILE SAVE FLAG
        STA SAVFLG
        LXI H,FCB3
        CALL INITFCB   		; BLANK OUT FCB SO WRITTEN FILE..
        JMP MENU1       	; ..CAN'T BE ERASED.

XPRMODE:LDA XPRFLG
        CMAŠ        STA XPRFLG
        JMP MENU1


COMPARE:MOV B,M         	; COMPARES A-REG WITH LIST..
COMPLP: INX H           	; ..ADDRESSED BY HL. FIRST ELEMENT..
        CMP M           	; ..OF LIST MUST BE NUMBER OF ELEMENTS..
        JZ VALID        	; ..BEING COMPARED. RETRNS WITH..
        DCR B           	; ..CARRY SET IF A-REG DOES NOT..
        JNZ COMPLP      	; .. CONTAIN AN ELEMENT IN LIST.
        STC
VALID:  RET

COMPLIST:DB 5, 'S', 'R', 'T', 'E', 'K' 

ILCOMP: XTHL            	; POINT HL TO 1ST CHAR.
        PUSH D
ILCMPL: MOV A,M         	; HL POINTS TO IN-LINE STRING.
        ORA A           	; END OF STRING IF ZERO.
        JZ SAME
        LDAX D
        CMP M
        JNZ NOTSAME
        INX H
        INX D
        JMP ILCMPL
NOTSAME:MVI A,0         	; IF NOT SAME, FINISH THRU..
NSLP:   INX H           	; ..STRING SO RETURN WILL..
        CMP M           	; ..GO TO INSTRUCTION AFTER..
        JNZ NSLP        	; ..STRING AND NOT REMAINDER OF STRING.
        STC
SAME:   POP D
        INX H           	; AVOIDS A NOP INSTRUCTION..
        XTHL            	; ..WHEN RETURNING.
        RET

INBUFF: PUSH PSW
        PUSH H
        PUSH B
        PUSH D          	; DE REGISTERS MUST BE PUSHED LAST
STRT:   CALL CLEAR      	; CLEAR THE BUFFER AREA
        POP D           	; GET ADDRESS OF BUFFER ON RETRIES
        PUSH D          	; RESTORE STACK
        XRA A
        INX D           	; ADDRESS COUNT FIELD
        STAX D          	; INITIALIZE WITH A ZERO IN COUNT BYTE
        INX D
        XCHG            	; ADDRESS FIRST BUFFER BYTE WITH HL

INBUFA: CALL CONIN
	CPI 'C'-40H		;RESET DISKS?
	CZ NEWDSK		;YES,DO IT
        CPI 0DH         	; IS IT A RETURN?
        JZ INBUFR       	; IF SO, THEN RETURN
        CPI 7FH         	; IS IT A DELETE?Š        JZ DELETE
        CPI 8           	; CTRL-H WILL BACKSPACE..
        JZ DELETE       	; ..OVER DELETED CHAR.
        CPI 'U'-40H     	; IS IT A CTRL-U
        JZ INBUFO       	; OUTPUT # CR LF AND START OVER
        CPI 'R'-40H     	; CTRL-R RETYPES LINE
        JZ RETYPE
        CPI 'E'-40H
        JZ PCRLF
        CPI 20H         	; NO CONTROL CHARACTERS OTHER..
        JC INBUFA       	; ..THAN ABOVE ALLOWED.
	MOV B,A         	; SAVE INPUTTED CHARACTER
        XCHG            	; SAVE HL IN DE
        POP H           	; GET ADDRESS OF BUFFER IN HL
        PUSH H          	; RESTORE STACK
        INX H           	; ADDRESS COUNT BYTE
        INR M           	; INCREASE COUNT BYTE
        DCX H           	; ADDRESS MAXIMUM
        MOV A,M         	; PUT MAXIMUM IN A
        INX H           	; ADDRESS COUNT
        CMP M           	; COMPARE COUNT TO MAXIMUM
        JC ALERT        	; IF MAXIMUM, RING BELL AND WAIT FOR CR
        XCHG            	; RESTORE BUFFER POINTER TO HL
        MOV M,B         	; PUT INPUTTED CHARACTER IN BUFFER
        MOV A,B         	; OUTPUT IT
        CALL CONOUT
        INX H           	; BUMP POINTER
        JMP INBUFA      	; GET NEXT CHARACTER

DELETE: XCHG            	; SAVE BUFFER POINTER IN DE
        POP H           	; ADDRESS BEGINNING OF BUFFER
        PUSH H          	; RESTORE STACK
        INX H           	; ADDRESS COUNT FIELD
        MOV B,A         	; SAVE DELETE CHAR - 7FH OR 08H
        MOV A,M
        SUI 1           	; DECREASE COUNT
        MOV M,A
        JC NODEL        	; DON'T DELETE PAST BEGINING OF BUFFER.
        XCHG            	; RESTORE BUFFER POINTER TO HL
        DCX H           	; POINT TO LAST BYTE INPUTTED
        MOV A,B         	; GET BACK EITHER 7FH OR 08H
        MOV B,M         	; GET CHARACTER BEING DELETED
        MVI M,20H       	; RESTORE BLANK
        CPI 08H
        JZ BKSPC
        MOV A,B         	; ECHO CHAR IF 7FH
        CALL CONOUT
        JMP INBUFA      	; GET NEXT CHARACTER
NODEL:  INR M           	; DON'T LEAVE COUNT NEGATIVE
        XCHG            	; RESTORE POINTER TO HL
        JMP INBUFA
BKSPC:  CALL CONOUT     	; TRUE ERASE IF 08H
        MVI A,20H
        CALL CONOUT
        MVI A,08Š        CALL CONOUT
        JMP INBUFA

INBUFO: MVI A,'#'
        CALL CONOUT
        MVI A,0DH
        CALL CONOUT
        MVI A,0AH
        CALL CONOUT
        JMP STRT

RETYPE: POP D
        PUSH D
        INX D           	; POINT TO CURRENT NUMBER..
        LDAX D          	; ..OF CHARACTERS.
        MOV B,A
        MVI A,'#'
        CALL CONOUT
        MVI A,0DH
        CALL CONOUT
        MVI A,0AH
        CALL CONOUT
        MOV A,B         	; TEST IF ZERO INPUT
        ORA A
        JZ INBUFA
CTLRLP: INX D
        LDAX D
        CALL CONOUT
        DCR B
        JNZ CTLRLP
        JMP INBUFA
        
ALERT:  MVI A,7
        CALL CONOUT
        DCR M
        XCHG
        JMP INBUFA

PCRLF:  MVI A,0DH
        CALL CONOUT
        MVI A,0AH
        CALL CONOUT
        JMP INBUFA

INBUFR: MVI A,0DH
        CALL CONOUT
        MVI A,0AH
        CALL CONOUT
        POP D
        POP B
        POP H
        POP PSW
        RET

CLEAR:  POP D           	; ACCOUNTS FOR CALLŠ        POP H           	; ADDRESS BUFFER IN HL
        PUSH H          	; RESTORE..
        PUSH D          	; ..STACK
        MOV B,M         	; SAVE MAXIMUM IN B
        INX H           	; POINT TO FIRST..
        INX H           	; ..BUFFER BYTE.
        MVI A,20H
CLEARL: MOV M,A
        INX H
        DCR B
        JNZ CLEARL
        RET

CONIN:  PUSH H 
	PUSH D 
	PUSH B
CONINLP:CALL CONSTAT
        ORA A
        JZ CONINLP
	CALL CONIN1

; IF YOU WISH ALL COMMANDS GOING TO THE BUFFER TO BE CONVERTED
; TO UPPER CASE THEN RE-INITIALIZE THE FOLLOWING CODE, BUT
; THE PHONE DIRECTORY WILL THEN ONLY RECOGNIZE THE UPPER CASE
; ALPHABET
;
;       CPI 61H         	; CHANGE TO UPPER..
;       JC NOUCASE      	; ..CASE SINCE CP/M..
;       CPI 7BH         	; ..DOES THE SAME.
;       JNC NOUCASE
;       ANI 5FH

NOUCASE:POP B 
	POP D 
	POP H
        RET
CONIN1: LHLD 1
        LXI D,6
        DAD D
        PCHL

CONSTAT:PUSH H 
	PUSH D 
	PUSH B
        CALL CONST1
        POP B 
	POP D 
	POP H
        RET
CONST1: LHLD 1
        LXI D,3
        DAD D
        PCHL

CONOUT: PUSH H Š	PUSH D 
	PUSH B 
	PUSH PSW
        CALL CONOT1
        POP PSW 
	POP B 
	POP D 
	POP H
        RET
CONOT1: LHLD 1
        LXI D,9
        DAD D
        MOV C,A
        PCHL

CPMLINE:PUSH PSW
        PUSH B
        PUSH D
        PUSH H

        CALL INIT       	; FILLS FCBS WITH BLANKS AND NULLS

        XCHG            	; GET START OF COMMAND LINE IN HL.
        INX H           	; ADDRESS # BYTES IN CMD LINE.
        MOV E,M         	; LOAD DE PAIR WITH # BYTES.
        MVI D,0
        INX H
        DAD D           	; POINT TO BYTE AFTER LAST CHAR..
        MVI M,0DH       	; ..IN CMD LINE AND STORE DELIMITER.
        POP H           	; RESTORE HL AND DE.
        POP D
        PUSH D
        PUSH H
        INX D           	; ADDRESS START OF COMMAND.
        INX D

        CALL DRIV

NAME1:  MVI C,8         	; TRANSFER FIRST FILENAME TO FCB.
        CALL TRANS
        CPI 0DH
        JZ DONE2
        CPI 20H         	; IF SPACE, THEN START OF..
        JZ NAME2        	; ..SECOND FILENAME.

TYPE1:  POP H           	; FILETYPE MUST BE AFTER..
        PUSH H          	; ..EIGHTH BYTE OF NAME.
        LXI B,9
        DAD B
        MVI C,3         	; TRANSFER TYPE OF FIRST FILE
        CALL TRANS
        CPI 0DH
        JZ DONE2

NAME2:  LDAX D          	; EAT MULTIPLE SPACES..Š        CPI 20H         	; ..BETWEEN NAMES.
        JNZ NAME2C
        INX D
        JMP NAME2
        LDAX D
        CPI 0DH         	; TEST IF FIRST NAME..
        JZ DONE2         	; ..ONLY AND THEN SPACE.
NAME2C: POP H           	; SECOND NAME STARTS IN 16TH BYTE.
        PUSH H          	; POINT HL TO THIS BYTE.
        LXI B,16
        DAD B
        CALL DRIV
        MVI C,8
        CALL TRANS
        CPI 0DH
        JZ DONE2

TYPE2:  POP H           	; SECOND TYPE STARTS IN 25TH BYTE.
        PUSH H
        LXI B,25
        DAD B
        MVI C,3
        CALL TRANS

DONE2:  POP H
        PUSH H
        INX H       		; POINT TO FIRST CHAR OF FIRST NAME IN FCB.
        CALL SCANM   		; CHECK FOR * (AMBIGUOUS NAMES).
        POP H
        PUSH H
        LXI B,17    		; POINT TO FIRST CHAR OF SECOND NAME IN FCB.
        DAD B
        CALL SCANM
        POP H
        POP D
        POP B
        POP PSW
        RET

INIT:   PUSH H  		; INITIALIZES FCB WITH 1 NULL (FOR FIRST DRIV).
        PUSH B  		; ..11 BLANKS, 4 NULLS, 1 NULL (FOR 2ND DRIV),.
        MVI M,0         	; ..11 BLANKS, AND 4 NULLS.
        INX H
        MVI B,11
        MVI A,20H
        CALL INTFIL
        MVI B,5
        MVI A,0
        CALL INTFIL
        MVI B,11
        MVI A,20H
        CALL INTFIL
        MVI B,4
        MVI A,0
        CALL INTFILŠ        POP B
        POP H
        RET

INTFIL: MOV M,A
        INX H
        DCR B
        JNZ INTFIL
        RET

DRIV:   INX D           	; CHECK 2ND BYTE OF FILENAME. IF IT..
        LDAX D          	; ..IS A ":", THEN DRIV WAS SPECIFIED.
        DCX D
        CPI ':'
        JNZ DEFDR 		; ELSE ZERO DEFAULT DRIV ('INIT' PUT ZERO)
        LDAX D
        ANI 5FH
        SUI 40H         	; CALCULATE DRIV (A=1, B=2,...)..
        MOV M,A         	; ..AND PLACE IT IN FCB.
        INX D           	; ADDRESS FIRST BYTE OF..
        INX D           	; ..IN CMD LINE,..
DEFDR:  INX H           	; ..AND NAME FIELD IN FCB.
        RET

TRANS:  LDAX D          	; TRANSFER FROM CMD LINE TO FCB..
        INX D           	; ..UP TO NUMBER OF CHARS SPECIFIED..
        CPI 0DH         	; ..BY C-REG. KEEP SCANNING FIELD..
        RZ              	; ..WITHOUT TRANSFER UNTIL DELIMITING..
        CPI '.'         	; ..FIELD CHAR SUCH AS '.', BLANK, OR..
        RZ              	; ..C/R (FOR END OF CMD LINE).
        CPI 20H
        RZ
        DCR C
        JM TRANS  		; ONCE C-REG IS LESS THAN ZERO, KEEP READING..
        MOV M,A         	; ..CMD LINE BUT DO NOT TRANSFER TO FCB.
        INX H
        JMP TRANS

SCANM:  MVI B,8         	; SCAN FILE NAME ADDRESSED BY HL.
TSTNAM: MOV A,M
        CPI '*'         	; IF '*' FOUND, FILL IN REST OF FIELD..
        JZ FILL1        	; ..WITH '?' FOR AMBIGUOUS NAME.
        INX H
        DCR B
        JNZ TSTNAM
        JMP TSTTYP
FILL1:  CALL FILL

TSTTYP: MVI B,3         	; SCAN AND FILL TYPE FIELD FOR NAME..
TSTYPL: MOV A,M         	; ..SPECIFIED ABOVE.
        CPI '*'
        JZ FILL2
        INX H
        DCR B
        RZŠ        JMP TSTYPL
FILL2:  CALL FILL
        RET

FILL:   MVI M,'?'       	; ROUTINE TRANSFERS '?'.
        INX H
        DCR B
        JNZ FILL
        RET


DIRLST: LXI D,CMDBUF    	; PUT COMMAND LINE IN FCB
        LXI H,5CH
        CALL CPMLINE
        LXI H,SRCHFCB
        CALL INITFCB
        LDA 6CH         	; GET DRIVE #
        STA SRCHFCB
        LDA 6DH
        CPI 20H         	; IF BLANK GET ALL NAMES
        PUSH PSW
        CZ QSTMARK
        POP PSW
        CNZ MVNM    		; ELSE MOVE NAME INTO FCB
        CALL DRIVE
        LXI D,80H
        MVI C,STDMA
        CALL BDOS
        XRA A
        STA NAMCT      		; CR AFTER 4 NAMES
        LXI D,SRCHFCB
        MVI C,SRCHF     	; DO FIRST SEARCH
        CALL BDOS
        CPI 0FFH
        JZ NOFILE

DIRLP:  CALL GETADD
        LXI D,15        	; OFFSET FOR RECORD COUNT
        DAD D
        MOV A,M
        ORA A
        JZ NEXTSR       	; NO LIST IF FILE IS ZERO LENGTH
        LXI D,-5
        DAD D           	; POINT TO $SYS ATTRIB BYTE
        MOV A,M
        ANI 80H
        JNZ NEXTSR      	; NO LIST IF $SYS FILE
        LXI D,-10
        DAD D           	; POINT TO BEGINNING OF NAME
        INX H           	; POINT TO FIRST LETTER
        LXI D,PRNTNM
        MVI B,8
        CALL MOVE
        INX D
        MVI B,3Š        CALL MOVE

        CALL ILPRT
PRNTNM: DB '        ',' ','   ',  ' | ', 0   ;8,1,3 SPACES

        LDA NAMCT
        INR A
        STA NAMCT
        ANI 03H
        ORA A
        CZ CRLF
NEXTSR: LXI D,SRCHFCB
        MVI C,SRCHN     	; DO NEXT SEARCH
        CALL BDOS
        CPI 0FFH
        JZ DIRDONE
        JMP DIRLP

NOFILE: CALL ILPRT
        DB CR,LF,'++ FILE NOT FOUND ++',0

DIRDONE:CALL CRLF
        RET
;
SCDSK:  DB  0
;
QSTMARK:MVI A,'?'       	; IF BLANK IN FCB, PUT IN 11 ?'s
        MVI B,11
        LXI H,SRCHFCB+1
QSTLP:  MOV M,A
        INX H
        DCR B
        JNZ QSTLP
        RET

MVNM:   LXI H,6DH
        LXI D,SRCHFCB+1
        MVI B,11
        CALL MOVE               ; MOVE IN CP/M PROGRAM
        RET

GETADD: ANI 03H                 ; GET MOD4 FOR CP/M 1.4
        ADD A 
	ADD A 
	ADD A   		; ADD 32
        ADD A 
	ADD A
        MOV E,A
        MVI D,0
        LXI H,80H               ; ADD DMA OFFSET
        DAD D
        RET

DRIVE:  LDA SRCHFCB             ; IF NO DRIVE, CAL
        ORA A                   ; LOGGED IN DRIVEŠ        JZ CALCDR
        ADI 40H
        JMP PRNTHD
CALCDR: MVI C,25
        CALL BDOS
        ADI 41H
PRNTHD: STA DRNAME

        CALL ILPRT
        DB CR,LF,'++ DRIVE '
DRNAME: DB ' :',CR,LF,0
        RET

	IF OSBORNE

OSCODE	EQU	$

OFSET	EQU	0A000H	; OUT OF HARMS WAY


SIN EQU $-OSCODE+OFSET
 DI
 OUT 0
; MOV B,A
 LDA 2A01H
 OUT 1
 EI
 RET

SOUT EQU $-OSCODE+OFSET
 DI
 OUT 0
; MOV B,A
 STA 2A01H
 OUT 1
; MOV A,B
 EI
 RET

SSTAT EQU $-OSCODE+OFSET
 DI
 OUT 0
 LDA 2A00H
 OUT 1
 EI
 RET

OLENG	EQU	$-OSCODE+1
	ENDIF	; OSBORNE


SRCHFCB:DS 33
NAMCT:  DS 1

ŠNFLFLG:DB FALSE      		; NORMALLY SET TO FALSE. ALLOWS WRITE TO..
                      		; ..MEMORY IN TERMINAL MODE.

OPTION: DB 0

OPTBL   EQU $
DISCFLG:DB 'D'
QFLG:   DB 'Q'
RSEEFLG:DB 'R'
SSEEFLG:DB 'S'
VSEEFLG:DB 'V'
TERMFLG:DB 'T'
ECHOFLG:DB 'E'
CRCFLG: DB 'C'
BATCHFLG:DS 1   		; SET TO 'B' BY MENU. DOES NOT ALLOW MULTI-..
OPTBE   EQU $   		; ..FILE XFER WHEN PROGRAM INITIALLY CALLED.

RESTROPT:       		; MUST BE IN SAME ORDER AS TABLE ABOVE

        DB 'D','Q','R','S','V','T','E','C','B'

RESTSN: DB 0,0,0,0,0,0
        DW DBUF
        DB 0,0,0,0,0,0

SECTNB  EQU $
RCVSNO: DB 0
SECTNO: DW 0
ERRCT:  DB 0
ERRCDE: DB 0
EOFLG:  DB 0
SECPTR: DW DBUF
SECINBF:DB 0
MAXEXT: DB 0
RCNT:	DW 0
DATAFLG:DB 0
EXACFL:	DB 0
SECTNE  EQU $

FSTFLG: DB TRUE

CMDBUF: DB 80H,0
        DS 80H

HLSAVE: DS 2
DISKNO: DS 1
SENDFLG:DS 1
NBSAVE: DS 2
BGNMS:  DS 2
FILECT: DS 1
NAMECT: DS 1

        DS 60
STACK:  DS 2
FCB3:   DS 33ŠFCBBUF: DS 15

BOTRAM	EQU	$		; BOTTOM OF SMODEM3 RAM

DBUF	EQU $   		; DISK BUFFER...DBFSIZ SET AT 
				; BEGINNING
NAMEBUF EQU DBUF+(DBFSIZ*1024)	; BUFFER FOR NAMES IN BATCH MODE.
				; OVERFLOWS ABOVE PROGRAM CODE.
;        BDOS EQUATES

RDCON   EQU 1
WRCON   EQU 2
PRINT   EQU 9
RDBUF   EQU 10
CONST   EQU 11
RESET   EQU 13
SELDSK  EQU 14
OPEN    EQU 15
CLOSE   EQU 16
SRCHF   EQU 17
SRCHN   EQU 18
ERASE   EQU 19
READ    EQU 20
WRITE   EQU 21
MAKE    EQU 22
REN     EQU 23
RCDSK	EQU 25
STDMA   EQU 26
FILSIZ	EQU 35
BDOS    EQU 5
REIPL   EQU 0
FCB     EQU 5CH
FCBEXT  EQU FCB+12
FCBSNO  EQU FCB+32
FCBRNO  EQU FCB+32
FCB2    EQU 6CH

END                    

