OSDN Git Service

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