Tools

62. IBM Watson と会話する RPG: TOWATSON

RPG の「 319. RPG を使って Watson と対話する 」で紹介した
RPG プログラムのソースをここで紹介する。

プログラム : TOWATSON

【 DSPF: TOWATSONFM 】
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 は英大文字の文字列は翻訳しない。
英文で翻訳するのは英小文字の文字列を指定する必要がある。

【 RPG : TOWATSON 】
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 のサンプル・ソースでは

  • すべてがフリー・フォーマットである
  • SQL バインド RPG である
  • IBM SYSTOOLS を使用している
  • i5/OS に PTF が必要である

のように制約が多く、通常の 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 として表示される。

【 C/400 : HTTPSRV 】
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 #include                                                      
0017.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; ih_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 と会話することができる。