.title	K11DIA	dial command for kermit-11
	.ident	/t2.40/

;	18-Oct-85  20:06:09 Brian Nelson
;
;	04-Dec-85  11:22:32 BDN	 Add optional linked list structure to
;				define modem responses, will be useful
;				when adding a SET DIAL command.
;	06-Dec-85  11:53:59 BDN	 Added extra field in DEFINE macro and
;				support code to call external routines
;				for dialing, needed for PRO/TMS.
;	09-Jan-86  17:48:17 RTM  Added support for the RIXON Intelligent
;		(RTM01)		autodial modem (R212A).
;
;	13-Feb-86  10:10:08 BDN	 Put the DF112 and DF224 responses into
;				linked lists.
;	23-Sep-86  14:10:30 BDN	 Vadic 4224 modems
;	23-Sep-86  14:10:42 BDN	 Added format effector %M for pulse/tone
;				if a SET PHONE PULSE/TONE was done. Also
;				added %B for 'blind' dialing, enabled if
;				SET PHONE BLIND
;	30-Sep-86  13:05:53 BDN	 Added CTS2424, Also SHO DIAL
;	09-Feb-89  00:00:00 JCH  Complete definition of DF224 modem.
;
;	Copyright (C) 1985 1986 Change Software, Inc.
;
;
;	 Its about time for a DIAL command. Would be really nice to use
;	on my PRO/350 and the XK: port. Of limitted utility  on the  44
;	as I  have to enter the GANDALF PACX to access the VADIC 212PAR
;	modems.
;
;	 As noted in a number of comments, the timer support for RSTS/E
;	is abbysmal, the only thing you can do is SLEEP n, where 'n' is
;	in seconds.  Even worse is  the fact that various  asynchronous
;	events can prematurely cancel the sleep, like a delimiter typed
;	at a terminal allocated to the job. Also, you can NOT do a mark
;	time on RSTS/E, though version 9 does have the groundwork layed
;	for adding timer AST's in that v9 supports asych i/o,  thus the
;	needed executive data structures are mostly present.
;
;	 I do not mean to knock RSTS/E really,  RSTS has a great number
;	of features that make interfacing with the terminal driver much
;	simpler than what one finds on RSX and RT11,  while at the same
;	time introducing its own peculiarities. RSX is by far the worst
;	as I often find grossly dissimiliar behavior between RSX sites.
;
;	 As a final reflection, if I were to grade RSTS, RT and RSX  on
;	simplicity and stability of terminal driver interfacing,   RT11
;	would have to come first (both MT and XC/XL versions), followed
;	by RSTS and bringing up the rear, RSX (I've been burned on both
;	RSX and RSTS when new versions came out,  though being a RSTS/E
;	field test site tends to help).





	.if ndf, K11INC
	.ift
	.include	/IN:K11MAC.MAC/
	.endc

	.enabl	lc
	.nlist


;	 It would be nice to be able to do this in a macro call but the
;	PDP-11 assembler does not allow continuation lines.  So what we
;	will instead do is define each arg as a word offset from a base
;	address of a list for that modem.
;	In many cases we could fit all the info on one line, but macros
;	dragged out that way are unreadable. It would be really nice to
;	be able to say:
;
;	moddef	type	= <VA212PAR> - ,
;		dial.time = 30. - ,
;		wake.string = .....      and so on.
;
;	.macro	moddef	dial.t,wake.s,wake.r,wake.p,dmod.s,dmod.p,dial.s,dial.r
;
;	Losely based on CKUDIAL.C
;
;	All times for delays are in TICKS (1/60 second intervals)
;
;	dial.time	Time the modem may use to dial a number
;	wake.string	Get modems attention, like in VADIC 212 ^E<CR>
;	wake.rate	Delay in milliseconds modem may need
;	wake.prompt	Modems command mode prompt
;	dmod.string	String needed to get it to dial a number
;	dmod.prompt	Dial mode prompt
;	dial.string	The string for dial, includes a %s for number position
;	dial.rate	delay between sending numbers over, in TICKS
;	wake.ack	as in va212, 'HELLO:I'M READY'
;	dial.ack	string to wait for to confirm number
;	dial.echo
;
;	WARNING: If any of these values are CHANGED, and there is absolutely
;	NO reason to do so,  you must check K11ST0.MAC  where a few of these
;	are also defined for the SET DIAL command. Anything new that's need-
;	ed in the modem database is  always added on to the END of the list.
;	While it is freely acknowledged that there are  now a couple of  ob-
;	solete fields, it doesn't cost that much. Leave the structure alone.

	mod.next	=:	0	; next modem in list
	mod.str		=:	2	; address of name of modem
	mod.val		=:	4	; numeric value for dispatching
	dial.time	=:	6	; value of dial time
	wake.string	=:	10	; address of wakeup string
	wake.rate	=:	12	; value of delay
	wake.prompt	=:	14	; address of wakeup prompt
	dmod.string	=:	16	; address of dial dial string
	dmod.prompt	=:	20	; address of prompt returned for dial
	dial.string	=:	22	; address of formatting string for dial
	dial.rate	=:	24	; value of delay
	wake.ack	=:	26	; address of wakeup response
	dial.ack	=:	30	; 1st = waitfor, 2nd to confirm number
	dial.online	=:	32	; online ack string
	dial.blind	=:	34	; blind ack
	dial.wait	=:	36	; String for PAUSE characters
	dial.confirm	=:	40	; string to confirm number for dialing
	dial.go		=:	42	; ie, va212 returns "DIALING\n"
	res.bin		=:	44	; if <>, returns status with \n
					; otherwise a binary response (DF03)
	dial.echo	=:	46	; if <>, numbers are echoed immediately
	mod.comment	=:	50	;
	res.head	=:	52	; 
	ext.dial	=:	54	; if ne, address of external dialer
	dial.xabort	=:	56	; /45/ To abort call from modem
	dial.idle	=:	60	; /45/ Place modem in IDLE state
	dial.pulse	=:	62	; /45/ Switch to pulse dialing
	dial.nopulse	=:	64	; /45/ Switch to tone dialing
	def.guard	=:	66	; /45/ last thing (unused)




	.psect	modinf	,ro,d,lcl,rel,con
	.enabl	lc

	.macro	modval	val,offset
	.save
	.psect	modinf
	. = $$current + offset
	.word	val
	.restore
	.endm	modval

	.macro	modstr	s,offset
	.save
	.psect	string
	$$addr	=	.
	$$ = 0
	.irpc	ch,<s>
	 ch1 = ''ch
	 .if eq, ch1 - '^
	 .ift
	   $$ = 100
	 .iff
	   .if ne	,$$
	   .if ge	, <ch1!40> - <'a!40>
	    .iif le, <ch1!40> - <'z!40>, ch1 = ch1&137
	   .endc
	   .endc
	 .byte	ch1-$$
	 $$ = 0
	 .endc
	.endr
	.byte	0
	.restore
	.save
	.psect	modinf
	. = $$current + offset
	.word	$$addr
	.restore
	.endm	modstr
	

	.sbttl	inialize subfields of modem info structure


	.macro	dial$time	val
	modval	val,dial.time
	.endm	dial$time

	.macro	wake$rate	val
	modval	val,wake.rate
	.endm	wake$rate

	.macro	dial$rate	val
	modval	val,dial.rate
	.endm	dial$rate

	.macro	wake$string	s
	modstr	<s>,wake.string
	.endm	wake$string

	.macro	wake$prompt	s
	modstr	<s>,wake.prompt
	.endm	wake$prompt

	.macro	dmod$string	s
	modstr	<s>,dmod.string
	.endm	dmod$string

	.macro	dmod$prompt	s
	modstr	<s>,dmod.prompt
	.endm	dmod$prompt

	.macro	dial$string	s
	modstr	<s>,dial.string
	.endm	dial$string

	.macro	mod$comment	s
	modstr	<s>,mod.com
	.endm	mod$comment

	.macro	dial$ack	s
	modstr	<s>,dial.ack
	.endm	dial$ack

	.macro	dial$confirm	s
	modstr	<s>,dial.confirm
	.endm	dial$confirm

	.macro	dial$online	s
	modstr	<s>,dial.online
	.endm	dial$online

	.macro	dial$blind	s
	modstr	<s>,dial.blind
	.endm	dial$blind

	.macro	dial$wait	s
	modstr	<s>,dial.wait
	.endm	dial$wait

	.macro	dial$go		s
	modstr	<s>,dial.go
	.endm	dial$go

	.macro	dial$echo	v
	modval	v,dial.echo
	.endm	dial$echo

	.macro	dial$pulse	s	; /45/ String to force PULSE dialing
	modstr	<s>,dial.pulse		; /45/ ...
	.endm	dial$pulse		; /45/ ...

	.macro	dial$nopulse	s	; /45/ String to force tone dialing
	modstr	<s>,dial.nopulse	; /45/ ...
	.endm	dial$nopulse		; /45/ ...

	.macro	dial$xabort	s	; /45/ Use this field if we detect
	modstr	<s>,dial.xabort		; /45/ a control C abort and need
	.endm	dial$xabort		; /45/ to get the modem to stop dialing

	.macro	dial$idle	s	; /45/ Switch from command mode to
	modstr	<s>,dial.idle		; /45/ to IDLE mode
	.endm	dial$idle		; /45/


	.macro	ext$dial	v
	modval	v,ext.dial
	.endm	ext$dial

	.macro	res$bin	v
	modval	v,res.bin
	.endm	res$bin

	.macro	wake$ack	s
	modstr	<s>,wake.ack
	.endm	wake$ack


	$$prev	=	modinf
	$$seq	=	1

	.save
	.psect	usermd	,rw,d,gbl,rel,con
