/* * Aipo is a groupware program developed by TOWN, Inc. * Copyright (C) 2004-2015 TOWN, 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; 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.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.Enumeration; import java.util.List; import java.util.Properties; import java.util.jar.Attributes; import javax.mail.Address; import javax.mail.Header; import javax.mail.Message; import javax.mail.Message.RecipientType; import javax.mail.MessagingException; import javax.mail.Session; import javax.mail.internet.InternetAddress; import javax.mail.internet.MimeMessage; import javax.mail.internet.MimeUtility; import org.apache.cayenne.exp.Expression; import org.apache.cayenne.exp.ExpressionFactory; import org.apache.jetspeed.services.logging.JetspeedLogFactoryService; import org.apache.jetspeed.services.logging.JetspeedLogger; import org.apache.turbine.util.RunData; import org.apache.velocity.context.Context; import com.aimluck.eip.cayenne.om.portlet.EipMMailAccount; import com.aimluck.eip.cayenne.om.portlet.EipTMail; import com.aimluck.eip.cayenne.om.portlet.EipTMailFilter; import com.aimluck.eip.common.ALEipConstants; import com.aimluck.eip.mail.util.ALAttachmentsExtractor; import com.aimluck.eip.mail.util.ALMailUtils; 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.storage.ALStorageService; import com.aimluck.eip.util.ALCommonUtils; import com.aimluck.eip.util.ALEipUtils; import com.sk_jp.mail.MailUtility; import com.sk_jp.mail.MultipartUtility; /** * 送受信したメールを保持するローカルフォルダの抽象クラスです。 <br /> * */ public abstract class ALAbstractFolder implements ALFolder { /** logger */ private static final JetspeedLogger logger = JetspeedLogFactoryService .getLogger(ALAbstractFolder.class.getName()); /** 受信 or 送信 */ protected int type_mail = -1; protected String org_id; protected int user_id; protected int account_id; /** ルートフォルダのフルパス */ protected String rootFolderPath = null; /** カテゴリキー(mail) */ protected String categoryKey = null; /** 表示行数 */ private int rows_num = 10; /** 表示文字数 */ private int strlen = 0; /** 開始位置 */ private int start; /** 総件数 */ private int count; /** 総ページ数 */ private int pages_num = 1; /** 現在のページ */ private int current_page = 1; /** 現在のソート */ private String current_sort; /** 現在のソートタイプ (asc:昇順、desc:降順) */ private String current_sort_type; protected final String LIST_SORT_STR = new StringBuffer().append( this.getClass().getName()).append(ALEipConstants.LIST_SORT).toString(); protected final String LIST_SORT_TYPE_STR = new StringBuffer().append( this.getClass().getName()).append(ALEipConstants.LIST_SORT_TYPE).toString(); /** * コンストラクタ * * @param parentFolder * 親フォルダ * @param folderName * 自身のフォルダ名 */ public ALAbstractFolder(int type_mail, String org_id, int user_id, int account_id) { this.type_mail = type_mail; this.org_id = org_id; this.user_id = user_id; this.account_id = account_id; } protected void init(RunData rundata, Context context) { if (rundata.getParameters().containsKey(ALEipConstants.LIST_SORT)) { ALEipUtils.setTemp(rundata, context, LIST_SORT_STR, rundata .getParameters() .getString(ALEipConstants.LIST_SORT)); } if (rundata.getParameters().containsKey(ALEipConstants.LIST_SORT_TYPE)) { ALEipUtils.setTemp(rundata, context, LIST_SORT_TYPE_STR, rundata .getParameters() .getString(ALEipConstants.LIST_SORT_TYPE)); } if (rundata.getParameters().containsKey(ALEipConstants.LIST_START)) { current_page = rundata.getParameters().getInt(ALEipConstants.LIST_START); } } protected boolean insertMailToDB(MimeMessage mimeMessage, String filePath, boolean saveContents, boolean isRead) { try { EipTMail email = Database.create(EipTMail.class); if (saveContents) { ByteArrayOutputStream output = new ByteArrayOutputStream(); mimeMessage.writeTo(output); } else { Session session = Session.getDefaultInstance(new Properties()); Message newMsg = new MimeMessage(session); Enumeration<?> headers = mimeMessage.getAllHeaders(); while (headers.hasMoreElements()) { Header h = (Header) headers.nextElement(); newMsg.addHeader(h.getName(), h.getValue()); } newMsg.setText("メールのサイズが" + ALCommonUtils.getMaxFileSize() + "MBを超えていたため、このメールを受信できませんでした。\r\n 誠に恐れ入りますが、別のメーラーで受信してください。"); ByteArrayOutputStream output = new ByteArrayOutputStream(); newMsg.writeTo(output); } String subject; Address[] personAddress; Address[] receiveAddress; String person; Date sentDate = null; // 件名 subject = mimeMessage.getHeader(ALLocalMailMessage.SUBJECT, null); if (subject == null) { subject = MailUtility.encodeWordJIS("無題"); } else { subject = subject.replaceAll("\r", ""); subject = subject.replaceAll("\n", ""); } String type0 = (ALFolder.TYPE_RECEIVE == type_mail) ? "R" : "S"; // 差出人 or 受取人 if ("R".equals(type0)) { try { personAddress = ALMailUtils.getFromDelegateExtractForAddress(mimeMessage); } catch (MessagingException ex) { personAddress = null; } } else { try { // MimeMessage.getAllrecipientsを使うと()が抜けてデコードされた形になる personAddress = getAllRecipients(mimeMessage); } catch (MessagingException ex) { personAddress = null; } } try { // MimeMessage.getAllrecipientsを使うと()が抜けてデコードされた形になる receiveAddress = getAllRecipients(mimeMessage); } catch (MessagingException ex) { receiveAddress = null; } if (personAddress != null && personAddress.length > 0) { InternetAddress iaddress = (InternetAddress) personAddress[0]; String personaladdr = iaddress.toString(); personaladdr = MimeUtility.decodeText(personaladdr); if (personAddress.length > 1) { personaladdr += ",..."; } person = personaladdr; } else { person = "--"; } // 日付 try { sentDate = mimeMessage.getSentDate(); } catch (MessagingException ex) { } if (sentDate == null) { sentDate = Calendar.getInstance().getTime(); } // ファイル容量(KB) int fileVolume = 0; try { fileVolume = (int) Math.ceil(mimeMessage.getSize() / 1024.0); } catch (MessagingException ex) { fileVolume = 0; } // 添付ファイルの有無 String hasAttachments = null; if (saveContents) { try { ALAttachmentsExtractor h = new ALAttachmentsExtractor(); MultipartUtility.process(mimeMessage, h); hasAttachments = (h.getCount() > 0) ? "T" : "F"; } catch (MessagingException ex) { hasAttachments = "F"; } } else { hasAttachments = "F"; } // メールタイプ・既読フラグ String type = (ALFolder.TYPE_RECEIVE == type_mail) ? "R" : "S"; String read_flg = isRead ? "T" : "F"; // アカウントのフォルダに代入 EipMMailAccount account = ALMailUtils.getMailAccount(user_id, account_id); int folder_id = account.getDefaultFolderId(); // フォルダ振り分け処理 List<EipTMailFilter> filters = ALMailUtils.getEipTMailFilters(account); if (filters != null && "R".equals(type0)) { for (EipTMailFilter mailFilter : filters) { if (ALMailUtils.isMatchFilter( mailFilter, subject, person, receiveAddress)) { folder_id = mailFilter.getEipTMailFolder().getFolderId(); break; } } } email.setUserId(Integer.valueOf(user_id)); email.setAccountId(Integer.valueOf(account_id)); email.setType(type); email.setReadFlg(read_flg); email.setSubject(subject); email.setPerson(person); email.setEventDate(sentDate); email.setFileVolume(Integer.valueOf(fileVolume)); email.setHasFiles(hasAttachments); email.setFilePath(filePath); email.setFolderId(Integer.valueOf(folder_id)); // 作成日 email.setCreateDate(Calendar.getInstance().getTime()); // 更新日 email.setUpdateDate(Calendar.getInstance().getTime()); Database.commit(); } catch (Throwable t) { Database.rollback(); logger.error("ALAbstractFolder.insertMailToDB", t); return false; } return true; } /** * インデックス情報を取得します。 * * @param rundata * @param context * @return */ @Override public ResultList<EipTMail> getIndexRows(RunData rundata, Context context) throws Exception { try { // // 未読メール総数をセットする. // setUnreadMailSum(); // // 最終更新日を取得し,セットする. // setFinalAccessDate(rundata, context); String sort = ALEipUtils.getTemp(rundata, context, LIST_SORT_STR); if (sort == null || sort.equals("")) { ALEipUtils.setTemp(rundata, context, LIST_SORT_STR, ALEipUtils .getPortlet(rundata, context) .getPortletConfig() .getInitParameter("p2a-sort")); } init(rundata, context); // ソート対象が日時だった場合、ソート順を逆にする. if ("date".equals(ALEipUtils.getTemp(rundata, context, LIST_SORT_STR))) { String sort_type = ALEipUtils.getTemp(rundata, context, LIST_SORT_TYPE_STR); if (sort_type == null || sort_type.equals("")) { ALEipUtils.setTemp( rundata, context, LIST_SORT_TYPE_STR, ALEipConstants.LIST_SORT_TYPE_DESC); } } SelectQuery<EipTMail> query = getSelectQuery(rundata, context); buildSelectQueryForListView(query); buildSelectQueryForListViewSort(query, rundata, context); ResultList<EipTMail> resultList = query.getResultList(); setPageParam(resultList.getTotalCount()); return resultList; } catch (Exception ex) { logger.error("ALAbstractFolder.getIndexRows", ex); return null; } } /** * 検索条件を設定した SelectQuery を返します。 <BR> * * @param rundata * @param context * @return */ private SelectQuery<EipTMail> getSelectQuery(RunData rundata, Context context) { String type = (type_mail == TYPE_RECEIVE) ? "R" : "S"; // メールタイプが「受信」の場合、セッションからフォルダIDを取得する String folder_id = ""; if (type_mail == TYPE_RECEIVE) { folder_id = ALEipUtils.getTemp(rundata, context, ALMailUtils.FOLDER_ID); } SelectQuery<EipTMail> query = Database.query(EipTMail.class); query.select(EipTMail.MAIL_ID_PK_COLUMN); query.select(EipTMail.READ_FLG_COLUMN); query.select(EipTMail.SUBJECT_COLUMN); query.select(EipTMail.PERSON_COLUMN); query.select(EipTMail.EVENT_DATE_COLUMN); query.select(EipTMail.FILE_VOLUME_COLUMN); query.select(EipTMail.HAS_FILES_COLUMN); Expression exp1 = ExpressionFactory.matchExp(EipTMail.USER_ID_PROPERTY, Integer .valueOf(user_id)); query.setQualifier(exp1); Expression exp2 = ExpressionFactory.matchExp(EipTMail.ACCOUNT_ID_PROPERTY, Integer .valueOf(account_id)); query.andQualifier(exp2); Expression exp3 = ExpressionFactory.matchExp(EipTMail.TYPE_PROPERTY, type); query.andQualifier(exp3); // folder_id が空でなければ、フォルダIDで絞り込む if (!("".equals(folder_id))) { Expression exp4 = ExpressionFactory.matchExp(EipTMail.FOLDER_ID_PROPERTY, Integer .valueOf(folder_id)); if (ALEipUtils.getTemp(rundata, context, "WebMail_Normal") != null && ALEipUtils.getTemp(rundata, context, "WebMail_Normal") == "false") { query.andQualifier(exp4); } } return query; } /** * 保存してある UID リストを取得する. * * @return */ @Override public List<String> loadUID() { List<String> oldUIDL = new ArrayList<String>(); BufferedReader reader = null; InputStream is = null; try { try { is = ALStorageService.getFile(getFullName() + ALStorageService.separator() + ALFolder.FILE_UIDL); } catch (Throwable t) { // } if (is == null) { return oldUIDL; } reader = new BufferedReader(new InputStreamReader(is)); String line = null; while ((line = reader.readLine()) != null) { oldUIDL.add(line); } } catch (IOException ioe) { // } finally { if (is != null) { try { is.close(); } catch (IOException i) { // } } if (reader != null) { try { reader.close(); } catch (IOException ioe) { } } } return oldUIDL; } /** * UID の一覧を保存する. * * @param oldUIDL */ @Override public void saveUID(List<String> oldUIDL) { try { int length = oldUIDL.size(); StringBuilder b = new StringBuilder(); for (int i = 0; i < length; i++) { b.append(oldUIDL.get(i)); b.append(System.getProperty("line.separator")); } ALStorageService.saveFile(new ByteArrayInputStream(b.toString().getBytes( "utf-8")), getFullName(), ALFolder.FILE_UIDL); } catch (IOException ioe) { } finally { } } @Override public void setRootFolderPath(String str) { rootFolderPath = str; } protected String getRootFolderPath() { return (rootFolderPath != null && !"".equals(rootFolderPath)) ? rootFolderPath : ALMailUtils.rootFolderPath; } protected String getCategoryKey() { return (categoryKey != null && !"".equals(categoryKey)) ? categoryKey : ALMailUtils.categoryKey; } /** * 自身のフォルダまでのフルパスを取得する。 * * @return */ @Override public String getFullName() { StringBuilder key = new StringBuilder(); String categoryKeytmp = getCategoryKey(); if (categoryKeytmp != null && !"".equals(categoryKeytmp)) { key.append(categoryKeytmp); } key.append(ALStorageService.separator()); key.append(user_id); key.append(ALStorageService.separator()); key.append(account_id); if (ALFolder.TYPE_RECEIVE == type_mail) { key.append(ALStorageService.separator()).append("Receive"); } else { key.append(ALStorageService.separator()).append("Send"); } return ALStorageService.getDocumentPath(ALMailUtils.rootFolderPath, key .toString()); } /** * ページング結果のリストを取得します。 * * @param records * 検索結果 */ protected void buildSelectQueryForListView(SelectQuery<EipTMail> query) { query.limit(getRowsNum()); query.page(current_page); } /** * ページング結果のリストを取得します。 * * @param records * 検索結果 * @deprecated */ @Deprecated protected List<EipTMail> buildPaginatedList(List<EipTMail> records) { List<EipTMail> list = new ArrayList<EipTMail>(); setPageParam(records.size()); int size = records.size(); int end = (start + rows_num <= size) ? start + rows_num : size; for (int i = start; i < end; i++) { list.add(records.get(i)); } return list; } /** * * @param cnt */ protected void setPageParam(int cnt) { count = cnt; pages_num = ((int) (Math.ceil(count / (double) rows_num))); current_page = (current_page <= pages_num) ? current_page : pages_num; start = rows_num * ((current_page > 0) ? (current_page - 1) : current_page); } /** * ソート用の <code>SelectQuery</code> を構築します。 * * @param crt * @return */ protected SelectQuery<EipTMail> buildSelectQueryForListViewSort( SelectQuery<EipTMail> query, RunData rundata, Context context) { String sort = ALEipUtils.getTemp(rundata, context, LIST_SORT_STR); String sort_type = ALEipUtils.getTemp(rundata, context, LIST_SORT_TYPE_STR); String crt_key = null; Attributes map = getColumnMap(); if (sort == null) { return query; } crt_key = map.getValue(sort); if (crt_key == null) { return query; } if (sort_type != null && ALEipConstants.LIST_SORT_TYPE_DESC.equals(sort_type)) { query.orderDesending(crt_key); } else { query.orderAscending(crt_key); sort_type = ALEipConstants.LIST_SORT_TYPE_ASC; } current_sort = sort; current_sort_type = sort_type; return query; } /** * 表示する項目数を設定します。 * * @param num */ @Override public void setRowsNum(int num) { if (num >= 1) { rows_num = num; } } /** * 表示文字数を設定します。 * * @param num */ public void setStrLength(int num) { if (num >= 0) { strlen = num; } } /** * 表示文字数を取得します。 * * @return */ @Override public int getStrLength() { return strlen; } /** * 表示する項目数を取得します。 * * @return */ @Override public int getRowsNum() { return rows_num; } /** * 総件数を取得します。 * * @return */ @Override public int getCount() { return count; } /** * 総ページ数を取得します。 * * @return */ @Override public int getPagesNum() { return pages_num; } /** * 現在表示されているページを取得します。 * * @return */ @Override public int getCurrentPage() { return current_page; } /** * * @return */ @Override public String getCurrentSort() { return current_sort; } /** * * @return */ @Override public String getCurrentSortType() { return current_sort_type; } /** * * @return */ protected abstract Attributes getColumnMap(); /** * @return */ @Override public int getStart() { return start; } private Address[] getAllRecipients(MimeMessage message) throws MessagingException { // MimeMessage getAllRecipientsの移植 Address[] to = null; Address[] cc = null; Address[] bcc = null; if (message instanceof ALLocalMailMessage) { ALLocalMailMessage almessage = (ALLocalMailMessage) message; to = almessage.getRecipients(RecipientType.TO, false); cc = almessage.getRecipients(RecipientType.CC, false); bcc = almessage.getRecipients(RecipientType.BCC, false); } else { to = message.getRecipients(RecipientType.TO); cc = message.getRecipients(RecipientType.CC); bcc = message.getRecipients(RecipientType.BCC); } if (cc == null && bcc == null) { return to; // a common case } int numRecip = (to != null ? to.length : 0) + (cc != null ? cc.length : 0) + (bcc != null ? bcc.length : 0); Address[] addresses = new Address[numRecip]; int pos = 0; if (to != null) { System.arraycopy(to, 0, addresses, pos, to.length); pos += to.length; } if (cc != null) { System.arraycopy(cc, 0, addresses, pos, cc.length); pos += cc.length; } if (bcc != null) { System.arraycopy(bcc, 0, addresses, pos, bcc.length); pos += bcc.length; } Address[] all = addresses; Address[] ng = null; if (message instanceof ALLocalMailMessage) { ALLocalMailMessage almessage = (ALLocalMailMessage) message; ng = almessage.getRecipients(MimeMessage.RecipientType.NEWSGROUPS); } else { ng = message.getRecipients(MimeMessage.RecipientType.NEWSGROUPS); } if (ng == null || ng.length == 0) { return all; // the common case } if (all.length == 0) { return ng; // a rare case } Address[] _addresses = new Address[all.length + ng.length]; System.arraycopy(all, 0, addresses, 0, all.length); System.arraycopy(ng, 0, addresses, all.length, ng.length); return _addresses; } }