FolderSyncParser.java revision 00d91b2e12d65df06916afdc4bebca67fd27214c
1ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank/*
2ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank * Copyright (C) 2008-2009 Marc Blank
3ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank * Licensed to The Android Open Source Project.
4ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank *
5ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank * Licensed under the Apache License, Version 2.0 (the "License");
6ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank * you may not use this file except in compliance with the License.
7ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank * You may obtain a copy of the License at
8ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank *
9ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank *      http://www.apache.org/licenses/LICENSE-2.0
10ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank *
11ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank * Unless required by applicable law or agreed to in writing, software
12ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank * distributed under the License is distributed on an "AS IS" BASIS,
13ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank * See the License for the specific language governing permissions and
15ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank * limitations under the License.
16ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank */
17ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank
18ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blankpackage com.android.exchange.adapter;
19ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank
20ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blankimport com.android.email.provider.EmailProvider;
21ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blankimport com.android.exchange.Eas;
22ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blankimport com.android.exchange.EasSyncService;
23ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blankimport com.android.exchange.MockParserStream;
24ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blankimport com.android.exchange.SyncManager;
25ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blankimport com.android.exchange.EmailContent.Account;
26ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blankimport com.android.exchange.EmailContent.Mailbox;
27ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blankimport com.android.exchange.EmailContent.MailboxColumns;
28ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank
29ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blankimport android.content.ContentProviderOperation;
30ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blankimport android.content.ContentResolver;
31ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blankimport android.content.ContentUris;
32ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blankimport android.content.Context;
33ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blankimport android.content.OperationApplicationException;
34ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blankimport android.database.Cursor;
35ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blankimport android.os.RemoteException;
36ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blankimport android.util.Log;
37ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank
3800d91b2e12d65df06916afdc4bebca67fd27214cMarc Blankimport java.io.IOException;
3900d91b2e12d65df06916afdc4bebca67fd27214cMarc Blankimport java.io.InputStream;
4000d91b2e12d65df06916afdc4bebca67fd27214cMarc Blankimport java.util.ArrayList;
4100d91b2e12d65df06916afdc4bebca67fd27214cMarc Blankimport java.util.Arrays;
4200d91b2e12d65df06916afdc4bebca67fd27214cMarc Blankimport java.util.List;
4300d91b2e12d65df06916afdc4bebca67fd27214cMarc Blank
44ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank/**
45ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank * Parse the result of a FolderSync command
46ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank *
47ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank * Handles the addition, deletion, and changes to folders in the user's Exchange account.
48ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank **/
49ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank
50ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blankpublic class EasFolderSyncParser extends EasParser {
51ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank
5222bc4e0e4f4a5e43e4eea8d59e1961860c507594Marc Blank    private static boolean DEBUG_LOGGING = false;
5322bc4e0e4f4a5e43e4eea8d59e1961860c507594Marc Blank
54ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank    public static final String TAG = "FolderSyncParser";
55ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank
56ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank    // These are defined by the EAS protocol
57ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank    public static final int USER_FOLDER_TYPE = 1;
58ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank    public static final int INBOX_TYPE = 2;
59ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank    public static final int DRAFTS_TYPE = 3;
60ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank    public static final int DELETED_TYPE = 4;
61ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank    public static final int SENT_TYPE = 5;
62ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank    public static final int OUTBOX_TYPE = 6;
63ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank    public static final int TASKS_TYPE = 7;
64ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank    public static final int CALENDAR_TYPE = 8;
65ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank    public static final int CONTACTS_TYPE = 9;
66ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank    public static final int NOTES_TYPE = 10;
67ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank    public static final int JOURNAL_TYPE = 11;
68ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank    public static final int USER_MAILBOX_TYPE = 12;
69ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank
70ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank    public static final List<Integer> mValidFolderTypes = Arrays.asList(INBOX_TYPE, DRAFTS_TYPE,
71ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank            DELETED_TYPE, SENT_TYPE, OUTBOX_TYPE, USER_MAILBOX_TYPE, CALENDAR_TYPE, CONTACTS_TYPE);
72ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank
73ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank    private static final String WHERE_SERVER_ID_AND_ACCOUNT = MailboxColumns.SERVER_ID + "=? and " +
74ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank        MailboxColumns.ACCOUNT_KEY + "=?";
75ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank
76ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank    private static final String WHERE_DISPLAY_NAME_AND_ACCOUNT = MailboxColumns.DISPLAY_NAME +
77ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank        "=? and " + MailboxColumns.ACCOUNT_KEY + "=?";
78ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank
79ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank    private static final String WHERE_PARENT_SERVER_ID_AND_ACCOUNT =
80ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank        MailboxColumns.PARENT_SERVER_ID +"=? and " + MailboxColumns.ACCOUNT_KEY + "=?";
81ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank
82ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank    private static final String[] MAILBOX_ID_COLUMNS_PROJECTION =
83ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank        new String[] {MailboxColumns.ID, MailboxColumns.SERVER_ID};
84ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank
85ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank    private Account mAccount;
86ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank
87ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank    private long mAccountId;
88ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank
89ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank    private String mAccountIdAsString;
90ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank
91ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank    private EasSyncService mService;
92ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank
93ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank    private Context mContext;
94ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank
95ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank    private ContentResolver mContentResolver;
96ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank
97ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank    private MockParserStream mMock = null;
98ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank
99ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank    private String[] mBindArguments = new String[2];
100ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank
101ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank    public EasFolderSyncParser(InputStream in, EasSyncService service) throws IOException {
102ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank        super(in);
103ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank        mService = service;
104ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank        mAccount = service.mAccount;
105ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank        mAccountId = mAccount.mId;
106ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank        mAccountIdAsString = Long.toString(mAccountId);
107ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank        mContext = service.mContext;
108ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank        mContentResolver = mContext.getContentResolver();
109ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank        if (in instanceof MockParserStream) {
110ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank            mMock = (MockParserStream)in;
111ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank        }
11222bc4e0e4f4a5e43e4eea8d59e1961860c507594Marc Blank        if (DEBUG_LOGGING) {
11322bc4e0e4f4a5e43e4eea8d59e1961860c507594Marc Blank            setDebug(true);
11422bc4e0e4f4a5e43e4eea8d59e1961860c507594Marc Blank        }
115ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank    }
116ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank
117ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank    public boolean parse() throws IOException {
118ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank        int status;
119ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank        boolean res = false;
120ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank        if (nextTag(START_DOCUMENT) != EasTags.FOLDER_FOLDER_SYNC)
121ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank            throw new IOException();
122ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank        while (nextTag(START_DOCUMENT) != END_DOCUMENT) {
123ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank            if (tag == EasTags.FOLDER_STATUS) {
124ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                status = getValueInt();
125ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                if (status != Eas.FOLDER_STATUS_OK) {
126ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                    mService.errorLog("FolderSync failed: " + status);
127ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                    if (status == Eas.FOLDER_STATUS_INVALID_KEY) {
128ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                        mAccount.mSyncKey = "0";
129ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                        mService.errorLog("Bad sync key; RESET and delete all folders");
130ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                        mContentResolver.delete(Mailbox.CONTENT_URI,
131ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                                MailboxColumns.ACCOUNT_KEY + '=' + mAccountId, null);
132ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                        // Stop existing syncs and reconstruct _main
133ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                        SyncManager.folderListReloaded(mAccountId);
134ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                        res = true;
135ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                    } else {
136ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                        // Other errors are at the server, so let's throw an error that will
137ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                        // cause this sync to be retried at a later time
138ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                        mService.errorLog("Throwing IOException; will retry later");
139ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                        throw new IOException();
140ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                    }
141ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                }
142ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank            } else if (tag == EasTags.FOLDER_SYNC_KEY) {
143ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                mAccount.mSyncKey = getValue();
144ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                mService.userLog("New Account SyncKey: " + mAccount.mSyncKey);
145ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank            } else if (tag == EasTags.FOLDER_CHANGES) {
146ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                changesParser();
147ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank            } else
148ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                skipTag();
149ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank        }
150ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank
151ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank        mAccount.saveOrUpdate(mContext);
152ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank        return res;
153ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank    }
154ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank
155ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank    private Cursor getServerIdCursor(String serverId) {
156ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank        mBindArguments[0] = serverId;
157ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank        mBindArguments[1] = mAccountIdAsString;
158ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank        return mContentResolver.query(Mailbox.CONTENT_URI, new String[] {MailboxColumns.ID},
159ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                WHERE_SERVER_ID_AND_ACCOUNT, mBindArguments, null);
160ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank    }
161ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank
162ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank    public void deleteParser(ArrayList<ContentProviderOperation> ops) throws IOException {
163ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank        while (nextTag(EasTags.SYNC_DELETE) != END) {
164ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank            switch (tag) {
165ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                case EasTags.FOLDER_SERVER_ID:
166ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                    String serverId = getValue();
167ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                    // Find the mailbox in this account with the given serverId
168ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                    Cursor c = getServerIdCursor(serverId);
169ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                    try {
170ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                        if (c.moveToFirst()) {
171ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                            mService.userLog("Deleting " + serverId);
172ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                            ops.add(ContentProviderOperation.newDelete(
173ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                                    ContentUris.withAppendedId(Mailbox.CONTENT_URI,
174ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                                            c.getLong(0))).build());
175ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                        }
176ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                    } finally {
177ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                        c.close();
178ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                    }
179ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                    break;
180ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                default:
181ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                    skipTag();
182ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank            }
183ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank        }
184ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank    }
185ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank
186ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank    public void addParser(ArrayList<ContentProviderOperation> ops) throws IOException {
187ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank        String name = null;
188ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank        String serverId = null;
189ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank        String parentId = null;
190ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank        int type = 0;
191ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank
192ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank        while (nextTag(EasTags.FOLDER_ADD) != END) {
193ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank            switch (tag) {
194ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                case EasTags.FOLDER_DISPLAY_NAME: {
195ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                    name = getValue();
196ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                    break;
197ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                }
198ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                case EasTags.FOLDER_TYPE: {
199ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                    type = getValueInt();
200ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                    break;
201ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                }
202ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                case EasTags.FOLDER_PARENT_ID: {
203ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                    parentId = getValue();
204ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                    break;
205ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                }
206ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                case EasTags.FOLDER_SERVER_ID: {
207ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                    serverId = getValue();
208ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                    break;
209ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                }
210ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                default:
211ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                    skipTag();
212ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank            }
213ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank        }
214ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank        if (mValidFolderTypes.contains(type)) {
215ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank            Mailbox m = new Mailbox();
216ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank            m.mDisplayName = name;
217ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank            m.mServerId = serverId;
218ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank            m.mAccountKey = mAccountId;
2196396cfb310b09c53b8e9b51d9ba58d2f6b65c266Andrew Stadler            m.mType = Mailbox.TYPE_MAIL;
220ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank            m.mSyncFrequency = Account.CHECK_INTERVAL_NEVER;
221ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank            switch (type) {
222ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                case INBOX_TYPE:
223ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                    m.mSyncFrequency = Account.CHECK_INTERVAL_PUSH;
224ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                    m.mType = Mailbox.TYPE_INBOX;
225ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                    break;
226ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                case OUTBOX_TYPE:
227ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                    m.mSyncFrequency = Account.CHECK_INTERVAL_NEVER;
228ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                    // TYPE_OUTBOX mailboxes are known by SyncManager to sync whenever they aren't
229ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                    // empty.  The value of mSyncFrequency is ignored for this kind of mailbox.
230ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                    m.mType = Mailbox.TYPE_OUTBOX;
231ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                    break;
232ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                case SENT_TYPE:
233ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                    m.mType = Mailbox.TYPE_SENT;
234ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                    break;
235ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                case DRAFTS_TYPE:
236ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                    m.mType = Mailbox.TYPE_DRAFTS;
237ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                    break;
238ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                case DELETED_TYPE:
239ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                    m.mType = Mailbox.TYPE_TRASH;
240ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                    break;
241ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                case CALENDAR_TYPE:
242ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                    m.mType = Mailbox.TYPE_CALENDAR;
243ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                    // TODO This could be push, depending on settings
244ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                    // For now, no sync, since it's not yet implemented
245ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                    break;
246ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                case CONTACTS_TYPE:
247ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                    m.mType = Mailbox.TYPE_CONTACTS;
248ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                    // TODO Frequency below should depend on settings
249ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                    m.mSyncFrequency = Account.CHECK_INTERVAL_PUSH;
250ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                    break;
251ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank            }
252ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank
253ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank            // Make boxes like Contacts and Calendar invisible in the folder list
254ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank            m.mFlagVisible = (m.mType < Mailbox.TYPE_NOT_EMAIL);
255ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank
256ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank            if (!parentId.equals("0")) {
257ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                m.mParentServerId = parentId;
258ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank            }
259ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank
260ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank            Log.v(TAG, "Adding mailbox: " + m.mDisplayName);
261ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank            ops.add(ContentProviderOperation
262ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                    .newInsert(Mailbox.CONTENT_URI).withValues(m.toContentValues()).build());
263ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank        }
264ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank
265ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank        return;
266ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank    }
267ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank
268ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank    public void changesParser() throws IOException {
269ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank        // Keep track of new boxes, deleted boxes, updated boxes
270ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank        ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
271ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank
272ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank        while (nextTag(EasTags.FOLDER_CHANGES) != END) {
273ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank            // TODO Handle FOLDER_CHANGE and FOLDER_DELETE
274ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank            if (tag == EasTags.FOLDER_ADD) {
275ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                addParser(ops);
276ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank            } else if (tag == EasTags.FOLDER_DELETE) {
277ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                deleteParser(ops);
278ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank            } else if (tag == EasTags.FOLDER_COUNT) {
279ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                getValueInt();
280ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank            } else
281ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                skipTag();
282ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank        }
283ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank
284ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank        // The mock stream is used for junit tests, so that the parsing code can be tested
285ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank        // separately from the provider code.
286ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank        // TODO Change tests to not require this; remove references to the mock stream
287ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank        if (mMock != null) {
288ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank            mMock.setResult(null);
289ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank            return;
290ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank        }
291ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank
292ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank        // Create the new mailboxes in a single batch operation
293ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank        if (!ops.isEmpty()) {
294ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank            mService.userLog("Applying " + ops.size() + " mailbox operations.");
295ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank
296ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank            // Then, we create an update for the account (most importantly, updating the syncKey)
297ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank            ops.add(ContentProviderOperation.newUpdate(
298ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                    ContentUris.withAppendedId(Account.CONTENT_URI, mAccountId)).withValues(
299ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                    mAccount.toContentValues()).build());
300ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank
301ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank            // Finally, we execute the batch
302ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank            try {
303ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                mService.mContext.getContentResolver()
304ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                        .applyBatch(EmailProvider.EMAIL_AUTHORITY, ops);
30522bc4e0e4f4a5e43e4eea8d59e1961860c507594Marc Blank                mService.userLog("New Account SyncKey: " + mAccount.mSyncKey);
306ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank            } catch (RemoteException e) {
307ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                // There is nothing to be done here; fail by returning null
308ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank            } catch (OperationApplicationException e) {
309ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                // There is nothing to be done here; fail by returning null
310ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank            }
311ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank
312ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank            // Look for sync issues and its children and delete them
313ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank            // I'm not aware of any other way to deal with this properly
314ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank            mBindArguments[0] = "Sync Issues";
315ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank            mBindArguments[1] = mAccountIdAsString;
316ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank            Cursor c = mContentResolver.query(Mailbox.CONTENT_URI, MAILBOX_ID_COLUMNS_PROJECTION,
317ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                    WHERE_DISPLAY_NAME_AND_ACCOUNT, mBindArguments, null);
318ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank            String parentServerId = null;
319ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank            long id = 0;
320ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank            try {
321ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                if (c.moveToFirst()) {
322ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                    id = c.getLong(0);
323ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                    parentServerId = c.getString(1);
324ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                }
325ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank            } finally {
326ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                c.close();
327ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank            }
328ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank            if (parentServerId != null) {
329ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                mContentResolver.delete(ContentUris.withAppendedId(Mailbox.CONTENT_URI, id),
330ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                        null, null);
331ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                mBindArguments[0] = parentServerId;
332ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                mContentResolver.delete(Mailbox.CONTENT_URI, WHERE_PARENT_SERVER_ID_AND_ACCOUNT,
333ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                        mBindArguments);
334ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank            }
335ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank        }
336ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank    }
337ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank
338ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank}
339