null2:	.byte	0
null:	.byte	0
	.psect	string	,ro,d,lcl,rel,con
	.psect	rwdata	,rw,d,lcl,rel,con
bell:	.byte	'G&37,'G&37,0
	.even
modtyp:	.word	0
buffer:	.blkb	200
ttbuff:	.blkb	200
	.restore	


	.macro	define	lab	,s	,user

	.if nb	,user			; if we are defining the 'user'
	.ift				; modem we need to be in a global
	.save				; psect to be located in the root
	.psect	usermd	,rw,d,gbl,rel,con ; put a reference to this psect
	.iff				; in k11dat
	$modtail==	.		; to manually set link to 'usermd'
	.endc				; 
	.iif	ndf, $$prev	,$$prev = modinf
	$$current	=	.	; save current pc
	$res	=	0
	$reslast=	0
lab:	.word	0			; link to next please
	.iif nb, user, .globl lab	; must be global if USER mode
	.save				; save current psect
	.psect	string			; switch to string psect
	$$ = .				; save it's current PC
	.asciz	/s/			; insert the modem type string
	.even				; always useful for word addressing
	.restore			; pop the previous psect (modinf)
	.word	$$			; and insert address of the string
	$'lab	=	$$seq		; define sequence value
	.word	$$seq			; store value in structure
	$$seq	=	$$seq + 1	; sequence number
	.word	30.			; default for dial time
	.word	null			; default for wakeup
	.word	0			; default for delay
	.word	null			; default for command mode prompt
	.word	null			; default for dial command
	.word	null			; default for dial prompt
	.word	null			; default for dial formatting
	.word	0			; default for dial delay
	.word	null			; default for wakeup ack
	.word	null2			; default for ack string
	.word	null			; default for dial.online
	.word	null			; default for dial.blind
	.word	null			; default for dial.wait
	.word	null			; default for dial.confirm
	.word	null			; default for dial.go
	.word	0			; 0 normal, else 1 for binary (res.bin)
	.word	0			; default for dial.echo
	.word	null			; default for MOD$COMMENT
	.word	0			; res.head
	.word	0			; possible external dialer address
	.word	null			; /45/ Default for XABORT string
	.word	null			; /45/ Default for IDLE string
	.word	null			; /45/ Default for PULSE dialing
	.word	null			; /45/ Default for TONE dialing
	.word	0			; guard word
	$$end	=	.

	$$size	=	$$end - $$current
	.assume	$$size  eq <def.guard+2>

	.if b	,user			; we don't want psect errors from
	.ift				; MAC for the USER modem type.
	.	=	$$prev
	.word	lab
	.	=	$$end
	$$prev	=	lab
	.iff
	.restore			; for USER type, return to old psect
	.endc				; Also, the USER modem MUST be last
	.endm	define


	.sbttl	create a linked list, header in res.head

;	Added edit /39/ Brian Nelson  4-DEC-1985 09:46
;
;	 Create a linked  list  of  possible  modem  responses.  The
;	advantages  of  this is that we could use a SET DIAL command
;	to create a modem data  structure  at  run  time,  and  that
;	defining  modems  is  simplified.  As  a  note,  there is no
;	requirement to use this structure. It will be used  for  the
;	DEFAULT entry in the 'GETSTS' routine. 
;
;
;	Format is:	res.head(current_modem) --> first entry
;
;
;	Entry format:	.word	next	(or zero for tail)
;			.word	class	(-1 fail, 0 info, 1 sucess)
;			.asciz	/response_string/

	CONNECT	=	1
	INFO	=	0
	FAILED	=	-1


	.save
	.psect	resdat	,rw,d,lcl,rel,con
resdat:
	.restore

	.macro	mod$res	s,class

	.save				; save current psect context
	.psect	resdat	,rw,d,lcl,rel,con
	$res1	=	.		; save current pc in 'resdat'
	.word	0			; link to next is zero
	.if b, class			; if class not specified, then
	.word	0			; make it zero
	.iff				; else insert it
	.word	class			; response class
	.endc				; if b, class
	.asciz	/s/			; the actual text
	.even				; must do
	.restore			; get last psect
	.if eq	,$res			; is this first time for new
	.ift				; type ?
	modval	$res1,res.head		; yes, stuff the link header
	.iff				; not the first time
	.save				; save current psect context
	.psect	resdat			; and a new one
	$respc = .			; save the current pc
	. = $reslast			; backup to link word from previous
	.word	$res1			; insert address of new entry
	. = $respc			; restore correct pc
	.restore			; restore old psect context
	.endc				; end
	$reslast = $res1		; lastlink = current_entry
	$res	=	1		; not the first time anymore

	.endm				; thats it

	.list


	.sbttl	finally, we can define the modem
	.psect	modinf	,ro,d,lcl,rel,con


