Let’s ‘C’ it’s been a while

It’s been a long time since I did anything with the Let’s ‘C’ project so while I had a few moments I thought I would do something a bit different. The use of PHP on IBM i seems to be on the increase so adding a bit of PHP to our Let’s ‘C’ project seemed like a good idea and something that may show just how easy it is to get data from the IBM i. We have already written a Server program to allow connectivity from any ASCII platform so we decided to use a PHP page to simply retrieve the messages from IBM i and display them on a web page.

First thing was to set up the webserver and content, as we already have Apache running on Linux we simply created a virtual host and called it letsphp.local. then we added the web pages that would be used to collect the message data and display them back to the user. The pages we created are nothing spectacular, infact they are too basic to be of any use but they do show the capabilities without too much effort so we stuck with keeping them simple.

This is the simple page we created as the initial page to be displayed when the user connected to the webserver, it requests that the user enters their IBM user id and password which we will use to connect to the IBM i using sockets in PHP.
<!DOCTYPE html>
<!--
To change this license header, choose License Headers in Project Properties.
To change this template file, choose Tools | Templates
and open the template in the editor.
-->
<html>
    <head>
        <meta charset="UTF-8">
        <title>Test Sign On</title>
        <?php
        // start the session processing for storing values
        session_start();
        ?>
    </head>
    <body>
        <?php
        if (isset($_SESSION['valid_user'])) {
            echo("You are signed in as :" . $_SESSION['valid_user']);
        } else {
            ?>
            <table>                    
                <form action="scripts/getmsg.php" method="POST">
                    <tr><td><label>Name : </label><input name="userid" type="text" value="" size="10" maxlength="10" /></td></tr>
                    <tr><td><label>Password : </label><input name="pwd" type="password" value="" size="10" /></td></tr>
                    <tr><td><input type="submit" value="Get Messages" /></td></tr>
                </form>
            </table>
            <?php
            if (isset($_SESSION['ErrMsg'])) {
                echo($_SESSION['ErrMsg'] . "<br />");
                $_SESSION['ErrMsg'] = NULL;
            }
        }
        ?>
    </body>
</html>
Its uses a form to collect the user name and password and sends it off to the getmsg.php script on the webserver. The script is where all the work happens to request the data from the IBM i and return to the page.
<?php
/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
// set up some variables to be used
$key = "0000 ";
$name = $_POST['userid'];
$pass = $_POST['pwd'];
$port = 12345;
$bytes_read = 0;
$bytes_written = 0;
// get the host address
$address = gethostbyname('sas4.shield.local');
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
if ($socket === false) {
    $_SESSION['ErrMsg'] = "socket_create() failed: reason: " . socket_strerror(socket_last_error()) . "\n";
    header("Location: /index.php");
    exit(0);
}
// connect to the remote host
$result = socket_connect($socket, $address, $port);
if ($result === false) {
    $_SESSION['ErrMsg'] = "socket_connect() failed.\nReason: ($result) " . socket_strerror(socket_last_error($socket)) . "\n";
    //header("Location: /index.php");
    exit(0);
}
// send the request to server
$bytes_written = socket_write($socket, $key, 5);
// the server now sends request for name 
$output = socket_read($socket, 2048, PHP_BINARY_READ);
// make sure we get what we expect
if ($output != "Please enter your Profile name : ") {
    $_SESSION['ErrMsg'] = "Incorrect data returned : " . $output;
    socket_close($socket);
    header("Location: /index.php");
    exit(0);
}
// we could check to make sure its the right info 
// now send the user name from above
$bytes_written = socket_write($socket, $name, strlen($name));
if ($bytes_written <= 0) {
    $_SESSION['ErrMsg'] = "Failed to write to socket : " . $bytes_written . " : " . $name;
    socket_close($socket);
    //header("Location: /index.php");
    exit(0);
}
// request for password
$output = socket_read($socket, 2048, PHP_BINARY_READ);
if ($output != "Please enter your Password : ") {
    $_SESSION['ErrMsg'] = "Incorrect data returned : " . $output;
    socket_close($socket);
    header("Location: /index.php");
    exit(0);
}
// send in the password
$bytes_written = socket_write($socket, $pass, strlen($pass));
if ($bytes_written <= 0) {
    $_SESSION['ErrMsg'] = "Failed to write to socket : " . $bytes_written . " : " . $pass;
    socket_close($socket);
    //header("Location: /index.php");
    exit(0);
}
// get the messages
$key = "0003 ";
$output = "";
socket_write($socket, $key, 5);
// get the message requesting the message queue
$output = socket_read($socket, 2048, PHP_BINARY_READ);
if ($output != "Please enter the message Queue Name : ") {
    $_SESSION['ErrMsg'] = "Incorrect data returned : " . $output;
    socket_close($socket);
    header("Location: /index.php");
    exit(0);
}
// send in the message queue
$mq = "QSYSOPR   *LIBL     ";
$bytes_written = socket_write($socket, $mq, 20);
// get the messages, they are sent one at a time and require OK to proceed
do {
    $output = socket_read($socket, 2048, PHP_BINARY_READ);
    echo($output ."<br />");
    // if end of messages then no need to confirm as remote loop will break
    if($output != "End of Messages : ") {
        $bytes_written = socket_write($socket,"OK",2);
    }    
} while ($output != "End of Messages : ");
echo("<br />");
// send the sign off key
socket_write($socket,"0001 ");
// close the socket
socket_close($socket);
exit(0);

