	PROGRAM NOTIFY

C
C	PROGRAM NOTIFY
C
C	If executed in a batch process, sends a message back to the user
C	who submitted the job (if he/she is still logged in), and also
C	prints the message in the batch log.
C
C	If executed in an interactive process, displays a message on the
C	terminal screen.
C
C	If executed with the /TERMINALS qualifier, sends a message to the
C	requested terminal(s).
C
C	If executed with the /USERS qualifier, sends a message to the re-
C	quested user(s), if they are logged in.
C
C	If executed with the /ALL qualifier, sends a message to all current-
C	ly logged-in users.
C
C	NOTIFY must be defined as a DCL command, using the Command Definition
C	Facility (see the VAX/VMS Utilities Reference Manual).  The suggested
C	command definition is:
C
C		DEFINE VERB  NOTIFY
C
C		    IMAGE  SYS$SYSDEVICE:[K105UTIL]NOTIFY  (or whatever)
C
C			PARAMETER  P1
C
C			QUALIFIER  /TERMINALS , VALUE ( REQUIRED,LIST )
C
C			QUALIFIER  /USERS     , VALUE ( REQUIRED,LIST )
C
C			QUALIFIER  /ALL
C
C
C	NOTIFY is executed as any of the following:
C
C		$ NOTIFY "text of message"
C
C		$ NOTIFY /TERMINAL=TTxx "text of message"
C
C		$ NOTIFY /TERM=(TTxx,TTyy,...) "text"
C
C		$ NOTIFY /USER=JONES "text"
C
C		$ NOTIFY /USERS=(JONES,SMITH,...) "text"
C
C		$ NOTIFY /ALL "text"
C
C
C	This program is designed to be used with VT100 terminals.  The
C	message is displayed on the terminal in bold reverse video,
C	centered in an 80-column field.  If the message is delimited by
C	quotation marks, these are not displayed.  The message must not
C	be longer than 80 characters; if /TERMINALS, /USERS, or /ALL is
C	specified, this is reduced to about 60 characters.
C
C	NOTIFY needs WORLD and OPER privileges (if the /USERS and /ALL 
C	qualifiers are not used, or are only used for users in the same
C	group, GROUP privilege can be substituted for WORLD).  If you want
C	unprivileged users to use it, you must use the INSTALL utility to
C	install it with WORLD (or GROUP) and OPER privileges.
C
C
C	ALAN L. ZIRKLE     K105     29 JULY 1982
C

	IMPLICIT INTEGER (A-Z)

	CHARACTER*128 MESSAGE
	CHARACTER*80  MSG

	EQUIVALENCE (MESSAGE,MSG)

	COMMON /MSG_/ MESSAGE

	CHARACTER*1  ESC,BEL
	CHARACTER*10 FRT
	CHARACTER*3  BCK

	PARAMETER ( ESC = CHAR(27) )
	PARAMETER ( BEL = CHAR(7) )
	PARAMETER ( FRT = ESC//'[1;7m'//BEL//BEL//BEL//BEL )
	PARAMETER ( BCK = ESC//'[m' )

	LOGICAL TERMQUAL,USERQUAL,ALLQUAL,QUAL,BATCH

	CHARACTER*16 PROCNAME
	CHARACTER*8  TERMNAME
	CHARACTER*12 USERNAME

	INTEGER*2 PNLEN,TNLEN,UNLEN

	COMMON /USER_DATA_/ PID,STAT,UIC,PROCNAME,TERMNAME,USERNAME,
	1				  PNLEN,   TNLEN,   UNLEN	

	TERMQUAL = CLI$PRESENT('TERMINALS')
	USERQUAL = CLI$PRESENT('USERS')
	ALLQUAL  = CLI$PRESENT('ALL')
	QUAL     = TERMQUAL .OR. USERQUAL .OR. ALLQUAL
	BATCH    = BATCH_MODE()

C	Get this process' Username, if it will be needed later.

	IF (QUAL.OR.BATCH) CALL USER_HAS_PRIV(' ')

C	Get the text of the message from the command line.  Compute
C	its length (limited to 80 characters).

	CALL CLI_GET('P1',MESSAGE,MESS_LEN)

	MESS_LEN = MIN(MESS_LEN,80)

C	If a qualifier is present, prefix the message with the name of the
C	sending user.

	IF (QUAL) THEN

	    MESSAGE = 'From ' // USERNAME(1:UNLEN) // ':  ' //
	1						MESSAGE(1:MESS_LEN)

	    MESS_LEN = MIN(MESS_LEN+5+UNLEN+3,80)

	ENDIF

C	Center the message in an eighty-column field.

	IF (MESS_LEN.LT.80) THEN

	    COL=(80-MESS_LEN)/2+1

	    MESSAGE(COL:)=MESSAGE

	    MESSAGE(1:COL-1)=' '

	ENDIF

C	Send the message.  Method depends on qualifiers and run mode.

	IF (.NOT.QUAL) THEN

	    IF (BATCH) THEN			     ! Batch mode, no qualifier

		PRINT 1000,MSG

		CALL SEND_MESSAGE(USERNAME(1:UNLEN),MSG)

	    ELSE				    ! Interactive, no qualifier

		CALL LIB$PUT_OUTPUT(FRT//MSG//BCK)

	    ENDIF

	ELSE					    ! Qualifier present

	    IF (TERMQUAL) THEN

		CALL TERMINALS				      ! /TERM qualifier

	    ELSE IF (USERQUAL) THEN

		CALL USERS				      ! /USER qualifier

	    ELSE IF (ALLQUAL) THEN

		CALL ALL				      ! /ALL qualifier

	    ENDIF

	ENDIF

1000	FORMAT (1X,10('--------')/1X,A/1X,10('--------'))

	END
	SUBROUTINE USERS

	IMPLICIT INTEGER (A-Z)

	LOGICAL CLI$GET_VALUE

	CHARACTER*12 USERNAME

	CHARACTER*80 MSG

	COMMON /MSG_/ MSG

10	IF (CLI$GET_VALUE('USERS',USERNAME) ) THEN

	    UNLEN = STR_LEN(USERNAME)

	    CALL SEND_MESSAGE(USERNAME(1:UNLEN),MSG)

	    GO TO 10

	ENDIF

	END
	SUBROUTINE TERMINALS

	IMPLICIT INTEGER (A-Z)

	LOGICAL CLI$GET_VALUE

	CHARACTER*8 TERMNAME

	CHARACTER*80 MSG

	COMMON /MSG_/ MSG

10	IF ( CLI$GET_VALUE('TERMINALS',TERMNAME) ) THEN

	    TNLEN = STR_LEN(TERMNAME)

	    IF (INDEX(TERMNAME(1:TNLEN),':').EQ.0) THEN

		TNLEN = TNLEN + 1
		TERMNAME(TNLEN:TNLEN) = ':'

	    ENDIF

	    CALL SEND_MESSAGE(TERMNAME(1:TNLEN),MSG)

	    GO TO 10

	ENDIF

	END
	SUBROUTINE ALL

	IMPLICIT INTEGER (A-Z)

	LOGICAL GETJPI

	CHARACTER*80 MSG

	COMMON /MSG_/ MSG

	CHARACTER*16 PROCNAME
	CHARACTER*8  TERMNAME
	CHARACTER*12 USERNAME

	INTEGER*2 PNLEN,TNLEN,UNLEN

	COMMON /GETJPI_1/ PID,STAT,UIC,PROCNAME,TERMNAME,USERNAME,
	1				PNLEN,   TNLEN,   UNLEN	

10	IF (.NOT.GETJPI(1)) CALL EXIT

	CALL SEND_MESSAGE(TERMNAME(1:TNLEN),MSG)

	GO TO 10

	END
