1d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank/*
2d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank * Copyright (C) 2008-2009 Marc Blank
3d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank * Licensed to The Android Open Source Project.
4d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank *
5d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank * Licensed under the Apache License, Version 2.0 (the "License");
6d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank * you may not use this file except in compliance with the License.
7d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank * You may obtain a copy of the License at
8d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank *
9d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank *      http://www.apache.org/licenses/LICENSE-2.0
10d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank *
11d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank * Unless required by applicable law or agreed to in writing, software
12d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank * distributed under the License is distributed on an "AS IS" BASIS,
13d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank * See the License for the specific language governing permissions and
15d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank * limitations under the License.
16d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank */
17d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank
18d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blankpackage com.android.exchange.adapter;
19d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank
20d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blankimport android.content.ContentResolver;
21d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blankimport android.content.ContentValues;
22d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blankimport android.content.Context;
23d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank
24d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blankimport com.android.emailcommon.provider.Account;
25d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blankimport com.android.emailcommon.provider.EmailContent.MailboxColumns;
26d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blankimport com.android.emailcommon.provider.Mailbox;
27d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blankimport com.android.exchange.CommandStatusException;
28d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blankimport com.android.exchange.CommandStatusException.CommandStatus;
29d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blankimport com.android.exchange.EasSyncService;
30d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blankimport com.android.exchange.ExchangeService;
31d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank
32d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blankimport java.io.IOException;
33d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blankimport java.io.InputStream;
34d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank
35d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank/**
36d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank * Base class for the Email and PIM sync parsers
37d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank * Handles the basic flow of syncKeys, looping to get more data, handling errors, etc.
38d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank * Each subclass must implement a handful of methods that relate specifically to the data type
39d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank *
40d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank */
41d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blankpublic abstract class AbstractSyncParser extends Parser {
42d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank
43d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank    protected EasSyncService mService;
44d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank    protected Mailbox mMailbox;
45d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank    protected Account mAccount;
46d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank    protected Context mContext;
47d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank    protected ContentResolver mContentResolver;
48d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank    protected AbstractSyncAdapter mAdapter;
49d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank
50d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank    private boolean mLooping;
51d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank
52d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank    public AbstractSyncParser(InputStream in, AbstractSyncAdapter adapter) throws IOException {
53d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        super(in);
54d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        init(adapter);
55d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank    }
56d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank
57d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank    public AbstractSyncParser(Parser p, AbstractSyncAdapter adapter) throws IOException {
58d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        super(p);
59d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        init(adapter);
60d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank    }
61d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank
62d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank    private void init(AbstractSyncAdapter adapter) {
63d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        mAdapter = adapter;
64d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        mService = adapter.mService;
65d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        mContext = mService.mContext;
66d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        mContentResolver = mContext.getContentResolver();
67d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        mMailbox = mService.mMailbox;
68d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        mAccount = mService.mAccount;
69d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank    }
70d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank
71d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank    /**
72d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank     * Read, parse, and act on incoming commands from the Exchange server
73d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank     * @throws IOException if the connection is broken
74d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank     * @throws CommandStatusException
75d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank     */
76d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank    public abstract void commandsParser() throws IOException, CommandStatusException;
77d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank
78d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank    /**
79d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank     * Read, parse, and act on server responses
80d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank     * @throws IOException
81d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank     */
82d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank    public abstract void responsesParser() throws IOException;
83d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank
84d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank    /**
85d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank     * Commit any changes found during parsing
86d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank     * @throws IOException
87d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank     */
88d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank    public abstract void commit() throws IOException;
89d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank
90d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank    public boolean isLooping() {
91d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        return mLooping;
92d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank    }
93d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank
94d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank    /**
95d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank     * Skip through tags until we reach the specified end tag
96d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank     * @param endTag the tag we end with
97d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank     * @throws IOException
98d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank     */
99d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank    public void skipParser(int endTag) throws IOException {
100d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        while (nextTag(endTag) != END) {
101d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank            skipTag();
102d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        }
103d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank    }
104d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank
105d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank    /**
106d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank     * Loop through the top-level structure coming from the Exchange server
107d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank     * Sync keys and the more available flag are handled here, whereas specific data parsing
108d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank     * is handled by abstract methods implemented for each data class (e.g. Email, Contacts, etc.)
109d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank     * @throws CommandStatusException
110d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank     */
111d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank    @Override
112d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank    public boolean parse() throws IOException, CommandStatusException {
113d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        int status;
114d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        boolean moreAvailable = false;
115d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        boolean newSyncKey = false;
116d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        int interval = mMailbox.mSyncInterval;
117d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        mLooping = false;
118d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        // If we're not at the top of the xml tree, throw an exception
119d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        if (nextTag(START_DOCUMENT) != Tags.SYNC_SYNC) {
120d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank            throw new EasParserException();
121d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        }
122d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank
123d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        boolean mailboxUpdated = false;
124d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        ContentValues cv = new ContentValues();
125d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank
126d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        // Loop here through the remaining xml
127d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        while (nextTag(START_DOCUMENT) != END_DOCUMENT) {
128d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank            if (tag == Tags.SYNC_COLLECTION || tag == Tags.SYNC_COLLECTIONS) {
129d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank                // Ignore these tags, since we've only got one collection syncing in this loop
130d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank            } else if (tag == Tags.SYNC_STATUS) {
131d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank                // Status = 1 is success; everything else is a failure
132d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank                status = getValueInt();
133d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank                if (status != 1) {
134d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank                    mService.errorLog("Sync failed: " + CommandStatus.toString(status));
135d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank                    if (status == 3 || CommandStatus.isBadSyncKey(status)) {
136d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank                        // Must delete all of the data and start over with syncKey of "0"
137d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank                        mAdapter.setSyncKey("0", false);
138d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank                        // Make this a push box through the first sync
139d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank                        // TODO Make frequency conditional on user settings!
140d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank                        mMailbox.mSyncInterval = Mailbox.CHECK_INTERVAL_PUSH;
141d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank                        mService.errorLog("Bad sync key; RESET and delete data");
142d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank                        mAdapter.wipe();
143d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank                        // Indicate there's more so that we'll start syncing again
144d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank                        moreAvailable = true;
145d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank                    } else if (status == 16 || status == 5) {
146d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank                        // Status 16 indicates a transient server error (indeterminate state)
147d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank                        // Status 5 indicates "server error"; this tends to loop for a while so
148d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank                        // throwing IOException will at least provide backoff behavior
149d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank                        throw new IOException();
150d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank                    } else if (status == 8 || status == 12) {
151d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank                        // Status 8 is Bad; it means the server doesn't recognize the serverId it
152d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank                        // sent us.  12 means that we're being asked to refresh the folder list.
153d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank                        // We'll do that with 8 also...
154d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank                        ExchangeService.reloadFolderList(mContext, mAccount.mId, true);
155d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank                        // We don't have any provision for telling the user "wait a minute while
156d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank                        // we sync folders"...
157d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank                        throw new IOException();
158d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank                    } else if (status == 7) {
159d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank                        mService.mUpsyncFailed = true;
160d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank                        moreAvailable = true;
161d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank                    } else {
162d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank                        // Access, provisioning, transient, etc.
163d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank                        throw new CommandStatusException(status);
164d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank                    }
165d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank                }
166d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank            } else if (tag == Tags.SYNC_COMMANDS) {
167d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank                commandsParser();
168d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank            } else if (tag == Tags.SYNC_RESPONSES) {
169d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank                responsesParser();
170d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank            } else if (tag == Tags.SYNC_MORE_AVAILABLE) {
171d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank                moreAvailable = true;
172d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank            } else if (tag == Tags.SYNC_SYNC_KEY) {
173d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank                if (mAdapter.getSyncKey().equals("0")) {
174d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank                    moreAvailable = true;
175d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank                }
176d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank                String newKey = getValue();
177d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank                userLog("Parsed key for ", mMailbox.mDisplayName, ": ", newKey);
178d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank                if (!newKey.equals(mMailbox.mSyncKey)) {
179d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank                    mAdapter.setSyncKey(newKey, true);
180d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank                    cv.put(MailboxColumns.SYNC_KEY, newKey);
181d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank                    mailboxUpdated = true;
182d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank                    newSyncKey = true;
183d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank                }
184d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank                // If we were pushing (i.e. auto-start), now we'll become ping-triggered
185d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank                if (mMailbox.mSyncInterval == Mailbox.CHECK_INTERVAL_PUSH) {
186d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank                    mMailbox.mSyncInterval = Mailbox.CHECK_INTERVAL_PING;
187d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank                }
188d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank           } else {
189d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank                skipTag();
190d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank           }
191d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        }
192d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank
193d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        // If we don't have a new sync key, ignore moreAvailable (or we'll loop)
194d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        if (moreAvailable && !newSyncKey) {
195d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank            mLooping = true;
196d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        }
197d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank
198d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        // Commit any changes
199d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        commit();
200d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank
201d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        boolean abortSyncs = false;
202d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank
203d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        // If the sync interval has changed, we need to save it
204d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        if (mMailbox.mSyncInterval != interval) {
205d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank            cv.put(MailboxColumns.SYNC_INTERVAL, mMailbox.mSyncInterval);
206d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank            mailboxUpdated = true;
207d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        // If there are changes, and we were bounced from push/ping, try again
208d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        } else if (mService.mChangeCount > 0 &&
209d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank                mAccount.mSyncInterval == Account.CHECK_INTERVAL_PUSH &&
210d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank                mMailbox.mSyncInterval > 0) {
211d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank            userLog("Changes found to ping loop mailbox ", mMailbox.mDisplayName, ": will ping.");
212d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank            cv.put(MailboxColumns.SYNC_INTERVAL, Mailbox.CHECK_INTERVAL_PING);
213d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank            mailboxUpdated = true;
214d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank            abortSyncs = true;
215d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        }
216d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank
217d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        if (mailboxUpdated) {
218d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank             synchronized (mService.getSynchronizer()) {
219d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank                if (!mService.isStopped()) {
220d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank                     mMailbox.update(mContext, cv);
221d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank                }
222d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank            }
223d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        }
224d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank
225d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        if (abortSyncs) {
226d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank            userLog("Aborting account syncs due to mailbox change to ping...");
227d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank            ExchangeService.stopAccountSyncs(mAccount.mId);
228d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        }
229d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank
230d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        // Let the caller know that there's more to do
231d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        if (moreAvailable) {
232d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank            userLog("MoreAvailable");
233d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        }
234d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        return moreAvailable;
235d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank    }
236d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank
237d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank    void userLog(String ...strings) {
238d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        mService.userLog(strings);
239d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank    }
240d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank
241d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank    void userLog(String string, int num, String string2) {
242d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        mService.userLog(string, num, string2);
243d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank    }
244d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank}
245