/* * (C) Copyright 2006-2009 Nuxeo SAS (http://nuxeo.com/) and contributors. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the GNU Lesser General Public License * (LGPL) version 2.1 which accompanies this distribution, and is available at * http://www.gnu.org/licenses/lgpl.html * * This library 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 * Lesser General Public License for more details. * * Contributors: * Nuxeo - initial API and implementation * * $Id$ */ package org.nuxeo.ecm.platfrom.mail.listener.action; import static org.nuxeo.ecm.platform.mail.utils.MailCoreConstants.ATTACHMENTS_KEY; import static org.nuxeo.ecm.platform.mail.utils.MailCoreConstants.CC_RECIPIENTS_KEY; import static org.nuxeo.ecm.platform.mail.utils.MailCoreConstants.MIMETYPE_SERVICE_KEY; import static org.nuxeo.ecm.platform.mail.utils.MailCoreConstants.RECIPIENTS_KEY; import static org.nuxeo.ecm.platform.mail.utils.MailCoreConstants.SENDER_KEY; import static org.nuxeo.ecm.platform.mail.utils.MailCoreConstants.SENDING_DATE_KEY; import static org.nuxeo.ecm.platform.mail.utils.MailCoreConstants.SUBJECT_KEY; import static org.nuxeo.ecm.platform.mail.utils.MailCoreConstants.TEXT_KEY; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Collection; import java.util.List; import javax.mail.Address; import javax.mail.Message; import javax.mail.MessagingException; import javax.mail.Multipart; import javax.mail.Part; import javax.mail.internet.ContentType; import javax.mail.internet.InternetAddress; import javax.mail.internet.MimeUtility; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.nuxeo.common.utils.FileUtils; import org.nuxeo.ecm.core.api.Blob; import org.nuxeo.ecm.core.api.impl.blob.FileBlob; import org.nuxeo.ecm.platform.mail.action.ExecutionContext; import org.nuxeo.ecm.platform.mimetype.interfaces.MimetypeRegistry; /** * Puts on the pipe execution context the values retrieved from the new messages * found in the INBOX. These values are used later when new MailMessage * documents are created based on them. * * @author Catalin Baican * */ public class ExtractMessageInformationAction extends AbstractMailAction { private static final Log log = LogFactory.getLog(ExtractMessageInformationAction.class); public static final String DEFAULT_BINARY_MIMETYPE = "application/octet-stream*"; public static final String MESSAGE_RFC822_MIMETYPE = "message/rfc822"; private String bodyContent; public boolean execute(ExecutionContext context) throws Exception { bodyContent = ""; try { Message message = context.getMessage(); if (log.isDebugEnabled()) { log.debug("Transforming message" + message.getSubject()); } // Subject String subject = message.getSubject(); if (subject != null) { subject = subject.trim(); } if (subject == null || "".equals(subject)) { subject = ""; } context.put(SUBJECT_KEY, subject); // Sender Address[] from = message.getFrom(); String sender = null; if (from != null) { Address addr = from[0]; if (addr instanceof InternetAddress) { InternetAddress iAddr = (InternetAddress) addr; sender = iAddr.getPersonal() + " <" + iAddr.getAddress() + ">"; } else { sender += addr.toString(); } } context.put(SENDER_KEY, sender); // Sending date context.put(SENDING_DATE_KEY, message.getSentDate()); // Recipients Address[] to = message.getRecipients(Message.RecipientType.TO); Collection recipients = new ArrayList(); if (to != null) { for (Address addr : to) { if (addr instanceof InternetAddress) { InternetAddress iAddr = (InternetAddress) addr; if (iAddr.getPersonal() != null) { recipients.add(iAddr.getPersonal() + " <" + iAddr.getAddress() + ">"); } else { recipients.add(iAddr.getAddress()); } } else { recipients.add(addr.toString()); } } } context.put(RECIPIENTS_KEY, recipients); // CC recipients Address[] toCC = message.getRecipients(Message.RecipientType.CC); Collection ccRecipients = new ArrayList(); if (toCC != null) { for (Address addr : toCC) { if (addr instanceof InternetAddress) { InternetAddress iAddr = (InternetAddress) addr; ccRecipients.add(iAddr.getPersonal() + " " + iAddr.getAddress()); } else { ccRecipients.add(addr.toString()); } } } context.put(CC_RECIPIENTS_KEY, ccRecipients); MimetypeRegistry mimeService = (MimetypeRegistry) context.getInitialContext().get( MIMETYPE_SERVICE_KEY); List blobs = new ArrayList(); context.put(ATTACHMENTS_KEY, blobs); // process content getAttachmentParts(message, subject, mimeService, context); context.put(TEXT_KEY, bodyContent); return true; } catch (Exception e) { log.error(e, e); } return false; } protected static String getFilename(Part p, String defaultFileName) throws Exception { String originalFilename = p.getFileName(); if (originalFilename == null || originalFilename.trim().length() == 0) { String filename = defaultFileName; // using default filename => add extension for this type if (p.isMimeType("text/plain")) { filename += ".txt"; } else if (p.isMimeType("text/html")) { filename += ".html"; } return filename; } else { try { return MimeUtility.decodeText(originalFilename.trim()); } catch (Exception e) { return originalFilename.trim(); } } } protected void getAttachmentParts(Part part, String defaultFilename, MimetypeRegistry mimeService, ExecutionContext context) throws Exception { String filename = getFilename(part, defaultFilename); List blobs = (List) context.get(ATTACHMENTS_KEY); if (!part.isMimeType("multipart/*")) { String disp = part.getDisposition(); // no disposition => mail body, which can be also blob (image for // instance) if (disp == null && // convert only text part.getContentType().toLowerCase().startsWith("text/")) { bodyContent += decodeMailBody(part); } else { FileBlob fileBlob = new FileBlob(part.getInputStream()); String mime = DEFAULT_BINARY_MIMETYPE; try { if (mimeService != null) { ContentType contentType = new ContentType( part.getContentType()); mime = mimeService.getMimetypeFromFilenameAndBlobWithDefault( filename, fileBlob, contentType.getBaseType()); } } catch (Exception e) { log.error(e); } fileBlob.setMimeType(mime); fileBlob.setFilename(filename); blobs.add(fileBlob); } } if (part.isMimeType("multipart/*")) { // This is a Multipart Multipart mp = (Multipart) part.getContent(); int count = mp.getCount(); for (int i = 0; i < count; i++) { getAttachmentParts(mp.getBodyPart(i), defaultFilename, mimeService, context); } } else if (part.isMimeType(MESSAGE_RFC822_MIMETYPE)) { // This is a Nested Message getAttachmentParts((Part) part.getContent(), defaultFilename, mimeService, context); } } public void reset(ExecutionContext context) throws Exception { // do nothing } /** * Interprets the body accordingly to the charset used. It relies on the * content type being ****;charset={charset};****** * * @param part * @return the decoded String * @throws MessagingException * @throws IOException */ protected static String decodeMailBody(Part part) throws MessagingException, IOException { InputStream is = part.getInputStream(); String contType = part.getContentType(); final String charsetIdentifier = "charset="; final String ISO88591 = "iso-8859-1"; final String WINDOWS1252 = "windows-1252"; int offset = contType.indexOf(charsetIdentifier); String charset = ""; if (offset >= 0) { charset = contType.substring(offset + charsetIdentifier.length()); offset = charset.indexOf(";"); if (offset > 0) { charset = charset.substring(0, offset); } } log.debug("Content type: " + contType + "; charset: " + charset); if (charset.equalsIgnoreCase(ISO88591)) { // see // http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html#character1 // for more details see http://en.wikipedia.org/wiki/ISO_8859-1 // section "ISO-8859-1 and Windows-1252 confusion" charset = WINDOWS1252; log.debug("Using replacing charset: " + charset); } String ret; // FIXME new String(FileUtils.readBytes(is), charset) throws exceptions all the time, //commented out for the moment. // if (StringUtils.isBlank(charset)) { // ret = new String(FileUtils.readBytes(is)); // } else { // ret = new String(FileUtils.readBytes(is), charset); // } ret = new String(FileUtils.readBytes(is)); return ret; } }