;	All xxxx$rate values are in TICKS (1/60 second)
;	WARNING: The definition for USER_DEFINED MUST be last !!!!!!!
;	WARNING: Before accessing any data here  from outside of this
;	module (overlay), insure the overlay is loaded, as in calling
;	FINDMODEM with the modem type string .asciz pointed to by R5.

modinf::
	define	v2pa	,<VA212PA>	; stand alone VA212PA
	dial$time	35.
	wake$string	<^E^M>
	wake$rate	10		; wait 8 ticks (8/60 second)
	wake$ack	<HELLO:I'M READY>
	wake$prompt	<*>
	dmod$string	<D^M>
	dmod$prompt	<?>
	dial$string	<%s^M>
	dial$rate	10
	dial$ack	<^M>
	dial$confirm	<^M>
	dial$go		<DIALING>
	dial$echo	1
	dial$xabort	<^M>
	dial$idle	<I^M>
	dial$wait	<K>
	mod$comment	<Stand alone VADIC VA212>
	mod$res		<ON LINE>	,CONNECT
	mod$res		<ONLINE>	,CONNECT
	mod$res		<BUSY>		,FAILED
	mod$res		<FAILED CALL>	,FAILED
	mod$res		<NO DIAL>	,FAILED
	mod$res		<VOICE>		,FAILED
	mod$res		<TIME OUT>	,FAILED
	mod$res		<RINGING>	,INFO

	define	v2par	,<VA212PAR>	; rack mounted VA212PAR
	dial$time	35.
	wake$string	<^E^M>
	wake$rate	10
	wake$ack	<HELLO:I'M READY>
	wake$prompt	<*>
	dmod$string	<D^M>
	dmod$prompt	<?>
	dial$string	<%s^M>
	dial$rate	10
	dial$go		<DIALING>
	dial$echo	1
	dial$xabort	<^M>
	dial$idle	<I^M>
	dial$wait	<K>
	mod$comment	<Rack mounted VADIC VA212PAR>
	mod$res		<ON LINE>	,CONNECT
	mod$res		<ONLINE>	,CONNECT
	mod$res		<BUSY>		,FAILED
	mod$res		<FAILED CALL>	,FAILED
	mod$res		<NO DIAL>	,FAILED
	mod$res		<VOICE>		,FAILED
	mod$res		<TIME OUT>	,FAILED
	mod$res		<RINGING>	,INFO

	define	vadic	,<VADIC>	; stand alone VA212PA
	dial$time	35.
	wake$string	<^E^M>
	wake$rate	10
	wake$ack	<HELLO:I'M READY>
	wake$prompt	<*>
	dmod$string	<D^M>
	dmod$prompt	<?>
	dial$string	<%s^M>
	dial$rate	10
	dial$ack	<^M>
	dial$confirm	<^M>
	dial$go		<DIALING>
	dial$echo	1
	dial$xabort	<^M>
	dial$idle	<I^M>
	dial$wait	<K>
	mod$comment	<Generic VADIC with autodial>
	mod$res		<ON LINE>	,CONNECT
	mod$res		<ONLINE>	,CONNECT
	mod$res		<BUSY>		,FAILED
	mod$res		<FAILED CALL>	,FAILED
	mod$res		<NO DIAL>	,FAILED
	mod$res		<VOICE>		,FAILED
	mod$res		<TIME OUT>	,FAILED
	mod$res		<RINGING>	,INFO


	define	cts24	,<CTS2424>	; CTS (Fabritek) 2424 autodial
	dial$time	35.
	wake$string	<^T^WAT^Q^M>	; Just in case add ^Q<cr> in also
	wake$rate	10
	wake$ack	<Modem Ready>
	dial$string	<D%M%B%S^M>
	dial$rate	10
	dial$xabort	<^T^W>
	dial$idle	<^T^W>
	dial$wait	<+>
	dial$pulse	<P>
	dial$nopulse	<T>
	dial$blind	<&>
	dial$echo	1
	mod$comment	<CTS/Fabri-Tek 2424AD V.22bis Autodialier>
	mod$res		<Ring>		,INFO
	mod$res		<Busy>		,FAILED
	mod$res		<Dead Line>	,FAILED
	mod$res		<Disconnect>	,FAILED
	mod$res		<Modem Ready>	,INFO
	mod$res		<No Answer>	,FAILED
	mod$res		<No Dialtone>	,FAILED
	mod$res		<No Tone>	,FAILED
	mod$res		<On Line>	,CONNECT
	mod$res		<On Line Originate>,CONNECT
	mod$res		<Redialing>	,INFO


	define	va42	,<VA4224>	; Rack mount 2400 baud
	dial$time	35.
	wake$string	<^E^M>
	wake$rate	10
	wake$ack	<HELLO:I'M READY>
	wake$prompt	<*>
	dial$string	<D%M%S%B^M>
	dial$rate	10
	dial$go		<DIALING>
	dial$echo	1
	dial$xabort	<^M>
	dial$idle	<I^M>
	dial$wait	<K>
	dial$pulse	<P>
	dial$nopulse	<T>
	dial$blind	<B>
	mod$comment	<Vadic 4224 CCITT V.22bis autodial>
	mod$res		<ON LINE>	,CONNECT
	mod$res		<ONLINE>	,CONNECT
	mod$res		<BUSY>		,FAILED
	mod$res		<FAILED CALL>	,FAILED
	mod$res		<NO DIAL>	,FAILED
	mod$res		<VOICE>		,FAILED
	mod$res		<TIME OUT>	,FAILED
	mod$res		<RINGING>	,INFO
	mod$res		<ON LINE 300>	,CONNECT
	mod$res		<ON LINE 1200>	,CONNECT
	mod$res		<ON LINE 2400>	,CONNECT
	mod$res		<ERROR CONTROL>	,INFO
	mod$res		<NO ERROR CONTROL>,INFO

	define	df03	,<DF03>		; dec DF03
	dial$time	30.
	wake$string	<^A^B>
	dial$string	<%s>
	dial$echo	1
	res$bin		1		; responds in binary (no crlf)
	mod$comment	<DEC DF03AC Autodial modem>

	define	df100	,<DF100>	; a DF112
	dial$time	30.
	wake$string	<^B>
	wake$rate	0
	wake$ack	<Ready>
	wake$prompt	<Ready>
	dial$string	<%s#>		; /45/
	dial$rate	10
	dial$xabort	<^M>
	dial$echo	1
	mod$comment	<DEC Standalone DF112>
	mod$res		<Attached>	,CONNECT
	mod$res		<Busy>		,FAILED
	mod$res		<Disconnected>	,FAILED
	mod$res		<Error>		,FAILED
	mod$res		<No answer>	,FAILED
	mod$res		<No dial tone>	,FAILED
	mod$res		<Speed:>	,FAILED

	define	df200	,<DF200>	; a DF2xx ?
	dial$time	30.
	wake$string	<^B>
	wake$rate	0
	wake$ack	<Ready>
	wake$prompt	<Ready>
	dial$string	<%b%m%s!>		; /60/
	dial$rate	0
	dial$xabort	<^B>			; /60/
	dial$echo	1
	dial$pulse	<P>			; /60/
	dial$nopulse	<T>			; /60/
	dial$blind	<^A>			; /60/
	mod$comment	<DEC Standalone DF224>
	mod$res		<Attached>	,CONNECT
	mod$res		<Busy>		,FAILED
	mod$res		<Disconnected>	,FAILED
	mod$res		<Error>		,FAILED
	mod$res		<No answer>	,FAILED
	mod$res		<No dial tone>	,FAILED
	mod$res		<Speed:>	,FAILED


	define	hayes	,<HAYES>	; actually, its a VOLKSMODEM 12
	dial$time	35.		; that we are testing with. It's
	wake$string	<ATZ V1^M>	; supposed to be compatible.
	wake$rate	0
	wake$ack	<OK>
	wake$prompt	<OK>
	dmod$string	<>
	dmod$prompt	<>
	dial$string	<AT D %s^M>
	dial$rate	0
	dial$echo	1


	define	microcom,<MICROCOM>	; 
	dial$time	35.
	wake$string	<4445^MSE2^MS1C0^MSCE ON^M>
	wake$rate	10
	wake$ack	<!>
	wake$prompt	<!>
	dial$string	<D%s^M>
	dial$rate	10
	dial$echo	1
	mod$res		<CONNECT>	,CONNECT
	mod$res		<NO CONNECT>	,FAILED
	mod$res		<!>		,FAILED
	mod$comment	<MicroCom SX1200>