We are using sockets to request the contents of the QSYSOPR message queue, first we create the socket and connect before we send the login credentials to the IBM i. Once the credentials have been accepted we send in the key to request the message queue content, as part of this we do some verification that the data sent back from the IBM i is actually what we would expect. This is more about showing the process rather than doing anything purposeful so in production we would probably dispense with a lot of it.

The do loop is where all of the messages are printed out to the page, we have updated the ‘C’ code which runs on the IBM i to format the data into a JSON format which can be parsed if required (this is a simple example so no need for a proper parser for the data). Once all of the messages have been sent a message with the content ‘End of Messages : ‘ is sent to signify that no more messages exist which causes the program to break from the loop and clean up before displaying the page to the user.

The changes to the ‘C’ program were made so the data could be parsed correctly, we had to put in controls that would allow the data to be sent as a json string and we wanted to send each message individually so we could display them with line breaks. This is the new function which will send out the messages which is part of the SRVFUNC service program.
// Function handle_MR()
// purpose: retrieve messages from a message queue
// @parms
//      socket
//      conversion table a-e
//      conversion table e-a
// returns 1 on success

int handle_MR(int accept_sd,
              iconv_t a_e_ccsid,
              iconv_t e_a_ccsid) {
int rc = 0;                                 // return code
int len = 0;                                // counter
int Min_Recs = 50;                          // Async record request
int Num_Recs = 0;                           // number records processed
int Total_Recs = 0;                         // total records in queue
int i = 0;                                  // counter
int more = 1;                               // more messages
char Sort_Info = '0';                       // msg sort (not sorted)
char recv_buf[_32K];                        // recv buffer
char msg_dta[1024];                         // message buffer
char convBuf[_1KB];                         // conversion buffer
char Q_MsgQ[22];                            // qualified message queue
char SPC_Name[20] = "QGYOLMSG  QTEMP     "; // usrspc for data
char ListInfo[80];                          // list info returned by API
char QI[21] = {'1',' '};                    // msgq to list
char QL[44];                                // holder
char Msg_Buf[_1KB];                         // returned message
char MsgQ[20] = "          *LIBL     ";     // message queue
char json_str[500];                         // json string
char msgid[8];                              // message ID
char sev[3];                                // message severity
char msg[133];                              // message
char ts[21];                                // time stamp
char *space;                                // usrspc pointer
char *tmp;                                  // temp ptr
char *Data;                                 // data ptr
SelInf_t SI = {0};                          // selection info
Msg_Ret_t *QIPtr;                           // queue info ptr
time_fmt_t *t;                              // time struct ptr
date_fmt_t *d;                              // date struct ptr
Qgy_Olmsg_ListInfo_t *ret_info;             // returned hdr
Qgy_Olmsg_RecVar_t *ret_msg;                // returned message
Qgy_Olmsg_IDFieldInfo_t *field_data;        // returned msg dta
Os_EC_t Error_Code = {0};                   // Error Code

Error_Code.EC.Bytes_Provided = _ERR_REC;
// first get the message queue name
sprintf(msg_dta,"Please enter the message Queue Name : ");
len = strlen(msg_dta);
convert_buffer(msg_dta,convBuf,len,_1KB,e_a_ccsid);
rc = send(accept_sd,convBuf,len,0);
// make sure the data was sent
if(rc != len) {
   return -1;
   }
// get the message queue to process
rc = recv(accept_sd,recv_buf,_32K,0);
// convert to EBCDIC
convert_buffer(recv_buf,convBuf,rc,_1KB,a_e_ccsid);
// copy with removed A0
memcpy(MsgQ,convBuf,rc);
// set up the message queue to retrieve, '1' denotes message queue
memcpy(&QI[1],MsgQ,20);
// get a space pointer for the messages
if(Get_Spc_Ptr(SPC_Name,&space,_1MB) != 1) {
   return -1;
   }
memcpy(SI.osData.List_Direction,"*PRV      ",10);
// return all messages
SI.osData.Severity_Criteria = 0;
// max message length for 0302 key
SI.osData.Max_Msg_Length = 132;
// help length, we do not request
SI.osData.Max_Help_Length = 0;
//offset to selection criteria (44 bytes)
SI.osData.Sel_Criteria_Offset = sizeof(_Packed struct Qgy_Olmsg_MsgSelInfo);
// number of selections
SI.osData.Num_Sel_Criteria = 1;
// offset to keys
SI.osData.Start_Msg_Keys_Offset = 54;
SI.osData.Retd_Fields_IDs_Offset = 58;
SI.osData.Num_Fields = 2;
// select all with key based on last message added
memcpy(SI.Sel_Cri[0],"*ALL      ",10);
memset(SI.Msg_Key[0],0xFF,4);
// fields to return, msg with data and reply status
SI.FieldID[0] = 302;
SI.FieldID[1] = 1001;
// set up the pointer to the message structure
ret_msg = (Qgy_Olmsg_RecVar_t *)Msg_Buf;
// set up the pointer to list info
ret_info = (Qgy_Olmsg_ListInfo_t *)ListInfo;
// date and time conversion
t = (time_fmt_t *)ret_msg->Time_Sent;
d = (date_fmt_t *)ret_msg->Date_Sent;
do {
   // pull the messages into the user space
   QGYOLMSG(space,
            _1MB,
            ListInfo,
            Min_Recs,
            &Sort_Info,
            &SI,
            sizeof(SI),
            QI,
            QL,
            &Error_Code);
   if(Error_Code.EC.Bytes_Available > 0) {
      snd_error_msg(Error_Code);
      return -1;
      }
   sprintf(msg_dta,"Messages %d - %d",ret_info->Records_Retd,ret_info->Total_Records);
   Total_Recs += ret_info->Records_Retd;
   Num_Recs = ret_info->Records_Retd;
   //snd_msg("GEN0001",msg_dta,strlen(msg_dta));
   // if nothing to do just break
   if(ret_info->Records_Retd <= 0) {
      sprintf(msg_dta,"No records to read");
      snd_msg("GEN0001",msg_dta,strlen(msg_dta));
      break;
      }
   // loop through and get the messages to be sent
   for(i = 1; i <= Num_Recs; i++) {
      QGYGTLE(Msg_Buf,
              sizeof(Msg_Buf),
              ret_info->Request_Handle,
              &ListInfo,
              1,
              i,
              &Error_Code);
      if(Error_Code.EC.Bytes_Available > 0) {
         // clean up and return to caller
         if(memcmp(Error_Code.EC.Exception_Id,"GUI0006",7) != 0)
            snd_error_msg(Error_Code);
         QGYCLST(ret_info->Request_Handle,&Error_Code);
         return -1;
         }
      // set up the access to the data
      tmp = Msg_Buf;
      tmp += ret_msg->Offset_to_Fields_Retd;
      field_data = (Qgy_Olmsg_IDFieldInfo_t *)tmp;
      Data = tmp;
      Data += sizeof(_Packed struct Qgy_Olmsg_IDFieldInfo);
      sprintf(msgid,"%.7s",ret_msg->Msg_ID);
      sprintf(sev,"%.2d",ret_msg->Msg_Severity);
      memset(msg,'\0',133);
      memcpy(msg,Data,field_data->Data_Length);
      sprintf(ts,"20%.2s-%.2s-%.2s %.2s:%.2s:%.2s",d->Y,d->M,d->D,t->H,t->M,t->S);
      sprintf(json_str,"{msgid : %s,sev : %s,msg : %s,ts : %s}",msgid,sev,msg,ts);
      // convert to ASCII and send
      convert_buffer(json_str,convBuf,strlen(json_str),_1KB,e_a_ccsid);
      rc = send(accept_sd,convBuf,strlen(json_str),0);
      // get response
      rc = recv(accept_sd,recv_buf,1024,0);
      // if no response break
      if(rc <= 0) {
         break;
         }
      }
   // set the starting message key
   memcpy(SI.Msg_Key[0],ret_msg->Msg_Key,4);
   } while(Total_Recs < ret_info->Total_Records);
// clean up the resources
QGYCLST(ret_info->Request_Handle,&Error_Code);
if(Error_Code.EC.Bytes_Available > 0) {
   snd_error_msg(Error_Code);
   return -1;
   }
// first get the message queue name
sprintf(msg_dta,"End of Messages : ");
len = strlen(msg_dta);
convert_buffer(msg_dta,convBuf,len,_1KB,e_a_ccsid);
rc = send(accept_sd,convBuf,len,0);
// make sure the data was sent
if(rc != len) {
   return -1;
   }
return 1;
}               
The following shows the output generated from our system.

