cherrypick: Check for duplicated mailboxes and correct if found

Bug: 7232680
Change-Id: Id4d0328c7d8ff0c05442a429b43b92c846ce8f48
diff --git a/exchange2/src/com/android/exchange/ExchangeService.java b/exchange2/src/com/android/exchange/ExchangeService.java
index be2ad65..9fa8fee 100644
--- a/exchange2/src/com/android/exchange/ExchangeService.java
+++ b/exchange2/src/com/android/exchange/ExchangeService.java
@@ -52,6 +52,7 @@
 import com.android.emailcommon.TempDirectory;
 import com.android.emailcommon.provider.Account;
 import com.android.emailcommon.provider.EmailContent;
+import com.android.emailcommon.provider.EmailContent.AccountColumns;
 import com.android.emailcommon.provider.EmailContent.Attachment;
 import com.android.emailcommon.provider.EmailContent.Body;
 import com.android.emailcommon.provider.EmailContent.BodyColumns;
@@ -856,7 +857,8 @@
         }
 
         private void addAccountMailbox(long acctId) {
-            Account acct = Account.restoreAccountWithId(getContext(), acctId);
+            Context context = getContext();
+            Account acct = Account.restoreAccountWithId(context, acctId);
             Mailbox main = new Mailbox();
             main.mDisplayName = Eas.ACCOUNT_MAILBOX_PREFIX;
             main.mServerId = Eas.ACCOUNT_MAILBOX_PREFIX + System.nanoTime();
@@ -864,10 +866,13 @@
             main.mType = Mailbox.TYPE_EAS_ACCOUNT_MAILBOX;
             main.mSyncInterval = Mailbox.CHECK_INTERVAL_PUSH;
             main.mFlagVisible = false;
-            main.save(getContext());
+            main.save(context);
+            // Set sync key to "0" for the account
+            ContentValues cv = new ContentValues();
+            cv.put(AccountColumns.SYNC_KEY, "0");
+            acct.update(context, cv);
             log("Initializing account: " + acct.mDisplayName);
         }
-
     }
 
     /**
diff --git a/exchange2/src/com/android/exchange/adapter/FolderSyncParser.java b/exchange2/src/com/android/exchange/adapter/FolderSyncParser.java
index 2c213a4..59e4245 100644
--- a/exchange2/src/com/android/exchange/adapter/FolderSyncParser.java
+++ b/exchange2/src/com/android/exchange/adapter/FolderSyncParser.java
@@ -24,7 +24,9 @@
 import android.database.Cursor;
 import android.os.RemoteException;
 import android.text.TextUtils;
+import android.util.Log;
 
+import com.android.emailcommon.Logging;
 import com.android.emailcommon.provider.Account;
 import com.android.emailcommon.provider.EmailContent;
 import com.android.emailcommon.provider.EmailContent.AccountColumns;
@@ -150,6 +152,20 @@
         while (nextTag(START_DOCUMENT) != END_DOCUMENT) {
             if (tag == Tags.FOLDER_STATUS) {
                 status = getValueInt();
+                // Do a sanity check on the account here; if we have any duplicated folders, we'll
+                // act as though we have a bad folder sync key (wipe/reload mailboxes)
+                // Note: The ContentValues isn't used, but no point creating a new one
+                int dupes =  mContentResolver.update(
+                        ContentUris.withAppendedId(EmailContent.ACCOUNT_CHECK_URI, mAccountId),
+                        UNINITIALIZED_PARENT_KEY, null, null);
+                if (dupes > 0) {
+                    String e = "Duplicate mailboxes found for account " + mAccountId + ": " + dupes;
+                    // For verbose logging, make sure this is in emaillog.txt
+                    userLog(e);
+                    // Worthy of logging, regardless
+                    Log.w(Logging.LOG_TAG, e);
+                    status = Eas.FOLDER_STATUS_INVALID_KEY;
+                }
                 if (status != Eas.FOLDER_STATUS_OK) {
                     mService.errorLog("FolderSync failed: " + CommandStatus.toString(status));
                     // If the account hasn't been saved, this is a validation attempt, so we don't
@@ -163,23 +179,26 @@
                     } else if (status == Eas.FOLDER_STATUS_INVALID_KEY ||
                             CommandStatus.isBadSyncKey(status)) {
                         mService.errorLog("Bad sync key; RESET and delete all folders");
-                        // Reset the sync key and save
-                        mAccount.mSyncKey = "0";
-                        ContentValues cv = new ContentValues();
-                        cv.put(AccountColumns.SYNC_KEY, mAccount.mSyncKey);
-                        mContentResolver.update(ContentUris.withAppendedId(Account.CONTENT_URI,
-                                mAccount.mId), cv, null, null);
                         // Delete PIM data
                         ExchangeService.deleteAccountPIMData(mAccountId);
                         // Save away any mailbox sync information that is NOT default
                         saveMailboxSyncOptions();
                         // And only then, delete mailboxes
-                        mContentResolver.delete(Mailbox.CONTENT_URI, ALL_BUT_ACCOUNT_MAILBOX,
+                        mContentResolver.delete(Mailbox.CONTENT_URI,
+                                MailboxColumns.ACCOUNT_KEY + "=?",
                                 new String[] {Long.toString(mAccountId)});
                         // Stop existing syncs and reconstruct _main
                         ExchangeService.stopNonAccountMailboxSyncsForAccount(mAccountId);
                         res = true;
                         resetFolders = true;
+                        // Reset the sync key and save (this should trigger the AccountObserver
+                        // in ExchangeService, which will recreate the account mailbox, which
+                        // will then start syncing folders, etc.)
+                        mAccount.mSyncKey = "0";
+                        ContentValues cv = new ContentValues();
+                        cv.put(AccountColumns.SYNC_KEY, mAccount.mSyncKey);
+                        mContentResolver.update(ContentUris.withAppendedId(Account.CONTENT_URI,
+                                mAccount.mId), cv, null, null);
                     } else {
                         // Other errors are at the server, so let's throw an error that will
                         // cause this sync to be retried at a later time