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