.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