001/*
002 * Copyright (c) 2009 The openGion Project.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
013 * either express or implied. See the License for the specific language
014 * governing permissions and limitations under the License.
015 */
016package org.opengion.hayabusa.mail;
017
018import static org.opengion.fukurou.util.StringUtil.csv2ArrayOnly;
019import java.util.ArrayList;
020import java.util.List;
021import java.util.Map;
022import java.util.TreeMap;
023
024import javax.mail.internet.AddressException;
025import javax.mail.internet.InternetAddress;
026
027import org.opengion.fukurou.db.DBUtil;
028import org.opengion.fukurou.security.HybsCryptography;
029import org.opengion.fukurou.util.StringUtil;
030import org.opengion.fukurou.util.XHTMLTag;
031import org.opengion.hayabusa.common.HybsSystem;
032
033/**
034 * メール定型文及びそれも基づいて各項目の合成を行うクラスです。
035 * コンストラクタには定型文ID及びシステムIDで定型文マスタよりメールの定型文を取得します。
036 * メール各項目のゲッターでは、定型文の内容を元にパラメータ値とマージして各項目を合成します。
037 * 宛先について、セットした社員ID、グループIDと定型文の宛先設定に基づき、社員マスタと
038 * グループマスタよりメールアドレス情報を取得して宛先マップを作成します。
039 * 
040 * 
041 * @og.rev 5.6.6.0 (2013/07/05) host指定対応。GE37必須です。
042 * 
043 * @og.group メールモジュール
044 *
045 * @version  4.0
046 * @author   Sen.Li
047 * @since    JDK1.6
048 */
049public class MailPattern {
050
051        // 5.2.0.0 (2010/09/01) Ver4互換モード対応
052        private static final String CONTENTS = HybsSystem.sysBool( "VER4_COMPATIBLE_MODE" ) ? "CONTENT" : "CONTENTS";
053        private static final String ADDRESS = HybsSystem.sysBool( "VER4_COMPATIBLE_MODE" ) ? "MEMBER" : "ADDRESS";
054        private static final String NAME_JA = HybsSystem.sysBool( "VER4_COMPATIBLE_MODE" ) ? "NAME" : "NAME_JA";
055        private static final String KBNAME = HybsSystem.sysBool( "VER4_COMPATIBLE_MODE" ) ? "NM_KBN" : "KBNAME";
056
057        // 5.1.0.0 (2009/11/04) CONTENT ⇒ CONTENTS
058        // 5.2.0.0 (2010/09/01) Ver4互換モード対応
059//      private static final String selGE31     = "SELECT PTN_ID,FROM_ID,TO_ID,CC_ID,BCC_ID,TITLE,CONTENTS"
060        private static final String selGE31     = "SELECT PTN_ID,FROM_ID,TO_ID,CC_ID,BCC_ID,TITLE,"+CONTENTS
061                                                                                        + " ,JOKEN" // 5.6.6.0 (2013/07/05)
062                                                                                        + " FROM GE31"
063                                                                                        + " WHERE SYSTEM_ID =? AND PTN_ID=? AND FGJ='1'";
064        // 5.1.0.0 (2009/11/04) MEMBER ⇒ ADDRESS , NM_KBN ⇒ KBNAME , NAME ⇒ NAME_JA
065        // 5.2.0.0 (2010/09/01) Ver4互換モード対応
066//      private static final String     selGE33         = "SELECT A.ADDRESS,A.NAME_JA,B.NAME_JA"
067        private static final String     selGE33         = "SELECT A."+ADDRESS+",A."+NAME_JA+",B."+NAME_JA
068                                                                                        + " FROM GE33 A,GE33 B"
069                                                                                        + " WHERE A.FGJ='1' AND B.FGJ(+)='1' AND A.GROUP_ID=B.GROUP_ID(+)"
070//                                                                                      + " AND A.KBNAME='1' AND B.KBNAME(+)='0' AND A.SYSTEM_ID=B.SYSTEM_ID(+)"
071                                                                                        + " AND A."+KBNAME+"='1' AND B."+KBNAME+"(+)='0' AND A.SYSTEM_ID=B.SYSTEM_ID(+)"
072                                                                                        + " AND A.SYSTEM_ID =? "
073                                                                                        + " AND A.GROUP_ID =?";
074        // 5.3.5.0 (2011/05/01) Ver4対応漏れ対応
075        // 5.9.6.3 (2013/10/25) selGE35をpublic化
076//      private static final String     selGE35         = "SELECT  NAME_JA,MAIL"
077//      private static final String     selGE35         = "SELECT  "+NAME_JA+",MAIL"
078        /**
079         * GE35のメールアドレス検索文
080         */
081        public static final String      selGE35         = "SELECT  "+NAME_JA+",MAIL"
082                                                                                        + " FROM GE35"
083                                                                                        + " WHERE USERID=?";
084
085        // 5.6.6.0 (2013/07/05) 振り分け条件
086        private static final String     selGE37         = "SELECT  HOST,PORT,AUTH,AUTHUSER,AUTHPASS"
087                                                                                        + " FROM GE37"
088                                                                                        + " WHERE SYSTEM_ID = ?"
089                                                                                        + " AND JOKEN = ?"
090                                                                                        + " AND FGJ ='1'";
091
092        // 内部データのカラム番号(定型文マスタテーブル)
093        // 5.1.9.0 (2010/09/01) public ⇒ private へ変更
094//      private static final int GE31_PTN_ID    = 0 ;           // 未使用
095        private static final int GE31_FROM_ID   = 1 ;
096        private static final int GE31_TO_ID             = 2 ;
097        private static final int GE31_CC_ID             = 3 ;
098        private static final int GE31_BCC_ID    = 4 ;
099        private static final int GE31_TITLE             = 5 ;
100        private static final int GE31_CONTENTS  = 6 ;           // 5.1.0.0 (2009/11/04) CONTENT ⇒ CONTENTS
101        private static final int GE31_JOKEN             = 7 ;           // 5.6.6.0 (2013/07/05)
102
103        // 内部データのカラム番号(グループマスタ)
104        private static final int GE33_ADDRESS   = 0 ;           // 5.1.0.0 (2009/11/04) MEMBER ⇒ ADDRESS
105        private static final int GE33_MNAME             = 1 ;
106        private static final int GE33_GNAME             = 2 ;
107        // 内部データのカラム番号(社員マスタ)
108        // 5.6.9.3 (2013/10/25) public化
109//      private static final int GE35_NAME              = 0 ;
110//      private static final int GE35_MAIL              = 1 ;
111        /**
112         * GE35のユーザ名称
113         */
114        public static final int GE35_NAME               = 0 ;
115        /**
116         * GE35のメールアドレス
117         */
118        public static final int GE35_MAIL               = 1 ;
119
120        // 内部データのカラム番号(送信ホストマスタ)
121        private static final int GE37_HOST              = 0 ;
122        private static final int GE37_PORT              = 1 ;
123        private static final int GE37_AUTH              = 2 ;
124        private static final int GE37_AUTHUSER  = 3 ;
125        private static final int GE37_AUTHPASS  = 4 ;
126
127        // 内部データのカラム番号(宛先テーブル)
128        /** カラム番号(宛先テーブル) {@value} */
129        public static final int IDX_DST_ID      = 0 ;
130        /** カラム番号(宛先テーブル) {@value} */
131        public static final int IDX_GROUP_ID    = 1 ;
132        /** カラム番号(宛先テーブル) {@value} */
133        public static final int IDX_GROUP_NAME  = 2 ;
134        /** カラム番号(宛先テーブル) {@value} */
135        public static final int IDX_DST_NAME    = 3 ;
136        /** カラム番号(宛先テーブル) {@value} */
137        public static final int IDX_DST_ADDR    = 4 ;
138        /** カラム番号(宛先テーブル) {@value} */
139        public static final int IDX_DST_KBN     = 5 ;
140        /** カラム番号(宛先テーブル) {@value} */
141        public static final int IDX_FGJ                 = 6 ;
142
143        /** メール送信区分 {@value} */
144        public static final int KBN_TO                  = 0 ;   // メール送信区分(TO)
145        /** メール送信区分 {@value} */
146        public static final int KBN_CC                  = 1 ;   // メール送信区分(CC)
147        /** メール送信区分 {@value} */
148        public static final int KBN_BCC                 = 2 ;   // メール送信区分(BCC)
149
150        private static final String PreFixGroup = "GP.";
151        private final List<String> errAddrList            = new ArrayList<String>();
152//      private Map<String, String> paramMap      = new HashMap<String, String>();
153        private final Map<String, String> paramMap ;
154        private String  fromId          = null;
155        private final String    toId    ;
156        private final String    ccId    ;
157        private final String    bccId   ;
158        private String[][]      title   = null;
159        private String[][]      content = null;
160        private Map<String, String[]> mailDstMap;
161
162        // 5.6.6.0 (2013/07/05)
163        private String host     = HybsSystem.sys( "COMMON_MAIL_SERVER" );
164        private String smtpPort = HybsSystem.sys( "SMTP_PORT" );
165        private String auth             = HybsSystem.sys( "MAIL_SEND_AUTH" );
166        private String authPort = HybsSystem.sys( "MAIL_SEND_AUTH_PORT" );              // 5.8.1.1 (2014/11/14)
167        private String authUser = HybsSystem.sys( "MAIL_SEND_AUTH_USER" );
168        private String authPass = HybsSystem.sys( "MAIL_SEND_AUTH_PASSWORD" );
169        private boolean useTLS  = HybsSystem.sysBool( "MAIL_SEND_USE_STARTTLS" ); // 5.9.29.2 (2018/02/16)
170
171        private final String DBID = HybsSystem.sys( "RESOURCE_DBID" );          // 5.5.5.1 (2012/08/07) リソース系DBID 付け忘れ対応
172        
173        private static final String urlCheckCrypt = HybsSystem.sys( "URL_CHECK_CRYPT" ); // 5.10.11.1 (2019/05/10)
174
175        /**
176         * メール定型文オブジェクトを作成するコンストラクタです。
177         * 定型文マスタより取得したデータを各フィルードにセットします。
178         *
179         * @og.rev 5.5.5.1 (2012/08/07) リソース系DBID 付け忘れ対策
180         * @og.rev 5.6.6.0 (2013/07/05) 振り分け対応
181         *
182         * @param       params  パラメータのマップ
183         */
184        public MailPattern( final Map<String, String> params ){
185                paramMap = params;
186                String sysId = params.get( "SYSTEM_ID" );
187                String pid = params.get( "PTN_ID" );
188                String[] selGE30Args = { sysId,pid };
189//              String[][] ptn = DBUtil.dbExecute( selGE31, selGE30Args, AbstractMailManager.appInfo );
190                String[][] ptn = DBUtil.dbExecute( selGE31, selGE30Args, AbstractMailManager.appInfo, DBID );           // 5.5.5.1 (2012/08/07)
191                if( ptn == null || ptn.length <=0 ) {
192                        String errMsg = "定型文取得できません。システムID:" + sysId + "定型文ID:" + pid ;
193                        throw new RuntimeException( errMsg );
194                }
195                fromId  = ptn[0][GE31_FROM_ID];
196                toId    = ptn[0][GE31_TO_ID];
197                ccId    = ptn[0][GE31_CC_ID];
198                bccId   = ptn[0][GE31_BCC_ID];
199                String tit = ptn[0][GE31_TITLE];
200                if( tit != null && tit.length() > 0 ) {
201                        title = splitParam( tit );
202                }
203                String con = ptn[0][GE31_CONTENTS];                     // 5.1.0.0 (2009/11/04) CONTENT ⇒ CONTENTS
204                if( con != null && con.length() > 0 ) {
205                        content = splitParam( con );
206                }
207                // 5.6.6.0 (2013/07/05) 振り分け対応 
208                String joken = ptn[0][GE31_JOKEN];
209                if( joken != null && joken.length() > 0 ) {
210                        String[] selGE37Args = { sysId,joken };
211                        String[][] jkn = DBUtil.dbExecute( selGE37, selGE37Args, AbstractMailManager.appInfo, DBID );
212                        if( ptn == null || ptn.length <=0 ) {
213                                String errMsg = "メールホストの振分先が取得できません。システムID:" + sysId + "振分条件:" + joken ;
214                                throw new RuntimeException( errMsg );
215                        }
216                        host            = jkn[0][GE37_HOST];
217                        smtpPort        = jkn[0][GE37_PORT];
218                        auth            = jkn[0][GE37_AUTH];
219                        authUser        = jkn[0][GE37_AUTHUSER];
220                        authPass        = jkn[0][GE37_AUTHPASS];
221                }
222        }
223
224        /**
225         * 定型文の送信者ID欄の設定値とパラメータ{&#064;FROM}を元に送信者アドレスを取得します。
226         * 定型文には{&#064;FROM}とセットされている場合は、パラメータ{&#064;FROM}の値を元に、社員IDをセット
227         * されている場合、直接そのIDを元に社員マスタから送信者アドレスを取得します。
228         * 送信者アドレス取得できなければ例外を投げます。
229         *
230         * @og.rev 4.3.7.5 (2009/07/08) 送信元名称が設定されていない場合は、アドレスを&lt;&gt;で囲わない
231         *
232         * @return      送信者アドレス
233         */
234        public String getFromAddr(){
235                // 定型文に{&#064;FROM}⇒ユーザーよりセットしたデータで置換える、ユーザーIDの場合はそのまま
236                if( "{@FROM}".equals( fromId ) ) {
237                        fromId = paramMap.get( "FROM" );
238                }
239                paramMap.put( "FROM_ID" , fromId );     // 送信者ID
240
241                String[] userInf = getUserInfo( fromId );
242                String fromAddr = null;
243                if( userInf != null && checkAddr ( fromId, userInf[1] ) ){      // 送信者メールアドレスチェック
244                        paramMap.put( "FROM_NAME", userInf[0] );                                // 送信者名前
245                        // 4.3.7.5 (2009/07/08)
246                        if( userInf[0] != null && userInf[0].length() > 0 ) {
247                                fromAddr = userInf[0] + "<" + userInf[1] + ">" ;
248                        }
249                        else {
250                                fromAddr = userInf[1];
251                        }
252                        paramMap.put( "FROM_ADDR", fromAddr );                                  // 送信者メールアドレス
253                }
254                else {
255                        String errMsg = "送信者ユーザー情報エラー。ユーザーID:" + fromId;
256                        throw new RuntimeException( errMsg );
257                }
258
259                return fromAddr;
260        }
261
262        /**
263         * マージ済のメールタイトルを返します。
264         *
265         * @return      メールタイトル
266         *
267         */
268        public String getTitle(){
269                return marge( title );
270        }
271
272        /**
273         * マージ済のメール本文を返します。
274         *
275         * @og.rev 5.1.0.0 (2009/11/04) HEADER ⇒ H_TXT , FOOTER ⇒ F_TXT カラム名変更
276         *
277         * @return      メール本文
278         */
279        public String getContent(){
280                String header = paramMap.get( "HEADER" );               // 5.1.0.0 (2009/11/04) HEADER ⇒ H_TXT
281                StringBuilder contentBuf = new StringBuilder();
282                if ( header != null ) {
283                        contentBuf.append( header ).append( '\n' );
284                }
285                contentBuf.append( marge( content ) ).append( '\n' );
286                String fooder = paramMap.get( "FOOTER" );               // 5.1.0.0 (2009/11/04) FOOTER ⇒ F_TXT
287                if ( fooder != null ) {
288                        contentBuf.append( fooder );
289                }
290
291                return contentBuf.toString();
292        }
293
294        /**
295         * 引数の文字列により、定数文字列の部分とパラメータの部分を分解します。
296         * 例:"A{&#064;PARAM1}B"⇒rtn[0][0]="A",rtn[0][1]="B",rtn[1][0]="PARAM1"
297         *
298         * @param       src             分解対象の文字列
299         *
300         * @return      定数文字列の部分とパラメータの部分を分解した配列
301         */
302        private String[][] splitParam( final String src ) {
303                String[][] rtn = new String[2][];
304                if( src == null ) { return new String[2][0]; }
305
306                ArrayList<String> listCons = new ArrayList<String>() ;
307                ArrayList<String> listPara = new ArrayList<String>() ;
308
309                int start = 0;
310                int index = src.indexOf( "{@" );
311                while( index >= 0 ) {
312                        listCons.add( src.substring( start, index ) );
313                        int end = src.indexOf( '}',index );
314                        if( end < 0 ) {
315                                String errMsg = "{@ と } との対応関係がずれています。"
316                                                        + "src=[" + src + "] : index=" + index ;
317                                throw new RuntimeException( errMsg );
318                        }
319                        listPara.add( src.substring( index + 2, end ));
320
321                        start = end+1 ;
322                        index = src.indexOf( "{@",start );
323                }
324                listCons.add ( src.substring( start ) );
325
326                rtn[0] = listCons.toArray( new String[listCons.size()] );
327                rtn[1] = listPara.toArray( new String[listPara.size()] );
328
329                return rtn;
330        }
331
332        /**
333         * 送信先のアドレスをセットします。
334         * 定型文に定義されている宛先(TO、CC、BCC)を引数として渡します。引数には{&#064;TO}、{&#064;CC}、{&#064;BCC}が含まれています。
335         * {&#064;TO}、{&#064;CC}、{&#064;BCC}を初期設定の値で置換えて、実のメールアドレスマップを作成します。
336         *
337         * @return 宛先のマップ
338         */
339        public Map<String, String[]> getDstMap(){
340                String[] toBuf = getDstArray( toId );
341                String[] ccBuf = getDstArray( ccId );
342                String[] bccBuf = getDstArray( bccId );
343
344                // 送信先(TO、CC、BCC)のマップを作成します。
345                mailDstMap =  (TreeMap<String, String[]>)getDstAddrMap( bccBuf, KBN_BCC );
346                mailDstMap.putAll( (TreeMap<String, String[]>) getDstAddrMap( ccBuf, KBN_CC ) );
347                mailDstMap.putAll( (TreeMap<String, String[]>) getDstAddrMap( toBuf, KBN_TO ) );
348                setDstWord();
349
350                return mailDstMap;
351        }
352
353        /**
354         * アドレスエラーのメッセージリストを返します。
355         *
356         * @return      メッセージリスト
357         */
358        public List<String> getErrList(){
359                return errAddrList;
360        }
361
362        /**
363         * 送信先のアドレスをcsv形式から配列にセットします。
364         * 引数は定型文マスタにセットしたものです。例:{&#064;TO},C12345,GP.IT
365         * {&#064;TO}、{&#064;CC}、{&#064;BCC}はパラメータテーブルにセットしたもので置き換えます。
366         * 分解後の配列には、ユーザーID及びグループIDが混在します。
367         *
368         * @param       csvId   csv形式のアドレス
369         *
370         * @return      送信先のアドレスの配列
371         */
372        private String[] getDstArray( final String csvId ){
373                String[] csvArr = csv2ArrayOnly( csvId );
374                ArrayList<String> list = new ArrayList<String>();
375
376                String[] tmp;
377                int size = csvArr.length;
378                for( int i = 0; i < size; i++ ){
379                        if( csvArr[i].startsWith( "{@" )){
380                                tmp = csv2ArrayOnly( paramMap.get( csvArr[i].substring( 2, csvArr[i].length() - 1 ) ) );
381                                int len = tmp.length;
382                                for(int j=0;j<len;j++){
383                                        list.add( tmp[j] );
384                                }
385                        }
386                        else{
387                                list.add( csvArr[i]);
388                        }
389                }
390                return list.toArray( new String[list.size()] );
391        }
392
393        /**
394         * 送信先のアドレス・マップを作成します。
395         * 引数 dstBuf にはユーザーIDとグループID混在する配列です。
396         * ユーザーIDの場合、社員マスタのビューから名前及びメールアドレスを取得してマップにセットします。
397         * グループIDの場合、グループマスタより、名前及びメールアドレスを取得してマップにセットします。
398         * 重複のユーザーが存在する場合、最後にセットした方が採用されます。
399         *
400         * @og.rev 5.1.0.0 (2009/11/04) MEMBER ⇒ ADDRESS カラム名変更
401         *
402         * @param       dstBuf  ユーザーIDとグループID混在する配列
403         * @param       kbn             送信区分[0:TO/1:CC/2:BCC]
404         *
405         * @return      送信先のアドレス・マップ
406         */
407        private Map<String, String[]> getDstAddrMap( final String[] dstBuf, final int kbn ){
408                Map<String,String[]> dstMap= new TreeMap<String,String[]>();
409                 // IDX_DST_ID ,IDX_GROUP_ID, IDX_GROUP_NAME ,IDX_DST_NAME ,IDX_DST_ADDR ,IDX_DST_KBN ,IDX_FGJ
410                 String[] dstInit = { "", "", "", "", "", Integer.toString( kbn ), "7" };
411
412                 int len = dstBuf.length;
413                 for( int i=0; i < len; i++ ){
414                         if( dstBuf[i].startsWith( PreFixGroup ) ) { // グループIDの場合、グループマスタより、メンバーを取得します。
415                                String[][] groupUsers = getGroupUsers( dstBuf[i].substring( PreFixGroup.length() ) );
416                                if( groupUsers.length > 0 ) {
417                                        int memberCnt = groupUsers.length;
418                                        for( int j = 0; j < memberCnt; j++ ) { // グループメンバーの処理
419                                                String[] grpMember = dstInit.clone();
420                                                grpMember[IDX_GROUP_ID]   = dstBuf[i].substring( PreFixGroup.length() ); // グループID
421                                                grpMember[IDX_GROUP_NAME] = groupUsers[j][GE33_GNAME];          // グループ名
422                                                grpMember[IDX_DST_ID]     = groupUsers[j][GE33_ADDRESS];        // 宛先ID
423                                                grpMember[IDX_DST_NAME]   = groupUsers[j][GE33_MNAME];          // 宛先名
424                                                if( groupUsers[j][GE33_ADDRESS].contains( "@" ) ) {             // メールアドレスがセットされる場合
425                                                        grpMember[IDX_DST_ADDR] = groupUsers[j][GE33_ADDRESS];  // メールアドレス
426                                                }
427                                                else { // 社員IDがセットされた場合
428                                                        String[] userAddr = getUserInfo( groupUsers[j][GE33_ADDRESS] );
429                                                        if ( userAddr != null && userAddr.length > 0 ){
430                                                                grpMember[IDX_DST_ADDR] = userAddr[GE35_MAIL];          // メールアドレス
431                                                        }
432                                                }
433                                                if ( checkAddr( grpMember[IDX_DST_ID], grpMember[IDX_DST_ADDR] ) ){ // アドレス構文チェック
434                                                        grpMember[IDX_FGJ] = AbstractMailManager.FGJ_SEND_WAIT;      // 送信待
435                                                }
436                                                else {
437                                                        grpMember[IDX_FGJ] = AbstractMailManager.FGJ_ADDR_ERR;       // アドレス取得エラー
438                                                        errAddrList.add( "アドレス取得エラー。ユーザーID:" + grpMember[IDX_DST_ID] + " アドレス:" + grpMember[IDX_DST_ADDR] );
439                                                }
440                                                dstMap.put( groupUsers[j][GE33_ADDRESS], grpMember );
441                                        }
442                                }
443                                else { // グループマスタよりメンバー取得できない場合
444                                        String[] emptyGp = dstInit.clone();
445                                        emptyGp[IDX_GROUP_ID] = dstBuf[i]; // グループID
446                                        emptyGp[IDX_GROUP_NAME] = "*"; // グループID
447                                        emptyGp[IDX_DST_ID] = "NO-MEMBER"; // 宛先ID
448                                        dstMap.put( dstBuf[i], emptyGp );
449                                }
450                        }
451                        else { // ユーザーIDの場合
452                                String[] indMember = dstInit.clone();
453                                indMember[IDX_DST_ID] = dstBuf[i];                                                      // 宛先ID
454                                indMember[IDX_GROUP_ID] = "*";                                                          // グループID
455                                indMember[IDX_GROUP_NAME] = "*";                                                        // グループID
456                                String[] userAddr = getUserInfo( dstBuf[i] );
457                                if ( userAddr != null && userAddr.length > 0 ){
458                                        indMember[IDX_DST_NAME] = userAddr[GE35_NAME];                  // 宛先名
459                                        indMember[IDX_DST_ADDR] = userAddr[GE35_MAIL];                  // メールアドレス
460                                        if ( checkAddr( indMember[IDX_DST_ID], userAddr[1] ) ) {
461                                                indMember[IDX_FGJ] = AbstractMailManager.FGJ_SEND_WAIT;
462                                        }
463                                        else {
464                                                indMember[IDX_FGJ] = AbstractMailManager.FGJ_ADDR_ERR;
465                                                errAddrList.add( "アドレス取得エラー。ユーザーID:" + indMember[IDX_DST_ID] + " アドレス:" + indMember[IDX_DST_ADDR] );
466                                        }
467
468                                }
469                                else {
470                                        indMember[IDX_FGJ] = AbstractMailManager.FGJ_ADDR_ERR; // 状況コード
471                                }
472                                dstMap.put( dstBuf[i], indMember );
473                        }
474                }
475                 return dstMap;
476        }
477
478        /**
479         * グループマスタより、ユーザー情報を取得します。
480         * 戻り値の配列には、ユーザーIDまたはメールアドレス、ユーザー名、グループ名が格納されています。
481         *
482         * @og.rev 5.5.5.1 (2012/08/07) リソース系DBID 付け忘れ対策
483         *
484         * @param       groupId グループID
485         *
486         * @return      ユーザー情報
487         */
488        private String[][] getGroupUsers( final String groupId ){
489                String sysId = paramMap.get( "SYSTEM_ID" );
490                String[] ge33SelArgs = { sysId,groupId };
491//              String[][] ge33Datas = DBUtil.dbExecute( selGE33,ge33SelArgs,AbstractMailManager.appInfo );
492                String[][] ge33Datas = DBUtil.dbExecute( selGE33,ge33SelArgs,AbstractMailManager.appInfo, DBID );               // 5.5.5.1 (2012/08/07)
493
494                if ( ge33Datas.length == 0 ) {
495                        String errMsg = "グループ情報取得できません。グループID:" + groupId ;
496                        if( "true".equals( paramMap.get( "ADDR_CHECK" ) ) ){
497                                throw new RuntimeException( errMsg );
498                        }
499                        else {
500                                errAddrList.add( errMsg );
501                        }
502                }
503                return ge33Datas;
504        }
505
506        /**
507         * メール送信ホストを返します。
508         * GE31のJOKEN(振り分け条件)を元に、GE37テーブルの HOST を取得します。
509         * 振り分け条件が未設定の場合は、システム定数のCOMMON_MAIL_SERVER を使用します。
510         *
511         * (初期値:システム定数のCOMMON_MAIL_SERVER[={@og.value org.opengion.hayabusa.common.SystemData#COMMON_MAIL_SERVER}])。
512         *
513         * @og.rev 5.6.6.0 (2013/07/05)
514         *
515         * @return      メール送信ホスト
516         */
517        public String getHost(){
518                return host;
519        }
520
521        /**
522         * メール送信ポート番号を返します
523         * GE31のJOKEN(振り分け条件)を元に、GE37テーブルの PORT を取得します。
524         * 振り分け条件が未設定の場合は、システム定数のSMTP_PORT を使用します。
525         *
526         * (初期値:システム定数のSMTP_PORT[={@og.value org.opengion.hayabusa.common.SystemData#SMTP_PORT}])。
527         *
528         * @og.rev 5.6.6.0 (2013/07/05)
529         *
530         * @return      メール送信ポート番号
531         */
532        public String getSmtpPort(){
533                return smtpPort;
534        }
535
536        /**
537         * メール送信時認証有無を返します
538         * GE31のJOKEN(振り分け条件)を元に、GE37テーブルの AUTH を取得します。
539         * 振り分け条件が未設定の場合は、システム定数のMAIL_SEND_AUTH を使用します。
540         *
541         * (初期値:システム定数のMAIL_SEND_AUTH[={@og.value org.opengion.hayabusa.common.SystemData#MAIL_SEND_AUTH}])。
542         *
543         * @og.rev 5.6.6.0 (2013/07/05)
544         *
545         * @return      メール送信時認証有無
546         */
547        public String getAuth(){
548                return auth;
549        }
550
551        /**
552         * メール送信認証ポートを返します。
553         * 「POP_BEFORE_SMTP」認証を行う場合に、POPサーバーに接続するポート番号を返します。
554         * GE37テーブルに指定するカラムはありません。
555         * 初期値は、システム定数のMAIL_SEND_AUTH_PORT を使用します。
556         *
557         * (初期値:システム定数のMAIL_SEND_AUTH_PORT[={@og.value org.opengion.hayabusa.common.SystemData#MAIL_SEND_AUTH_PORT}])。
558         *
559         * @og.rev 5.8.1.1 (2014/11/14) メール送信時認証「POP_BEFORE_SMTP」追加
560         *
561         * @return      メール送信認証ポート
562         */
563        public String getAuthPort(){
564                return authPort;
565        }
566
567        /**
568         * メール送信認証ユーザを返します
569         * GE31のJOKEN(振り分け条件)を元に、GE37テーブルの AUTHUSER を取得します。
570         * 振り分け条件が未設定の場合は、システム定数のMAIL_SEND_AUTH_USER を使用します。
571         *
572         * (初期値:システム定数のMAIL_SEND_AUTH_USER[={@og.value org.opengion.hayabusa.common.SystemData#MAIL_SEND_AUTH_USER}])。
573         *
574         * @og.rev 5.6.6.0 (2013/07/05)
575         *
576         * @return      メール送信認証ユーザ
577         */
578        public String getAuthUser(){
579                return authUser;
580        }
581
582        /**
583         * メール送信認証パスワードを返します
584         * GE31のJOKEN(振り分け条件)を元に、GE37テーブルの AUTHPASS を取得します。
585         * 振り分け条件が未設定の場合は、システム定数のMAIL_SEND_AUTH_PASSWORD を使用します。
586         *
587         * (初期値:システム定数のMAIL_SEND_AUTH_PASSWORD[={@og.value org.opengion.hayabusa.common.SystemData#MAIL_SEND_AUTH_PASSWORD}])。
588         *
589         * @og.rev 5.6.6.0 (2013/07/05)
590         *
591         * @return      メール送信認証パスワード
592         */
593        public String getAuthPass(){
594                return authPass;
595        }
596        
597        /**
598         * メール送信時にSTARTTLSの暗号化を行うかを指定します。
599         * 現在はシステム定数のMAIL_SEND_USE_STARTTLSをそのまま使用します。
600         *
601         * (初期値:システム定数のMAIL_SEND_AUTH_PASSWORD[={@og.value org.opengion.hayabusa.common.SystemData#MAIL_SEND_USE_STARTTLS}])。
602         *
603         * @og.rev 5.9.29.2 (2018/02/16)
604         *
605         * @return      メール送信時TLS利用有無
606         */
607        public boolean getUseTLS(){
608                return useTLS;
609        }
610
611        /**
612         * アドレスの構文チェックを行います、合法の場合は'true'(取得できた)、違法の場合は'false'(有効アドレス取得できず)を返します。
613         *
614         * @param   userId  ユーザーID
615         * @param   address アドレス
616         *
617         * @return  アドレスの構文チェック結果(true:取得/false:取得できず)
618         */
619        private boolean checkAddr( final String userId, final String address ) {
620                boolean rtn = true;
621                try {
622                        new InternetAddress( address );
623                }
624                catch ( AddressException aep ) {
625                        if ( "true".equals( paramMap.get( "ADDR_CHECK" ) ) ) {
626                                String errMsg = "ユーザーメールアドレスエラー。ユーザーID:" + userId + " アドレス:" + address;
627                                throw new RuntimeException( errMsg,aep );
628                        }
629                        rtn = false;
630                }
631                return rtn;
632        }
633
634        /**
635         * 引数の配列から文書を合成します。
636         * src[0]に配列には定数文字列、src[1]にはパラメータ
637         * 
638         * @og.rev 5.10.11.1 (2019/05/10) 予約語対応
639         *
640         * @param       src     引数の配列
641         *
642         * @return      合成された文章
643         */
644        private String marge( final String[][] src ){
645                StringBuilder rtnBuf = new StringBuilder();
646                String rtn;
647                if ( src != null ){
648                        int len = src[1].length;
649                        for(int i=0; i< len; i++) {
650                                rtnBuf.append( src[0][i] );
651//                              rtnBuf.append( paramMap.get( src[1][i] ) );
652                                rtnBuf.append( getReservedValue( src[1][i] ) ); // 5.10.11.1 (2019/05/10)
653                        }
654                        rtnBuf.append( src[0][len] );
655                        rtn = rtnBuf.toString();
656                }
657                else {
658                        rtn = null;
659                }
660
661                return rtn;
662        }
663        
664        /**
665         * メールでのみ有効な予約語関係の処理を行います。
666         * 
667         * LINK.URLCはURLチェックを付加したURLを作成するための予約語です。
668         * {&#064;LINK.URLC url?key= &#064;PARAMx [CryptkeyStr]} ではをURL?key=ParamXにURLチェックを付加したものを返します。
669         * 第一パラメータはURLで、第二パラメータを付加します。複数のパラメータの付加は出来ません。
670         * ユーザ制限無し、期間は固定です。
671         *
672         * @og.rev 5.10.11.1 (2019/05/10) 新規作成
673         * 
674         * @param key
675         * @return 変換後文字列
676         */
677        private String getReservedValue( final String key ) {
678                if( key == null ) { return ""; }
679
680                String rtn="" ;
681                int adrs = key.indexOf( '.' );
682                if( adrs > 0 ) {
683                        String subKey = key.substring( adrs+1 );
684                        
685                        // 利用頻度が低いと思われるため、この中で処理してしまう
686                        if( key.startsWith( "LINK.URLC" ) ) {
687                                String[] vals = StringUtil.csv2Array( subKey,' ' );
688                                String prm0 = vals[0] ; //URLCなので利用しない
689                                String prm1 = (vals.length >= 2) ? vals[1] : "" ; //URL
690                                String prm2 = (vals.length >= 3) ? vals[2] : "" ; //リクエスト変数
691                                String prm3 = (vals.length >= 4) ? vals[3] : urlCheckCrypt ;
692
693                                if( prm1 != null && prm1.startsWith( "@" ) ) {
694                                        prm1 = paramMap.get( prm1.substring(1) );
695                                }
696                                if( prm2 != null && prm2.startsWith( "@" ) ) {
697                                        prm2 = paramMap.get( prm2.substring(1) );
698                                }
699                                if( prm3 != null && prm3.startsWith( "@" ) ) {
700                                        prm3 = paramMap.get( prm3.substring(1) );
701                                }
702                                
703                                rtn = prm1 + prm2; // URLとパラメータを合成
704                                
705                                if( rtn != null && rtn.length() > 0) {
706                                        HybsCryptography criptCls = null;
707                                        if( prm3 != null && prm3.length() > 0 ){
708                                                criptCls = new HybsCryptography( prm3 );
709                                        }
710                                        //ユーザ指定なし、30日間有効のURLを作成
711                                        rtn = XHTMLTag.addURLCheckKey( rtn, HybsSystem.URL_CHECK_KEY, "*", System.currentTimeMillis() + 1000L*60*60*24*30, criptCls );
712                                }
713                        }
714                }
715                else {
716                        rtn = paramMap.get(key);
717                }
718                return rtn;
719        }
720
721        /**
722         * 宛先(TO、CC、BCC)のID、名前、メールアドレスをパラメータマップにセットします。
723         *
724         */
725        private void setDstWord() {
726                StringBuilder to_id    = new StringBuilder();
727                StringBuilder to_name  = new StringBuilder();
728                StringBuilder to_addr  = new StringBuilder();
729                StringBuilder cc_id    = new StringBuilder();
730                StringBuilder cc_name  = new StringBuilder();
731                StringBuilder cc_addr  = new StringBuilder();
732                StringBuilder bcc_id   = new StringBuilder();
733                StringBuilder bcc_name = new StringBuilder();
734                StringBuilder bcc_addr = new StringBuilder();
735                int kbn;
736                for( String dstId : mailDstMap.keySet() ) {
737                        kbn = Integer.parseInt( mailDstMap.get( dstId )[IDX_DST_KBN]);
738                        switch( kbn ) {
739                                case KBN_TO:
740                                        to_id.append( ',' ).append( dstId );
741                                        to_name.append( ',' ).append( mailDstMap.get( dstId )[IDX_DST_NAME] );
742                                        to_addr.append( ',' ).append( mailDstMap.get( dstId )[IDX_DST_NAME] );
743                                        to_addr.append( '<' ).append( mailDstMap.get( dstId )[IDX_DST_ADDR] ).append( ">" );
744                                        break;
745                                case KBN_CC:
746                                        cc_id.append( ',' ).append( dstId );
747                                        cc_name.append( ',' ).append( mailDstMap.get( dstId )[IDX_DST_NAME] );
748                                        cc_addr.append( ',' ).append( mailDstMap.get( dstId )[IDX_DST_NAME] );
749                                        cc_addr.append( '<' ).append( mailDstMap.get( dstId )[IDX_DST_ADDR] ).append( ">" );
750                                        break;
751                                case KBN_BCC:
752                                        bcc_id.append( ',' ).append( dstId );
753                                        bcc_name.append( ',' ).append( mailDstMap.get( dstId )[IDX_DST_NAME] );
754                                        bcc_addr.append( ',' ).append( mailDstMap.get( dstId )[IDX_DST_NAME] );
755                                        bcc_addr.append( '<' ).append( mailDstMap.get( dstId )[IDX_DST_ADDR] ).append( ">" );
756                                        break;
757                                default:
758                                        String errMsg = "このアドレス区分がサポートされません。区分:" + kbn;
759                                        throw new RuntimeException( errMsg );
760                        }
761                }
762                // 予約語マップに追加します。
763                paramMap.put( "TO_ID"   , ( to_id.length()    > 0 ) ? to_id.toString().substring( 1 ):"" );
764                paramMap.put( "TO_NAME" , ( to_name.length()  > 0 ) ? to_name.toString().substring( 1 ):"" );
765                paramMap.put( "TO_ADDR" , ( to_addr.length()  > 0 ) ? to_addr.toString().substring( 1 ):"" );
766                paramMap.put( "CC_ID"   , ( cc_id.length()    > 0 ) ? cc_id.toString().substring( 1 ):"" );
767                paramMap.put( "CC_NAME" , ( cc_name.length()  > 0 ) ? cc_name.toString().substring( 1 ):"" );
768                paramMap.put( "CC_ADDR" , ( cc_addr.length()  > 0 ) ? cc_addr.toString().substring( 1 ):"" );
769                paramMap.put( "BCC_ID"  , ( bcc_id.length()   > 0 ) ? bcc_id.toString().substring( 1 ):"" );
770                paramMap.put( "BCC_NAME", ( bcc_name.length() > 0 ) ? bcc_name.toString().substring( 1 ):"" );
771                paramMap.put( "BCC_ADDR", ( bcc_addr.length() > 0 ) ? bcc_addr.toString().substring( 1 ):"" );
772        }
773
774        /**
775         * 社員マスタより名前、メールアドレスを取得します。
776         * 戻り値 rtn[0]:ユーザー名、 rtn[1]:ユーザーメールアドレス
777         *
778         * @og.rev 4.3.6.6 (2009/05/15) メールアドレスが直接指定された場合に対応
779         * @og.rev 5.5.5.1 (2012/08/07) リソース系DBID 付け忘れ対策
780         *
781         * @param   userId  ユーザーID
782         *
783         * @return      配列文字列(rtn[0]:ユーザー名、 rtn[1]:ユーザーメールアドレス)
784         */
785        private String[] getUserInfo( final String userId ){
786                String[] rtn = null;
787
788                if ( userId.contains( "@" ) ) {
789                        rtn = new String[2];
790                        rtn[0] = "";
791                        rtn[1] = userId;
792                }
793                else {
794                        String[] ge35SelArgs = { userId };
795//                      String[][] ge35Datas = DBUtil.dbExecute( selGE35,ge35SelArgs,AbstractMailManager.appInfo );
796                        String[][] ge35Datas = DBUtil.dbExecute( selGE35,ge35SelArgs,AbstractMailManager.appInfo, DBID );               // 5.5.5.1 (2012/08/07)
797                        if ( ge35Datas.length > 0) {
798                                rtn = ge35Datas[0];
799                        }
800                        else {
801                                String errMsg = "ユーザー情報取得できません。ユーザーID:" + userId ;
802                                if( "true".equals( paramMap.get( "ADDR_CHECK" ) ) ){
803                                        throw new RuntimeException( errMsg );
804                                }
805                                else {
806                                        errAddrList.add( errMsg );
807                                }
808                        }
809                }
810                return rtn;
811        }
812}