MimeMessage.java revision b3f7dd0169a35221184b9327c8ce337b09dc6d1f
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
1796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectpackage com.android.email.mail.internet;
1896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
19d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadlerimport com.android.email.mail.Address;
20d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadlerimport com.android.email.mail.Body;
21d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadlerimport com.android.email.mail.BodyPart;
22d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadlerimport com.android.email.mail.Message;
23d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadlerimport com.android.email.mail.MessagingException;
24d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadlerimport com.android.email.mail.Part;
25d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler
26d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadlerimport org.apache.james.mime4j.BodyDescriptor;
27d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadlerimport org.apache.james.mime4j.ContentHandler;
28d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadlerimport org.apache.james.mime4j.EOLConvertingInputStream;
29d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadlerimport org.apache.james.mime4j.MimeStreamParser;
30d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadlerimport org.apache.james.mime4j.field.DateTimeField;
31d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadlerimport org.apache.james.mime4j.field.Field;
32d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler
33a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaokaimport android.text.TextUtils;
34a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka
3596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport java.io.BufferedWriter;
3696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport java.io.IOException;
3796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport java.io.InputStream;
3896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport java.io.OutputStream;
3996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport java.io.OutputStreamWriter;
4096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport java.text.SimpleDateFormat;
4196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport java.util.Date;
4296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport java.util.Locale;
4396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport java.util.Stack;
443469902379242c723b871d1dcb09b02d0998d538The Android Open Source Projectimport java.util.regex.Pattern;
4596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
4696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project/**
47dfd53b0e821a6c48f128f62566066876a063fed6Andrew Stadler * An implementation of Message that stores all of its metadata in RFC 822 and
4896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * RFC 2045 style headers.
49dfd53b0e821a6c48f128f62566066876a063fed6Andrew Stadler *
50dfd53b0e821a6c48f128f62566066876a063fed6Andrew Stadler * NOTE:  Automatic generation of a local message-id is becoming unwieldy and should be removed.
51dfd53b0e821a6c48f128f62566066876a063fed6Andrew Stadler * It would be better to simply do it explicitly on local creation of new outgoing messages.
5296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */
5396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectpublic class MimeMessage extends Message {
5444552da606048720de11f89321dc767ef291c391Andrew Stadler    private MimeHeader mHeader;
5544552da606048720de11f89321dc767ef291c391Andrew Stadler    private MimeHeader mExtendedHeader;
563469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project
573469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project    // NOTE:  The fields here are transcribed out of headers, and values stored here will supercede
583469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project    // the values found in the headers.  Use caution to prevent any out-of-phase errors.  In
593469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project    // particular, any adds/changes/deletes here must be echoed by changes in the parse() function.
6044552da606048720de11f89321dc767ef291c391Andrew Stadler    private Address[] mFrom;
6144552da606048720de11f89321dc767ef291c391Andrew Stadler    private Address[] mTo;
6244552da606048720de11f89321dc767ef291c391Andrew Stadler    private Address[] mCc;
6344552da606048720de11f89321dc767ef291c391Andrew Stadler    private Address[] mBcc;
6444552da606048720de11f89321dc767ef291c391Andrew Stadler    private Address[] mReplyTo;
6544552da606048720de11f89321dc767ef291c391Andrew Stadler    private Date mSentDate;
6644552da606048720de11f89321dc767ef291c391Andrew Stadler    private Body mBody;
6744552da606048720de11f89321dc767ef291c391Andrew Stadler    protected int mSize;
68dfd53b0e821a6c48f128f62566066876a063fed6Andrew Stadler    private boolean mInhibitLocalMessageId = false;
6944552da606048720de11f89321dc767ef291c391Andrew Stadler
7044552da606048720de11f89321dc767ef291c391Andrew Stadler    // Shared random source for generating local message-id values
71b3f7dd0169a35221184b9327c8ce337b09dc6d1fMakoto Onuki    private static final java.util.Random sRandom = new java.util.Random();
723469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project
7396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    // In MIME, en_US-like date format should be used. In other words "MMM" should be encoded to
7496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    // "Jan", not the other localized format like "Ene" (meaning January in locale es).
7596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    // This conversion is used when generating outgoing MIME messages. Incoming MIME date
7696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    // headers are parsed by org.apache.james.mime4j.field.DateTimeField which does not have any
7796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    // localization code.
7844552da606048720de11f89321dc767ef291c391Andrew Stadler    private static final SimpleDateFormat DATE_FORMAT =
7996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss Z", Locale.US);
8096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
813469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project    // regex that matches content id surrounded by "<>" optionally.
823469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project    private static final Pattern REMOVE_OPTIONAL_BRACKETS = Pattern.compile("^<?([^>]+)>?$");
83a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka    // regex that matches end of line.
84a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka    private static final Pattern END_OF_LINE = Pattern.compile("\r?\n");
853469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project
8696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    public MimeMessage() {
8744552da606048720de11f89321dc767ef291c391Andrew Stadler        mHeader = null;
8896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    }
8996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
9044552da606048720de11f89321dc767ef291c391Andrew Stadler    /**
9144552da606048720de11f89321dc767ef291c391Andrew Stadler     * Generate a local message id.  This is only used when none has been assigned, and is
9244552da606048720de11f89321dc767ef291c391Andrew Stadler     * installed lazily.  Any remote (typically server-assigned) message id takes precedence.
9344552da606048720de11f89321dc767ef291c391Andrew Stadler     * @return a long, locally-generated message-ID value
9444552da606048720de11f89321dc767ef291c391Andrew Stadler     */
9596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    private String generateMessageId() {
9696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        StringBuffer sb = new StringBuffer();
9796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        sb.append("<");
9896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        for (int i = 0; i < 24; i++) {
9944552da606048720de11f89321dc767ef291c391Andrew Stadler            // We'll use a 5-bit range (0..31)
10044552da606048720de11f89321dc767ef291c391Andrew Stadler            int value = sRandom.nextInt() & 31;
10144552da606048720de11f89321dc767ef291c391Andrew Stadler            char c = "0123456789abcdefghijklmnopqrstuv".charAt(value);
10244552da606048720de11f89321dc767ef291c391Andrew Stadler            sb.append(c);
10396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        }
10496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        sb.append(".");
10596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        sb.append(Long.toString(System.currentTimeMillis()));
10696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        sb.append("@email.android.com>");
10796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        return sb.toString();
10896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    }
10996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
11096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    /**
11196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     * Parse the given InputStream using Apache Mime4J to build a MimeMessage.
11296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     *
11396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     * @param in
11496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     * @throws IOException
11596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     * @throws MessagingException
11696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     */
11796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    public MimeMessage(InputStream in) throws IOException, MessagingException {
11896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        parse(in);
11996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    }
12096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
12196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    protected void parse(InputStream in) throws IOException, MessagingException {
1223469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project        // Before parsing the input stream, clear all local fields that may be superceded by
1233469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project        // the new incoming message.
12444552da606048720de11f89321dc767ef291c391Andrew Stadler        getMimeHeaders().clear();
125dfd53b0e821a6c48f128f62566066876a063fed6Andrew Stadler        mInhibitLocalMessageId = true;
12696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        mFrom = null;
1273469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project        mTo = null;
1283469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project        mCc = null;
1293469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project        mBcc = null;
1303469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project        mReplyTo = null;
13196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        mSentDate = null;
1323469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project        mBody = null;
13396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
13496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        MimeStreamParser parser = new MimeStreamParser();
13596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        parser.setContentHandler(new MimeMessageBuilder());
13696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        parser.parse(new EOLConvertingInputStream(in));
13796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    }
13896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
13944552da606048720de11f89321dc767ef291c391Andrew Stadler    /**
14044552da606048720de11f89321dc767ef291c391Andrew Stadler     * Return the internal mHeader value, with very lazy initialization.
14144552da606048720de11f89321dc767ef291c391Andrew Stadler     * The goal is to save memory by not creating the headers until needed.
14244552da606048720de11f89321dc767ef291c391Andrew Stadler     */
14344552da606048720de11f89321dc767ef291c391Andrew Stadler    private MimeHeader getMimeHeaders() {
14444552da606048720de11f89321dc767ef291c391Andrew Stadler        if (mHeader == null) {
14544552da606048720de11f89321dc767ef291c391Andrew Stadler            mHeader = new MimeHeader();
14644552da606048720de11f89321dc767ef291c391Andrew Stadler        }
14744552da606048720de11f89321dc767ef291c391Andrew Stadler        return mHeader;
14844552da606048720de11f89321dc767ef291c391Andrew Stadler    }
14944552da606048720de11f89321dc767ef291c391Andrew Stadler
150165e8bfe7a46564ea98bb16cb059102ba356a1b5Makoto Onuki    @Override
15196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    public Date getReceivedDate() throws MessagingException {
15296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        return null;
15396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    }
15496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
155165e8bfe7a46564ea98bb16cb059102ba356a1b5Makoto Onuki    @Override
15696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    public Date getSentDate() throws MessagingException {
15796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        if (mSentDate == null) {
15896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            try {
15996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                DateTimeField field = (DateTimeField)Field.parse("Date: "
16096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                        + MimeUtility.unfoldAndDecode(getFirstHeader("Date")));
16196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                mSentDate = field.getDate();
16296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            } catch (Exception e) {
16396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
16496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            }
16596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        }
16696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        return mSentDate;
16796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    }
16896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
169165e8bfe7a46564ea98bb16cb059102ba356a1b5Makoto Onuki    @Override
17096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    public void setSentDate(Date sentDate) throws MessagingException {
17144552da606048720de11f89321dc767ef291c391Andrew Stadler        setHeader("Date", DATE_FORMAT.format(sentDate));
17296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        this.mSentDate = sentDate;
17396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    }
17496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
175165e8bfe7a46564ea98bb16cb059102ba356a1b5Makoto Onuki    @Override
17696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    public String getContentType() throws MessagingException {
17796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        String contentType = getFirstHeader(MimeHeader.HEADER_CONTENT_TYPE);
17896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        if (contentType == null) {
17996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            return "text/plain";
18096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        } else {
18196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            return contentType;
18296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        }
18396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    }
18496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
18596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    public String getDisposition() throws MessagingException {
18696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        String contentDisposition = getFirstHeader(MimeHeader.HEADER_CONTENT_DISPOSITION);
18796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        if (contentDisposition == null) {
18896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            return null;
18996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        } else {
19096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            return contentDisposition;
19196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        }
19296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    }
19396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
1943469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project    public String getContentId() throws MessagingException {
1953469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project        String contentId = getFirstHeader(MimeHeader.HEADER_CONTENT_ID);
1963469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project        if (contentId == null) {
1973469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project            return null;
1983469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project        } else {
1993469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project            // remove optionally surrounding brackets.
2003469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project            return REMOVE_OPTIONAL_BRACKETS.matcher(contentId).replaceAll("$1");
2013469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project        }
2023469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project    }
2033469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project
20496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    public String getMimeType() throws MessagingException {
20596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        return MimeUtility.getHeaderParameter(getContentType(), null);
20696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    }
20796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
20896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    public int getSize() throws MessagingException {
20996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        return mSize;
21096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    }
21196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
21296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    /**
21396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     * Returns a list of the given recipient type from this message. If no addresses are
21496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     * found the method returns an empty array.
21596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     */
216165e8bfe7a46564ea98bb16cb059102ba356a1b5Makoto Onuki    @Override
21796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    public Address[] getRecipients(RecipientType type) throws MessagingException {
21896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        if (type == RecipientType.TO) {
21996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            if (mTo == null) {
22096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                mTo = Address.parse(MimeUtility.unfold(getFirstHeader("To")));
22196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            }
22296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            return mTo;
22396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        } else if (type == RecipientType.CC) {
22496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            if (mCc == null) {
22596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                mCc = Address.parse(MimeUtility.unfold(getFirstHeader("CC")));
22696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            }
22796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            return mCc;
22896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        } else if (type == RecipientType.BCC) {
22996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            if (mBcc == null) {
23096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                mBcc = Address.parse(MimeUtility.unfold(getFirstHeader("BCC")));
23196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            }
23296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            return mBcc;
23396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        } else {
23496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            throw new MessagingException("Unrecognized recipient type.");
23596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        }
23696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    }
23796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
238165e8bfe7a46564ea98bb16cb059102ba356a1b5Makoto Onuki    @Override
23996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    public void setRecipients(RecipientType type, Address[] addresses) throws MessagingException {
240d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        final int TO_LENGTH = 4;  // "To: "
241d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        final int CC_LENGTH = 4;  // "Cc: "
242d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        final int BCC_LENGTH = 5; // "Bcc: "
24396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        if (type == RecipientType.TO) {
24496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            if (addresses == null || addresses.length == 0) {
24596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                removeHeader("To");
24696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                this.mTo = null;
24796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            } else {
248d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler                setHeader("To", MimeUtility.fold(Address.toHeader(addresses), TO_LENGTH));
24996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                this.mTo = addresses;
25096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            }
25196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        } else if (type == RecipientType.CC) {
25296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            if (addresses == null || addresses.length == 0) {
25396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                removeHeader("CC");
25496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                this.mCc = null;
25596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            } else {
256d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler                setHeader("CC", MimeUtility.fold(Address.toHeader(addresses), CC_LENGTH));
25796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                this.mCc = addresses;
25896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            }
25996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        } else if (type == RecipientType.BCC) {
26096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            if (addresses == null || addresses.length == 0) {
26196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                removeHeader("BCC");
26296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                this.mBcc = null;
26396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            } else {
264d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler                setHeader("BCC", MimeUtility.fold(Address.toHeader(addresses), BCC_LENGTH));
26596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                this.mBcc = addresses;
26696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            }
26796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        } else {
26896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            throw new MessagingException("Unrecognized recipient type.");
26996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        }
27096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    }
27196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
27296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    /**
27396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     * Returns the unfolded, decoded value of the Subject header.
27496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     */
275165e8bfe7a46564ea98bb16cb059102ba356a1b5Makoto Onuki    @Override
27696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    public String getSubject() throws MessagingException {
27796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        return MimeUtility.unfoldAndDecode(getFirstHeader("Subject"));
27896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    }
27996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
280165e8bfe7a46564ea98bb16cb059102ba356a1b5Makoto Onuki    @Override
28196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    public void setSubject(String subject) throws MessagingException {
2827dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler        final int HEADER_NAME_LENGTH = 9;     // "Subject: "
2837dbeb7d91c7b3970426af6debe48301ba053fd79Andy Stadler        setHeader("Subject", MimeUtility.foldAndEncode2(subject, HEADER_NAME_LENGTH));
28496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    }
28596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
286165e8bfe7a46564ea98bb16cb059102ba356a1b5Makoto Onuki    @Override
28796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    public Address[] getFrom() throws MessagingException {
28896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        if (mFrom == null) {
28996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            String list = MimeUtility.unfold(getFirstHeader("From"));
29096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            if (list == null || list.length() == 0) {
29196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                list = MimeUtility.unfold(getFirstHeader("Sender"));
29296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            }
29396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            mFrom = Address.parse(list);
29496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        }
29596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        return mFrom;
29696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    }
29796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
298165e8bfe7a46564ea98bb16cb059102ba356a1b5Makoto Onuki    @Override
29996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    public void setFrom(Address from) throws MessagingException {
300d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        final int FROM_LENGTH = 6;  // "From: "
30196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        if (from != null) {
302d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler            setHeader("From", MimeUtility.fold(from.toHeader(), FROM_LENGTH));
30396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            this.mFrom = new Address[] {
30496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                    from
30596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                };
30696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        } else {
30796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            this.mFrom = null;
30896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        }
30996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    }
31096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
311165e8bfe7a46564ea98bb16cb059102ba356a1b5Makoto Onuki    @Override
31296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    public Address[] getReplyTo() throws MessagingException {
31396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        if (mReplyTo == null) {
31496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            mReplyTo = Address.parse(MimeUtility.unfold(getFirstHeader("Reply-to")));
31596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        }
31696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        return mReplyTo;
31796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    }
31896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
319165e8bfe7a46564ea98bb16cb059102ba356a1b5Makoto Onuki    @Override
32096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    public void setReplyTo(Address[] replyTo) throws MessagingException {
321d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler        final int REPLY_TO_LENGTH = 10;  // "Reply-to: "
32296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        if (replyTo == null || replyTo.length == 0) {
32396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            removeHeader("Reply-to");
32496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            mReplyTo = null;
32596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        } else {
326d8cbeaf7aee0b307b96c2aa1c2a93c4c417838e2Andy Stadler            setHeader("Reply-to", MimeUtility.fold(Address.toHeader(replyTo), REPLY_TO_LENGTH));
32796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            mReplyTo = replyTo;
32896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        }
32996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    }
3303b85e2c2b5662c58525baa41479e42c59e292f66The Android Open Source Project
3313b85e2c2b5662c58525baa41479e42c59e292f66The Android Open Source Project    /**
3323b85e2c2b5662c58525baa41479e42c59e292f66The Android Open Source Project     * Set the mime "Message-ID" header
3333b85e2c2b5662c58525baa41479e42c59e292f66The Android Open Source Project     * @param messageId the new Message-ID value
3343b85e2c2b5662c58525baa41479e42c59e292f66The Android Open Source Project     * @throws MessagingException
3353b85e2c2b5662c58525baa41479e42c59e292f66The Android Open Source Project     */
33644552da606048720de11f89321dc767ef291c391Andrew Stadler    @Override
3373b85e2c2b5662c58525baa41479e42c59e292f66The Android Open Source Project    public void setMessageId(String messageId) throws MessagingException {
3383b85e2c2b5662c58525baa41479e42c59e292f66The Android Open Source Project        setHeader("Message-ID", messageId);
3393b85e2c2b5662c58525baa41479e42c59e292f66The Android Open Source Project    }
3403b85e2c2b5662c58525baa41479e42c59e292f66The Android Open Source Project
3413b85e2c2b5662c58525baa41479e42c59e292f66The Android Open Source Project    /**
34244552da606048720de11f89321dc767ef291c391Andrew Stadler     * Get the mime "Message-ID" header.  This value will be preloaded with a locally-generated
343dfd53b0e821a6c48f128f62566066876a063fed6Andrew Stadler     * random ID, if the value has not previously been set.  Local generation can be inhibited/
344dfd53b0e821a6c48f128f62566066876a063fed6Andrew Stadler     * overridden by explicitly clearing the headers, removing the message-id header, etc.
345dfd53b0e821a6c48f128f62566066876a063fed6Andrew Stadler     * @return the Message-ID header string, or null if explicitly has been set to null
3463b85e2c2b5662c58525baa41479e42c59e292f66The Android Open Source Project     */
34744552da606048720de11f89321dc767ef291c391Andrew Stadler    @Override
3483b85e2c2b5662c58525baa41479e42c59e292f66The Android Open Source Project    public String getMessageId() throws MessagingException {
34944552da606048720de11f89321dc767ef291c391Andrew Stadler        String messageId = getFirstHeader("Message-ID");
350dfd53b0e821a6c48f128f62566066876a063fed6Andrew Stadler        if (messageId == null && !mInhibitLocalMessageId) {
35144552da606048720de11f89321dc767ef291c391Andrew Stadler            messageId = generateMessageId();
35244552da606048720de11f89321dc767ef291c391Andrew Stadler            setMessageId(messageId);
3533b85e2c2b5662c58525baa41479e42c59e292f66The Android Open Source Project        }
35444552da606048720de11f89321dc767ef291c391Andrew Stadler        return messageId;
3553b85e2c2b5662c58525baa41479e42c59e292f66The Android Open Source Project    }
35696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
357165e8bfe7a46564ea98bb16cb059102ba356a1b5Makoto Onuki    @Override
35896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    public void saveChanges() throws MessagingException {
35996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        throw new MessagingException("saveChanges not yet implemented");
36096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    }
36196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
362165e8bfe7a46564ea98bb16cb059102ba356a1b5Makoto Onuki    @Override
36396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    public Body getBody() throws MessagingException {
36496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        return mBody;
36596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    }
36696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
367165e8bfe7a46564ea98bb16cb059102ba356a1b5Makoto Onuki    @Override
36896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    public void setBody(Body body) throws MessagingException {
36996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        this.mBody = body;
37096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        if (body instanceof com.android.email.mail.Multipart) {
37196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            com.android.email.mail.Multipart multipart = ((com.android.email.mail.Multipart)body);
37296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            multipart.setParent(this);
37396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            setHeader(MimeHeader.HEADER_CONTENT_TYPE, multipart.getContentType());
37496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            setHeader("MIME-Version", "1.0");
37596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        }
37696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        else if (body instanceof TextBody) {
37796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            setHeader(MimeHeader.HEADER_CONTENT_TYPE, String.format("%s;\n charset=utf-8",
37896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                    getMimeType()));
37996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            setHeader(MimeHeader.HEADER_CONTENT_TRANSFER_ENCODING, "base64");
38096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        }
38196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    }
38296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
38396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    protected String getFirstHeader(String name) throws MessagingException {
38444552da606048720de11f89321dc767ef291c391Andrew Stadler        return getMimeHeaders().getFirstHeader(name);
38596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    }
38696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
387165e8bfe7a46564ea98bb16cb059102ba356a1b5Makoto Onuki    @Override
38896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    public void addHeader(String name, String value) throws MessagingException {
38944552da606048720de11f89321dc767ef291c391Andrew Stadler        getMimeHeaders().addHeader(name, value);
39096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    }
39196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
392165e8bfe7a46564ea98bb16cb059102ba356a1b5Makoto Onuki    @Override
39396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    public void setHeader(String name, String value) throws MessagingException {
39444552da606048720de11f89321dc767ef291c391Andrew Stadler        getMimeHeaders().setHeader(name, value);
39596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    }
39696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
397165e8bfe7a46564ea98bb16cb059102ba356a1b5Makoto Onuki    @Override
39896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    public String[] getHeader(String name) throws MessagingException {
39944552da606048720de11f89321dc767ef291c391Andrew Stadler        return getMimeHeaders().getHeader(name);
40096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    }
40196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
402165e8bfe7a46564ea98bb16cb059102ba356a1b5Makoto Onuki    @Override
40396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    public void removeHeader(String name) throws MessagingException {
40444552da606048720de11f89321dc767ef291c391Andrew Stadler        getMimeHeaders().removeHeader(name);
405dfd53b0e821a6c48f128f62566066876a063fed6Andrew Stadler        if ("Message-ID".equalsIgnoreCase(name)) {
406dfd53b0e821a6c48f128f62566066876a063fed6Andrew Stadler            mInhibitLocalMessageId = true;
407dfd53b0e821a6c48f128f62566066876a063fed6Andrew Stadler        }
40896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    }
40996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
410a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka    /**
411a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka     * Set extended header
412a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka     *
413a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka     * @param name Extended header name
414a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka     * @param value header value - flattened by removing CR-NL if any
415a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka     * remove header if value is null
416a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka     * @throws MessagingException
417a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka     */
418a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka    public void setExtendedHeader(String name, String value) throws MessagingException {
419a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        if (value == null) {
420a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka            if (mExtendedHeader != null) {
421a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka                mExtendedHeader.removeHeader(name);
422a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka            }
423a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka            return;
424a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        }
425a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        if (mExtendedHeader == null) {
426a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka            mExtendedHeader = new MimeHeader();
427a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        }
428a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        mExtendedHeader.setHeader(name, END_OF_LINE.matcher(value).replaceAll(""));
429a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka    }
430a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka
431a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka    /**
432a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka     * Get extended header
433a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka     *
434a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka     * @param name Extended header name
435a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka     * @return header value - null if header does not exist
436a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka     * @throws MessagingException
437a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka     */
438a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka    public String getExtendedHeader(String name) throws MessagingException {
439a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        if (mExtendedHeader == null) {
440a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka            return null;
441a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        }
442a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        return mExtendedHeader.getFirstHeader(name);
443a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka    }
444a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka
445a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka    /**
446a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka     * Set entire extended headers from String
447a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka     *
448a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka     * @param headers Extended header and its value - "CR-NL-separated pairs
449a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka     * if null or empty, remove entire extended headers
450a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka     * @throws MessagingException
451a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka     */
452a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka    public void setExtendedHeaders(String headers) throws MessagingException {
453a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        if (TextUtils.isEmpty(headers)) {
454a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka            mExtendedHeader = null;
455a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        } else {
456a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka            mExtendedHeader = new MimeHeader();
457a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka            for (String header : END_OF_LINE.split(headers)) {
458a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka                String[] tokens = header.split(":", 2);
459a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka                if (tokens.length != 2) {
460a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka                    throw new MessagingException("Illegal extended headers: " + headers);
461a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka                }
462a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka                mExtendedHeader.setHeader(tokens[0].trim(), tokens[1].trim());
463a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka            }
464a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        }
465a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka    }
466a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka
467a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka    /**
468a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka     * Get entire extended headers as String
469a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka     *
470a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka     * @return "CR-NL-separated extended headers - null if extended header does not exist
471a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka     */
472a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka    public String getExtendedHeaders() {
473a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        if (mExtendedHeader != null) {
474a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka            return mExtendedHeader.writeToString();
475a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        }
476a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        return null;
477a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka    }
478a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka
479a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka    /**
480a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka     * Write message header and body to output stream
481a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka     *
482a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka     * @param out Output steam to write message header and body.
483a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka     */
48496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    public void writeTo(OutputStream out) throws IOException, MessagingException {
48596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out), 1024);
48644552da606048720de11f89321dc767ef291c391Andrew Stadler        // Force creation of local message-id
48744552da606048720de11f89321dc767ef291c391Andrew Stadler        getMessageId();
48844552da606048720de11f89321dc767ef291c391Andrew Stadler        getMimeHeaders().writeTo(out);
489a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        // mExtendedHeader will not be write out to external output stream,
490a8884b9b72b164dfd347dab24f754bd8f7fcbd7cTadashi Takaoka        // because it is intended to internal use.
49196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        writer.write("\r\n");
49296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        writer.flush();
49396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        if (mBody != null) {
49496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            mBody.writeTo(out);
49596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        }
49696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    }
49796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
49896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    public InputStream getInputStream() throws MessagingException {
49996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        return null;
50096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    }
50196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
50296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    class MimeMessageBuilder implements ContentHandler {
50396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        private Stack stack = new Stack();
50496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
50596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        public MimeMessageBuilder() {
50696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        }
50796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
50896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        private void expect(Class c) {
50996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            if (!c.isInstance(stack.peek())) {
51096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                throw new IllegalStateException("Internal stack error: " + "Expected '"
51196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                        + c.getName() + "' found '" + stack.peek().getClass().getName() + "'");
51296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            }
51396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        }
51496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
51596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        public void startMessage() {
51696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            if (stack.isEmpty()) {
51796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                stack.push(MimeMessage.this);
51896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            } else {
51996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                expect(Part.class);
52096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                try {
52196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                    MimeMessage m = new MimeMessage();
52296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                    ((Part)stack.peek()).setBody(m);
52396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                    stack.push(m);
52496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                } catch (MessagingException me) {
52596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                    throw new Error(me);
52696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                }
52796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            }
52896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        }
52996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
53096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        public void endMessage() {
53196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            expect(MimeMessage.class);
53296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            stack.pop();
53396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        }
53496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
53596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        public void startHeader() {
53696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            expect(Part.class);
53796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        }
53896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
53996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        public void field(String fieldData) {
54096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            expect(Part.class);
54196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            try {
54296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                String[] tokens = fieldData.split(":", 2);
54396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                ((Part)stack.peek()).addHeader(tokens[0], tokens[1].trim());
54496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            } catch (MessagingException me) {
54596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                throw new Error(me);
54696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            }
54796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        }
54896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
54996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        public void endHeader() {
55096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            expect(Part.class);
55196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        }
55296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
55396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        public void startMultipart(BodyDescriptor bd) {
55496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            expect(Part.class);
55596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
55696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            Part e = (Part)stack.peek();
55796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            try {
55896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                MimeMultipart multiPart = new MimeMultipart(e.getContentType());
55996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                e.setBody(multiPart);
56096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                stack.push(multiPart);
56196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            } catch (MessagingException me) {
56296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                throw new Error(me);
56396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            }
56496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        }
56596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
56696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        public void body(BodyDescriptor bd, InputStream in) throws IOException {
56796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            expect(Part.class);
56896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            Body body = MimeUtility.decodeBody(in, bd.getTransferEncoding());
56996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            try {
57096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                ((Part)stack.peek()).setBody(body);
57196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            } catch (MessagingException me) {
57296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                throw new Error(me);
57396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            }
57496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        }
57596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
57696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        public void endMultipart() {
57796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            stack.pop();
57896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        }
57996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
58096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        public void startBodyPart() {
58196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            expect(MimeMultipart.class);
58296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
58396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            try {
58496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                MimeBodyPart bodyPart = new MimeBodyPart();
58596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                ((MimeMultipart)stack.peek()).addBodyPart(bodyPart);
58696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                stack.push(bodyPart);
58796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            } catch (MessagingException me) {
58896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                throw new Error(me);
58996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            }
59096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        }
59196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
59296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        public void endBodyPart() {
59396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            expect(BodyPart.class);
59496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            stack.pop();
59596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        }
59696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
59796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        public void epilogue(InputStream is) throws IOException {
59896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            expect(MimeMultipart.class);
59996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            StringBuffer sb = new StringBuffer();
60096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            int b;
60196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            while ((b = is.read()) != -1) {
60296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                sb.append((char)b);
60396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            }
60496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            // ((Multipart) stack.peek()).setEpilogue(sb.toString());
60596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        }
60696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
60796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        public void preamble(InputStream is) throws IOException {
60896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            expect(MimeMultipart.class);
60996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            StringBuffer sb = new StringBuffer();
61096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            int b;
61196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            while ((b = is.read()) != -1) {
61296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                sb.append((char)b);
61396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            }
61496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            try {
61596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                ((MimeMultipart)stack.peek()).setPreamble(sb.toString());
61696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            } catch (MessagingException me) {
61796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                throw new Error(me);
61896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            }
61996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        }
62096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
62196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        public void raw(InputStream is) throws IOException {
62296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            throw new UnsupportedOperationException("Not supported");
62396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        }
62496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    }
62596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project}
626