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