;	The following entry was added by edit (RTM01).

	define	r212a	,<R212A>	; RIXON R212A Intelligent modem.
	dial$time	60.		; Long timeout for overseas.
	wake$string	<^M^M>
	wake$rate	10		; wait 8 ticks (8/60 second)
	wake$ack	<RIXON R212A INTELLIGENT MODEM>
	wake$prompt	<$>
	dmod$string	<K>
	dmod$prompt	<NUMBER:>
	dial$string	<%s^M>
	dial$rate	10
;	dial$ack	<^M>
;	dial$confirm	<^M>
	dial$go		<DIALING:>
	dial$echo	1
	mod$comment	<RIXON R212A Intelligent Modem>
	mod$res		<ON LINE>	,CONNECT
	mod$res		<ON-LINE>	,CONNECT
	mod$res		<NO ANSWER>	,FAILED
	mod$res		<DEAD LINE>	,FAILED
	mod$res		<BUSY>		,FAILED
	mod$res		<END D>		,INFO
	mod$res		<RINGING>	,INFO

	define	protms	,<PROTMS>	; this one has to use QIOS for dial
	ext$dial	tmsdial		; we will have to catch this one in
					; a not so clean manner. Waiting for
					; Steve Kovey's code for support.



	.sbttl	define user defined modem structure

;	 This one <USER_DEFINED> MUST be the last one in the list. The link
;	must  be inserted  at run time via a call to FINDMODEM with a known
;	type, like CALLS FINDMO,<#vadid>.
;	 NONE of the field macros used above  will work for this since  the
;	psect it's in is global.
;	 Setting up the fields is fairly simple,  for example,  setting the
;	wakeup string would be:
;
;	mov	#usermd	,r4
;	strcpy	#udiawake,argbuf
;	mov	#udiawake,wake.string(r4)	; stuff wakeup string addr
;
;	And setting a reponse string, assuming CONNECT is success
;
;	mov	#usermd	,r4		; address of data structure
;	mov	#contxt	,res.header(r4)	; and stuff the list in
;
;	contxt:	.word	faitxt		; link to next
;		.word	1		; > 0 for indicating connect
;		.asciz	/CONNECT/	; the string itself
;		.even			; please
;	faitxt:	.word	0		; no link to next
;		.word	-1		; flag call failed
;		.asciz	/NOCONNECT/	; the text if it fails
;		.even			; please
;
;	Where udiawake was a area in the root,  defined in  K11DAT.MAC
;	Keep in mind that the code which looks for a response will NOT
;	exit until (1) nothing happens for 30 seconds or  (2) it finds
;	a match in the list with a non-zero status.


	define	usermd	,<USER_DEFINED>,GLOBAL ; This MUST be the last one


;	No more definitions allowed past here




	.sbttl	local macros to make life simpler

	.macro	lowcase	s
	mov	s	,r0
	call	lowcas
	.endm	lowcase

	.macro	sleep	time
	calls	suspend	,<time,#0>
	.endm	sleep

	.macro	tsleep	ticks
	calls	suspend	,<#0,ticks>
	.endm	tsleep

	.macro	ttputstr	s
	mov	r1	,-(sp)
	mov	s	,r1
	call	doput
	mov	(sp)+	,r1
	.endm	ttputstr

	.macro	ttputc	c
	clr	-(sp)
	bisb	c	,(sp)
	mov	sp	,r0
	calls	binwri	,<r0,#1,#lun.ti>
	tst	(sp)+
	.endm	ttputc

	.macro	ttgetc	wait

;	lun.ti is the remote lun

	.if b	,wait
	.ift
	calls	xbinread,<#lun.ti,#0>
	.iff
	calls	xbinread,<#lun.ti,wait>
	.endc
	
	.endm	ttgetc


	.macro	waitfor	s	,time,fail
	.if	b	,time
	.ift
	clr	-(sp)
	.iff
	mov	time	,-(sp)
	.endc
	mov	s	,-(sp)
	call	waitfor
	.if nb, fail
	tst	r0
	beq	fail
	.endc
	.endm	waitfor

	.macro	waitc	c	,time
	clr	-(sp)
	mov	sp	,r0
	movb	c	,(r0)
	.if	b	,time
	.ift
	clr	-(sp)
	.iff
	mov	time	,-(sp)
	.endc
	mov	r0	,-(sp)
	call	waitfor
	tst	(sp)+
	.endm	waitc

	.macro	didweget	s,pat,status,ret,?b
	.save
	.psect	string
	$$ 	= .
	.asciz	/pat/
	.restore
	mov	#$$	,-(sp)
	mov	s	,-(sp)
	call	didweget
	tst	r0
	beq	b
	mov	status	,ret
b:
	.endm	didweget

	remmod	=	ter$cc


	.sbttl	REDIAL command

	.psect	$code
	.enabl	lsb

c$redi::mov	argbuf	,r3		; /40/ argbuf address
	mov	phnum	,r2		; /40/ address of phone number
	mov	#1	,r4		; /40/ default repeat count
	tstb	@r3			; /40/ Any repeat count passed ?
	beq	5$			; /40/ No
	calls	l$val	,<r3>		; /40/ retry count
	mov	r1	,r4		; /40/ save repeat count
	tst	r0			; /40/ success ?
	beq	5$			; /40/ yes
	message	<Invalid number!>,cr
	br	90$			; /40/ exit
5$:	tstb	@r2			; /40/ Any real phone number today?
	bne	10$			; /40/ yes
	message	<No previous number!>,cr
	br	90$			; /40/ exit if no DIAL command
10$:	message	<Using: >		; /40/ echo the number we will use
	print	r2			; /40/
	message				; /40/ crlf
	strcpy	r3	,r2		; /40/ copy old phone num to 'argbuf'

20$:	tst	cccnt			; /40/ control C abort ?
	bne	90$			; /40/ Yes, exit this loop NOW
	mov	r4	,-(sp)		; /40/ save looping counter
	call	c$dial			; /40/ no, try dialing
	mov	(sp)+	,r4		; /40/ restore looping counter
	tst	r0			; /40/ success ?
	beq	100$			; /40/ yes
	sob	r4	,20$		; /40/ No, try again please

90$:	mov	#-1	,r0		; /40/ failure
	inc	status			; /45/ Set global flag also
