196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project/* 296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project 396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * 496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * you may not use this file except in compliance with the License. 696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * You may obtain a copy of the License at 796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * 896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * 1096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 1196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 1296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * See the License for the specific language governing permissions and 1496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * limitations under the License. 1596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */ 1696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 172193962ca2b3157e79f731736afa2a0c972e778aMarc Blankpackage com.android.emailcommon.internet; 1896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 192193962ca2b3157e79f731736afa2a0c972e778aMarc Blankimport com.android.emailcommon.mail.Address; 202193962ca2b3157e79f731736afa2a0c972e778aMarc Blankimport com.android.emailcommon.mail.Body; 212193962ca2b3157e79f731736afa2a0c972e778aMarc Blankimport com.android.emailcommon.mail.BodyPart; 222193962ca2b3157e79f731736afa2a0c972e778aMarc Blankimport com.android.emailcommon.mail.Message; 232193962ca2b3157e79f731736afa2a0c972e778aMarc Blankimport com.android.emailcommon.mail.MessagingException; 242193962ca2b3157e79f731736afa2a0c972e778aMarc Blankimport com.android.emailcommon.mail.Multipart; 252193962ca2b3157e79f731736afa2a0c972e778aMarc Blankimport com.android.emailcommon.mail.Part; 26d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler 27d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadlerimport org.apache.james.mime4j.BodyDescriptor; 28d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadlerimport org.apache.james.mime4j.ContentHandler; 29d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadlerimport org.apache.james.mime4j.EOLConvertingInputStream; 30d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadlerimport org.apache.james.mime4j.MimeStreamParser; 31d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadlerimport org.apache.james.mime4j.field.DateTimeField; 32d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadlerimport org.apache.james.mime4j.field.Field; 33d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler 34a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaokaimport android.text.TextUtils; 35a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka 3696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport java.io.BufferedWriter; 3796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport java.io.IOException; 3896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport java.io.InputStream; 3996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport java.io.OutputStream; 4096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport java.io.OutputStreamWriter; 4196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport java.text.SimpleDateFormat; 4296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport java.util.Date; 4396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport java.util.Locale; 4496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport java.util.Stack; 453469902379242c723b871d1dcb09b02d0998d538The Android Open Source Projectimport java.util.regex.Pattern; 4696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 4796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project/** 48dfd53b0e821a6c48f128f62566066876a063fed6Andrew Stadler * An implementation of Message that stores all of its metadata in RFC 822 and 4996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * RFC 2045 style headers. 50dfd53b0e821a6c48f128f62566066876a063fed6Andrew Stadler * 51dfd53b0e821a6c48f128f62566066876a063fed6Andrew Stadler * NOTE: Automatic generation of a local message-id is becoming unwieldy and should be removed. 52dfd53b0e821a6c48f128f62566066876a063fed6Andrew Stadler * It would be better to simply do it explicitly on local creation of new outgoing messages. 5396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */ 5496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectpublic class MimeMessage extends Message { 5544552da606048720de11f89321dc767ef291c391Andrew Stadler private MimeHeader mHeader; 5644552da606048720de11f89321dc767ef291c391Andrew Stadler private MimeHeader mExtendedHeader; 575e39f90e9d4665713eba38586b08546f1d581adbTodd Kennedy 583469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project // NOTE: The fields here are transcribed out of headers, and values stored here will supercede 593469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project // the values found in the headers. Use caution to prevent any out-of-phase errors. In 603469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project // particular, any adds/changes/deletes here must be echoed by changes in the parse() function. 6144552da606048720de11f89321dc767ef291c391Andrew Stadler private Address[] mFrom; 6244552da606048720de11f89321dc767ef291c391Andrew Stadler private Address[] mTo; 6344552da606048720de11f89321dc767ef291c391Andrew Stadler private Address[] mCc; 6444552da606048720de11f89321dc767ef291c391Andrew Stadler private Address[] mBcc; 6544552da606048720de11f89321dc767ef291c391Andrew Stadler private Address[] mReplyTo; 6644552da606048720de11f89321dc767ef291c391Andrew Stadler private Date mSentDate; 6744552da606048720de11f89321dc767ef291c391Andrew Stadler private Body mBody; 6844552da606048720de11f89321dc767ef291c391Andrew Stadler protected int mSize; 69dfd53b0e821a6c48f128f62566066876a063fed6Andrew Stadler private boolean mInhibitLocalMessageId = false; 7044552da606048720de11f89321dc767ef291c391Andrew Stadler 7144552da606048720de11f89321dc767ef291c391Andrew Stadler // Shared random source for generating local message-id values 72b3f7dd0169a35221184b9327c8ce337b09dc6d1fMakoto Onuki private static final java.util.Random sRandom = new java.util.Random(); 735e39f90e9d4665713eba38586b08546f1d581adbTodd Kennedy 7496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project // In MIME, en_US-like date format should be used. In other words "MMM" should be encoded to 7596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project // "Jan", not the other localized format like "Ene" (meaning January in locale es). 7696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project // This conversion is used when generating outgoing MIME messages. Incoming MIME date 7796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project // headers are parsed by org.apache.james.mime4j.field.DateTimeField which does not have any 7896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project // localization code. 7944552da606048720de11f89321dc767ef291c391Andrew Stadler private static final SimpleDateFormat DATE_FORMAT = 8096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss Z", Locale.US); 8196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 823469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project // regex that matches content id surrounded by "<>" optionally. 833469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project private static final Pattern REMOVE_OPTIONAL_BRACKETS = Pattern.compile("^<?([^>]+)>?$"); 84a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka // regex that matches end of line. 85a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka private static final Pattern END_OF_LINE = Pattern.compile("\r?\n"); 863469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project 8796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public MimeMessage() { 8844552da606048720de11f89321dc767ef291c391Andrew Stadler mHeader = null; 8996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 9096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 9144552da606048720de11f89321dc767ef291c391Andrew Stadler /** 9244552da606048720de11f89321dc767ef291c391Andrew Stadler * Generate a local message id. This is only used when none has been assigned, and is 9344552da606048720de11f89321dc767ef291c391Andrew Stadler * installed lazily. Any remote (typically server-assigned) message id takes precedence. 9444552da606048720de11f89321dc767ef291c391Andrew Stadler * @return a long, locally-generated message-ID value 9544552da606048720de11f89321dc767ef291c391Andrew Stadler */ 9696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project private String generateMessageId() { 9796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project StringBuffer sb = new StringBuffer(); 9896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project sb.append("<"); 9996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project for (int i = 0; i < 24; i++) { 10044552da606048720de11f89321dc767ef291c391Andrew Stadler // We'll use a 5-bit range (0..31) 10144552da606048720de11f89321dc767ef291c391Andrew Stadler int value = sRandom.nextInt() & 31; 10244552da606048720de11f89321dc767ef291c391Andrew Stadler char c = "0123456789abcdefghijklmnopqrstuv".charAt(value); 10344552da606048720de11f89321dc767ef291c391Andrew Stadler sb.append(c); 10496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 10596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project sb.append("."); 10696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project sb.append(Long.toString(System.currentTimeMillis())); 10796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project sb.append("@email.android.com>"); 10896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return sb.toString(); 10996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 11096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 11196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project /** 11296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * Parse the given InputStream using Apache Mime4J to build a MimeMessage. 11396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * 11496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * @param in 11596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * @throws IOException 11696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * @throws MessagingException 11796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */ 11896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public MimeMessage(InputStream in) throws IOException, MessagingException { 11996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project parse(in); 12096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 12196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 12296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project protected void parse(InputStream in) throws IOException, MessagingException { 1233469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project // Before parsing the input stream, clear all local fields that may be superceded by 1243469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project // the new incoming message. 12544552da606048720de11f89321dc767ef291c391Andrew Stadler getMimeHeaders().clear(); 126dfd53b0e821a6c48f128f62566066876a063fed6Andrew Stadler mInhibitLocalMessageId = true; 12796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mFrom = null; 1283469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project mTo = null; 1293469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project mCc = null; 1303469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project mBcc = null; 1313469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project mReplyTo = null; 13296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mSentDate = null; 1333469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project mBody = null; 13496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 13596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project MimeStreamParser parser = new MimeStreamParser(); 13696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project parser.setContentHandler(new MimeMessageBuilder()); 13796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project parser.parse(new EOLConvertingInputStream(in)); 13896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 13996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 14044552da606048720de11f89321dc767ef291c391Andrew Stadler /** 14144552da606048720de11f89321dc767ef291c391Andrew Stadler * Return the internal mHeader value, with very lazy initialization. 14244552da606048720de11f89321dc767ef291c391Andrew Stadler * The goal is to save memory by not creating the headers until needed. 14344552da606048720de11f89321dc767ef291c391Andrew Stadler */ 14444552da606048720de11f89321dc767ef291c391Andrew Stadler private MimeHeader getMimeHeaders() { 14544552da606048720de11f89321dc767ef291c391Andrew Stadler if (mHeader == null) { 14644552da606048720de11f89321dc767ef291c391Andrew Stadler mHeader = new MimeHeader(); 14744552da606048720de11f89321dc767ef291c391Andrew Stadler } 14844552da606048720de11f89321dc767ef291c391Andrew Stadler return mHeader; 14944552da606048720de11f89321dc767ef291c391Andrew Stadler } 15044552da606048720de11f89321dc767ef291c391Andrew Stadler 151165e8bfe7a46564ea98bb16cb059102ba356a1b5Makoto Onuki @Override 15296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public Date getReceivedDate() throws MessagingException { 15396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return null; 15496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 15596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 156165e8bfe7a46564ea98bb16cb059102ba356a1b5Makoto Onuki @Override 15796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public Date getSentDate() throws MessagingException { 15896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (mSentDate == null) { 15996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project try { 16096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project DateTimeField field = (DateTimeField)Field.parse("Date: " 16196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project + MimeUtility.unfoldAndDecode(getFirstHeader("Date"))); 16296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mSentDate = field.getDate(); 16396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } catch (Exception e) { 16496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 16596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 16696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 16796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return mSentDate; 16896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 16996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 170165e8bfe7a46564ea98bb16cb059102ba356a1b5Makoto Onuki @Override 17196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public void setSentDate(Date sentDate) throws MessagingException { 17244552da606048720de11f89321dc767ef291c391Andrew Stadler setHeader("Date", DATE_FORMAT.format(sentDate)); 17396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project this.mSentDate = sentDate; 17496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 17596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 176165e8bfe7a46564ea98bb16cb059102ba356a1b5Makoto Onuki @Override 17796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public String getContentType() throws MessagingException { 17896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project String contentType = getFirstHeader(MimeHeader.HEADER_CONTENT_TYPE); 17996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (contentType == null) { 18096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return "text/plain"; 18196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } else { 18296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return contentType; 18396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 18496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 18596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 18696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public String getDisposition() throws MessagingException { 18796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project String contentDisposition = getFirstHeader(MimeHeader.HEADER_CONTENT_DISPOSITION); 18896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (contentDisposition == null) { 18996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return null; 19096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } else { 19196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return contentDisposition; 19296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 19396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 19496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 1953469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project public String getContentId() throws MessagingException { 1963469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project String contentId = getFirstHeader(MimeHeader.HEADER_CONTENT_ID); 1973469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project if (contentId == null) { 1983469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project return null; 1993469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project } else { 2003469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project // remove optionally surrounding brackets. 2013469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project return REMOVE_OPTIONAL_BRACKETS.matcher(contentId).replaceAll("$1"); 2023469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project } 2033469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project } 2043469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project 20596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public String getMimeType() throws MessagingException { 20696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return MimeUtility.getHeaderParameter(getContentType(), null); 20796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 20896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 20996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public int getSize() throws MessagingException { 21096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return mSize; 21196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 21296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 21396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project /** 21496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * Returns a list of the given recipient type from this message. If no addresses are 21596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * found the method returns an empty array. 21696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */ 217165e8bfe7a46564ea98bb16cb059102ba356a1b5Makoto Onuki @Override 21896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public Address[] getRecipients(RecipientType type) throws MessagingException { 21996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (type == RecipientType.TO) { 22096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (mTo == null) { 22196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mTo = Address.parse(MimeUtility.unfold(getFirstHeader("To"))); 22296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 22396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return mTo; 22496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } else if (type == RecipientType.CC) { 22596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (mCc == null) { 22696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mCc = Address.parse(MimeUtility.unfold(getFirstHeader("CC"))); 22796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 22896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return mCc; 22996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } else if (type == RecipientType.BCC) { 23096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (mBcc == null) { 23196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mBcc = Address.parse(MimeUtility.unfold(getFirstHeader("BCC"))); 23296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 23396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return mBcc; 23496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } else { 23596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project throw new MessagingException("Unrecognized recipient type."); 23696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 23796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 23896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 239165e8bfe7a46564ea98bb16cb059102ba356a1b5Makoto Onuki @Override 24096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public void setRecipients(RecipientType type, Address[] addresses) throws MessagingException { 241d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler final int TO_LENGTH = 4; // "To: " 242d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler final int CC_LENGTH = 4; // "Cc: " 243d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler final int BCC_LENGTH = 5; // "Bcc: " 24496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (type == RecipientType.TO) { 24596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (addresses == null || addresses.length == 0) { 24696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project removeHeader("To"); 24796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project this.mTo = null; 24896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } else { 249d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler setHeader("To", MimeUtility.fold(Address.toHeader(addresses), TO_LENGTH)); 25096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project this.mTo = addresses; 25196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 25296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } else if (type == RecipientType.CC) { 25396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (addresses == null || addresses.length == 0) { 25496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project removeHeader("CC"); 25596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project this.mCc = null; 25696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } else { 257d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler setHeader("CC", MimeUtility.fold(Address.toHeader(addresses), CC_LENGTH)); 25896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project this.mCc = addresses; 25996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 26096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } else if (type == RecipientType.BCC) { 26196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (addresses == null || addresses.length == 0) { 26296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project removeHeader("BCC"); 26396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project this.mBcc = null; 26496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } else { 265d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler setHeader("BCC", MimeUtility.fold(Address.toHeader(addresses), BCC_LENGTH)); 26696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project this.mBcc = addresses; 26796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 26896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } else { 26996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project throw new MessagingException("Unrecognized recipient type."); 27096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 27196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 27296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 27396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project /** 27496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * Returns the unfolded, decoded value of the Subject header. 27596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */ 276165e8bfe7a46564ea98bb16cb059102ba356a1b5Makoto Onuki @Override 27796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public String getSubject() throws MessagingException { 27896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return MimeUtility.unfoldAndDecode(getFirstHeader("Subject")); 27996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 28096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 281165e8bfe7a46564ea98bb16cb059102ba356a1b5Makoto Onuki @Override 28296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public void setSubject(String subject) throws MessagingException { 2837dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler final int HEADER_NAME_LENGTH = 9; // "Subject: " 2847dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler setHeader("Subject", MimeUtility.foldAndEncode2(subject, HEADER_NAME_LENGTH)); 28596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 28696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 287165e8bfe7a46564ea98bb16cb059102ba356a1b5Makoto Onuki @Override 28896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public Address[] getFrom() throws MessagingException { 28996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (mFrom == null) { 29096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project String list = MimeUtility.unfold(getFirstHeader("From")); 29196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (list == null || list.length() == 0) { 29296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project list = MimeUtility.unfold(getFirstHeader("Sender")); 29396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 29496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mFrom = Address.parse(list); 29596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 29696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return mFrom; 29796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 29896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 299165e8bfe7a46564ea98bb16cb059102ba356a1b5Makoto Onuki @Override 30096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public void setFrom(Address from) throws MessagingException { 301d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler final int FROM_LENGTH = 6; // "From: " 30296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (from != null) { 303d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler setHeader("From", MimeUtility.fold(from.toHeader(), FROM_LENGTH)); 30496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project this.mFrom = new Address[] { 30596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project from 30696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project }; 30796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } else { 30896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project this.mFrom = null; 30996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 31096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 31196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 312165e8bfe7a46564ea98bb16cb059102ba356a1b5Makoto Onuki @Override 31396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public Address[] getReplyTo() throws MessagingException { 31496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (mReplyTo == null) { 31596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mReplyTo = Address.parse(MimeUtility.unfold(getFirstHeader("Reply-to"))); 31696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 31796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return mReplyTo; 31896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 31996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 320165e8bfe7a46564ea98bb16cb059102ba356a1b5Makoto Onuki @Override 32196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public void setReplyTo(Address[] replyTo) throws MessagingException { 322d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler final int REPLY_TO_LENGTH = 10; // "Reply-to: " 32396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (replyTo == null || replyTo.length == 0) { 32496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project removeHeader("Reply-to"); 32596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mReplyTo = null; 32696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } else { 327d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler setHeader("Reply-to", MimeUtility.fold(Address.toHeader(replyTo), REPLY_TO_LENGTH)); 32896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mReplyTo = replyTo; 32996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 33096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 3315e39f90e9d4665713eba38586b08546f1d581adbTodd Kennedy 3323b85e2c2b5662c58525baa41479e42c59e292f66The Android Open Source Project /** 3333b85e2c2b5662c58525baa41479e42c59e292f66The Android Open Source Project * Set the mime "Message-ID" header 3343b85e2c2b5662c58525baa41479e42c59e292f66The Android Open Source Project * @param messageId the new Message-ID value 3353b85e2c2b5662c58525baa41479e42c59e292f66The Android Open Source Project * @throws MessagingException 3363b85e2c2b5662c58525baa41479e42c59e292f66The Android Open Source Project */ 33744552da606048720de11f89321dc767ef291c391Andrew Stadler @Override 3383b85e2c2b5662c58525baa41479e42c59e292f66The Android Open Source Project public void setMessageId(String messageId) throws MessagingException { 3393b85e2c2b5662c58525baa41479e42c59e292f66The Android Open Source Project setHeader("Message-ID", messageId); 3403b85e2c2b5662c58525baa41479e42c59e292f66The Android Open Source Project } 3415e39f90e9d4665713eba38586b08546f1d581adbTodd Kennedy 3423b85e2c2b5662c58525baa41479e42c59e292f66The Android Open Source Project /** 34344552da606048720de11f89321dc767ef291c391Andrew Stadler * Get the mime "Message-ID" header. This value will be preloaded with a locally-generated 344dfd53b0e821a6c48f128f62566066876a063fed6Andrew Stadler * random ID, if the value has not previously been set. Local generation can be inhibited/ 345dfd53b0e821a6c48f128f62566066876a063fed6Andrew Stadler * overridden by explicitly clearing the headers, removing the message-id header, etc. 346dfd53b0e821a6c48f128f62566066876a063fed6Andrew Stadler * @return the Message-ID header string, or null if explicitly has been set to null 3473b85e2c2b5662c58525baa41479e42c59e292f66The Android Open Source Project */ 34844552da606048720de11f89321dc767ef291c391Andrew Stadler @Override 3493b85e2c2b5662c58525baa41479e42c59e292f66The Android Open Source Project public String getMessageId() throws MessagingException { 35044552da606048720de11f89321dc767ef291c391Andrew Stadler String messageId = getFirstHeader("Message-ID"); 351dfd53b0e821a6c48f128f62566066876a063fed6Andrew Stadler if (messageId == null && !mInhibitLocalMessageId) { 35244552da606048720de11f89321dc767ef291c391Andrew Stadler messageId = generateMessageId(); 35344552da606048720de11f89321dc767ef291c391Andrew Stadler setMessageId(messageId); 3543b85e2c2b5662c58525baa41479e42c59e292f66The Android Open Source Project } 35544552da606048720de11f89321dc767ef291c391Andrew Stadler return messageId; 3563b85e2c2b5662c58525baa41479e42c59e292f66The Android Open Source Project } 35796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 358165e8bfe7a46564ea98bb16cb059102ba356a1b5Makoto Onuki @Override 35996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public void saveChanges() throws MessagingException { 36096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project throw new MessagingException("saveChanges not yet implemented"); 36196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 36296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 363165e8bfe7a46564ea98bb16cb059102ba356a1b5Makoto Onuki @Override 36496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public Body getBody() throws MessagingException { 36596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return mBody; 36696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 36796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 368165e8bfe7a46564ea98bb16cb059102ba356a1b5Makoto Onuki @Override 36996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public void setBody(Body body) throws MessagingException { 37096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project this.mBody = body; 3712193962ca2b3157e79f731736afa2a0c972e778aMarc Blank if (body instanceof Multipart) { 3722193962ca2b3157e79f731736afa2a0c972e778aMarc Blank Multipart multipart = ((Multipart)body); 37396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project multipart.setParent(this); 37496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project setHeader(MimeHeader.HEADER_CONTENT_TYPE, multipart.getContentType()); 37596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project setHeader("MIME-Version", "1.0"); 37696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 37796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project else if (body instanceof TextBody) { 37896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project setHeader(MimeHeader.HEADER_CONTENT_TYPE, String.format("%s;\n charset=utf-8", 37996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project getMimeType())); 38096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project setHeader(MimeHeader.HEADER_CONTENT_TRANSFER_ENCODING, "base64"); 38196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 38296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 38396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 38496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project protected String getFirstHeader(String name) throws MessagingException { 38544552da606048720de11f89321dc767ef291c391Andrew Stadler return getMimeHeaders().getFirstHeader(name); 38696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 38796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 388165e8bfe7a46564ea98bb16cb059102ba356a1b5Makoto Onuki @Override 38996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public void addHeader(String name, String value) throws MessagingException { 39044552da606048720de11f89321dc767ef291c391Andrew Stadler getMimeHeaders().addHeader(name, value); 39196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 39296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 393165e8bfe7a46564ea98bb16cb059102ba356a1b5Makoto Onuki @Override 39496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public void setHeader(String name, String value) throws MessagingException { 39544552da606048720de11f89321dc767ef291c391Andrew Stadler getMimeHeaders().setHeader(name, value); 39696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 39796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 398165e8bfe7a46564ea98bb16cb059102ba356a1b5Makoto Onuki @Override 39996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public String[] getHeader(String name) throws MessagingException { 40044552da606048720de11f89321dc767ef291c391Andrew Stadler return getMimeHeaders().getHeader(name); 40196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 40296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 403165e8bfe7a46564ea98bb16cb059102ba356a1b5Makoto Onuki @Override 40496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public void removeHeader(String name) throws MessagingException { 40544552da606048720de11f89321dc767ef291c391Andrew Stadler getMimeHeaders().removeHeader(name); 406dfd53b0e821a6c48f128f62566066876a063fed6Andrew Stadler if ("Message-ID".equalsIgnoreCase(name)) { 407dfd53b0e821a6c48f128f62566066876a063fed6Andrew Stadler mInhibitLocalMessageId = true; 408dfd53b0e821a6c48f128f62566066876a063fed6Andrew Stadler } 40996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 41096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 411a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka /** 412a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka * Set extended header 4135e39f90e9d4665713eba38586b08546f1d581adbTodd Kennedy * 414a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka * @param name Extended header name 415a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka * @param value header value - flattened by removing CR-NL if any 416a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka * remove header if value is null 417a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka * @throws MessagingException 418a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka */ 419a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka public void setExtendedHeader(String name, String value) throws MessagingException { 420a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka if (value == null) { 421a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka if (mExtendedHeader != null) { 422a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka mExtendedHeader.removeHeader(name); 423a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka } 424a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka return; 425a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka } 426a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka if (mExtendedHeader == null) { 427391ae25c43a38829cc0990af18c36bdc7cc374cfMarc Blank mExtendedHeader = new MimeHeader(); 428a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka } 429a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka mExtendedHeader.setHeader(name, END_OF_LINE.matcher(value).replaceAll("")); 430a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka } 431a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka 432a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka /** 433a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka * Get extended header 4345e39f90e9d4665713eba38586b08546f1d581adbTodd Kennedy * 435a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka * @param name Extended header name 436a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka * @return header value - null if header does not exist 437391ae25c43a38829cc0990af18c36bdc7cc374cfMarc Blank * @throws MessagingException 438a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka */ 439a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka public String getExtendedHeader(String name) throws MessagingException { 440a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka if (mExtendedHeader == null) { 441a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka return null; 442a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka } 443a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka return mExtendedHeader.getFirstHeader(name); 444a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka } 445a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka 446a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka /** 447a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka * Set entire extended headers from String 4485e39f90e9d4665713eba38586b08546f1d581adbTodd Kennedy * 449a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka * @param headers Extended header and its value - "CR-NL-separated pairs 450a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka * if null or empty, remove entire extended headers 451a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka * @throws MessagingException 452a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka */ 453a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka public void setExtendedHeaders(String headers) throws MessagingException { 454a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka if (TextUtils.isEmpty(headers)) { 455a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka mExtendedHeader = null; 456a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka } else { 457a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka mExtendedHeader = new MimeHeader(); 458a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka for (String header : END_OF_LINE.split(headers)) { 459a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka String[] tokens = header.split(":", 2); 460a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka if (tokens.length != 2) { 461a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka throw new MessagingException("Illegal extended headers: " + headers); 462a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka } 463a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka mExtendedHeader.setHeader(tokens[0].trim(), tokens[1].trim()); 464a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka } 465a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka } 466a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka } 467a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka 468a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka /** 469a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka * Get entire extended headers as String 4705e39f90e9d4665713eba38586b08546f1d581adbTodd Kennedy * 471a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka * @return "CR-NL-separated extended headers - null if extended header does not exist 472a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka */ 473a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka public String getExtendedHeaders() { 474a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka if (mExtendedHeader != null) { 475a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka return mExtendedHeader.writeToString(); 476a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka } 477a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka return null; 478a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka } 479a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka 480a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka /** 481a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka * Write message header and body to output stream 4825e39f90e9d4665713eba38586b08546f1d581adbTodd Kennedy * 483a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka * @param out Output steam to write message header and body. 484a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka */ 48596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public void writeTo(OutputStream out) throws IOException, MessagingException { 48696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out), 1024); 48744552da606048720de11f89321dc767ef291c391Andrew Stadler // Force creation of local message-id 48844552da606048720de11f89321dc767ef291c391Andrew Stadler getMessageId(); 48944552da606048720de11f89321dc767ef291c391Andrew Stadler getMimeHeaders().writeTo(out); 490a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka // mExtendedHeader will not be write out to external output stream, 491a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka // because it is intended to internal use. 49296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project writer.write("\r\n"); 49396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project writer.flush(); 49496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (mBody != null) { 49596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project mBody.writeTo(out); 49696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 49796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 49896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 49996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public InputStream getInputStream() throws MessagingException { 50096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return null; 50196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 50296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 50396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project class MimeMessageBuilder implements ContentHandler { 5045e39f90e9d4665713eba38586b08546f1d581adbTodd Kennedy private Stack<Object> stack = new Stack<Object>(); 50596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 50696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public MimeMessageBuilder() { 50796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 50896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 50996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project private void expect(Class c) { 51096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (!c.isInstance(stack.peek())) { 51196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project throw new IllegalStateException("Internal stack error: " + "Expected '" 51296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project + c.getName() + "' found '" + stack.peek().getClass().getName() + "'"); 51396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 51496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 51596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 51696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public void startMessage() { 51796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (stack.isEmpty()) { 51896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project stack.push(MimeMessage.this); 51996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } else { 52096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project expect(Part.class); 52196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project try { 52296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project MimeMessage m = new MimeMessage(); 52396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project ((Part)stack.peek()).setBody(m); 52496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project stack.push(m); 52596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } catch (MessagingException me) { 52696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project throw new Error(me); 52796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 52896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 52996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 53096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 53196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public void endMessage() { 53296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project expect(MimeMessage.class); 53396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project stack.pop(); 53496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 53596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 53696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public void startHeader() { 53796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project expect(Part.class); 53896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 53996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 54096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public void field(String fieldData) { 54196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project expect(Part.class); 54296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project try { 54396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project String[] tokens = fieldData.split(":", 2); 54496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project ((Part)stack.peek()).addHeader(tokens[0], tokens[1].trim()); 54596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } catch (MessagingException me) { 54696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project throw new Error(me); 54796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 54896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 54996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 55096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public void endHeader() { 55196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project expect(Part.class); 55296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 55396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 55496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public void startMultipart(BodyDescriptor bd) { 55596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project expect(Part.class); 55696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 55796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project Part e = (Part)stack.peek(); 55896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project try { 55996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project MimeMultipart multiPart = new MimeMultipart(e.getContentType()); 56096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project e.setBody(multiPart); 56196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project stack.push(multiPart); 56296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } catch (MessagingException me) { 56396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project throw new Error(me); 56496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 56596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 56696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 56796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public void body(BodyDescriptor bd, InputStream in) throws IOException { 56896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project expect(Part.class); 56996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project Body body = MimeUtility.decodeBody(in, bd.getTransferEncoding()); 57096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project try { 57196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project ((Part)stack.peek()).setBody(body); 57296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } catch (MessagingException me) { 57396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project throw new Error(me); 57496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 57596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 57696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 57796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public void endMultipart() { 57896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project stack.pop(); 57996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 58096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 58196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public void startBodyPart() { 58296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project expect(MimeMultipart.class); 58396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 58496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project try { 58596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project MimeBodyPart bodyPart = new MimeBodyPart(); 58696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project ((MimeMultipart)stack.peek()).addBodyPart(bodyPart); 58796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project stack.push(bodyPart); 58896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } catch (MessagingException me) { 58996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project throw new Error(me); 59096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 59196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 59296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 59396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public void endBodyPart() { 59496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project expect(BodyPart.class); 59596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project stack.pop(); 59696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 59796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 59896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public void epilogue(InputStream is) throws IOException { 59996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project expect(MimeMultipart.class); 60096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project StringBuffer sb = new StringBuffer(); 60196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project int b; 60296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project while ((b = is.read()) != -1) { 60396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project sb.append((char)b); 60496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 60596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project // ((Multipart) stack.peek()).setEpilogue(sb.toString()); 60696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 60796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 60896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public void preamble(InputStream is) throws IOException { 60996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project expect(MimeMultipart.class); 61096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project StringBuffer sb = new StringBuffer(); 61196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project int b; 61296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project while ((b = is.read()) != -1) { 61396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project sb.append((char)b); 61496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 61596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project try { 61696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project ((MimeMultipart)stack.peek()).setPreamble(sb.toString()); 61796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } catch (MessagingException me) { 61896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project throw new Error(me); 61996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 62096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 62196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 62296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public void raw(InputStream is) throws IOException { 62396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project throw new UnsupportedOperationException("Not supported"); 62496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 62596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 62696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project} 627