	.title	USERMN	User Terminal Monitor
	.IDENT	/X01.03/
	.ENABLE	LC
;	.list	me
;	.list	meb
	.nlist	cnd

	.sbttl	Introduction
;
; USERMN - User Terminal Activity Monitor for RSX-11M/M+
;
;
; Author:
;	Bruce R. Mitchell
;
;	Patterned after the POOL monitor task supplied by Digital
;		Equipment Corporation on RSX-11M-PLUS V1.0 Autopatch E.
;
;
; Source Site:
;	Engineering Systems and Technology Laboratory
;	3M Company, 3M Center, St. Paul, Minnesota  55144
;
; Revision History:
;
;	31-dec-81	First version written
;	3-jan-82	Command file generates Ascii strings for time
;	5-jan-82	In-house version released
;	9-jan-82	Decnet HT: support conditionally added
;	11-jan-82	Decus version released
;	20-jan-82	VT100 support conditionalized
;	27-feb-82	Warning messages cleared for active terminals
;	15-mar-82	Correct conditionlization for HT's
;	21-Jun-82	Modified to fit CBD's 11/44 system
;			First warning sets terminal no-priv 
;			Added software to log off TT0:
;				by using 'ghost' tasks
;			Added loop counter
;	25-aug-82	resets non-logged in terminals to the
;				non-logged in CLI (lgocli)
;
;
	.page
	.sbttl	Macro calls and Definitions
;
;	System definition macros from LB:[1,1]EXEMC.MLB
;
	.mcall	dcbdf$		; Device control block offsets
	.mcall	hwddf$		; Hardware registers
	.mcall	tcbdf$		; Terminal control block offsets
	.mcall	ucbdf$		; Unit control block offsets

	dcbdf$
	hwddf$
	tcbdf$
	ucbdf$
;
;
;	Directive macros from LB:[1,1]SYSLIB.OLB
;
	.mcall	alun$		; assign logical unit number
	.mcall	dir$		; execute directive
	.mcall	gtim$		; get system clock tiem
	.mcall	mrkt$		; mark time (wait)
	.mcall	qiow$		; queue i/o and wait
	.mcall	spwn$		; spawn task
	.mcall	stse$		; stop for single event flag
	.mcall	wtse$		; wait for single event flag
	.mcall	scli$		; set cli
;
	.page
	.sbttl Local Variables
;
;
;	Local variables
;
lopcnt:	.word	0		; loop counter
;
;
datbuf:	.blkw	8.		; Buffer area for date and time
;
;
;	local terminals data storage area
;
;		format: Flag word - idle counter
;
;	TT	offsets		TT	offsets
;
;	0	0		1	4
;	2	10		3	14 ......
;
;
trmdat:				; beginning of data storage area

.rept	ntt			; repeat for number of terminals
	.word	0		; terminal flags
	.word	0		; idle time counter
.endr

.if df rs.nsl			; if number of HT: terminals is defined
;
;
;	decnet terminals data storage area
;
netdat:				; beginning of data storage area

.rept	nht			; repeat for number of terminals
	.word	0		; terminal flags
	.word	0		; idle time counter
.endr

.endc
;
;
	.page
	.sbttl	Data Structures
;
;	directive data structures
;
;
asslun:	alun$	2, TT, 0	; lun for tty warning or logout message
datdpb:	gtim$	datbuf 		; dpb for current time
timdpb:	mrkt$	efn2,secnds,2	; wait for the monitoring interval
brodpb:	qiow$	io.wbt,lun2,efn1,,,,< , >	; print messages on terminals
condpb:	qiow$	io.wbt,lun1,efn1,,,,<conmsg,conlen>	; console message

;	spawn MCR to log out the terminal at address MCRTRM, setting
;		event flag SPNEFN on exit or status emmission
mcrspn:	spwn$	MCR...,,,,,spnefn,,,mcrbye,byelth,,TT
mcrbye:	.ascii	/bye/		; MCR command to logout terminal
byelth	= . - mcrbye		; length of command
	.even

setspn:	spwn$	MCR...,,,,,spnefn,,,mcrset,setlth,,TT
mcrset:	.ascii	\set /nopriv=ti:\	; MCR command to de-privilege terminal
setlth	= . - mcrset		; length of command
	.even

