			.title	send

;	this program sends a one line message to an individual user,
;	specified by username.  this program must be installed as a foreign
;	command.  oper and world priveleges are required--suggest granting 
;	these to the installed image.
;
;	syntax:
;		send/username a string of any sort at all
;	delimiters should not be placed around the string.
;
;	throughout this little procedure, r6 is used as an index into the 
;	buffer in which the message is being constructed.  r7 is used as a
;	counter to keep track of the length of the message as it is compiled.

;	suggested enhancements:  this little fellow should really
;		check the i/o status block.
;
;	written by lisa thoerle, house information systems, u.s. house
;		of representatives

;	audit trail
;	ltt     28-nov-84	created
;	ltt	06-dec-84	change syntax to match that of reply--
;				username is now appended to the command
;				with a switch.  add /all switch, to
;				notify all processes with terminals

;	global references
	$jpidef
	$brdcstdef
	$ssdef

.page
;	data
			.psect data,quad,noexe,wrt

;	getjpi data area
;	part of this block will be reused for the second, abbreviated
;	call to $getjpi.  the long word addressed by zero_here will be cleared
;	to flag the end of the item list.


mypid:		.long	0			;identify caller
pid:		.long	-1			;wildcard search by process id
item_list:	.word	12			;buffer size for username
		.word	jpi$_username		;flag for username
		.address u_buff			;buffer for name
		.address u_size			;buffer for name size
zero_here:	.word	7			;buffer size for term device
		.word	jpi$_terminal		;flag for terminal info
		.address t_buff			;buffer for terminal device
		.address t_size			;buffer for device size
		.long	0			;end of list(first incarnation)

;	descriptor for input string
input_desc:	.word	80	
		.byte	dsc$k_dtype_vt
		.byte	dsc$k_class_vs		;descriptor type=dynamic string
		.address in_buff		;# of input buffer

;	descriptor for output string
output_desc:	.word	0
		.byte	dsc$k_dtype_vt
		.byte	dsc$k_class_vs
		.address msg_buff

;	descriptor for device string
device_desc:	.word	0
		.byte	dsc$k_dtype_vt
		.byte	dsc$k_class_vs
		.address t_buff

;	buffers and other goodies

in_buff:	.blkb	82			;buffer for input string
u_buff:		.blkb	12			;buffer for returned username
u_size:		.long	0			;size of username
iostblk:	.blkq	1			;i/o status block
t_size:		.long	0			;size of device name
nam_buff:	.blkb	12			;buffer for supplied username
msg_buff:	.blkb	80			;buffer for message
t_buff:		.blkw	7			;buffer for device name
flag:		.word	0			;flag word

;	local values
global=1					;flag for switch

;	switches
everybody: .ascii /ALL/	

;	error messages
no_msg:	.ascid	/please include a message for your victim/
no_such_proc: .ascid /nobody's home/
too_long: .ascid /message must be shorter than 80 letters and spaces/
no_user:  .ascid /please include a username/

.page

			.psect	code,exe,nowrt

start:		.word	0			;entry mask


;	get input string from command line

		pushal	input_desc		;push the string descriptor
		calls	#1,g^lib$get_foreign	;get the input string

;	parse the command string into username and message.
;	consider anything up to the first space to be the username,
;	consider the rest that follows to be the message to be sent.

		clrl	r8			;counter for size of username
		moval	nam_buff,r6		;point to the buffer
						;for the supplied username
		moval	in_buff,r5		;point to command string
		movzwl	(r5)+,r4		;get count of characters
		decl	r4			;remember to subtract the switch

;	verify that the first character is a switch character, and
;	advance beyond it.

		cmpb	(r5)+,#^a?/?		;switch character?
		beql	5$			;if it isn't--error
		pushal	no_user
		brw	error

;	see if /all was specified.  if so, bump counters, set flag,
;	and advance to pursuing usernames.
		
