Admin Alert: Selectively Sending Break Messages to Active Users
February 7, 2007 Joe Hertvik
In a recent column, I discussed how to use the i5/OS Send Break Message command (SNDBRKMSG) to send messages that will immediately display on all 5250 terminals. Unfortunately, SNDBRKMSG has some issues in that it sends break messages to all defined user terminal message queues, not just the terminals of currently signed on users. In this issue, I’ll discuss my utility to send break messages only to signed-on users.
The Problem with SNDBRKMSG (and SNDMSG, Too)
In my target scenario, I want to send a message to all my signed on interactive 5250 users asking them to perform some function (i.e., please get off the system, please exit a program, etc). I also want this message to automatically display as soon as their 5250 terminal receives it (an immediate message, which the user receives in break mode). To send messages to user terminals, IBM offers two commands, each of close but not quite appropriate for my needs.
As written, SNDBRKMSG meets my needs, except that it sends messages to more terminals than are currently active. To make it more efficient, I’m going to write a program that sends my break message only to those user terminals that are currently signed on to the system. To create this program, I’ll use the following template.
Once I have my basic program written, I can then call it interactively from a green-screen command line, through iSeries Navigator’s (OpsNav) Run Command feature, include it in a CL program, or create a command to launch the program. It will be flexible enough to meet most of my immediate messaging needs.
Here’s how I can create a program that takes care of these issues.
Step One: Create a WRKACTJOB Job File
Programming this function would be a lot easier if the WRKACTJOB command had an option to output its results to a physical file. It doesn’t, so I have to create a physical file template for reading WRKACTJOB output and then copy a WRKACTJOB spool file into that file for processing.
To create a spooled file containing current WRKACTJOB information, I would run WRKACTJOB this way.
This creates a spooled file called QPDSPAJB that contains all the output from my WRKACTJOB screen. To read that output into a physical file, I need to create DDS specifications for a new file. Those specs must mirror the job information contained on a WRKACTJOB line, which contains 132 characters. Knowing this and what the job lines on a WRKACTJOB printout looks like, I can create a WRKACTJOB DDS file to capture my command’s output.
To do this, I’ll use the name of the WRKACTJOB spooled file (QPDSPAJB) as my file name and my DDS record format for that file will look like this:
A R WRKACTJOB A FILLER1 3A TEXT('FILLER') A JOBNAM 10A TEXT('JOB/TERMINAL NAME') A FILLER2 3A TEXT('FILLER') A USRNAM 10A TEXT('USER NAME') A FILLER3 2A TEXT('FILLER') A JOBNMB 6A TEXT('JOB NUMBER') A FILLER4 3A TEXT('FILLER') A JOBTYP 3A TEXT('JOB TYPE') A FILLER5 4A TEXT('FILLER') A SBSPOOL 2A TEXT('SUBSYSTEM POOL') A FILLER6 4A TEXT('FILLER') A JOBPTY 2A TEXT('JOB PRIORITY') A FILLER7 5A TEXT('FILLER') A CPUPCT 5A TEXT('CPU Percentage used') A FILLER8 30A TEXT('FILLER') A FUNCTN 15A TEXT('FUNCTION') A FILLER9 3A TEXT('FILLER') A JOBSTS 4A TEXT('JOB STATUS') A FILLER10 7A TEXT('FILLER') A THREADS 3A TEXT('THREADS') A FILLER11 8A TEXT('FILLER')
This contains most of the relevant information listed on a standard WRKACTJOB screen. The nice thing about this file is that it can be used for a number of different purposes beyond what I’m writing about today.
Step Two: Write a Program to Only Send Break Messages to Signed-On Users
After I have my WRKACTJOB information file, my next job is to write the program that will use that information to send break message only to currently signed-on users. The name of my program is SNDABRKMSG and here’s the code that the program contains.
0001.00 PGM PARM(&TEXT) 0002.00 0003.00 DCL VAR(&TEXT) TYPE(*CHAR) LEN(512) 0004.00 DCL VAR(&COUNTER) TYPE(*DEC) LEN(3 0) VALUE(0) 0005.00 DCL VAR(&WORK) TYPE(*CHAR) LEN(1) VALUE(' ') 0006.00 DCL VAR(&NULL) TYPE(*CHAR) LEN(1) VALUE(X'00') 0007.00 0008.00 DCLF FILE(QGPL/QPDSPAJB) 0009.00 0010.00 CHGVAR VAR(&COUNTER) VALUE(0) 0011.00 0012.00 COUNT: IF COND(&COUNTER *LT 512) THEN(DO) 0013.00 CHGVAR VAR(&COUNTER) VALUE(&COUNTER + 1) 0014.00 0015.00 CHGVAR VAR(&WORK) VALUE(%SST(&TEXT &COUNTER 1)) 0016.00 IF COND(&WORK *EQ &NULL) THEN(CHGVAR + 0017.00 VAR(%SST(&TEXT &COUNTER 1)) VALUE(' ')) 0018.00 GOTO CMDLBL(COUNT) 0019.00 ENDDO 0020.00 0021.00 CHKOBJ OBJ(QTEMP/QPDSPAJB) OBJTYPE(*FILE) 0022.00 MONMSG MSGID(CPF9801) EXEC(CRTDUPOBJ OBJ(QPDSPAJB) + 0023.00 FROMLIB(QGPL) OBJTYPE(*FILE) TOLIB(QTEMP)) 0024.00 0025.00 CLRPFM FILE(QTEMP/QPDSPAJB) 0026.00 0027.00 WRKACTJOB OUTPUT(*PRINT) 0028.00 0029.00 CPYSPLF FILE(QPDSPAJB) TOFILE(QTEMP/QPDSPAJB) + 0030.00 SPLNBR(*LAST) 0031.00 0032.00 OVRDBF FILE(QPDSPAJB) TOFILE(QTEMP/QPDSPAJB) 0033.00 0034.00 GETREC: RCVF 0035.00 MONMSG MSGID(CPF0864) EXEC(GOTO CMDLBL(ENDPGM)) 0036.00 0037.00 IF COND((&FILLER1 *EQ ' ') *AND (&FILLER2 *EQ ' + 0038.00 ')) THEN(DO) 0039.00 0040.00 IF COND(&JOBTYP *EQ 'INT') THEN(DO) 0041.00 SNDBRKMSG MSG(&TEXT) TOMSGQ(&JOBNAM) 0042.00 ENDDO 0043.00 ENDDO 0044.00 0045.00 GOTO CMDLBL(GETREC) 0046.00 0047.00 ENDPGM: DLTOVR FILE(*ALL) 0048.00 0050.00 DLTF FILE(QTEMP/QPDSPAJB) 0051.00 CHGVAR VAR(&TEXT) VALUE(*BLANKS) 0052.00 0053.00 ENDPGM
Here’s what each piece of code does.
Input parameters: Lines 1.00 through 8.00 allow you to pass in the text message that you want to send to your active users. The text message is received into the program as parameter &TEXT. On i5/OS V5R3, SNDBRKMSG can send messages up to 512 characters long, so &TEXT is a character variable (*CHAR) with a length of 512. This section also defines your work variables for formatting the message text correctly.
Formatting the Data: Lines 12.00 through 20.00 massage the incoming text message so that it will display correctly on the user’s terminal. Due to a quirk in CL, you can receive unpredictable results when passing in parameters that are more 32 characters long, and i5/OS will not right-fill the incoming 512-character parameter with spaces. What I found in creating this code was that in some instances, my incoming message parameter would contain the null character (x’00’) in all parameter positions after the last character I had passed into the program through the &TEXT parameter. This code examines the incoming message &TEXT variable and replaces any null characters in the message with spaces.
Creating the WRKACTJOB File (QPDSPAJB): Lines 21.00 through 32.00 create a temporary copy of the QPDSPAJB file in my job’s QTEMP library, if it doesn’t already exist. It then clears the file, creates a spooled file containing my current WRKACTJOB information, and then copies that spooled file information into my QTEMP/QPDSPAJB file by using the Copy Spooled File command (CPYSPLF). The program then uses the Override with Data Base File command (OVRDBF) to make sure that any references to QPDSPAJB file point to the newly created QPDSPAJB file in QTEMP.
Sending Break Messages to All Signed-On Users: Lines 33.00 through 46.00 read the QPDSPAJB file and use the SNDBRKMSG command to send my message to the message queues associated with all signed-on interactive jobs (those jobs with a status of ‘INT’). In this file, interactive job entries can also be identified by those records where there is no entry in either the FILLER1 or FILLER2 fields. This code uses SNDBRKMSG to send our cleaned up message to the proper message queue, as defined in QPDSPAJB’s &JOBNAM parameter. By defining which active users receive the break message, this program fixes SNDBRKMSG’s flaw by only sending break messages to terminal message queues that are currently signed on to the system.
Cleaning up the process: Lines 47.00 through 53.00 remove the QTEMP/QPDSPAJB override and deletes the temporary file the program created. This code also clears out the &TEXT variable so that it is empty inside the program for its next activation. Due to another quirk in CL, I found that the program does not reinitialize the &TEXT variable on its next call. Rather, the program will keep the &TEXT value I passed in the last time I called it and (if the old message value is longer than the new message value being passed in) parts of the old message may be sent to your active users along with the new message in the &TEXT field. This cleanup reinitializes the &TEXT variable for the next call.
And that’s my routine for creating a better SNDBRKMSG command. It’s fairly simple to do and (as advertised) it can be called from a command line, included in a CL program, called from iSeries Navigator via its Run Command facility, or it can be wrappered in a promptable command. It’s a simple utility but one that improves on IBM’s original command, and only talks to signed on terminal users, not everyone on the system.
About Our Testing Environment
All configurations described in this article were tested on an i5 box running i5/OS V5R3. However, most of these commands and features are also available on i5/OS V5R4 and most earlier versions of OS/400 V4R5 and below running on AS/400 and iSeries machines.
Special thanks to reader Doug Streifling for providing me with the idea for this article.