lgoset:	scli$	LGOCLI,TT,0
sleep:	stse$	efn2		; goto sleep and wait until next check time
spnwai:	wtse$	spnefn		; wait for spawn or timeout event flag
;
;
;
ghosts = 3			; number of tasks the are NOT considered active
ghstnm:	.rad50	/COT.../	; name of the first task to ignore 
	.rad50	/BIGBRO/	; ignore us
	.rad50	/MCR.../	; and lets forget this too!
;
;
	.page
	.sbttl	Messages
;
;	
	.nlist	bin
;
conmsg:	.ascii	<cr><lf>	; 
time:	.blkb	8.		; storage for time string
	.ascii	/  /		; separating spaces
hedlen	= . - conmsg		; length of header area

	.ascii	/Idle terminal forced logout on /
	.even
lgodev:	.blkw	1		; space to print terminal type
lgotrm:	.blkb	2		; space to print terminal number
	.ascii	/:/<cr><lf>	; 
conlen	= . - conmsg
;
warn1:	.ascii	<cr><lf><lf><lf>
	.ascii	/From BIG BROTHER:  First idle terminal warning!/<cr><lf><07>
	.ascii	/                    /
.if df v$t100			; if vt100 support
	.ascii	<esc><133><65><73><61><155>	; esc[5;1m (bold and blink)
.endc
	.even
	.word	time1		; remaining time
	.ascii	/ minutes/
.if df v$t100
	.ascii	<esc><133><60><155>	;esc[0m
.endc
	.ascii	/ before forced logout./
	.ascii	<cr><lf>
wrn1ln	= . - warn1;
;
;
	.even
warnp:	.ascii	/                   Terminal now non-privileged/<cr><lf><07>
	.ascii	<cr><lf><lf>
wrnpln	= . - warnp
	.even
warn2:	.ascii	<cr><lf><lf><lf>
	.ascii	/From BIG BROTHER:  Second idle terminal warning!/<cr><lf><07>
	.ascii	/                    /
.if df v$t100			; if vt100 support
	.ascii	<esc><133><65><73><61><155>	; esc[5;1m (bold and blink)
.endc
	.even
	.word	time2		; remaining time
	.ascii	/ minutes/
.if df v$t100
	.ascii	<esc><133><60><155>	;esc[0m
.endc
	.ascii	/ before forced logout./<cr><lf><lf><lf>
wrn2ln	= . - warn2;
;
;
	.even
warn3:	.ascii	<cr><lf><lf><lf>
	.ascii	/From BIG BROTHER:  Third idle terminal warning!/<cr><lf><bel>
	.ascii	/                    /
.if df v$t100			; if vt100 support
	.ascii	<esc><133><65><73><61><155>	; esc[5;1m (bold and blink)
.endc
	.even
	.ascii	/ 1.0000 minute/
.if df v$t100
	.ascii	<esc><133><60><155>	;esc[0m
.endc
	.ascii	/ before forced logout./<cr><lf><lf><lf>
wrn3ln	= . - warn3;
;
;
	.even
banzai:	.ascii	<cr><lf><lf><lf>
.if df v$t100	
	.ascii	<esc><133><61><73><61><110>	; esc[1;1H
	.ascii	<esc>/#9/			; esc#9
	.ascii	<esc>/[>3;11;0;14;132J/	; clear lines 11-14 inclusive
	.ascii	<esc><133><65><155>		; esc[5m
	.ascii	<esc>/[12;26H/			; move to row 12, col 26
.endc
	.ascii	/From BIG BROTHER:  BYE, BYE/<cr><lf>
.if df v$t100
	.ascii	<esc>/[13;26H/
.endc
	.ascii	/      -- Idle terminal logout/<cr><lf>
.if df v$t100
	.ascii	<esc><133><60><155>		; esc[0m
.endc
	.ascii	<cr><lf><lf><lf>
banzln	= . - banzai
;
;
	.even
	.list	bin
	.page
	.sbttl
	.sbttl	Mainline Code
	.sbttl
	.sbttl	TSKS	Search active task list

;
;
;	Mainline code
;
usermn::
tsks:	mov	#<itt*4.>,r0		; r0 counts down TT: data blocks
10$:	bic	#<tm.prv!tm.log!tm.tsk>,trmdat(r0) ; clear terminal active flags
	sub	#4,r0			; point at flag for preceding unit
	bge	10$			; if not passed TT0:, loop again
.if df rs.nsl
	mov	#<iht*4.>,r0		; r0 counts down HT: data blocks
20$:	bic	#<tm.prv!tm.log!tm.tsk>,netdat(r0) ; clear terminal active flags
	sub	#4,r0			; point at flag for preceding unit
	bge	20$			; if not passed HT0:, loop again
.endc
;
;	switch to system state and check active task list
;
	call	$SWSTK,compar		; switch to system state
					;  and return at compar
	mov	$acthd,r0		;; r0 points to active task listhead
23$:	mov	#ghstnm,r3		;; get basis of ghost names
	mov	#ghosts,r1		;; get number of ghosts
	beq	30$			;; ignore if no ghosts
25$:	cmp	(r3)+,t.nam(r0)		;; is this task a ghost?
	beq	26$			;;  maybe, first three letters match
	inc	r3			;;  no, skip second word (three letters)
	inc	r3			;;  ( by two bytes)
	br	27$			;;  and then go to the next ghost
26$:	cmp	(r3)+,t.nam+2(r0)	;; do the second three letters match?
	beq	70$			;;  yes, so ignore it
27$:	sob	r1,25$			;; no, so try again...	
30$:	mov	t.ucb(r0),r3		;; r3 points to UCB for this task
	mov	u.dcb(r3),r1		;; r1 points to DCB for the UCB
	cmp	d.nam(r1),#"TT		;; is this a terminal dcb?
.if ndf rs.nsl	
	bne	70$			;; not a TT:, and no HT:'s so skip
.iff
	bne	40$			;; not a TT:, but now check HT:'s
	clr	r4			;; r4 clear -> TT:
	br	50$			;;  and go process it
40$:	cmp	d.nam(r1),#"HT		;; is this a decnet terminal?
	bne	70$			;;  no, so we don't care....
	inc	r4			;; indicate an HT:
.endc

;	calculate terminal number and set active task flag

50$:	sub	d.ucb(r1),r3		;; r3 is distance of UCB from 1st UCB
	clr	r2			;; clear 32-bit extension word
	div	d.ucbl(r1),r2		;; divide distance by length of UCB
	movb	d.unit(r1),r1		;; r1 is lowest unit # on DCB
	add	r1,r2			;; r2 is now the terminal number
	asl	r2			;; multiply r2 by 4 for addressing
	asl	r2			;;   (2 bytes/word * 2 words)

.if ndf rs.nsl				; if decnet not supported
	bis	#tm.tsk,trmdat(r2)	;; set active task flag for TT:
.iff
	tst	r4			;; HT: or TT:
	bne	60$			;;  if an HT:, go process it
	bis	#tm.tsk,trmdat(r2)	;;  if a TT:, take care of it
	br	70$			;; next task
60$:	bis	#tm.tsk,netdat(r2)	;; take care of HT:
.endc

;	set up pointers for next active task and check for list end

70$:	mov	t.actl(r0),r0		;; point to next active task
	tst	r0			;; is this the last task?
	bne	23$			;; no, so get more

	.page
	.sbttl	DCBs	search DCB list

;
;	now we know which tty's have tasks. next thing to do is
;	find the logged in tty's. but before that, clear the flags
;
DCBS:	mov	$devhd,r0		;; ro points to DCB listhead
10$:	cmp	d.nam(r0),#"TT		;; is this a TT: DCB?

.if ndf rs.nsl				; if no decnet
	bne	70$			;; not a TT:, skip to new DCB
.iff
	bne	20$			;; not a TT:, check for HT:
	clr	r4			;; r4 clear -> TT:
	br	30$			;;  and go process TT:
20$:	cmp	d.nam(r0),#"HT		;; is this an HT: DCB?
	bne	70$			;; no, skip to new DCB
	inc	r4			;; r4 not clear -> HT:
.endc

30$:	movb	d.unit(r0),r1		;; r1 is lowest unit number on DCB
	movb	d.unit+1(r0),r3		;; r3 is highest unit number
	sub	r1,r3			;; r3 is number of units served - 1
	inc	r3			;; r3 is number of units served
		 			;;  and usable as down counter
	mov	r1,r2			;; r2 is lowest unit number of DCB
	asl	r2			;; multiply it by 4 for addressing
	asl	r2			;;   ( 2 bytes/word * 2 words)
	mov	r1,r5			;; and hold unit number too
	mov	d.ucb(r0),r1		;; r1 points to first terminal's UCB

;	loop through all units on this DCB, checking for logged-in units

40$:	bit	#u2.log,u.cw2(r1)	;; is this unit logged-in?
	bne	60$			;; no, so get another one
	
.if ndf rs.nsl
45$:	bis	#tm.log,trmdat(r2)	;; set logged-in flag

.iff
45$:	tst	r4			;; TT: or HT:
	bne	50$			;; if an HT:, go to it
	bis	#tm.log,trmdat(r2)	;; set flag for logged-in TT:
	br	55$			;; go for next unit
50$:	bis	#tm.log,netdat(r2)	;; set flag for logged-in HT:
.endc

55$:	bit	#u2.prv,u.cw2(r1)	;; is this unit priv'ed
	beq	60$			;; no, look at next unit

.if ndf rs.nsl
	bis	#tm.prv,trmdat(r2)	;; set priv'ed flag
.iff
	tst	r4			;; TT: or HT:
	bne	555$			;; if an HT:, go to it
	bis	#tm.prv,trmdat(r2)	;; set flag for priv'ed TT:
	br	60$			;; go for next unit
555$:	bis	#tm.prv,netdat(r2)	;; set flag for priv'ed HT:
.endc

60$:	add	#4,r2			;; r2 points at next terminal flag word
	inc	r5
	add	d.ucbl(r0),r1		;; r1 points at next UCB on DCB
	sob	r3,40$			;; loop for each UCB on DCB

;	finish with DCB, prepare for next DCB

70$:	mov	d.lnk(r0),r0		;; r0 now points at next DCB in list
	bne	10$			;; if more, check them out
	
	return				;; return to user state

	.page
	.sbttl	COMPAR crosscheck tasks and terminals
;
;	back in user state. check task vs. logged-in. bump idle counter
;	for logged-in, no task terminals and reset idle counter for those
;	that have active tasks.
;
compar:	mov	#<itt*4>,r0		; r0 counts down terminal data blocks
	mov	#itt,r5			; r5 counts down terminal number
10$:	bit	#tm.log,trmdat(r0)	; is this terminal logged-in?
	bne	20$			; if so, skip and process it
	mov	#"TT,lgoset+s.cidv	; set SCLI$ DPB to TT's
	mov	r5,lgoset+s.ciun	; set SCLI$ DPB unit
	dir$	#lgoset			; set not logged in terminal to lgocli
	clr	trmdat+2(r0)		; not logged-in, clear idle counter
	br	40$			; and set up for next data block

;	terminal logged in; check for active task

20$:	bit	#tm.tsk,trmdat(r0)	; does it have and active task?
	bne	30$			;  if so, skip 'no task' code
	inc	trmdat+2(r0)		;  no active task -> bump idle counter
	br	40$			; and set up for next data block
	
30$:	clr	trmdat+2(r0)		; active task, clear idle counter
	bic	#<tm.1st!tm.2nd!tm.3rd>,trmdat(r0)	; clear warning flags

;	set up for next TT: data block

40$:	sub	#4,r0			; point at flag word of preceding unit
	dec	r5
	bge	10$			; more still to go..

.if df rs.nsl

	mov	#<iht*4>,r0		; r0 counts down HT data blocks
	mov	#iht,r5
50$:	bit	#tm.log,netdat(r2)	; is this HT logged-in?
	bne	60$			; if so, skip and process it
	mov	#"HT,lgoset+s.cidv	; set SCLI$ DPB to HT's
	mov	r5,lgoset+s.ciun	; set SCLI$ DPB unit
	dir$	#lgoset			; set not logged in terminal to lgocli
	clr	netdat+2(r0)		; not logged-in, clear idle counter
	br	80$			; and set up for next data block

;	HT logged in; check for active task

60$:	bit	#tm.tsk,netdat(r0)	; does it have and active task?
	bne	70$			;  if so, skip 'no task' code
	inc	netdat+2(r0)		;  no active task -> bump idle counter
	br	80$			; and set up for next data block
	
70$:	clr	netdat+2(r0)		; active task, clear idle counter
	bic	#<tm.1st!tm.2nd!tm.3rd>,netdat(r0)	; clear warning flags

;	set up for next HT: data block

80$:	sub	#4,r0			; point at flag word of preceding unit
	dec	r5
	bge	50$			; more still to go..
.endc

	.page
	.sbttl	CKTIME  check terminal idle time
;
;	check terminals with nonzero idle counters for log-off
;

cktime:	clr	r1			; r1 is terminal number
	clr	r2			; r2 is offset in terminal data block

.if df rs.nsl
 	clr	r3			; assume terminal type is TT:
.endc

	mov	#"TT,asslun+a.luna	; set device to TT for alun$
	mov	#"TT,mcrspn+s.pwdn	; set device to TT for spwn$
	mov	#"TT,lgodev		; set device to TT for console message
10$:	tst	trmdat+2(r2)		; is this an idle terminal?
	beq	60$			; yes, set up for next terminal

;	terminal is idle - do it to it

	cmp	trmdat+2(r2),#first	; idle less than first warning time?
	bge	20$			;  if not, do something
	br	60$			;  if so, don't

;	check against logout time limit

20$:	cmp	trmdat+2(r2),#fourth	; past logout time?
	blt	30$			; not quite
	call	killit			; goody,goody!!!
	br	60$			; and go for another terminal

;	check against final warning time limit

30$:	cmp	trmdat+2(r2),#third	; final warning?
	blt	40$			; not quite
	call	warfin			; good,good
	br	60$			; and go for another terminal

;	check against second warning time limit

40$:	cmp	trmdat+2(r2),#second	; second warning?
	blt	50$			; not quite
	call	wartwo			; ok,ok
	br	60$			; and go for another terminal

;	issue first warning

50$:	call	warone			; weellll, better than nothing

;	check for last terminal and setup for next

60$:	cmp	r1,#itt			; last terminal?

.if ndf rs.nsl
	bge	140$			; yes, so exit loop
.iff
	bge	70$			; yes, so do HT:'s
.endc
	
	inc	r1			; next terminal number
	add	#4,r2			; next offset
	br	10$			; and go for it

.if df rs.nsl

70$:	clr	r1			; r1 is HT: number
	clr	r2			; r2 is offset in HT: data block
 	mov	#1,r3			; assume HT: type is HT:
	mov	#"HT,asslun+a.luna	; set device to HT for alun$
	mov	#"HT,mcrspn+s.pwdn	; set device to HT for spwn$
	mov	#"HT,lgodev		; set device to HT for console message
80$:	tst	netdat+2(r2)		; is this an idle HT: terminal?
	beq	130$			; yes, set up for next HT:

;	HT: is idle - do it to it

	cmp	netdat+2(r2),#first	; idle less than first warning time?
	bge	90$			;  if not, do something
	br	130$			;  if so, don't

;	check against logout time limit

90$:	cmp	netdat+2(r2),#fourth	; past logout time?
	blt	100$			; not quite
	call	killit			; goody,goody!!!
	br	130$			; and go for another HT:

;	check against final warning time limit

100$:	cmp	netdat+2(r2),#third	; final warning?
	blt	110$			; not quite
	call	warfin			; good,good
	br	130$			; and go for another HT:

;	check against second warning time limit

110$:	cmp	netdat+2(r2),#second	; second warning?
	blt	120$			; not quite
	call	wartwo			; ok,ok
	br	130$			; and go for another HT:

;	issue first warning

120$:	call	warone			; weellll, better than nothing

;	check for last HT: and setup for next

130$:	cmp	r1,#iht			; last HT:?
	bge	140$			; yes, so exit loop
	inc	r1			; next HT: number
	add	#4,r2			; next offset
	br	80$			; and go for it
.endc

;	all terminals processed, back to sleep

140$:	dir$	#timdpb			; set wake-up call
	inc	lopcnt			; say we finished another iteration
	mov	lopcnt,r0		;
	dir$	#sleep			; and go to sleep
	jmp	tsks			; rise and shine and do it all again

	.page
	.sbttl
	.sbttl subroutines
	.sbttl
	.sbttl	datsub	create ascii time
;
;	datsub - get current time and convert to ascii
;
;	inputs - none
;
;	outputs - time gets ascii time
;
;	all registers preserved
;
datsub:	mov	r0,-(sp)
	mov	r1,-(sp)
	mov	r2,-(sp)
	dir$	#datdpb			; execute date-time directive 
	mov	#time,r0		; load ascii time field address in r0
	mov	#datbuf+g.tihr,r1	; load binary time field address in r1
	mov	#3,r2			; specify HH:MM:SS format
	call	$tim			; convert to ascii
	mov	(sp)+,r2
	mov	(sp)+,r1
	mov	(sp)+,r0
	return				; return to caller

	.page
	.sbttl killit	log out idle terminal
;
;	killit log out idle terminal
;
;	inputs:	r1 - number of target terminal
;		r2 - pointer to terminal block
;		r3 - 0 -> TT:,  1 -> HT:
;
;	outputs: terminal flag word is cleared
;
;	registers are not saved and restored
;
;

killit:	mov	r1,mcrspn+s.pwvt	; load terminal number in spwn$ DPB
	dir$	#mcrspn			; say BYE-BYE!!!
	bcc	5$			; if ok, continue
	return				; if not ok, punt
5$:	dir$	#spnwai			; wait for completion
	mov	r1,asslun+a.lunu	; load terminal number ins alun$ DPB
	dir$	#asslun			; assign lun 2 to target terminal
	bcc	10$			; if ok, issue message
	return				; if not, punt

;	log forced logout of the target terminal

10$:	mov	#banzai,brodpb+q.iopl	; load message address into qio DPB
	mov	#banzln,brodpb+q.iopl+2	; load message length into qio DPB
	dir$	#brodpb			; send logout message

.if df rs.nsl
	tst	r3			; is this a TT: or HT:
	beq	15$			; if TT:, skip HT: code
	clr	netdat(r2)		; clear all HT: flags
	br	20$			; and continue
.endc

15$:	clr	trmdat(r2)		; clear all flags for TT:

;	log forced logout of the target terminal on console


20$:	call	datsub			; get message time and date
	mov	r0,-(sp)		; save r's
	mov	r1,-(sp)		;
	mov	r2,-(sp)		;
	mov	#0,lgotrm		; null fill terminal number
	mov	#lgotrm,r0		; move address of output field to r0
	clr	r2			; specify suppression of leading 0's
	call	$cbomg			; convert binary TT to ascii
	mov	(sp)+,r2
	mov	(sp)+,r1
	mov	(sp)+,r0
	dir$	#condpb			; and send out message
	return				; and back to caller

	.page
	.sbttl	warone issue first warning
;
;	warone - issue first warning and de-privilege the terminal
;
;	inputs:	r1 - target terminal number
;		r2 - data block offset
;		r3 - 0 -> TT:,   1 -> HT:
;
;	outputs: terminal flag word is updated
;
;	registers are not save or restored
;
.if df rs.nsl
warone:	tst	r3			; is this an HT:?
	beq	5$			; a TT:
	bit	#tm.1st,netdat(r2)	; an HT:, has first message been sent?
	beq	10$			; no, so send it 
	return				; yes, so don't bother
5$:	bit	#tm.1st,trmdat(r2)	; a TT:, has first message been sent?
.iff
warone:	bit	#tm.1st,trmdat(r2)	; has the first message been sent?
.endc

	beq	10$			; no, so issue it
	return				; yes, don't do it again
10$:	mov	r1,asslun+a.lunu	; load terminal number in alun$ DPB
	dir$	#asslun			; assign lun 2 to target terminal
	bcc	20$			; if it succeeded, issue message
	return				; if failed, punt
20$:	mov	#warn1,brodpb+q.iopl	; load message address into qio DPB
	mov	#wrn1ln,brodpb+q.iopl+2	; load message length into qio DPB
	dir$	#brodpb			; send out message

.if df rs.nsl
	tst	r3			; is this a TT:, or an HT:
	beq	25$			; TT:, so go to TT: code
	bis	#tm.1st,netdat(r2)	; HT:, set first message sent flag
	bit	#tm.prv,netdat(r2)	; was HT: priv'ed
	beq	40$			; no, so leave
	br	30$			; yes, rejoin common code
.endc

25$:	bis	#tm.1st,trmdat(r2)	; TT:, set first message sent flag
	bit	#tm.prv,trmdat(r2)	; TT:, was TT: priv'ed
	beq	40$			; no, so go home	
30$:	mov	r1,setspn+s.pwvt	; load terminal number into spwn$ DPB
	dir$	#setspn			; de-privilege terminal
	bcc	35$			; if ok, good
	return				; if not, punt
35$:	dir$	#spnwai			; wait for spawn to complete
	mov	#warnp,brodpb+q.iopl	; load message address into qio DPB
	mov	#wrnpln,brodpb+q.iopl+2	; load message length into qio DPB
	dir$	#brodpb			; send out message
40$:	return				; and go home


	.page
	.sbttl	wartwo issue first warning
;
;	wartwo - issue second warning
;
;	inputs:	r1 - target terminal number
;		r2 - data block offset
;		r3 - 0 -> TT:,   1 -> HT:
;
;	outputs: terminal flag word is updated
;
;	registers are not save or restored
;
.if df rs.nsl
wartwo:	tst	r3			; is this an HT:?
	beq	5$			; a TT:
	bit	#tm.2nd,netdat(r2)	; an HT:, has second message been sent?
	beq	10$			; no, so send it 
	return				; yes, so don't bother
5$:	bit	#tm.2nd,trmdat(r2)	; a TT:, has second message been sent?
.iff
wartwo:	bit	#tm.2nd,trmdat(r2)	; has the second message been sent?
.endc

	beq	10$			; no, so issue it
	return				; yes, don't do it again
10$:	mov	r1,asslun+a.lunu	; load terminal number in alun$ DPB
	dir$	#asslun			; assign lun 2 to target terminal
	bcc	20$			; if it succeeded, issue message
	return				; if failed, punt
20$:	mov	#warn2,brodpb+q.iopl	; load message address into qio DPB
	mov	#wrn2ln,brodpb+q.iopl+2	; load message length into qio DPB
	dir$	#brodpb			; send out message

.if df rs.nsl
	tst	r3			; is this a TT:, or an HT:
	beq	25$			; TT:, so go to TT: code
	bis	#tm.2nd,netdat(r2)	; HT:, set second message sent flag
	br	30$			; and rejoin common code
.endc
25$:	bis	#tm.2nd,trmdat(r2)	; TT:, set second message sent flag
30$:	return				; and go home


	.page
	.sbttl	warfin issue final warning
;
;	warfin - issue final warning
;
;	inputs:	r1 - target terminal number
;		r2 - data block offset
;		r3 - 0 -> TT:,   1 -> HT:
;
;	outputs: terminal flag word is updated
;
;	registers are not save or restored
;
.if df rs.nsl
warfin:	tst	r3			; is this an HT:?
	beq	5$			; a TT:
	bit	#tm.3rd,netdat(r2)	; an HT:, has third message been sent?
	beq	10$			; no, so send it 
	return				; yes, so don't bother
5$:	bit	#tm.3rd,trmdat(r2)	; a TT:, has third message been sent?
.iff
warfin:	bit	#tm.3rd,trmdat(r2)	; has the third been sent?
.endc

	beq	10$			; no, so issue it
	return				; yes, don't do it again
10$:	mov	r1,asslun+a.lunu	; load terminal number in alun$ DPB
	dir$	#asslun			; assign lun 2 to target terminal
	bcc	20$			; if it succeeded, issue message
	return				; if failed, punt
20$:	mov	#warn3,brodpb+q.iopl	; load message address into qio DPB
	mov	#wrn3ln,brodpb+q.iopl+2	; load message length into qio DPB
	dir$	#brodpb			; send out message

.if df rs.nsl
	tst	r3			; is this a TT:, or an HT:
	beq	25$			; TT:, so go to TT: code
	bis	#tm.3rd,netdat(r2)	; HT:, set third message sent flag
	br	30$			; and rejoin common code
.endc
25$:	bis	#tm.3rd,trmdat(r2)	; TT:, set third message sent flag
30$:	return				; and go home


	.end	usermn
