1da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdonpackage com.android.exchange.eas; 2c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu 33f72ccad244824f81c327d39af026aee1f22f171Martin Hibdonimport android.content.ContentUris; 4c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Huimport android.content.Context; 5c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Huimport android.net.Uri; 6c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Huimport android.text.format.DateUtils; 7adc77ca7aae4d6f50d40379141e4398ca052d5d5Alon Albertimport android.util.Log; 8c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu 9c60938ced3be4837f0f9350f614b2eb40a5417f5Martin Hibdonimport com.android.emailcommon.internet.MimeUtility; 10c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Huimport com.android.emailcommon.internet.Rfc822Output; 11c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Huimport com.android.emailcommon.provider.Account; 12da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdonimport com.android.emailcommon.provider.Mailbox; 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.utility.Utility; 21da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdonimport com.android.exchange.CommandStatusException; 22c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Huimport com.android.exchange.Eas; 23c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Huimport com.android.exchange.EasResponse; 24da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdonimport com.android.exchange.CommandStatusException.CommandStatus; 25da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdonimport com.android.exchange.adapter.SendMailParser; 26c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Huimport com.android.exchange.adapter.Serializer; 27c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Huimport com.android.exchange.adapter.Tags; 28da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdonimport com.android.exchange.adapter.Parser.EmptyStreamException; 2999905866eb53becb2bd2c15f27546d634df9b3b0Tony Mantlerimport com.android.mail.utils.LogUtils; 30c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu 31c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Huimport org.apache.http.HttpEntity; 32c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Huimport org.apache.http.HttpStatus; 33c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Huimport org.apache.http.entity.InputStreamEntity; 34c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu 35c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Huimport java.io.ByteArrayOutputStream; 36c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Huimport java.io.File; 37c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Huimport java.io.FileInputStream; 38c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Huimport java.io.FileNotFoundException; 39c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Huimport java.io.FileOutputStream; 40c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Huimport java.io.IOException; 41c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Huimport java.io.OutputStream; 42c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Huimport java.util.ArrayList; 43c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu 44da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdonpublic class EasOutboxSync extends EasOperation { 45da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon 46c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu // Value for a message's server id when sending fails. 47c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu public static final int SEND_FAILED = 1; 48c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu // This needs to be long enough to send the longest reasonable message, without being so long 49c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu // as to effectively "hang" sending of mail. The standard 30 second timeout isn't long enough 50c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu // for pictures and the like. For now, we'll use 15 minutes, in the knowledge that any socket 51c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu // failure would probably generate an Exception before timing out anyway 52c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu public static final long SEND_MAIL_TIMEOUT = 15 * DateUtils.MINUTE_IN_MILLIS; 53c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu 54da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon public static final int RESULT_OK = 1; 55da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon public static final int RESULT_IO_ERROR = -100; 56da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon public static final int RESULT_ITEM_NOT_FOUND = -101; 57da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon public static final int RESULT_SEND_FAILED = -102; 58da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon 59da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon private final Message mMessage; 60da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon private final boolean mIsEas14; 61c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu private final File mCacheDir; 62da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon private final SmartSendInfo mSmartSendInfo; 63da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon private final int mModeTag; 64da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon private File mTmpFile; 65da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon private FileInputStream mFileStream; 66c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu 67da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon public EasOutboxSync(final Context context, final Account account, final Message message, 68da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon final boolean useSmartSend) { 69c35d2fa94faa0f9abeded869a01108bac2bcedccYu Ping Hu super(context, account); 70da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon mMessage = message; 71da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon mIsEas14 = (Double.parseDouble(mAccount.mProtocolVersion) >= 72da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon Eas.SUPPORTED_PROTOCOL_EX2010_DOUBLE); 73c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu mCacheDir = context.getCacheDir(); 74da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon if (useSmartSend) { 75da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon mSmartSendInfo = SmartSendInfo.getSmartSendInfo(mContext, mAccount, mMessage); 76da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon } else { 77da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon mSmartSendInfo = null; 78da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon } 79da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon mModeTag = getModeTag(mSmartSendInfo); 80c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu } 81c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu 82da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon @Override 83da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon protected String getCommand() { 84da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon String cmd = "SendMail"; 85da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon if (mSmartSendInfo != null) { 86da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon // In EAS 14, we don't send itemId and collectionId in the command 87da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon if (mIsEas14) { 88da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon cmd = mSmartSendInfo.isForward() ? "SmartForward" : "SmartReply"; 89da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon } else { 90da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon cmd = mSmartSendInfo.generateSmartSendCmd(); 91da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon } 92da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon } 93da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon // If we're not EAS 14, add our save-in-sent setting here 94da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon if (!mIsEas14) { 95da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon cmd += "&SaveInSent=T"; 96da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon } 97da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon return cmd; 98da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon } 99da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon 100da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon @Override 101f6158587a963720526d72ba118ad710e21d1c5d2Martin Hibdon protected HttpEntity getRequestEntity() throws IOException, MessageInvalidException { 102c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu try { 103da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon mTmpFile = File.createTempFile("eas_", "tmp", mCacheDir); 104da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon } catch (final IOException e) { 105da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon LogUtils.w(LOG_TAG, "IO error creating temp file"); 106da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon throw new IllegalStateException("Failure creating temp file"); 107da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon } 108da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon 109da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon if (!writeMessageToTempFile(mTmpFile, mMessage, mSmartSendInfo)) { 110f6158587a963720526d72ba118ad710e21d1c5d2Martin Hibdon // There are several reasons this could happen, possibly the message is corrupt (e.g. 111f6158587a963720526d72ba118ad710e21d1c5d2Martin Hibdon // the To header is null) or the disk is too full to handle the temporary message. 112f6158587a963720526d72ba118ad710e21d1c5d2Martin Hibdon // We can't send this message, but we don't want to abort the entire sync. Returning 113f6158587a963720526d72ba118ad710e21d1c5d2Martin Hibdon // this error code will let the caller recognize that this operation failed, but we 114f6158587a963720526d72ba118ad710e21d1c5d2Martin Hibdon // should continue on with the rest of the sync. 115da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon LogUtils.w(LOG_TAG, "IO error writing to temp file"); 116f6158587a963720526d72ba118ad710e21d1c5d2Martin Hibdon throw new MessageInvalidException("Failure writing to temp file"); 117da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon } 118da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon 119da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon try { 120da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon mFileStream = new FileInputStream(mTmpFile); 121da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon } catch (final FileNotFoundException e) { 122da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon LogUtils.w(LOG_TAG, "IO error creating fileInputStream"); 123da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon throw new IllegalStateException("Failure creating fileInputStream"); 124da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon } 125da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon final long fileLength = mTmpFile.length(); 126da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon final HttpEntity entity; 127da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon if (mIsEas14) { 128da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon entity = new SendMailEntity(mFileStream, fileLength, mModeTag, mMessage, 129da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon mSmartSendInfo); 130da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon } else { 131da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon entity = new InputStreamEntity(mFileStream, fileLength); 132da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon } 133da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon 134da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon return entity; 135da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon } 136da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon 137da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon @Override 138da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon protected int handleHttpError(int httpStatus) { 139da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon if (httpStatus == HttpStatus.SC_INTERNAL_SERVER_ERROR && mSmartSendInfo != null) { 140da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon // Let's retry without "smart" commands. 141da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon return RESULT_ITEM_NOT_FOUND; 142da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon } else { 143da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon return RESULT_OTHER_FAILURE; 144da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon } 145da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon } 146c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu 147da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon @Override 148da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon protected void onRequestMade() { 1493f72ccad244824f81c327d39af026aee1f22f171Martin Hibdon try { 1503f72ccad244824f81c327d39af026aee1f22f171Martin Hibdon mFileStream.close(); 1513f72ccad244824f81c327d39af026aee1f22f171Martin Hibdon } catch (IOException e) { 1523f72ccad244824f81c327d39af026aee1f22f171Martin Hibdon LogUtils.w(LOG_TAG, "IOException closing fileStream %s", e); 1533f72ccad244824f81c327d39af026aee1f22f171Martin Hibdon } 1543f72ccad244824f81c327d39af026aee1f22f171Martin Hibdon if (mTmpFile != null && mTmpFile.exists()) { 155da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon mTmpFile.delete(); 156da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon } 157da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon } 158d738c447d8597062f2f20ecb94b96e8bee12a531Yu Ping Hu 159da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon @Override 160da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon protected int handleResponse(EasResponse response) throws IOException, CommandStatusException { 161da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon if (mIsEas14) { 162da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon try { 163da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon // Try to parse the result 164da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon final SendMailParser p = new SendMailParser(response.getInputStream(), mModeTag); 165da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon // If we get here, the SendMail failed; go figure 166da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon p.parse(); 167da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon // The parser holds the status 168da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon final int status = p.getStatus(); 169da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon if (CommandStatus.isNeedsProvisioning(status)) { 170da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon LogUtils.w(LOG_TAG, "Needs provisioning sending mail"); 171da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon return RESULT_PROVISIONING_ERROR; 172da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon } else if (status == CommandStatus.ITEM_NOT_FOUND && 173da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon mSmartSendInfo != null) { 174da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon // Let's retry without "smart" commands. 175da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon LogUtils.w(LOG_TAG, "Needs provisioning sending mail"); 176da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon return RESULT_ITEM_NOT_FOUND; 177c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu } 178da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon 179da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon // TODO: Set syncServerId = SEND_FAILED in DB? 180da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon LogUtils.d(LOG_TAG, "General failure sending mail"); 181da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon return RESULT_SEND_FAILED; 182da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon } catch (final EmptyStreamException e) { 183da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon // This is actually fine; an empty stream means SendMail succeeded 184da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon LogUtils.d(LOG_TAG, "empty response sending mail"); 185e573fcd7d1b15d29920760802eb403f9307728dfMartin Hibdon // Don't return here, fall through so that we'll delete the sent message. 186da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon } catch (final IOException e) { 187da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon // Parsing failed in some other way. 188da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon LogUtils.w(LOG_TAG, "IOException sending mail"); 189da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon return RESULT_IO_ERROR; 190c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu } 191da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon } else { 192da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon // FLAG: Do we need to parse results for earlier versions? 193da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon } 1943f72ccad244824f81c327d39af026aee1f22f171Martin Hibdon mContext.getContentResolver().delete( 1953f72ccad244824f81c327d39af026aee1f22f171Martin Hibdon ContentUris.withAppendedId(Message.CONTENT_URI, mMessage.mId), null, null); 196da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon return RESULT_OK; 197da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon } 198da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon 199da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon /** 200da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon * Writes message to the temp file. 201da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon * @param tmpFile The temp file to use. 202da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon * @param message The {@link Message} to write. 203da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon * @param smartSendInfo The {@link SmartSendInfo} for this message send attempt. 204da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon * @return Whether we could successfully write the file. 205da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon */ 206da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon private boolean writeMessageToTempFile(final File tmpFile, final Message message, 207da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon final SmartSendInfo smartSendInfo) { 208da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon final FileOutputStream fileStream; 209da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon try { 210da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon fileStream = new FileOutputStream(tmpFile); 211da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon Log.d(LogUtils.TAG, "created outputstream"); 212da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon } catch (final FileNotFoundException e) { 213da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon Log.e(LogUtils.TAG, "Failed to create message file", e); 214da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon return false; 215da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon } 216da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon try { 217da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon final boolean smartSend = smartSendInfo != null; 218da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon final ArrayList<Attachment> attachments = 219da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon smartSend ? smartSendInfo.mRequiredAtts : null; 220da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon Rfc822Output.writeTo(mContext, message, fileStream, smartSend, true, attachments); 221da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon } catch (final Exception e) { 222da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon Log.e(LogUtils.TAG, "Failed to write message file", e); 223da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon return false; 224c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu } finally { 225da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon try { 226da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon fileStream.close(); 227da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon } catch (final IOException e) { 228da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon // should not happen 229da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon Log.e(LogUtils.TAG, "Failed to close file - should not happen", e); 230da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon } 231c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu } 232da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon return true; 233da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon } 234da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon 235da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon private int getModeTag(final SmartSendInfo smartSendInfo) { 236da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon if (mIsEas14) { 237da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon if (smartSendInfo == null) { 238da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon return Tags.COMPOSE_SEND_MAIL; 239da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon } else if (smartSendInfo.isForward()) { 240da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon return Tags.COMPOSE_SMART_FORWARD; 241da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon } else { 242da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon return Tags.COMPOSE_SMART_REPLY; 243da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon } 244da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon } 245da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon return 0; 246c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu } 247c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu 248c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu /** 249c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu * Information needed for SmartReply/SmartForward. 250c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu */ 251c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu private static class SmartSendInfo { 252c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu public static final String[] BODY_SOURCE_PROJECTION = 253c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu new String[] {BodyColumns.SOURCE_MESSAGE_KEY}; 254c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu public static final String WHERE_MESSAGE_KEY = Body.MESSAGE_KEY + "=?"; 255c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu 256c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu final String mItemId; 257c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu final String mCollectionId; 258c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu final boolean mIsReply; 259c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu final ArrayList<Attachment> mRequiredAtts; 260c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu 261da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon private SmartSendInfo(final String itemId, final String collectionId, 262da9fdf76396ca6aa1c8507a6f71336a8bd4145a9Martin Hibdon final boolean isReply,ArrayList<Attachment> requiredAtts) { 263c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu mItemId = itemId; 264c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu mCollectionId = collectionId; 265c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu mIsReply = isReply; 266c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu mRequiredAtts = requiredAtts; 267c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu } 268c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu 269c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu public String generateSmartSendCmd() { 270c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu final StringBuilder sb = new StringBuilder(); 271c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu sb.append(isForward() ? "SmartForward" : "SmartReply"); 272c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu sb.append("&ItemId="); 273c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu sb.append(Uri.encode(mItemId, ":")); 274c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu sb.append("&CollectionId="); 275c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu sb.append(Uri.encode(mCollectionId, ":")); 276c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu return sb.toString(); 277c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu } 278c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu 279c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu public boolean isForward() { 280c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu return !mIsReply; 281c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu } 282c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu 283c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu /** 284c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu * See if a given attachment is among an array of attachments; it is if the locations of 285c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu * both are the same (we're looking to see if they represent the same attachment on the 286c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu * server. Note that an attachment that isn't on the server (e.g. an outbound attachment 287c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu * picked from the gallery) won't have a location, so the result will always be false. 288c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu * 289c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu * @param att the attachment to test 290c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu * @param atts the array of attachments to look in 291c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu * @return whether the test attachment is among the array of attachments 292c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu */ 293c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu private static boolean amongAttachments(final Attachment att, final Attachment[] atts) { 294c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu final String location = att.mLocation; 295c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu if (location == null) return false; 296c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu for (final Attachment a: atts) { 297c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu if (location.equals(a.mLocation)) { 298c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu return true; 299c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu } 300c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu } 301c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu return false; 302c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu } 303c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu 304c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu /** 305c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu * If this message should use SmartReply or SmartForward, return an object with the data 306c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu * for the smart send. 307c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu * 308c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu * @param context the caller's context 309c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu * @param account the Account we're sending from 310c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu * @param message the Message being sent 311c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu * @return an object to support smart sending, or null if not applicable. 312c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu */ 313c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu public static SmartSendInfo getSmartSendInfo(final Context context, 314c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu final Account account, final Message message) { 315c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu final int flags = message.mFlags; 316c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu // We only care about the original message if we include quoted text. 317c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu if ((flags & Message.FLAG_NOT_INCLUDE_QUOTED_TEXT) != 0) { 318c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu return null; 319c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu } 320c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu final boolean reply = (flags & Message.FLAG_TYPE_REPLY) != 0; 321c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu final boolean forward = (flags & Message.FLAG_TYPE_FORWARD) != 0; 322c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu // We also only care for replies or forwards. 323c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu if (!reply && !forward) { 324c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu return null; 325c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu } 326c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu // Just a sanity check here, since we assume that reply and forward are mutually 327c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu // exclusive throughout this class. 328c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu if (reply && forward) { 329c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu return null; 330c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu } 331c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu // If we don't support SmartForward and it's a forward, then don't proceed. 332c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu if (forward && (account.mFlags & Account.FLAGS_SUPPORTS_SMART_FORWARD) == 0) { 333c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu return null; 334c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu } 335c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu 336c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu // Note: itemId and collectionId are the terms used by EAS to refer to the serverId and 337c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu // mailboxId of a Message 338c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu String itemId = null; 339c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu String collectionId = null; 340c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu 341c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu // First, we need to get the id of the reply/forward message 342c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu String[] cols = Utility.getRowColumns(context, Body.CONTENT_URI, BODY_SOURCE_PROJECTION, 343c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu WHERE_MESSAGE_KEY, new String[] {Long.toString(message.mId)}); 344c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu long refId = 0; 345b160b48067ff1d6ff937d3e75c182a8102f655adYu Ping Hu // TODO: We can probably just write a smarter query to do this all at once. 346b160b48067ff1d6ff937d3e75c182a8102f655adYu Ping Hu if (cols != null && cols[0] != null) { 347c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu refId = Long.parseLong(cols[0]); 348c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu // Then, we need the serverId and mailboxKey of the message 349c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu cols = Utility.getRowColumns(context, Message.CONTENT_URI, refId, 350c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu SyncColumns.SERVER_ID, MessageColumns.MAILBOX_KEY, 351c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu MessageColumns.PROTOCOL_SEARCH_INFO); 352c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu if (cols != null) { 353c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu itemId = cols[0]; 354c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu final long boxId = Long.parseLong(cols[1]); 355c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu // Then, we need the serverId of the mailbox 356c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu cols = Utility.getRowColumns(context, Mailbox.CONTENT_URI, boxId, 357c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu MailboxColumns.SERVER_ID); 358c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu if (cols != null) { 359c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu collectionId = cols[0]; 360c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu } 361c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu } 362c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu } 363c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu // We need either a longId or both itemId (serverId) and collectionId (mailboxId) to 364c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu // process a smart reply or a smart forward 365c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu if (itemId != null && collectionId != null) { 366c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu final ArrayList<Attachment> requiredAtts; 367c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu if (forward) { 368c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu // See if we can really smart forward (all reference attachments must be sent) 369c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu final Attachment[] outAtts = 370c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu Attachment.restoreAttachmentsWithMessageId(context, message.mId); 371c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu final Attachment[] refAtts = 372c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu Attachment.restoreAttachmentsWithMessageId(context, refId); 373c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu for (final Attachment refAtt: refAtts) { 374c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu // If an original attachment isn't among what's going out, we can't be smart 375c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu if (!amongAttachments(refAtt, outAtts)) { 376c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu return null; 377c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu } 378c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu } 379c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu requiredAtts = new ArrayList<Attachment>(); 380c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu for (final Attachment outAtt: outAtts) { 381c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu // If an outgoing attachment isn't in original message, we must send it 382c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu if (!amongAttachments(outAtt, refAtts)) { 383c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu requiredAtts.add(outAtt); 384c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu } 385c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu } 386c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu } else { 387c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu requiredAtts = null; 388c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu } 389c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu return new SmartSendInfo(itemId, collectionId, reply, requiredAtts); 390c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu } 391c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu return null; 392c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu } 393c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu } 394c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu 395c60938ced3be4837f0f9350f614b2eb40a5417f5Martin Hibdon @Override 396c60938ced3be4837f0f9350f614b2eb40a5417f5Martin Hibdon public String getRequestContentType() { 397c60938ced3be4837f0f9350f614b2eb40a5417f5Martin Hibdon // When using older protocols, we need to use a different MIME type for sending messages. 398c60938ced3be4837f0f9350f614b2eb40a5417f5Martin Hibdon if (getProtocolVersion() < Eas.SUPPORTED_PROTOCOL_EX2010_DOUBLE) { 399c60938ced3be4837f0f9350f614b2eb40a5417f5Martin Hibdon return MimeUtility.MIME_TYPE_RFC822; 400c60938ced3be4837f0f9350f614b2eb40a5417f5Martin Hibdon } else { 401c60938ced3be4837f0f9350f614b2eb40a5417f5Martin Hibdon return super.getRequestContentType(); 402c60938ced3be4837f0f9350f614b2eb40a5417f5Martin Hibdon } 403c60938ced3be4837f0f9350f614b2eb40a5417f5Martin Hibdon } 404c60938ced3be4837f0f9350f614b2eb40a5417f5Martin Hibdon 405c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu /** 406c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu * Our own HttpEntity subclass that is able to insert opaque data (in this case the MIME 407c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu * representation of the message body as stored in a temporary file) into the serializer stream 408c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu */ 409c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu private static class SendMailEntity extends InputStreamEntity { 410c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu private final FileInputStream mFileStream; 411c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu private final long mFileLength; 412c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu private final int mSendTag; 413c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu private final Message mMessage; 414c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu private final SmartSendInfo mSmartSendInfo; 415c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu 416c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu public SendMailEntity(final FileInputStream instream, final long length, final int tag, 417c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu final Message message, final SmartSendInfo smartSendInfo) { 418c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu super(instream, length); 419c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu mFileStream = instream; 420c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu mFileLength = length; 421c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu mSendTag = tag; 422c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu mMessage = message; 423c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu mSmartSendInfo = smartSendInfo; 424c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu } 425c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu 426c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu /** 427c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu * We always return -1 because we don't know the actual length of the POST data (this 428c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu * causes HttpClient to send the data in "chunked" mode) 429c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu */ 430c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu @Override 431c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu public long getContentLength() { 432c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu final ByteArrayOutputStream baos = new ByteArrayOutputStream(); 433c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu try { 434c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu // Calculate the overhead for the WBXML data 435c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu writeTo(baos, false); 436c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu // Return the actual size that will be sent 437c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu return baos.size() + mFileLength; 438c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu } catch (final IOException e) { 439c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu // Just return -1 (unknown) 440c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu } finally { 441c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu try { 442c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu baos.close(); 443c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu } catch (final IOException e) { 444c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu // Ignore 445c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu } 446c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu } 447c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu return -1; 448c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu } 449c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu 450c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu @Override 451c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu public void writeTo(final OutputStream outstream) throws IOException { 452c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu writeTo(outstream, true); 453c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu } 454c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu 455c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu /** 456c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu * Write the message to the output stream 457c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu * @param outstream the output stream to write 458c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu * @param withData whether or not the actual data is to be written; true when sending 459c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu * mail; false when calculating size only 460c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu * @throws IOException 461c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu */ 462c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu public void writeTo(final OutputStream outstream, final boolean withData) 463c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu throws IOException { 464c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu // Not sure if this is possible; the check is taken from the superclass 465c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu if (outstream == null) { 466c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu throw new IllegalArgumentException("Output stream may not be null"); 467c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu } 468c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu 469c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu // We'll serialize directly into the output stream 470c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu final Serializer s = new Serializer(outstream); 471c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu // Send the appropriate initial tag 472c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu s.start(mSendTag); 473c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu // The Message-Id for this message (note that we cannot use the messageId stored in 474c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu // the message, as EAS 14 limits the length to 40 chars and we use 70+) 475c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu s.data(Tags.COMPOSE_CLIENT_ID, "SendMail-" + System.nanoTime()); 476c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu // We always save sent mail 477c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu s.tag(Tags.COMPOSE_SAVE_IN_SENT_ITEMS); 478c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu 479c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu // If we're using smart reply/forward, we need info about the original message 480c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu if (mSendTag != Tags.COMPOSE_SEND_MAIL) { 481c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu if (mSmartSendInfo != null) { 482c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu s.start(Tags.COMPOSE_SOURCE); 483c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu // For search results, use the long id (stored in mProtocolSearchInfo); else, 484c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu // use folder id/item id combo 485c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu if (mMessage.mProtocolSearchInfo != null) { 486c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu s.data(Tags.COMPOSE_LONG_ID, mMessage.mProtocolSearchInfo); 487c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu } else { 488c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu s.data(Tags.COMPOSE_ITEM_ID, mSmartSendInfo.mItemId); 489c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu s.data(Tags.COMPOSE_FOLDER_ID, mSmartSendInfo.mCollectionId); 490c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu } 491c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu s.end(); // Tags.COMPOSE_SOURCE 492c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu } 493c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu } 494c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu 495c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu // Start the MIME tag; this is followed by "opaque" data (byte array) 496c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu s.start(Tags.COMPOSE_MIME); 497c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu // Send opaque data from the file stream 498c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu if (withData) { 499c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu s.opaque(mFileStream, (int)mFileLength); 500c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu } else { 501c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu s.opaqueWithoutData((int)mFileLength); 502c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu } 503c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu // And we're done 504c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu s.end().end().done(); 505c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu } 506c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu } 507c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu} 508