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