100$:	return

	.dsabl	lsb


set$mo::strcpy	#modem	,argbuf
	call	findmodem
	tst	r0
	bne	100$
	mov	#-1	,r0
	inc	status			; /45/ Global flag also
	return
100$:	clr	r0
	return



	

	.sbttl	the DIAL command

	.psect	$code
	.enabl	lsb

c$dial::strcpy	phnum	,argbuf		; /40/ save the phone number
	tstb	ttdial			; check for a real terminal name
	bne	10$			; ok
	message	<Please use the SET LINE command first>,cr
	br	90$			; exit
10$:	tstb	modem			; check for a SET MODEM command
	bne	20$			; ok
	tst	proflg			; /39/ is this a pro/350 ?
	beq	15$			; /39/ no, fatal error
	cmpb	ttdial	,#'X&137	; /39/ check for XTn:
	bne	15$			; /39/ no
	cmpb	ttdial+1,#'T&137	; /39/ if so, must be TMS on P/OS
	bne	15$			; /39/ no, so no modem type fatal
	strcpy	#modem	,protms+mod.str	; /39/ stuff 'PROTMS' in please
	br	20$			; /39/ lookup the modem now
15$:	message	<Please use the SET MODEM command first>,cr
	br	90$
20$:	call	findnumber		; /45/ Perhaps a SET PHO NUM ?
	bcs	90$			; /51/
	call	findmodem		; do we know about this modem ?
	mov	r0	,modtype	; save the address of descriptor
	beq	90$			; no luck, exit with failure
	mov	ext.dial(r0),r1		; /39/ need external routine to dial?
	beq	30$			; /39/ no
	jsr	pc	,@r1		; /39/ yes, call it then
	br	120$			; /39/ and exit
30$:	mov	dial.string(r0),r0	; /39/ get dial formatting string addr
	tstb	@r0			; /39/ anything there ?
	bne	40$			; /39/ yes
	message	<A dial formatting string has not been defined>,cr
	br	90$			; /39/ exit
40$:	calls	ttyini	,<#ttname,#lun.ti,#remmod>
	tst	r0			; did we get a successful open on line?
	bne	80$			; no, emit some sort of error message
	call	tidias			; /45/ Set characteristics (TC.DLU)
	call	getatn			; try to get modems attention
	tst	r0			; did getting modems attn succeed?
	beq	90$			; no
	call	dodial			; actually try to dial the number now
	mov	r0	,-(sp)		; /45/ Save status return
	call	tidiar			; /45/ Reset characteristics
	mov	(sp)+	,r0		; /45/ Restore status return
	tst	r0			; returns 1 for success, zero else
	beq	90$			; failure
	br	100$			; success, return(0) re normal k11


80$:	direrr	r0			; emit an error message and exit
90$:	mov	#-1	,r0
	br	110$
100$:	clr	r0
110$:	call	200$
120$:	tst	r0			; /45/ Errors ?
	beq	130$			; /45/ No
	inc	status			; /45/ Yes, set into global flag
130$:	return


200$:	mov	r0	,-(sp)
	calls	ttyfin	,<#ttname,#lun.ti> ; close the terminal up now
	mov	(sp)+	,r0
	return

	.dsabl	lsb



	.sbttl	match type of modem
	.enabl	lsb

;	FINDMODEM
;
;	Passed:	nothing, assumes MODEM name is in global modem::
;
;	Return:	r0	address of structure for the modem
;		r0 = 0	if the modem type could not be found
;
;	Remark:	 It might be better to call PRINTM to display messages
;		to better control the case if we got spawned under RSX
;		or RSTS so we  could avoid I/O and instead return some
;		status info.


findmo::tst	$modtail		; /39/ Is the usre mode defined?
	bne	5$			; /39/ Yes
	mov	#usermd	,$modtail	; /39/ no, insert it please
5$:	mov	#modinf	,r3		; get address of head of list
10$:	strcmp	#modem	,mod.str(r3)	; check for a match please
	tst	r0			; a match
	beq	80$			; yes
	mov	mod.next(r3),r3		; no, try the next one please
	bne	10$			; keep going
	message	<This modem type is unknown. The known modem types>,cr
	message	<are:>,cr
	message
	mov	#modinf	,r3		; now print the list of modems
20$:	print	mod.str(r3)		; first one
	strlen	mod.str(r3)		; /39/ length of modem type
	sub	#40	,r0		; /39/ tab over please
	neg	r0			; /39/ make it > 0
30$:	print	#200$			; /39/ a space
	sob	r0	,30$		; /39/ next please
	print	mod.com(r3)		; /39/ dump comment string
	message				; cr/lf
	mov	mod.next(r3),r3		; next one in list
	bne	20$			; ok
	br	90$			; exit with failure
80$:	mov	r3	,r0		; return address of structure
	br	100$			; bye
90$:	clr	r0			; failure
100$:	return				; bye

	.save
	.psect	$Pdata	,d
200$:	.byte	40,0
	.restore

	global	<modem>



	.dsabl	lsb


	.sbttl	Look for defined phone numbers
	.enabl	lsb

;	Added /45/ 20-Feb-86  13:00:50 BDN
;
;	Check through linked list for phone number definitions


findnu:	mov	r3	,-(sp)		; Save this 
	mov	r2	,-(sp)		; Save this one also
	cmpb	@argbuf	,#'0		; Only if not number in first pos
	blo	5$			; Ok
	cmpb	@argbuf	,#'9		; Well ?
	bhi	5$			; No
	clc				; Success, exit
	jmp	100$			; A number, exit please
5$:	mov	#pnhead	,r2		; Get listhead
;-	calls	tlog	,<argbuf>	; /47/ Check for logical names
					; Loop a little
10$:	mov	(r2)	,r2		; Get next entry
	beq	90$			; Nothing there
	mov	r2	,r3		; Get address of text
	add	#2	,r3		; +2 for data
	mov	#ntemp	,r0		; Store temp here
20$:	cmpb	(r3)	,#40		; All done looking ?
	beq	30$			; Yes
	movb	(r3)+	,(r0)+		; No, copy more of the NAME
	bne	20$			; All done
30$:	clrb	(r0)			; Insure .asciz please
	strcmp	#ntemp	,argbuf		; Check for a match please
	tst	r0			; Find a match ?
	bne	10$			; No, check the next one
					;
40$:	inc	r3			; Point to number field
	tstb	(r3)			; Anything really there?
	beq	100$			; No, exit please
	message	<Using: >		; Print the translation out
	strcpy	argbuf	,r3		; Copy it over
	print	argbuf			; ...
	message				; ....
	clc				; Success
	br	100$			; Exit
	
90$:	print	#npr			; /51/ Dump a prompt
	mov	#ttbuff	,r2		; /51/ Set address up
	calls	kbread	,<r2>		; /51/ Read the response
	bicb	#40	,r2		; /51/ Cvt to lower case
	cmpb	@r2	,#15		; /51/ A CR
	beq	95$			; /51/ Ok
	tstb	@r2			; /51/ Null ?
	beq	95$			; /51/ Yes, success
	cmpb	@r2	,#'Y&137	; /51/ A 'YES'
	beq	95$			; /51/ Y, success
	sec				; /51/ No, failure
	br	100$			; /51/ Exit
