/*
 * Aipo is a groupware program developed by Aimluck,Inc.
 * Copyright (C) 2004-2008 Aimluck,Inc.
 * http://aipostyle.com/
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
package com.aimluck.eip.mail.util;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
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.net.UnknownHostException;
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.List;
import java.util.Map;
import java.util.Properties;
import java.util.StringTokenizer;
import java.util.TimeZone;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;
import javax.activation.DataHandler;
import javax.mail.Address;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Part;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeUtility;
import javax.servlet.ServletConfig;

import org.apache.cayenne.access.DataContext;
import org.apache.cayenne.exp.Expression;
import org.apache.cayenne.exp.ExpressionFactory;
import org.apache.cayenne.query.SelectQuery;
import org.apache.jetspeed.services.JetspeedSecurity;
import org.apache.jetspeed.services.JetspeedUserManagement;
import org.apache.jetspeed.services.daemonfactory.DaemonFactoryService;
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.services.TurbineServices;
import org.apache.jetspeed.services.rundata.JetspeedRunData;
import org.apache.jetspeed.services.rundata.JetspeedRunDataService;
import org.apache.turbine.services.rundata.RunDataService;
import org.apache.turbine.util.RunData;

import com.aimluck.commons.utils.ALStringUtil;
import com.aimluck.eip.cayenne.om.account.EipMCompany;
import com.aimluck.eip.cayenne.om.portlet.EipMMailAccount;
import com.aimluck.eip.cayenne.om.portlet.EipMMailNotifyConf;
import com.aimluck.eip.common.ALBaseUser;
import com.aimluck.eip.common.ALEipConstants;
import com.aimluck.eip.common.ALEipUser;
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.ALMailReceiver;
import com.aimluck.eip.mail.ALMailReceiverContext;
import com.aimluck.eip.mail.ALMailSenderContext;
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.DatabaseOrmService;
import com.aimluck.eip.services.daemonfactory.AipoDaemonFactoryService;
import com.aimluck.eip.services.eventlog.ALEventlogConstants;
import com.aimluck.eip.services.eventlog.ALEventlogFactoryService;
import com.aimluck.eip.util.ALEipUtils;
import com.sk_jp.io.CharCodeConverter;
import com.sk_jp.mail.JISDataSource;
import com.sk_jp.mail.MailUtility;
import com.sun.mail.util.BASE64EncoderStream;

/**
 * メールのユーティリティクラスです。 <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;

  // /** メール送信時のメッセージ種別（伝言メモを送信．宛先ユーザのパソコン用メールアドレスが未設定でメール送信不可） */
  // private final int SEND_MSG_TYPE_NON_ADDR_PC = 1;
  //
  // /** メール送信時のメッセージ種別（伝言メモを送信．宛先ユーザーの携帯用メールアドレスが未設定でメール送信不可） */
  // private final int SEND_MSG_TYPE_NON_ADDR_CELL = 2;
  //
  // /** メール送信時のメッセージ種別（伝言メモを送信．宛先ユーザーのパソコン用と携帯用のメールアドレスが未設定でメール送信不可） */
  // private final int SEND_MSG_TYPE_NON_ADDR_PC_CELL = 3;
  //
  // /** メール送信時のメッセージ種別（伝言メモの送信不可．宛先ユーザーが存在しないため，伝言メモを送信できませんでした） */
  // private final int SEND_MSG_TYPE_NON_RECIPIENT = 4;
  //
  // /** メール送信時のメッセージ種別（伝言メモの送信不可．送信ユーザーのメールアカウントが未設定でメール送信不可） */
  // private final int SEND_MSG_TYPE_NON_MAILACCOUNT = 5;

  /** メール通知のキー（毎日通知スケジュール用） */
  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", "");

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

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

    try {

      DataContext dataContext = null;
      if (orgId == null || "".equals(orgId)) {
        dataContext = DatabaseOrmService.getInstance().getDataContext();
      } else {
        dataContext = DataContext.createDataContext(orgId);
      }

      SelectQuery query = new SelectQuery(EipMMailAccount.class);
      Expression exp1 = ExpressionFactory.matchExp(
          EipMMailAccount.USER_ID_PROPERTY, Integer.valueOf(userId));
      query.setQualifier(exp1);
      Expression exp2 = ExpressionFactory.matchDbExp(
          EipMMailAccount.ACCOUNT_ID_PK_COLUMN, Integer.valueOf(accountId));
      query.andQualifier(exp2);
      List accounts = dataContext.performQuery(query);
      if (accounts == null || accounts.size() == 0) {
        // 指定したアカウントIDのレコードが見つからない場合
        logger.debug("[WebMail] Not found AccountID...");
        return null;
      }

      return ((EipMMailAccount) accounts.get(0));
    } catch (Exception ex) {
      logger.error("Exception", ex);
      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(null, 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(""))
      return null;
    if (str.indexOf(CR) < 0)
      return new String[] { str };

    String token = null;
    ArrayList tokens = new ArrayList();
    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 = (String[]) 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)
      return "";
    StringBuffer sb = new StringBuffer();
    InternetAddress addr = null;
    int length = addresses.length - 1;
    for (int i = 0; i < length; i++) {
      addr = (InternetAddress) addresses[i];
      if (addr.getPersonal() != null) {
        String personaladdr = getOneString(
            getTokens(addr.getPersonal(), "\r\n"), "");
        sb.append(MailUtility.decodeText(personaladdr)).append(" <").append(
            addr.getAddress()).append(">, ");
      } else {
        sb.append(addr.getAddress()).append(", ");
      }
    }
    addr = (InternetAddress) addresses[length];
    if (addr.getPersonal() != null) {
      String personaladdr = getOneString(getTokens(addr.getPersonal(), "\r\n"),
          "");
      sb.append(MailUtility.decodeText(personaladdr)).append(" <").append(
          addr.getAddress()).append(">");
    } else {
      sb.append(addr.getAddress());
    }
    return sb.toString();
  }

  /**
   * 複数の文字列を区切り文字で区切った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;
  }

  /**
   * 指定したプロパティファイルから値を取得する．
   *
   * @param filename
   *            プロパティファイル名
   * @param key
   *            プロパティのキー
   * @return プロパティの値
   */
  public static String getProperty(String filename, String key) {
    File file = getFile(filename);
    if (file == null)
      return null;

    String value = null;
    Properties prop = new Properties();
    FileInputStream input = null;
    try {
      input = new FileInputStream(file);
      prop.load(input);
      value = prop.getProperty(key);
    } catch (Exception e) {
      logger.error("Exception", e);
      value = null;
    } finally {
      if (input != null) {
        try {
          input.close();
        } catch (IOException e) {
          logger.error("Exception", e);
          value = null;
        }
      }
    }

    return value;
  }

  /**
   * 指定したプロパティファイルに値を保存する．
   *
   * @param filename
   *            プロパティファイル名
   * @param key
   *            プロパティのキー
   * @param value
   *            プロパティの値
   */
  public static void setProperty(String filename, String key, String value) {
    File file = getFile(filename);
    if (file == null)
      return;

    Properties prop = new Properties();
    FileInputStream input = null;
    try {
      input = new FileInputStream(file);
      prop.load(input);
      prop.put(key, value);
      prop.store(new FileOutputStream(file), null);
    } catch (Exception e) {
      logger.error("Exception", e);
    }
  }

  /**
   * 指定したファイル名に対するクラス File のオブジェクトを取得する．
   *
   * @param filename
   * @return
   */
  public static File getFile(String filename) {
    if (filename == null)
      return null;
    File file = new File(filename);
    if (!file.exists()) {
      try {
        if (!file.createNewFile())
          return null;
      } catch (IOException e) {
        return null;
      }
    }
    return file;
  }

  /**
   * 指定したフォルダ以下を全て削除する．
   *
   * @return
   */
  public static boolean deleteFolder(File folder) {
    if (folder == null)
      return true;

    String[] files = folder.list();
    if (files == null) {
      folder.delete();
      return true;
    }

    int length = files.length;
    if (length <= 0) {
      folder.delete();
      return true;
    }
    String folderPath = folder.getAbsolutePath() + File.separator;
    File tmpfile = null;
    for (int i = 0; i < length; i++) {
      tmpfile = new File(folderPath + files[i]);
      if (tmpfile.exists()) {
        if (tmpfile.isFile()) {
          tmpfile.delete();
        } else if (tmpfile.isDirectory()) {
          deleteFolder(tmpfile);
        }
      }
    }
    folder.delete();
    return true;
  }

  /**
   * [メール削除機能] ロックファイルを生成する．
   *
   * @param dir
   * @param userId
   * @return
   */
  public static boolean createLockFile(String dir, String userId) {
    try {
      File lockDir = new File(dir);
      if (!lockDir.exists()) {
        lockDir.mkdirs();
      }

      StringBuffer sb = new StringBuffer();
      sb.append(dir).append(File.separator).append(userId).append(".lock");
      File lockFile = new File(sb.toString());
      if (!lockFile.createNewFile()) {
        long lastModifiedTime = lockFile.lastModified();
        Calendar calendar = Calendar.getInstance();
        long nowTime = calendar.getTimeInMillis();
        // 最後の変更時間（作成時間）と現在時間を比較し，タイムアウト時間内かを検証する．
        if (lastModifiedTime + ALMailReceiver.TIMEOUT_SPAN < nowTime) {
          // タイムアウト時間を過ぎた場合，ロックファイルを削除し，
          // 新たにロックファイルの作成を試みる．
          lockFile.delete();
          if (!lockFile.createNewFile()) {
            return false;
          }
        } else {
          return false;
        }
      }
    } catch (IOException e) {
      e.printStackTrace();
      return false;
    }
    return true;
  }

  /**
   * [メール削除機能] ロックファイルを削除する．
   *
   * @param dir
   * @param userId
   * @return
   */
  public static boolean deleteLockFile(String dir, String userId) {
    StringBuffer sb = new StringBuffer();
    sb.append(dir).append(File.separator).append(userId).append(".lock");

    File lockFile = new File(sb.toString());
    if (!lockFile.delete())
      return false;
    return true;
  }

  /**
   * 受信メールの受信日時を取得する（ヘッダ 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(BASE64EncoderStream.encode(CharCodeConverter
              .sjisToJis(UnicodeCorrecter.correctToCP932(s).getBytes(
                  "Windows-31J")))) + "?=";
    } 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;
  }

  /**
   * ファイルが存在することを確認する．
   *
   * @param filePaths
   *            ファイルへのフルパス
   * @return
   */
  public static String[] checkFilesExistance(String[] filePaths) {
    ArrayList checkedList = new ArrayList();
    File file = null;
    int filePathsLength = filePaths.length;
    for (int i = 0; i < filePathsLength; i++) {
      file = new File(filePaths[i]);
      if (!file.exists())
        continue;
      checkedList.add(filePaths[i]);
    }

    int checkedListLength = checkedList.size();
    String[] filePathList = new String[checkedListLength];
    for (int i = 0; i < checkedListLength; i++) {
      filePathList[i] = (String) checkedList.get(i);
    }
    return filePathList;
  }

  public static String getFileNameFromText(String FilePath) {
    String line = "";
    BufferedReader reader = null;
    try {
      reader = new BufferedReader(new InputStreamReader(new FileInputStream(
          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;

  }

  /**
   * テキストをセットします。 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");
  }

  /**
   * 「暗号化＋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());
    } 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());

      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())));

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

  /**
   * 送信メッセージ（SMTP）のコンテキストを取得します。
   *
   * @param orgId
   * @param account
   * @return
   */
  public static ALSmtpMailContext getALSmtpMailContext(String[] to,
      String[] cc, String[] bcc, String from, String name, String subject,
      String msgText, String[] filePaths, Map 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;
  }

  /**
   * 管理者 admin のメールアカウントのオブジェクトモデルを取得する． <BR>
   *
   * @param rundata
   * @param context
   * @param isJoin
   *            カテゴリテーブルをJOINするかどうか
   * @return
   */
  public static EipMMailAccount getEipMMailAccountForAdmin() {
    try {
      DataContext dataContext = DatabaseOrmService.getInstance()
          .getDataContext();
      SelectQuery query = new SelectQuery(EipMMailAccount.class);
      // admin の ID を指定
      Expression exp = ExpressionFactory.matchExp(
          EipMMailAccount.USER_ID_PROPERTY, Integer.valueOf(1));
      query.andQualifier(exp);
      List accounts = dataContext.performQuery(query);
      if (accounts == null || accounts.size() == 0) {
        // 指定したアカウントIDのレコードが見つからない場合
        logger.debug("[ALMailUtils] Not found AccountID...");
        return null;
      }
      return ((EipMMailAccount) accounts.get(0));
    } catch (Exception ex) {
      logger.error("Exception", ex);
      return null;
    }
  }

  /**
   * デフォルトのメールアカウントの情報をデータベースから所得する．
   *
   * @param userId
   * @return
   */
  public static EipMMailAccount getFirstEipMMailAccount(int userId) {
    try {
      DataContext dataContext = DatabaseOrmService.getInstance()
          .getDataContext();
      SelectQuery query = new SelectQuery(EipMMailAccount.class);
      Expression exp1 = ExpressionFactory.matchExp(
          EipMMailAccount.USER_ID_PROPERTY, Integer.valueOf(userId));
      query.setQualifier(exp1);
      Expression exp21 = ExpressionFactory.matchExp(
          EipMMailAccount.ACCOUNT_TYPE_PROPERTY, "1");
      Expression exp22 = ExpressionFactory.matchExp(
          EipMMailAccount.ACCOUNT_TYPE_PROPERTY, "2");
      query.andQualifier(exp21.orExp(exp22));
      List accounts = dataContext.performQuery(query);
      if (accounts == null || accounts.size() == 0) {
        // 指定したアカウントIDのレコードが見つからない場合
        logger.debug("[ALMailUtils] Not found AccountID...");
        return null;
      }
      return (EipMMailAccount) accounts.get(0);
    } catch (Exception ex) {
      logger.error("Exception", ex);
      return null;
    }
  }

  /**
   * メールアカウント情報をデータベースに保存する．
   *
   * @param rundata
   * @param context
   * @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 authReceiveFlg
   * @param delAtPop3Flg
   * @param delAtPop3BeforeDaysFlg
   * @param delAtPop3BeforeDays
   * @param nonReceivedFlg
   * @return
   */
  public static boolean insertMailAccountData(RunData rundata,
      ArrayList 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) {

    boolean enableUpdate = false;

    try {
      DataContext dataContext = DatabaseOrmService.getInstance()
          .getDataContext();

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

      EipMMailAccount mailAccount = null;
      if (accountType == ACCOUNT_TYPE_INIT) {
        // 新規オブジェクトモデル
        mailAccount = (EipMMailAccount) dataContext
            .createAndRegisterNewObject(EipMMailAccount.class);
        mailAccount.setAccountType(Integer.toString(ACCOUNT_TYPE_INIT));
      } else {
        SelectQuery query = new SelectQuery(EipMMailAccount.class);
        Expression exp1 = ExpressionFactory.matchExp(
            EipMMailAccount.USER_ID_PROPERTY, Integer.valueOf(userId));
        query.setQualifier(exp1);
        Expression exp2 = ExpressionFactory.matchExp(
            EipMMailAccount.ACCOUNT_TYPE_PROPERTY, Integer
                .valueOf(ACCOUNT_TYPE_INIT));
        query.andQualifier(exp2);
        List list = dataContext.performQuery(query);
        if (list == null || list.size() <= 0) {
          // 新規オブジェクトモデル
          mailAccount = (EipMMailAccount) dataContext
              .createAndRegisterNewObject(EipMMailAccount.class);

          SelectQuery query3 = new SelectQuery(EipMMailAccount.class);
          Expression exp3 = ExpressionFactory.matchExp(
              EipMMailAccount.USER_ID_PROPERTY, Integer.valueOf(userId));
          query3.setQualifier(exp3);
          List mails = dataContext.performQuery(query3);
          int count = (mails != null && mails.size() > 0) ? mails.size() : 0;
          if (count <= 0) {
            mailAccount.setAccountType(Integer.toString(ACCOUNT_TYPE_DEFAULT));
          } else {
            mailAccount.setAccountType(Integer.toString(ACCOUNT_TYPE_NON));
          }
        } else {
          EipMMailAccount acc = (EipMMailAccount) list.get(0);
          mailAccount = acc;
          if (Integer.toString(ACCOUNT_TYPE_INIT).equals(acc.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.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);
      }

      dataContext.commitChanges();
      // イベントログに保存
      ALEventlogFactoryService.getInstance().getEventlogHandler().log(
          mailAccount.getAccountId(),
          ALEventlogConstants.PORTLET_TYPE_WEBMAIL_ACCOUNT,
          mailAccount.getAccountName());
    } catch (Exception ex) {
      ex.printStackTrace();
      logger.error("Exception", ex);
      return false;
    }
    return true;
  }

  public static boolean sendMailDelegate(String org_id, int srcUserId,
      List destMemberList, String pcSubject, String cellularSubject,
      String pcBody, String cellularBody, int destType, ArrayList 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 {
      ArrayList destEmailAddrs = new ArrayList();
      ArrayList destCellularEMailAddrs = new ArrayList();
      int size = destMemberList.size();
      for (int i = 0; i < size; i++) {
        ALEipUserAddr user = (ALEipUserAddr) destMemberList.get(i);
        String emailAddr = user.getPcMailAddr();
        if (emailAddr != null && !emailAddr.equals("")) {
          destEmailAddrs.add(emailAddr);
        }
        String cellularEmailAddr = user.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 = (String[]) destEmailAddrs.toArray(tos);

        // 送信メッセージのコンテキスト
        ALSmtpMailContext mailcontext = ALMailUtils.getALSmtpMailContext(tos,
            null, null, account.getMailAddress(), ALStringUtil
                .unsanitizing(account.getMailUserName()), ALStringUtil
                .unsanitizing(pcSubject), ALStringUtil.unsanitizing(pcBody),
            null, null);

        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 = (String[]) destCellularEMailAddrs.toArray(tos);

        ALSmtpMailContext mailcontext = ALMailUtils.getALSmtpMailContext(tos,
            null, null, account.getMailAddress(), ALStringUtil
                .unsanitizing(account.getMailUserName()), ALStringUtil
                .unsanitizing(cellularSubject), ALStringUtil
                .unsanitizing(cellularBody), null, null);

        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);
  }

  public static boolean sendMailDelegate_note(String org_id, int srcUserId,
      List destMemberList, String pcSubject, String cellularSubject,
      String pcBody, String cellularBody, int destType, ArrayList 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 {
      ArrayList destEmailAddrs = new ArrayList();
      ArrayList destCellularEmailAddrs = new ArrayList();
      int size = destMemberList.size();
      for (int i = 0; i < size; i++) {
        ALEipUserAddr user = (ALEipUserAddr) destMemberList.get(i);
        String emailAddr = user.getPcMailAddr();
        if (emailAddr != null && !emailAddr.equals("")) {
          destEmailAddrs.add(emailAddr);
        }
        String cellularEmailAddr = user.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 = (String[]) destEmailAddrs.toArray(tos);

        // 送信メッセージのコンテキスト
        ALSmtpMailContext mailcontext = ALMailUtils.getALSmtpMailContext(tos,
            null, null, account.getMailAddress(), ALStringUtil
                .unsanitizing(account.getMailUserName()), ALStringUtil
                .unsanitizing(pcSubject), ALStringUtil.unsanitizing(pcBody),
            null, null);

        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 = (String[]) destCellularEmailAddrs.toArray(tos);

        ALSmtpMailContext mailcontext = ALMailUtils.getALSmtpMailContext(tos,
            null, null, account.getMailAddress(), ALStringUtil
                .unsanitizing(account.getMailUserName()), ALStringUtil
                .unsanitizing(cellularSubject), ALStringUtil
                .unsanitizing(cellularBody), null, null);

        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);
  }

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

    ALEipUserAddr useraddr = null;
    int membersize = memberList.size();
    for (int i = 0; i < membersize; i++) {
      ALEipUser user = (ALEipUser) 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());
        resList.add(useraddr);
      } catch (Exception ex) {
        logger.error("Exception", ex);
      }
    }

    return resList;
  }

  /**
   * プロパティファイルから送信先の設定を取得する。
   *
   * @param keyMsgtype
   * @return
   */
  public static int getSendDestType(int keyMsgtype) {
    int destType = VALUE_MSGTYPE_DEST_NONE;

    try {
      DataContext dataContext = DatabaseOrmService.getInstance()
          .getDataContext();
      SelectQuery query = new SelectQuery(EipMMailNotifyConf.class);
      Expression exp1 = ExpressionFactory.matchExp(
          EipMMailNotifyConf.USER_ID_PROPERTY, Integer.valueOf(1));
      query.setQualifier(exp1);
      Expression exp2 = ExpressionFactory.matchExp(
          EipMMailNotifyConf.NOTIFY_TYPE_PROPERTY, Integer.valueOf(keyMsgtype));
      query.andQualifier(exp2);
      List confs = dataContext.performQuery(query);
      if (confs == null || confs.size() == 0) {
        // レコードが見つからない場合
        logger.debug("[ALMailUtils] Not found Notify...");
        return VALUE_MSGTYPE_DEST_NONE;
      }

      EipMMailNotifyConf conf = (EipMMailNotifyConf) confs.get(0);
      destType = conf.getNotifyFlg().intValue();

    } catch (Exception ex) {
      logger.error("Exception", ex);
      return VALUE_MSGTYPE_DEST_NONE;
    }

    return destType;

    // try {
    // // プロパティファイルから設定読み込み
    // String propertiesPath = JetspeedResources.getString("aipo.conf", "");
    // Properties prop = new Properties();
    // prop.load(new FileInputStream(propertiesPath + File.separator
    // + "WebMailAdminSettings.properties"));
    // return Integer.parseInt(prop.getProperty(keyMsgtype));
    // } catch (Exception e) {
    // return TYPE_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;

      DataContext dataContext = DatabaseOrmService.getInstance()
          .getDataContext();
      SelectQuery query = new SelectQuery(EipMMailNotifyConf.class);
      Expression exp1 = ExpressionFactory.matchExp(
          EipMMailNotifyConf.NOTIFY_TYPE_PROPERTY, Integer.valueOf(keyMsgtype));
      query.setQualifier(exp1);
      List confs = dataContext.performQuery(query);

      if (confs == null || confs.size() == 0) {
        // レコードが見つからない場合
        logger.debug("[ALMailUtils] Not found Notify...");
        return false;
      }

      EipMMailNotifyConf conf = (EipMMailNotifyConf) confs.get(0);
      conf.setNotifyFlg(valueMsgtype);

      dataContext.commitChanges();
    } catch (Exception ex) {
      logger.error("Exception", ex);
      return false;
    }
    return true;
  }

  public static String getGlobalurl() {
    String url;

    EipMCompany record = ALEipUtils.getEipMCompany("1");
    String domain = getUrl(record.getIpaddress(), record.getPort().intValue(),
            getServletName());

    JetspeedRunDataService runDataService = (JetspeedRunDataService) TurbineServices
    .getInstance().getService(RunDataService.SERVICE_NAME);

    JetspeedRunData rundata = null;
    if (runDataService != null) {
      rundata = runDataService.getCurrentRunData();
    }

    if (domain != null && domain.length() > 0) {
      String endword;
      String company_id = rundata.getParameters().getString(
          DatabaseOrmService.ORG_PRE, "");
      if (company_id == null || "".equals(company_id)) {
        endword = "";
      } else {
        endword = "portal/org/" + company_id + "/";
      }

      url = domain + endword;
    } else {
      url = "";
    }
    return url;
  }

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

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

  private static String getServletName() {
    AipoDaemonFactoryService aipoDaemonService = (AipoDaemonFactoryService) TurbineServices
        .getInstance().getService(DaemonFactoryService.SERVICE_NAME);
    ServletConfig servlet_config = aipoDaemonService.getServletConfig();
    return servlet_config.getServletName();
  }

  private static String getUrl(String ip, int port, String servername) {
    if (ip == null || ip.length() == 0 || port == -1)
      return "";

    String protocol = JetspeedResources
        .getString("access.url.protocol", "http");

    StringBuffer url = new StringBuffer();

    if (port == 80) {
      url.append(protocol).append("://").append(ip).append("/").append(
          servername).append("/");
    } else {
      url.append(protocol).append("://").append(ip).append(":").append(port)
          .append("/").append(servername).append("/");
    }
    return url.toString();
  }

  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 = new Time(0);
    time = Time.valueOf(sb.toString());

    DataContext dataContext = DatabaseOrmService.getInstance().getDataContext();

    SelectQuery query = new SelectQuery(EipMMailNotifyConf.class);
    Expression exp = ExpressionFactory.matchDbExp(
        EipMMailNotifyConf.NOTIFY_ID_PK_COLUMN, "1");
    query.setQualifier(exp);

    List list = dataContext.performQuery(query);
    if (list == null || list.size() == 0)
      return false;

    EipMMailNotifyConf notify = (EipMMailNotifyConf) list.get(0);
    notify.setNotifyTime(time);
    dataContext.commitChanges();
    return true;
  }

  public static String getNotifyTime() {
    DataContext dataContext = DatabaseOrmService.getInstance().getDataContext();
    SelectQuery query = new SelectQuery(EipMMailNotifyConf.class);
    Expression exp = ExpressionFactory.matchDbExp(
        EipMMailNotifyConf.NOTIFY_ID_PK_COLUMN, "1");
    query.setQualifier(exp);

    List list = dataContext.performQuery(query);
    if (list == null || list.size() == 0)
      return null;

    Date date = ((EipMMailNotifyConf) list.get(0)).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();
  }
}
