/******************************************************************************* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. *******************************************************************************/ package org.apache.ofbiz.service.mail; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.nio.ByteBuffer; import java.sql.Timestamp; import java.util.LinkedList; import java.util.List; import java.util.Properties; 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.MimeMessage; import org.apache.ofbiz.base.conversion.AbstractConverter; import org.apache.ofbiz.base.conversion.ConversionException; import org.apache.ofbiz.base.conversion.Converters; import org.apache.ofbiz.base.util.Debug; import org.apache.ofbiz.base.util.GeneralRuntimeException; import org.apache.ofbiz.base.util.UtilDateTime; @SuppressWarnings("serial") public class MimeMessageWrapper implements java.io.Serializable { public static final String module = MimeMessageWrapper.class.getName(); protected transient MimeMessage message = null; protected transient Session session = null; protected Properties mailProperties = null; protected String contentType = null; protected byte[] serializedBytes = null; protected int parts = 0; public MimeMessageWrapper(Session session, MimeMessage message) { this(session); this.setMessage(message); } public MimeMessageWrapper(Session session) { this.setSession(session); } public void setSession(Session session) { this.session = session; this.mailProperties = session.getProperties(); } public synchronized Session getSession() { if (session == null) { session = Session.getInstance(mailProperties, null); } return session; } public void setMessage(MimeMessage message) { if (message != null) { // serialize the message this.message = message; ByteArrayOutputStream baos = new ByteArrayOutputStream(); try { message.writeTo(baos); baos.flush(); serializedBytes = baos.toByteArray(); this.contentType = message.getContentType(); // see if this is a multi-part message Object content = message.getContent(); if (content instanceof Multipart) { Multipart mp = (Multipart) content; this.parts = mp.getCount(); } else { this.parts = 0; } } catch (MessagingException e) { Debug.logError(e, module); } catch (IOException e) { Debug.logError(e, module); } finally { try { baos.close(); } catch (IOException e) { Debug.logError(e, module); } } } } public synchronized MimeMessage getMessage() { if (message == null) { // deserialize the message if (serializedBytes != null) { ByteArrayInputStream bais = new ByteArrayInputStream(serializedBytes); try { message = new MimeMessage(this.getSession(), bais); } catch (MessagingException e) { Debug.logError(e, module); throw new GeneralRuntimeException(e.getMessage(), e); } } } return message; } public String getFirstHeader(String header) { String[] headers = getHeader(header); if (headers != null && headers.length > 0) { return headers[0]; } else { return null; } } public String[] getHeader(String header) { MimeMessage message = getMessage(); try { return message.getHeader(header); } catch (MessagingException e) { Debug.logError(e, module); return null; } } public Address[] getFrom() { MimeMessage message = getMessage(); try { return message.getFrom(); } catch (MessagingException e) { Debug.logError(e, module); return null; } } public Address[] getTo() { MimeMessage message = getMessage(); try { return message.getRecipients(MimeMessage.RecipientType.TO); } catch (MessagingException e) { Debug.logError(e, module); return null; } } public Address[] getCc() { MimeMessage message = getMessage(); try { return message.getRecipients(MimeMessage.RecipientType.CC); } catch (MessagingException e) { Debug.logError(e, module); return null; } } public Address[] getBcc() { MimeMessage message = getMessage(); try { return message.getRecipients(MimeMessage.RecipientType.BCC); } catch (MessagingException e) { Debug.logError(e, module); return null; } } public String getSubject() { MimeMessage message = getMessage(); try { return message.getSubject(); } catch (MessagingException e) { Debug.logError(e, module); return null; } } public String getMessageId() { MimeMessage message = getMessage(); try { return message.getMessageID(); } catch (MessagingException e) { Debug.logError(e, module); return null; } } public Timestamp getSentDate() { MimeMessage message = getMessage(); try { return UtilDateTime.toTimestamp(message.getSentDate()); } catch (MessagingException e) { Debug.logError(e, module); return null; } } public Timestamp getReceivedDate() { MimeMessage message = getMessage(); try { return UtilDateTime.toTimestamp(message.getReceivedDate()); } catch (MessagingException e) { Debug.logError(e, module); return null; } } public String getContentType() { return contentType; } public int getMainPartCount() { return this.parts; } public int getSubPartCount(int index) { BodyPart part = getPart(Integer.toString(index)); try { Object content = part.getContent(); if (content instanceof Multipart) { return ((Multipart) content).getCount(); } else { return 0; } } catch (Exception e) { Debug.logError(e, module); return -1; } } public List<String> getAttachmentIndexes() { List<String> attachments = new LinkedList<String>(); if (getMainPartCount() == 0) { // single part message (no attachments) return attachments; } else { for (int i = 0; i < getMainPartCount(); i++) { int subPartCount = getSubPartCount(i); String idx = Integer.toString(i); if (subPartCount > 0) { for (int si = 0; si < subPartCount; si++) { String sidx = idx + "." + Integer.toString(si); if (getPartDisposition(sidx) != null && (getPartDisposition(sidx).equalsIgnoreCase(Part.ATTACHMENT) || getPartDisposition(sidx).equalsIgnoreCase(Part.INLINE))) { attachments.add(sidx); } } } else { if (getPartDisposition(idx) != null && (getPartDisposition(idx).equalsIgnoreCase(Part.ATTACHMENT) || getPartDisposition(idx).equalsIgnoreCase(Part.INLINE))) { attachments.add(idx); } } } return attachments; } } public String getMessageBody() { MimeMessage message = getMessage(); if (getMainPartCount() == 0) { // single part message try { Object content = message.getContent(); return getContentText(content); } catch (Exception e) { Debug.logError(e, module); return null; } } else { // multi-part message StringBuffer body = new StringBuffer(); for (int i = 0; i < getMainPartCount(); i++) { int subPartCount = getSubPartCount(i); String idx = Integer.toString(i); if (subPartCount > 0) { for (int si = 0; si < subPartCount; si++) { String sidx = idx + "." + Integer.toString(si); if (getPartContentType(sidx) != null && getPartContentType(sidx).toLowerCase().startsWith("text")) { if (getPartDisposition(sidx) == null || getPartDisposition(sidx).equals(Part.INLINE)) { body.append(getPartText(sidx)).append("\n"); } } } } else { if (getPartContentType(idx) != null && getPartContentType(idx).toLowerCase().startsWith("text")) { // make sure the part isn't an attachment if (getPartDisposition(idx) == null || getPartDisposition(idx).equals(Part.INLINE)) { body.append(getPartText(idx)).append("\n"); } } } } return body.toString(); } } public String getMessageBodyContentType() { String contentType = getContentType(); if (contentType != null && contentType.toLowerCase().startsWith("text")) { return contentType; } else { for (int i = 0; i < getMainPartCount(); i++) { int subPartCount = getSubPartCount(i); String idx = Integer.toString(i); if (subPartCount > 0) { for (int si = 0; si < subPartCount; si++) { String sidx = idx + "." + Integer.toString(si); if (getPartContentType(sidx) != null && getPartContentType(sidx).toLowerCase().startsWith("text")) { if (getPartDisposition(sidx) == null || getPartDisposition(sidx).equals(Part.INLINE)) { return getPartContentType(sidx); } } } } else { if (getPartContentType(idx) != null && getPartContentType(idx).toLowerCase().startsWith("text")) { // make sure the part isn't an attachment if (getPartDisposition(idx) == null || getPartDisposition(idx).equals(Part.INLINE)) { return getPartContentType(idx); } } } } } return "text/html"; } public String getMessageRawText() { MimeMessage message = getMessage(); try { return getTextFromStream(message.getInputStream()); } catch (Exception e) { Debug.logError(e, module); return null; } } public String getPartDescription(String index) { BodyPart part = getPart(index); if (part != null) { try { return part.getDescription(); } catch (MessagingException e) { Debug.logError(e, module); return null; } } else { return null; } } public String getPartContentType(String index) { BodyPart part = getPart(index); if (part != null) { try { return part.getContentType(); } catch (MessagingException e) { Debug.logError(e, module); return null; } } else { return null; } } public String getPartDisposition(String index) { BodyPart part = getPart(index); if (part != null) { try { return part.getDisposition(); } catch (MessagingException e) { Debug.logError(e, module); return null; } } else { return null; } } public String getPartFilename(String index) { BodyPart part = getPart(index); if (part != null) { try { return part.getFileName(); } catch (MessagingException e) { Debug.logError(e, module); return null; } } else { return null; } } public ByteBuffer getPartByteBuffer(String index) { BodyPart part = getPart(index); if (part != null) { try { InputStream stream = part.getInputStream(); return getByteBufferFromStream(stream); } catch (Exception e) { Debug.logError(e, module); return null; } } else { return null; } } public String getPartText(String index) { BodyPart part = getPart(index); if (part != null) { try { return getContentText(part.getContent()); } catch (Exception e) { Debug.logError(e, module); return null; } } else { return null; } } public String getPartRawText(String index) { BodyPart part = getPart(index); if (part != null) { try { return getTextFromStream(part.getInputStream()); } catch (Exception e) { Debug.logError(e, module); return null; } } else { return null; } } public BodyPart getPart(String indexStr) { int mainIndex, subIndex; try { if (indexStr.indexOf(".") == -1) { mainIndex = Integer.parseInt(indexStr); subIndex = -1; } else { String[] indexSplit = indexStr.split("\\."); mainIndex = Integer.parseInt(indexSplit[0]); subIndex = Integer.parseInt(indexSplit[1]); } } catch (NumberFormatException e) { Debug.logError(e, "Illegal index string format. Should be part 'dot' subpart: " + indexStr, module); return null; } catch (ArrayIndexOutOfBoundsException e) { Debug.logError(e, "Illegal index string format. Should be part 'dot' subpart: " + indexStr, module); return null; } if (getMainPartCount() > 0 && getMainPartCount() > mainIndex) { MimeMessage message = this.getMessage(); try { Multipart mp = (Multipart) message.getContent(); if (subIndex == -1) { return mp.getBodyPart(mainIndex); } else { BodyPart part = mp.getBodyPart(mainIndex); int subPartCount = getSubPartCount(mainIndex); if (subPartCount > subIndex) { Multipart sp = (Multipart) part.getContent(); return sp.getBodyPart(subIndex); } else { Debug.logWarning("Requested a subpart [" + subIndex + "] which deos not exist; only [" + getSubPartCount(mainIndex) + "] parts", module); // there is no sub part to find return part; } } } catch (MessagingException e) { Debug.logError(e, module); return null; } catch (IOException e) { Debug.logError(e, module); return null; } } else { Debug.logWarning("Requested a part [" + mainIndex + "] which deos not exist; only [" + getMainPartCount() + "] parts", module); return null; } } protected String getContentText(Object content) { if (content == null) return null; if (content instanceof String) { return (String) content; } else if (content instanceof InputStream) { return getTextFromStream((InputStream) content); } else if (content instanceof Message) { try { return getTextFromStream(((Message) content).getInputStream()); } catch (Exception e) { Debug.logError(e, module); return null; } } else { Debug.logWarning("Content was not a string or a stream; no known handler -- " + content.toString(), module); return null; } } protected String getTextFromStream(InputStream stream) { StringBuilder builder = new StringBuilder(); byte[] buffer = new byte[4096]; try { for (int n; (n = stream.read(buffer)) != -1;) { builder.append(new String(buffer, 0, n)); } } catch (IOException e) { Debug.logError(e, module); return null; } return builder.toString(); } protected ByteBuffer getByteBufferFromStream(InputStream stream) { ByteArrayOutputStream baos = new ByteArrayOutputStream(); byte[] buffer = new byte[4096]; try { for (int n; (n = stream.read(buffer)) != -1;) { baos.write(buffer, 0, n); } } catch (IOException e) { Debug.logError(e, module); return null; } return ByteBuffer.wrap(baos.toByteArray()); } static { Converters.registerConverter(new MimeMessageToString<String>()); } /** * Convert MimeMessageWrapper to String. This is used when sending emails. * */ private static class MimeMessageToString<E> extends AbstractConverter<MimeMessageWrapper, String> { public MimeMessageToString() { super(MimeMessageWrapper.class, String.class); } public String convert(MimeMessageWrapper obj) throws ConversionException { return obj.toString(); } } }