| package com.android.exchange.eas; |
| |
| import android.content.ContentResolver; |
| import android.content.ContentUris; |
| import android.content.ContentValues; |
| import android.content.Context; |
| import android.content.SyncResult; |
| |
| import com.android.emailcommon.provider.Account; |
| import com.android.emailcommon.provider.EmailContent; |
| import com.android.emailcommon.provider.MessageMove; |
| import com.android.exchange.EasResponse; |
| import com.android.exchange.adapter.MoveItemsParser; |
| import com.android.exchange.adapter.Serializer; |
| import com.android.exchange.adapter.Tags; |
| import com.android.mail.utils.LogUtils; |
| |
| import org.apache.http.HttpEntity; |
| |
| import java.io.IOException; |
| import java.util.List; |
| |
| /** |
| * Performs a MoveItems request, which is used to move items between collections. |
| * See http://msdn.microsoft.com/en-us/library/ee160102(v=exchg.80).aspx for more details. |
| * TODO: Investigate how this interacts with ItemOperations. |
| */ |
| public class EasMoveItems extends EasOperation { |
| |
| /** Result code indicating that no moved messages were found for this account. */ |
| public final static int RESULT_NO_MESSAGES = 0; |
| public final static int RESULT_OK = 1; |
| |
| private static class MoveResponse { |
| public final String sourceMessageId; |
| public final String newMessageId; |
| public final int moveStatus; |
| |
| public MoveResponse(final String srcMsgId, final String dstMsgId, final int status) { |
| sourceMessageId = srcMsgId; |
| newMessageId = dstMsgId; |
| moveStatus = status; |
| } |
| } |
| |
| private MessageMove mMove; |
| private MoveResponse mResponse; |
| |
| public EasMoveItems(final Context context, final Account account) { |
| super(context, account); |
| } |
| |
| // TODO: Allow multiple messages in one request. Requires parser changes. |
| public int upsyncMovedMessages(final SyncResult syncResult) { |
| final List<MessageMove> moves = MessageMove.getMoves(mContext, mAccountId); |
| if (moves == null) { |
| return RESULT_NO_MESSAGES; |
| } |
| |
| final long[][] messageIds = new long[3][moves.size()]; |
| final int[] counts = new int[3]; |
| |
| for (final MessageMove move : moves) { |
| mMove = move; |
| final int result = performOperation(syncResult); |
| final int status; |
| if (result == RESULT_OK) { |
| processResponse(mMove, mResponse); |
| status = mResponse.moveStatus; |
| } else { |
| // TODO: Perhaps not all errors should be retried? |
| status = MoveItemsParser.STATUS_CODE_RETRY; |
| } |
| final int index = status - 1; |
| messageIds[index][counts[index]] = mMove.getMessageId(); |
| ++counts[index]; |
| } |
| |
| final ContentResolver cr = mContext.getContentResolver(); |
| MessageMove.upsyncSuccessful(cr, messageIds[0], counts[0]); |
| MessageMove.upsyncFail(cr, messageIds[1], counts[1]); |
| MessageMove.upsyncRetry(cr, messageIds[2], counts[2]); |
| |
| return RESULT_OK; |
| } |
| |
| @Override |
| protected String getCommand() { |
| return "MoveItems"; |
| } |
| |
| @Override |
| protected HttpEntity getRequestEntity() throws IOException { |
| final Serializer s = new Serializer(); |
| s.start(Tags.MOVE_MOVE_ITEMS); |
| s.start(Tags.MOVE_MOVE); |
| s.data(Tags.MOVE_SRCMSGID, mMove.getServerId()); |
| s.data(Tags.MOVE_SRCFLDID, mMove.getSourceFolderId()); |
| s.data(Tags.MOVE_DSTFLDID, mMove.getDestFolderId()); |
| s.end(); |
| s.end().done(); |
| return makeEntity(s); |
| } |
| |
| @Override |
| protected int handleResponse(final EasResponse response, final SyncResult syncResult) |
| throws IOException { |
| if (!response.isEmpty()) { |
| final MoveItemsParser parser = new MoveItemsParser(response.getInputStream()); |
| parser.parse(); |
| final String sourceMessageId = parser.getSourceServerId(); |
| final String newMessageId = parser.getNewServerId(); |
| final int status = parser.getStatusCode(); |
| mResponse = new MoveResponse(sourceMessageId, newMessageId, status); |
| } |
| return RESULT_OK; |
| } |
| |
| private void processResponse(final MessageMove request, final MoveResponse response) { |
| // TODO: Eventually this should use a transaction. |
| // TODO: Improve how the parser reports statuses and how we handle them here. |
| if (!response.sourceMessageId.equals(request.getServerId())) { |
| // TODO: This is bad, but I think we need to respect the response anyway. |
| LogUtils.e(LOG_TAG, "Got a response for a message we didn't request"); |
| } |
| |
| final ContentValues cv = new ContentValues(1); |
| if (response.moveStatus == MoveItemsParser.STATUS_CODE_REVERT) { |
| // Restore the old mailbox id |
| cv.put(EmailContent.MessageColumns.MAILBOX_KEY, request.getSourceFolderKey()); |
| } else if (response.moveStatus == MoveItemsParser.STATUS_CODE_SUCCESS) { |
| if (response.newMessageId != null |
| && !response.newMessageId.equals(response.sourceMessageId)) { |
| cv.put(EmailContent.SyncColumns.SERVER_ID, response.newMessageId); |
| } |
| } |
| if (cv.size() != 0) { |
| mContext.getContentResolver().update( |
| ContentUris.withAppendedId(EmailContent.Message.CONTENT_URI, |
| request.getMessageId()), cv, null, null); |
| } |
| } |
| } |