/*
 * Aipo is a groupware program developed by Aimluck,Inc.
 * Copyright (C) 2004-2011 Aimluck,Inc.
 * http://www.aipo.com
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package com.aimluck.eip.mail.util;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.StringReader;
import java.io.UnsupportedEncodingException;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.sql.Time;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.StringTokenizer;
import java.util.TimeZone;
import java.util.TreeMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.activation.DataHandler;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;
import javax.mail.Address;
import javax.mail.BodyPart;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.Part;
import javax.mail.Session;
import javax.mail.internet.ContentType;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeUtility;

import org.apache.cayenne.access.DataContext;
import org.apache.cayenne.access.Transaction;
import org.apache.cayenne.exp.Expression;
import org.apache.cayenne.exp.ExpressionFactory;
import org.apache.commons.codec.binary.Base64;
import org.apache.jetspeed.services.JetspeedSecurity;
import org.apache.jetspeed.services.logging.JetspeedLogFactoryService;
import org.apache.jetspeed.services.logging.JetspeedLogger;
import org.apache.jetspeed.services.resources.JetspeedResources;
import org.apache.turbine.util.RunData;

import com.aimluck.commons.field.ALStringField;
import com.aimluck.commons.utils.ALStringUtil;
import com.aimluck.eip.cayenne.om.account.EipMCompany;
import com.aimluck.eip.cayenne.om.portlet.AvzTMailSend;
import com.aimluck.eip.cayenne.om.portlet.AvzTMailSendRecvAcl;
import com.aimluck.eip.cayenne.om.portlet.EipMMailAccount;
import com.aimluck.eip.cayenne.om.portlet.EipMMailNotifyConf;
import com.aimluck.eip.cayenne.om.portlet.EipTMail;
import com.aimluck.eip.cayenne.om.portlet.EipTMailFilter;
import com.aimluck.eip.cayenne.om.portlet.EipTMailFolder;
import com.aimluck.eip.cayenne.om.security.TurbineUser;
import com.aimluck.eip.common.ALBaseUser;
import com.aimluck.eip.common.ALDBErrorException;
import com.aimluck.eip.common.ALEipConstants;
import com.aimluck.eip.common.ALEipUser;
import com.aimluck.eip.mail.ALExtFolderInfo;
import com.aimluck.eip.mail.ALLocalMailMessage;
import com.aimluck.eip.mail.ALMailFactoryService;
import com.aimluck.eip.mail.ALMailHandler;
import com.aimluck.eip.mail.ALMailMessage;
import com.aimluck.eip.mail.ALMailReceiverContext;
import com.aimluck.eip.mail.ALMailSenderContext;
import com.aimluck.eip.mail.ALMailService;
import com.aimluck.eip.mail.ALPop3MailReceiverContext;
import com.aimluck.eip.mail.ALSmtpMailContext;
import com.aimluck.eip.mail.ALSmtpMailSender;
import com.aimluck.eip.mail.ALSmtpMailSenderContext;
import com.aimluck.eip.orm.Database;
import com.aimluck.eip.orm.query.ResultList;
import com.aimluck.eip.orm.query.SelectQuery;
import com.aimluck.eip.services.eventlog.ALEventlogConstants;
import com.aimluck.eip.services.eventlog.ALEventlogFactoryService;
import com.aimluck.eip.services.storage.ALStorageService;
import com.aimluck.eip.util.ALCommonUtils;
import com.aimluck.eip.util.ALEipUtils;
import com.aimluck.eip.util.ALServletUtils;
import com.sk_jp.io.ByteToCharUTF7;
import com.sk_jp.mail.MailUtility;
import com.sk_jp.text.formatter.ParseException;
import com.sun.mail.util.ASCIIUtility;
import com.sun.mail.util.BASE64DecoderStream;
import com.sun.mail.util.QDecoderStream;

/**
 * メールのユーティリティクラスです。 <BR>
 * 
 */
public class ALMailUtils {

  private static final JetspeedLogger logger = JetspeedLogFactoryService.getLogger(ALMailUtils.class.getName());

  /** 改行文字 */
  public static final String CR = System.getProperty("line.separator");

  /** アカウントタイプを無指定 */
  public static final int ACCOUNT_TYPE_NON = 0;

  /** デフォルトアカウント */
  public static final int ACCOUNT_TYPE_DEFAULT = 1;

  /** 初期アカウント */
  public static final int ACCOUNT_TYPE_INIT = 2;

  /** メール通知のキー（毎日通知スケジュール用） */
  public static final int KEY_MSGTYPE_DAYMAIL = 1;

  /** メール通知のキー（伝言メモ用） */
  public static final int KEY_MSGTYPE_NOTE = 21;

  /** メール通知のキー（ブログ用） */
  public static final int KEY_MSGTYPE_BLOG = 22;

  /** メール通知のキー（ワークフロー用） */
  public static final int KEY_MSGTYPE_WORKFLOW = 23;

  /** メール通知のキー（スケジュール用） */
  public static final int KEY_MSGTYPE_SCHEDULE = 24;

  /** メール通知の値（送信先なし） */
  public static final int VALUE_MSGTYPE_DEST_NONE = 0;

  /** メール通知の値（パソコン用メールアドレス） */
  public static final int VALUE_MSGTYPE_DEST_PC = 1;

  /** メール通知の値（携帯用メールアドレス） */
  public static final int VALUE_MSGTYPE_DEST_CELLULAR = 2;

  /** メール通知の値（パソコン用メールアドレスと携帯用メールアドレス） */
  public static final int VALUE_MSGTYPE_DEST_PC_CELLULAR = 3;

  /** オブジェクト比較タイプ：昇順 */
  public static final int COMPARE_TYPE_ASC = 1;

  /** オブジェクト比較タイプ：降順 */
  public static final int COMPARE_TYPE_DESC = 2;

  /** オブジェクト比較名称：件名 */
  public static final int COMPARE_NAME_SUBJECT = 1;

  /** オブジェクト比較名称：差出人 or 受取人 */
  public static final int COMPARE_NAME_PERSON = 2;

  /** オブジェクト比較名称：日付 */
  public static final int COMPARE_NAME_DATE = 3;

  /** オブジェクト比較名称：ファイル容量 */
  public static final int COMPARE_NAME_FILE_VOLUME = 4;

  public static final String DATE_FORMAT = "yyyy/MM/dd HH:mm";

  public static final String storePath = JetspeedResources.getString("aipo.home", "");

  public static final String rootFolderPath = JetspeedResources.getString("aipo.mail.home", "");

  public static final String categoryKey = JetspeedResources.getString("aipo.mail.key", "");

  // add
  public static final String excludeSpamKey = JetspeedResources.getString("aipo.spam.word", "");

  /** メールアカウントのパスワードを暗号化する時の共通鍵 */
  private static final String seacretPassword = "1t's a s3@cr3t k3y";

  /** フィルタタイプ */
  /** 送信元メールアドレス */
  public final static String FILTER_TYPE_MAILADDRESS = "M";

  /** 送信元ドメイン */
  public final static String FILTER_TYPE_DOMAIN = "D";

  /** 件名 */
  public final static String FILTER_TYPE_SUBJECT = "S";

  /** 送信先メールアドレス */
  public final static String FILTER_TYPE_TO = "T";

  /** セッションの識別子 */
  public static final String FOLDER_ID = "folderid";

  // add by motegi start
  /** フォルダ種別：受信 */
  public static final String FOLDER_KIND_RECEIVE = "R";

  /** フォルダ種別：送信 */
  public static final String FOLDER_KIND_SEND = "S";

  /** フォルダタイプ：通常 */
  public static final String FOLDER_TYPE_NORMAL = "0";

  /** フォルダタイプ：下書き */
  public static final String FOLDER_TYPE_DRAFT = "D";

  /** フォルダタイプ：ゴミ箱 */
  public static final String FOLDER_TYPE_TRASH = "T";

  /** フォルダタイプ：迷惑メール */
  public static final String FOLDER_TYPE_SPAM = "S";

  /** フォルダタイプ：戻したメール */
  public static final String FOLDER_TYPE_RETURN = "R";

  // add start
  /** 会議案内用制御文字列(1)： PC：プレフィックスをはずす、携帯スマホ：プレフィックスをはずす */
  public static final String PREFIX_PATTERN_REMOVE_BOTH = "DEL--";

  /** 会議案内用制御文字列(2)： PC：スキップ、携帯スマホ：プレフィックスをはずす */
  public static final String PREFIX_PATTERN_SKIP_PC = "COM--";

  /** 会議案内用制御文字列(3)： PC：プレフィックスをはずす、携帯スマホ：スキップ */
  public static final String PREFIX_PATTERN_SKIP_CEL = "COMLINK--";

  /** 会議案内用制御文字列(4)： PC：スキップ、携帯スマホ：スキップ */
  public static final String PREFIX_PATTERN_SKIP_BOTH = "DELLINK--";

  /** 会議案内用制御文字列(5)： 返信コメント、キャンセル理由シンボル */
  public static final String PREFIX_PATTERN_COMMENT = "COMMENT--";

  /** クラス Pattern 大文字と小文字を区別しないマッチングを有効にします。 */
  public static final int CASE_INSENSITIVE = 2;

  /** 文字コード iso-2022-jp * */
  public static final String ISO_2022_JP = "iso-2022-jp";

  /** 文字コード utf-7 * */
  public static final String UTF_7 = "utf-7";

  /** 文字コード UTF8 * */
  public static final String UTF8 = "UTF8";

  /** 文字コード gb2312 * */
  public static final String GB2312 = "GB2312";

  /** 文字コード GB18030 * */
  public static final String GB18030 = "GB18030";

  /** 文字コード Windows-31J * */
  public static final String WINDOWS_31J = "Windows-31J";

  /** CONTENT_TRANSFER_ENCORDING 7bit * */
  public static final String STR_7BIT = "7bit";

  /** 文字コード charset比較用gb2312 * */
  public static final String CHARSET_GB2312 = "gb2312";

  /** 文字コード charset比較用GB18030 * */
  public static final String CHARSET_GB18030 = "gb18030";

  public static int comma_position_count = 0;

  // add end

  // add start 2012.2.24 受入障害No.294
  public static final String USER_ACCOUNT = "0";

  // add end 2012.2.24

  // add start 運用フェーズ障害128
  public static final String REPLACE_NULL_CHAR = " ";

  // add end

  // add start 2次開発 要件No.20 キャラクタセットCP932メール対応
  /** 文字コード cp932 * */
  public static final String CP932 = "cp932";

  // add end
  /**
   * メールアカウントを取得する．
   * 
   * @param userId
   * @param accountId
   * @return
   */
  public static EipMMailAccount getMailAccount(int userId, int accountId) {
    if (userId < 0 || accountId < 0) {
      return null;
    }

    try {

      SelectQuery<EipMMailAccount> query = Database.query(EipMMailAccount.class);
      Expression exp1 = ExpressionFactory.matchExp(EipMMailAccount.USER_ID_PROPERTY, Integer.valueOf(userId));
      Expression exp2 = ExpressionFactory.matchDbExp(EipMMailAccount.ACCOUNT_ID_PK_COLUMN, Integer.valueOf(accountId));

      EipMMailAccount account = query.andQualifier(exp1).andQualifier(exp2).fetchSingle();
      if (account == null) {
        logger.debug("[WebMail] Not found AccountID...");
        return null;
      }
      return account;
    } catch (Exception ex) {
      // change start
      // logger.error("Exception", ex);
      logger.error("メールアカウントの取得に失敗しました。ユーザーID=" + userId + " アカウントID=" + accountId, ex);
      // change end
      return null;
    }
  }

  /**
   * メールアカウント名を取得する．
   * 
   * @param userId
   * @param accountId
   * @return
   */
  public static String getAccountName(int userId, int accountId) {
    if (userId < 0 || accountId < 0) {
      return null;
    }

    String accountName = null;
    try {
      EipMMailAccount mailAccount = getMailAccount(userId, accountId);
      if (mailAccount == null) {
        return null;
      }
      accountName = mailAccount.getAccountName();
    } catch (Exception ex) {
      logger.error("Exception", ex);
      return null;
    }
    return accountName;
  }

  /**
   * メールの返信に必要な値をセットする．
   * 
   * @param msg
   * @return
   */
  public static ALMailMessage getReplyMessage(ALMailMessage mailmsg) {
    if (mailmsg == null) {
      return null;
    }

    ALLocalMailMessage msg = null;
    try {
      msg = (ALLocalMailMessage) mailmsg;

      StringBuffer sb = new StringBuffer();
      sb.append(" ").append(CR).append("----- Original Message ----- ").append(CR);
      sb.append("From: ").append(getAddressString(msg.getFrom())).append(CR);
      sb.append("To: ").append(getAddressString(msg.getRecipients(Message.RecipientType.TO))).append(CR);
      sb.append("Sent: ").append(msg.getSentDate()).append(CR);
      sb.append("Subject: ").append(UnicodeCorrecter.correctToISO2022JP(msg.getSubject())).append(CR).append(" ").append(CR);

      msg.setSubject(MimeUtility.encodeText("Re: " + UnicodeCorrecter.correctToISO2022JP(msg.getSubject())));
      msg.setRecipient(Message.RecipientType.TO, msg.getReplyTo()[0]);
      String[] lines = msg.getBodyTextArray();
      if (lines != null && lines.length > 0) {
        int length = lines.length;
        for (int i = 0; i < length; i++) {
          sb.append("> ").append(lines[i]).append(CR);
        }
      }
      msg.setText(UnicodeCorrecter.correctToISO2022JP(sb.toString()));
    } catch (Exception e) {
      logger.error("Exception", e);
      return null;
    }
    return msg;
  }

  /**
   * メールの転送に必要な値をセットする．
   * 
   * @param msg
   * @return
   */
  public static ALMailMessage getForwardMessage(ALMailMessage mailmsg) {
    if (mailmsg == null) {
      return null;
    }

    ALLocalMailMessage msg = null;
    try {
      msg = (ALLocalMailMessage) mailmsg;

      StringBuffer sb = new StringBuffer();
      sb.append(" ").append(CR).append("----- Original Message ----- ").append(CR);
      sb.append("From: ").append(getAddressString(msg.getFrom())).append(CR);
      sb.append("To: ").append(getAddressString(msg.getRecipients(Message.RecipientType.TO))).append(CR);
      sb.append("Sent: ").append(msg.getSentDate()).append(CR);
      sb.append("Subject: ").append(UnicodeCorrecter.correctToISO2022JP(msg.getSubject())).append(CR).append(" ").append(CR);

      msg.setSubject(MimeUtility.encodeText("Fwd: " + UnicodeCorrecter.correctToISO2022JP(msg.getSubject())));
      // msg.setRecipient(Message.RecipientType.TO, msg.getFrom()[0]);
      String[] lines = msg.getBodyTextArray();
      if (lines != null && lines.length > 0) {
        int length = lines.length;
        for (int i = 0; i < length; i++) {
          sb.append(lines[i]).append(CR);
        }
      }
      msg.setText(UnicodeCorrecter.correctToISO2022JP(sb.toString()));
    } catch (Exception e) {
      logger.error("Exception", e);
      return null;
    }
    return msg;
  }

  /**
   * 改行を含む文字列を，改行で区切った文字列の配列を取得する．
   * 
   * @param str
   * @return
   */
  public static String[] getLines(String str) {
    if (str == null || str.equals("")) {
      // change start
      // return null;
      return new String[0];
      // change end
    }
    // change start
    // if (str.indexOf(CR) < 0) {
    if (str.indexOf(CR) < 0 && str.indexOf("\n") < 0) {
      // change end
      return new String[] { str };
    }

    String token = null;
    List<String> tokens = new ArrayList<String>();
    BufferedReader reader = null;
    String[] lines = null;
    try {
      reader = new BufferedReader(new StringReader(str));
      while ((token = reader.readLine()) != null) {
        tokens.add(token);
      }
      reader.close();

      lines = new String[tokens.size()];
      lines = tokens.toArray(lines);
    } catch (Exception ioe) {
      logger.error("Exception", ioe);
      try {
        reader.close();
      } catch (IOException e) {
      }
      return null;
    }
    return lines;
  }

  /**
   * 区切り文字で区切った文字列の配列を取得する．
   * 
   * @param line
   *            区切り文字を含む文字列
   * @param delim
   *            区切り文字
   * @return
   */
  public static String[] getTokens(String line, String delim) {
    if (line == null || line.equals("")) {
      return null;
    }
    if (line.indexOf(delim) < 0) {
      return new String[] { line };
    }

    StringTokenizer st = new StringTokenizer(line, delim);
    int length = st.countTokens();
    String[] tokens = new String[length];
    for (int i = 0; i < length; i++) {
      tokens[i] = st.nextToken();
    }
    return tokens;
  }

  /**
   * 指定された配列の並び順を逆にする．
   * 
   * @param objs
   * @return
   */
  public static int[] reverse(int[] objs) {
    if (objs == null) {
      return null;
    }
    int length = objs.length;
    int[] destObjs = new int[length];
    System.arraycopy(objs, 0, destObjs, 0, length);
    Arrays.sort(destObjs);

    int[] reverseObjs = new int[length];
    for (int i = 0; i < length; i++) {
      reverseObjs[i] = destObjs[length - i - 1];
    }
    return reverseObjs;

  }

  /**
   * 複数のアドレスをカンマ区切りの1つの文字列に変換する．
   * 
   * @param addresses
   * @return
   */
  public static String getAddressString(Address[] addresses) {
    if (addresses == null || addresses.length <= 0) {
      return "";
    }
    HashSet<String> foundAddress = new HashSet<String>();

    StringBuffer sb = new StringBuffer();
    InternetAddress addr = null;
    int length = addresses.length;
    for (int i = 0; i < length; i++) {
      addr = (InternetAddress) addresses[i];
      if (foundAddress.contains(addr.getAddress())) {
        continue;
      }
      foundAddress.add(addr.getAddress());

      if (addr.getPersonal() != null) {
        // add start 2011/12/23 Shift-Jis対応
        String encodedPersonal = "";
        try {
          encodedPersonal = ALMailUtils.decodeText(addr.toString());
        } catch (Exception e) {

        }
        // add end
        String personaladdr =
        // change start 2011/12/23 Shift-Jis対応
          // getOneString(getTokens(addr.getPersonal(), "\r\n"), "");
          // sb.append(MailUtility.decodeText(personaladdr)).append("
          // <").append(
          // addr.getAddress()).append(">, ");
          getOneString(getTokens(encodedPersonal, "\r\n"), "");
        sb.append(MailUtility.decodeText(personaladdr)).append(", ");
        // change end

      } else {
        sb.append(addr.getAddress()).append(", ");
      }
    }
    String addressStr = sb.toString();
    return addressStr.substring(0, addressStr.length() - 2);
  }

