EasLoadAttachment.java revision 7848f4e9c1a50fa36ddcce692b11ee713df14cb8
1b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee/* 2b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee * Copyright (C) 2014 The Android Open Source Project 3b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee * 4b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee * Licensed under the Apache License, Version 2.0 (the "License"); 5b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee * you may not use this file except in compliance with the License. 6b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee * You may obtain a copy of the License at 7b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee * 8b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee * http://www.apache.org/licenses/LICENSE-2.0 9b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee * 10b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee * Unless required by applicable law or agreed to in writing, software 11b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee * distributed under the License is distributed on an "AS IS" BASIS, 12b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee * See the License for the specific language governing permissions and 14b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee * limitations under the License. 15b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee */ 16b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee 17b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Leepackage com.android.exchange.eas; 18b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee 19b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Leeimport android.content.Context; 20b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Leeimport android.os.RemoteException; 21b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee 22b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Leeimport com.android.emailcommon.provider.EmailContent; 23b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Leeimport com.android.emailcommon.provider.EmailContent.Attachment; 24b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Leeimport com.android.emailcommon.service.EmailServiceStatus; 25b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Leeimport com.android.emailcommon.service.IEmailServiceCallback; 26b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Leeimport com.android.emailcommon.utility.AttachmentUtilities; 27b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Leeimport com.android.exchange.Eas; 28b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Leeimport com.android.exchange.EasResponse; 29b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Leeimport com.android.exchange.adapter.ItemOperationsParser; 30b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Leeimport com.android.exchange.adapter.Serializer; 31b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Leeimport com.android.exchange.adapter.Tags; 32b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Leeimport com.android.exchange.service.EasService; 33b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Leeimport com.android.exchange.utility.UriCodec; 34b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Leeimport com.android.mail.utils.LogUtils; 35b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee 36b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Leeimport org.apache.http.HttpEntity; 37b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee 38b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Leeimport java.io.Closeable; 39b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Leeimport java.io.File; 40b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Leeimport java.io.FileInputStream; 41b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Leeimport java.io.FileNotFoundException; 42b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Leeimport java.io.FileOutputStream; 43b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Leeimport java.io.IOException; 44b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Leeimport java.io.InputStream; 45b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Leeimport java.io.OutputStream; 46b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee 47b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee/** 48b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee * This class performs the heavy lifting of loading attachments from the Exchange server to the 49b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee * device in a local file. 50b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee * TODO: Add ability to call back to UI when this failed, and generally better handle error cases. 51b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee */ 52b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Leepublic final class EasLoadAttachment extends EasOperation { 53b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee 54b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee /** Attachment Loading Errors **/ 55b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee public static final int RESULT_LOAD_ATTACHMENT_INFO_ERROR = -100; 56b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee public static final int RESULT_ATTACHMENT_NO_LOCATION_ERROR = -101; 57b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee public static final int RESULT_ATTACHMENT_LOAD_MESSAGE_ERROR = -102; 58b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee public static final int RESULT_ATTACHMENT_INTERNAL_HANDLING_ERROR = -103; 59b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee public static final int RESULT_ATTACHMENT_RESPONSE_PARSING_ERROR = -104; 60b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee 61b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee private final IEmailServiceCallback mCallback; 62b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee private final long mAttachmentId; 63b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee 64b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee // These members are set in a future point in time outside of the constructor. 65b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee private Attachment mAttachment; 66b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee 67b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee /** 68b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee * Constructor for use with {@link EasService} when performing an actual sync. 69b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee * @param context Our {@link Context}. 70b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee * @param accountId The id of the account in question (i.e. its id in the database). 71b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee * @param attachmentId The local id of the attachment (i.e. its id in the database). 72b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee * @param callback The callback for any status updates. 73b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee */ 74b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee public EasLoadAttachment(final Context context, final long accountId, final long attachmentId, 75b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee final IEmailServiceCallback callback) { 76b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee // The account is loaded before performOperation but it is not guaranteed to be available 77b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee // before then. 78b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee super(context, accountId); 79b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee mCallback = callback; 80b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee mAttachmentId = attachmentId; 81b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee } 82b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee 83b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee /** 84b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee * Helper function that makes a callback for us within our implementation. 85b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee */ 86b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee private static void doStatusCallback(final IEmailServiceCallback callback, 87b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee final long messageKey, final long attachmentId, final int status, final int progress) { 88b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee if (callback != null) { 89b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee try { 90b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee // loadAttachmentStatus is mart of IEmailService interface. 91b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee callback.loadAttachmentStatus(messageKey, attachmentId, status, progress); 92b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee } catch (final RemoteException e) { 93b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee LogUtils.e(LOG_TAG, "RemoteException in loadAttachment: %s", e.getMessage()); 94b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee } 95b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee } 96b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee } 97b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee 98b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee /** 99b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee * Helper class that is passed to other objects to perform callbacks for us. 100b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee */ 101b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee public static class ProgressCallback { 102b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee private final IEmailServiceCallback mCallback; 103b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee private final EmailContent.Attachment mAttachment; 104b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee 105b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee public ProgressCallback(final IEmailServiceCallback callback, 106b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee final EmailContent.Attachment attachment) { 107b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee mCallback = callback; 108b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee mAttachment = attachment; 109b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee } 110b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee 111b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee public void doCallback(final int progress) { 112b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee doStatusCallback(mCallback, mAttachment.mMessageKey, mAttachment.mId, 113b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee EmailServiceStatus.IN_PROGRESS, progress); 114b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee } 115b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee } 116b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee 117b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee /** 118b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee * Encoder for Exchange 2003 attachment names. They come from the server partially encoded, 119b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee * but there are still possible characters that need to be encoded (Why, MSFT, why?) 120b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee */ 121b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee private static class AttachmentNameEncoder extends UriCodec { 122b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee @Override 123b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee protected boolean isRetained(final char c) { 124b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee // These four characters are commonly received in EAS 2.5 attachment names and are 125b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee // valid (verified by testing); we won't encode them 126b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee return c == '_' || c == ':' || c == '/' || c == '.'; 127b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee } 128b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee } 129b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee 130b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee /** 131b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee * Finish encoding attachment names for Exchange 2003. 132b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee * @param str A partially encoded string. 133b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee * @return The fully encoded version of str. 134b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee */ 135b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee private static String encodeForExchange2003(final String str) { 136b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee final AttachmentNameEncoder enc = new AttachmentNameEncoder(); 137b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee final StringBuilder sb = new StringBuilder(str.length() + 16); 138b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee enc.appendPartiallyEncoded(sb, str); 139b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee return sb.toString(); 140b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee } 141b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee 142b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee /** 143b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee * Finish encoding attachment names for Exchange 2003. 144b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee * @return A {@link EmailServiceStatus} code that indicates the result of the operation. 145b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee */ 146b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee @Override 1478c95506ad96f5990d5e4d4ca86b05ec95dd4b1d6Yu Ping Hu public int performOperation() { 148b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee mAttachment = EmailContent.Attachment.restoreAttachmentWithId(mContext, mAttachmentId); 149b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee if (mAttachment == null) { 150b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee LogUtils.e(LOG_TAG, "Could not load attachment %d", mAttachmentId); 151b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee doStatusCallback(mCallback, -1, mAttachmentId, EmailServiceStatus.ATTACHMENT_NOT_FOUND, 152b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee 0); 153b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee return RESULT_LOAD_ATTACHMENT_INFO_ERROR; 154b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee } 155b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee if (mAttachment.mLocation == null) { 156b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee LogUtils.e(LOG_TAG, "Attachment %d lacks a location", mAttachmentId); 157b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee doStatusCallback(mCallback, -1, mAttachmentId, EmailServiceStatus.ATTACHMENT_NOT_FOUND, 158b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee 0); 159b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee return RESULT_ATTACHMENT_NO_LOCATION_ERROR; 160b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee } 161b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee final EmailContent.Message message = EmailContent.Message 162b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee .restoreMessageWithId(mContext, mAttachment.mMessageKey); 163b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee if (message == null) { 164b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee LogUtils.e(LOG_TAG, "Could not load message %d", mAttachment.mMessageKey); 165b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee doStatusCallback(mCallback, mAttachment.mMessageKey, mAttachmentId, 166b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee EmailServiceStatus.MESSAGE_NOT_FOUND, 0); 167b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee return RESULT_ATTACHMENT_LOAD_MESSAGE_ERROR; 168b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee } 169b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee 170b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee // First callback to let the client know that we have started the attachment load. 1717848f4e9c1a50fa36ddcce692b11ee713df14cb8Anthony Lee LogUtils.e(LOG_TAG, "Calling callback for %d with IN_PROGRESS", mAttachmentId); 1727848f4e9c1a50fa36ddcce692b11ee713df14cb8Anthony Lee doStatusCallback(mCallback, mAttachment.mMessageKey, mAttachmentId, 173b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee EmailServiceStatus.IN_PROGRESS, 0); 174b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee 1758c95506ad96f5990d5e4d4ca86b05ec95dd4b1d6Yu Ping Hu final int return_value = super.performOperation(); 176b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee 1777848f4e9c1a50fa36ddcce692b11ee713df14cb8Anthony Lee // Last callback to report results. 1787848f4e9c1a50fa36ddcce692b11ee713df14cb8Anthony Lee if (return_value < 0) { 1797848f4e9c1a50fa36ddcce692b11ee713df14cb8Anthony Lee // We had an error processing an attachment, let's report a {@link EmailServiceStatus} 1807848f4e9c1a50fa36ddcce692b11ee713df14cb8Anthony Lee // connection error in this case 1817848f4e9c1a50fa36ddcce692b11ee713df14cb8Anthony Lee LogUtils.d(LOG_TAG, "Invoking callback for attachmentId: %d with CONNECTION_ERROR", 1827848f4e9c1a50fa36ddcce692b11ee713df14cb8Anthony Lee mAttachmentId); 1837848f4e9c1a50fa36ddcce692b11ee713df14cb8Anthony Lee doStatusCallback(mCallback, mAttachment.mMessageKey, mAttachmentId, 1847848f4e9c1a50fa36ddcce692b11ee713df14cb8Anthony Lee EmailServiceStatus.CONNECTION_ERROR, 0); 1857848f4e9c1a50fa36ddcce692b11ee713df14cb8Anthony Lee } else { 1867848f4e9c1a50fa36ddcce692b11ee713df14cb8Anthony Lee LogUtils.d(LOG_TAG, "Invoking callback for attachmentId: %d with SUCCESS", 1877848f4e9c1a50fa36ddcce692b11ee713df14cb8Anthony Lee mAttachmentId); 1887848f4e9c1a50fa36ddcce692b11ee713df14cb8Anthony Lee doStatusCallback(mCallback, mAttachment.mMessageKey, mAttachmentId, 1897848f4e9c1a50fa36ddcce692b11ee713df14cb8Anthony Lee EmailServiceStatus.SUCCESS, 0); 190b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee } 191b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee return return_value; 192b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee } 193b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee 194b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee @Override 195b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee protected String getCommand() { 196b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee if (mAttachment == null) { 197b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee LogUtils.wtf(LOG_TAG, "Error, mAttachment is null"); 198b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee } 199b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee 200b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee final String cmd; 201b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee if (getProtocolVersion() >= Eas.SUPPORTED_PROTOCOL_EX2010_DOUBLE) { 202b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee // The operation is different in EAS 14.0 than in earlier versions 203b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee cmd = "ItemOperations"; 204b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee } else { 205b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee final String location; 206b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee // For Exchange 2003 (EAS 2.5), we have to look for illegal chars in the file name 207b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee // that EAS sent to us! 208b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee if (getProtocolVersion() < Eas.SUPPORTED_PROTOCOL_EX2007_DOUBLE) { 209b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee location = encodeForExchange2003(mAttachment.mLocation); 210b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee } else { 211b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee location = mAttachment.mLocation; 212b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee } 213b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee cmd = "GetAttachment&AttachmentName=" + location; 214b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee } 215b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee return cmd; 216b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee } 217b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee 218b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee @Override 219b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee protected HttpEntity getRequestEntity() throws IOException { 220b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee if (mAttachment == null) { 221b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee LogUtils.wtf(LOG_TAG, "Error, mAttachment is null"); 222b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee } 223b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee 224b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee final HttpEntity entity; 225b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee final Serializer s = new Serializer(); 226b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee if (getProtocolVersion() >= Eas.SUPPORTED_PROTOCOL_EX2010_DOUBLE) { 227b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee s.start(Tags.ITEMS_ITEMS).start(Tags.ITEMS_FETCH); 228b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee s.data(Tags.ITEMS_STORE, "Mailbox"); 229b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee s.data(Tags.BASE_FILE_REFERENCE, mAttachment.mLocation); 230b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee s.end().end().done(); // ITEMS_FETCH, ITEMS_ITEMS 231b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee entity = makeEntity(s); 232b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee } else { 233b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee // Older versions of the protocol have the attachment location in the command. 234b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee entity = null; 235b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee } 236b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee return entity; 237b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee } 238b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee 239b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee /** 240b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee * Close, ignoring errors (as during cleanup) 241b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee * @param c a Closeable 242b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee */ 243b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee private static void close(final Closeable c) { 244b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee try { 245b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee c.close(); 246b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee } catch (IOException e) { 247b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee LogUtils.e(LOG_TAG, "IOException while cleaning up attachment: %s", e.getMessage()); 248b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee } 249b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee } 250b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee 251b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee /** 252b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee * Save away the contentUri for this Attachment and notify listeners 253b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee */ 254b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee private boolean finishLoadAttachment(final EmailContent.Attachment attachment, final File file) { 255b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee final InputStream in; 256b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee try { 257b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee in = new FileInputStream(file); 258b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee } catch (final FileNotFoundException e) { 259b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee // Unlikely, as we just created it successfully, but log it. 260b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee LogUtils.e(LOG_TAG, "Could not open attachment file: %s", e.getMessage()); 261b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee return false; 262b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee } 263b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee AttachmentUtilities.saveAttachment(mContext, in, attachment); 264b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee close(in); 265b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee return true; 266b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee } 267b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee 268b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee /** 269b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee * Read the {@link EasResponse} and extract the attachment data, saving it to the provider. 270b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee * @param response The (successful) {@link EasResponse} containing the attachment data. 2717848f4e9c1a50fa36ddcce692b11ee713df14cb8Anthony Lee * @return A status code, 0 is a success, anything negative is an error outlined by constants 2727848f4e9c1a50fa36ddcce692b11ee713df14cb8Anthony Lee * in this class or its base class. 273b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee */ 274b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee @Override 2758c95506ad96f5990d5e4d4ca86b05ec95dd4b1d6Yu Ping Hu protected int handleResponse(final EasResponse response) { 276b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee // Some very basic error checking on the response object first. 277b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee // Our base class should be responsible for checking these errors but if the error 278b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee // checking is done in the override functions, we can be more specific about 279b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee // the errors that are being returned to the caller of performOperation(). 280b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee if (response.isEmpty()) { 281b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee LogUtils.e(LOG_TAG, "Error, empty response."); 2827848f4e9c1a50fa36ddcce692b11ee713df14cb8Anthony Lee return RESULT_REQUEST_FAILURE; 283b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee } 284b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee 285b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee // This is a 2 step process. 286b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee // 1. Grab what came over the wire and write it to a temp file on disk. 287b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee // 2. Move the attachment to its final location. 288b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee final File tmpFile; 289b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee try { 290b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee tmpFile = File.createTempFile("eas_", "tmp", mContext.getCacheDir()); 291b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee } catch (final IOException e) { 292b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee LogUtils.e(LOG_TAG, "Could not open temp file: %s", e.getMessage()); 2937848f4e9c1a50fa36ddcce692b11ee713df14cb8Anthony Lee return RESULT_REQUEST_FAILURE; 294b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee } 295b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee 296b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee try { 297b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee final OutputStream os; 298b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee try { 299b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee os = new FileOutputStream(tmpFile); 300b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee } catch (final FileNotFoundException e) { 301b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee LogUtils.e(LOG_TAG, "Temp file not found: %s", e.getMessage()); 3027848f4e9c1a50fa36ddcce692b11ee713df14cb8Anthony Lee return RESULT_ATTACHMENT_INTERNAL_HANDLING_ERROR; 303b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee } 304b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee try { 305b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee final InputStream is = response.getInputStream(); 306b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee try { 307b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee // TODO: Right now we are explictly loading this from a class 308b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee // that will be deprecated when we move over to EasService. When we start using 309b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee // our internal class instead, there will be rippling side effect changes that 310b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee // need to be made when this time comes. 311b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee final ProgressCallback callback = new ProgressCallback(mCallback, mAttachment); 312b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee final boolean success; 313b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee if (getProtocolVersion() >= Eas.SUPPORTED_PROTOCOL_EX2010_DOUBLE) { 314b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee final ItemOperationsParser parser = new ItemOperationsParser(is, os, 315b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee mAttachment.mSize, callback); 316b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee parser.parse(); 317b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee success = (parser.getStatusCode() == 1); 318b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee } else { 319b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee final int length = response.getLength(); 320b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee if (length != 0) { 321b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee // len > 0 means that Content-Length was set in the headers 322b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee // len < 0 means "chunked" transfer-encoding 323b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee ItemOperationsParser.readChunked(is, os, 324b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee (length < 0) ? mAttachment.mSize : length, callback); 325b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee } 326b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee success = true; 327b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee } 328b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee // Check that we successfully grabbed what came over the wire... 329b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee if (!success) { 330b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee LogUtils.e(LOG_TAG, "Error parsing server response"); 3317848f4e9c1a50fa36ddcce692b11ee713df14cb8Anthony Lee return RESULT_ATTACHMENT_RESPONSE_PARSING_ERROR; 332b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee } 333b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee // Now finish the process and save to the final destination. 334b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee final boolean loadResult = finishLoadAttachment(mAttachment, tmpFile); 335b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee if (!loadResult) { 336b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee LogUtils.e(LOG_TAG, "Error post processing attachment file."); 3377848f4e9c1a50fa36ddcce692b11ee713df14cb8Anthony Lee return RESULT_ATTACHMENT_INTERNAL_HANDLING_ERROR; 338b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee } 339b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee } catch (final IOException e) { 340b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee LogUtils.e(LOG_TAG, "Error handling attachment: %s", e.getMessage()); 341b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee return RESULT_ATTACHMENT_INTERNAL_HANDLING_ERROR; 342b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee } finally { 343b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee close(is); 344b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee } 345b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee } finally { 346b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee close(os); 347b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee } 348b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee } finally { 349b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee tmpFile.delete(); 350b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee } 3517848f4e9c1a50fa36ddcce692b11ee713df14cb8Anthony Lee return 0; 352b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee } 353b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee} 354