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. WRKACTJOB OUTPUT(*PRINT) 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. Mission Accomplished 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. RELATED STORIES Running Green-Screen Commands From OpsNav, Part 1 Running Green-Screen Commands From OpsNav, Part 2 
 | 

 
							  
								 
                      
                
     
					