95$:	clc				; /51/ Success
100$:	mov	(sp)+	,r2		; Pop and
	mov	(sp)+	,r3		; pop again, then...
	return				; Exit

	.dsabl	lsb
	.save
	.psect	string
	.even
ntemp:	.blkb	200
npr:	.asciz	/No translation found for number. Continue <Yes> ? /
	.even
	.restore

	global	<pnhead>



	.sbttl	GETATN	wake the modem up
	.enabl	lsb

;	Input:	MODTYPE	address of modem descriptor
;	Return:	R0	zero on failure, else success
;
;	In case the modem is already awake (at command prompt mode)
;	we will dump the string,  wait for the  ackknowledgment and
;	then loop until we are sure there is no more data.  For ex-
;	ample, the VA212 will send back a INVALID COMMAND\n* string
;	for the ^E and one also for the <CR>. We could,  of course,
;	first send the modem it's IDLE command, but there are times
;	when that may be undesirable,  like when the modem is being
;	accessed via some sort of LAN or PABX.


getatn::save	<r1,r2,r3,r4>		; perhaps save something
	mov	modtype	,r4		; get address of structure
	call	eatjunk			; trash stuff that may be waiting
	mov	#3	,r3		; loop a little to get modem going
	mov	wake.string(r4),r2	; Get address of wakeup string

10$:	ttputc	(r2)+			; We may need to insert delays
	tstb	@r2			; for the faster modems.
	beq	15$			; All done?
	tsleep	wake.rate(r4)		; Not done, pause if need be
	br	10$			; And do some more

15$:	waitfor	wake.prompt(r4),#3,20$	; now wait for an ack
	br	25$			; success
20$:	call	eatjunk			; trash stuff that may be waiting
	mov	wake.string(r4),r2	; reset wakeup string
	sob	r3	,10$		; next please
	br	90$			; a complete failure, exit

25$:	message	<Modem in command mode>,cr
30$:	call	eatjunk
	mov	#1	,r0		; return(success)
	br	100$			; and exit
90$:	message	<Failed to get modems attention>,cr
	clr	r0
100$:	unsave	<r4,r3,r2,r1>
	return

	.dsabl	lsb


	.sbttl	actually dial the number
	.enabl	lsb

;	 Note that the waitfor routine, called by macro of same name will
;	exit immediatly if the string to compare against is NULL, thus it
;	won't hurt anything to call it for modems that may not respond.
;	 One other problem is in inserting delays into dumping strings to
;	the  modem in that the smallest  interval RSTS/E can delay is one
;	second. As always in Kermit-11,  we must try to allow for code to
;	function under all execs, not just RT or just RSTS or .....


dodial:	save	<r2,r3,r4,r5>		; save registers that we might zap
	mov	#buffer	,r3		; and a pointer to it also
	mov	modtype	,r4		; get address of modem descriptor
	mov	#1	,r2		; since RSTSE can't sleep < 1 second
	mov	#cccnt	,r5		; control C int flag
	call	fmtstr			; format the dialing string
	tst	dialmode		; /45/ Should we force PULSE or TONE?
	beq	5$			; /45/ Nothing
	bmi	4$			; /45/ Tone
	ttputs	dial.pulse(r4)		; /45/ See if user selected PULSE
	br	5$			; /45/ Now get the thing to dial
4$:	ttputs	dial.nopulse(r4)	; /45/ Force TONE dialing
5$:	ttputs	dmod.string(r4)		; dump the prompt for dialing out
	waitfor	dmod.prompt(r4),#4,80$	; wait for a response
	call	eatjunk			; let things settle a bit
10$:	tstb	(r3)			; end of it all ?
	beq	40$			; yes
	tst	@r5			; user interupt happen ?
	bne	90$			; yes, exit now
	ttputc	(r3)+			; no, dump one character out
	tst	dial.echo(r4)		; does it echo characters after each
	beq	20$			; character ?
	ttgetc	#1			; yes, just wait a second for the echo