5$:		cmpc3	#3,(r5),everybody	;/all specified?
		bneq	10$			;no--ferret out username

		addl	#3,r5			;advance beyond switch
		bisw	#global,flag		;flag global broadcast
		subl	#3,r4			;adjust counter for switch
						;characters we're skipping
				
;	start shuffling characters.  move them into the username buffer 
;	until we hit a space. if we've come here by falling through
;	/all switch processing above, then we'd better be pointing to a
;	space.

10$:		cmpb	(r5),#^a/ /		;space?
		beql	30$			;yup, leave this loop

		sobgtr	r4,20$			;keep track of how many chars
						;we are consuming
						;if we eat them all here, then
		pushal	no_msg			;no message was supplied
		brw	error

20$:		movb	(r5)+,(r6)+		;ship a character
		incl	r8			;keep track of name length
		brb	10$			;'til we're done
		
;	we've loaded the username into nam_buff.  now load the remainder
;	of the string into msg_buff.

30$:		cmpw	r4,#77			;is this message too long?
		blss	40$			;not yet

		pushal	too_long		;address of error message
		brw	error			;and exit

40$:		movzwl	r4,r7			;save the length--we'll need it
		moval	msg_buff,r6		;point to the message buffer

50$:		movb	(r5)+,(r6)+		;move a character
		sobgtr	r4,50$			;until we've captured all

;	if the /all switch was specified, jump to identifying the 
;	caller next.
	
		bitw	#global,flag		
		bneq	who_are_you

;	scan the job tables to see if the user is logged in and
;	attached to a terminal.

get_proc:	$getjpi_s efn=#1,-		;wait for event flag
			pidadr=pid,-		;wildcard search
			itmlst=item_list,-
			iosb=iostblk		;i/o status block

		blbs	r0,watch_flag		;if we succeed, go wait
						;for the event flag
		cmpw	r0,#ss$_suspended	;suspended job?
		beql	get_proc		;if so, pass

		cmpw	r0,#ss$_nomoreproc	;at end of list?
		bneq	10$			;if so, no such user

		pushal	no_such_proc		;exit with error
		brw	error

10$:		cmpw	r0,#ss$_nonexpr		;non-existent process?
		beql	get_proc		;if so, try again

		brw	go_away			;whatever it is, we're not 
						;going to handle it

;	wait for the local event flag.  when we get it, see if this process
;	name matches the one supplied.

watch_flag:	$waitfr_s efn=#1		;wait for this guy
		tstl	t_size			;connected to a terminal?
		beql	get_proc		;no--keep trying

		cmpc3	r8,u_buff,nam_buff	;compare usernames
		bneq	get_proc		;no match--fetch another

;	if we're here, we've found the process and verified that it is attached
;	to a terminal.  time to find out who our caller is and broadcast the
;	message.

who_are_you:	clrl	zero_here		;clear this logword in order
						;to truncate the item list 
						;for this $getjpi call
		$getjpi_s pidadr=mypid,-	;get caller's username
			itmlst=item_list,-
			iosb=iostblk

;	load the caller's name into the message buffer.  r6 still indexes
;	into msg_buff.

		moval	u_buff,r8		;point to buffer with username
		incl	r7			;increment counter
		movb	#^a?/?,(r6)+		;move in divider

10$:		cmpb	(r8),#^a/ /		;space?
		beql	send_it			;if so, we're done here

		movb	(r8)+,(r6)+		;shuffle bytes
		aobleq	#80.,r7,10$		;keep character count

		pushal	too_long		;if we've overflowed the buffer
		brw	error			;exit with error

;	time to send the message.  if a username has been specified,
;	the strings for the required descriptors have been built.
;	if the /all switch was found, the entry t_size is still
;	0, so the message will be broadcast to all users.

send_it:	movw	r7,output_desc		;load size of string
		movw	t_size,device_desc	;into descriptor

		$brdcst_s -			;send the message
			msgbuf=output_desc,-
			devnam=device_desc,-
			flags=brdcst$m_bottom
		brb	go_away			;and exit

error:		calls	#1,g^lib$put_output	;put out the error message
go_away:	ret				;and go away

.end	start