  /**
   * 複数の文字列を区切り文字で区切った1つの文字列に変換する．
   * 
   * @param addresses
   * @param delim
   * @return
   */
  public static String getOneString(String[] strs, String delim) {
    if (strs == null) {
      return "";
    }
    String delimiter = delim + " ";
    StringBuffer sb = new StringBuffer();
    int length = strs.length - 1;
    for (int i = 0; i < length; i++) {
      sb.append(strs[i]).append(delimiter);
    }
    sb.append(strs[length]);
    return sb.toString();
  }

  /**
   * Date のオブジェクトを "yyyy/MM/dd hh:mm" 形式の文字列に変換する．
   * 
   * @param date
   * @return
   */
  public static String translateDate(Date date) {
    if (date == null) {
      return null;
    }

    // 日付を表示形式に変換
    SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT);
    sdf.setTimeZone(TimeZone.getTimeZone("JST"));
    return sdf.format(date);
  }

  /**
   * "yyyy/MM/dd hh:mm" 形式の文字列を Date のオブジェクトに変換する．
   * 
   * @param dateStr
   * @return
   */
  public static Date translateDate(String dateStr) {
    if (dateStr == null || dateStr.equals("")) {
      return null;
    }
    Date date = null;

    // 日付を表示形式に変換
    SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT);
    sdf.setTimeZone(TimeZone.getTimeZone("JST"));
    try {
      date = sdf.parse(dateStr);
    } catch (Exception e) {
      return null;
    }
    return date;
  }

  /**
   * 受信メールの受信日時を取得する（ヘッダ Recieved を解析する）．
   * 
   * @param msg
   * @return
   */
  public static Date getReceivedDate(MimeMessage msg) {
    try {
      String[] receivedHeaders = msg.getHeader("Received");

      if (receivedHeaders == null || receivedHeaders.length == 0) {
        return null;
      }

      Date receivedDate = null;
      StringTokenizer st = new StringTokenizer(receivedHeaders[0], ";");
      if (st.countTokens() == 2) {
        st.nextToken();
        String receivedDateStr = st.nextToken();
        if (receivedDateStr != null && !receivedDateStr.equals("")) {
          receivedDate = MailUtility.parseDate(receivedDateStr);
        }
        return receivedDate;
      } else {
        return null;
      }
    } catch (Exception e) {
      return null;
    }
  }

  public static String convertBase64ToIso2022(String str) {
    if (str == null || str.length() <= 0) {
      return str;
    }

    StringBuffer sb = new StringBuffer("=?ISO-2022-JP?B?");
    sb.append(str).append("?=");

    return sb.toString();
  }

  /**
   * 日本語を含むヘッダ用テキストを生成します。 変換結果は ASCII なので、これをそのまま setSubject や InternetAddress
   * のパラメタとして使用してください。
   */
  public static String encodeWordJIS(String s) {
    try {
      return "=?ISO-2022-JP?B?"
        + new String(Base64.encodeBase64(CharCodeConverter.sjisToJis(UnicodeCorrecter.correctToCP932(s).getBytes("Windows-31J"))))
        + "?=";
    } catch (UnsupportedEncodingException e) {
      throw new RuntimeException("CANT HAPPEN");
    }
  }

  /**
   * 日本語を含むヘッダ用テキストを生成します。 変換結果は ASCII なので、これをそのまま setSubject や InternetAddress
   * のパラメタとして使用してください。
   */
  public static String encodeWordGB18030(String s) {
    try {
      return "=?GB18030?B?" + new String(Base64.encodeBase64(s.getBytes(ALMailUtils.GB18030))) + "?=";
    } catch (UnsupportedEncodingException e) {
      throw new RuntimeException("CANT HAPPEN");
    }
  }

  /**
   * String 型のアドレス → InternetAddress 型のアドレス に変換する．
   * 
   * @param addr
   * @return
   */
  public static InternetAddress getInternetAddress(String addr) {
    InternetAddress address = null;
    StringTokenizer st = new StringTokenizer(addr, "<>");
    int count = st.countTokens();
    try {
      if (count <= 0) {
        return null;
      } else if (count == 1) {
        address = new InternetAddress(st.nextToken().trim());
      } else if (count == 2) {
        String name = st.nextToken().trim();
        String addressStr = st.nextToken().trim();
        address = new InternetAddress(addressStr, ALMailUtils.encodeWordJIS(name));
      }
    } catch (Exception e) {
      logger.error("Exception", e);
      return null;
    }
    return address;
  }

  public static String getFileNameFromText(String filePath) {
    String line = "";
    BufferedReader reader = null;
    try {
      reader = new BufferedReader(new InputStreamReader(ALStorageService.getFile(filePath + ".txt"), ALEipConstants.DEF_CONTENT_ENCODING));
      line = reader.readLine();
    } catch (Exception e) {
      logger.error("Exception", e);
    } finally {
      if (reader != null) {
        try {
          reader.close();
        } catch (IOException ex) {
          logger.error("Exception", ex);
        }
      }
    }
    return line;

  }

  // add start 2012.1.19 簡体字中国語対応
  public static String getFileNameFromTextGB18030(String filePath) {
    String line = "";
    BufferedReader reader = null;
    try {
      reader = new BufferedReader(new InputStreamReader(ALStorageService.getFile(filePath + ".txt"), ALEipConstants.DEF_CONTENT_ENCODING));
      line = reader.readLine();
    } catch (Exception e) {
      logger.error("Exception", e);
    } finally {
      if (reader != null) {
        try {
          reader.close();
        } catch (IOException ex) {
          logger.error("Exception", ex);
        }
      }
    }
    return line;

  }

  // add end

  /**
   * テキストをセットします。 Part#setText() の代わりにこちらを使うようにします。
   */
  public static void setTextContent(Part p, String s) throws MessagingException {
    p.setDataHandler(new DataHandler(new JISDataSource(s)));
    p.setHeader(ALLocalMailMessage.CONTENT_TRANSFER_ENCORDING, "7bit");
  }

  // add start 2012.1.19 簡体字中国語対応
  /**
   * テキストをセットします。 Part#setText() の代わりにこちらを使うようにします。
   */
  public static void setTextContentGB18030(Part p, String s) throws MessagingException {
    p.setDataHandler(new DataHandler(new GB18030DataSource(s)));
    p.setHeader(ALLocalMailMessage.CONTENT_TRANSFER_ENCORDING, "7bit");
  }

  // add end 2012.1.19
  /**
   * 「暗号化＋Base64符号化」の文字列を，もとの文字列に復号する．
   * 
   * @param password
   * @param data
   * @return
   */
  public static final byte[] getDecryptedMailAccountPasswd(byte[] data) {
    return getDecryptedMailAccountPasswd(seacretPassword.toCharArray(), data);
  }

  /**
   * 「暗号化＋Base64符号化」の文字列を，もとの文字列に復号する．
   * 
   * @param password
   * @param data
   * @return
   */
  public static final byte[] getDecryptedMailAccountPasswd(char[] password, byte[] data) {
    if (data == null) {
      return null;
    }

    byte[] decryptedData = null;
    try {
      decryptedData = cryptPBEWithMD5AndDES(Cipher.DECRYPT_MODE, password, data);
      if (decryptedData == null) {
        return null;
      }
    } catch (Exception e) {
      logger.error("Exception", e);
      return null;
    }
    return decryptedData;
  }

  /**
   * 「暗号化＋Base64符号化」した文字列を取得する．
   * 
   * @param password
   * @param data
   * @return
   */
  public static final byte[] getEncryptedMailAccountPasswd(byte[] data) {
    return getEncryptedMailAccountPasswd(seacretPassword.toCharArray(), data);
  }

  /**
   * 「暗号化＋Base64符号化」した文字列を取得する．
   * 
   * @param password
   * @param data
   * @return
   */
  public static final byte[] getEncryptedMailAccountPasswd(char[] password, byte[] data) {
    if (data == null) {
      return null;
    }

    byte[] encryptedData = null;
    try {
      encryptedData = cryptPBEWithMD5AndDES(Cipher.ENCRYPT_MODE, password, data);
    } catch (Exception e) {
      logger.error("Exception", e);
      return null;
    }
    return encryptedData;
  }

  /**
   * 指定したパスワードでデータを暗号化／復号する． 暗号化方式：PBEWithMD5AndDES
   * 
   * @param cipherMode
   *            Cipher.ENCRYPT_MODE もしくは Cipher.DECRYPT_MODE
   * @param password
   * @param data
   * @return
   */
  public static final byte[] cryptPBEWithMD5AndDES(int cipherMode, char[] password, byte[] data) {
    byte[] ciphertext = null;
    PBEKeySpec pbeKeySpec;
    PBEParameterSpec pbeParamSpec;
    SecretKeyFactory keyFac;

    // Salt
    byte[] salt = { (byte) 0xc7, (byte) 0x73, (byte) 0x21, (byte) 0x8c, (byte) 0x7e, (byte) 0xc8, (byte) 0xee, (byte) 0x99 };

    // Iteration count
    int count = 20;

    // Create PBE parameter set
    pbeParamSpec = new PBEParameterSpec(salt, count);

    pbeKeySpec = new PBEKeySpec(password);
    try {
      keyFac = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
      SecretKey pbeKey = keyFac.generateSecret(pbeKeySpec);

      // Create PBE Cipher
      Cipher pbeCipher = Cipher.getInstance("PBEWithMD5AndDES");

      // Initialize PBE Cipher with key and parameters
      pbeCipher.init(cipherMode, pbeKey, pbeParamSpec);

      // Encrypt/Decrypt the cleartext
      ciphertext = pbeCipher.doFinal(data);
    } catch (Exception e) {
      logger.error("Exception", e);
      return null;
    }
    return ciphertext;
  }

  /**
   * メール受信用コンテキスト（POP3）を取得します。
   * 
   * @param orgId
   * @param account
   * @return
   */
  public static ALMailReceiverContext getALPop3MailReceiverContext(String orgId, EipMMailAccount account) {
    if (account == null) {
      return null;
    }

    ALPop3MailReceiverContext rcontext = new ALPop3MailReceiverContext();
    try {
      rcontext.setOrgId(orgId);
      rcontext.setUserId(account.getUserId());
      rcontext.setAccountId(account.getAccountId());
      rcontext.setPop3Host(account.getPop3serverName());
      rcontext.setPop3Port(account.getPop3Port());
      rcontext.setPop3UserId(account.getPop3userName());
      rcontext.setPop3UserPasswd(new String(ALMailUtils.getDecryptedMailAccountPasswd(account.getPop3password())));
      rcontext.setDelete(Integer.parseInt(account.getDelAtPop3Flg()) == 1);
      rcontext.setEnableSavingDays(Integer.parseInt(account.getDelAtPop3BeforeDaysFlg()) == 1);
      rcontext.setSavingDays(account.getDelAtPop3BeforeDays().intValue());
      rcontext.setDenyReceivedMail(Integer.parseInt(account.getNonReceivedFlg()) == 1);
      rcontext.setAuthReceiveFlag(account.getAuthReceiveFlg().intValue());
      rcontext.setEncryptionFlag(account.getPop3EncryptionFlg());
    } catch (Exception e) {
      return null;
    }

    return rcontext;
  }

  /**
   * メール送信用コンテキスト（SMTP）を取得します。
   * 
   * @param orgId
   * @param account
   * @return
   */
  public static ALMailSenderContext getALSmtpMailSenderContext(String orgId, EipMMailAccount account) {
    if (account == null) {
      return null;
    }

    ALSmtpMailSenderContext scontext = new ALSmtpMailSenderContext();

    int authSendFlg = 0;
    try {
      authSendFlg = account.getAuthSendFlg();
    } catch (NumberFormatException e) {
      authSendFlg = 0;
    }

    try {
      scontext.setOrgId(orgId);
      scontext.setUserId(account.getUserId().intValue());
      scontext.setAccountId(account.getAccountId().intValue());
      scontext.setSmtpHost(account.getSmtpserverName());
      scontext.setSmtpPort(account.getSmtpPort());
      scontext.setAuthSendFlag(authSendFlg);
      scontext.setAuthSendUserId(account.getAuthSendUserId());
      scontext.setEncryptionFlag(account.getSmtpEncryptionFlg());

      byte[] auth_pass = ALMailUtils.getDecryptedMailAccountPasswd(account.getAuthSendUserPasswd());
      if (auth_pass != null) {
        scontext.setAuthSendUserPassword(new String(ALMailUtils.getDecryptedMailAccountPasswd(account.getAuthSendUserPasswd())));
      } else {
        scontext.setAuthSendUserPassword(null);
      }

      scontext.setPop3Host(account.getPop3serverName());
      scontext.setPop3Port(account.getPop3Port());
      scontext.setPop3UserId(account.getPop3userName());
      scontext.setPop3UserPasswd(new String(ALMailUtils.getDecryptedMailAccountPasswd(account.getPop3password())));
      scontext.setPop3EncryptionFlag(account.getSmtpEncryptionFlg());

    } catch (Exception e) {
      return null;
    }
    return scontext;
  }

  /**
   * 送信メッセージ（SMTP）のコンテキストを取得します。
   * 
   * @param orgId
   * @param account
   * @return
   */
  // mod by motegi start 開封確認
  // public static ALSmtpMailContext getALSmtpMailContext(String[] to,
  // String[] cc, String[] bcc, String from, String name, String subject,
  // String msgText, String[] filePaths, Map<String, String> additionalHeaders)
  // {
  //
  // ALSmtpMailContext mailcontext = new ALSmtpMailContext();
  // mailcontext.setTo(to);
  // mailcontext.setCc(cc);
  // mailcontext.setBcc(bcc);
  // mailcontext.seFrom(from);
  // mailcontext.setName(name);
  // mailcontext.setSubject(subject);
  // mailcontext.setMsgText(msgText);
  // mailcontext.setFilePaths(filePaths);
  // mailcontext.setAdditionalHeaders(additionalHeaders);
  //
  // return mailcontext;
  // }
  public static ALSmtpMailContext getALSmtpMailContext(String[] to, String[] cc, String[] bcc, String from, String name, String subject, String msgText,
      String[] filePaths, Map<String, String> additionalHeaders) {

    ALSmtpMailContext mailcontext = new ALSmtpMailContext();
    mailcontext.setTo(to);
    mailcontext.setCc(cc);
    mailcontext.setBcc(bcc);
    mailcontext.seFrom(from);
    mailcontext.setName(name);
    mailcontext.setSubject(subject);
    mailcontext.setMsgText(msgText);
    mailcontext.setFilePaths(filePaths);
    mailcontext.setAdditionalHeaders(additionalHeaders);
    // add by motegi start
    // 開封確認付きメールか？
    mailcontext.setHasDispositionNotification(false);
    // 開封確認付きメールに対する応答か？
    mailcontext.setReplyDispositionNotification(false);
    // end

    return mailcontext;
  }

  public static ALSmtpMailContext getALSmtpMailContext(String[] to, String[] cc, String[] bcc, String from, String name, String subject, String msgText,
      String[] filePaths, Map<String, String> additionalHeaders, boolean hasDispositionNotification, boolean isReplyDispositionNotification,
      boolean isChineseMail) {

    ALSmtpMailContext mailcontext = new ALSmtpMailContext();
    mailcontext.setTo(to);
    mailcontext.setCc(cc);
    mailcontext.setBcc(bcc);
    mailcontext.seFrom(from);
    mailcontext.setName(name);
    mailcontext.setSubject(subject);
    mailcontext.setMsgText(msgText);
    mailcontext.setFilePaths(filePaths);
    mailcontext.setAdditionalHeaders(additionalHeaders);
    // add by motegi start
    // 開封確認付きメールか？
    mailcontext.setHasDispositionNotification(hasDispositionNotification);
    // 開封確認付きメールに対する応答か？
    mailcontext.setReplyDispositionNotification(isReplyDispositionNotification);
    // end
    // add start 2012.1.19 簡体字中国語対応
    mailcontext.setChineseMail(isChineseMail);
    // add end

    return mailcontext;
  }

  // mod end

  /**
   * 管理者 admin のメールアカウントのオブジェクトモデルを取得する． <BR>
   * 
   * @param rundata
   * @param context
   * @param isJoin
   *            カテゴリテーブルをJOINするかどうか
   * @return
   */
  public static EipMMailAccount getEipMMailAccountForAdmin() {
    try {
      SelectQuery<EipMMailAccount> query = Database.query(EipMMailAccount.class);

      Expression exp = ExpressionFactory.matchExp(EipMMailAccount.USER_ID_PROPERTY, Integer.valueOf(1));
      EipMMailAccount account = query.andQualifier(exp).fetchSingle();

      if (account == null) {
        logger.debug("[ALMailUtils] Not found AccountID...");
        return null;
      }
      return account;
    } catch (Exception ex) {
      logger.error("Exception", ex);
      return null;
    }
  }

  /**
   * デフォルトのメールアカウントの情報をデータベースから所得する．
   * 
   * @param userId
   * @return
   */
  public static EipMMailAccount getFirstEipMMailAccount(int userId) {
    try {
      SelectQuery<EipMMailAccount> query = Database.query(EipMMailAccount.class);

      Expression exp1 = ExpressionFactory.matchExp(EipMMailAccount.USER_ID_PROPERTY, Integer.valueOf(userId));
      Expression exp21 = ExpressionFactory.matchExp(EipMMailAccount.ACCOUNT_TYPE_PROPERTY, "1");
      Expression exp22 = ExpressionFactory.matchExp(EipMMailAccount.ACCOUNT_TYPE_PROPERTY, "2");
      EipMMailAccount account = query.andQualifier(exp1).andQualifier(exp21.orExp(exp22)).fetchSingle();

      if (account == null) {
        logger.debug("[ALMailUtils] Not found AccountID...");
        return null;
      }
      return account;
    } catch (Exception ex) {
      logger.error("Exception", ex);
      return null;
    }
  }

  /**
   * メールアカウント情報をデータベースに保存する．
   * 
   * @param rundata
   * @param msgList
   * @param userId
   * @param accountName
   * @param accountType
   * @param mailAddress
   * @param mailUserName
   * @param smtpServerName
   * @param smtpPort
   * @param Pop3ServerName
   * @param pop3Port
   * @param pop3UserName
   * @param pop3Password
   * @param authSendFlag
   * @param authSendUserId
   * @param authSendUserPasswd
   * @param authReceiveFlg
   * @param delAtPop3Flg
   * @param delAtPop3BeforeDaysFlg
   * @param delAtPop3BeforeDays
   * @param nonReceivedFlg
   * @param signature
   * @param smtpEncryptionFlg
   * @param pop3EncryptionFlg
   * @return
   * @throws Exception
   */
  public static boolean insertMailAccountData(RunData rundata, List<String> msgList, int userId, String accountName, int accountType, String mailAddress,
      String mailUserName, String smtpServerName, int smtpPort, String Pop3ServerName, int pop3Port, String pop3UserName, String pop3Password,
      int authSendFlag, String authSendUserId, String authSendUserPasswd, int authReceiveFlg, int delAtPop3Flg, int delAtPop3BeforeDaysFlg,
      int delAtPop3BeforeDays, String nonReceivedFlg, String signature, int smtpEncryptionFlg, int pop3EncryptionFlg
      // add start 2012.2.24 受入障害No.294
      // 引数にアカウント用途を追加(通常ユーザー:"0" 会議室ユーザー:"1")
      , String accountUsage
  // add end 2012.2.24
  ) throws Exception {

    boolean enableUpdate = false;

    // add by motegi start アカウントのデフォルトフォルダに（ROOT）フォルダ追加に伴う
    // 標準のトランザクション（オートコミット）
    Transaction baseTx = Transaction.getThreadTransaction();

    DataContext dataContext = DataContext.getThreadDataContext();

    // 自己管理トランザクション
    Transaction tx = Transaction.internalTransaction(DataContext.getThreadDataContext().getParentDataDomain().getTransactionDelegate());

    // 標準のトランザクションを自己管理トランザクションに置き換えます。
    Transaction.bindThreadTransaction(tx);
    // add by motegi end

    try {
      // add by motegi start
      // トランザクション開始
      tx.begin();
      // add by motegi end

      Date createdDate = Calendar.getInstance().getTime();

      EipMMailAccount mailAccount = null;

      if (accountType == ACCOUNT_TYPE_INIT) {
        mailAccount = Database.create(EipMMailAccount.class);
        mailAccount.setAccountType(Integer.toString(ACCOUNT_TYPE_INIT));
      } else {
        SelectQuery<EipMMailAccount> query = Database.query(EipMMailAccount.class);

        Expression exp1 = ExpressionFactory.matchExp(EipMMailAccount.USER_ID_PROPERTY, Integer.valueOf(userId));
        Expression exp2 = ExpressionFactory.matchExp(EipMMailAccount.ACCOUNT_TYPE_PROPERTY, Integer.valueOf(ACCOUNT_TYPE_INIT));
        EipMMailAccount account = query.andQualifier(exp1).andQualifier(exp2).fetchSingle();

        if (account == null) {
          // 新規オブジェクトモデル
          mailAccount = Database.create(EipMMailAccount.class);

          SelectQuery<EipMMailAccount> query3 = Database.query(EipMMailAccount.class);

          Expression exp3 = ExpressionFactory.matchExp(EipMMailAccount.USER_ID_PROPERTY, Integer.valueOf(userId));
          EipMMailAccount anotherAccount = query3.andQualifier(exp3).fetchSingle();

          if (anotherAccount == null) {
            mailAccount.setAccountType(Integer.toString(ACCOUNT_TYPE_DEFAULT));
          } else {
            mailAccount.setAccountType(Integer.toString(ACCOUNT_TYPE_NON));
          }
        } else {
          mailAccount = account;
          if (Integer.toString(ACCOUNT_TYPE_INIT).equals(account.getAccountType())) {
            enableUpdate = true;
            mailAccount.setAccountType(Integer.toString(ACCOUNT_TYPE_DEFAULT));
          } else {
            mailAccount.setAccountType(Integer.toString(ACCOUNT_TYPE_NON));
          }
        }
      }

      // ユーザーID
      mailAccount.setUserId(Integer.valueOf(userId));
      mailAccount.setAccountName(accountName);
      mailAccount.setSmtpserverName(smtpServerName);
      mailAccount.setPop3serverName(Pop3ServerName);
      mailAccount.setPop3userName(pop3UserName);
      mailAccount.setPop3password(ALMailUtils.getEncryptedMailAccountPasswd(pop3Password.getBytes()));
      mailAccount.setMailUserName(mailUserName);
      mailAccount.setMailAddress(mailAddress);
      mailAccount.setSmtpPort(Integer.toString(smtpPort));
      mailAccount.setPop3Port(Integer.toString(pop3Port));
      mailAccount.setAuthSendFlg((short) authSendFlag);
      mailAccount.setAuthSendUserId(authSendUserId);
      if (authSendUserPasswd != null) {
        mailAccount.setAuthSendUserPasswd(ALMailUtils.getEncryptedMailAccountPasswd(authSendUserPasswd.getBytes()));
      }
      mailAccount.setSmtpEncryptionFlg((short) smtpEncryptionFlg);
      mailAccount.setPop3EncryptionFlg((short) pop3EncryptionFlg);
      mailAccount.setAuthReceiveFlg(Short.valueOf((short) authReceiveFlg));
      mailAccount.setDelAtPop3Flg(Integer.valueOf(delAtPop3Flg).toString());
      mailAccount.setDelAtPop3BeforeDaysFlg(Integer.valueOf(delAtPop3BeforeDaysFlg).toString());
      mailAccount.setDelAtPop3BeforeDays(Integer.valueOf(delAtPop3BeforeDays));
      mailAccount.setNonReceivedFlg(nonReceivedFlg);
      mailAccount.setUpdateDate(createdDate);
      mailAccount.setSignature(signature);

      if (!enableUpdate) {
        // 新規作成日
        mailAccount.setCreateDate(createdDate);
      }

      // 以下の処理により、受信メールフォルダのトップフォルダ（”受信”）を登録する。
      EipTMailFolder rootRecvFolder = null;
      rootRecvFolder = Database.create(EipTMailFolder.class);
      rootRecvFolder.setEipMMailAccount(mailAccount);
      rootRecvFolder.setFolderName(EipTMailFolder.DEFAULT_ROOT_RECEIVE_FOLDER_NAME);
      rootRecvFolder.setCreateDate(createdDate);
      rootRecvFolder.setUpdateDate(createdDate);
      rootRecvFolder.setParentFolderId(0);
      rootRecvFolder.setFolderType(FOLDER_TYPE_NORMAL);
      rootRecvFolder.setFolderVolume(0L);
      rootRecvFolder.setFolderKind(FOLDER_KIND_RECEIVE);
      dataContext.commitChanges();

      EipTMailFolder mailFolder = null;

      // 以下の処理により、受信メールフォルダのデフォルトフォルダ（”受信トレイ”）を登録する。
      EipTMailFolder mailDefaultFolder = Database.create(EipTMailFolder.class);
      mailDefaultFolder.setEipMMailAccount(mailAccount);
      mailDefaultFolder.setFolderName(EipTMailFolder.DEFAULT_FOLDER_NAME);
      mailDefaultFolder.setCreateDate(createdDate);
      mailDefaultFolder.setUpdateDate(createdDate);
      mailDefaultFolder.setParentFolderId(rootRecvFolder.getFolderId());
      mailDefaultFolder.setFolderType(FOLDER_TYPE_NORMAL);
      mailDefaultFolder.setFolderVolume(0L);
      mailDefaultFolder.setFolderKind(FOLDER_KIND_RECEIVE);
      dataContext.commitChanges();

      // 以下の処理により、受信メールフォルダの戻したメールフォルダ（”戻したメール”）を登録する。
      mailFolder = Database.create(EipTMailFolder.class);
      mailFolder.setEipMMailAccount(mailAccount);
      mailFolder.setFolderName(EipTMailFolder.DEFAULT_RETURNMAIL_FOLDER_NAME);
      mailFolder.setCreateDate(createdDate);
      mailFolder.setUpdateDate(createdDate);
      mailFolder.setParentFolderId(rootRecvFolder.getFolderId());
      mailFolder.setFolderType(FOLDER_TYPE_RETURN);
      mailFolder.setFolderVolume(0L);
      mailFolder.setFolderKind(FOLDER_KIND_RECEIVE);
      dataContext.commitChanges();

      // 以下の処理により、受信メールフォルダの迷惑メールフォルダ（”迷惑メール”）を登録する。
      mailFolder = Database.create(EipTMailFolder.class);
      mailFolder.setEipMMailAccount(mailAccount);
      mailFolder.setFolderName(EipTMailFolder.DEFAULT_SPAMMAIL_FOLDER_NAME);
      mailFolder.setCreateDate(createdDate);
      mailFolder.setUpdateDate(createdDate);
      mailFolder.setParentFolderId(rootRecvFolder.getFolderId());
      mailFolder.setFolderType(FOLDER_TYPE_SPAM);
      mailFolder.setFolderVolume(0L);
      mailFolder.setFolderKind(FOLDER_KIND_RECEIVE);
      dataContext.commitChanges();

      // SPAMメール除外条件
      EipTMailFilter filter = Database.create(EipTMailFilter.class);
      filter.setEipMMailAccount(mailAccount);
      filter.setFilterName("SPAMメール除外ルール");
      filter.setEipTMailFolder(mailFolder);
      filter.setFilterString(ALMailUtils.excludeSpamKey);
      filter.setFilterType("S");
      filter.setSortOrder(1);
      dataContext.commitChanges();

      // 以下の処理により、受信メールフォルダのごみ箱フォルダ（”ごみ箱”）を登録する。
      mailFolder = Database.create(EipTMailFolder.class);
      mailFolder.setEipMMailAccount(mailAccount);
      mailFolder.setFolderName(EipTMailFolder.DEFAULT_TRASH_FOLDER_NAME);
      mailFolder.setCreateDate(createdDate);
      mailFolder.setUpdateDate(createdDate);
      mailFolder.setParentFolderId(rootRecvFolder.getFolderId());
      mailFolder.setFolderType(FOLDER_TYPE_TRASH);
      mailFolder.setFolderVolume(0L);
      mailFolder.setFolderKind(FOLDER_KIND_RECEIVE);
      dataContext.commitChanges();

      // 以下の処理により、送信メールフォルダのトップフォルダ（”送信”）を登録する。
      EipTMailFolder rootSendFolder = null;
      rootSendFolder = Database.create(EipTMailFolder.class);
      rootSendFolder.setEipMMailAccount(mailAccount);
      rootSendFolder.setFolderName(EipTMailFolder.DEFAULT_ROOT_SEND_FOLDER_NAME);
      rootSendFolder.setCreateDate(createdDate);
      rootSendFolder.setUpdateDate(createdDate);
      rootSendFolder.setParentFolderId(0);
      rootSendFolder.setFolderType(FOLDER_TYPE_NORMAL);
      rootSendFolder.setFolderVolume(0L);
      rootSendFolder.setFolderKind(FOLDER_KIND_SEND);
      dataContext.commitChanges();

      // 以下の処理により、送信メールフォルダのデフォルトフォルダ（”送信トレイ”）を登録する。
      EipTMailFolder mailDefaultSendFolder = Database.create(EipTMailFolder.class);
      mailDefaultSendFolder.setEipMMailAccount(mailAccount);
      mailDefaultSendFolder.setFolderName(EipTMailFolder.DEFAULT_SEND_FOLDER_NAME);
      mailDefaultSendFolder.setCreateDate(createdDate);
      mailDefaultSendFolder.setUpdateDate(createdDate);
      mailDefaultSendFolder.setParentFolderId(rootSendFolder.getFolderId());
      mailDefaultSendFolder.setFolderType(FOLDER_TYPE_NORMAL);
      mailDefaultSendFolder.setFolderVolume(0L);
      mailDefaultSendFolder.setFolderKind(FOLDER_KIND_SEND);
      dataContext.commitChanges();

      // 以下の処理により、送信メールフォルダのごみ箱フォルダ（”ごみ箱”）を登録する。
      mailFolder = Database.create(EipTMailFolder.class);
      mailFolder.setEipMMailAccount(mailAccount);
      mailFolder.setFolderName(EipTMailFolder.DEFAULT_TRASH_FOLDER_NAME);
      mailFolder.setCreateDate(createdDate);
      mailFolder.setUpdateDate(createdDate);
      mailFolder.setParentFolderId(rootSendFolder.getFolderId());
      mailFolder.setFolderType(FOLDER_TYPE_TRASH);
      mailFolder.setFolderVolume(0L);
      mailFolder.setFolderKind(FOLDER_KIND_SEND);
      dataContext.commitChanges();

      // 以下の処理により、送信メールフォルダのごみ箱フォルダ（”下書き”）を登録する。
      mailFolder = Database.create(EipTMailFolder.class);
      mailFolder.setEipMMailAccount(mailAccount);
      mailFolder.setFolderName(EipTMailFolder.DEFAULT_DRAFT_FOLDER_NAME);
      mailFolder.setCreateDate(createdDate);
      mailFolder.setUpdateDate(createdDate);
      mailFolder.setParentFolderId(rootSendFolder.getFolderId());
      mailFolder.setFolderType(FOLDER_TYPE_DRAFT);
      mailFolder.setFolderVolume(0L);
      mailFolder.setFolderKind(FOLDER_KIND_SEND);
      dataContext.commitChanges();

      // デフォルトのフォルダID
      mailAccount.setDefaultFolderId(mailDefaultFolder.getFolderId());
      mailAccount.setDefaultSendFolderId(mailDefaultSendFolder.getFolderId());
      mailAccount.setCreateDate(createdDate);

      // add start 2012.2.24 受入障害No.294
      mailAccount.setAccountUsage(accountUsage);
      // add end 2012.2.24
      dataContext.commitChanges();

      // コミット
      Database.commit();

      // イベントログに保存
      ALEventlogFactoryService.getInstance().getEventlogHandler().log(
        mailAccount.getAccountId(),
        ALEventlogConstants.PORTLET_TYPE_WEBMAIL_ACCOUNT,
        mailAccount.getAccountName());

      // change start
      // } catch (Throwable t) {
    } catch (Exception e) {
      // change end
      Database.rollback();
      // change start
      // logger.error(t);
      // return false;
      throw e;
      // change end

      // add by motegi start
    } finally {
      // 自己管理トランザクションを標準のトランザクションに戻します。
      Transaction.bindThreadTransaction(baseTx);
      // add by motegi end
    }
    return true;
  }

  public static boolean sendMailDelegateOne(String org_id, int srcUserId, ALEipUserAddr userAddr, String pcSubject, String cellularSubject, String pcBody,
      String cellularBody, int destType, List<String> msgList) throws Exception {

    List<ALEipUserAddr> rcptUsers = new ArrayList<ALEipUserAddr>();
    rcptUsers.add(userAddr);

    return sendMailDelegate(org_id, srcUserId, rcptUsers, pcSubject, cellularSubject, pcBody, cellularBody, destType, msgList);
  }

  /**
   * 
   * @param org_id
   * @param srcUserId
   * @param destMemberList
   * @param pcSubject
   * @param cellularSubject
   * @param pcBody
   * @param cellularBody
   * @param destType
   * @param msgList
   * @return
   * @throws Exception
   * 
   * @deprecated {@link ALMailService#sendAdminMail}
   */
  @Deprecated
  public static boolean sendMailDelegate(String org_id, int srcUserId, List<ALEipUserAddr> destMemberList, String pcSubject, String cellularSubject,
      String pcBody, String cellularBody, int destType, List<String> msgList) throws Exception {

    if (destType < VALUE_MSGTYPE_DEST_NONE || destType > VALUE_MSGTYPE_DEST_PC_CELLULAR) {
      return false;
    }

    if (destMemberList == null || destMemberList.size() == 0) {
      return false;
    }

    // メールの送信
    EipMMailAccount account = getEipMMailAccountForAdmin();
    int successSendToPc = ALSmtpMailSender.SEND_MSG_SUCCESS;
    int successSendToCell = ALSmtpMailSender.SEND_MSG_SUCCESS;

    if (account == null) {
      // メールアカウントがない場合
      if (destType == VALUE_MSGTYPE_DEST_PC) {
        successSendToPc = ALSmtpMailSender.SEND_MSG_FAIL_NO_ACCOUNT;
      } else if (destType == VALUE_MSGTYPE_DEST_CELLULAR) {
        successSendToCell = ALSmtpMailSender.SEND_MSG_FAIL_NO_ACCOUNT;
      } else {
        successSendToPc = ALSmtpMailSender.SEND_MSG_FAIL_NO_ACCOUNT;
        successSendToCell = ALSmtpMailSender.SEND_MSG_FAIL_NO_ACCOUNT;
      }
    } else {
      List<String> destEmailAddrs = new ArrayList<String>();
      List<String> destCellularEMailAddrs = new ArrayList<String>();

      for (ALEipUserAddr userAddr : destMemberList) {
        if (ALEipUtils.isEnabledUser(userAddr.getUserId())) {
          String emailAddr = userAddr.getPcMailAddr();
          if (emailAddr != null && !emailAddr.equals("")) {
            destEmailAddrs.add(emailAddr);
          }
          String cellularEmailAddr = userAddr.getCellMailAddr();
          if (cellularEmailAddr != null && !cellularEmailAddr.equals("")) {
            destCellularEMailAddrs.add(cellularEmailAddr);
          }
        }
      }

      int destEmailAddrsSize = destEmailAddrs.size();
      int destCellularEMailAddrsSize = destCellularEMailAddrs.size();

      ALMailHandler mailhandler = ALMailFactoryService.getInstance().getMailHandler();
      // 送信サーバ情報
      ALMailSenderContext scontext = ALMailUtils.getALSmtpMailSenderContext(org_id, account);

      // パソコンへメールを送信
      if ((destType == VALUE_MSGTYPE_DEST_PC || destType == VALUE_MSGTYPE_DEST_PC_CELLULAR) && (destEmailAddrsSize > 0)) {
        String[] tos = new String[destEmailAddrsSize];
        tos = destEmailAddrs.toArray(tos);

        // 送信メッセージのコンテキスト
        // mod by motegi 開封確認
        // ALSmtpMailContext mailcontext =
        // ALMailUtils.getALSmtpMailContext(
        // tos,
        // null,
        // null,
        // account.getMailAddress(),
        // ALStringUtil.unsanitizing(account.getMailUserName()),
        // ALStringUtil.unsanitizing(pcSubject),
        // ALStringUtil.unsanitizing(pcBody),
        // null,
        // null);
        ALSmtpMailContext mailcontext =
          ALMailUtils.getALSmtpMailContext(tos, null, null, account.getMailAddress(), ALStringUtil.unsanitizing(account.getMailUserName()), ALStringUtil
            .unsanitizing(pcSubject), ALStringUtil.unsanitizing(pcBody), null, null, false, false, false);
        // mod end
        successSendToPc = mailhandler.send(scontext, mailcontext);
      }

      // 携帯電話へメールを送信
      if ((destType == VALUE_MSGTYPE_DEST_CELLULAR || destType == VALUE_MSGTYPE_DEST_PC_CELLULAR) && (destCellularEMailAddrsSize > 0)) {
        String[] tos = new String[destCellularEMailAddrsSize];
        tos = destCellularEMailAddrs.toArray(tos);

        // mod by motegi 開封確認
        // ALSmtpMailContext mailcontext =
        // ALMailUtils.getALSmtpMailContext(
        // tos,
        // null,
        // null,
        // account.getMailAddress(),
        // ALStringUtil.unsanitizing(account.getMailUserName()),
        // ALStringUtil.unsanitizing(cellularSubject),
        // ALStringUtil.unsanitizing(cellularBody),
        // null,
        // null);
        ALSmtpMailContext mailcontext =
          ALMailUtils.getALSmtpMailContext(tos, null, null, account.getMailAddress(), ALStringUtil.unsanitizing(account.getMailUserName()), ALStringUtil
            .unsanitizing(cellularSubject), ALStringUtil.unsanitizing(cellularBody), null, null, false, false, false);
        // mod end

        successSendToCell = mailhandler.send(scontext, mailcontext);
      }
    }

    if (successSendToPc != ALSmtpMailSender.SEND_MSG_SUCCESS) {
      if (successSendToPc == ALSmtpMailSender.SEND_MSG_OVER_MAIL_MAX_SIZE) {
        msgList.add("メールサイズが送信可能サイズよりも大きいため、パソコンのメールアドレスにメールを送信できませんでした。");
      } else if (successSendToPc == ALSmtpMailSender.SEND_MSG_LOCK) {
        msgList.add("ロックがかかっていて、パソコンのメールアドレスにメールを送信できませんでした。");
      } else if (successSendToPc == ALSmtpMailSender.SEND_MSG_FAIL_POP_BEFORE_SMTP_AUTH) {
        msgList.add("Pop before SMTPの認証に失敗したため、パソコンのメールアドレスにメールを送信できませんでした。");
      } else if (successSendToPc == ALSmtpMailSender.SEND_MSG_FAIL_SMTP_AUTH) {
        msgList.add("SMTP認証の認証に失敗したため、パソコンのメールアドレスにメールを送信できませんでした。");
      } else if (successSendToPc == ALSmtpMailSender.SEND_MSG_FAIL_NO_ACCOUNT) {
        msgList.add("管理者のメールアカウントが設定されていないため、パソコンのメールアドレスにメールを送信できませんでした。");
      } else {
        msgList.add("送信メールサーバに接続できなかったため、パソコンのメールアドレスにメールを送信できませんでした。");
      }
    }

    if (successSendToCell != ALSmtpMailSender.SEND_MSG_SUCCESS) {
      if (successSendToCell == ALSmtpMailSender.SEND_MSG_OVER_MAIL_MAX_SIZE) {
        msgList.add("メールサイズが送信可能サイズよりも大きいため、携帯のメールアドレスにメールを送信できませんでした。");
      } else if (successSendToCell == ALSmtpMailSender.SEND_MSG_LOCK) {
        msgList.add("ロックがかかっていて、携帯のメールアドレスにメールを送信できませんでした。");
      } else if (successSendToCell == ALSmtpMailSender.SEND_MSG_FAIL_POP_BEFORE_SMTP_AUTH) {
        msgList.add("Pop before SMTPの認証に失敗したため、携帯のメールアドレスにメールを送信できませんでした。");
      } else if (successSendToCell == ALSmtpMailSender.SEND_MSG_FAIL_SMTP_AUTH) {
        msgList.add("SMTP認証の認証に失敗したため、携帯のメールアドレスにメールを送信できませんでした。");
      } else if (successSendToCell == ALSmtpMailSender.SEND_MSG_FAIL_NO_ACCOUNT) {
        msgList.add("管理者のメールアカウントが設定されていないため、携帯のメールアドレスにメールを送信できませんでした。");
      } else {
        msgList.add("送信メールサーバに接続できなかったため、携帯のメールアドレスにメールを送信できませんでした。");
      }
    }

    return (successSendToPc == ALSmtpMailSender.SEND_MSG_SUCCESS && successSendToCell == ALSmtpMailSender.SEND_MSG_SUCCESS);
  }

  /**
   * 
   * @param org_id
   * @param srcUserId
   * @param destMemberList
   * @param pcSubject
   * @param cellularSubject
   * @param pcBody
   * @param cellularBody
   * @param destType
   * @param msgList
   * @return
   * @throws Exception
   */
  @Deprecated
  public static boolean sendMailDelegate_note(String org_id, int srcUserId, List<ALEipUserAddr> destMemberList, String pcSubject, String cellularSubject,
      String pcBody, String cellularBody, int destType, List<String> msgList) throws Exception {

    if (destType < VALUE_MSGTYPE_DEST_NONE || destType > VALUE_MSGTYPE_DEST_PC_CELLULAR) {
      return false;
    }

    if (destMemberList == null || destMemberList.size() == 0) {
      return false;
    }

    // メールの送信
    EipMMailAccount account = getEipMMailAccountForAdmin();
    int successSendToPc = ALSmtpMailSender.SEND_MSG_SUCCESS;
    int successSendToCell = ALSmtpMailSender.SEND_MSG_SUCCESS;

    if (account == null) {
      // メールアカウントがない場合
      if (destType == VALUE_MSGTYPE_DEST_PC) {
        successSendToPc = ALSmtpMailSender.SEND_MSG_FAIL_NO_ACCOUNT;
      } else if (destType == VALUE_MSGTYPE_DEST_CELLULAR) {
        successSendToCell = ALSmtpMailSender.SEND_MSG_FAIL_NO_ACCOUNT;
      } else {
        successSendToPc = ALSmtpMailSender.SEND_MSG_FAIL_NO_ACCOUNT;
        successSendToCell = ALSmtpMailSender.SEND_MSG_FAIL_NO_ACCOUNT;
      }
    } else {
      List<String> destEmailAddrs = new ArrayList<String>();
      List<String> destCellularEmailAddrs = new ArrayList<String>();

      for (ALEipUserAddr userAddr : destMemberList) {
        if (ALEipUtils.isEnabledUser(userAddr.getUserId())) {
          String emailAddr = userAddr.getPcMailAddr();
          if (emailAddr != null && !emailAddr.equals("")) {
            destEmailAddrs.add(emailAddr);
          }
          String cellularEmailAddr = userAddr.getCellMailAddr();
          if (cellularEmailAddr != null && !cellularEmailAddr.equals("")) {
            destCellularEmailAddrs.add(cellularEmailAddr);
          }
        }
      }

      int destEmailAddrsSize = destEmailAddrs.size();
      int destCellularEmailAddrsSize = destCellularEmailAddrs.size();

      ALMailHandler mailhandler = ALMailFactoryService.getInstance().getMailHandler();
      // 送信サーバ情報
      ALMailSenderContext scontext = ALMailUtils.getALSmtpMailSenderContext(org_id, account);

      // パソコンへメールを送信
      if ((destType == VALUE_MSGTYPE_DEST_PC || destType == VALUE_MSGTYPE_DEST_PC_CELLULAR) && (destEmailAddrsSize > 0)) {
        String[] tos = new String[destEmailAddrsSize];
        tos = destEmailAddrs.toArray(tos);

        // 送信メッセージのコンテキスト
        // mod by motegi 開封確認
        // ALSmtpMailContext mailcontext =
        // ALMailUtils.getALSmtpMailContext(
        // tos,
        // null,
        // null,
        // account.getMailAddress(),
        // ALStringUtil.unsanitizing(account.getMailUserName()),
        // ALStringUtil.unsanitizing(pcSubject),
        // ALStringUtil.unsanitizing(pcBody),
        // null,
        // null);
        ALSmtpMailContext mailcontext =
          ALMailUtils.getALSmtpMailContext(tos, null, null, account.getMailAddress(), ALStringUtil.unsanitizing(account.getMailUserName()), ALStringUtil
            .unsanitizing(pcSubject), ALStringUtil.unsanitizing(pcBody), null, null, false, false, false);
        // mod end

        successSendToPc = mailhandler.send(scontext, mailcontext);
      }
      // PCへ送信するにチェックはしてあるが, 送信先PCのアドレスが未登録
      if (((destType == VALUE_MSGTYPE_DEST_PC) || (destType == VALUE_MSGTYPE_DEST_PC_CELLULAR)) && destEmailAddrsSize <= 0) {
        successSendToPc = -1;
      }

      // 携帯電話へメールを送信
      if (((destType == VALUE_MSGTYPE_DEST_CELLULAR) || (destType == VALUE_MSGTYPE_DEST_PC_CELLULAR)) && (destCellularEmailAddrsSize > 0)) {
        String[] tos = new String[destCellularEmailAddrsSize];
        tos = destCellularEmailAddrs.toArray(tos);

        // mod by motegi 開封確認
        // ALSmtpMailContext mailcontext =
        // ALMailUtils.getALSmtpMailContext(
        // tos,
        // null,
        // null,
        // account.getMailAddress(),
        // ALStringUtil.unsanitizing(account.getMailUserName()),
        // ALStringUtil.unsanitizing(cellularSubject),
        // ALStringUtil.unsanitizing(cellularBody),
        // null,
        // null);
        ALSmtpMailContext mailcontext =
          ALMailUtils.getALSmtpMailContext(tos, null, null, account.getMailAddress(), ALStringUtil.unsanitizing(account.getMailUserName()), ALStringUtil
            .unsanitizing(cellularSubject), ALStringUtil.unsanitizing(cellularBody), null, null, false, false, false);
        // mod end

        successSendToCell = mailhandler.send(scontext, mailcontext);

      }
      // 携帯へ送信するにチェックはしてあるが, 送信先携帯のアドレスが未登録
      if (((destType == VALUE_MSGTYPE_DEST_CELLULAR) || (destType == VALUE_MSGTYPE_DEST_PC_CELLULAR)) && destCellularEmailAddrsSize <= 0) {
        successSendToCell = -1;
      }
    }

    if (successSendToPc != ALSmtpMailSender.SEND_MSG_SUCCESS) {
      if (successSendToPc == ALSmtpMailSender.SEND_MSG_OVER_MAIL_MAX_SIZE) {
        msgList.add("メールサイズが送信可能サイズよりも大きいため、パソコンのメールアドレスにメールを送信できませんでした。");
      } else if (successSendToPc == ALSmtpMailSender.SEND_MSG_LOCK) {
        msgList.add("ロックがかかっていて、パソコンのメールアドレスにメールを送信できませんでした。");
      } else if (successSendToPc == ALSmtpMailSender.SEND_MSG_FAIL_POP_BEFORE_SMTP_AUTH) {
        msgList.add("Pop before SMTPの認証に失敗したため、パソコンのメールアドレスにメールを送信できませんでした。");
      } else if (successSendToPc == ALSmtpMailSender.SEND_MSG_FAIL_SMTP_AUTH) {
        msgList.add("SMTP認証の認証に失敗したため、パソコンのメールアドレスにメールを送信できませんでした。");
      } else if (successSendToPc == ALSmtpMailSender.SEND_MSG_FAIL_NO_ACCOUNT) {
        msgList.add("管理者のメールアカウントが設定されていないため、パソコンのメールアドレスにメールを送信できませんでした。");
      } else if (successSendToPc == -1) {
        msgList.add("送信先のメールアカウントが設定されていないため、パソコンのメールアドレスにメールを送信できませんでした。");
      } else {
        msgList.add("送信メールサーバに接続できなかったため、パソコンのメールアドレスにメールを送信できませんでした。");
      }
    }

    if (successSendToCell != ALSmtpMailSender.SEND_MSG_SUCCESS) {
      if (successSendToCell == ALSmtpMailSender.SEND_MSG_OVER_MAIL_MAX_SIZE) {
        msgList.add("メールサイズが送信可能サイズよりも大きいため、携帯のメールアドレスにメールを送信できませんでした。");
      } else if (successSendToCell == ALSmtpMailSender.SEND_MSG_LOCK) {
        msgList.add("ロックがかかっていて、携帯のメールアドレスにメールを送信できませんでした。");
      } else if (successSendToCell == ALSmtpMailSender.SEND_MSG_FAIL_POP_BEFORE_SMTP_AUTH) {
        msgList.add("Pop before SMTPの認証に失敗したため、携帯のメールアドレスにメールを送信できませんでした。");
      } else if (successSendToCell == ALSmtpMailSender.SEND_MSG_FAIL_SMTP_AUTH) {
        msgList.add("SMTP認証の認証に失敗したため、携帯のメールアドレスにメールを送信できませんでした。");
      } else if (successSendToCell == ALSmtpMailSender.SEND_MSG_FAIL_NO_ACCOUNT) {
        msgList.add("管理者のメールアカウントが設定されていないため、携帯のメールアドレスにメールを送信できませんでした。");
      } else if (successSendToCell == -1) {
        msgList.add("送信先の携帯メールアドレスが設定されていないため、携帯のメールアドレスにメールを送信できませんでした。");
      } else {
        msgList.add("送信メールサーバに接続できなかったため、携帯のメールアドレスにメールを送信できませんでした。");
      }
    }

    return (successSendToPc == ALSmtpMailSender.SEND_MSG_SUCCESS && successSendToCell == ALSmtpMailSender.SEND_MSG_SUCCESS);
  }

  public static ALEipUserAddr getALEipUserAddrByUserId(int userId) {
    try {
      ALEipUserAddr userAddress = new ALEipUserAddr();
      TurbineUser user = ALEipUtils.getTurbineUser(userId);

      userAddress.setUserId(user.getUserId());
      userAddress.setPcMailAddr(user.getEmail());
      userAddress.setCellMailAddr(user.getCellularMail());
      // add start
      userAddress.setLoginName(user.getLoginName());
      userAddress.setLastName(user.getLastName());
      userAddress.setFirstName(user.getFirstName());
      userAddress.setDisplayName(user.getDisplayName());
      // add end

      return userAddress;
    } catch (ALDBErrorException e) {
      logger.error(e);
      return null;
    }

  }

  /**
   * ALEipUserのリストをもとに、ALEipUserAddrのリストを取得する。
   * 
   * @param memberList
   * @param loginUserId
   * @param includeLoginUser
   * @return
   */
  public static List<ALEipUserAddr> getALEipUserAddrs(List<ALEipUser> memberList, int loginUserId, boolean includeLoginUser) {
    List<ALEipUserAddr> resList = new ArrayList<ALEipUserAddr>();

    ALEipUserAddr useraddr = null;
    int membersize = memberList.size();
    for (int i = 0; i < membersize; i++) {
      ALEipUser user = memberList.get(i);
      if (!includeLoginUser && (user.getUserId().getValue() == loginUserId)) {
        // ログインユーザをメール送信先から外す
        continue;
      }
      try {
        ALBaseUser baseuser = (ALBaseUser) JetspeedSecurity.getUser(user.getName().getValue());
        useraddr = new ALEipUserAddr();
        useraddr.setUserId(Integer.valueOf(baseuser.getUserId()));
        useraddr.setPcMailAddr(baseuser.getEmail());
        useraddr.setCellMailAddr(baseuser.getCellularMail());
        useraddr.setDisplayName(baseuser.getDisplayName());
        resList.add(useraddr);
      } catch (Exception ex) {
        logger.error("Exception", ex);
      }
    }

    return resList;
  }

  /**
   * メール通知設定表から送信先の設定を取得する。
   * 
   * @param keyMsgtype
   * @return
   */
  public static int getSendDestType(int keyMsgtype) {
    try {
      SelectQuery<EipMMailNotifyConf> query = Database.query(EipMMailNotifyConf.class);

      Expression exp1 = ExpressionFactory.matchExp(EipMMailNotifyConf.USER_ID_PROPERTY, Integer.valueOf(1));
      Expression exp2 = ExpressionFactory.matchExp(EipMMailNotifyConf.NOTIFY_TYPE_PROPERTY, Integer.valueOf(keyMsgtype));
      EipMMailNotifyConf mail_notify_conf = query.andQualifier(exp1).andQualifier(exp2).fetchSingle();

      if (mail_notify_conf == null) {
        logger.debug("[ALMailUtils] Not found Notify...");
        return VALUE_MSGTYPE_DEST_NONE;
      }
      return mail_notify_conf.getNotifyFlg().intValue();
    } catch (Exception ex) {
      logger.error("Exception", ex);
      return VALUE_MSGTYPE_DEST_NONE;
    }
  }

  /**
   * メール通知設定表から送信先の設定を取得する。
   * 
   * @param keyMsgtype
   * @return
   */
  public static boolean setSendDestType(int keyMsgtype, int valueMsgtype) {
    try {
      if (valueMsgtype < VALUE_MSGTYPE_DEST_NONE || valueMsgtype > VALUE_MSGTYPE_DEST_PC_CELLULAR) {
        return false;
      }

      SelectQuery<EipMMailNotifyConf> query = Database.query(EipMMailNotifyConf.class);

      Expression exp1 = ExpressionFactory.matchExp(EipMMailNotifyConf.NOTIFY_TYPE_PROPERTY, Integer.valueOf(keyMsgtype));
      EipMMailNotifyConf mail_notify_conf = query.andQualifier(exp1).fetchSingle();

      if (mail_notify_conf == null) {
        logger.debug("[ALMailUtils] Not found Notify...");
        return false;
      }
      mail_notify_conf.setNotifyFlg(valueMsgtype);
      Database.commit();
    } catch (Throwable t) {
      Database.rollback();
      logger.error(t);
      return false;
    }
    return true;
  }

  public static String getGlobalurl() {
    EipMCompany record = ALEipUtils.getEipMCompany("1");
    return ALServletUtils.getAccessUrl(record.getIpaddress(), record.getPort().intValue(), true);
  }

  public static String getLocalurl() {
    EipMCompany record = ALEipUtils.getEipMCompany("1");
    String localurl = "";

    try {
      String ipaddress = record.getIpaddressInternal();
      if (null == ipaddress || "".equals(ipaddress)) {
        Enumeration<NetworkInterface> enuIfs = NetworkInterface.getNetworkInterfaces();
        if (null != enuIfs) {
          while (enuIfs.hasMoreElements()) {
            NetworkInterface ni = enuIfs.nextElement();
            Enumeration<InetAddress> enuAddrs = ni.getInetAddresses();
            while (enuAddrs.hasMoreElements()) {
              InetAddress in4 = enuAddrs.nextElement();
              if (!in4.isLoopbackAddress()) {
                ipaddress = in4.getHostAddress();
              }
            }
          }
        }
      }
      Integer port_internal = record.getPortInternal();
      if (null == port_internal) {
        port_internal = 80;
      }
      localurl = ALServletUtils.getAccessUrl(ipaddress, port_internal, false);
    } catch (SocketException e) {
      logger.error(e);
    }
    return localurl;
  }

  /**
   * 指定されたIDのメール通知設定表を取得します。
   * 
   * @param category_id
   * @return
   */
  public static EipMMailNotifyConf getEipMMailNotifyConf(int conf_id) {
    try {
      EipMMailNotifyConf result = Database.get(EipMMailNotifyConf.class, conf_id);

      if (result == null) {
        logger.debug("[ALMailUtils] Not found ID...");
        return null;
      }
      return result;
    } catch (Exception ex) {
      logger.error("Exception", ex);
      return null;
    }
  }

  public static boolean setNotifyTime(int hour, int minute) {
    StringBuffer sb = new StringBuffer();
    if (hour < 10) {
      sb.append("0");
    }
    sb.append(Integer.toString(hour)).append(":");
    if (minute < 10) {
      sb.append("0");
    }
    sb.append(Integer.toString(minute)).append(":00");
    Time time = Time.valueOf(sb.toString());

    try {
      EipMMailNotifyConf conf = getEipMMailNotifyConf(1);
      if (conf == null) {
        return false;
      }

      conf.setNotifyTime(time);
      Database.commit();
      return true;
    } catch (Throwable t) {
      Database.rollback();
      logger.error(t);
      return false;
    }
  }

  public static String getNotifyTime() {
    try {
      EipMMailNotifyConf conf = getEipMMailNotifyConf(1);
      if (conf == null) {
        return null;
      }

      Date date = conf.getNotifyTime();
      Calendar cal = Calendar.getInstance();
      cal.setTime(date);

      StringBuffer sb = new StringBuffer();
      int hour = cal.get(Calendar.HOUR_OF_DAY);
      int minute = cal.get(Calendar.MINUTE);
      if (hour < 10) {
        sb.append("0");
      }
      sb.append(hour).append(":");
      if (minute < 10) {
        sb.append("0");
      }
      sb.append(minute);

      return sb.toString();
    } catch (Exception e) {
      logger.error("error", e);
      return null;
    }
  }

  /**
   * フォルダオブジェクトモデルを取得します。 <BR>
   * 
   * @param rundata
   * @param context
   * @return
   * @throws Exception
   */
  public static List<EipTMailFolder> getEipTMailFolderAll(EipMMailAccount account) throws Exception {
    try {
      if (account == null) {
        // アカウントが空の場合
        logger.debug("[WebMail Folder] Empty Account...");
        // change start
        throw new Exception("アカウントが渡されていません。");
        // return null;
        // change end
      }
      // change start
      // SelectQuery<EipTMailFolder> query =
      // Database.query(EipTMailFolder.class);
      //
      // Expression exp =
      // ExpressionFactory.matchDbExp(
      // EipTMailFolder.EIP_MMAIL_ACCOUNT_PROPERTY,
      // account);
      // List<EipTMailFolder> folder_list =
      // query.andQualifier(exp).orderAscending(
      // EipTMailFolder.FOLDER_NAME_PROPERTY).fetchList();
      //
      // if (folder_list == null || folder_list.size() == 0) {
      // logger.debug("[WebMail Folder] Not found ID...");
      // return null;
      // }
      //
      // // 受信トレイを先頭に配置する
      // List<EipTMailFolder> res = new ArrayList<EipTMailFolder>();
      // for (EipTMailFolder folder : folder_list) {
      // if (folder.getFolderName().equals(EipTMailFolder.DEFAULT_FOLDER_NAME))
      // {
      // EipTMailFolder inbox = folder;
      // folder_list.remove(folder);
      // res.add(inbox);
      // res.addAll(folder_list);
      // break;
      // }
      // }
      // return res.size() == 0 ? folder_list : res;

      List<EipTMailFolder> folder_list = new ArrayList<EipTMailFolder>();

      // 受信トレイの全フォルダ取得
      folder_list.addAll(getEipTMailFolderByKind(account, FOLDER_KIND_RECEIVE));
      // 送信トレイの全フォルダ取得
      folder_list.addAll(getEipTMailFolderByKind(account, FOLDER_KIND_SEND));
      // change end

      return folder_list;
    } catch (Exception ex) {
      logger.error("Exception", ex);
      // change start
      throw ex;
      // return null;
      // change end
    }
  }

  /**
   * フォルダオブジェクトモデルを取得します。 <BR>
   * 
   * @param rundata
   * @param context
   * @return
   * @throws Exception
   */
  public static List<EipTMailFolder> getEipTMailFolderByKind(EipMMailAccount account, String folder_kind) throws Exception {
    try {
      if (account == null) {
        // アカウントが空の場合
        logger.debug("[WebMail Folder] Empty Account...");
        // change start
        throw new Exception("アカウントが渡されていません。");
        // return null;
        // change end
      }

      SelectQuery<EipTMailFolder> query = Database.query(EipTMailFolder.class);

      Expression exp = ExpressionFactory.matchDbExp(EipTMailFolder.EIP_MMAIL_ACCOUNT_PROPERTY, account);
      // change start
      Expression exp2 = ExpressionFactory.matchExp(EipTMailFolder.FOLDER_KIND_PROPERTY, folder_kind);

      List<EipTMailFolder> folder_list =
        query
          .andQualifier(exp)
          .andQualifier(exp2)
          .orderAscending(EipTMailFolder.FOLDER_TYPE_PROPERTY)
          .orderAscending(EipTMailFolder.FOLDER_NAME_PROPERTY)
          .fetchList();

      if (folder_list == null || folder_list.size() == 0) {
        logger.debug("[WebMail Folder] Not found ID...");
        throw new Exception("指定されたメールフォルダがデータベースにありません。アカウントID=" + account.getAccountId() + " フォルダ種別=" + folder_kind);
        // return null;
      }

      // 受信トレイまたは送信トレイを先頭に配置する
      List<EipTMailFolder> res = new ArrayList<EipTMailFolder>();
      for (EipTMailFolder folder : folder_list) {
        if ((folder.getFolderName().equals(EipTMailFolder.DEFAULT_FOLDER_NAME)) || (folder.getFolderName().equals(EipTMailFolder.DEFAULT_SEND_FOLDER_NAME))) {
          EipTMailFolder inbox = folder;
          folder_list.remove(folder);
          res.add(inbox);
          res.addAll(folder_list);
          break;
        }
      }
      // change end
      return res.size() == 0 ? folder_list : res;
    } catch (Exception ex) {
      // change start
      logger.error("Exception", ex);
      throw ex;
      // return null;
      // change end
    }
  }

  /**
   * 受信メール取得
   * <p>
   * 指定されたフォルダに入っている受信メールを全て取得します。 <BR>
   * 
   * @param folder
   *            メールフォルダオブジェクト
   * @return List<EipTMail> 受信メール情報リストを返します。
   * @throws Exception
   *             異常発生時にスローします。
   */
  public static List<EipTMail> getEipTMails(EipTMailFolder folder) throws Exception {
    try {
      if (folder == null) {
        logger.debug("[WebMail Folder] Empty Folder...");
        // change start
        throw new Exception("フォルダが渡されていません。");
        // return null;
        // change end
      }
      SelectQuery<EipTMail> query = Database.query(EipTMail.class);

      // change start
      Expression exp =
      // ExpressionFactory.matchDbExp(EipTMail.FOLDER_ID_PROPERTY, folder
        // .getFolderId());
        ExpressionFactory.matchExp(EipTMail.FOLDER_ID_PROPERTY, folder.getFolderId());
      // change end
      List<EipTMail> mail_list = query.andQualifier(exp).fetchList();

      if (mail_list == null || mail_list.size() == 0) {
        logger.debug("[WebMail Folder] No Mail in the Folder...");
        return null;
      }
      return mail_list;
    } catch (Exception ex) {
      logger.error("Exception", ex);
      // change start
      throw ex;
      // return null;
    }
  }

  // add start
  /**
   * 送信メール取得
   * <p>
   * 指定されたフォルダに入っている送信メールを全て取得します。 <BR>
   * 
   * @param folder
   *            メールフォルダオブジェクト
   * @return List<AvzTMailSend> 送信メール情報リストを返します。
   * @throws Exception
   *             異常発生時にスローします。
   */
  public static List<AvzTMailSend> getEipTMailsSend(EipTMailFolder folder) throws Exception {
    try {
      if (folder == null) {
        logger.debug("[WebMail Folder] Empty Folder...");
        throw new Exception("フォルダが渡されていません。");
      }
      SelectQuery<AvzTMailSend> query = Database.query(AvzTMailSend.class);

      Expression exp = ExpressionFactory.matchExp(AvzTMailSend.FOLDER_ID_PROPERTY, folder.getFolderId());
      List<AvzTMailSend> mail_list = query.andQualifier(exp).fetchList();

      if (mail_list == null || mail_list.size() == 0) {
        logger.debug("[WebMail Folder] No Mail in the Folder...");
        return null;
      }
      return mail_list;
    } catch (Exception ex) {
      logger.error("Exception", ex);
      throw ex;
    }
  }

  // add end

  /**
   * フィルタオブジェクトモデルを取得します。（アカウントで検索） <BR>
   * 
   * @param rundata
   * @param context
   * @return
   */
  public static List<EipTMailFilter> getEipTMailFilters(EipMMailAccount mailAccount) {
    try {
      SelectQuery<EipTMailFilter> query = Database.query(EipTMailFilter.class);

      Expression exp = ExpressionFactory.matchExp(EipTMailFilter.EIP_MMAIL_ACCOUNT_PROPERTY, mailAccount);
      List<EipTMailFilter> filter_list = query.andQualifier(exp).orderAscending(EipTMailFilter.SORT_ORDER_PROPERTY).fetchList();

      if (filter_list == null || filter_list.size() == 0) {
        logger.debug("[WebMail Filter] Not found ID...");
        return null;
      }
      return filter_list;
    } catch (Exception ex) {
      logger.error("Exception", ex);
      return null;
    }
  }

  /**
   * メールがフィルタの条件(件名、送信元メールアドレス、送信先メールアドレス)に合致するかどうか調べます。
   * 
   * @param mailFilter
   * @param subject
   * @param from
   * @param receivers
   * @return boolean
   */
  public static boolean isMatchFilter(EipTMailFilter mailFilter, String subject, String from, Address[] receivers) {
    String filterType = mailFilter.getFilterType();
    String filterString = mailFilter.getFilterString();
    // int dstFolderId = mailFilter.getEipTMailFolder().getFolderId();

    if (FILTER_TYPE_DOMAIN.equals(filterType)) {
      // ドメインを含む
      try {
        String[] domainArray = from.split("@");
        String domain = domainArray[domainArray.length - 1];
        return domain.toLowerCase().contains(filterString.toLowerCase());
      } catch (Exception e) {
        return false;
      }
    } else if (FILTER_TYPE_MAILADDRESS.equals(filterType)) {
      // メールアドレスを含む
      String[] mailAddrArray = from.split("<");
      String mailAddr = mailAddrArray[mailAddrArray.length - 1];
      return mailAddr.toLowerCase().contains(filterString.toLowerCase());

    } else if (FILTER_TYPE_SUBJECT.equals(filterType)) {
      // 件名を含む
      return decodeSubject(subject).toLowerCase().contains(filterString.toLowerCase());
    } else if (FILTER_TYPE_TO.equals(filterType)) {
      for (Address address : receivers) {
        String addressStr = address.toString();
        String[] mailAddrArray = addressStr.split("<");
        String mailAddr = mailAddrArray[mailAddrArray.length - 1];
        boolean result = mailAddr.toLowerCase().contains(filterString.toLowerCase());
        if (result) {
          return true;
        }
      }
      return false;
    }

    return false;
  }

  /**
   * フィルタタイプの一覧を取得します。 <BR>
   * 
   * @param rundata
   * @param context
   * @return
   */
  public static Map<String, String> getMailFilterTypeMap() {
    Map<String, String> typeMap = new TreeMap<String, String>();
    typeMap.put(FILTER_TYPE_MAILADDRESS, "送信元（From）");
    typeMap.put(FILTER_TYPE_TO, "送信先（To）");
    // ドメインは送信元に包括されるのでコメントアウト
    // typeMap.put(FILTER_TYPE_DOMAIN, "ドメイン");
    typeMap.put(FILTER_TYPE_SUBJECT, "件名");

    return typeMap;
  }

  /**
   * 件名のデコードを行ないます。
   * 
   * @param subject
   * @return
   */
  // change start 運用フェーズ障害128
  // public static String decodeSubject(String subject) {
  public static String decodeSubjectBase(String subject) {
    // change end
    try {
      // change start 2011/12/20 IBM拡張文字に対する対応
      // subject = MimeUtility.decodeText(MimeUtility.unfold(subject));
      // MimeUtility.decodeTextメソッドをカスタマイズしたdecodeTextを呼ぶ
      if (subject == null || subject.equals("")) {
        subject = "";
        return subject;
      }
      subject = decodeText(MimeUtility.unfold(subject));
      // change end
      return UnicodeCorrecter.correctToCP932(MailUtility.decodeText(subject));
      // change start 2012.1.11
      // 件名がQエンコード、もしくはBase64エンコード以外の形式のメールを受信した場合
      // RunTimeExceptionが発生し、後続処理が止まってしまう不具合対応
      // } catch (UnsupportedEncodingException e) {
      // return MailUtility.decodeText(subject);
      // }
    } catch (UnsupportedEncodingException e) {
      logger.error("メールの件名デコード処理に失敗しました 件名:" + subject);
      return "";
    }
    // change end
  }

  // add start 運用フェーズ障害128
  /**
   * 件名のデコード処理（NULLコードの置換を行なう）
   * 
   * @param subject
   *            件名
   * 
   */
  public static String decodeSubject(String subject) {
    return decodeSubjectBase(subject).replace("\0", REPLACE_NULL_CHAR);
  }

  // add end

  // add start
  /**
   * メールアカウントを取得する．
   * 
   * @param userId
   * @param accountId
   * @return
   * @throws Exception
   */
  public static EipMMailAccount getMailAccount(int accountId) throws Exception {

    try {
      if (accountId < 0) {
        throw new Exception("エンティティIDが渡されていません。");
      }

      SelectQuery<EipMMailAccount> query = Database.query(EipMMailAccount.class);
      Expression exp2 = ExpressionFactory.matchDbExp(EipMMailAccount.ACCOUNT_ID_PK_COLUMN, Integer.valueOf(accountId));

      EipMMailAccount account = query.andQualifier(exp2).fetchSingle();
      if (account == null) {
        logger.debug("[WebMail] Not found AccountID...");
        throw new Exception("指定されたメールアカウントがデータベースにありません。ID=" + accountId);
      }
      return account;
    } catch (Exception ex) {
      throw ex;
    }
  }

  /**
   * フォルダオブジェクトモデルを取得します。 <BR>
   * 
   * @param rundata
   * @param context
   * @return
   */
  public static List<EipTMailFolder> getEipTMailFolderAll(EipMMailAccount account, String folder_kind) throws Exception {
    try {
      if (account == null) {
        // アカウントが空の場合
        logger.debug("[WebMail Folder] Empty Account...");
        // change start
        throw new Exception("アカウントが渡されていません。");
        // return null;
        // change end
      }

      SelectQuery<EipTMailFolder> query = Database.query(EipTMailFolder.class);

      Expression exp = ExpressionFactory.matchDbExp(EipTMailFolder.EIP_MMAIL_ACCOUNT_PROPERTY, account);

      Expression exp2 = ExpressionFactory.matchExp(EipTMailFolder.FOLDER_KIND_PROPERTY, folder_kind);

      List<EipTMailFolder> folder_list =
        query
          .andQualifier(exp)
          .andQualifier(exp2)
          .orderAscending(EipTMailFolder.FOLDER_TYPE_PROPERTY)
          .orderAscending(EipTMailFolder.FOLDER_NAME_PROPERTY)
          .fetchList();

      if (folder_list == null || folder_list.size() == 0) {
        logger.debug("[WebMail Folder] Not found ID...");
        throw new Exception("指定されたメールフォルダがデータベースにありません。アカウントID=" + account.getAccountId() + " フォルダ種別=" + folder_kind);
        // return null;
      }

      // 受信トレイを先頭に配置する
      List<EipTMailFolder> res = new ArrayList<EipTMailFolder>();
      for (EipTMailFolder folder : folder_list) {
        if (folder.getFolderName().equals(EipTMailFolder.DEFAULT_FOLDER_NAME)) {
          EipTMailFolder inbox = folder;
          folder_list.remove(folder);
          res.add(inbox);
          res.addAll(folder_list);
          break;
        }
      }
      return res.size() == 0 ? folder_list : res;
    } catch (Exception ex) {
      logger.error("Exception", ex);
      throw ex;
      // return null;
    }
  }

  /**
   * フォルダオブジェクトモデル(携帯向け)を取得します。 <BR>
   * 
   * @param rundata
   * @param context
   * @return
   */
  public static List<EipTMailFolder> getEipTMailFolderAllForMobile(EipMMailAccount account, String folder_kind) throws Exception {
    try {
      if (account == null) {
        // アカウントが空の場合
        logger.debug("[WebMail Folder] Empty Account...");
        // change start
        throw new Exception("アカウントが渡されていません。");
        // return null;
        // change end
      }

      SelectQuery<EipTMailFolder> query = Database.query(EipTMailFolder.class);

      Expression exp = ExpressionFactory.matchDbExp(EipTMailFolder.EIP_MMAIL_ACCOUNT_PROPERTY, account);

      Expression exp2 = ExpressionFactory.matchExp(EipTMailFolder.FOLDER_KIND_PROPERTY, folder_kind);

      Expression exp3 = ExpressionFactory.noMatchExp(EipTMailFolder.FOLDER_TYPE_PROPERTY, FOLDER_TYPE_DRAFT);

      List<EipTMailFolder> folder_list =
        query.andQualifier(exp).andQualifier(exp2).andQualifier(exp3).orderAscending(EipTMailFolder.FOLDER_TYPE_PROPERTY).orderAscending(
          EipTMailFolder.FOLDER_NAME_PROPERTY).fetchList();

      if (folder_list == null || folder_list.size() == 0) {
        logger.debug("[WebMail Folder] Not found ID...");
        throw new Exception("指定されたメールフォルダがデータベースにありません。アカウントID=" + account.getAccountId() + " フォルダ種別=" + folder_kind);
        // return null;
      }

      // 受信トレイを先頭に配置する
      List<EipTMailFolder> res = new ArrayList<EipTMailFolder>();
      for (EipTMailFolder folder : folder_list) {
        if (folder.getFolderName().equals(EipTMailFolder.DEFAULT_FOLDER_NAME)) {
          EipTMailFolder inbox = folder;
          folder_list.remove(folder);
          res.add(inbox);
          res.addAll(folder_list);
          break;
        }
      }
      return res.size() == 0 ? folder_list : res;
    } catch (Exception ex) {
      logger.error("Exception", ex);
      throw ex;
      // return null;
    }
  }

  /**
   * 改行コードを含む文字列を、複数行に分割します。
   * <p>
   * 
   * @return
   */
  public static String getMessageList(String msgline, boolean isFromAipoSchedulePortlet, boolean isSSL, String myUrl, String mediatype) {
    StringBuffer sb = new StringBuffer();
    ALStringField field = null;

    if (msgline == null || msgline.equals("")) {
      return "";
    }
    if (msgline.indexOf("\r") < 0 && msgline.indexOf("\n") < 0 && msgline.indexOf("\r\n") < 0) {
      field = new ALStringField();
      field.setTrim(false);
      field.setValue(msgline);
      return ALCommonUtils.replaceToAutoCR(replaceStrToLink(field.toString(), isFromAipoSchedulePortlet, isSSL, myUrl, mediatype, true));
    }

    String token = null;
    BufferedReader reader = null;
    try {
      reader = new BufferedReader(new StringReader(msgline));
      while ((token = reader.readLine()) != null) {
        field = new ALStringField();
        field.setTrim(false);
        field.setValue(token);
        // change start
        // sb.append(
        // ALCommonUtils.replaceToAutoCR(replaceStrToLink(
        // ALEipUtils.replaseLeftSpace(field.toString()),
        // isFromAipoSchedulePortlet,
        // isSSL,
        // myUrl,
        // mediatype))).append("<br/>");
        if (!isFromAipoSchedulePortlet) {
          sb.append(
            ALCommonUtils.replaceToAutoCR(replaceStrToLink(
              ALEipUtils.replaseLeftSpace(field.toString()),
              isFromAipoSchedulePortlet,
              isSSL,
              myUrl,
              mediatype,
              true))).append("<br/>");
        } else {
          String tmp = replaceStrToLink(ALEipUtils.replaseLeftSpace(field.toString()), isFromAipoSchedulePortlet, isSSL, myUrl, mediatype, true);
          if (tmp != null) {
            sb.append(
              ALCommonUtils.replaceToAutoCR(replaceStrToLink(
                ALEipUtils.replaseLeftSpace(field.toString()),
                isFromAipoSchedulePortlet,
                isSSL,
                myUrl,
                mediatype,
                true))).append("<br/>");
          }

        }
        // change end
      }
      reader.close();
    } catch (IOException ioe) {
      try {
        reader.close();
      } catch (IOException e) {
      }
      return "";
    }

    int index = sb.lastIndexOf("<br/>");
    if (index == -1) {
      return sb.toString();
    }
    return sb.substring(0, index);
  }

  /**
   * 文字列内のリンクにタグAを追加します。
   * <p>
   * Aタグの色をblueにします。<BR>
   * target=_blankとして別ウィンドウで開きます。<BR>
   * 
   * @param msg
   * @return
   */
  public static String replaceStrToLink(String msg, boolean isFromAipoSchedulePortlet, boolean isSSL, String myUrl, String mediatype, boolean doLinked) {

    if (msg != null) {
      String newMsg = "";
      if (isFromAipoSchedulePortlet) {
        // スケジュールポートレットからの会議案内系メール

        if (isSSL) {
          // HTTPS通信
          // change start 運用フェーズ課題・障害台帳No.135対応
          // if (msg.contains("https:")) {
          if (msg.contains("https:")
            && !msg.startsWith(PREFIX_PATTERN_SKIP_PC)
            && !msg.startsWith(PREFIX_PATTERN_REMOVE_BOTH)
            && !msg.startsWith(PREFIX_PATTERN_COMMENT)) {
            // change end
            String[] elements = msg.split("[?]");
            if (elements.length > 1) {
              msg = " " + myUrl + "?" + elements[1];
            }
          }

          if ("html".equals(mediatype)) {

            if (!msg.startsWith(PREFIX_PATTERN_SKIP_PC) && !msg.startsWith(PREFIX_PATTERN_SKIP_BOTH)) {
              // PC向け
              newMsg = msg.replaceFirst(PREFIX_PATTERN_REMOVE_BOTH, "");
              newMsg = newMsg.replaceFirst(PREFIX_PATTERN_SKIP_CEL, "");
              newMsg = newMsg.replaceFirst(PREFIX_PATTERN_COMMENT, "");

              if (doLinked) {
                newMsg =
                  newMsg
                    .replaceAll(
                      "(https|ftp|gopher|telnet|whois|news)\\:([\\w|\\:\\!\\#\\$\\%\\=\\&\\-\\^\\`\\\\|\\@\\~\\[\\{\\]\\}\\;\\+\\*\\,\\.\\?\\/]+)",
                      "<a href=\"javascript:void(0);\" onclick=\"aipo.common.showWindow('$1\\:$2');return false;\" target=\"_blank\" style=\"color:blue\">$1\\:$2</a>");
              }
            } else {
              newMsg = null;
            }
          } else {
            // 携帯・スマホ向け
            if (!msg.startsWith(PREFIX_PATTERN_SKIP_CEL) && !msg.startsWith(PREFIX_PATTERN_SKIP_BOTH)) {
              newMsg = msg.replaceFirst(PREFIX_PATTERN_REMOVE_BOTH, "");
              newMsg = newMsg.replaceFirst(PREFIX_PATTERN_SKIP_PC, "");
              newMsg = newMsg.replaceFirst(PREFIX_PATTERN_COMMENT, "");
            } else {
              newMsg = null;
            }
          }
        } else {
          // HTTP通信
          // change start 運用フェーズ課題・障害台帳No.135対応
          // if (msg.contains("http:")) {
          if (msg.contains("http:")
            && !msg.startsWith(PREFIX_PATTERN_SKIP_PC)
            && !msg.startsWith(PREFIX_PATTERN_REMOVE_BOTH)
            && !msg.startsWith(PREFIX_PATTERN_COMMENT)) {
            // change end
            String[] elements = msg.split("[?]");
            if (elements.length > 1) {
              msg = " " + myUrl + "?" + elements[1];
            }
          }

          if ("html".equals(mediatype)) {

            if (!msg.startsWith(PREFIX_PATTERN_SKIP_PC) && !msg.startsWith(PREFIX_PATTERN_SKIP_BOTH)) {
              // PC向け
              newMsg = msg.replaceFirst(PREFIX_PATTERN_REMOVE_BOTH, "");
              newMsg = newMsg.replaceFirst(PREFIX_PATTERN_SKIP_CEL, "");
              newMsg = newMsg.replaceFirst(PREFIX_PATTERN_COMMENT, "");

              if (doLinked) {
                newMsg =
                  newMsg
                    .replaceAll(
                      "(http|ftp|gopher|telnet|whois|news)\\:([\\w|\\:\\!\\#\\$\\%\\=\\&\\-\\^\\`\\\\|\\@\\~\\[\\{\\]\\}\\;\\+\\*\\,\\.\\?\\/]+)",
                      "<a href=\"javascript:void(0);\" onclick=\"aipo.common.showWindow('$1\\:$2');return false;\" target=\"_blank\" style=\"color:blue\">$1\\:$2</a>");
              }
            } else {
              newMsg = null;
            }
          } else {
            // 携帯・スマホ向け
            if (!msg.startsWith(PREFIX_PATTERN_SKIP_CEL) && !msg.startsWith(PREFIX_PATTERN_SKIP_BOTH)) {
              // newMsg = msg.replaceFirst("下記リンクをクリックして詳細を確認して下さい。", "");
              newMsg = msg.replaceFirst(PREFIX_PATTERN_REMOVE_BOTH, "");
              newMsg = newMsg.replaceFirst(PREFIX_PATTERN_SKIP_PC, "");
              newMsg = newMsg.replaceFirst(PREFIX_PATTERN_COMMENT, "");
            } else {
              newMsg = null;
            }
          }
        }

      } else {
        // 通常のメール
        newMsg =
          msg.replaceAll(
            "(https?|ftp|gopher|telnet|whois|news)\\:([\\w|\\:\\!\\#\\$\\%\\=\\&\\-\\^\\`\\\\|\\@\\~\\[\\{\\]\\}\\;\\+\\*\\,\\.\\?\\/]+)",
            "<a href=\"$1\\:$2\" target=\"_blank\" style=\"color:blue\">$1\\:$2</a>");
      }
      // change start 詳細画面でのメールリンク表示を抑止
      // return newMsg.replaceAll(
      // "[\\w\\.\\-]+@([\\w\\-]+\\.)+[\\w\\-]+",
      // "<a href='mailto:$0'>$0</a>");
      return newMsg;
      // change end
    } else {
      return "";
    }
  }

  // add end

  // add start
  /**
   * フォルダオブジェクトモデルを取得します。
   * <p>
   * 指定されたアカウント、フォルダIDよりフォルダオブジェクトモデルを取得します。 <BR>
   * 
   * @param account
   *            アカウント情報オブジェクト
   * @param folderId
   *            フォルダID
   * @return EipTMailFolder フォルダ情報オブジェクト
   * @throws Exception
   *             異常発生時にスローします。
   */
  public static EipTMailFolder getEipTMailFolder(EipMMailAccount account, String folderId) throws Exception {
    try {
      if (account == null) {
        // アカウントが空の場合
        logger.debug("[WebMail Folder] Empty Account...");
        // change start
        throw new Exception("アカウントが渡されていません。");
        // return null;
        // change end
      }
      if (folderId == null || Integer.valueOf(folderId) == null) {
        // フォルダIDが空の場合、デフォルトのフォルダIDを使う
        folderId = account.getDefaultFolderId().toString();
      }

      SelectQuery<EipTMailFolder> query = Database.query(EipTMailFolder.class);

      Expression exp = ExpressionFactory.matchDbExp(EipTMailFolder.FOLDER_ID_PK_COLUMN, folderId);
      Expression exp2 = ExpressionFactory.matchDbExp(EipTMailFolder.EIP_MMAIL_ACCOUNT_PROPERTY, account);

      EipTMailFolder folder = query.setQualifier(exp.andExp(exp2)).fetchSingle();
      if (folder == null) {
        logger.debug("[WebMail Folder] Not found ID...");
        // change start
        throw new Exception("指定されたメールフォルダがデータベースにありません。アカウントID=" + account.getAccountId() + " フォルダID=" + folderId);
        // return null;
        // change end
      }
      return folder;
    } catch (Exception ex) {
      logger.error("Exception", ex);
      // change start
      throw ex;
      // return null;
      // change end
    }
  }

  /**
   * フォルダ種別、フォルダタイプよりフォルダオブジェクトモデルを取得します。 <BR>
   * 
   * @param account
   *            アカウント情報オブジェクト
   * @param folderKind
   *            フォルダ種別
   * @param folderType
   *            フォルダタイプ
   * @return EipTMailFolder フォルダ情報オブジェクト
   * @throws Exception
   *             異常発生時にスローします。
   */
  public static EipTMailFolder getEipTMailFolderByKindAndType(EipMMailAccount account, String folderKind, String folderType) throws Exception {
    try {
      if (account == null) {
        // アカウントが空の場合
        logger.debug("[WebMail Folder] Empty Account...");
        throw new Exception("アカウントが渡されていません。");
      }
      if (null == folderKind) {
        // フォルダ種別が空の場合
        logger.debug("[WebMail Folder] Empty FolderKind...");
        throw new Exception("フォルダ種別が渡されていません。");
      }

      if (null == folderType) {
        // フォルダタイプが空の場合
        logger.debug("[WebMail Folder] Empty FolderType...");
        throw new Exception("フォルダタイプが渡されていません。");
      }

      SelectQuery<EipTMailFolder> query = Database.query(EipTMailFolder.class);

      Expression exp = ExpressionFactory.matchExp(EipTMailFolder.FOLDER_KIND_PROPERTY, folderKind);
      Expression exp2 = ExpressionFactory.matchExp(EipTMailFolder.FOLDER_TYPE_PROPERTY, folderType);
      Expression exp3 = ExpressionFactory.matchDbExp(EipTMailFolder.EIP_MMAIL_ACCOUNT_PROPERTY, account);

      EipTMailFolder folder = query.setQualifier(exp.andExp(exp2).andExp(exp3)).fetchSingle();
      if (folder == null) {
        logger.debug("[WebMail Folder] Not found ID...");
        throw new Exception("指定されたメールフォルダがデータベースにありません。アカウントID=" + account.getAccountId() + " フォルダ種別=" + folderKind + " フォルダタイプ=" + folderType);
      }
      return folder;
    } catch (Exception ex) {
      // logger.error("Exception", ex);
      throw ex;
    }
  }

  /**
   * 指定されたメールIDで受信メールを取得します。 <BR>
   * 
   * @param mailId
   *            メールID
   * @return EipTMail 受信メール情報オブジェクト
   * @throws Exception
   *             異常発生時にスローします。
   */
  public static EipTMail getEipTMail(String mailId) throws Exception {
    try {
      if (mailId == null) {
        logger.debug("[WebMail mailId] Empty mailId...");
        throw new Exception("メールIDが渡されていません。");
      }
      SelectQuery<EipTMail> query = Database.query(EipTMail.class);

      Expression exp = ExpressionFactory.matchDbExp(EipTMail.MAIL_ID_PK_COLUMN, mailId);
      EipTMail mail = query.andQualifier(exp).fetchSingle();

      if (mail == null) {
        logger.debug("[WebMail] No Mail mailId=" + mailId);
        throw new Exception("指定された受信メールがデータベースにありません。メールID=" + mailId);
      }
      return mail;
    } catch (Exception ex) {
      logger.error("Exception", ex);
      throw ex;
    }
  }

  /**
   * 指定されたメールIDで送信メールを取得します。 <BR>
   * 
   * @param mailId
   *            メールID
   * @return AvzTMailSend 送信メール情報オブジェクト
   * @throws Exception
   *             異常発生時にスローします。
   */
  public static AvzTMailSend getAvzTMailSend(String mailId) throws Exception {
    try {
      if (mailId == null) {
        logger.debug("[WebMail mailId] Empty mailId...");
        throw new Exception("メールIDが渡されていません。");
      }
      SelectQuery<AvzTMailSend> query = Database.query(AvzTMailSend.class);

      Expression exp = ExpressionFactory.matchDbExp(AvzTMailSend.MAIL_ID_PK_COLUMN, mailId);
      AvzTMailSend mail = query.andQualifier(exp).fetchSingle();

      if (mail == null) {
        logger.debug("[WebMail] No Mail mailId=" + mailId);
        throw new Exception("指定された送信メールがデータベースにありません。メールID=" + mailId);
      }
      return mail;
    } catch (Exception ex) {
      logger.error("Exception", ex);
      throw ex;
    }
  }

  /**
   * @param list
   * @return
   */
  public static List<ALExtFolderInfo> getFolderList(List<ALExtFolderInfo> list) {
    try {
      if (list == null || list.size() <= 0) {
        return null;
      }

      List<ALExtFolderInfo> res = new ArrayList<ALExtFolderInfo>();
      int size = list.size();
      for (int i = 0; i < size; i++) {
        ALExtFolderInfo info = list.get(i);
        res.add(info);
        List<ALExtFolderInfo> infos = info.getList();
        List<ALExtFolderInfo> a = getFolderList(infos);
        if (a != null && a.size() > 0) {
          res.addAll(a);
        }
      }
      return res;
    } catch (Exception e) {
      return null;
    }

  }

  /**
   * @param folder_id
   * @param account_id
   * @param folder_kind
   * @return
   */
  public static List<ALExtFolderInfo> getFolderList(int folder_id, int account_id, String folder_kind) {
    try {
      SelectQuery<EipTMailFolder> query = Database.query(EipTMailFolder.class);
      query.orderAscending(EipTMailFolder.FOLDER_TYPE_PROPERTY);
      query.orderAscending(EipTMailFolder.FOLDER_NAME_PROPERTY);

      Expression exp = ExpressionFactory.matchDbExp(EipTMailFolder.EIP_MMAIL_ACCOUNT_PROPERTY + "." + EipMMailAccount.ACCOUNT_ID_PK_COLUMN, account_id);
      query.andQualifier(exp);
      Expression exp2 = ExpressionFactory.matchExp(EipTMailFolder.FOLDER_KIND_PROPERTY, folder_kind);
      query.andQualifier(exp2);

      ResultList<EipTMailFolder> list = query.getResultList();
      if (list == null || list.size() < 0) {
        return null;
      }

      List<ALExtFolderInfo> prerootlist = getExtFolderInfoList(list, folder_id, 0);

      List<ALExtFolderInfo> result = getFolderList(prerootlist);

      return result;
    } catch (Exception e) {
      e.printStackTrace();
      return null;
    }
  }

  /**
   * @param dblist
   * @param parent_id
   * @param hierarchy_index
   * @return
   */
  private static List<ALExtFolderInfo> getExtFolderInfoList(List<EipTMailFolder> dblist, int parent_id, int hierarchy_index) {
    List<ALExtFolderInfo> list = new ArrayList<ALExtFolderInfo>();
    int size = dblist.size();
    for (int i = 0; i < size; i++) {
      EipTMailFolder folder = dblist.get(i);
      if (folder.getParentFolderId().intValue() == parent_id) {
        ALExtFolderInfo info = new ALExtFolderInfo();
        info.setHierarchyIndex(hierarchy_index);
        info.setFolderId(folder.getFolderId().intValue());
        info.setParentFolderId(folder.getParentFolderId().intValue());
        info.setFolderName(folder.getFolderName());
        list.add(info);
      }
    }

    if (list.size() <= 0) {
      return null;
    }

    int size2 = list.size();
    for (int i = 0; i < size2; i++) {
      ALExtFolderInfo info = list.get(i);
      List<ALExtFolderInfo> colist = getExtFolderInfoList(dblist, info.getFolderId(), info.getHierarchyIndex() + 1);
      if (colist != null && colist.size() > 0) {
        info.setList(colist);
      }
    }
    return list;
  }

  /**
   * 指定されたファイルを読み込み，mail メッセージを取得する．
   * 
   * @param fileName
   *            メールファイル名
   * @return メールファイル情報
   * @throws Exception
   */
  public static ALLocalMailMessage readMail(String filepath) throws Exception {
    // change end
    System.setProperty("mail.mime.charset", "ISO-2022-JP");
    System.setProperty("mail.mime.decodetext.strict", "false");
    Properties prop = new Properties();
    prop.setProperty("mail.mime.address.strict", "false");
    ALLocalMailMessage localmsg = null;
    BufferedInputStream input = null;
    try {
      input = new BufferedInputStream(ALStorageService.getFile(filepath));
      localmsg = new ALLocalMailMessage(Session.getDefaultInstance(prop), input);
      input.close();
    } catch (Exception ex) {
      // logger.error("Exception", ex);
      throw ex;
    }
    return localmsg;
  }

  /**
   * 代理受信アカウントリスト取得
   * <p>
   * 指定されたユーザーの代理受信元アカウントのリストを取得する<BR>
   * 
   * @param userId
   *            ユーザーID
   * @return 指定ユーザーの代理受信元アカウントリスト
   * @throws Exception
   */
  public static List<AvzTMailSendRecvAcl> getRepresentReceiveAccount(int userId) throws Exception {

    try {
      // ユーザーの代理受信元アカウント情報取得
      SelectQuery<AvzTMailSendRecvAcl> query = Database.query(AvzTMailSendRecvAcl.class);
      Expression exp1 = ExpressionFactory.matchExp(AvzTMailSendRecvAcl.ACL_TYPE_PROPERTY, "R");
      Expression exp2 = ExpressionFactory.matchExp(AvzTMailSendRecvAcl.TARGET_TYPE_PROPERTY, "U");
      Expression exp3 = ExpressionFactory.matchExp(AvzTMailSendRecvAcl.TARGET_ID_PROPERTY, userId);
      query.setQualifier(exp1);
      query.andQualifier(exp2);
      query.andQualifier(exp3);

      return query.fetchList(); // 代理受信アカウントリスト

    } catch (RuntimeException e) {
      logger.error("代理受信アカウントの取得に失敗しました。ユーザーID=" + userId, e);
      throw e;
    }
  }

  /**
   * 代理受信アカウントチェック
   * <p>
   * アカウントが指定ユーザーの代理受信元アカウントであることを確認する<BR>
   * 
   * @param account
   *            アカウント情報
   * @param userId
   *            ユーザーID
   * @return true:指定ユーザーの代理受信元アカウントである false:指定ユーザーの代理受信元アカウントではない
   * @throws Exception
   */
  public static boolean isRepresentReceiveAccount(EipMMailAccount account, int userId) throws Exception {

    // アカウントのログインユーザーに対する代理受信許可をチェック

    // ユーザーの代理受信元アカウント情報取得
    List<AvzTMailSendRecvAcl> deputyList = getRepresentReceiveAccount(userId);

    boolean isContainsAccount = false;
    // 代理受信アカウントリストの中に指定されたアカウントが含まれていることを確認
    for (int i = 0; i < deputyList.size(); i++) {
      if (account.getAccountId() == deputyList.get(i).getAccountId().intValue()) {
        isContainsAccount = true;
      }
    }
    // 含まれていない（アカウントがログインユーザーの代理受信元ではない）場合
    if (!isContainsAccount) {
      logger.error("指定されたアカウントは不正です。アカウントID=" + account.getAccountId() + " ユーザーID=" + userId);
      return false;
    }

    return true;
  }

  // add end

  // add start 2011/12/20 IBM拡張文字に対する対応
  /**
   * １文字の２バイト Shift_JIS コードを JIS コードに変換して書き出す．
   */
  public static void ibmSjisToJis(ByteArrayOutputStream out, byte bh, byte bl) {
    // NEC拡張文字のJISコードへのマッピング処理
    // IBM拡張文字の115区画から119区画を
    // NEC拡張文字の89区画から92区画までマッピング
    int h = bh & 0xFF;
    int l = bl & 0xFF;

    if ((h == 0xfa) && (l >= 0x40 && l <= 0x49)) {
      // IBM拡張文字FA40からFA49までを
      // NECのIBM拡張文字92区にマッピング
      h -= 0x7e;
      l += 0x31;
    }
    if ((h == 0xfa) && (l >= 0x54 && l <= 0x57)) {
      // IBM拡張文字FA54からFA57までを
      // NECのIBM拡張文字92区にマッピング
      h -= 0x7e;
      l += 0x27;
    }
    if ((h == 0xfa) && (l >= 0x58 && l <= 0x5b)) {
      // IBM拡張文字FA58からFA5Bまでを
      // NECのIBM拡張文字13区にマッピング
      if (l == 0x58) {
        // IBM拡張文字FA58
        h = 0x2d;
        l = 0x6a;
      }
      if (l == 0x59) {
        // IBM拡張文字FA59
        h = 0x2d;
        l = 0x62;
      }
      if (l == 0x5a) {
        // IBM拡張文字FA5A
        h = 0x2d;
        l = 0x64;
      }
      if (l == 0x5b) {
        // IBM拡張文字FA5B
        h = 0x2d;
        l = 0x7a;
      }
    }
    if ((h == 0xfa) && (l >= 0x5c && l <= 0xba)) {
      // IBM拡張文字FA5CからFABAまでを
      // NECのIBM拡張文字89区にマッピング
      if (l <= 0x7e) {
        h -= 0xd;
        l -= 0x1c;
        h -= 0x74;
        l -= 0x1f;
      } else if (l <= 0x9b) {
        h -= 0xd;
        l -= 0x1d;
        h -= 0x74;
        l -= 0x1f;
      } else {
        h -= 0xd;
        l -= 0x1c;
        h -= 0x74;
        l -= 0x20;
      }
    }

    if ((h == 0xfa) && (l >= 0xbb && l <= 0xfc)) {
      // IBM拡張文字FABBからFAFCまでを
      // NECのIBM拡張文字90区にマッピング
      h -= 0x80;
      l -= 0x9a;
    }
    if ((h >= 0xfb) && (l >= 0x40 && l <= 0x5b)) {
      // IBM拡張文字FB40からFB5Bまでを
      // NECのIBM拡張文字90区にマッピング
      h -= 0x81;
      l += 0x23;
    }

    if ((h == 0xfb) && (l >= 0x5c && l <= 0x7e)) {
      // IBM拡張文字FB5CからFB7Eまでを
      // NECのIBM拡張文字91区にマッピング
      h -= 0x80;
      l -= 0x3b;
    }
    if ((h == 0xfb) && (l >= 0x80 && l <= 0x9e)) {
      // IBM拡張文字FB80からFB9Eまでを
      // NECのIBM拡張文字91区にマッピング
      h -= 0x80;
      l -= 0x3c;
    }
    if ((h == 0xfb) && (l >= 0x9f && l <= 0xba)) {
      // IBM拡張文字FB9FからFBBAまでを
      // NECのIBM拡張文字91区にマッピング
      h -= 0x80;
      l -= 0x3c;
    }

    if ((h == 0xfb) && (l >= 0xbb && l <= 0xfc)) {
      // NECのIBM拡張文字92区にマッピング
      h -= 0x7f;
      l -= 0x9a;
    }
    if ((h == 0xfc) && (l >= 0x40 && l <= 0x4b)) {
      // NECのIBM拡張文字92区にマッピング
      h -= 0x7f;
      l -= 0xdd;
    }

    out.write(h);
    out.write(l);
  }

  /**
   * JIS byte[] -> MS932 byte[] 変換を行います
   * 
   * @parum JISのbyte配列
   * @return SJISのbyte配列
   */
  public static byte[] JIStoSJIS(byte[] jis) {
    boolean modeAscii = true; // true:アスキー文字列 false:漢字
    boolean hankakukana = false; // true:半角カナ文字列 false:半角カナ以外
    ByteArrayOutputStream os = new ByteArrayOutputStream();
    for (int cnt = 0, cmax = jis.length; cnt < cmax; cnt++) {
      int c1 = ((jis[cnt]) & 0xff);
      int c2 = (cnt + 1 < cmax) ? ((jis[cnt + 1]) & 0xff) : 0;
      int c3 = (cnt + 2 < cmax) ? ((jis[cnt + 2]) & 0xff) : 0;
      // ESC $ B || ESC $ @
      if ((c1 == 0x1b && c2 == 0x24 && c3 == 0x42) || (c1 == 0x1b && c2 == 0x24 && c3 == 0x40)) {
        cnt += 2;
        modeAscii = false;
        hankakukana = false;
        continue;
      }
      // 0f || ESC ( B || ESC ( J
      else if (c1 == 0x0f || (c1 == 0x1b && c2 == 0x28 && c3 == 0x42) || (c1 == 0x1b && c2 == 0x28 && c3 == 0x4A)) {
        cnt += 2;
        modeAscii = true;
        hankakukana = false;
        continue;
        // 0e || ESC ( I
      } else if (c1 == 0x0e || (c1 == 0x1b && c2 == 0x28 && c3 == 0x49)) {
        cnt += 2;
        modeAscii = true;
        hankakukana = true;
        continue;
      }
      if (modeAscii) {
        // 半角かな対応
        if (hankakukana) {
          _JIStoSJIS_HANKAKUKANA(os, c1);
        } else {
          os.write((byte) c1);
        }
      } else if (c2 != 0) {
        _JIStoSJIS(os, c1, c2);
        cnt++;
      }
    }
    return os.toByteArray();
  }

  /** コード変換 */
  private static void _JIStoSJIS(ByteArrayOutputStream os, int knj1, int knj2) {
    if ((knj1 & 0x01) != 0) {
      knj1 >>= 1;
      if (knj1 < 0x2F) {
        knj1 += 0x71;
      } else {
        knj1 -= 0x4F;
      }
      if (knj2 > 0x5F) {
        knj2 += 0x20;
      } else {
        knj2 += 0x1F;
      }
    } else {
      knj1 >>= 1;
      if (knj1 <= 0x2F) {
        knj1 += 0x70;
      } else {
        knj1 -= 0x50;
      }
      knj2 += 0x7E;
    }
    os.write((byte) knj1);
    os.write((byte) knj2);
  }

  /** コード変換 */
  private static void _JIStoSJIS_HANKAKUKANA(ByteArrayOutputStream os, int hankakukana) {

    hankakukana += 0x80;

    os.write((byte) hankakukana);

  }

  // MimeUtility.decodeTextメソッドをIBM拡張文字対応用に変更する
  public static String decodeText(String etext) throws UnsupportedEncodingException {
    boolean decodeStrict;
    String k = System.getProperty("mail.mime.decodetext.strict");
    decodeStrict = k == null || !k.equalsIgnoreCase("false");

    String lwsp = " \t\n\r";

    if (etext.indexOf("=?") == -1) {
      return etext;
    }

    StringTokenizer st = new StringTokenizer(etext, lwsp, true);
    StringBuffer sb = new StringBuffer();
    StringBuffer wsb = new StringBuffer();
    boolean prevWasEncoded = false;

    while (st.hasMoreTokens()) {
      String s = st.nextToken();
      char c;
      if ((c = s.charAt(0)) == ' ' || c == '\t' || c == '\r' || c == '\n') {
        wsb.append(c);
      } else {
        String word;

        try {
          word = decodeWord(s);
          if (!prevWasEncoded && wsb.length() > 0) {
            sb.append(wsb);
          }

          prevWasEncoded = true;
        } catch (ParseException pex) {
          word = s;

          if (!decodeStrict) {
            word = decodeInnerWords(word);
          }

          if (wsb.length() > 0) {
            sb.append(wsb);
          }
          prevWasEncoded = false;
        }
        sb.append(word);
        wsb.setLength(0);
      }
    }
    return sb.toString();
  }

  public static String decodeWord(String eword) throws ParseException, UnsupportedEncodingException {
    boolean decodeStrict;
    String k = System.getProperty("mail.mime.decodetext.strict");
    decodeStrict = k == null || !k.equalsIgnoreCase("false");
    if (!eword.startsWith("=?")) {
      throw new ParseException();
    }

    int start = 2;
    int pos;
    if ((pos = eword.indexOf('?', start)) == -1) {
      throw new ParseException();
    }
    String charset = MimeUtility.javaCharset(eword.substring(start, pos));

    start = pos + 1;
    if ((pos = eword.indexOf('?', start)) == -1) {
      throw new ParseException();
    }
    String encoding = eword.substring(start, pos);

    start = pos + 1;
    if ((pos = eword.indexOf("?=", start)) == -1) {
      throw new ParseException();
    }
    String word = eword.substring(start, pos);

    try {
      String decodedWord;
      if (word.length() > 0) {

        ByteArrayInputStream bis = new ByteArrayInputStream(ASCIIUtility.getBytes(word));
        InputStream is;

        boolean isQencode = false;
        if (encoding.equalsIgnoreCase("B")) {
          is = new BASE64DecoderStream(bis);
        } else if (encoding.equalsIgnoreCase("Q")) {
          isQencode = true;
          is = new QDecoderStream(bis);
        } else {
          throw new UnsupportedEncodingException("unknown encoding: " + encoding);
        }

        int count = bis.available();
        byte bytes[] = new byte[count];
        count = is.read(bytes, 0, count);

        if (isQencode) {
          // add start 2次開発 要件No.20 キャラクタセットCP932メール対応
          if (ALMailUtils.CP932.equalsIgnoreCase(charset)) {
            charset = WINDOWS_31J;
          }
          // add end
          // change start 2次開発 要件No.20 キャラクタセットCP932メール対応
          // decodedWord = count > 0 ? new String(bytes, 0, count, charset) :
          // "";
          if (UTF_7.equalsIgnoreCase(charset)) {
            charset = WINDOWS_31J;
            decodedWord = getUTF7Subject(new String(bytes, charset));
          } else {
            decodedWord = count > 0 ? new String(bytes, 0, count, charset) : "";
          }
          // change end
        } else {
          // IBM拡張文字対応
          byte[] encodedWordBtye = word.getBytes();
          byte[] decodedWordBtye = Base64.decodeBase64(encodedWordBtye);
          byte[] sjisByte = JIStoSJIS(decodedWordBtye);

          // change start 運用障害83
          // // change start 2012.1.17 受入障害No.216対応
          // // if (!(charset.equals("UTF8"))) {
          // // charset = "Windows-31J";
          // // }
          // // decodedWord = new String(sjisByte, charset);
          // // }
          // boolean isUTF7 = false;
          // boolean isChineseMail = false;
          // if (!(UTF8.equals(charset))) {
          // if (UTF_7.equals(charset)) {
          // isUTF7 = true;
          // } else if (GB2312.equals(charset)
          // || GB18030.equals(charset)
          // || CHARSET_GB2312.equals(charset)
          // || CHARSET_GB18030.equals(charset)) {
          // isChineseMail = true;
          // }
          // charset = WINDOWS_31J;
          // }
          // if (isUTF7) {
          // decodedWord = getUTF7Subject(new String(sjisByte, charset));
          // } else if (isChineseMail) {
          // decodedWord = new String(decodedWordBtye, GB18030);
          // } else {
          // decodedWord = new String(sjisByte, charset);
          // }
          String lower_charset = charset.toLowerCase();

          if (UTF_7.equals(lower_charset)) {
            charset = WINDOWS_31J;
            decodedWord = getUTF7Subject(new String(decodedWordBtye, charset));
          } else if (CHARSET_GB2312.equals(lower_charset) || CHARSET_GB18030.equals(lower_charset)) {
            decodedWord = new String(decodedWordBtye, GB18030);
          } else if ("iso-2022-jp".equals(lower_charset)) {
            charset = WINDOWS_31J;
            decodedWord = new String(sjisByte, charset);
            // add start 2次開発 要件No.20 キャラクタセットCP932メール対応
          } else if (CP932.equalsIgnoreCase(lower_charset)) {
            charset = WINDOWS_31J;
            decodedWord = new String(sjisByte, charset);
            // add end
          } else {
            decodedWord = new String(decodedWordBtye, charset);
          }
          // change end 運用障害83
        }
        // change end 2012.1.17

      } else {
        decodedWord = "";
      }
      if (pos + 2 < eword.length()) {
        String rest = eword.substring(pos + 2);
        if (!decodeStrict) {
          rest = decodeInnerWords(rest);
        }
        decodedWord = decodedWord + rest;
      }
      return decodedWord;
    } catch (UnsupportedEncodingException uex) {
      throw uex;
    } catch (IOException ioex) {
      throw new ParseException();
    } catch (IllegalArgumentException iex) {

      throw new UnsupportedEncodingException();
    }
  }

  // add start 運用障害96
  /**
   * String#indexOfで、Qエンコードの"?Q?="を無視するように拡張
   * 
   * @param s
   *            ソース文字列
   * @param i
   *            検索開始位置
   * 
   * @return 位置
   * 
   */
  private static int indexOfIgnoreQEncodeSymbol(String s, int i) {
    int index = s.indexOf("?Q?=", i);
    if (index == -1) {
      return s.indexOf("?=", i);
    }
    return s.indexOf("?=", index + 4);
  }

  // add end

  private static String decodeInnerWords(String word) throws UnsupportedEncodingException {

    int start = 0;
    StringBuffer buf = new StringBuffer();
    do {
      int i;
      if ((i = word.indexOf("=?", start)) < 0) {
        break;
      }
      buf.append(word.substring(start, i));
      // change start 運用障害96
      // int end = word.indexOf("?=", i);
      int end = indexOfIgnoreQEncodeSymbol(word, i);
      // change end
      if (end < 0) {
        break;
      }
      String s = word.substring(i, end + 2);
      try {
        s = decodeWord(s);
      } catch (ParseException pex) {
      }
      buf.append(s);
      start = end + 2;
    } while (true);
    if (start == 0) {
      return word;
    }
    if (start < word.length()) {
      buf.append(word.substring(start));
    }
    return buf.toString();
  }

  // add start 2次開発 要件No.23 テキスト部を持たないメール（HTMLメール）対応
  /**
   * メールパートを解析し本文として有効な文字列を返します。
   * 
   * @param content
   *            コンテンツ
   * @param part
   *            メールパート
   * @return 本文文字列
   * @throws MessagingException
   *             メールパートの各部読み込みに失敗した場合
   * @throws IOException
   *             メールパート読み込み、中文解析に失敗した場合
   */
  public static String parseContent(Object content, Part part) throws MessagingException, IOException {

    String result = parseContent(content, part, true);
    if (result == null || "".equals(result)) {
      result = parseContent(content, part, false);
    }
    return result;
  }

  // add end

  // add start 2011/12/21 IBM拡張文字対応
  // content-typeがMultipart時に文字コードをWindows-31Jにする
  /**
   * メールパートを解析し本文として有効な文字列を返します。
   * 
   * @param content
   *            コンテンツ
   * @param part
   *            メールパート
   * @param textMode
   *            抽出モード true:テキストボディを出力、false:HTMLボディからテキストを抽出
   * @return 本文文字列
   * @throws MessagingException
   *             メールパートの各部読み込みに失敗した場合
   * @throws IOException
   *             メールパート読み込み、中文解析に失敗した場合
   */
  // change start 2次開発 要件No.23 テキスト部を持たないメール（HTMLメール）対応
  // public static String parseContent(Object content, Part part) throws
  // MessagingException, IOException {
  public static String parseContent(Object content, Part part, boolean textMode) throws MessagingException, IOException {
    // change end

    StringBuffer buf = new StringBuffer();
    if (content instanceof String) {
      // 運用課題No.110(#362)HTMLパートのみのメール対応
      // コンテンツが文字列の場合も、ヘッダーのチェックを実施
      // change start 2次開発 要件No.23 テキスト部を持たないメール（HTMLメール）対応
      // if (isEffectiveContent(part.getDataHandler().getContentType(), part)) {
      // buf.append(content);
      // }
      if (textMode) {
        if (isEffectiveContent(part.getDataHandler().getContentType(), part)) {
          buf.append(content);
        }
      } else {
        try {
          String contentType = part.getDataHandler().getContentType();
          if (contentType.indexOf("text/html") != -1) {
            HtmlExtractor ext = new HtmlExtractor();
            String charset = (new ContentType(part.getDataHandler().getContentType())).getParameter("charset");
            InputStream bais = new ByteArrayInputStream(((String) content).getBytes(charset));
            InputStreamReader isr = new InputStreamReader(bais, charset);
            buf.append(ext.exec(isr));
          }
        } catch (UnsupportedEncodingException e) {
          logger.error("JavaMailでのサポート対象外の文字エンコーディングです。UTF-7とみなして処理します。" + e);
          HtmlExtractor ext = new HtmlExtractor();
          InputStream bais = new ByteArrayInputStream(((String) content).getBytes("utf-8"));
          InputStreamReader isr = new InputStreamReader(bais, "utf-8");
          buf.append(ext.exec(isr));
        } catch (Exception e) {
          logger.error("HTMLフォーマットが不正のため本文の抽出は行ないません。", e);
        }
      }
      // change end
    } else if (content instanceof Multipart) {
      Multipart mp = (Multipart) content;
      for (int i = 0; i < mp.getCount(); i++) {
        BodyPart body_part = mp.getBodyPart(i);

        String contentType = body_part.getDataHandler().getContentType();

        // contentType = contentType.toLowerCase();

        String regex = ISO_2022_JP;
        Pattern p = Pattern.compile(regex, CASE_INSENSITIVE);
        Matcher m = p.matcher(contentType);
        contentType = m.replaceAll(ISO_2022_JP);

        contentType = contentType.replaceAll(ISO_2022_JP, WINDOWS_31J);

        // add start 2次開発 要件No.20 キャラクタセットCP932メール対応
        String lower_contentType = contentType.toLowerCase();
        if (lower_contentType.indexOf(CP932) != -1) {
          contentType = lower_contentType.replaceAll(CP932, WINDOWS_31J);
        }
        // add end

        // 中文対応
        // body_part.setDataHandler(new DataHandler(new SJISDataSource(body_part
        // .getInputStream(), contentType)));
        // 2012.2.23 受入障害対応No.293
        // ContentType取得エラー時の解析のため
        // ログを挟む
        String charset = null;
        try {
          charset = (new ContentType(contentType)).getParameter("charset");
        } catch (javax.mail.internet.ParseException e) {
          logger.error("「ContentType」から「charset」の取得処理において例外が発生しました。Parse対象の「contentType」は" + "\"" + contentType + "\"" + "です。", e);
          // delete start 2012.5.18 障害No.302
          // throw e;
          // delete end 2012.5.18
        }
        if (GB2312.equals(charset) || GB18030.equals(charset) || CHARSET_GB2312.equals(charset) || CHARSET_GB18030.equals(charset)) {
          BufferedReader reader = new BufferedReader(new InputStreamReader(body_part.getInputStream(), GB18030));
          StringBuffer buf2 = new StringBuffer();
          String str;
          while ((str = reader.readLine()) != null) {
            buf2.append(str);
            buf2.append("\n");
          }
          String gb18030 = buf2.toString();

          // change start 2次開発 要件No.23 テキスト部を持たないメール（HTMLメール）対応
          // body_part.setDataHandler(new DataHandler(new
          // GB18030DataSource(gb18030)));
          body_part.setDataHandler(new DataHandler(new GB18030DataSource(gb18030, contentType)));
          // change end
        } else {
          body_part.setDataHandler(new DataHandler(new SJISDataSource(body_part.getInputStream(), contentType)));
        }
        // 運用課題No.110(#362)HTMLパートのみのメール対応
        // 有効パートのみ本文バッファへ設定
        // change start 2次開発 要件No.23 テキスト部を持たないメール（HTMLメール）対応
        // if (!isEffectiveContent(contentType, body_part)) {
        // // 無効な種類・処置の場合、何もしない
        // continue;
        // } else {
        // // 有効な種類・処置の場合、パートの本文をバッファに追加
        // try {
        // buf.append(parseContent(body_part.getContent(), body_part));
        // } catch (UnsupportedEncodingException e) {
        // logger.error("JavaMailでのサポート対象外の文字エンコーディングです。" + e);
        // buf.append(getUTF7BodyPart((body_part.getInputStream())));
        // }
        // }
        try {
          buf.append(parseContent(body_part.getContent(), body_part, textMode));
        } catch (UnsupportedEncodingException e) {
          logger.error("JavaMailでのサポート対象外の文字エンコーディングです。" + e);
          buf.append(parseContent(getUTF7BodyPart((body_part.getInputStream())), body_part, textMode));
        }
        // change end
      }
    }
    return buf.toString();
  }

  // 運用課題No.110(#362)HTMLパートのみのメール対応
  /**
   * メールパートの種類・処置が有効か判定します。
   * 
   * @param buf
   *            バッファ
   * @param contentType
   *            コンテントタイプ
   * @param bodyPart
   *            メールパート
   * @return 有効な場合true、無効な場合false
   * @throws MessagingException
   *             メールパートの各部読み込みに失敗した場合
   */
  private static boolean isEffectiveContent(String contentType, Part bodyPart) throws MessagingException {

    // HTMLメール判定
    boolean isHtml = true;
    if (contentType.indexOf("text/html") == -1) {
      isHtml = false;
    }

    // 種類・処置を判定
    String disposition = bodyPart.getDisposition();
    if (Part.ATTACHMENT.equals(disposition)
    // change start 運用保守フェーズ障害No.129
      // || Part.INLINE.equals(disposition)
      || (Part.INLINE.equals(disposition) && contentType.indexOf("text/plain") == -1)
      // change end
      || isHtml) {
      // 無効な種類・処置の場合
      return false;
    } else {
      // 有効な種類・処置の場合
      return true;
    }
  }

  // add end

  // add start 2012.1.17 受入障害No.216対応
  /**
   * UTF-7メールデコード処理メソッド
   * 
   * @parum メールのcontentType
   * @parum メールオブジェクト
   * @parum メール件名
   * @parum ユーザーID
   * @return メールコンテンツUTF-7デコード後文字列
   */
  public static String getUTF7Content(MimeMessage mimeMessage, String mailSubject, int userid) {
    try {
      InputStream in = mimeMessage.getRawInputStream();
      return getDecodeUTF7String(in);
    } catch (Exception e) {
      logger.error("受信メールのコンテンツUTF-7デコード処理に失敗しました（件名：" + mailSubject + " 受信者：" + ALEipUtils.getUserLoginName(Integer.valueOf(userid)) + " " + e);
      return "";
    }
  }

  /**
   * UTF-7メールBodyTextデコードメソッド
   * 
   * @parum メールのcontentType
   * @parum メールオブジェクト
   * @return メールBodyTextUTF-7デコード後文字列
   */
  public static String getUTF7BodyText(MimeMessage mimeMessage) {
    try {
      InputStream in = mimeMessage.getRawInputStream();
      return getDecodeUTF7String(in);
    } catch (Exception e) {
      logger.error("受信メールのコンテンツUTF-7デコード処理に失敗しました" + e);
      return "";
    }
  }

  /**
   * 中文メールBodyTextデコードメソッド
   * 
   * @parum メールのcontentType
   * @parum メールオブジェクト
   * @return メールBodyTextデコード後文字列
   */
  public static String getChineseMailBodyText(ContentType contentType, MimeMessage mimeMessage) {
    String string = "";
    try {
      ByteArrayOutputStream out2 = new ByteArrayOutputStream();
      InputStream in = mimeMessage.getRawInputStream();
      int c;
      while ((c = in.read()) != -1) {
        out2.write(c);
      }
      byte[] bytes = out2.toByteArray();
      string = new String(bytes, ALMailUtils.GB18030);
    } catch (Exception e) {
      logger.error("中文メールのコンテンツ取得処理に失敗しました" + e);
      return string;
    }
    return string;
  }

  /**
   * メール件名UTF-7デコードメソッド
   * 
   * @parum メールのcontentType
   * @parum メールオブジェクト
   * @return メール件名UTF-7デコード後文字列
   */
  public static String getUTF7Subject(String subject) {
    return getDecodeUTF7String(new ByteArrayInputStream(subject.getBytes()));
  }

  /**
   * メールBodyPartUTF-7デコードメソッド
   * 
   * @parum メールのcontentType
   * @parum メールオブジェクト
   * @return メール件名UTF-7デコード後文字列
   */
  public static String getUTF7BodyPart(InputStream body_part) {
    return getDecodeUTF7String(body_part);

  }

  /**
   * UTF7コンテンツ内容取得処理メソッド
   * 
   */
  public static String getDecodeUTF7String(InputStream ins) {
    try {
      String string = "";
      ByteArrayOutputStream out2 = new ByteArrayOutputStream();
      InputStream in = ins;
      int c;
      // add start 2次開発 要件No.23 テキスト部を持たないメール（HTMLメール）対応
      boolean flg = false;
      // add end
      while ((c = in.read()) != -1) {

        // add start 2次開発 要件No.23 テキスト部を持たないメール（HTMLメール）対応
        if (c == '=') {
          flg = true;
          continue;
        } else if (c == '\n' || c == '\r') {
          if (flg) {
            continue;
          }
        } else {
          flg = false;
        }
        // add end

        out2.write(c);
      }
      ByteToCharUTF7 btc = new ByteToCharUTF7();
      byte[] bytes = out2.toByteArray();
      char[] chars = new char[bytes.length];
      int len = btc.convert(bytes, 0, bytes.length, chars, 0, chars.length);
      char[] w = new char[len];
      System.arraycopy(chars, 0, w, 0, len);
      string = new String(w);
      return string;
    } catch (Exception e) {
      logger.error("受信メールのコンテンツUTF-7デコード処理に失敗しました" + e);
      return "";
    }
  }

  /**
   * メールCharsetがUTF-7かどうかの確認メソッド
   * 
   * @parum メールのcontentType
   * @return UTF-7:true それ以外:false
   */
  public static boolean isCharsetUTF7(ContentType contentType) {
    String specifiedCharset = contentType.getParameter("charset");
    if ("UTF-7".equalsIgnoreCase(specifiedCharset)) {
      return true;
    } else {
      return false;
    }
  }

  /**
   * 中文メールかどうかの確認メソッド
   * 
   * @parum メールのcontentType
   * @return UTF-7:true それ以外:false
   */
  public static boolean isChineseMail(ContentType contentType) {
    String specifiedCharset = contentType.getParameter("charset");
    if (GB2312.equals(specifiedCharset)
      || GB18030.equals(specifiedCharset)
      || CHARSET_GB2312.equals(specifiedCharset)
      || CHARSET_GB18030.equals(specifiedCharset)) {
      return true;
    } else {
      return false;
    }
  }

  /**
   * 受信メール、サポート外エンコードコンテンツの取得処理
   * 
   * @parum メールオブジェクト
   * @parum メール件名
   * @parum ユーザーID
   * @return メールコンテンツ文字列
   */
  public static String getUnsupportedEncodingContent(MimeMessage mimeMessage, String mailSubject, int userid) {
    try {
      ContentType contentType = new ContentType(mimeMessage.getContentType());
      if (isCharsetUTF7(contentType)) {
        // charsetがUTF-7の場合はデコードして返す
        return getUTF7Content(mimeMessage, mailSubject, userid);
      } else {
        // charsetがUTF-7以外の場合は空文字返す
        return "";
      }
    } catch (Exception e) {
      logger.error("受信メール、サポート外エンコードコンテンツの取得処理に失敗しました（件名：" + mailSubject + " 受信者：" + ALEipUtils.getUserLoginName(Integer.valueOf(userid)) + " " + e);
      return "";
    }
  }

  // add end 2012.1.17 受入障害No.216対応

  // add start 2012.1.27 受入障害No.252対応
  /**
   * 区切り文字で区切った文字列の配列を取得する．
   * 
   * @param line
   *            区切り文字を含む文字列
   * @param delim
   *            区切り文字
   * @return
   * @throws IOException
   */
  public static String[] getTokensExt(String line, String delim) throws IOException {
    if (line == null || line.equals("")) {
      return null;
    }
    CSVParser st = new CSVParser(delim.charAt(0));
    // 運用課題No.64
    // 空要素を除去する
    // return st.parseLine(line);
    String[] workArray = st.parseLine(line);
    List<String> workList = new ArrayList<String>(0);
    for (String item : workArray) {
      if (!"".equals(item)) {
        workList.add(item);
      }
    }
    return workList.toArray(new String[0]);
  }

  // add end

  // add start 2012.1.27 受入障害No.252対応
  // change 2012.2.21 受入障害No.288により全処理見直し
  /**
   * (携帯向け)区切り文字で区切った文字列の配列を取得する．
   * 
   * @param line
   *            区切り文字を含む文字列
   * @param delim
   *            区切り文字
   * @return
   * @throws IOException
   */
  public static String[] getTokensExtForMobile(String line, String delim) throws IOException {

    if (line == null || line.equals("")) {
      return null;
    }

    List<String> provisionalStringArray = new ArrayList<String>();

    comma_position_count = 0;
    for (int line_length_count = 0; line_length_count < line.length(); line_length_count++) {

      // 引数のアドレス文字列を先頭から一文字ずつチェックしていく
      String target_string = line.substring(line_length_count, line_length_count + 1);

      if (target_string.equals("\"")) {

        // アドレスがダブルコーテーションで囲まれている場合は
        // 次のカンマ(escapeされていないカンマ)までを
        // アドレスとして抜き出す
        int comma_position = line.indexOf(delim, line_length_count);
        if (comma_position == -1) {
          // カンマがない場合は最後までセット
          provisionalStringArray.add(trimParseString(line.substring(line_length_count)));
          // 処理終了
          break;

        } else {
          // カンマがある場合
          // エスケープされていないカンマか確認
          if ("\\".equals(line.substring(comma_position - 1, comma_position))) {
            // エスケープ処理されている場合は
            // エスケープ処理されていないカンマまで繰り返す
            provisionalStringArray.add(getParseIgnoreCommaPositionString(line, line_length_count, comma_position));
            line_length_count = getCommaPosition();
          } else {
            // エスケープ処理されていない場合は
            // カンマまでを対象配列にセット
            provisionalStringArray.add(line.substring(line_length_count, comma_position - 1));
            line_length_count = comma_position;
          }
        }

      } else {
        // アドレスがダブルコーテーションで囲まれていない場合は
        // 次のカンマまでをアドレスとして抜き出す
        int comma_position = line.indexOf(delim, line_length_count);
        if (comma_position == -1) {
          provisionalStringArray.add(trimParseString(line.substring(line_length_count)));
          // 処理終了
          break;

        } else {
          // エスケープ処理されていない場合は
          // カンマまでを対象配列にセット
          provisionalStringArray.add(getParseCommaPositionString(line, line_length_count, comma_position));
          line_length_count = comma_position;
        }
      }
    }

    return provisionalStringArray.toArray(new String[provisionalStringArray.size()]);
  }

  private static String getParseCommaPositionString(String line, int line_length_count, int comma_position) {
    String parse_string = line.substring(line_length_count, comma_position);
    return trimParseString(parse_string);
  }

  private static String getParseIgnoreCommaPositionString(String line, int line_length_count, int comma_position) {
    // エスケープされていないカンマまでを取得する。
    String line2 = line.substring(comma_position);

    int next_comma_position = line2.indexOf(',', 1);
    String parse_string = "";
    if (next_comma_position == -1) {
      int line2_length = line2.length();
      parse_string = line.substring(line_length_count);
      setCommaPosition(comma_position + line2_length);
    } else {
      setCommaPosition(next_comma_position + comma_position);
      if ("\\".equals(line2.substring(next_comma_position - 1, next_comma_position))) {
        parse_string = getParseIgnoreCommaPositionString(line, line_length_count, next_comma_position + comma_position);
      } else {
        parse_string = getParseCommaPositionString(line, line_length_count, comma_position + (next_comma_position));
      }
    }
    return trimParseString(parse_string);
  }

  /**
   * InternetAddressメソッドでExceptionにならないように前後のダブルクォートをtrimする
   * 
   * @param parse_string
   * @return エスケープ文字と前後のダブルクォートをtrimした文字列
   */
  private static String trimParseString(String parse_string) {
    String trim_parse_string = parse_string;
    if (null != trim_parse_string && (!"".equals(trim_parse_string))) {
      if ("\"".equals(trim_parse_string.substring(0, 1))
        && "\"".equals(trim_parse_string.substring(trim_parse_string.length() - 1, trim_parse_string.length()))) {
        trim_parse_string = trim_parse_string.substring(1, trim_parse_string.length() - 1);
      }
    }
    return trim_parse_string;
  }

  private static void setCommaPosition(int couont) {
    comma_position_count = couont;
  }

  private static int getCommaPosition() {
    return comma_position_count;
  }
  // add end
}
