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