EasOutboxSync.java revision c35d2fa94faa0f9abeded869a01108bac2bcedcc
1c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hupackage com.android.exchange.service;
2c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu
3c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Huimport android.content.ContentUris;
4c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Huimport android.content.Context;
5c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Huimport android.database.Cursor;
6c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Huimport android.net.TrafficStats;
7c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Huimport android.net.Uri;
8c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Huimport android.text.format.DateUtils;
9c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu
10c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Huimport com.android.emailcommon.TrafficFlags;
11c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Huimport com.android.emailcommon.internet.Rfc822Output;
12c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Huimport com.android.emailcommon.provider.Account;
13c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Huimport com.android.emailcommon.provider.EmailContent.Attachment;
14c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Huimport com.android.emailcommon.provider.EmailContent.Body;
15c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Huimport com.android.emailcommon.provider.EmailContent.BodyColumns;
16c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Huimport com.android.emailcommon.provider.EmailContent.MailboxColumns;
17c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Huimport com.android.emailcommon.provider.EmailContent.Message;
18c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Huimport com.android.emailcommon.provider.EmailContent.MessageColumns;
19c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Huimport com.android.emailcommon.provider.EmailContent.SyncColumns;
20c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Huimport com.android.emailcommon.provider.Mailbox;
21c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Huimport com.android.emailcommon.utility.Utility;
22c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Huimport com.android.exchange.CommandStatusException.CommandStatus;
23c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Huimport com.android.exchange.Eas;
24c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Huimport com.android.exchange.EasResponse;
25c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Huimport com.android.exchange.adapter.Parser;
26c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Huimport com.android.exchange.adapter.Parser.EmptyStreamException;
27c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Huimport com.android.exchange.adapter.Serializer;
28c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Huimport com.android.exchange.adapter.Tags;
29c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu
30c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Huimport org.apache.http.HttpEntity;
31c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Huimport org.apache.http.HttpStatus;
32c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Huimport org.apache.http.entity.InputStreamEntity;
33c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu
34c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Huimport java.io.ByteArrayOutputStream;
35c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Huimport java.io.File;
36c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Huimport java.io.FileInputStream;
37c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Huimport java.io.FileNotFoundException;
38c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Huimport java.io.FileOutputStream;
39c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Huimport java.io.IOException;
40c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Huimport java.io.InputStream;
41c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Huimport java.io.OutputStream;
42c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Huimport java.util.ArrayList;
43c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu
44c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu/**
45c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu * Performs an Exchange Outbox sync, i.e. sends all mail from the Outbox.
46c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu */
47d738c447d8597062f2f20ecb94b96e8bee12a531Yu Ping Hupublic class EasOutboxSyncHandler extends EasServerConnection {
48c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu    // Value for a message's server id when sending fails.
49c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu    public static final int SEND_FAILED = 1;
50c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu
51c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu    // WHERE clause to query for unsent messages.
52c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu    // TODO: Is the SEND_FAILED check actually what we want?
53c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu    public static final String MAILBOX_KEY_AND_NOT_SEND_FAILED =
54c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            MessageColumns.MAILBOX_KEY + "=? and (" + SyncColumns.SERVER_ID + " is null or " +
55c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            SyncColumns.SERVER_ID + "!=" + SEND_FAILED + ')';
56c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu
57c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu    // This needs to be long enough to send the longest reasonable message, without being so long
58c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu    // as to effectively "hang" sending of mail.  The standard 30 second timeout isn't long enough
59c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu    // for pictures and the like.  For now, we'll use 15 minutes, in the knowledge that any socket
60c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu    // failure would probably generate an Exception before timing out anyway
61c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu    public static final long SEND_MAIL_TIMEOUT = 15 * DateUtils.MINUTE_IN_MILLIS;
62c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu
63d738c447d8597062f2f20ecb94b96e8bee12a531Yu Ping Hu    private final Mailbox mMailbox;
64c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu    private final File mCacheDir;
65c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu
66d738c447d8597062f2f20ecb94b96e8bee12a531Yu Ping Hu    public EasOutboxSyncHandler(final Context context, final Account account,
67d738c447d8597062f2f20ecb94b96e8bee12a531Yu Ping Hu            final Mailbox mailbox) {
68c35d2fa94faa0f9abeded869a01108bac2bcedccYu Ping Hu        super(context, account);
69d738c447d8597062f2f20ecb94b96e8bee12a531Yu Ping Hu        mMailbox = mailbox;
70c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu        mCacheDir = context.getCacheDir();
71c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu    }
72c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu
73d738c447d8597062f2f20ecb94b96e8bee12a531Yu Ping Hu    public void performSync() {
74c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu        // Use SMTP flags for sending mail
75c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu        TrafficStats.setThreadStatsTag(TrafficFlags.getSmtpFlags(mContext, mAccount));
76c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu        // Get a cursor to Outbox messages
77c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu        final Cursor c = mContext.getContentResolver().query(Message.CONTENT_URI,
78c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                Message.CONTENT_PROJECTION, MAILBOX_KEY_AND_NOT_SEND_FAILED,
79c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                new String[] {Long.toString(mMailbox.mId)}, null);
80c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu        try {
81c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            // Loop through the messages, sending each one
82c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            while (c.moveToNext()) {
83c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                final Message message = new Message();
84c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                message.restore(c);
85c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                if (Utility.hasUnloadedAttachments(mContext, message.mId)) {
86c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                    // We'll just have to wait on this...
87c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                    continue;
88c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                }
89c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu
90d738c447d8597062f2f20ecb94b96e8bee12a531Yu Ping Hu                // TODO: Fix -- how do we want to signal to UI that we started syncing?
91d738c447d8597062f2f20ecb94b96e8bee12a531Yu Ping Hu                // Note the entire callback mechanism here needs improving.
92d738c447d8597062f2f20ecb94b96e8bee12a531Yu Ping Hu                //sendMessageStatus(message.mId, null, EmailServiceStatus.IN_PROGRESS, 0);
93d738c447d8597062f2f20ecb94b96e8bee12a531Yu Ping Hu
94d738c447d8597062f2f20ecb94b96e8bee12a531Yu Ping Hu                if (!sendOneMessage(message,
95d738c447d8597062f2f20ecb94b96e8bee12a531Yu Ping Hu                        SmartSendInfo.getSmartSendInfo(mContext, mAccount, message))) {
96d738c447d8597062f2f20ecb94b96e8bee12a531Yu Ping Hu                    break;
97c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                }
98c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            }
99c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu        } finally {
100c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            // TODO: Some sort of sendMessageStatus() is needed here.
101c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            c.close();
102c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu        }
103c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu    }
104c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu
105c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu    /**
106c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu     * Information needed for SmartReply/SmartForward.
107c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu     */
108c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu    private static class SmartSendInfo {
109c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu        public static final String[] BODY_SOURCE_PROJECTION =
110c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                new String[] {BodyColumns.SOURCE_MESSAGE_KEY};
111c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu        public static final String WHERE_MESSAGE_KEY = Body.MESSAGE_KEY + "=?";
112c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu
113c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu        final String mItemId;
114c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu        final String mCollectionId;
115c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu        final boolean mIsReply;
116c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu        final ArrayList<Attachment> mRequiredAtts;
117c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu
118c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu        private SmartSendInfo(final String itemId, final String collectionId, final boolean isReply,
119c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                final ArrayList<Attachment> requiredAtts) {
120c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            mItemId = itemId;
121c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            mCollectionId = collectionId;
122c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            mIsReply = isReply;
123c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            mRequiredAtts = requiredAtts;
124c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu        }
125c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu
126c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu        public String generateSmartSendCmd() {
127c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            final StringBuilder sb = new StringBuilder();
128c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            sb.append(isForward() ? "SmartForward" : "SmartReply");
129c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            sb.append("&ItemId=");
130c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            sb.append(Uri.encode(mItemId, ":"));
131c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            sb.append("&CollectionId=");
132c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            sb.append(Uri.encode(mCollectionId, ":"));
133c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            return sb.toString();
134c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu        }
135c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu
136c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu        public boolean isForward() {
137c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            return !mIsReply;
138c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu        }
139c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu
140c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu        /**
141c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu         * See if a given attachment is among an array of attachments; it is if the locations of
142c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu         * both are the same (we're looking to see if they represent the same attachment on the
143c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu         * server. Note that an attachment that isn't on the server (e.g. an outbound attachment
144c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu         * picked from the  gallery) won't have a location, so the result will always be false.
145c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu         *
146c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu         * @param att the attachment to test
147c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu         * @param atts the array of attachments to look in
148c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu         * @return whether the test attachment is among the array of attachments
149c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu         */
150c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu        private static boolean amongAttachments(final Attachment att, final Attachment[] atts) {
151c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            final String location = att.mLocation;
152c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            if (location == null) return false;
153c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            for (final Attachment a: atts) {
154c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                if (location.equals(a.mLocation)) {
155c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                    return true;
156c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                }
157c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            }
158c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            return false;
159c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu        }
160c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu
161c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu        /**
162c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu         * If this message should use SmartReply or SmartForward, return an object with the data
163c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu         * for the smart send.
164c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu         *
165c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu         * @param context the caller's context
166c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu         * @param account the Account we're sending from
167c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu         * @param message the Message being sent
168c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu         * @return an object to support smart sending, or null if not applicable.
169c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu         */
170c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu        public static SmartSendInfo getSmartSendInfo(final Context context,
171c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                final Account account, final Message message) {
172c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            final int flags = message.mFlags;
173c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            // We only care about the original message if we include quoted text.
174c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            if ((flags & Message.FLAG_NOT_INCLUDE_QUOTED_TEXT) != 0) {
175c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                return null;
176c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            }
177c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            final boolean reply = (flags & Message.FLAG_TYPE_REPLY) != 0;
178c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            final boolean forward = (flags & Message.FLAG_TYPE_FORWARD) != 0;
179c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            // We also only care for replies or forwards.
180c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            if (!reply && !forward) {
181c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                return null;
182c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            }
183c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            // Just a sanity check here, since we assume that reply and forward are mutually
184c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            // exclusive throughout this class.
185c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            if (reply && forward) {
186c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                return null;
187c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            }
188c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            // If we don't support SmartForward and it's a forward, then don't proceed.
189c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            if (forward && (account.mFlags & Account.FLAGS_SUPPORTS_SMART_FORWARD) == 0) {
190c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                return null;
191c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            }
192c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu
193c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            // Note: itemId and collectionId are the terms used by EAS to refer to the serverId and
194c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            // mailboxId of a Message
195c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            String itemId = null;
196c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            String collectionId = null;
197c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu
198c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            // First, we need to get the id of the reply/forward message
199c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            String[] cols = Utility.getRowColumns(context, Body.CONTENT_URI, BODY_SOURCE_PROJECTION,
200c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                    WHERE_MESSAGE_KEY, new String[] {Long.toString(message.mId)});
201c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            long refId = 0;
202c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            if (cols != null) {
203c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                refId = Long.parseLong(cols[0]);
204c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                // Then, we need the serverId and mailboxKey of the message
205c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                cols = Utility.getRowColumns(context, Message.CONTENT_URI, refId,
206c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                        SyncColumns.SERVER_ID, MessageColumns.MAILBOX_KEY,
207c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                        MessageColumns.PROTOCOL_SEARCH_INFO);
208c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                if (cols != null) {
209c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                    itemId = cols[0];
210c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                    final long boxId = Long.parseLong(cols[1]);
211c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                    // Then, we need the serverId of the mailbox
212c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                    cols = Utility.getRowColumns(context, Mailbox.CONTENT_URI, boxId,
213c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                            MailboxColumns.SERVER_ID);
214c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                    if (cols != null) {
215c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                        collectionId = cols[0];
216c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                    }
217c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                }
218c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            }
219c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            // We need either a longId or both itemId (serverId) and collectionId (mailboxId) to
220c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            // process a smart reply or a smart forward
221c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            if (itemId != null && collectionId != null) {
222c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                final ArrayList<Attachment> requiredAtts;
223c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                if (forward) {
224c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                    // See if we can really smart forward (all reference attachments must be sent)
225c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                    final Attachment[] outAtts =
226c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                            Attachment.restoreAttachmentsWithMessageId(context, message.mId);
227c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                    final Attachment[] refAtts =
228c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                            Attachment.restoreAttachmentsWithMessageId(context, refId);
229c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                    for (final Attachment refAtt: refAtts) {
230c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                        // If an original attachment isn't among what's going out, we can't be smart
231c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                        if (!amongAttachments(refAtt, outAtts)) {
232c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                            return null;
233c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                        }
234c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                    }
235c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                    requiredAtts = new ArrayList<Attachment>();
236c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                    for (final Attachment outAtt: outAtts) {
237c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                        // If an outgoing attachment isn't in original message, we must send it
238c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                        if (!amongAttachments(outAtt, refAtts)) {
239c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                            requiredAtts.add(outAtt);
240c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                        }
241c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                    }
242c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                } else {
243c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                    requiredAtts = null;
244c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                }
245c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                return new SmartSendInfo(itemId, collectionId, reply, requiredAtts);
246c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            }
247c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            return null;
248c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu        }
249c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu    }
250c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu
251c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu    /**
252c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu     * Our own HttpEntity subclass that is able to insert opaque data (in this case the MIME
253c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu     * representation of the message body as stored in a temporary file) into the serializer stream
254c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu     */
255c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu    private static class SendMailEntity extends InputStreamEntity {
256c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu        private final FileInputStream mFileStream;
257c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu        private final long mFileLength;
258c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu        private final int mSendTag;
259c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu        private final Message mMessage;
260c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu        private final SmartSendInfo mSmartSendInfo;
261c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu
262c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu        public SendMailEntity(final FileInputStream instream, final long length, final int tag,
263c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                final Message message, final SmartSendInfo smartSendInfo) {
264c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            super(instream, length);
265c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            mFileStream = instream;
266c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            mFileLength = length;
267c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            mSendTag = tag;
268c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            mMessage = message;
269c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            mSmartSendInfo = smartSendInfo;
270c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu        }
271c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu
272c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu        /**
273c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu         * We always return -1 because we don't know the actual length of the POST data (this
274c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu         * causes HttpClient to send the data in "chunked" mode)
275c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu         */
276c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu        @Override
277c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu        public long getContentLength() {
278c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            final ByteArrayOutputStream baos = new ByteArrayOutputStream();
279c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            try {
280c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                // Calculate the overhead for the WBXML data
281c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                writeTo(baos, false);
282c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                // Return the actual size that will be sent
283c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                return baos.size() + mFileLength;
284c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            } catch (final IOException e) {
285c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                // Just return -1 (unknown)
286c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            } finally {
287c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                try {
288c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                    baos.close();
289c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                } catch (final IOException e) {
290c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                    // Ignore
291c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                }
292c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            }
293c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            return -1;
294c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu        }
295c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu
296c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu        @Override
297c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu        public void writeTo(final OutputStream outstream) throws IOException {
298c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            writeTo(outstream, true);
299c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu        }
300c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu
301c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu        /**
302c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu         * Write the message to the output stream
303c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu         * @param outstream the output stream to write
304c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu         * @param withData whether or not the actual data is to be written; true when sending
305c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu         *   mail; false when calculating size only
306c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu         * @throws IOException
307c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu         */
308c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu        public void writeTo(final OutputStream outstream, final boolean withData)
309c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                throws IOException {
310c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            // Not sure if this is possible; the check is taken from the superclass
311c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            if (outstream == null) {
312c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                throw new IllegalArgumentException("Output stream may not be null");
313c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            }
314c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu
315c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            // We'll serialize directly into the output stream
316c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            final Serializer s = new Serializer(outstream);
317c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            // Send the appropriate initial tag
318c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            s.start(mSendTag);
319c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            // The Message-Id for this message (note that we cannot use the messageId stored in
320c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            // the message, as EAS 14 limits the length to 40 chars and we use 70+)
321c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            s.data(Tags.COMPOSE_CLIENT_ID, "SendMail-" + System.nanoTime());
322c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            // We always save sent mail
323c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            s.tag(Tags.COMPOSE_SAVE_IN_SENT_ITEMS);
324c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu
325c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            // If we're using smart reply/forward, we need info about the original message
326c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            if (mSendTag != Tags.COMPOSE_SEND_MAIL) {
327c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                if (mSmartSendInfo != null) {
328c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                    s.start(Tags.COMPOSE_SOURCE);
329c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                    // For search results, use the long id (stored in mProtocolSearchInfo); else,
330c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                    // use folder id/item id combo
331c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                    if (mMessage.mProtocolSearchInfo != null) {
332c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                        s.data(Tags.COMPOSE_LONG_ID, mMessage.mProtocolSearchInfo);
333c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                    } else {
334c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                        s.data(Tags.COMPOSE_ITEM_ID, mSmartSendInfo.mItemId);
335c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                        s.data(Tags.COMPOSE_FOLDER_ID, mSmartSendInfo.mCollectionId);
336c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                    }
337c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                    s.end();  // Tags.COMPOSE_SOURCE
338c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                }
339c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            }
340c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu
341c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            // Start the MIME tag; this is followed by "opaque" data (byte array)
342c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            s.start(Tags.COMPOSE_MIME);
343c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            // Send opaque data from the file stream
344c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            if (withData) {
345c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                s.opaque(mFileStream, (int)mFileLength);
346c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            } else {
347c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                s.opaqueWithoutData((int)mFileLength);
348c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            }
349c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            // And we're done
350c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            s.end().end().done();
351c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu        }
352c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu    }
353c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu
354c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu    private static class SendMailParser extends Parser {
355c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu        private final int mStartTag;
356c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu        private int mStatus;
357c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu
358c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu        public SendMailParser(final InputStream in, final int startTag) throws IOException {
359c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            super(in);
360c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            mStartTag = startTag;
361c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu        }
362c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu
363c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu        public int getStatus() {
364c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            return mStatus;
365c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu        }
366c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu
367c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu        /**
368c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu         * The only useful info in the SendMail response is the status; we capture and save it
369c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu         */
370c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu        @Override
371c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu        public boolean parse() throws IOException {
372c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            if (nextTag(START_DOCUMENT) != mStartTag) {
373c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                throw new IOException();
374c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            }
375c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            while (nextTag(START_DOCUMENT) != END_DOCUMENT) {
376c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                if (tag == Tags.COMPOSE_STATUS) {
377c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                    mStatus = getValueInt();
378c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                } else {
379c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                    skipTag();
380c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                }
381c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            }
382c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            return true;
383c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu        }
384c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu    }
385c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu
386c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu    /**
387c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu     * Attempt to send one message.
388c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu     * @param message The message to send.
389c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu     * @param smartSendInfo The SmartSendInfo for this message, or null if we don't have or don't
390c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu     *      want to use smart send.
391d738c447d8597062f2f20ecb94b96e8bee12a531Yu Ping Hu     * @return Whether or not sending this message succeeded.
392d738c447d8597062f2f20ecb94b96e8bee12a531Yu Ping Hu     * TODO: Improve how we handle the types of failures. I've left the old error codes in as TODOs
393d738c447d8597062f2f20ecb94b96e8bee12a531Yu Ping Hu     * for future reference.
394c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu     */
395d738c447d8597062f2f20ecb94b96e8bee12a531Yu Ping Hu    private boolean sendOneMessage(final Message message, final SmartSendInfo smartSendInfo) {
396c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu        final File tmpFile;
397c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu        try {
398c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            tmpFile = File.createTempFile("eas_", "tmp", mCacheDir);
399c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu        } catch (final IOException e) {
400d738c447d8597062f2f20ecb94b96e8bee12a531Yu Ping Hu            return false; // TODO: Handle SyncStatus.FAILURE_IO;
401c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu        }
402c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu
403c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu        final EasResponse resp;
404c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu        // Send behavior differs pre and post EAS14.
405c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu        final boolean isEas14 = (Double.parseDouble(mAccount.mProtocolVersion) >=
406c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                Eas.SUPPORTED_PROTOCOL_EX2010_DOUBLE);
407c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu        final int modeTag = getModeTag(isEas14, smartSendInfo);
408c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu        try {
409c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            if (!writeMessageToTempFile(tmpFile, message, smartSendInfo)) {
410d738c447d8597062f2f20ecb94b96e8bee12a531Yu Ping Hu                return false; // TODO: Handle SyncStatus.FAILURE_IO;
411c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            }
412c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu
413c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            final FileInputStream fileStream;
414c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            try {
415c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                fileStream = new FileInputStream(tmpFile);
416c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            } catch (final FileNotFoundException e) {
417d738c447d8597062f2f20ecb94b96e8bee12a531Yu Ping Hu                return false; // TODO: Handle SyncStatus.FAILURE_IO;
418c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            }
419c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            try {
420c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu
421c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                final long fileLength = tmpFile.length();
422c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                final HttpEntity entity;
423c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                if (isEas14) {
424c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                    entity = new SendMailEntity(fileStream, fileLength, modeTag, message,
425c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                            smartSendInfo);
426c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                } else {
427c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                    entity = new InputStreamEntity(fileStream, fileLength);
428c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                }
429c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu
430c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                // Create the appropriate command.
431c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                String cmd = "SendMail";
432c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                if (smartSendInfo != null) {
433c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                    // In EAS 14, we don't send itemId and collectionId in the command
434c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                    if (isEas14) {
435c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                        cmd = smartSendInfo.isForward() ? "SmartForward" : "SmartReply";
436c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                    } else {
437c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                        cmd = smartSendInfo.generateSmartSendCmd();
438c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                    }
439c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                }
440c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                // If we're not EAS 14, add our save-in-sent setting here
441c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                if (!isEas14) {
442c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                    cmd += "&SaveInSent=T";
443c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                }
444c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                // Finally, post SendMail to the server
445c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                try {
446c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                    resp = sendHttpClientPost(cmd, entity, SEND_MAIL_TIMEOUT);
447c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                } catch (final IOException e) {
448d738c447d8597062f2f20ecb94b96e8bee12a531Yu Ping Hu                    return false; // TODO: Handle SyncStatus.FAILURE_IO;
449c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                }
450c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu
451c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            } finally {
452c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                try {
453c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                    fileStream.close();
454c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                } catch (final IOException e) {
455c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                    // TODO: Should we do anything here, or is it ok to just proceed?
456c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                }
457c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            }
458c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu        } finally {
459c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            if (tmpFile.exists()) {
460c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                tmpFile.delete();
461c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            }
462c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu        }
463c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu
464c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu        try {
465c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            final int code = resp.getStatus();
466c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            if (code == HttpStatus.SC_OK) {
467c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                // HTTP OK before EAS 14 is a thumbs up; in EAS 14, we've got to parse
468c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                // the reply
469c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                if (isEas14) {
470c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                    try {
471c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                        // Try to parse the result
472c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                        final SendMailParser p = new SendMailParser(resp.getInputStream(), modeTag);
473c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                        // If we get here, the SendMail failed; go figure
474c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                        p.parse();
475c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                        // The parser holds the status
476c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                        final int status = p.getStatus();
477c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                        if (CommandStatus.isNeedsProvisioning(status)) {
478d738c447d8597062f2f20ecb94b96e8bee12a531Yu Ping Hu                            return false; // TODO: Handle SyncStatus.FAILURE_SECURITY;
479c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                        } else if (status == CommandStatus.ITEM_NOT_FOUND &&
480c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                                smartSendInfo != null) {
481c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                            // Let's retry without "smart" commands.
482c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                            return sendOneMessage(message, null);
483c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                        }
484c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                        // TODO: Set syncServerId = SEND_FAILED in DB?
485d738c447d8597062f2f20ecb94b96e8bee12a531Yu Ping Hu                        return false; // TODO: Handle SyncStatus.FAILURE_MESSAGE;
486c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                    } catch (final EmptyStreamException e) {
487c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                        // This is actually fine; an empty stream means SendMail succeeded
488c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                    } catch (final IOException e) {
489c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                        // Parsing failed in some other way.
490d738c447d8597062f2f20ecb94b96e8bee12a531Yu Ping Hu                        return false; // TODO: Handle SyncStatus.FAILURE_IO;
491c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                    }
492c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                }
493c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            } else if (code == HttpStatus.SC_INTERNAL_SERVER_ERROR && smartSendInfo != null) {
494c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                // Let's retry without "smart" commands.
495c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                return sendOneMessage(message, null);
496c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            } else {
497c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                if (EasResponse.isAuthError(code)) {
498d738c447d8597062f2f20ecb94b96e8bee12a531Yu Ping Hu                    return false; // TODO: Handle SyncStatus.FAILURE_LOGIN;
499c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                } else if (EasResponse.isProvisionError(code)) {
500d738c447d8597062f2f20ecb94b96e8bee12a531Yu Ping Hu                    return false; // TODO: Handle SyncStatus.FAILURE_SECURITY;
501c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                }
502c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            }
503c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu        } finally {
504c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            resp.close();
505c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu        }
506c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu
507c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu        // If we manage to get here, the message sent successfully. Hooray!
508c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu        // Delete the sent message.
509c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu        mContext.getContentResolver().delete(
510c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                ContentUris.withAppendedId(Message.CONTENT_URI, message.mId), null, null);
511d738c447d8597062f2f20ecb94b96e8bee12a531Yu Ping Hu        return true;
512c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu    }
513c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu
514c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu    /**
515c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu     * Writes message to the temp file.
516c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu     * @param tmpFile The temp file to use.
517c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu     * @param message The {@link Message} to write.
518c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu     * @param smartSendInfo The {@link SmartSendInfo} for this message send attempt.
519c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu     * @return Whether we could successfully write the file.
520c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu     */
521c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu    private boolean writeMessageToTempFile(final File tmpFile, final Message message,
522c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            final SmartSendInfo smartSendInfo) {
523c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu        final FileOutputStream fileStream;
524c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu        try {
525c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            fileStream = new FileOutputStream(tmpFile);
526c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu        } catch (final FileNotFoundException e) {
527c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            return false;
528c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu        }
529c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu        try {
530c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            final boolean smartSend = smartSendInfo != null;
531c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            final ArrayList<Attachment> attachments =
532c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                    smartSend ? smartSendInfo.mRequiredAtts : null;
533c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            Rfc822Output.writeTo(mContext, message, fileStream, smartSend, true, attachments);
534c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu        } catch (final Exception e) {
535c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            // TODO: Handle file write errors.
536c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu        } finally {
537c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            try {
538c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                fileStream.close();
539c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            } catch (final IOException e) {
540c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                // TODO: Should we do anything here, or is it ok to just proceed?
541c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            }
542c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu        }
543c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu
544c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu        return true;
545c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu    }
546c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu
54756d35257ef1493e849522c3c2828d904e4c5531fScott Kennedy    private static int getModeTag(final boolean isEas14, final SmartSendInfo smartSendInfo) {
548c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu        if (isEas14) {
549c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            if (smartSendInfo == null) {
550c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                return Tags.COMPOSE_SEND_MAIL;
551c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            } else if (smartSendInfo.isForward()) {
552c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                return Tags.COMPOSE_SMART_FORWARD;
553c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            } else {
554c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                return Tags.COMPOSE_SMART_REPLY;
555c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            }
556c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu        }
557c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu        return 0;
558c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu    }
559c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu}
560