RPG の「 319. RPG を使って Watson と対話する 」で紹介した
RPG プログラムのソースをここで紹介する。
0001.00 A*%%TS SD 20180617 093516 QTR REL-V6R1M0 5761-WDS 0002.00 A*-----------------------------------------------* 0003.00 A* TOWATSONFM : WATOSON 翻訳 0004.00 A*-----------------------------------------------* 0005.00 A*%%EC 0006.00 A DSPSIZ(24 80 *DS3) 0007.00 A MSGLOC(24) 0008.00 A PRINT 0009.00 A R DSPDTA01 0010.00 A*%%TS SD 20180617 093516 QTR REL-V6R1M0 5761-WDS 0011.00 A TEXT(' 初期画面 ') 0012.00 A CF03(03 ' 終了 ') 0013.00 A BLINK 0014.00 A OVERLAY 0015.00 A 1 2'TOWATSON' 0016.00 A 1 27' 初めてのワトソン ' 0017.00 A DSPATR(HI) 0018.00 A 1 66' 日付 ' 0019.00 A 1 73DATE 0020.00 A EDTCDE(Y) 0021.00 A 4 2' 言語 ' 0022.00 A FROMLG 1Y 0B 4 10VALUES(1 2 3 4 5) 0023.00 A 4 13' から ' 0024.00 A TOLANG 1Y 0B 4 23VALUES(1 2 3 4 5) 0025.00 A 4 26' へ翻訳します ' SOSI A 4 42'(1= 英語 2= スペイン語 3=* 0027.00 A ス語 ' 0028.00 A 5 43'4= イタリア語 5= 日本語 )' 0029.00 A 8 2' 原文 ' 0030.00 A FROMTXT 120O B 8 10DSPATR(PC) 0031.00 A CHECK(LC) 0032.00 A 13 2' 訳文 ' 0033.00 A TOTXT 120O B 13 10 0034.00 A 80 22 2' お待ちください。 ' 0035.00 A DSPATR(HI) 0036.00 A 23 2'F3= 終了 ' 0037.00 A COLOR(BLU)
0030.00 A FROMTXT 120O B 8 10DSPATR(PC) 0031.00 A CHECK(LC)
の FROMTEXT には RPG で I am a boy という文字列が初期にセットされる。
英小文字を入力するためには CHECK ( LC ) の指定が必要である。
Watson は英大文字の文字列は翻訳しない。
英文で翻訳するのは英小文字の文字列を指定する必要がある。
0001.00 H DFTNAME(TOWATSON) DATEDIT(*YMD/) BNDDIR('QC2LE') 0002.00 F********** 初めてのワトソン ****************************************** 0003.00 FTOWATSONFMCF E WORKSTN 0004.00 F********************************************************************** 0005.00 0006.00 * CRTRPGMOD OBJ(QTEMP/TOWATSON) SRCFILE(R610SRC/QRPGLESRC) 0007.00 * DBGVIEW(*SOURCE) AUT(*ALL) 0008.00 * CRTPGM PGM(QUATTRO/TOWATSON) MODULE(QTEMP/TOWATSON) 0009.00 * BNDSRVPGM(ASNET.COM/HTTPSRV) ACTGRP(*NEW) AUT(*ALL) 0010.00 0011.00 *-------------------------------------------------------------------* 0012.00 * 2017/05/01 : 作成 0013.00 *-------------------------------------------------------------------* 0014.00 *( 作業変数 ) 0015.00 D DCR S 1A DIM(15) CTDATA PERRCD(15) 0016.00 D AR S 1A DIM(256) 0017.00 D N S 4S 0 0018.00 D M S 4S 0 0019.00 D TRUE# S 4B 0 INZ(0) 0020.00 D FALSE# S 4B 0 INZ(-1) 0021.00 D NULL C CONST(X'00') 0022.00 0023.00 D DS 0024.00 D 1 10A INZ('オトオヘカネケホタア') 0025.00 D LANG 1 10A DIM(5) 0026.00 0027.00 D*( TRANSLATE のプロトタイプ宣言 ) 0028.00 D TRANSLATE PR 0029.00 D FROMLANG 2A VALUE 0030.00 D TOLANG 2A VALUE 0031.00 D FROMTXT 120A VALUE 0032.00 D TOTXT * VALUE 0033.00 0034.00 D*( ENCODE のプロトタイプ宣言 ) 0035.00 D ENCODE PR 1000A 0036.00 D FROMSTR 120A VALUE 0037.00 0038.00 D*( HTTP_REQUEST のプロトタイプ宣言 ) 0039.00 D HTTP_REQUEST PR 10I 0 0040.00 D URLPATH * VALUE 0041.00 D RTNVALUE * VALUE 0042.00 D RTNLEN * VALUE 0043.00 D MODE 10I 0 VALUE 0044.00 0045.00 C*( 明細画面 ) 0046.00 C*----------------------------------------------------+ 0047.00 C DSPLY TAG 0048.00 C EXFMT DSPDTA01 0049.00 C*----------------------------------------------------+ 0050.00 C SETOFF 99 0051.00 C*( CF03 )- 終了 0052.00 C *IN03 IFEQ *ON 0053.00 C SETON LR 0054.00 C LR RETURN 0055.00 C GOTO DSPLY 0056.00 C END 0057.00 C*( 実行キー ) 0058.00 C SETON 80 0059.00 C WRITE DSPDTA01 0060.00 C SETOFF 80 0061.00 /FREE 0062.00 TRANSLATE(LANG(FROMLG):LANG(TOLANG):FROMTXT:%ADDR(TOTXT)); 0063.00 /END-FREE 0064.00 C GOTO DSPLY 0065.00 C SETON LR 0066.00 C RETURN 0067.00 C****************************************************** 0068.00 C *INZSR BEGSR 0069.00 C****************************************************** 0070.00 C Z-ADD 1 FROMLG 0071.00 C Z-ADD 5 TOLANG 0072.00 C MOVEL(P) 'I am a boy' FROMTXT 0073.00 C ENDSR 0074.00 C****************************************************** 0075.00 P TRANSLATE B EXPORT 0076.00 C****************************************************** 0077.00 D PI 0078.00 D FROMLANG 2A VALUE 0079.00 D TOLANG 2A VALUE 0080.00 D FROMTXT 120A VALUE 0081.00 D TOTEXT_P * VALUE 0082.00 0083.00 D STR1 S 1000A 0084.00 D STR2 S 1000A 0085.00 D RC S 10I 0 0086.00 D TOTEXT S 120A BASED(TOTEXT_P) 0087.00 0088.00 D TEXTBACK DS QUALIFIED 0089.00 D LEN 1 4S 0 0090.00 D DATA 5 260A 0091.00 0092.00 /FREE 0093.00 STR2 = ENCODE(%TRIMR(FROMTXT)); 0094.00 STR1 = *BLANKS; 0095.00 STR1 = 'https://watson-api-explorer.ng.bluemix.net/' + 0096.00 'language-translator/api/v2/translate?model_id=' + 0097.00 FROMLANG + '-' + TOLANG + '&text=' + STR2 + NULL; 0098.00 STR1 = %TRIMR(STR1); 0099.00 RC = HTTP_REQUEST(%ADDR(STR1): %ADDR(TEXTBACK.DATA): 0100.00 %ADDR(TEXTBACK.LEN): 1); 0101.00 IF (TEXTBACK.LEN > 0); 0102.00 TOTEXT = TEXTBACK.DATA; 0103.00 ELSE; 0104.00 TOTEXT = *BLANKS; 0105.00 ENDIF; 0106.00 RETURN; 0107.00 /END-FREE 0108.00 P E 0109.00 C****************************************************** 0110.00 P ENCODE B EXPORT 0111.00 C****************************************************** 0112.00 D PI 1000A 0113.00 D FROMSTR 120A VALUE 0114.00 0115.00 D TOSTR S 1000A 0116.00 D BUFLEN S 5P 0 0117.00 D STRING S 256A 0118.00 D N S 4S 0 0119.00 D POS S 4S 0 INZ(1) 0120.00 D AR S 1A DIM(256) 0121.00 D BR S 1A DIM(3) 0122.00 D FLD3 S 3A 0123.00 D UPPER S 1A 0124.00 D LOWER S 1A 0125.00 0126.00 D DS 0127.00 D CH01 1 1 INZ(X'00') 0128.00 D CH02 2 2 0129.00 D BIN4 1 2B 0 0130.00 0131.00 C FROMSTR CAT(P) NULL:0 STRING 0132.00 C EVAL BUFLEN = %LEN(%TRIMR(FROMSTR)) 0133.00 C*----------------------------------------------------+ 0134.00 C CALL 'QDCXLATE' 99 0135.00 C PARM BUFLEN 0136.00 C PARM STRING 0137.00 C PARM 'QASCII ' TBL 10 0138.00 C PARM 'QSYS ' TBLLIB 10 0139.00 C*----------------------------------------------------+ 0140.00 C MOVEA *BLANKS AR 0141.00 C MOVEA *BLANKS BR 0142.00 C EVAL BR(1) = '%' 0143.00 C 1 DO BUFLEN N 0144.00 C EVAL CH02 = %SUBST(STRING:N:1) 0145.00 C BIN4 DIV 16 BIN4 0146.00 C MVR AMARI 2 0 0147.00 *( 上位ビット ) 0148.00 C EVAL M = BIN4 0149.00 C MOVE DCR(M) UPPER 0150.00 *( 下位ビット ) 0151.00 C AMARI IFGT 0 0152.00 C Z-ADD AMARI BIN4 0153.00 C Z-ADD AMARI M 0154.00 C MOVE DCR(M) LOWER 0155.00 C ELSE 0156.00 C MOVE '0' LOWER 0157.00 C ENDIF 0158.00 * 0159.00 /FREE 0160.00 FLD3 = '%' + UPPER + LOWER; 0161.00 /END-FREE 0162.00 C MOVEA FLD3 AR(POS) 0163.00 C ADD 3 POS 0164.00 C ENDDO 0165.00 C MOVEA(P) AR TOSTR 0166.00 C TOSTR CAT NULL:0 TOSTR 0167.00 C EVAL TOSTR = %TRIMR(TOSTR) 0168.00 C RETURN TOSTR 0169.00 P E 0170.00 R - 以下は配列 0170.00 ** DCR - 以下は配列 0171.00 123456789ABCDEF
上記が Watson にアクセスするための ILE-RPG であるが
IBM のサンプル・ソースでは
のように制約が多く、通常の RPG 開発者では容易には
開発する事ができない。
まず初めに
0072.00 C MOVEL(P) 'I am a boy' FROMTXT
で I am a boy を FROMTXT にセットして
EXFMT で表示画面レコード : DSPDTA01 を表示する。
0061.00 /FREE 0062.00 TRANSLATE(LANG(FROMLG):LANG(TOLANG):FROMTXT:%ADDR(TOTXT)); 0063.00 /END-FREE
によって翻訳プロシージャー: TRANSLATE で翻訳を行う。
TRANSLATE プロシージャーで最初に行っているのは
0093.00 STR2 = ENCODE(%TRIMR(FROMTXT));
というエンコード処理である。
HTTP プロトコルで文字列を渡す場合には HEX コードを
ASCII コードとして分割表示した形式で渡す必要がある。
これは HTTP プロトコルの仕様である。
例えば「/」という文字は ASCII では X'2F' なのでこれを %2F と表記する。
これがエンコードである。
HTTP リクエストは ASCII コードでのエンコードが必要なので、
ENCODE サブ・ルーチンの中では最初に
0133.00 C*----------------------------------------------------+ 0134.00 C CALL 'QDCXLATE' 99 0135.00 C PARM BUFLEN 0136.00 C PARM STRING 0137.00 C PARM 'QASCII ' TBL 10 0138.00 C PARM 'QSYS ' TBLLIB 10 0139.00 C*----------------------------------------------------+
で ASCII コードに変換してから
0159.00 /FREE 0160.00 FLD3 = '%' + UPPER + LOWER; 0161.00 /END-FREE
によってエンコード文字列に組み立てている。
さて
0095.00 STR1 = 'https://watson-api-explorer.ng.bluemix.net/' + 0096.00 'language-translator/api/v2/translate?model_id=' + 0097.00 FROMLANG + '-' + TOLANG + '&text=' + STR2 + NULL;
が重要な URL を組み立てている部分である。
FROMLANG は en から TOLANG には jp が入り、
英語から日本語への翻訳を指示している。
先ほどエンコードした文字列は STR2 の部分である。
最後に
0099.00 RC = HTTP_REQUEST(%ADDR(STR1): %ADDR(TEXTBACK.DATA): 0100.00 %ADDR(TEXTBACK.LEN): 1);
で C 言語で EXPORT している HTTP_REQUEST プロシージャーに
STR1 を投げて結果としての TEXTBACK.DATA を受取る。
これが DSPF の TOTXT として表示される。
0001.00 /********************************************************************/ 0002.00 /* */ 0003.00 /* HTTPSRV : HTTP サービス・プログラム */ 0004.00 /* */ 0005.00 /* Office Quattro Co,.Ltd 2018/06/28 15:34:00 created */ 0006.00 /* */ 0007.00 /* CRTCMOD QTEMP/HTTPSRV SRCFILE(R720SRC/QCSRC) AUT(*ALL) */ 0008.00 /* CRTSRVPGM ASNET.COM/HTTPSRV MODULE(QTEMP/HTTPSRV) */ 0009.00 /* BNDSRVPGM((ASNET.COM/UNI_CODE)) ACTGRP(*CALLER) AUT(*ALL) */ 0010.00 /* */ 0011.00 /********************************************************************/ 0012.00 #pragma comment(COPYRIGHT, "as400-net.com EnterpriseServer (C) CopyRigh 0013.00 Office Quattro.Corp. 2018- All right reserved. Users Restricted ™ 0014.00 Rights - Use, duplication or disclosure restricted by Office Quattro ™ 0015.00 Corp. Licenced Materials-Property of Office Quattro.") 0016.00 #include0017.00 #include 0018.00 #include 0019.00 #include /* triml */ 0020.00 #include 0021.00 #include 0022.00 #include 0023.00 #include 0024.00 #include 0025.00 #include 0026.00 #include 0027.00 #include 0028.00 #include 0029.00 #include 0030.00 #include 0031.00 #include 0032.00 0033.00 #define TRUE 0 0034.00 #define FALSE -1 0035.00 #define GSK_FALSE 0 0036.00 #define DEBUG 2 0037.00 0038.00 /*( UTF 変数 )*/ 0039.00 #define UTF8 1208 0040.00 #define USA 0 0041.00 #define JPN 1 0042.00 #define CHS 2 0043.00 #define CHT 3 0044.00 0045.00 int bLR = FALSE; 0046.00 char ASC_CRLF[] = {0x0d, 0x0a, 0x00}; /* ASCII 改行コード */ 0047.00 char W_ASC_CRLF[] = {0x0d, 0x0a, 0x0d, 0x0a, 0x00}; 0048.00 typedef struct { 0049.00 int BYTESPRO; 0050.00 int BYTESAVL; 0051.00 char MSGID[7]; 0052.00 char RESRVD; 0053.00 char EXCPDATA[100]; 0054.00 } ERRSTRUCTURE; /* Define the error return structure */ 0055.00 ERRSTRUCTURE errcode;/* Error Code Structure for RCVMSG */ 0056.00 volatile _INTRPT_Hndlr_Parms_T ca; 0057.00 0058.00 /*************************************************************/ 0059.00 /* 内 部 使 用 関 数 */ 0060.00 /*************************************************************/ 0061.00 void INZSR(void); 0062.00 short int getcLen(char cLen[4]); 0063.00 void LRRTN(void); 0064.00 0065.00 /*************************************************************/ 0066.00 /* EXPORT 関 数 */ 0067.00 /*************************************************************/ 0068.00 int HTTP_REQUEST(char* URLPath, char* rtnvalue, char rtnlen[5], int m 0069.00 /*************************************************************/ 0070.00 /* EXPORT 変 数 */ 0071.00 /*************************************************************/ 0072.00 /*************************************************************/ 0073.00 /* IMPORT 関 数 */ 0074.00 /*************************************************************/ 0075.00 int toUTF8(char* ebcbuf, char* unibuf, int CNTRY); 0076.00 int fromUTF8(char* unibuf, char* ebcbuf, int CNTRY); 0077.00 /*************************************************************/ 0078.00 /* IMPORT 変 数 */ 0079.00 /*************************************************************/ 0080.00 /*************************************************************/ 0081.00 /* 外 部 呼 出 し 関 数 */ 0082.00 /*************************************************************/ 0083.00 void MonitorMSG(_INTRPT_Hndlr_Parms_T ca, char* ref); 0084.00 #pragma linkage(MonitorMSG, OS) 0085.00 #pragma map(MonitorMSG, "ASNET.COM/MONMSG") 0086.00 /*************************************************************/ 0087.00 /* グ ロ ー バ ル 変 数 */ 0088.00 /*************************************************************/ 0089.00 /*------( 受取りパラメータ値 )----------*/ 0090.00 /*------( 受取りパラメータ値 )----------*/ 0091.00 char ref[133]; 0092.00 int bINZSR = FALSE, m_bSSL = FALSE, sockfd = FALSE; 0093.00 gsk_handle my_env_handle = NULL; /* secure enviroment handle */ 0094.00 gsk_handle my_session_handle = NULL; /* secure session handle */ 0095.00 0096.00 /********************************************************************** 0097.00 int HTTP_REQUEST(char* URLPath, char* rtnvalue, char rtnlen[5], int m 0098.00 /********************************************************************** 0099.00 /* mode: 1= リリース 2= デバッグ */ 0100.00 { 0101.00 char http[7], *ptr, host[98], cPORT[5], ebcHTTP[512],ascHTTP[2048],a 0102.00 eHost[98], HOST[98], cLen[4]; 0103.00 int pos, PORT = 80, len, length, sndlen, rcvlen, rcvlen2, rc = 0, i 0104.00 struct sockaddr_in serv_addr; 0105.00 struct hostent * hostp; 0106.00 _Decimal(5,0) dclen, outlen; 0107.00 _Decimal(5,0) maxotl = 2048; 0108.00 short int shlen; 0109.00 0110.00 if(bINZSR == FALSE) INZSR(); 0111.00 0112.00 /*(1) SOCKET/SSL の判別 */ 0113.00 memcpy(http, URLPath, 6); 0114.00 http[6] = 0x00; 0115.00 if(strncmp(http, "https", 5) == 0 || 0116.00 strncmp(http, "HTTPS", 5) == 0){/*SSL*/ 0117.00 PORT = 443; 0118.00 /* GSK 環境のオープン */ 0119.00 rc = errno = 0; 0120.00 rc = gsk_environment_open(&my_env_handle); 0121.00 if(rc != GSK_OK){/*SSL 生成エラー */ 0122.00 printf("HTTVSRV[%d] SSL 生成エラー :%s™n", __LINE__, 0123.00 gsk_strerror(errno)); 0124.00 printf("HTTPSRV[%d] rc = %d, errno = %d™n", __LINE__, rc, errno 0125.00 getchar(); 0126.00 return FALSE; 0127.00 }/*SSL 生成エラー */ 0128.00 /* 適用業務 ID のセット */ 0129.00 rc = errno = 0; 0130.00 rc = gsk_attribute_set_buffer(my_env_handle, GSK_OS400_APPLICATIO 0131.00 "HTTPSRV", 7); 0132.00 if(rc != GSK_OK){/* エラー */ 0133.00 printf("HTTPSVR[%d] SSL 適用業務 ID 生成エラー :%s™n", __LINE__ 0134.00 gsk_strerror(errno)); 0135.00 printf("HTTPSRV[%d] rc = %d, errno = %d™n", __LINE__, rc, errno 0136.00 getchar(); 0137.00 return FALSE; 0138.00 }/* エラー */ 0139.00 /* enum のセット */ 0140.00 rc = gsk_attribute_set_enum(my_env_handle, GSK_SESSION_TYPE, 0141.00 GSK_CLIENT_SESSION); 0142.00 if(rc != GSK_OK){/* エラー */ SOSI printf("HTTPSVR[%d] SSL クライアント・セッションのセット・エラ 0144.00 __LINE__); 0145.00 printf(" [%d] %s™n", __LINE__, gsk_strerror(errno)); 0146.00 printf("HTTPSRV[%d] rc = %d, errno = %d™n", __LINE__, rc, errno 0147.00 getchar(); 0148.00 return FALSE; 0149.00 }/* エラー */ 0150.00 0151.00 /*( 次でエラーが発生する )*/ 0152.00 /* 機密保護環境の初期化 */ 0153.00 rc = errno = 0; 0154.00 rc = gsk_environment_init(my_env_handle); 0155.00 if(rc != GSK_OK){/* エラー */ SOSI printf("HTTPSRV[%d] 機密保護環境 (my_env_handle) 初期設定エラ 0157.00 __LINE__, gsk_strerror(errno)); 0158.00 printf("[%d] 6002 = GSK_AS400_ERROR_NOT_REGISTERED™n", __LINE_ 0159.00 printf("HTTPSRV[%d] rc = %d, errno = %d™n", __LINE__, rc, errn 0160.00 printf("[%d] GSK_OK = %d, GSK_TRUE = %d, GSK_FALSE = %d™n", 0161.00 __LINE__, GSK_OK, GSK_TRUE, GSK_FALSE); SOSI printf("HTTPSRV[%d]TSL1.2 がサポートされていない可能性がありま 0163.00 getchar(); 0164.00 return FALSE; 0165.00 }/* エラー */ 0166.00 m_bSSL = TRUE; 0167.00 }/*SSL*/ 0168.00 else if(strncmp(http, "http", 4) == 0 || 0169.00 strncmp(http, "HTTP", 4) == 0){/*SOCKET*/ 0170.00 PORT = 80; 0171.00 }/*SOCKET*/ 0172.00 else{/*NO SOCKET*/ 0173.00 printf("HTTPSRV[%d] HTTP 指定が見つかりません :%s™n", __LINE__, UR SOSI printf("HTTPSRV[%d] 実行環境の CCSID が正しくない可能性があります 0175.00 __LINE__); 0176.00 getchar(); 0177.00 return FALSE; 0178.00 }/*NO SOCKET*/ 0179.00 0180.00 /*(2) ホスト IP アドレスの抽出 */ 0181.00 if((ptr = strstr(URLPath, "://")) != NULL){/* ホスト名 */ 0182.00 pos = (int)(ptr - URLPath) + 3; 0183.00 memcpy(host, &URLPath[pos], 48); 0184.00 host[48] = 0x00; 0185.00 if((ptr = strchr(host, '/')) != NULL){/* 切れ目 */ 0186.00 pos = (int)(ptr - host); 0187.00 host[pos] = 0x00; 0188.00 if((ptr = strchr(host, ':')) != NULL){/*PORT あるか */ 0189.00 pos = (int)(ptr - host); 0190.00 strcpy(cPORT, &host[pos+1]); 0191.00 PORT = atoi(cPORT); 0192.00 host[pos] = 0x00; 0193.00 }/*PORT あるか */ 0194.00 for(i = 0; i h_addr,sizeof(&serv_addr.si 0209.00 /* printf("HTTPSRV[%d] サーバー IP アドレス =%d.%d.%d.%d™n", __LI 0210.00 hostp->h_addr[0], hostp->h_addr[1], hostp->h_addr[2], 0211.00 hostp->h_addr[3]); */ 0212.00 sprintf(eHost, "%d.%d.%d.%d", hostp->h_addr[0], hostp->h_addr 0213.00 hostp->h_addr[2], hostp->h_addr[3]); 0214.00 }/* 成功 */ 0215.00 serv_addr.sin_port = htons(PORT); 0216.00 0217.00 /*(3) Socket の作成 */ 0218.00 if(m_bSSL == TRUE){/*SSL*/ 0219.00 if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){/* 失敗 */ 0220.00 printf("HTTPSRV[%d]SOCKET 作成エラー :%s™n",__LINE__,strerror 0221.00 getchar(); 0222.00 return FALSE; 0223.00 }/* 失敗 */ 0224.00 }/*SSL*/ 0225.00 else{/*SOCKET 作成 */ 0226.00 if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){/* 失敗 */ 0227.00 printf("HTTPSRV[%d]SOCKET 作成エラー :%s™n",__LINE__,strerror 0228.00 getchar(); 0229.00 return FALSE; 0230.00 }/* 失敗 */ 0231.00 }/*SOCKET 作成 */ 0232.00 0233.00 /*(4) CONNECT */ 0234.00 if(m_bSSL == TRUE){/*SSL*/ 0235.00 if(connect(sockfd, (struct sockaddr *)&serv_addr, 0236.00 sizeof(serv_addr)) < 0){/*connect エラー */ 0237.00 close(sockfd); 0238.00 printf("HTTPSRV[%d] CONNECT エラー :%s™n", __LINE__, 0239.00 strerror(errno)); 0240.00 printf("HTTPSRV[%d] ホストの指定の誤りの可能性があります ™ 0241.00 __LINE__); 0242.00 getchar(); 0243.00 return FALSE; 0244.00 }/*connect エラー */ 0245.00 /*( 機密保護セッションのオープン )*/ 0246.00 rc = gsk_secure_soc_open(my_env_handle, &my_session_handle); 0247.00 if(rc != GSK_OK){/* エラー */ 0248.00 close(sockfd); SOSI printf("HTTPSRV[%d] 保護セッション (soc_open) オープン・エ * 0250.00 __LINE__, gsk_strerror(errno)); 0251.00 printf("HTTPSRV[%d] rc = %d, errno = %d™n", __LINE__, rc, er 0252.00 getchar(); 0253.00 return FALSE; 0254.00 }/* エラー */ 0255.00 /*( 保護セッションに sockfd を関連づけ )*/ 0256.00 rc = gsk_attribute_set_numeric_value(my_session_handle, GSK_FD 0257.00 if(rc != GSK_OK){/* エラー */ 0258.00 close(sockfd); 0259.00 printf("HTTPSRV[%d] sockfd 関連づけエラー :%s™n", __LINE__, 0260.00 gsk_strerror(errno)); 0261.00 printf("HTTPSRV[%d] rc = %d, errno = %d™n", __LINE__, rc, er 0262.00 getchar(); 0263.00 return FALSE; 0264.00 }/* エラー */ 0265.00 /*( 機密保護のハンドシェイク )*/ 0266.00 rc = errno = 0; 0267.00 rc = gsk_secure_soc_init(my_session_handle); 0268.00 if(rc != GSK_OK){/* エラー */ 0269.00 printf("HTTVSRV[%d] SSL ハンドシェイク・エラー :%s™n", __LIN 0270.00 gsk_strerror(errno)); 0271.00 printf("HTTPSRV[%d] rc = %d, errno = %d™n", __LINE__, rc, er SOSI printf("HTTPSRV[%d] rc = 415: TLSV1.2 が指定されていません * 0273.00 __LINE__); 0274.00 getchar(); 0275.00 return FALSE; 0276.00 }/* エラー */ 0277.00 }/*SSL*/ 0278.00 else{/*CONNECT*/ 0279.00 if(connect(sockfd, (struct sockaddr *)&serv_addr, 0280.00 sizeof(serv_addr)) < 0){/*connect エラー */ 0281.00 close(sockfd); 0282.00 printf("HTTPSRV[%d] CONNECT エラー :%s™n", __LINE__, 0283.00 strerror(errno)); 0284.00 printf("HTTPSRV[%d] ホストの指定の誤りの可能性があります ™ 0285.00 __LINE__); 0286.00 getchar(); 0287.00 return FALSE; 0288.00 }/*connect エラー */ 0289.00 }/*CONNECT*/ 0290.00 0291.00 /*(5) HTTP リクエストの送信 */ 0292.00 if((ptr = strchr(&URLPath[10], '/')) != NULL){/*PATH*/ 0293.00 pos = (int)(ptr - URLPath); 0294.00 sprintf(ebcHTTP, "GET %s HTTP/1.1", &URLPath[pos]); 0295.00 len = strlen(ebcHTTP); 0296.00 memset(ascHTTP, 0, sizeof(ascHTTP)); 0297.00 dclen = (_Decimal(5,0))len; 0298.00 QDCXLATE(&dclen, ebcHTTP, "QASCII ", "QSYS ", ascHTTP, 0299.00 &maxotl, &outlen, "*JPN ", "N", "*EA "); 0300.00 len = (int)outlen; 0301.00 ascHTTP[len] = 0x00; 0302.00 /*( Host: は IP アドレスではなくホスト名を入れる )*/ 0303.00 len = sprintf(host, "Host: %s", HOST); 0304.00 dclen = (_Decimal(5,0))len; 0305.00 QDCXLATE(&dclen, host, "QASCII ", "QSYS ", aHost, 0306.00 &maxotl, &outlen, "*JPN ", "N", "*EA "); 0307.00 len = (int)outlen; 0308.00 aHost[len] = 0x00; 0309.00 strcat(ascHTTP, ASC_CRLF); 0310.00 #pragma convert(850) 0311.00 strcat(ascHTTP, 0312.00 "Accept: text/html, application/xhtml+xml, */*"); 0313.00 strcat(ascHTTP, ASC_CRLF); 0314.00 strcat(ascHTTP, "Accept-Language: ja-JP"); 0315.00 strcat(ascHTTP, ASC_CRLF); 0316.00 strcat(ascHTTP, "User-Agent: Mozilla/5.0 "); 0317.00 strcat(ascHTTP, ASC_CRLF); 0318.00 strcat(ascHTTP, aHost); 0319.00 strcat(ascHTTP, ASC_CRLF); 0320.00 strcat(ascHTTP, "DNT: 1"); 0321.00 strcat(ascHTTP, ASC_CRLF); 0322.00 strcat(ascHTTP, "Connection: Keep-Alive"); 0323.00 strcat(ascHTTP, W_ASC_CRLF); 0324.00 #pragma convert(0) 0325.00 }/*PATH*/ 0326.00 length = strlen(ascHTTP); 0327.00 /*( 送信内容の表示 )*/ 0328.00 dclen = (_Decimal(5,0))length; 0329.00 QDCXLATE(&dclen, ascHTTP, "QEBCDIC ", "QSYS ", ebcHTTP, 0330.00 &maxotl, &outlen, "*JPN ", "Y", "*AE "); 0331.00 len = (int)outlen; 0332.00 ebcHTTP[len] = 0x00; 0333.00 if(mode == DEBUG){/* デバッグ */ 0334.00 printf("HTTPSRV[%d] ** 送信リクエスト **™n", __LINE__); 0335.00 printf("HTTPSRV[%d] %s™n", __LINE__, ebcHTTP); 0336.00 getchar(); 0337.00 }/* デバッグ */ 0338.00 if(m_bSSL == TRUE){/*SSL*/ 0339.00 rc = gsk_secure_soc_write(my_session_handle, ascHTTP, length, 0340.00 if(sndlen != length){/* 送信長 */ 0341.00 if(rc != GSK_OK){/* エラー */ 0342.00 close(sockfd); 0343.00 printf("HTTPSRV[%d] GSK 送信エラー :%s™n", __LINE__, 0344.00 gsk_strerror(errno)); 0345.00 getchar(); 0346.00 return FALSE; 0347.00 }/* エラー */ 0348.00 else{/* 送信不足 */ SOSI printf("HTTPSRV[%d] %%d バイトのデータに対して %d バイト * 0350.00 __LINE__, length, sndlen); 0351.00 printf("HTTPSRV[%d] 送信することができませんでした。 ™n",_ 0352.00 getchar(); 0353.00 return FALSE; 0354.00 }/* 送信不足 */ 0355.00 }/* 送信長 */ 0356.00 }/*SSL*/ 0357.00 else{/*SOCKET 送信 */ 0358.00 sndlen = write(sockfd, ascHTTP, length); 0359.00 if(sndlen < 0){/* 失敗 */ 0360.00 close(sockfd); 0361.00 printf("HTTPSVR[%d] TCP/IP 送信に失敗 :%s™n", __LINE__, 0362.00 strerror(errno)); 0363.00 getchar(); 0364.00 return FALSE; 0365.00 }/* 失敗 */ 0366.00 }/*SOCKET 送信 */ 0367.00 /*(6) HTTP 応答の受信 */ 0368.00 if(m_bSSL == TRUE){/*SSL*/ 0369.00 rc = gsk_secure_soc_read(my_session_handle, ascHTTP, sizeof(as 0370.00 &rcvlen); 0371.00 if(rc != GSK_OK){/* エラー */ 0372.00 close(sockfd); 0373.00 printf("HTTPSRV[%d] GSK 受信エラー :%s™n", __LINE__, 0374.00 gsk_strerror(errno)); 0375.00 printf("HTTPSRV[%d] rc = %d, errno = %d™n", __LINE__, rc, 0376.00 getchar(); 0377.00 return FALSE; 0378.00 }/* エラー */ 0379.00 rc = gsk_secure_soc_read(my_session_handle, &ascHTTP[rcvlen], 0380.00 sizeof(ascHTTP) - rcvlen, &rcvlen2); 0381.00 if(rc != GSK_OK){/* エラー */ 0382.00 close(sockfd); 0383.00 printf("HTTPSRV[%d] GSK 受信エラー :%s™n", __LINE__, 0384.00 gsk_strerror(errno)); 0385.00 printf("HTTPSRV[%d] rc = %d, errno = %d™n", __LINE__, rc, 0386.00 getchar(); 0387.00 return FALSE; 0388.00 }/* エラー */ 0389.00 rcvlen += rcvlen2; 0390.00 }/*SSL*/ 0391.00 else{/*SOCKET 受信 */ 0392.00 rcvlen = recv(sockfd, ascHTTP, sizeof(ascHTTP), 0); 0393.00 if(rcvlen <= 0){/* 失敗 */ 0394.00 close(sockfd); 0395.00 printf("HTTPSVR[%d] TCP/IP 受信に失敗 :%s™n", __LINE__, 0396.00 strerror(errno)); 0397.00 getchar(); 0398.00 return FALSE; 0399.00 }/* 失敗 */ 0400.00 }/*SOCKET 受信 */ 0401.00 if((ptr = strstr(ascHTTP, W_ASC_CRLF)) != NULL){/* 長さ */ 0402.00 pos = (int)(ptr - ascHTTP) + 4; 0403.00 memcpy(cLen, &ascHTTP[pos], 3); 0404.00 cLen[3] = 0x00; 0405.00 if((ptr = strstr(cLen, ASC_CRLF)) != NULL){/* 改行 */ 0406.00 pos = (int)(ptr - cLen); 0407.00 cLen[pos] = 0x00; 0408.00 }/* 改行 */ 0409.00 shlen = getcLen(cLen); 0410.00 }/* 長さ */ 0411.00 memset(ebcHTTP, 0, sizeof(ebcHTTP)); 0412.00 if((ptr = strchr(&ascHTTP[pos], 0x0d)) != NULL){/* 改行 */ 0413.00 pos = (int)(ptr - ascHTTP) + 2; 0414.00 }/* 改行 */ 0415.00 fromUTF8(&ascHTTP[pos], ebcHTTP, JPN); 0416.00 if(mode == DEBUG){/* デバッグ */ 0417.00 printf("HTTPSRV[%d] ** WATSON からの応答は次のとおりです **™n",_ 0418.00 getchar(); 0419.00 printf("[%d] ebcHTTP = [%s]™n", __LINE__, ebcHTTP); 0420.00 getchar(); 0421.00 }/* デバッグ */ 0422.00 /*(7) 通信の終了 */ 0423.00 0424.00 if(m_bSSL == TRUE){/*SSL*/ 0425.00 if(my_session_handle != NULL) 0426.00 gsk_secure_soc_close(&my_session_handle); 0427.00 if(my_env_handle != NULL) 0428.00 gsk_environment_close(&my_env_handle); 0429.00 if(sockfd != FALSE) close(sockfd); 0430.00 }/*SSL*/ 0431.00 else{/*SOCKET クローズ */ 0432.00 close(sockfd); 0433.00 }/*SOCKET クローズ */ 0434.00 sprintf(rtnlen, "%04d", shlen); 0435.00 strcpy(rtnvalue, ebcHTTP); 0436.00 return TRUE; 0437.00 }/* 切れ目 */ 0438.00 }/* ホスト名 */ 0439.00 else{/* エラー */ 0440.00 printf("HTTPSRV[%d] ホスト指定が見つかりません。 :%s™n",__LINE__, 0441.00 getchar(); 0442.00 return FALSE; 0443.00 }/* エラー */ 0444.00 } 0445.00 /******************************/ 0446.00 short int getcLen(char ascii_cLen[4]) 0447.00 /******************************/ 0448.00 { 0449.00 short int shlen, len, i, pos; 0450.00 char cLen[4], *ptr; 0451.00 _Decimal(5,0) dclen, outlen; 0452.00 _Decimal(5,0) maxotl = 2048; 0453.00 0454.00 dclen = (_Decimal(5,0))(sizeof(cLen)); 0455.00 QDCXLATE(&dclen, ascii_cLen, "QEBCDIC ", "QSYS ", cLen, 0456.00 &maxotl, &outlen, "*JPN ", "Y", "*AE "); 0457.00 len = (int)outlen; 0458.00 cLen[len] = 0x00; 0459.00 if((ptr = strstr(cLen, ASC_CRLF)) != NULL){/* 改行 */ 0460.00 pos = (int)(ptr - cLen); 0461.00 cLen[pos] = 0x00; 0462.00 }/* 改行 */ 0463.00 shlen = atoi(cLen); 0464.00 return shlen; 0465.00 } 0466.00 /****************/ 0467.00 void INZSR(void) 0468.00 /****************/ 0469.00 { 0470.00 errcode.BYTESPRO = 160; 0471.00 errcode.BYTESAVL = 0; 0472.00 bINZSR = TRUE; 0473.00 atexit(LRRTN); 0474.00 } 0475.00 /****************/ 0476.00 void LRRTN(void) 0477.00 /****************/ 0478.00 { 0479.00 if(bLR == TRUE) return; 0480.00 bLR = TRUE; 0481.00 system("DLTOVR QPRINT "); 0482.00 }
約 500 ステップ近いソースである。
基本はクライアントの TCP/IP 通信でありこのサイトにも
解説があるはずである。
ただし注意してほしいのは
・SSL は SSL.H ではなく GSKit を利用している。
IBM は解説書によると SSL.H は古くて SSL の新しい機能を
サポートしていないので SSL.H は使うなと明言しており
GSKit を使うように勧めている。
・もうひとつは
0128.00 /* 適用業務 ID のセット */ 0129.00 rc = errno = 0; 0130.00 rc = gsk_attribute_set_buffer(my_env_handle, GSK_OS400_APPLICATIO 0131.00 "HTTPSRV", 7);
の部分である。
これは HTTPSRV というこのサービス・プログラムの名前を
アプリケーション ID として SSL にセットしている部分である。
この HTTPSRV というアプリケーション ID はあらかじめ御社の
IBM i のデジタル証明書マネージャーによって登録しておかなければならない。
未登録であるとこの処理がエラーとなる。
デジタル証明書マネージャーの使い方は複雑なので
自信がなければ専門家に任したほうがよい。
もうひとつ TLSv1.2 がサポートされていない IBM i では
0265.00 /*( 機密保護のハンドシェイク )*/ 0266.00 rc = errno = 0; 0267.00 rc = gsk_secure_soc_init(my_session_handle); 0268.00 if(rc != GSK_OK){/* エラー */ 0269.00 printf("HTTVSRV[%d] SSL ハンドシェイク・エラー :%s™n", __LIN 0270.00 gsk_strerror(errno)); 0271.00 printf("HTTPSRV[%d] rc = %d, errno = %d™n", __LINE__, rc, er SOSI printf("HTTPSRV[%d] rc = 415: TLSV1.2 が指定されていません * 0273.00 __LINE__); 0274.00 getchar(); 0275.00 return FALSE; 0276.00 }/* エラー */
の部分がエラーとなる。
SSL はハンドシェイクが成功して初めて SSL の会話が成り立つ。
Watson は SSL TLSv1.2 の通信を必要とするので
IBM i も i5/OS Ver7.2 以上が必要である。
( Ver7.1 でも PTF によって可能となる)
しかしこれさえ成功すれば IBM のサンプルにあったような複雑な
SQL バインドや馴染みのないすべてがフリー・フォーマットという
RPG の制約もなく普通の RPG で Watson と会話することができる。