1345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein/* 2345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein * Copyright (C) 2008 The Android Open Source Project 3345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein * 4345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein * Licensed under the Apache License, Version 2.0 (the "License"); 5345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein * you may not use this file except in compliance with the License. 6345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein * You may obtain a copy of the License at 7345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein * 8345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein * http://www.apache.org/licenses/LICENSE-2.0 9345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein * 10345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein * Unless required by applicable law or agreed to in writing, software 11345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein * distributed under the License is distributed on an "AS IS" BASIS, 12345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein * See the License for the specific language governing permissions and 14345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein * limitations under the License. 15345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein */ 16345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein 17345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sappersteinpackage com.android.emailcommon.internet; 18345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein 19345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sappersteinimport com.android.emailcommon.mail.Address; 20345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sappersteinimport com.android.emailcommon.mail.Body; 21345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sappersteinimport com.android.emailcommon.mail.BodyPart; 22345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sappersteinimport com.android.emailcommon.mail.Message; 23345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sappersteinimport com.android.emailcommon.mail.MessagingException; 24345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sappersteinimport com.android.emailcommon.mail.Multipart; 25345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sappersteinimport com.android.emailcommon.mail.Part; 2609eca8072a2396527baede2b312d91daf1c9c2b9Martin Hibdonimport com.android.mail.utils.LogUtils; 27345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein 28345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sappersteinimport org.apache.james.mime4j.BodyDescriptor; 29345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sappersteinimport org.apache.james.mime4j.ContentHandler; 30345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sappersteinimport org.apache.james.mime4j.EOLConvertingInputStream; 31345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sappersteinimport org.apache.james.mime4j.MimeStreamParser; 32345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sappersteinimport org.apache.james.mime4j.field.DateTimeField; 33345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sappersteinimport org.apache.james.mime4j.field.Field; 34345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein 35345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sappersteinimport android.text.TextUtils; 36345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein 37345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sappersteinimport java.io.BufferedWriter; 38345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sappersteinimport java.io.IOException; 39345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sappersteinimport java.io.InputStream; 40345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sappersteinimport java.io.OutputStream; 41345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sappersteinimport java.io.OutputStreamWriter; 42345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sappersteinimport java.text.SimpleDateFormat; 43345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sappersteinimport java.util.Date; 44345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sappersteinimport java.util.Locale; 45345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sappersteinimport java.util.Stack; 46345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sappersteinimport java.util.regex.Pattern; 47345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein 48345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein/** 49345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein * An implementation of Message that stores all of its metadata in RFC 822 and 50345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein * RFC 2045 style headers. 51345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein * 52345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein * NOTE: Automatic generation of a local message-id is becoming unwieldy and should be removed. 53345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein * It would be better to simply do it explicitly on local creation of new outgoing messages. 54345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein */ 55345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sappersteinpublic class MimeMessage extends Message { 56345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein private MimeHeader mHeader; 57345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein private MimeHeader mExtendedHeader; 58345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein 5909eca8072a2396527baede2b312d91daf1c9c2b9Martin Hibdon // NOTE: The fields here are transcribed out of headers, and values stored here will supersede 60345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein // the values found in the headers. Use caution to prevent any out-of-phase errors. In 61345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein // particular, any adds/changes/deletes here must be echoed by changes in the parse() function. 62345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein private Address[] mFrom; 63345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein private Address[] mTo; 64345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein private Address[] mCc; 65345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein private Address[] mBcc; 66345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein private Address[] mReplyTo; 67345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein private Date mSentDate; 68345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein private Body mBody; 69345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein protected int mSize; 70345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein private boolean mInhibitLocalMessageId = false; 71345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein private boolean mComplete = true; 72345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein 73345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein // Shared random source for generating local message-id values 74345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein private static final java.util.Random sRandom = new java.util.Random(); 75345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein 76345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein // In MIME, en_US-like date format should be used. In other words "MMM" should be encoded to 77345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein // "Jan", not the other localized format like "Ene" (meaning January in locale es). 78345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein // This conversion is used when generating outgoing MIME messages. Incoming MIME date 79345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein // headers are parsed by org.apache.james.mime4j.field.DateTimeField which does not have any 80345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein // localization code. 81345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein private static final SimpleDateFormat DATE_FORMAT = 82345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss Z", Locale.US); 83345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein 84345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein // regex that matches content id surrounded by "<>" optionally. 85345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein private static final Pattern REMOVE_OPTIONAL_BRACKETS = Pattern.compile("^<?([^>]+)>?$"); 86345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein // regex that matches end of line. 87345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein private static final Pattern END_OF_LINE = Pattern.compile("\r?\n"); 88345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein 89345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein public MimeMessage() { 90345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein mHeader = null; 91345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 92345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein 93345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein /** 94345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein * Generate a local message id. This is only used when none has been assigned, and is 95345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein * installed lazily. Any remote (typically server-assigned) message id takes precedence. 96345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein * @return a long, locally-generated message-ID value 97345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein */ 983b965d78774a42358ce6bbdcc43b4c8df130a60eScott Kennedy private static String generateMessageId() { 997ddf672ebc7b43350a52573ef682e4f3f59ae2d1Tony Mantler final StringBuilder sb = new StringBuilder(); 100345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein sb.append("<"); 101345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein for (int i = 0; i < 24; i++) { 102345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein // We'll use a 5-bit range (0..31) 1037ddf672ebc7b43350a52573ef682e4f3f59ae2d1Tony Mantler final int value = sRandom.nextInt() & 31; 1047ddf672ebc7b43350a52573ef682e4f3f59ae2d1Tony Mantler final char c = "0123456789abcdefghijklmnopqrstuv".charAt(value); 105345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein sb.append(c); 106345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 107345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein sb.append("."); 108345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein sb.append(Long.toString(System.currentTimeMillis())); 109345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein sb.append("@email.android.com>"); 110345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein return sb.toString(); 111345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 112345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein 113345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein /** 114345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein * Parse the given InputStream using Apache Mime4J to build a MimeMessage. 115345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein * 1167ddf672ebc7b43350a52573ef682e4f3f59ae2d1Tony Mantler * @param in InputStream providing message content 117345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein * @throws IOException 118345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein * @throws MessagingException 119345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein */ 120345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein public MimeMessage(InputStream in) throws IOException, MessagingException { 121345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein parse(in); 122345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 123345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein 124345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein private MimeStreamParser init() { 125345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein // Before parsing the input stream, clear all local fields that may be superceded by 126345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein // the new incoming message. 127345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein getMimeHeaders().clear(); 128345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein mInhibitLocalMessageId = true; 129345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein mFrom = null; 130345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein mTo = null; 131345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein mCc = null; 132345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein mBcc = null; 133345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein mReplyTo = null; 134345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein mSentDate = null; 135345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein mBody = null; 136345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein 1377ddf672ebc7b43350a52573ef682e4f3f59ae2d1Tony Mantler final MimeStreamParser parser = new MimeStreamParser(); 138345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein parser.setContentHandler(new MimeMessageBuilder()); 139345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein return parser; 140345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 141345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein 142345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein protected void parse(InputStream in) throws IOException, MessagingException { 1437ddf672ebc7b43350a52573ef682e4f3f59ae2d1Tony Mantler final MimeStreamParser parser = init(); 144345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein parser.parse(new EOLConvertingInputStream(in)); 145345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein mComplete = !parser.getPrematureEof(); 146345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 147345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein 148345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein public void parse(InputStream in, EOLConvertingInputStream.Callback callback) 149345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein throws IOException, MessagingException { 1507ddf672ebc7b43350a52573ef682e4f3f59ae2d1Tony Mantler final MimeStreamParser parser = init(); 151345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein parser.parse(new EOLConvertingInputStream(in, getSize(), callback)); 152345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein mComplete = !parser.getPrematureEof(); 153345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 154345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein 155345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein /** 156345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein * Return the internal mHeader value, with very lazy initialization. 157345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein * The goal is to save memory by not creating the headers until needed. 158345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein */ 159345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein private MimeHeader getMimeHeaders() { 160345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein if (mHeader == null) { 161345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein mHeader = new MimeHeader(); 162345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 163345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein return mHeader; 164345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 165345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein 166345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein @Override 167345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein public Date getReceivedDate() throws MessagingException { 168345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein return null; 169345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 170345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein 171345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein @Override 172345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein public Date getSentDate() throws MessagingException { 173345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein if (mSentDate == null) { 174345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein try { 175345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein DateTimeField field = (DateTimeField)Field.parse("Date: " 176345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein + MimeUtility.unfoldAndDecode(getFirstHeader("Date"))); 177345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein mSentDate = field.getDate(); 17809eca8072a2396527baede2b312d91daf1c9c2b9Martin Hibdon // TODO: We should make it more clear what exceptions can be thrown here, 17909eca8072a2396527baede2b312d91daf1c9c2b9Martin Hibdon // and whether they reflect a normal or error condition. 18009eca8072a2396527baede2b312d91daf1c9c2b9Martin Hibdon } catch (Exception e) { 1817ddf672ebc7b43350a52573ef682e4f3f59ae2d1Tony Mantler LogUtils.v(LogUtils.TAG, "Message missing Date header"); 18209eca8072a2396527baede2b312d91daf1c9c2b9Martin Hibdon } 18309eca8072a2396527baede2b312d91daf1c9c2b9Martin Hibdon } 18409eca8072a2396527baede2b312d91daf1c9c2b9Martin Hibdon if (mSentDate == null) { 18509eca8072a2396527baede2b312d91daf1c9c2b9Martin Hibdon // If we still don't have a date, fall back to "Delivery-date" 18609eca8072a2396527baede2b312d91daf1c9c2b9Martin Hibdon try { 18709eca8072a2396527baede2b312d91daf1c9c2b9Martin Hibdon DateTimeField field = (DateTimeField)Field.parse("Date: " 18809eca8072a2396527baede2b312d91daf1c9c2b9Martin Hibdon + MimeUtility.unfoldAndDecode(getFirstHeader("Delivery-date"))); 18909eca8072a2396527baede2b312d91daf1c9c2b9Martin Hibdon mSentDate = field.getDate(); 19009eca8072a2396527baede2b312d91daf1c9c2b9Martin Hibdon // TODO: We should make it more clear what exceptions can be thrown here, 19109eca8072a2396527baede2b312d91daf1c9c2b9Martin Hibdon // and whether they reflect a normal or error condition. 192345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } catch (Exception e) { 1937ddf672ebc7b43350a52573ef682e4f3f59ae2d1Tony Mantler LogUtils.v(LogUtils.TAG, "Message also missing Delivery-Date header"); 194345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 195345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 196345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein return mSentDate; 197345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 198345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein 199345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein @Override 200345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein public void setSentDate(Date sentDate) throws MessagingException { 201345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein setHeader("Date", DATE_FORMAT.format(sentDate)); 202345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein this.mSentDate = sentDate; 203345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 204345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein 205345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein @Override 206345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein public String getContentType() throws MessagingException { 2077ddf672ebc7b43350a52573ef682e4f3f59ae2d1Tony Mantler final String contentType = getFirstHeader(MimeHeader.HEADER_CONTENT_TYPE); 208345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein if (contentType == null) { 209345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein return "text/plain"; 210345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } else { 211345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein return contentType; 212345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 213345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 214345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein 215aa27bc0e1c3bb6be4609b00007637a9d3e960f5eScott Kennedy @Override 216345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein public String getDisposition() throws MessagingException { 2177ddf672ebc7b43350a52573ef682e4f3f59ae2d1Tony Mantler return getFirstHeader(MimeHeader.HEADER_CONTENT_DISPOSITION); 218345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 219345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein 220aa27bc0e1c3bb6be4609b00007637a9d3e960f5eScott Kennedy @Override 221345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein public String getContentId() throws MessagingException { 2227ddf672ebc7b43350a52573ef682e4f3f59ae2d1Tony Mantler final String contentId = getFirstHeader(MimeHeader.HEADER_CONTENT_ID); 223345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein if (contentId == null) { 224345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein return null; 225345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } else { 226345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein // remove optionally surrounding brackets. 227345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein return REMOVE_OPTIONAL_BRACKETS.matcher(contentId).replaceAll("$1"); 228345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 229345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 230345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein 231345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein public boolean isComplete() { 232345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein return mComplete; 233345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 234345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein 235aa27bc0e1c3bb6be4609b00007637a9d3e960f5eScott Kennedy @Override 236345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein public String getMimeType() throws MessagingException { 237345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein return MimeUtility.getHeaderParameter(getContentType(), null); 238345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 239345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein 240aa27bc0e1c3bb6be4609b00007637a9d3e960f5eScott Kennedy @Override 241345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein public int getSize() throws MessagingException { 242345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein return mSize; 243345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 244345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein 245345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein /** 246345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein * Returns a list of the given recipient type from this message. If no addresses are 247345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein * found the method returns an empty array. 248345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein */ 249345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein @Override 250345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein public Address[] getRecipients(RecipientType type) throws MessagingException { 251345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein if (type == RecipientType.TO) { 252345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein if (mTo == null) { 253345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein mTo = Address.parse(MimeUtility.unfold(getFirstHeader("To"))); 254345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 255345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein return mTo; 256345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } else if (type == RecipientType.CC) { 257345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein if (mCc == null) { 258345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein mCc = Address.parse(MimeUtility.unfold(getFirstHeader("CC"))); 259345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 260345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein return mCc; 261345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } else if (type == RecipientType.BCC) { 262345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein if (mBcc == null) { 263345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein mBcc = Address.parse(MimeUtility.unfold(getFirstHeader("BCC"))); 264345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 265345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein return mBcc; 266345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } else { 267345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein throw new MessagingException("Unrecognized recipient type."); 268345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 269345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 270345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein 271345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein @Override 272345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein public void setRecipients(RecipientType type, Address[] addresses) throws MessagingException { 273345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein final int TO_LENGTH = 4; // "To: " 274345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein final int CC_LENGTH = 4; // "Cc: " 275345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein final int BCC_LENGTH = 5; // "Bcc: " 276345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein if (type == RecipientType.TO) { 277345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein if (addresses == null || addresses.length == 0) { 278345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein removeHeader("To"); 279345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein this.mTo = null; 280345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } else { 281345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein setHeader("To", MimeUtility.fold(Address.toHeader(addresses), TO_LENGTH)); 282345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein this.mTo = addresses; 283345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 284345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } else if (type == RecipientType.CC) { 285345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein if (addresses == null || addresses.length == 0) { 286345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein removeHeader("CC"); 287345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein this.mCc = null; 288345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } else { 289345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein setHeader("CC", MimeUtility.fold(Address.toHeader(addresses), CC_LENGTH)); 290345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein this.mCc = addresses; 291345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 292345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } else if (type == RecipientType.BCC) { 293345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein if (addresses == null || addresses.length == 0) { 294345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein removeHeader("BCC"); 295345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein this.mBcc = null; 296345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } else { 297345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein setHeader("BCC", MimeUtility.fold(Address.toHeader(addresses), BCC_LENGTH)); 298345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein this.mBcc = addresses; 299345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 300345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } else { 301345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein throw new MessagingException("Unrecognized recipient type."); 302345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 303345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 304345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein 305345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein /** 306345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein * Returns the unfolded, decoded value of the Subject header. 307345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein */ 308345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein @Override 309345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein public String getSubject() throws MessagingException { 310345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein return MimeUtility.unfoldAndDecode(getFirstHeader("Subject")); 311345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 312345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein 313345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein @Override 314345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein public void setSubject(String subject) throws MessagingException { 315345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein final int HEADER_NAME_LENGTH = 9; // "Subject: " 316345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein setHeader("Subject", MimeUtility.foldAndEncode2(subject, HEADER_NAME_LENGTH)); 317345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 318345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein 319345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein @Override 320345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein public Address[] getFrom() throws MessagingException { 321345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein if (mFrom == null) { 322345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein String list = MimeUtility.unfold(getFirstHeader("From")); 323345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein if (list == null || list.length() == 0) { 324345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein list = MimeUtility.unfold(getFirstHeader("Sender")); 325345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 326345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein mFrom = Address.parse(list); 327345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 328345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein return mFrom; 329345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 330345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein 331345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein @Override 332345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein public void setFrom(Address from) throws MessagingException { 333345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein final int FROM_LENGTH = 6; // "From: " 334345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein if (from != null) { 335345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein setHeader("From", MimeUtility.fold(from.toHeader(), FROM_LENGTH)); 336345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein this.mFrom = new Address[] { 337345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein from 338345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein }; 339345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } else { 340345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein this.mFrom = null; 341345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 342345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 343345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein 344345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein @Override 345345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein public Address[] getReplyTo() throws MessagingException { 346345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein if (mReplyTo == null) { 347345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein mReplyTo = Address.parse(MimeUtility.unfold(getFirstHeader("Reply-to"))); 348345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 349345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein return mReplyTo; 350345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 351345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein 352345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein @Override 353345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein public void setReplyTo(Address[] replyTo) throws MessagingException { 354345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein final int REPLY_TO_LENGTH = 10; // "Reply-to: " 355345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein if (replyTo == null || replyTo.length == 0) { 356345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein removeHeader("Reply-to"); 357345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein mReplyTo = null; 358345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } else { 359345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein setHeader("Reply-to", MimeUtility.fold(Address.toHeader(replyTo), REPLY_TO_LENGTH)); 360345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein mReplyTo = replyTo; 361345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 362345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 363345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein 364345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein /** 365345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein * Set the mime "Message-ID" header 366345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein * @param messageId the new Message-ID value 367345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein * @throws MessagingException 368345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein */ 369345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein @Override 370345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein public void setMessageId(String messageId) throws MessagingException { 371345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein setHeader("Message-ID", messageId); 372345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 373345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein 374345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein /** 375345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein * Get the mime "Message-ID" header. This value will be preloaded with a locally-generated 376345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein * random ID, if the value has not previously been set. Local generation can be inhibited/ 377345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein * overridden by explicitly clearing the headers, removing the message-id header, etc. 378345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein * @return the Message-ID header string, or null if explicitly has been set to null 379345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein */ 380345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein @Override 381345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein public String getMessageId() throws MessagingException { 382345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein String messageId = getFirstHeader("Message-ID"); 383345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein if (messageId == null && !mInhibitLocalMessageId) { 384345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein messageId = generateMessageId(); 385345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein setMessageId(messageId); 386345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 387345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein return messageId; 388345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 389345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein 390345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein @Override 391345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein public void saveChanges() throws MessagingException { 392345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein throw new MessagingException("saveChanges not yet implemented"); 393345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 394345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein 395345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein @Override 396345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein public Body getBody() throws MessagingException { 397345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein return mBody; 398345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 399345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein 400345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein @Override 401345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein public void setBody(Body body) throws MessagingException { 402345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein this.mBody = body; 403345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein if (body instanceof Multipart) { 4047ddf672ebc7b43350a52573ef682e4f3f59ae2d1Tony Mantler final Multipart multipart = ((Multipart)body); 405345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein multipart.setParent(this); 406345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein setHeader(MimeHeader.HEADER_CONTENT_TYPE, multipart.getContentType()); 407345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein setHeader("MIME-Version", "1.0"); 408345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 409345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein else if (body instanceof TextBody) { 410345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein setHeader(MimeHeader.HEADER_CONTENT_TYPE, String.format("%s;\n charset=utf-8", 411345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein getMimeType())); 412345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein setHeader(MimeHeader.HEADER_CONTENT_TRANSFER_ENCODING, "base64"); 413345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 414345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 415345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein 416345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein protected String getFirstHeader(String name) throws MessagingException { 417345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein return getMimeHeaders().getFirstHeader(name); 418345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 419345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein 420345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein @Override 421345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein public void addHeader(String name, String value) throws MessagingException { 422345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein getMimeHeaders().addHeader(name, value); 423345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 424345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein 425345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein @Override 426345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein public void setHeader(String name, String value) throws MessagingException { 427345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein getMimeHeaders().setHeader(name, value); 428345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 429345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein 430345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein @Override 431345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein public String[] getHeader(String name) throws MessagingException { 432345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein return getMimeHeaders().getHeader(name); 433345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 434345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein 435345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein @Override 436345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein public void removeHeader(String name) throws MessagingException { 437345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein getMimeHeaders().removeHeader(name); 438345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein if ("Message-ID".equalsIgnoreCase(name)) { 439345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein mInhibitLocalMessageId = true; 440345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 441345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 442345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein 443345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein /** 444345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein * Set extended header 445345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein * 446345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein * @param name Extended header name 447345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein * @param value header value - flattened by removing CR-NL if any 448345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein * remove header if value is null 449345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein * @throws MessagingException 450345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein */ 451aa27bc0e1c3bb6be4609b00007637a9d3e960f5eScott Kennedy @Override 452345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein public void setExtendedHeader(String name, String value) throws MessagingException { 453345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein if (value == null) { 454345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein if (mExtendedHeader != null) { 455345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein mExtendedHeader.removeHeader(name); 456345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 457345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein return; 458345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 459345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein if (mExtendedHeader == null) { 460345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein mExtendedHeader = new MimeHeader(); 461345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 462345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein mExtendedHeader.setHeader(name, END_OF_LINE.matcher(value).replaceAll("")); 463345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 464345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein 465345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein /** 466345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein * Get extended header 467345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein * 468345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein * @param name Extended header name 469345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein * @return header value - null if header does not exist 470345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein * @throws MessagingException 471345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein */ 472aa27bc0e1c3bb6be4609b00007637a9d3e960f5eScott Kennedy @Override 473345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein public String getExtendedHeader(String name) throws MessagingException { 474345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein if (mExtendedHeader == null) { 475345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein return null; 476345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 477345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein return mExtendedHeader.getFirstHeader(name); 478345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 479345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein 480345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein /** 481345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein * Set entire extended headers from String 482345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein * 483345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein * @param headers Extended header and its value - "CR-NL-separated pairs 484345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein * if null or empty, remove entire extended headers 485345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein * @throws MessagingException 486345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein */ 487345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein public void setExtendedHeaders(String headers) throws MessagingException { 488345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein if (TextUtils.isEmpty(headers)) { 489345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein mExtendedHeader = null; 490345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } else { 491345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein mExtendedHeader = new MimeHeader(); 4927ddf672ebc7b43350a52573ef682e4f3f59ae2d1Tony Mantler for (final String header : END_OF_LINE.split(headers)) { 4937ddf672ebc7b43350a52573ef682e4f3f59ae2d1Tony Mantler final String[] tokens = header.split(":", 2); 494345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein if (tokens.length != 2) { 495345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein throw new MessagingException("Illegal extended headers: " + headers); 496345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 497345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein mExtendedHeader.setHeader(tokens[0].trim(), tokens[1].trim()); 498345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 499345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 500345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 501345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein 502345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein /** 503345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein * Get entire extended headers as String 504345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein * 505345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein * @return "CR-NL-separated extended headers - null if extended header does not exist 506345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein */ 507345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein public String getExtendedHeaders() { 508345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein if (mExtendedHeader != null) { 509345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein return mExtendedHeader.writeToString(); 510345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 511345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein return null; 512345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 513345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein 514345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein /** 515345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein * Write message header and body to output stream 516345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein * 517345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein * @param out Output steam to write message header and body. 518345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein */ 519aa27bc0e1c3bb6be4609b00007637a9d3e960f5eScott Kennedy @Override 520345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein public void writeTo(OutputStream out) throws IOException, MessagingException { 5217ddf672ebc7b43350a52573ef682e4f3f59ae2d1Tony Mantler final BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out), 1024); 522345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein // Force creation of local message-id 523345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein getMessageId(); 524345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein getMimeHeaders().writeTo(out); 525345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein // mExtendedHeader will not be write out to external output stream, 526345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein // because it is intended to internal use. 527345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein writer.write("\r\n"); 528345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein writer.flush(); 529345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein if (mBody != null) { 530345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein mBody.writeTo(out); 531345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 532345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 533345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein 534aa27bc0e1c3bb6be4609b00007637a9d3e960f5eScott Kennedy @Override 535345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein public InputStream getInputStream() throws MessagingException { 536345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein return null; 537345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 538345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein 539345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein class MimeMessageBuilder implements ContentHandler { 54009eca8072a2396527baede2b312d91daf1c9c2b9Martin Hibdon private final Stack<Object> stack = new Stack<Object>(); 541345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein 542345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein public MimeMessageBuilder() { 543345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 544345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein 5453b965d78774a42358ce6bbdcc43b4c8df130a60eScott Kennedy private void expect(Class<?> c) { 546345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein if (!c.isInstance(stack.peek())) { 547345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein throw new IllegalStateException("Internal stack error: " + "Expected '" 548345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein + c.getName() + "' found '" + stack.peek().getClass().getName() + "'"); 549345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 550345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 551345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein 552aa27bc0e1c3bb6be4609b00007637a9d3e960f5eScott Kennedy @Override 553345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein public void startMessage() { 554345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein if (stack.isEmpty()) { 555345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein stack.push(MimeMessage.this); 556345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } else { 557345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein expect(Part.class); 558345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein try { 5597ddf672ebc7b43350a52573ef682e4f3f59ae2d1Tony Mantler final MimeMessage m = new MimeMessage(); 560345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein ((Part)stack.peek()).setBody(m); 561345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein stack.push(m); 562345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } catch (MessagingException me) { 563345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein throw new Error(me); 564345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 565345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 566345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 567345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein 568aa27bc0e1c3bb6be4609b00007637a9d3e960f5eScott Kennedy @Override 569345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein public void endMessage() { 570345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein expect(MimeMessage.class); 571345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein stack.pop(); 572345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 573345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein 574aa27bc0e1c3bb6be4609b00007637a9d3e960f5eScott Kennedy @Override 575345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein public void startHeader() { 576345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein expect(Part.class); 577345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 578345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein 579aa27bc0e1c3bb6be4609b00007637a9d3e960f5eScott Kennedy @Override 580345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein public void field(String fieldData) { 581345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein expect(Part.class); 582345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein try { 5837ddf672ebc7b43350a52573ef682e4f3f59ae2d1Tony Mantler final String[] tokens = fieldData.split(":", 2); 584345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein ((Part)stack.peek()).addHeader(tokens[0], tokens[1].trim()); 585345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } catch (MessagingException me) { 586345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein throw new Error(me); 587345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 588345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 589345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein 590aa27bc0e1c3bb6be4609b00007637a9d3e960f5eScott Kennedy @Override 591345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein public void endHeader() { 592345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein expect(Part.class); 593345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 594345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein 595aa27bc0e1c3bb6be4609b00007637a9d3e960f5eScott Kennedy @Override 596345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein public void startMultipart(BodyDescriptor bd) { 597345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein expect(Part.class); 598345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein 5997ddf672ebc7b43350a52573ef682e4f3f59ae2d1Tony Mantler final Part e = (Part)stack.peek(); 600345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein try { 6017ddf672ebc7b43350a52573ef682e4f3f59ae2d1Tony Mantler final MimeMultipart multiPart = new MimeMultipart(e.getContentType()); 602345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein e.setBody(multiPart); 603345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein stack.push(multiPart); 604345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } catch (MessagingException me) { 605345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein throw new Error(me); 606345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 607345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 608345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein 609aa27bc0e1c3bb6be4609b00007637a9d3e960f5eScott Kennedy @Override 610345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein public void body(BodyDescriptor bd, InputStream in) throws IOException { 611345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein expect(Part.class); 6127ddf672ebc7b43350a52573ef682e4f3f59ae2d1Tony Mantler final Body body = MimeUtility.decodeBody(in, bd.getTransferEncoding()); 613345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein try { 614345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein ((Part)stack.peek()).setBody(body); 615345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } catch (MessagingException me) { 616345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein throw new Error(me); 617345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 618345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 619345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein 620aa27bc0e1c3bb6be4609b00007637a9d3e960f5eScott Kennedy @Override 621345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein public void endMultipart() { 622345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein stack.pop(); 623345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 624345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein 625aa27bc0e1c3bb6be4609b00007637a9d3e960f5eScott Kennedy @Override 626345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein public void startBodyPart() { 627345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein expect(MimeMultipart.class); 628345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein 629345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein try { 6307ddf672ebc7b43350a52573ef682e4f3f59ae2d1Tony Mantler final MimeBodyPart bodyPart = new MimeBodyPart(); 631345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein ((MimeMultipart)stack.peek()).addBodyPart(bodyPart); 632345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein stack.push(bodyPart); 633345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } catch (MessagingException me) { 634345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein throw new Error(me); 635345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 636345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 637345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein 638aa27bc0e1c3bb6be4609b00007637a9d3e960f5eScott Kennedy @Override 639345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein public void endBodyPart() { 640345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein expect(BodyPart.class); 641345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein stack.pop(); 642345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 643345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein 644aa27bc0e1c3bb6be4609b00007637a9d3e960f5eScott Kennedy @Override 645345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein public void epilogue(InputStream is) throws IOException { 646345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein expect(MimeMultipart.class); 6477ddf672ebc7b43350a52573ef682e4f3f59ae2d1Tony Mantler final StringBuilder sb = new StringBuilder(); 648345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein int b; 649345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein while ((b = is.read()) != -1) { 650345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein sb.append((char)b); 651345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 6527ddf672ebc7b43350a52573ef682e4f3f59ae2d1Tony Mantler // TODO: why is this commented out? 653345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein // ((Multipart) stack.peek()).setEpilogue(sb.toString()); 654345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 655345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein 656aa27bc0e1c3bb6be4609b00007637a9d3e960f5eScott Kennedy @Override 657345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein public void preamble(InputStream is) throws IOException { 658345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein expect(MimeMultipart.class); 6597ddf672ebc7b43350a52573ef682e4f3f59ae2d1Tony Mantler final StringBuilder sb = new StringBuilder(); 660345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein int b; 661345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein while ((b = is.read()) != -1) { 662345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein sb.append((char)b); 663345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 664345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein try { 665345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein ((MimeMultipart)stack.peek()).setPreamble(sb.toString()); 666345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } catch (MessagingException me) { 667345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein throw new Error(me); 668345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 669345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 670345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein 671aa27bc0e1c3bb6be4609b00007637a9d3e960f5eScott Kennedy @Override 672345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein public void raw(InputStream is) throws IOException { 673345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein throw new UnsupportedOperationException("Not supported"); 674345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 675345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein } 676345c43e12db42f6bdc0c15ac1c96af10164a458cAndrew Sapperstein} 677