印刷待ち行列(OUTQ) に印刷スプールが投入された、すなわち何らかの
印刷が行われた場合、
それらを検知してスプールの名前や属性情報を取得するにはどのようにすればよいだろうか?
CPYSPLF や Spoolライター Ver 3.0 の CVTSPLF コマンドを利用するにしても
スプールの名前や番号を特定しなければならない。
あるOUTQ に投入された印刷スプールを自動的に処理したいという要求は発生する。
毎度、WRKOUTQ によって手作業でスプールを検索するわけにはいかないからだ。
このような仕組みはOUTQにデータ待ち行列を関連づけることによって実現できる。
例えば
CHGOUTQ OUTQ(QGPL/QPRINT) DTAQ(MYLIB/MYDTAQ)
によって OUTQ : QGPL/QPRINT に対してデータ待ち行列 MYLIB/MYDTAQ を
関連づけるとトリガーのように QGPL/QPRINT に何らかの印刷スプールが
投入されると MYLIB/MYDATQ にデータが OS/400 によって送信される。
別に用意したPGM でこのデータ待ち行列を API: QRCVDTAQ を受信状態で
監視しておけば、QGPL/QPRINT に投入が発生すると直ちに QRCVDTAQ に
よってどのようなスプールが投入されたのかを知ることができる。
下記は実際にSpoolライター Ver 3.0 に使用されている WRITERD という
名前のサーバーである。
この例では永続待機ではなく、クライアントから定期的に検査の命令が
送られてくるので、その都度データ待ち行列を検査して、
スプールが見つかればクライアントにスプールの情報を戻してする例である。
0001.00 /**********************************************************************
0002.00 /*
0003.00 /* WRITERD : SpoolWTR Writer waiting server for Spool-Writer
0004.00 /*
0005.00 /* Office Quattro Co.ltd 2003.08.21 10:28:25 created
0006.00 /* this program will be waiting for OUTQ:
0007.00 /*
0008.00 /* create : CRTBNDC SPOOLWTR/WRITERD
0009.00 /*
0010.00 /**********************************************************************
0011.00 #include <stdio.h>
0012.00 #include <stdlib.h>
0013.00 #include <string.h>
0014.00 #include <sys/socket.h>
0015.00 #include <qrcvdtaq.h>
0016.00 #include <decimal.h>
0017.00 #include "QSYSINC/H/CMC" /* CPI-Communications pseudonyms */
0018.00
0019.00 #define TRUE 0
0020.00 #define FALSE -1
0021.00
0022.00 char writer[11];
0023.00 char cmn[4]; /* Communication Type */
0024.00 char convid[9]; /* Coversation ID */
0025.00 int sockid;
0026.00 char spool_inf[128];
0027.00 /********************************************************************/
0028.00 /* */
0029.00 /* main : parm 1. writer[10] */
0030.00 /* parm 2. cmn[1] (TCP or CPC) */
0031.00 /* parm 3. convid[8] */
0032.00 /* */
0033.00 /********************************************************************/
0034.00 void main(int argc, char *argv[]){
0035.00 _Decimal(5,0) data_len = 120;
0036.00 _Decimal(5,0) wait = 1;
0037.00 char send_buffer[3000];
0038.00 CM_INT32 send_length;
0039.00 unsigned char tcp_buffer[3004];
0040.00 CM_INT32 request_to_send_received;
0041.00 CM_INT32 return_code;
0042.00 int len;
0043.00 typedef struct{
0044.00 char job[11];
0045.00 char user[11];
0046.00 char jobnbr[7];
0047.00 } JOBINFO;
0048.00 JOBINFO jobinfo;
0049.00 char spoolf[11];
0050.00 int splnbr;
0051.00 typedef struct{
0052.00 char outq[11];
0053.00 char outqlib[11];
0054.00 } OUTQINFO;
0055.00 OUTQINFO outqinfo;
0056.00 int bSpool;
0057.00 char rcv_buffer[4];
0058.00 CM_INT32 requested_length;
0059.00 CM_INT32 data_received;
0060.00 CM_INT32 received_length;
0061.00 CM_INT32 status_received;
0062.00
0063.00 /*-------------------------------------------------------------------*/
0064.00 /* Copy the input parameters to local variables. */
0065.00 /*-------------------------------------------------------------------*/
0066.00 memset(writer, 0, sizeof(writer));
0067.00 memcpy(writer, argv[1], 10);
0068.00 writer[10] = 0x00;
0069.00 memset(cmn, 0, sizeof(cmn));
0070.00 memcpy(cmn, argv[2], 3);
0071.00 cmn[3] = 0x00;
0072.00 memset(convid, 0, sizeof(convid));
0073.00 memcpy(convid, argv[3], 8);
0074.00 convid[8] = 0x00;
0075.00 sockid = atoi(convid);
0076.00
0077.00 /*[ 1 秒間だけ待つ ]*/
0078.00 QRCVDTAQ(writer, "QUSRTEMP ", &data_len, spool_inf, wait);
0079.00 if(data_len == 0 ||
0080.00 strncmp(spool_inf, "*SPOOL ", 10) != 0){/* データなし */
0081.00 bSpool = FALSE;
0082.00 memcpy(send_buffer,"CMOK", 4);
0083.00 }/* データなし */
0084.00 else{/* データあり */
0085.00 bSpool = TRUE;
0086.00 memcpy(send_buffer,"SPLF", 4);
0087.00 }/* データあり */
0088.00 send_length = 4;
0089.00 if(cmn[0] == 'C'){/*( CPI-C )*/
0090.00 CMSEND(convid, send_buffer, &send_length,
0091.00 &request_to_send_received, &return_code);}
0092.00 else{
0093.00 memset(tcp_buffer, 0, sizeof(tcp_buffer));
0094.00 memcpy(&tcp_buffer[0], &send_length, 4);
0095.00 memcpy(&tcp_buffer[4], send_buffer, send_length);
0096.00 len = send_length + 4;
0097.00 tcp_buffer[len] = 0x00;
0098.00 return_code = send(sockid, tcp_buffer, len, 0);
0099.00 }
0100.00 if(bSpool == FALSE) return;
0101.00 /* 以下はデータありの処理 */
0102.00 /*[ 応答の受信 ... の開始 ]*/
0103.00 if(cmn[0] == 'C'){/*( CPI-C )*/
0104.00 requested_length = 4;
0105.00 CMRCV(convid, rcv_buffer, &requested_length,
0106.00 &data_received, &received_length, &status_received,
0107.00 &request_to_send_received, &return_code);
0108.00 }/*( CPI-C )*/
0109.00 else{/*( TCP/IP )*/
0110.00 recv(sockid, rcv_buffer, 4, 0);
0111.00 }/*( TCP/IP )*/
0112.00 /*[ 応答の受信 ... の終了 ]*/
0113.00 memcpy(jobinfo.job, &spool_inf[12], 10);
0114.00 jobinfo.job[10] = 0x00;
0115.00 memcpy(jobinfo.user, &spool_inf[22], 10);
0116.00 jobinfo.user[10] = 0x00;
0117.00 memcpy(jobinfo.jobnbr, &spool_inf[32], 6);
0118.00 jobinfo.jobnbr[6] = 0x00;
0119.00 memcpy(spoolf, &spool_inf[38], 10);
0120.00 spoolf[10] = 0x00;
0121.00 memcpy(&splnbr, &spool_inf[48], 4);
0122.00 memcpy(outqinfo.outq, &spool_inf[52], 10);
0123.00 outqinfo.outq[10] = 0x00;
0124.00 memcpy(outqinfo.outqlib, &spool_inf[62], 10);
0125.00 outqinfo.outqlib[10] = 0x00;
0126.00 send_length = sprintf(send_buffer,"%10s%10s%6s%10s%04d%10s%10s",
0127.00 jobinfo.job, jobinfo.user, jobinfo.jobnbr,
0128.00 spoolf, splnbr, outqinfo.outq, outqinfo.outqlib);
0129.00 if(cmn[0] == 'C'){/*( CPI-C )*/
0130.00 CMSEND(convid, send_buffer, &send_length,
0131.00 &request_to_send_received, &return_code);}
0132.00 else{
0133.00 memset(tcp_buffer, 0, sizeof(tcp_buffer));
0134.00 memcpy(&tcp_buffer[0], &send_length, 4);
0135.00 memcpy(&tcp_buffer[4], send_buffer, send_length);
0136.00 len = send_length + 4;
0137.00 tcp_buffer[len] = 0x00;
0138.00 return_code = send(sockid, tcp_buffer, len, 0);
0139.00 }
0140.00
0141.00 return;
0142.00 }
ライターとしての機能を考慮するのであれば STRWTR のようなライター開始コマンドの
実行のときには、OUTQ に登録されているスプールの一覧表を改めて、すべて
データ待ち行列に投入するような機能を用意しておく必要があることを忘れてはならない。
データ待ち行列にOS/400が情報を投入するのはあくまでも変化が起きたときだけなのである。
今回はデータ待ち行列を印刷スプールのトリガーとして使用したが、データ待ち行列は
通信やデータ・ベースのトリガーとしても応用範囲は広い。
一度、データ待ち行列を関連づけることができるオブジェクトが他にないかどうか
読者で調査してみることをお勧めする。
意外な応用範囲がデータ待ち行列の利用から広がるはずである。