20$:	dec	r2			; time to take a short nap ?
	bne	10$			; no
	tst	dial.rate(r4)		; do we REALLY need to suspend ?
	beq	30$			; no
	tsleep	dial.rate(r4)		; yes, do it (RSTS of course, can't
30$:	mov	#1	,r2		; sleep < 1 but RSX & RT can).
	br	10$			; may want to insert delays here
40$:	mov	#buffer	,r3		; restore buffer pointer
	waitfor	dial.ack(r4),#4		; wait for number being echoed perhaps
	sleep	#1			; another kludge (mostly RSTS again)
	tst	@r5			; control C or other abort?
	bne	90$			; yes
	ttputs	dial.conf(r4)		; stuff a confirm (ok if null)
	waitfor	dial.go(r4),#5,100$	; maybe wait for any confirm that its
	message	<Modem dialing>,cr	; dialing the number?
	call	getsts			; get final result of the call please
	tst	r0			; success ?
	bne	110$			; yes
	br	100$			; no, dump failure message

80$:	strcpy	#buffer,#nodprompt	; copy message for no dial prompt
	br	100$			; and dump message

90$:	strcpy	#buffer,#abort		; user interupt message

100$:	tst	cccnt			; /45/ Did this die from a control C
	beq	105$			; /45/ No
	ttputs	dial.xabort(r4)		; /45/ Yes, get the modem to STOP
105$:	ttputs	dial.idle(r4)		; /45/ Reset into IDLE state
	message	<Call failed >		; oops
	print	#buffer			; why it did
	message				; <CR><LF>
	clr	r0			; failure
	br	120$			; exit

110$:	message	<Connection made, use the CONNECT command to access remote>
	print	#bell			; /50/ Beep
	call	getsys			; /48/ Don't wait unless rsx flavor
	cmpb	r0	,#SY$MPL	; /48/ M+ ?
	beq	115$			; /48/ Yes, wait a moment
	cmpb	r0	,#SY$11M	; /48/ RSX11M 4.x ?
	bne	116$			; /48/ No, don't suspend
115$:	sleep	#2			; /45/ Wait a moment
116$:	message				; successful call
	mov	#1	,r0		; exit
120$:	unsave	<r5,r4,r3,r2>		; and registers
	return				; and exit


	.dsabl	lsb

	

	.sbttl	GETSTS	Get final result of dial

;	Passed:	R4	--> structure describing modem
;
;	Return:	R0	1 for success, else zero
;
;	 This is the messy part as we have to anticipate response from
;	whatever modem type we are trying to use.
;	 Much of the attempts to do timeouts is made very difficult by
;	the fact that out of P/OS, RT11, RSX11M/m+ and RSTS/E,  !ONLY!
;	RSTS is unable to schedule time based AST's (mrkt$s and so on)
;	 Timer AST's would greatly help out here.
;
;	Define dispatch table to take special actions for each modem type


	dispatch	basedsp=moddsp,baseval=modlst,default=.default

;- /39/	dispatch	$V2PA	,.v2pa		; standalone VA212PA
;- /39/	dispatch	$V2PAR	,.v2par		; rack mount VA212PAR
;- /39/	dispatch	$VADIC	,.vadic		; most vadics (same as 212PA)
	dispatch	$HAYES	,.hayes		; HAYES (really volksmodem12)
;- /45/	dispatch	$DF100	,.df100		; DEC DF112
;- /45/	dispatch	$DF200	,.df200		; DEC DF2xx series
	dispatch	$DF03	,.df03		; DEC DF03
	dispatch

	.save
	.psect
	.psect	string
defmsg:	.asciz	/ No connection/
exring:	.asciz	/ Excessive RINGING... messages returned/
abort:	.asciz	/ Operation aborted under user interupt/
nodpro:	.asciz	/ No response or invalid response to dial command/
	.restore

	CONNECT	=	1
	FAILED	=	-1
	status	=	0
	nrings	=	2
	temp	=	4
	locsiz	=	10


getsts::tst	diatmo			; /46/ Timeout set?
	bne	5$			; /46/ Yes
..diat	==	. + 2			; /46/ Patchable
	mov	#30.	,diatmo		; /46/ No, set it up
5$:	sub	#locsiz	,sp		; allocate local r/w data
	mov	sp	,r5		; and a pointer
	mov	#10	,nrings(r5)	; for VA212 PA, excessive ringing
	clr	temp(r5)		; temp
	clr	(r5)			; status = 0
	.assume	status eq 0		; assertion
	mov	#buffer	,r3		; a buffer pointer
	strcpy	r3	,#defmsg	; copy a message over

10$:	tst	(r5)			; while ( status == 0 )
	bne	90$			; exit with result
	mov	#buffer	,r3		; a buffer pointer

20$:	ttgetc	diatmo			; wait for a status return
	tst	r0			; successful ?
	beq	30$			; yes
	mov	#FAILED	,(r5)		; no
	br	70$			; exit loop
30$:	tstb	r1			; /51/ Never suffer imbedded NULLS
	beq	20$			; /51/ Ignore if such
	bicb	#^C177	,r1		; insure a real seven bit character
	movb	r1	,(r3)+		; copy the byte over
	clrb	(r3)			; insure we stay .asciz
	tst	res.bin(r4)		; exit loop on single character I/O?
	bne	40$			; yes
	cmpb	r1	,#CR		; carriage return finally found ?
	beq	40$			; yes
	cmpb	r1	,#LF		; no, but a line feed will do nicely
	bne	20$			; not a <LF>, try some more input then

40$:	scan	mod.val(r4),#modlst	; do a crude case statement
	asl	r0			; word indexing
	jsr	pc	,@moddsp(r0)	; simple
70$:	br	10$			; next please

90$:	mov	#1	,r0		; assume success
	tst	(r5)			; failure ?
	bpl	100$			; no
	clr	r0			; return(0) for failure
100$:	add	#locsiz	,sp		; pop temps and exit
	return				; exit

	global	<diatmo>		; /46/


	.sbttl	dispatch routines for specific modem (vadic, hayes)

	.enabl	lsb

;	 The DEFAULT entry will read possible responses, and their
;	message classes, from a linked list whose first address  is
;	in RES.HEADER(modem_address). Each list entry has a link to
;	the next one (or a zero), a message class (lt zero if fail,
;	== zero for ringing  message, and gt zero for SUCCESS ). If
;	a modem  has no entries at all,  the routine will  return a
;	failed call. While this method can tend to add size to this
;	module as similiar modems must have separate list,  it is a
;	bit more general,  while allowing us at some future time to
;	provide a SET DIAL command to dynamically create the  modem 
;	data structure for a previously undefined modem type. Added
;	edit 2.39, 04-DEC-1985 10:17, Brian Nelson.
;
;	 We do not need a real definition for modem type DEFAULT as
;	it  is not possible to ever get this far if the type is un-
;	defined.
;
;	Default:

.default:
	save	<r3>			; /39/ save temp register
	mov	res.head(r4),r3		; /39/ get listhead of responses
	beq	90$			; /39/ No responses defined ?
10$:	mov	r3	,-(sp)		; /39/ get address of ascii text
	add	#4	,(sp)		; /39/ 4 byte offset for text
	mov	#buffer	,-(sp)		; /39/ Stuff address of response
	call	didweget		; /39/ check for the response
	tst	r0			; /39/ find the text in the list?
	bne	20$			; /39/ yes, get the response class
	mov	(r3)	,r3		; /39/ no, get the next in the list
	bne	10$			; /39/ something is left
	br	100$			; /39/ nothing is left, continue...
20$:	mov	2(r3)	,(r5)		; /39/ response class
	bne	100$			; /39/ either success or failure
	PRINT	#buffer			; /54/
	MESSAGE				; /54/
	dec	nrings(r5)		; /39/ Choose a point to cut it off
	bne	100$			; /39/ after a lot of ringing messages.
	strcpy	#buffer,#exrings	; /39/ copy an informative message. Stop
	ttputs	wake.string(r4)		; /39/ the modem from trying too hard
	waitfor	wake.prompt(r4),#2	; /39/ eat any possible response please
90$:	mov	#FAILED	,(r5)		; /39/ exit
100$:	unsave	<r3>			; /39/ pop r3 and exit
	return				; /39/ bye

	.dsabl	lsb
	

	.sbttl	Special cases

	.enabl	lsb

;	Case HAYES:

.hayes:	didweget #buffer,<CONNECT>,#CONNECTED,(r5)
	didweget #buffer,<NO CARRIER>,#FAILED,(r5)
	didweget #buffer,<BUSY>,#FAILED,(r5)
	didweget #buffer,<ERROR>,#FAILED,(r5)
	didweget #buffer,<RING>,#1,r0	; macro clears r0 if string not found
	tst	r0			;
	beq	10$			; and ring and ring and ring forever it
	message	<Remote phone is ringing>,cr
	dec	nrings(r5)		; would seem. so chose a point to cut
	bne	10$			; it off at some point
	strcpy	#buffer,#exrings	; copy an informative message and stop
	ttputs	wake.string(r4)		; the modem from trying too hard
	waitfor	wake.prompt(r4),#2	; eat the OK please
	mov	#FAILED	,(r5)		; exit
10$:	return

	.dsabl	lsb



;	Case DF03:

.df03:	didweget #buffer,<A>,#CONNECTED,(r5)
	didweget #buffer,<B>,#FAILED,(r5)
	return





	.sbttl	format dial string (sprintf works a lot better)

;	Passed:	R3	address of buffer to place result
;		ARGBUF	the number to insert


fmtstr:	mov	r3	,-(sp)
	mov	dial.string(r4),r2	; point to the dial formatting string
10$:	tstb	(r2)			; done ?
	beq	50$			; yes
	cmpb	(r2)	,#'%		; look for a format effector
	bne	30$			; no
	mov	argbuf	,r0		; Assume phone number insertion
	cmpb	1(r2)	,#'s!40		; %s formatting ?
	beq	20$			; no
	cmpb	1(r2)	,#'s&137	; %S formatting ?
	beq	20$			; Yes
	mov	dial.wait(r4),r0	; No, assume pause string formatting
	cmpb	1(r2)	,#'p!40		; %P for pause string?
	beq	20$			; Yes
	cmpb	1(r2)	,#'p&137	; check both cases
	beq	20$			; No
					;
	cmpb	1(r2)	,#'M&137	; /54/ Mode (ie PULSE, TONE)
	beq	15$			; /54/ Found it
	cmpb	1(r2)	,#'m!40		; /54/ ...
	bne	16$			; /54/ Nope
15$:	mov	dial.pulse(r4),r0	; /54/ Assume PULSE dialing
	tst	pulse			; /54/ Ever SET PHONE PULSE/TONE?
	beq	25$			; /54/ No, ignore string
	bmi	20$			; /54/ SET PHONE PULSE
	mov	dial.nopulse(r4),r0	; /54/ SET PHONE TONE
	br	20$			;
16$:	cmpb	1(r2)	,#'B&137	; /54/ SET PHONE BLIND?
	beq	17$			; /54/ Is this the formatting char?
	cmpb	1(r2)	,#'b!40		; /54/ No, perhaps lower case?
	bne	30$			; /54/ No, copy data then
17$:	tst	blind			; /54/ Ever do the SET PHONE BLIND?
	beq	25$			; /54/ No, ignore string
	mov	dial.blind(r4),r0	; /54/ Yes, insert the data then.
					;
20$:	movb	(r0)+	,(r3)+		; copy a byte please
	bne	20$			; not a null, next please
	dec	r3			; fix current pointer up
25$:	inc	r2			; skip over the '%' please
	br	40$			; next please
30$:	movb	(r2)	,(r3)+		; not formatting, copy character
40$:	inc	r2			; skip over current character now
	br	10$			; next

50$:	clrb	(r3)			; insure dial string is .asciz
	mov	(sp)+	,r3		; restore pointer and exit
	return



	.sbttl	misc util routines
	.enabl	lsb

;	WAITFOR(s,timeout)
;
;	Wait for the character string in S
;
;	Passed:	2(sp)	string
;		4(sp)	timeout
;	Return:	1	success
;		0	timeout

waitfor:save	<r2,r3,r4>
	mov	2+6(sp)	,r4		; string we are looking to get
	mov	2+10(sp),r3		; timeout in seconds
10$:	movb	(r4)+	,r2		; next character to await
	beq	30$			; success, we can leave now
20$:	ttgetc	r3			; wait at most r3 seconds please
	tst	r0			; success ?
	bne	90$			; no (i/o routines use r0 for err code)
	bicb	#^C177	,r1		; remove parity always
	tstb	r1			; /51/ Ignore imbedded NULLS
	beq	20$			; /51/ ....
	cmpb	r1	,r2		; did we get the correct character?
	bne	20$			; no, keep waiting then
	br	10$			; found it, check for next character
30$:	mov	#1	,r0		; success
	br	100$			; exit
90$:	clr	r0			; failure, return(0)
100$:	unsave	<r4,r3,r2>
	mov	(sp)	,4(sp)		; move return address up and exit
	cmp	(sp)+	,(sp)+		; fix stack
	return				; exit

	.dsabl	lsb


didwege:save	<r1,r2,r3>
	mov	2+10(sp),r3		; string to look for
	mov	2+6(sp)	,r2		; string to find it in
	lowcase	r3			; /45/ Lowercase it in buffer
	strlen	r3			; string length of pattern
	mov	r0	,r1		; save it
	lowcase	r2			; /45/ Lowercase it in buffer
	strlen	r2			; length of source string
	calls	instr	,<r2,r0,r3,r1>	; simple (use funct we already have)
	unsave	<r3,r2,r1>		; pop temps and exit
	mov	(sp)	,4(sp)		; move return address up and exit
	cmp	(sp)+	,(sp)+		; fix stack
	return				; exit

eatjunk:save	<r0,r1>
10$:	ttgetc	#1
	tst	r0
	beq	10$
	unsave	<r1,r0>
	return


;	Added /45/

lowcas:	mov	r0	,-(sp)		; Save starting address
10$:	tstb	(r0)			; End of the line yet?
	beq	100$			; Yes, exit then
	cmpb	(r0)	,#'A&137	; A big letter?
	blo	20$			; No
	cmpb	(r0)	,#'Z&137	; A big letter?
	bhi	20$			; No
	bisb	#40	,(r0)		; Yes, make it lower
20$:	inc	r0			; Next please
	br	10$			; and check it
100$:	mov	(sp)+	,r0		; Return starting address
	return				; Exit

doput:	strlen	r1
	tst	r0
	beq	10$
	calls	binwri	,<r1,r0,#lun.ti>
10$:	return


	.sbttl	Show Modem/Dial

	.enabl	lsb

shomod::
shodia::call	findmodem		; Do we know about this modem ?
	mov	r0	,r4		; Save the address of descriptor
	bne	5$			; No luck, exit with failure
	MESSAGE	<No modem type has been SET>,CR
	return				;
5$:	mov	#slist	,r3		; Info list start
	tst	ext.dial(r4)		; Is this a built-in, like PRO/TMS?
	beq	10$			; No
	MESSAGE	<This is an internal modem>,CR
	jmp	100$			; Exit
					;
10$:	movb	(r3)+	,r1		; Type of data (1=String,0=Number)
	movb	(r3)+	,r2		; Offset, zero implies end.
	beq	60$			; All done
	add	r4	,r2		; Move to the correct offset
	PRINT	r3			; Dump the header
20$:	tstb	(r3)+			; Now look for the end of it
	bne	20$			; Not yet
	tstb	r1			; Data type, zero is numeric
	bne	30$			; Ascii
	DECOUT	(r2)			; Dump the data
	br	50$			; Next please
30$:	mov	(r2)	,r0		; Get the string data address
	beq	40$			; Nothing there
	tstb	@r0			; Again
	beq	40$			; Nothing has been set
	call	unfmts			; Convert and print it
	PRINT	r0			; Do it
	br	50$			; Next
40$:	MESSAGE	<The option has not been SET>
50$:	MESSAGE				;
	br	10$			; Next
					;
60$:	mov	res.head(r4),r3		; Response header
	beq	100$			; Nothing present
	MESSAGE				;
	MESSAGE	<Modem message            Message Class>,CR
	MESSAGE  			;
65$:	mov	r3	,r2		; Get the response address
	beq	100$			; All done
	add	#4	,r2		; Offset is four
	STRCPY	#buffer	,r2		; Copy it
	STRLEN	#buffer			; Length
	sub	#24.	,r0		; Amount to stuff in
	neg	r0			; Make it positive
	mov	r0	,r5		; Save it in a safe place
	ble	75$			; Avoid this please
70$:	STRCAT	#buffer	,#200$		; Do it
	sob	r5	,70$		; A few times
75$:	PRINT	#buffer			; Dump the text
	tst	2(r3)			; What is the message class?
	bmi	85$			; If < 0, failure to connect
	beq	80$			; If == 0 just informative
	MESSAGE	<Successfull connect>,CR;
	br	90$			; Next please
80$:	MESSAGE	<Informative message>,CR;
	br	90$			; Next please
85$:	MESSAGE	<Failure to  connect>,CR;
90$:	mov	(r3)	,r3		; Pick up link to next
	br	65$			; Next please
					;	
100$:	return

	.Save
	.psect	$Pdata,d

200$:	.asciz	/ /

	.macro	DES	Type,Offset,Title
	.if B, Type
	.byte	0,0
	.iff
	.byte	Type,Offset
	.asciz	@Title@
	.endc
	.endm	DES

slist:	DES	1,mod.comment,<Modem type:         >
	DES	1,wake.string,<Wakeup string:      >
	DES	1,wake.ack   ,<Response to wakeup: >
	DES	1,dial.string,<Format for dialing: >
	DES	0,dial.rate,  <Delay  for dialing: >
	DES

	.Even
	.Restore

	.end