{msgid : CPIEF01,sev : 00,msg : Service Agent is analyzing your system product activity log entries.,ts : 2018-09-06 16:13:49}
{msgid : CPIEF01,sev : 00,msg : Service Agent is analyzing your system product activity log entries.,ts : 2018-09-06 12:13:47}
{msgid : CPIEF01,sev : 00,msg : Service Agent is analyzing your system product activity log entries.,ts : 2018-09-06 08:13:46}
{msgid : CPIEF01,sev : 00,msg : Service Agent is analyzing your system product activity log entries.,ts : 2018-09-06 04:13:44}
{msgid : CPIEF01,sev : 00,msg : Service Agent is analyzing your system product activity log entries.,ts : 2018-09-06 00:13:43}
{msgid : CPC1E1D,sev : 00,msg : Cleanup has completed.,ts : 2018-09-05 22:00:27}
{msgid : CPI1E87,sev : 00,msg : Cleanup of system journals and system logs successfully completed.,ts : 2018-09-05 22:00:27}
{msgid : CPI1E86,sev : 00,msg : Cleanup of system journals and system logs started.,ts : 2018-09-05 22:00:26}
{msgid : CPI1E94,sev : 00,msg : Cleanup of job logs and other system output successfully completed.,ts : 2018-09-05 22:00:26}
{msgid : CPI1E83,sev : 00,msg : Cleanup of user messages successfully completed.,ts : 2018-09-05 22:00:26}
{msgid : CPI1E81,sev : 00,msg : 000010 of 000084 messages deleted from QSRVAGT.,ts : 2018-09-05 22:00:26}
{msgid : CPI1E81,sev : 00,msg : 000006 of 000048 messages deleted from QSRV.,ts : 2018-09-05 22:00:26}
{msgid : CPI1E81,sev : 00,msg : 000006 of 000042 messages deleted from QPGMR.,ts : 2018-09-05 22:00:26}
{msgid : CPI1E85,sev : 00,msg : Cleanup of operator and work station messages successfully completed.,ts : 2018-09-05 22:00:26}
{msgid : CPI1E93,sev : 00,msg : Cleanup of job logs and other system output started.,ts : 2018-09-05 22:00:26}
{msgid : CPI1E92,sev : 00,msg : User cleanup program successfully completed.,ts : 2018-09-05 22:00:26}
{msgid : CPI1E91,sev : 00,msg : User cleanup program started.,ts : 2018-09-05 22:00:26}
{msgid : CPI1E82,sev : 00,msg : Cleanup of user messages started.,ts : 2018-09-05 22:00:26}
{msgid : CPI1E84,sev : 00,msg : Cleanup of operator and work station messages started.,ts : 2018-09-05 22:00:26}
{msgid : CPI1E23,sev : 00,msg : Cleanup has started.,ts : 2018-09-05 22:00:26}
{msgid : CPI1143,sev : 10,msg : Job not submitted for job schedule entry QEZBKTMWED number 000011 because the entry is held.,ts : 2018-09-05 22:00:00}
{msgid : CPIEF01,sev : 00,msg : Service Agent is analyzing your system product activity log entries.,ts : 2018-09-05 20:13:41}
{msgid : CPI1143,sev : 10,msg : Job not submitted for job schedule entry QEZBKMGWED number 000029 because the entry is held.,ts : 2018-09-05 19:00:00}
{msgid : CPC1126,sev : 50,msg : Job 118161/CHRISH/WORKER was ended by user CHRISH.,ts : 2018-09-05 18:15:32}
{msgid : CPIEF01,sev : 00,msg : Service Agent is analyzing your system product activity log entries.,ts : 2018-09-05 16:13:40}
{msgid : CPIEF01,sev : 00,msg : Service Agent is analyzing your system product activity log entries.,ts : 2018-09-05 12:13:38}
{msgid : CPIEF01,sev : 00,msg : Service Agent is analyzing your system product activity log entries.,ts : 2018-09-05 08:13:37}
{msgid : CPIEF01,sev : 00,msg : Service Agent is analyzing your system product activity log entries.,ts : 2018-09-05 04:13:35}
{msgid : CPIEF01,sev : 00,msg : Service Agent is analyzing your system product activity log entries.,ts : 2018-09-05 00:13:34}
{msgid : CPC1E1D,sev : 00,msg : Cleanup has completed.,ts : 2018-09-04 22:00:26}
{msgid : CPI1E87,sev : 00,msg : Cleanup of system journals and system logs successfully completed.,ts : 2018-09-04 22:00:26}
{msgid : CPI1E86,sev : 00,msg : Cleanup of system journals and system logs started.,ts : 2018-09-04 22:00:26}
{msgid : CPI1E94,sev : 00,msg : Cleanup of job logs and other system output successfully completed.,ts : 2018-09-04 22:00:25}
{msgid : CPI1E83,sev : 00,msg : Cleanup of user messages successfully completed.,ts : 2018-09-04 22:00:25}
{msgid : CPI1E81,sev : 00,msg : 000010 of 000084 messages deleted from QSRVAGT.,ts : 2018-09-04 22:00:25}
{msgid : CPI1E81,sev : 00,msg : 000006 of 000048 messages deleted from QSRV.,ts : 2018-09-04 22:00:25}
{msgid : CPI1E81,sev : 00,msg : 000006 of 000042 messages deleted from QPGMR.,ts : 2018-09-04 22:00:25}
{msgid : CPI1E85,sev : 00,msg : Cleanup of operator and work station messages successfully completed.,ts : 2018-09-04 22:00:25}
{msgid : CPI1E81,sev : 00,msg : 000002 of 000012 messages deleted from CHRISH.,ts : 2018-09-04 22:00:25}
{msgid : CPI1E93,sev : 00,msg : Cleanup of job logs and other system output started.,ts : 2018-09-04 22:00:25}
{msgid : CPI1E92,sev : 00,msg : User cleanup program successfully completed.,ts : 2018-09-04 22:00:25}
{msgid : CPI1E91,sev : 00,msg : User cleanup program started.,ts : 2018-09-04 22:00:25}
{msgid : CPI1E82,sev : 00,msg : Cleanup of user messages started.,ts : 2018-09-04 22:00:25}
{msgid : CPI1E84,sev : 00,msg : Cleanup of operator and work station messages started.,ts : 2018-09-04 22:00:25}
{msgid : CPI1E23,sev : 00,msg : Cleanup has started.,ts : 2018-09-04 22:00:25}
{msgid : CPI1143,sev : 10,msg : Job not submitted for job schedule entry QEZBKTMTUE number 000010 because the entry is held.,ts : 2018-09-04 22:00:00}
{msgid : CPIEF01,sev : 00,msg : Service Agent is analyzing your system product activity log entries.,ts : 2018-09-04 20:13:32}
{msgid : CPI1143,sev : 10,msg : Job not submitted for job schedule entry QEZBKMGTUE number 000028 because the entry is held.,ts : 2018-09-04 19:00:00}
{msgid : CPIEF01,sev : 00,msg : Service Agent is analyzing your system product activity log entries.,ts : 2018-09-04 16:13:31}
{msgid : CPIEF01,sev : 00,msg : Service Agent is analyzing your system product activity log entries.,ts : 2018-09-04 12:13:29}
{msgid : CPIEF01,sev : 00,msg : Service Agent is analyzing your system product activity log entries.,ts : 2018-09-04 12:13:29}
{msgid : CPIEF01,sev : 00,msg : Service Agent is analyzing your system product activity log entries.,ts : 2018-09-04 08:13:28}
{msgid : CPIEF01,sev : 00,msg : Service Agent is analyzing your system product activity log entries.,ts : 2018-09-04 04:13:26}
{msgid : CPIEF01,sev : 00,msg : Service Agent is analyzing your system product activity log entries.,ts : 2018-09-04 00:13:25}
{msgid : CPC1E1D,sev : 00,msg : Cleanup has completed.,ts : 2018-09-03 22:00:26}
{msgid : CPI1E87,sev : 00,msg : Cleanup of system journals and system logs successfully completed.,ts : 2018-09-03 22:00:26}
{msgid : CPI1E86,sev : 00,msg : Cleanup of system journals and system logs started.,ts : 2018-09-03 22:00:25}
{msgid : CPI1E94,sev : 00,msg : Cleanup of job logs and other system output successfully completed.,ts : 2018-09-03 22:00:25}
{msgid : CPI1E83,sev : 00,msg : Cleanup of user messages successfully completed.,ts : 2018-09-03 22:00:25}
{msgid : CPI1E81,sev : 00,msg : 000010 of 000084 messages deleted from QSRVAGT.,ts : 2018-09-03 22:00:25}
{msgid : CPI1E81,sev : 00,msg : 000006 of 000048 messages deleted from QSRV.,ts : 2018-09-03 22:00:25}
{msgid : CPI1E81,sev : 00,msg : 000006 of 000042 messages deleted from QPGMR.,ts : 2018-09-03 22:00:25}
{msgid : CPI1E92,sev : 00,msg : User cleanup program successfully completed.,ts : 2018-09-03 22:00:25}
{msgid : CPI1E85,sev : 00,msg : Cleanup of operator and work station messages successfully completed.,ts : 2018-09-03 22:00:25}
{msgid : CPI1E81,sev : 00,msg : 000002 of 000012 messages deleted from CHRISH.,ts : 2018-09-03 22:00:25}
{msgid : CPI1E91,sev : 00,msg : User cleanup program started.,ts : 2018-09-03 22:00:25}
{msgid : CPI1E93,sev : 00,msg : Cleanup of job logs and other system output started.,ts : 2018-09-03 22:00:25}
{msgid : CPI1E82,sev : 00,msg : Cleanup of user messages started.,ts : 2018-09-03 22:00:25}
{msgid : CPI1E84,sev : 00,msg : Cleanup of operator and work station messages started.,ts : 2018-09-03 22:00:25}
{msgid : CPI1E23,sev : 00,msg : Cleanup has started.,ts : 2018-09-03 22:00:25}
{msgid : CPI1143,sev : 10,msg : Job not submitted for job schedule entry QEZBKTMMON number 000009 because the entry is held.,ts : 2018-09-03 22:00:00}
{msgid : CPIEF01,sev : 00,msg : Service Agent is analyzing your system product activity log entries.,ts : 2018-09-03 20:13:23}
{msgid : CPI1143,sev : 10,msg : Job not submitted for job schedule entry QEZBKMGMON number 000027 because the entry is held.,ts : 2018-09-03 19:00:00}
{msgid : CPIEF01,sev : 00,msg : Service Agent is analyzing your system product activity log entries.,ts : 2018-09-03 16:13:22}
{msgid : CPIEF01,sev : 00,msg : Service Agent is analyzing your system product activity log entries.,ts : 2018-09-03 12:13:20}
{msgid : CPIEF01,sev : 00,msg : Service Agent is analyzing your system product activity log entries.,ts : 2018-09-03 08:13:19}
{msgid : CPIEF01,sev : 00,msg : Service Agent is analyzing your system product activity log entries.,ts : 2018-09-03 04:13:18}
{msgid : CPIEF01,sev : 00,msg : Service Agent is analyzing your system product activity log entries.,ts : 2018-09-03 00:13:16}
{msgid : CPC1E1D,sev : 00,msg : Cleanup has completed.,ts : 2018-09-02 22:00:25}
{msgid : CPI1E87,sev : 00,msg : Cleanup of system journals and system logs successfully completed.,ts : 2018-09-02 22:00:25}
{msgid : CPI1E86,sev : 00,msg : Cleanup of system journals and system logs started.,ts : 2018-09-02 22:00:25}
{msgid : CPI1E94,sev : 00,msg : Cleanup of job logs and other system output successfully completed.,ts : 2018-09-02 22:00:24}
{msgid : CPI1E83,sev : 00,msg : Cleanup of user messages successfully completed.,ts : 2018-09-02 22:00:24}
{msgid : CPI1E81,sev : 00,msg : 000012 of 000086 messages deleted from QSRVAGT.,ts : 2018-09-02 22:00:24}
{msgid : CPI1E81,sev : 00,msg : 000006 of 000048 messages deleted from QSRV.,ts : 2018-09-02 22:00:24}
{msgid : CPI1E81,sev : 00,msg : 000006 of 000042 messages deleted from QPGMR.,ts : 2018-09-02 22:00:24}
{msgid : CPI1E93,sev : 00,msg : Cleanup of job logs and other system output started.,ts : 2018-09-02 22:00:24}
{msgid : CPI1E85,sev : 00,msg : Cleanup of operator and work station messages successfully completed.,ts : 2018-09-02 22:00:24}
{msgid : CPI1E92,sev : 00,msg : User cleanup program successfully completed.,ts : 2018-09-02 22:00:24}
{msgid : CPI1E91,sev : 00,msg : User cleanup program started.,ts : 2018-09-02 22:00:24}
{msgid : CPI1E82,sev : 00,msg : Cleanup of user messages started.,ts : 2018-09-02 22:00:24}
{msgid : CPI1E84,sev : 00,msg : Cleanup of operator and work station messages started.,ts : 2018-09-02 22:00:24}
{msgid : CPI1E23,sev : 00,msg : Cleanup has started.,ts : 2018-09-02 22:00:24}
{msgid : CPIEF01,sev : 00,msg : Service Agent is analyzing your system product activity log entries.,ts : 2018-09-02 20:13:15}
{msgid : CPIEF01,sev : 00,msg : Service Agent is analyzing your system product activity log entries.,ts : 2018-09-02 16:13:13}
{msgid : CPIEF01,sev : 00,msg : Service Agent is analyzing your system product activity log entries.,ts : 2018-09-02 12:13:12}
{msgid : CPIEF01,sev : 00,msg : Service Agent is analyzing your system product activity log entries.,ts : 2018-09-02 08:13:10}
{msgid : CPIEF01,sev : 00,msg : Service Agent is analyzing your system product activity log entries.,ts : 2018-09-02 04:13:09}
{msgid : CPIEF01,sev : 00,msg : Service Agent is analyzing your system product activity log entries.,ts : 2018-09-02 00:13:07}
End of Messages :

The code will be updated on GitHub for those who are interested.

Keep coding….
Chris…