1f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler/*
2f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler * Copyright (C) 2009 The Android Open Source Project
3f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler *
4f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler * Licensed under the Apache License, Version 2.0 (the "License");
5f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler * you may not use this file except in compliance with the License.
6f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler * You may obtain a copy of the License at
7f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler *
8f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler *      http://www.apache.org/licenses/LICENSE-2.0
9f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler *
10f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler * Unless required by applicable law or agreed to in writing, software
11f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler * distributed under the License is distributed on an "AS IS" BASIS,
12f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler * See the License for the specific language governing permissions and
14f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler * limitations under the License.
15f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler */
16f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler
17f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadlerpackage com.android.email.provider;
18f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler
19f33986d5cc248d2eeed0707143d81e94866f8e3aMihai Predaimport com.android.email.Email;
20a290f503f14432163f74548a5e5d1dc5003ad049Marc Blankimport com.android.email.provider.EmailContent.Account;
21a290f503f14432163f74548a5e5d1dc5003ad049Marc Blankimport com.android.email.provider.EmailContent.AccountColumns;
22a290f503f14432163f74548a5e5d1dc5003ad049Marc Blankimport com.android.email.provider.EmailContent.Attachment;
23a290f503f14432163f74548a5e5d1dc5003ad049Marc Blankimport com.android.email.provider.EmailContent.AttachmentColumns;
24a290f503f14432163f74548a5e5d1dc5003ad049Marc Blankimport com.android.email.provider.EmailContent.Body;
25a290f503f14432163f74548a5e5d1dc5003ad049Marc Blankimport com.android.email.provider.EmailContent.BodyColumns;
26a290f503f14432163f74548a5e5d1dc5003ad049Marc Blankimport com.android.email.provider.EmailContent.HostAuth;
27a290f503f14432163f74548a5e5d1dc5003ad049Marc Blankimport com.android.email.provider.EmailContent.HostAuthColumns;
28a290f503f14432163f74548a5e5d1dc5003ad049Marc Blankimport com.android.email.provider.EmailContent.Mailbox;
29a290f503f14432163f74548a5e5d1dc5003ad049Marc Blankimport com.android.email.provider.EmailContent.MailboxColumns;
30a290f503f14432163f74548a5e5d1dc5003ad049Marc Blankimport com.android.email.provider.EmailContent.Message;
31a290f503f14432163f74548a5e5d1dc5003ad049Marc Blankimport com.android.email.provider.EmailContent.MessageColumns;
32a290f503f14432163f74548a5e5d1dc5003ad049Marc Blankimport com.android.email.provider.EmailContent.SyncColumns;
33f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler
34e7e1ca432e1aace5b7f11a3f1684a4abc503e6b2Marc Blankimport android.accounts.AccountManager;
35f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadlerimport android.content.ContentProvider;
36fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blankimport android.content.ContentProviderOperation;
37fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blankimport android.content.ContentProviderResult;
38f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadlerimport android.content.ContentUris;
39f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadlerimport android.content.ContentValues;
40f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadlerimport android.content.Context;
41fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blankimport android.content.OperationApplicationException;
42f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadlerimport android.content.UriMatcher;
43f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadlerimport android.database.Cursor;
44a290f503f14432163f74548a5e5d1dc5003ad049Marc Blankimport android.database.SQLException;
45f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadlerimport android.database.sqlite.SQLiteDatabase;
460e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blankimport android.database.sqlite.SQLiteException;
47f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadlerimport android.database.sqlite.SQLiteOpenHelper;
48f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadlerimport android.net.Uri;
49f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadlerimport android.util.Log;
50f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler
510e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blankimport java.io.File;
5284969fb580f569c0e3625a3c59a71d2909ae198dFred Quintanaimport java.util.ArrayList;
5384969fb580f569c0e3625a3c59a71d2909ae198dFred Quintana
54f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadlerpublic class EmailProvider extends ContentProvider {
55f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler
56f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler    private static final String TAG = "EmailProvider";
57f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler
580e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank    protected static final String DATABASE_NAME = "EmailProvider.db";
590e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank    protected static final String BODY_DATABASE_NAME = "EmailProviderBody.db";
600e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank
610e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank    public static final Uri INTEGRITY_CHECK_URI =
620e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank        Uri.parse("content://" + EmailContent.AUTHORITY + "/integrityCheck");
63ef83299b99288c00b9d661260d19715e73e6889cMarc Blank
64ef83299b99288c00b9d661260d19715e73e6889cMarc Blank    // Definitions for our queries looking for orphaned messages
65ef83299b99288c00b9d661260d19715e73e6889cMarc Blank    private static final String[] ORPHANS_PROJECTION
66ef83299b99288c00b9d661260d19715e73e6889cMarc Blank        = new String[] {MessageColumns.ID, MessageColumns.MAILBOX_KEY};
67ef83299b99288c00b9d661260d19715e73e6889cMarc Blank    private static final int ORPHANS_ID = 0;
68ef83299b99288c00b9d661260d19715e73e6889cMarc Blank    private static final int ORPHANS_MAILBOX_KEY = 1;
69ef83299b99288c00b9d661260d19715e73e6889cMarc Blank
70ef83299b99288c00b9d661260d19715e73e6889cMarc Blank    private static final String WHERE_ID = EmailContent.RECORD_ID + "=?";
71f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank
724a8c70c09be3914ded18031b4cca5a6d867de0d3Andrew Stadler    // Any changes to the database format *must* include update-in-place code.
73e25698319325d5e9619bc45ae85d861b0f1c5954Marc Blank    // Original version: 3
74e7e1ca432e1aace5b7f11a3f1684a4abc503e6b2Marc Blank    // Version 4: Database wipe required; changing AccountManager interface w/Exchange
750d00889f83fc8c1d69039a2c849b630fb4dd28ddAndrew Stadler    // Version 5: Database wipe required; changing AccountManager interface w/Exchange
760d00889f83fc8c1d69039a2c849b630fb4dd28ddAndrew Stadler    // Version 6: Adding Message.mServerTimeStamp column
77ef83299b99288c00b9d661260d19715e73e6889cMarc Blank    // Version 7: Replace the mailbox_delete trigger with a version that removes orphaned messages
78ef83299b99288c00b9d661260d19715e73e6889cMarc Blank    //            from the Message_Deletes and Message_Updates tables
79fc8d943a828cd79ff71c703ced37001bd5482173Andrew Stadler    // Version 8: Add security flags column to accounts table
80345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler    // Version 9: Add security sync key and signature to accounts table
814006e5fc224d097450fd66a321901b6636f7d9c4Marc Blank    // Version 10: Add meeting info to message table
823aaba9eb87db34ea0861d70d5c08f84d7ca97ab0Andrew Stadler    // Version 11: Add content and flags to attachment table
8320225d57609d6a5e482c088fdad60c29212d31a0Makoto Onuki    // Version 12: Add content_bytes to attachment table. content is deprecated.
8420225d57609d6a5e482c088fdad60c29212d31a0Makoto Onuki    public static final int DATABASE_VERSION = 12;
85e25698319325d5e9619bc45ae85d861b0f1c5954Marc Blank
86e25698319325d5e9619bc45ae85d861b0f1c5954Marc Blank    // Any changes to the database format *must* include update-in-place code.
87e25698319325d5e9619bc45ae85d861b0f1c5954Marc Blank    // Original version: 2
88e25698319325d5e9619bc45ae85d861b0f1c5954Marc Blank    // Version 3: Add "sourceKey" column
89e7e1ca432e1aace5b7f11a3f1684a4abc503e6b2Marc Blank    // Version 4: Database wipe required; changing AccountManager interface w/Exchange
900d00889f83fc8c1d69039a2c849b630fb4dd28ddAndrew Stadler    // Version 5: Database wipe required; changing AccountManager interface w/Exchange
915fc57eccefeba517fe5e6f093786f37c6c4d50e6Marc Blank    // Version 6: Adding Body.mIntroText column
925fc57eccefeba517fe5e6f093786f37c6c4d50e6Marc Blank    public static final int BODY_DATABASE_VERSION = 6;
93f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler
94a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank    public static final String EMAIL_AUTHORITY = "com.android.email.provider";
95f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler
96f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler    private static final int ACCOUNT_BASE = 0;
97f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler    private static final int ACCOUNT = ACCOUNT_BASE;
98f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler    private static final int ACCOUNT_MAILBOXES = ACCOUNT_BASE + 1;
99f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler    private static final int ACCOUNT_ID = ACCOUNT_BASE + 2;
100c0c9c33322deecace00a32766e0a1b355aad4b31Marc Blank    private static final int ACCOUNT_ID_ADD_TO_FIELD = ACCOUNT_BASE + 3;
101f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank
102f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler    private static final int MAILBOX_BASE = 0x1000;
103f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler    private static final int MAILBOX = MAILBOX_BASE;
104f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler    private static final int MAILBOX_MESSAGES = MAILBOX_BASE + 1;
105f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler    private static final int MAILBOX_ID = MAILBOX_BASE + 2;
106c0c9c33322deecace00a32766e0a1b355aad4b31Marc Blank    private static final int MAILBOX_ID_ADD_TO_FIELD = MAILBOX_BASE + 3;
107f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank
108f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler    private static final int MESSAGE_BASE = 0x2000;
109f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler    private static final int MESSAGE = MESSAGE_BASE;
1104119218e2fd64341ac946fb8f2cbdb796a444cb8Andrew Stadler    private static final int MESSAGE_ID = MESSAGE_BASE + 1;
1114119218e2fd64341ac946fb8f2cbdb796a444cb8Andrew Stadler    private static final int SYNCED_MESSAGE_ID = MESSAGE_BASE + 2;
112f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank
113f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler    private static final int ATTACHMENT_BASE = 0x3000;
114f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler    private static final int ATTACHMENT = ATTACHMENT_BASE;
115f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler    private static final int ATTACHMENT_CONTENT = ATTACHMENT_BASE + 1;
116f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler    private static final int ATTACHMENT_ID = ATTACHMENT_BASE + 2;
1174119218e2fd64341ac946fb8f2cbdb796a444cb8Andrew Stadler    private static final int ATTACHMENTS_MESSAGE_ID = ATTACHMENT_BASE + 3;
118f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank
119f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler    private static final int HOSTAUTH_BASE = 0x4000;
120f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler    private static final int HOSTAUTH = HOSTAUTH_BASE;
121f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler    private static final int HOSTAUTH_ID = HOSTAUTH_BASE + 1;
122f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank
123e34525d0f026a7467cee1cb5fddcf25ba6f35207Marc Blank    private static final int UPDATED_MESSAGE_BASE = 0x5000;
124e34525d0f026a7467cee1cb5fddcf25ba6f35207Marc Blank    private static final int UPDATED_MESSAGE = UPDATED_MESSAGE_BASE;
125f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank    private static final int UPDATED_MESSAGE_ID = UPDATED_MESSAGE_BASE + 1;
126f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank
127f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank    private static final int DELETED_MESSAGE_BASE = 0x6000;
128f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank    private static final int DELETED_MESSAGE = DELETED_MESSAGE_BASE;
129f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank    private static final int DELETED_MESSAGE_ID = DELETED_MESSAGE_BASE + 1;
130f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank    private static final int DELETED_MESSAGE_MAILBOX = DELETED_MESSAGE_BASE + 2;
131f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank
132f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank    // MUST ALWAYS EQUAL THE LAST OF THE PREVIOUS BASE CONSTANTS
133f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank    private static final int LAST_EMAIL_PROVIDER_DB_BASE = DELETED_MESSAGE_BASE;
134f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank
135f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank    // DO NOT CHANGE BODY_BASE!!
136f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank    private static final int BODY_BASE = LAST_EMAIL_PROVIDER_DB_BASE + 0x1000;
137f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler    private static final int BODY = BODY_BASE;
138f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler    private static final int BODY_ID = BODY_BASE + 1;
13933e176f4919569a9444d641e94034785c10c5562Marc Blank    private static final int BODY_MESSAGE_ID = BODY_BASE + 2;
14033e176f4919569a9444d641e94034785c10c5562Marc Blank    private static final int BODY_HTML = BODY_BASE + 3;
141f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler    private static final int BODY_TEXT = BODY_BASE + 4;
142f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank
143f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank
144f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler    private static final int BASE_SHIFT = 12;  // 12 bits to the base type: 0, 0x1000, 0x2000, etc.
145f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank
146f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler    private static final String[] TABLE_NAMES = {
147a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank        EmailContent.Account.TABLE_NAME,
148a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank        EmailContent.Mailbox.TABLE_NAME,
149a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank        EmailContent.Message.TABLE_NAME,
150a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank        EmailContent.Attachment.TABLE_NAME,
151a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank        EmailContent.HostAuth.TABLE_NAME,
152f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank        EmailContent.Message.UPDATED_TABLE_NAME,
153f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank        EmailContent.Message.DELETED_TABLE_NAME,
154a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank        EmailContent.Body.TABLE_NAME
155f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler    };
156f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank
157f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler    private static final UriMatcher sURIMatcher = new UriMatcher(UriMatcher.NO_MATCH);
158f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler
159f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank    /**
160f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank     * Let's only generate these SQL strings once, as they are used frequently
161f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank     * Note that this isn't relevant for table creation strings, since they are used only once
162f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank     */
163f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank    private static final String UPDATED_MESSAGE_INSERT = "insert or ignore into " +
164f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank        Message.UPDATED_TABLE_NAME + " select * from " + Message.TABLE_NAME + " where " +
165f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank        EmailContent.RECORD_ID + '=';
166f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank
167f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank    private static final String UPDATED_MESSAGE_DELETE = "delete from " +
168f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank        Message.UPDATED_TABLE_NAME + " where " + EmailContent.RECORD_ID + '=';
169f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank
170f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank    private static final String DELETED_MESSAGE_INSERT = "insert or replace into " +
171f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank        Message.DELETED_TABLE_NAME + " select * from " + Message.TABLE_NAME + " where " +
172f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank        EmailContent.RECORD_ID + '=';
173f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank
174f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank    private static final String DELETE_ORPHAN_BODIES = "delete from " + Body.TABLE_NAME +
175fb7974f5bfb6275fb856b0f7ff386ef10680c83aMihai Preda        " where " + BodyColumns.MESSAGE_KEY + " in " + "(select " + BodyColumns.MESSAGE_KEY +
176f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank        " from " + Body.TABLE_NAME + " except select " + EmailContent.RECORD_ID + " from " +
177f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank        Message.TABLE_NAME + ')';
178f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank
179f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank    private static final String DELETE_BODY = "delete from " + Body.TABLE_NAME +
180fb7974f5bfb6275fb856b0f7ff386ef10680c83aMihai Preda        " where " + BodyColumns.MESSAGE_KEY + '=';
181f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank
182c0c9c33322deecace00a32766e0a1b355aad4b31Marc Blank    private static final String ID_EQUALS = EmailContent.RECORD_ID + "=?";
183c0c9c33322deecace00a32766e0a1b355aad4b31Marc Blank
184ef83299b99288c00b9d661260d19715e73e6889cMarc Blank    private static final String TRIGGER_MAILBOX_DELETE =
185ef83299b99288c00b9d661260d19715e73e6889cMarc Blank        "create trigger mailbox_delete before delete on " + Mailbox.TABLE_NAME +
186ef83299b99288c00b9d661260d19715e73e6889cMarc Blank        " begin" +
187ef83299b99288c00b9d661260d19715e73e6889cMarc Blank        " delete from " + Message.TABLE_NAME +
188ef83299b99288c00b9d661260d19715e73e6889cMarc Blank        "  where " + MessageColumns.MAILBOX_KEY + "=old." + EmailContent.RECORD_ID +
189ef83299b99288c00b9d661260d19715e73e6889cMarc Blank        "; delete from " + Message.UPDATED_TABLE_NAME +
190ef83299b99288c00b9d661260d19715e73e6889cMarc Blank        "  where " + MessageColumns.MAILBOX_KEY + "=old." + EmailContent.RECORD_ID +
191ef83299b99288c00b9d661260d19715e73e6889cMarc Blank        "; delete from " + Message.DELETED_TABLE_NAME +
192ef83299b99288c00b9d661260d19715e73e6889cMarc Blank        "  where " + MessageColumns.MAILBOX_KEY + "=old." + EmailContent.RECORD_ID +
193ef83299b99288c00b9d661260d19715e73e6889cMarc Blank        "; end";
194367963639d4291511b7e175a208e2b553aac26c2Marc Blank
195f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler    static {
196f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler        // Email URI matching table
197f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler        UriMatcher matcher = sURIMatcher;
198f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank
199f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler        // All accounts
200f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank        matcher.addURI(EMAIL_AUTHORITY, "account", ACCOUNT);
201f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler        // A specific account
202758a532fce2f672673d38b2daa5f67eb757b118bMarc Blank        // insert into this URI causes a mailbox to be added to the account
203f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank        matcher.addURI(EMAIL_AUTHORITY, "account/#", ACCOUNT_ID);
204f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler        // The mailboxes in a specific account
205f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler        matcher.addURI(EMAIL_AUTHORITY, "account/#/mailbox", ACCOUNT_MAILBOXES);
206f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank
207f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler        // All mailboxes
208f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank        matcher.addURI(EMAIL_AUTHORITY, "mailbox", MAILBOX);
209f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler        // A specific mailbox
210f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler        // insert into this URI causes a message to be added to the mailbox
211f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler        // ** NOTE For now, the accountKey must be set manually in the values!
212f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank        matcher.addURI(EMAIL_AUTHORITY, "mailbox/#", MAILBOX_ID);
213f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler        // The messages in a specific mailbox
214f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler        matcher.addURI(EMAIL_AUTHORITY, "mailbox/#/message", MAILBOX_MESSAGES);
215f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank
216f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler        // All messages
217f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank        matcher.addURI(EMAIL_AUTHORITY, "message", MESSAGE);
218f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler        // A specific message
219758a532fce2f672673d38b2daa5f67eb757b118bMarc Blank        // insert into this URI causes an attachment to be added to the message
220f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank        matcher.addURI(EMAIL_AUTHORITY, "message/#", MESSAGE_ID);
221f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank
222f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler        // A specific attachment
223f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank        matcher.addURI(EMAIL_AUTHORITY, "attachment", ATTACHMENT);
224f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler        // A specific attachment (the header information)
225f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank        matcher.addURI(EMAIL_AUTHORITY, "attachment/#", ATTACHMENT_ID);
226f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler        // The content for a specific attachment
227f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank        // NOT IMPLEMENTED
228f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler        matcher.addURI(EMAIL_AUTHORITY, "attachment/content/*", ATTACHMENT_CONTENT);
2294119218e2fd64341ac946fb8f2cbdb796a444cb8Andrew Stadler        // The attachments of a specific message (query only) (insert & delete TBD)
2304119218e2fd64341ac946fb8f2cbdb796a444cb8Andrew Stadler        matcher.addURI(EMAIL_AUTHORITY, "attachment/message/#", ATTACHMENTS_MESSAGE_ID);
231f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler
232f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler        // All mail bodies
233f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler        matcher.addURI(EMAIL_AUTHORITY, "body", BODY);
234f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler        // A specific mail body
235f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler        matcher.addURI(EMAIL_AUTHORITY, "body/#", BODY_ID);
23633e176f4919569a9444d641e94034785c10c5562Marc Blank        // The body for a specific message
23733e176f4919569a9444d641e94034785c10c5562Marc Blank        matcher.addURI(EMAIL_AUTHORITY, "body/message/#", BODY_MESSAGE_ID);
238f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler        // The HTML part of a specific mail body
239f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler        matcher.addURI(EMAIL_AUTHORITY, "body/#/html", BODY_HTML);
240f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler        // The plain text part of a specific mail body
241f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler        matcher.addURI(EMAIL_AUTHORITY, "body/#/text", BODY_TEXT);
242f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank
2434119218e2fd64341ac946fb8f2cbdb796a444cb8Andrew Stadler        // All hostauth records
2444119218e2fd64341ac946fb8f2cbdb796a444cb8Andrew Stadler        matcher.addURI(EMAIL_AUTHORITY, "hostauth", HOSTAUTH);
2454119218e2fd64341ac946fb8f2cbdb796a444cb8Andrew Stadler        // A specific hostauth
2464119218e2fd64341ac946fb8f2cbdb796a444cb8Andrew Stadler        matcher.addURI(EMAIL_AUTHORITY, "hostauth/#", HOSTAUTH_ID);
247f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank
248c0c9c33322deecace00a32766e0a1b355aad4b31Marc Blank        // Atomically a constant value to a particular field of a mailbox/account
249c0c9c33322deecace00a32766e0a1b355aad4b31Marc Blank        matcher.addURI(EMAIL_AUTHORITY, "mailboxIdAddToField/#", MAILBOX_ID_ADD_TO_FIELD);
250c0c9c33322deecace00a32766e0a1b355aad4b31Marc Blank        matcher.addURI(EMAIL_AUTHORITY, "accountIdAddToField/#", ACCOUNT_ID_ADD_TO_FIELD);
251c0c9c33322deecace00a32766e0a1b355aad4b31Marc Blank
252f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank        /**
253f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank         * THIS URI HAS SPECIAL SEMANTICS
254c0c9c33322deecace00a32766e0a1b355aad4b31Marc Blank         * ITS USE IS INTENDED FOR THE UI APPLICATION TO MARK CHANGES THAT NEED TO BE SYNCED BACK
255f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank         * TO A SERVER VIA A SYNC ADAPTER
256f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank         */
257f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank        matcher.addURI(EMAIL_AUTHORITY, "syncedMessage/#", SYNCED_MESSAGE_ID);
258f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank
259f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank        /**
260f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank         * THE URIs BELOW THIS POINT ARE INTENDED TO BE USED BY SYNC ADAPTERS ONLY
261f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank         * THEY REFER TO DATA CREATED AND MAINTAINED BY CALLS TO THE SYNCED_MESSAGE_ID URI
262f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank         * BY THE UI APPLICATION
263f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank         */
264f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank        // All deleted messages
265f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank        matcher.addURI(EMAIL_AUTHORITY, "deletedMessage", DELETED_MESSAGE);
266f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank        // A specific deleted message
267f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank        matcher.addURI(EMAIL_AUTHORITY, "deletedMessage/#", DELETED_MESSAGE_ID);
268f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank        // All deleted messages from a specific mailbox
269f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank        // NOT IMPLEMENTED; do we need this as a convenience?
270f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank        matcher.addURI(EMAIL_AUTHORITY, "deletedMessage/mailbox/#", DELETED_MESSAGE_MAILBOX);
271f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank
272f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank        // All updated messages
273f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank        matcher.addURI(EMAIL_AUTHORITY, "updatedMessage", UPDATED_MESSAGE);
274f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank        // A specific updated message
275f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank        matcher.addURI(EMAIL_AUTHORITY, "updatedMessage/#", UPDATED_MESSAGE_ID);
276f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler    }
277f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler
2789627d014e16235eadf981b9165807dc72a14a383Mihai Preda    /*
2799627d014e16235eadf981b9165807dc72a14a383Mihai Preda     * Internal helper method for index creation.
2809627d014e16235eadf981b9165807dc72a14a383Mihai Preda     * Example:
2819627d014e16235eadf981b9165807dc72a14a383Mihai Preda     * "create index message_" + MessageColumns.FLAG_READ
2829627d014e16235eadf981b9165807dc72a14a383Mihai Preda     * + " on " + Message.TABLE_NAME + " (" + MessageColumns.FLAG_READ + ");"
2839627d014e16235eadf981b9165807dc72a14a383Mihai Preda     */
2849627d014e16235eadf981b9165807dc72a14a383Mihai Preda    /* package */
2859627d014e16235eadf981b9165807dc72a14a383Mihai Preda    static String createIndex(String tableName, String columnName) {
2869627d014e16235eadf981b9165807dc72a14a383Mihai Preda        return "create index " + tableName.toLowerCase() + '_' + columnName
2879627d014e16235eadf981b9165807dc72a14a383Mihai Preda            + " on " + tableName + " (" + columnName + ");";
2889627d014e16235eadf981b9165807dc72a14a383Mihai Preda    }
2899627d014e16235eadf981b9165807dc72a14a383Mihai Preda
290a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank    static void createMessageTable(SQLiteDatabase db) {
291b6493a07ef625c0e290890c2e60256b47a066e5eMarc Blank        String messageColumns = MessageColumns.DISPLAY_NAME + " text, "
292b6493a07ef625c0e290890c2e60256b47a066e5eMarc Blank            + MessageColumns.TIMESTAMP + " integer, "
293b6493a07ef625c0e290890c2e60256b47a066e5eMarc Blank            + MessageColumns.SUBJECT + " text, "
294b6493a07ef625c0e290890c2e60256b47a066e5eMarc Blank            + MessageColumns.FLAG_READ + " integer, "
295b6493a07ef625c0e290890c2e60256b47a066e5eMarc Blank            + MessageColumns.FLAG_LOADED + " integer, "
296b6493a07ef625c0e290890c2e60256b47a066e5eMarc Blank            + MessageColumns.FLAG_FAVORITE + " integer, "
297b6493a07ef625c0e290890c2e60256b47a066e5eMarc Blank            + MessageColumns.FLAG_ATTACHMENT + " integer, "
298b6493a07ef625c0e290890c2e60256b47a066e5eMarc Blank            + MessageColumns.FLAGS + " integer, "
299b6493a07ef625c0e290890c2e60256b47a066e5eMarc Blank            + MessageColumns.CLIENT_ID + " integer, "
300b6493a07ef625c0e290890c2e60256b47a066e5eMarc Blank            + MessageColumns.MESSAGE_ID + " text, "
301b6493a07ef625c0e290890c2e60256b47a066e5eMarc Blank            + MessageColumns.MAILBOX_KEY + " integer, "
302b6493a07ef625c0e290890c2e60256b47a066e5eMarc Blank            + MessageColumns.ACCOUNT_KEY + " integer, "
303b6493a07ef625c0e290890c2e60256b47a066e5eMarc Blank            + MessageColumns.FROM_LIST + " text, "
304b6493a07ef625c0e290890c2e60256b47a066e5eMarc Blank            + MessageColumns.TO_LIST + " text, "
305b6493a07ef625c0e290890c2e60256b47a066e5eMarc Blank            + MessageColumns.CC_LIST + " text, "
306b6493a07ef625c0e290890c2e60256b47a066e5eMarc Blank            + MessageColumns.BCC_LIST + " text, "
3074006e5fc224d097450fd66a321901b6636f7d9c4Marc Blank            + MessageColumns.REPLY_TO_LIST + " text, "
3084006e5fc224d097450fd66a321901b6636f7d9c4Marc Blank            + MessageColumns.MEETING_INFO + " text"
309b6493a07ef625c0e290890c2e60256b47a066e5eMarc Blank            + ");";
310b6493a07ef625c0e290890c2e60256b47a066e5eMarc Blank
311b6493a07ef625c0e290890c2e60256b47a066e5eMarc Blank        // This String and the following String MUST have the same columns, except for the type
312b6493a07ef625c0e290890c2e60256b47a066e5eMarc Blank        // of those columns!
313b6493a07ef625c0e290890c2e60256b47a066e5eMarc Blank        String createString = " (" + EmailContent.RECORD_ID + " integer primary key autoincrement, "
3140d00889f83fc8c1d69039a2c849b630fb4dd28ddAndrew Stadler            + SyncColumns.SERVER_ID + " text, "
3150d00889f83fc8c1d69039a2c849b630fb4dd28ddAndrew Stadler            + SyncColumns.SERVER_TIMESTAMP + " integer, "
316b6493a07ef625c0e290890c2e60256b47a066e5eMarc Blank            + messageColumns;
317b6493a07ef625c0e290890c2e60256b47a066e5eMarc Blank
318b6493a07ef625c0e290890c2e60256b47a066e5eMarc Blank        // For the updated and deleted tables, the id is assigned, but we do want to keep track
319b6493a07ef625c0e290890c2e60256b47a066e5eMarc Blank        // of the ORDER of updates using an autoincrement primary key.  We use the DATA column
320b6493a07ef625c0e290890c2e60256b47a066e5eMarc Blank        // at this point; it has no other function
3216b158f715b2ab6b2f35e894857446023f1d8be88Marc Blank        String altCreateString = " (" + EmailContent.RECORD_ID + " integer unique, "
3220d00889f83fc8c1d69039a2c849b630fb4dd28ddAndrew Stadler            + SyncColumns.SERVER_ID + " text, "
3230d00889f83fc8c1d69039a2c849b630fb4dd28ddAndrew Stadler            + SyncColumns.SERVER_TIMESTAMP + " integer, "
324b6493a07ef625c0e290890c2e60256b47a066e5eMarc Blank            + messageColumns;
325f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank
326f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank        // The three tables have the same schema
327b6493a07ef625c0e290890c2e60256b47a066e5eMarc Blank        db.execSQL("create table " + Message.TABLE_NAME + createString);
328b6493a07ef625c0e290890c2e60256b47a066e5eMarc Blank        db.execSQL("create table " + Message.UPDATED_TABLE_NAME + altCreateString);
329b6493a07ef625c0e290890c2e60256b47a066e5eMarc Blank        db.execSQL("create table " + Message.DELETED_TABLE_NAME + altCreateString);
330f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank
3319627d014e16235eadf981b9165807dc72a14a383Mihai Preda        String indexColumns[] = {
3329627d014e16235eadf981b9165807dc72a14a383Mihai Preda            MessageColumns.TIMESTAMP,
3339627d014e16235eadf981b9165807dc72a14a383Mihai Preda            MessageColumns.FLAG_READ,
3349627d014e16235eadf981b9165807dc72a14a383Mihai Preda            MessageColumns.FLAG_LOADED,
3359627d014e16235eadf981b9165807dc72a14a383Mihai Preda            MessageColumns.MAILBOX_KEY,
3369627d014e16235eadf981b9165807dc72a14a383Mihai Preda            SyncColumns.SERVER_ID
3379627d014e16235eadf981b9165807dc72a14a383Mihai Preda        };
3389627d014e16235eadf981b9165807dc72a14a383Mihai Preda
3399627d014e16235eadf981b9165807dc72a14a383Mihai Preda        for (String columnName : indexColumns) {
3409627d014e16235eadf981b9165807dc72a14a383Mihai Preda            db.execSQL(createIndex(Message.TABLE_NAME, columnName));
3419627d014e16235eadf981b9165807dc72a14a383Mihai Preda        }
3422c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank
343f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank        // Deleting a Message deletes all associated Attachments
3442c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank        // Deleting the associated Body cannot be done in a trigger, because the Body is stored
3452c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank        // in a separate database, and trigger cannot operate on attached databases.
346758a532fce2f672673d38b2daa5f67eb757b118bMarc Blank        db.execSQL("create trigger message_delete before delete on " + Message.TABLE_NAME +
3472c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank                " begin delete from " + Attachment.TABLE_NAME +
348758a532fce2f672673d38b2daa5f67eb757b118bMarc Blank                "  where " + AttachmentColumns.MESSAGE_KEY + "=old." + EmailContent.RECORD_ID +
349758a532fce2f672673d38b2daa5f67eb757b118bMarc Blank                "; end");
350758a532fce2f672673d38b2daa5f67eb757b118bMarc Blank
351758a532fce2f672673d38b2daa5f67eb757b118bMarc Blank        // Add triggers to keep unread count accurate per mailbox
352758a532fce2f672673d38b2daa5f67eb757b118bMarc Blank
353758a532fce2f672673d38b2daa5f67eb757b118bMarc Blank        // Insert a message; if flagRead is zero, add to the unread count of the message's mailbox
354758a532fce2f672673d38b2daa5f67eb757b118bMarc Blank        db.execSQL("create trigger unread_message_insert before insert on " + Message.TABLE_NAME +
355758a532fce2f672673d38b2daa5f67eb757b118bMarc Blank                " when NEW." + MessageColumns.FLAG_READ + "=0" +
356758a532fce2f672673d38b2daa5f67eb757b118bMarc Blank                " begin update " + Mailbox.TABLE_NAME + " set " + MailboxColumns.UNREAD_COUNT +
357758a532fce2f672673d38b2daa5f67eb757b118bMarc Blank                '=' + MailboxColumns.UNREAD_COUNT + "+1" +
358758a532fce2f672673d38b2daa5f67eb757b118bMarc Blank                "  where " + EmailContent.RECORD_ID + "=NEW." + MessageColumns.MAILBOX_KEY +
359758a532fce2f672673d38b2daa5f67eb757b118bMarc Blank                "; end");
360758a532fce2f672673d38b2daa5f67eb757b118bMarc Blank
361758a532fce2f672673d38b2daa5f67eb757b118bMarc Blank        // Delete a message; if flagRead is zero, decrement the unread count of the msg's mailbox
362758a532fce2f672673d38b2daa5f67eb757b118bMarc Blank        db.execSQL("create trigger unread_message_delete before delete on " + Message.TABLE_NAME +
363758a532fce2f672673d38b2daa5f67eb757b118bMarc Blank                " when OLD." + MessageColumns.FLAG_READ + "=0" +
364758a532fce2f672673d38b2daa5f67eb757b118bMarc Blank                " begin update " + Mailbox.TABLE_NAME + " set " + MailboxColumns.UNREAD_COUNT +
365758a532fce2f672673d38b2daa5f67eb757b118bMarc Blank                '=' + MailboxColumns.UNREAD_COUNT + "-1" +
366758a532fce2f672673d38b2daa5f67eb757b118bMarc Blank                "  where " + EmailContent.RECORD_ID + "=OLD." + MessageColumns.MAILBOX_KEY +
367758a532fce2f672673d38b2daa5f67eb757b118bMarc Blank                "; end");
368758a532fce2f672673d38b2daa5f67eb757b118bMarc Blank
369758a532fce2f672673d38b2daa5f67eb757b118bMarc Blank        // Change a message's mailbox
370758a532fce2f672673d38b2daa5f67eb757b118bMarc Blank        db.execSQL("create trigger unread_message_move before update of " +
371758a532fce2f672673d38b2daa5f67eb757b118bMarc Blank                MessageColumns.MAILBOX_KEY + " on " + Message.TABLE_NAME +
372758a532fce2f672673d38b2daa5f67eb757b118bMarc Blank                " when OLD." + MessageColumns.FLAG_READ + "=0" +
373758a532fce2f672673d38b2daa5f67eb757b118bMarc Blank                " begin update " + Mailbox.TABLE_NAME + " set " + MailboxColumns.UNREAD_COUNT +
374758a532fce2f672673d38b2daa5f67eb757b118bMarc Blank                '=' + MailboxColumns.UNREAD_COUNT + "-1" +
375758a532fce2f672673d38b2daa5f67eb757b118bMarc Blank                "  where " + EmailContent.RECORD_ID + "=OLD." + MessageColumns.MAILBOX_KEY +
376758a532fce2f672673d38b2daa5f67eb757b118bMarc Blank                "; update " + Mailbox.TABLE_NAME + " set " + MailboxColumns.UNREAD_COUNT +
377758a532fce2f672673d38b2daa5f67eb757b118bMarc Blank                '=' + MailboxColumns.UNREAD_COUNT + "+1" +
378758a532fce2f672673d38b2daa5f67eb757b118bMarc Blank                " where " + EmailContent.RECORD_ID + "=NEW." + MessageColumns.MAILBOX_KEY +
379758a532fce2f672673d38b2daa5f67eb757b118bMarc Blank                "; end");
380758a532fce2f672673d38b2daa5f67eb757b118bMarc Blank
381758a532fce2f672673d38b2daa5f67eb757b118bMarc Blank        // Change a message's read state
382b720ed318324c69ddbcb15c4a1b9e132f3266775Vasu Nori        db.execSQL("create trigger unread_message_read before update of " +
383758a532fce2f672673d38b2daa5f67eb757b118bMarc Blank                MessageColumns.FLAG_READ + " on " + Message.TABLE_NAME +
384758a532fce2f672673d38b2daa5f67eb757b118bMarc Blank                " when OLD." + MessageColumns.FLAG_READ + "!=NEW." + MessageColumns.FLAG_READ +
385758a532fce2f672673d38b2daa5f67eb757b118bMarc Blank                " begin update " + Mailbox.TABLE_NAME + " set " + MailboxColumns.UNREAD_COUNT +
386758a532fce2f672673d38b2daa5f67eb757b118bMarc Blank                '=' + MailboxColumns.UNREAD_COUNT + "+ case OLD." + MessageColumns.FLAG_READ +
387758a532fce2f672673d38b2daa5f67eb757b118bMarc Blank                " when 0 then -1 else 1 end" +
388758a532fce2f672673d38b2daa5f67eb757b118bMarc Blank                "  where " + EmailContent.RECORD_ID + "=OLD." + MessageColumns.MAILBOX_KEY +
389758a532fce2f672673d38b2daa5f67eb757b118bMarc Blank                "; end");
390758a532fce2f672673d38b2daa5f67eb757b118bMarc Blank   }
391a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank
392e7e1ca432e1aace5b7f11a3f1684a4abc503e6b2Marc Blank    static void resetMessageTable(SQLiteDatabase db, int oldVersion, int newVersion) {
393ddc871d9eddd088c0200a30dbfeb24812a81cf80Andrew Stadler        try {
394ddc871d9eddd088c0200a30dbfeb24812a81cf80Andrew Stadler            db.execSQL("drop table " + Message.TABLE_NAME);
395ddc871d9eddd088c0200a30dbfeb24812a81cf80Andrew Stadler            db.execSQL("drop table " + Message.UPDATED_TABLE_NAME);
396ddc871d9eddd088c0200a30dbfeb24812a81cf80Andrew Stadler            db.execSQL("drop table " + Message.DELETED_TABLE_NAME);
397ddc871d9eddd088c0200a30dbfeb24812a81cf80Andrew Stadler        } catch (SQLException e) {
398ddc871d9eddd088c0200a30dbfeb24812a81cf80Andrew Stadler        }
399a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank        createMessageTable(db);
400a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank    }
401a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank
402a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank    static void createAccountTable(SQLiteDatabase db) {
403758a532fce2f672673d38b2daa5f67eb757b118bMarc Blank        String s = " (" + EmailContent.RECORD_ID + " integer primary key autoincrement, "
404a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank            + AccountColumns.DISPLAY_NAME + " text, "
405a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank            + AccountColumns.EMAIL_ADDRESS + " text, "
406a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank            + AccountColumns.SYNC_KEY + " text, "
407a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank            + AccountColumns.SYNC_LOOKBACK + " integer, "
4089e2c6bd5f21f2d19eef7ebfe30e6fdf94ede0857Andrew Stadler            + AccountColumns.SYNC_INTERVAL + " text, "
409a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank            + AccountColumns.HOST_AUTH_KEY_RECV + " integer, "
410a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank            + AccountColumns.HOST_AUTH_KEY_SEND + " integer, "
411a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank            + AccountColumns.FLAGS + " integer, "
412a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank            + AccountColumns.IS_DEFAULT + " integer, "
413a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank            + AccountColumns.COMPATIBILITY_UUID + " text, "
414a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank            + AccountColumns.SENDER_NAME + " text, "
41553093871c492d03947c494f17e2463b27345e083Marc Blank            + AccountColumns.RINGTONE_URI + " text, "
4164a8c70c09be3914ded18031b4cca5a6d867de0d3Andrew Stadler            + AccountColumns.PROTOCOL_VERSION + " text, "
417fc8d943a828cd79ff71c703ced37001bd5482173Andrew Stadler            + AccountColumns.NEW_MESSAGE_COUNT + " integer, "
418345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler            + AccountColumns.SECURITY_FLAGS + " integer, "
419345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler            + AccountColumns.SECURITY_SYNC_KEY + " text, "
420345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler            + AccountColumns.SIGNATURE + " text "
421a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank            + ");";
422a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank        db.execSQL("create table " + Account.TABLE_NAME + s);
4232c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank        // Deleting an account deletes associated Mailboxes and HostAuth's
424b720ed318324c69ddbcb15c4a1b9e132f3266775Vasu Nori        db.execSQL("create trigger account_delete before delete on " + Account.TABLE_NAME +
4252c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank                " begin delete from " + Mailbox.TABLE_NAME +
426758a532fce2f672673d38b2daa5f67eb757b118bMarc Blank                " where " + MailboxColumns.ACCOUNT_KEY + "=old." + EmailContent.RECORD_ID +
4272c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank                "; delete from " + HostAuth.TABLE_NAME +
428f00dccd32125c727cc18d837b59c15c95f5d78bcMarc Blank                " where " + EmailContent.RECORD_ID + "=old." + AccountColumns.HOST_AUTH_KEY_RECV +
429f00dccd32125c727cc18d837b59c15c95f5d78bcMarc Blank                "; delete from " + HostAuth.TABLE_NAME +
430f00dccd32125c727cc18d837b59c15c95f5d78bcMarc Blank                " where " + EmailContent.RECORD_ID + "=old." + AccountColumns.HOST_AUTH_KEY_SEND +
431f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank        "; end");
432f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank    }
433a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank
434e7e1ca432e1aace5b7f11a3f1684a4abc503e6b2Marc Blank    static void resetAccountTable(SQLiteDatabase db, int oldVersion, int newVersion) {
435a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank        try {
436a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank            db.execSQL("drop table " +  Account.TABLE_NAME);
437a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank        } catch (SQLException e) {
438a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank        }
439a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank        createAccountTable(db);
440a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank    }
441f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank
442a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank    static void createHostAuthTable(SQLiteDatabase db) {
443758a532fce2f672673d38b2daa5f67eb757b118bMarc Blank        String s = " (" + EmailContent.RECORD_ID + " integer primary key autoincrement, "
444a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank            + HostAuthColumns.PROTOCOL + " text, "
445a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank            + HostAuthColumns.ADDRESS + " text, "
446a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank            + HostAuthColumns.PORT + " integer, "
447a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank            + HostAuthColumns.FLAGS + " integer, "
448a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank            + HostAuthColumns.LOGIN + " text, "
449a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank            + HostAuthColumns.PASSWORD + " text, "
450a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank            + HostAuthColumns.DOMAIN + " text, "
451a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank            + HostAuthColumns.ACCOUNT_KEY + " integer"
452a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank            + ");";
453a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank        db.execSQL("create table " + HostAuth.TABLE_NAME + s);
454a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank    }
455a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank
456e7e1ca432e1aace5b7f11a3f1684a4abc503e6b2Marc Blank    static void resetHostAuthTable(SQLiteDatabase db, int oldVersion, int newVersion) {
457a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank        try {
458a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank            db.execSQL("drop table " + HostAuth.TABLE_NAME);
459a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank        } catch (SQLException e) {
460a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank        }
461a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank        createHostAuthTable(db);
462a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank    }
463a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank
464f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank    static void createMailboxTable(SQLiteDatabase db) {
465758a532fce2f672673d38b2daa5f67eb757b118bMarc Blank        String s = " (" + EmailContent.RECORD_ID + " integer primary key autoincrement, "
466a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank            + MailboxColumns.DISPLAY_NAME + " text, "
4679be10e62ed4c809c56e2bcc357d5bb7d5dd543c1Marc Blank            + MailboxColumns.SERVER_ID + " text, "
468a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank            + MailboxColumns.PARENT_SERVER_ID + " text, "
469a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank            + MailboxColumns.ACCOUNT_KEY + " integer, "
470a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank            + MailboxColumns.TYPE + " integer, "
471a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank            + MailboxColumns.DELIMITER + " integer, "
472a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank            + MailboxColumns.SYNC_KEY + " text, "
473a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank            + MailboxColumns.SYNC_LOOKBACK + " integer, "
4749e2c6bd5f21f2d19eef7ebfe30e6fdf94ede0857Andrew Stadler            + MailboxColumns.SYNC_INTERVAL + " integer, "
475a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank            + MailboxColumns.SYNC_TIME + " integer, "
476a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank            + MailboxColumns.UNREAD_COUNT + " integer, "
477a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank            + MailboxColumns.FLAG_VISIBLE + " integer, "
478a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank            + MailboxColumns.FLAGS + " integer, "
4799b598924ec1dd53f865a6aa552d40161aeb5dd0bMarc Blank            + MailboxColumns.VISIBLE_LIMIT + " integer, "
4809b598924ec1dd53f865a6aa552d40161aeb5dd0bMarc Blank            + MailboxColumns.SYNC_STATUS + " text"
481b6493a07ef625c0e290890c2e60256b47a066e5eMarc Blank            + ");";
482f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank        db.execSQL("create table " + Mailbox.TABLE_NAME + s);
483758a532fce2f672673d38b2daa5f67eb757b118bMarc Blank        db.execSQL("create index mailbox_" + MailboxColumns.SERVER_ID
484a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank                + " on " + Mailbox.TABLE_NAME + " (" + MailboxColumns.SERVER_ID + ")");
485758a532fce2f672673d38b2daa5f67eb757b118bMarc Blank        db.execSQL("create index mailbox_" + MailboxColumns.ACCOUNT_KEY
486a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank                + " on " + Mailbox.TABLE_NAME + " (" + MailboxColumns.ACCOUNT_KEY + ")");
487ef83299b99288c00b9d661260d19715e73e6889cMarc Blank        // Deleting a Mailbox deletes associated Messages in all three tables
488ef83299b99288c00b9d661260d19715e73e6889cMarc Blank        db.execSQL(TRIGGER_MAILBOX_DELETE);
489a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank    }
490a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank
491e7e1ca432e1aace5b7f11a3f1684a4abc503e6b2Marc Blank    static void resetMailboxTable(SQLiteDatabase db, int oldVersion, int newVersion) {
492a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank        try {
493a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank            db.execSQL("drop table " + Mailbox.TABLE_NAME);
494a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank        } catch (SQLException e) {
495a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank        }
496a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank        createMailboxTable(db);
497a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank    }
498f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank
499a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank    static void createAttachmentTable(SQLiteDatabase db) {
500758a532fce2f672673d38b2daa5f67eb757b118bMarc Blank        String s = " (" + EmailContent.RECORD_ID + " integer primary key autoincrement, "
501a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank            + AttachmentColumns.FILENAME + " text, "
502a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank            + AttachmentColumns.MIME_TYPE + " text, "
503a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank            + AttachmentColumns.SIZE + " integer, "
504a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank            + AttachmentColumns.CONTENT_ID + " text, "
505a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank            + AttachmentColumns.CONTENT_URI + " text, "
506a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank            + AttachmentColumns.MESSAGE_KEY + " integer, "
507a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank            + AttachmentColumns.LOCATION + " text, "
5083aaba9eb87db34ea0861d70d5c08f84d7ca97ab0Andrew Stadler            + AttachmentColumns.ENCODING + " text, "
5093aaba9eb87db34ea0861d70d5c08f84d7ca97ab0Andrew Stadler            + AttachmentColumns.CONTENT + " text, "
51020225d57609d6a5e482c088fdad60c29212d31a0Makoto Onuki            + AttachmentColumns.FLAGS + " integer, "
51120225d57609d6a5e482c088fdad60c29212d31a0Makoto Onuki            + AttachmentColumns.CONTENT_BYTES + " blob"
512a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank            + ");";
513a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank        db.execSQL("create table " + Attachment.TABLE_NAME + s);
5149627d014e16235eadf981b9165807dc72a14a383Mihai Preda        db.execSQL(createIndex(Attachment.TABLE_NAME, AttachmentColumns.MESSAGE_KEY));
515a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank    }
516a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank
517e7e1ca432e1aace5b7f11a3f1684a4abc503e6b2Marc Blank    static void resetAttachmentTable(SQLiteDatabase db, int oldVersion, int newVersion) {
518a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank        try {
519a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank            db.execSQL("drop table " + Attachment.TABLE_NAME);
520a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank        } catch (SQLException e) {
521a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank        }
522a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank        createAttachmentTable(db);
523a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank    }
524a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank
525a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank    static void createBodyTable(SQLiteDatabase db) {
526758a532fce2f672673d38b2daa5f67eb757b118bMarc Blank        String s = " (" + EmailContent.RECORD_ID + " integer primary key autoincrement, "
527a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank            + BodyColumns.MESSAGE_KEY + " integer, "
528a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank            + BodyColumns.HTML_CONTENT + " text, "
529936babc145e2e6eb2e222f2ce5e3da8f9e4fb9f2Andrew Stadler            + BodyColumns.TEXT_CONTENT + " text, "
530936babc145e2e6eb2e222f2ce5e3da8f9e4fb9f2Andrew Stadler            + BodyColumns.HTML_REPLY + " text, "
531e25698319325d5e9619bc45ae85d861b0f1c5954Marc Blank            + BodyColumns.TEXT_REPLY + " text, "
5325fc57eccefeba517fe5e6f093786f37c6c4d50e6Marc Blank            + BodyColumns.SOURCE_MESSAGE_KEY + " text, "
5335fc57eccefeba517fe5e6f093786f37c6c4d50e6Marc Blank            + BodyColumns.INTRO_TEXT + " text"
534a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank            + ");";
535a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank        db.execSQL("create table " + Body.TABLE_NAME + s);
5369627d014e16235eadf981b9165807dc72a14a383Mihai Preda        db.execSQL(createIndex(Body.TABLE_NAME, BodyColumns.MESSAGE_KEY));
537a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank    }
538a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank
539a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank    static void upgradeBodyTable(SQLiteDatabase db, int oldVersion, int newVersion) {
540657de3bfd6024811c6d6ef6fb2fb2c2750d9f54aMarc Blank        if (oldVersion < 5) {
541e25698319325d5e9619bc45ae85d861b0f1c5954Marc Blank            try {
542e25698319325d5e9619bc45ae85d861b0f1c5954Marc Blank                db.execSQL("drop table " + Body.TABLE_NAME);
543e25698319325d5e9619bc45ae85d861b0f1c5954Marc Blank                createBodyTable(db);
544e25698319325d5e9619bc45ae85d861b0f1c5954Marc Blank            } catch (SQLException e) {
545e25698319325d5e9619bc45ae85d861b0f1c5954Marc Blank            }
5465fc57eccefeba517fe5e6f093786f37c6c4d50e6Marc Blank        } else if (oldVersion == 5) {
5475fc57eccefeba517fe5e6f093786f37c6c4d50e6Marc Blank            try {
5485fc57eccefeba517fe5e6f093786f37c6c4d50e6Marc Blank                db.execSQL("alter table " + Body.TABLE_NAME
5495fc57eccefeba517fe5e6f093786f37c6c4d50e6Marc Blank                        + " add " + BodyColumns.INTRO_TEXT + " text");
5505fc57eccefeba517fe5e6f093786f37c6c4d50e6Marc Blank            } catch (SQLException e) {
5515fc57eccefeba517fe5e6f093786f37c6c4d50e6Marc Blank                // Shouldn't be needed unless we're debugging and interrupt the process
5525fc57eccefeba517fe5e6f093786f37c6c4d50e6Marc Blank                Log.w(TAG, "Exception upgrading EmailProviderBody.db from v5 to v6", e);
5535fc57eccefeba517fe5e6f093786f37c6c4d50e6Marc Blank            }
5545fc57eccefeba517fe5e6f093786f37c6c4d50e6Marc Blank            oldVersion = 6;
555e7e1ca432e1aace5b7f11a3f1684a4abc503e6b2Marc Blank        }
556a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank    }
557a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank
558f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler    private SQLiteDatabase mDatabase;
559a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank    private SQLiteDatabase mBodyDatabase;
560f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank
56177398c42899a383680005b92955a29ab3d872c5cAndrew Stadler    public synchronized SQLiteDatabase getDatabase(Context context) {
5620e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank        // Always return the cached database, if we've got one
5630e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank        if (mDatabase != null) {
564f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler            return mDatabase;
565a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank        }
5660e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank
5670e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank        // Whenever we create or re-cache the databases, make sure that we haven't lost one
5680e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank        // to corruption
5690e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank        checkDatabases();
5700e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank
571f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler        DatabaseHelper helper = new DatabaseHelper(context, DATABASE_NAME);
572f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler        mDatabase = helper.getWritableDatabase();
573a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank        if (mDatabase != null) {
574f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler            mDatabase.setLockingEnabled(true);
575a867ebba6233becf2061c80e1c53d7d395a6cffcMarc Blank            BodyDatabaseHelper bodyHelper = new BodyDatabaseHelper(context, BODY_DATABASE_NAME);
576a867ebba6233becf2061c80e1c53d7d395a6cffcMarc Blank            mBodyDatabase = bodyHelper.getWritableDatabase();
577a867ebba6233becf2061c80e1c53d7d395a6cffcMarc Blank            if (mBodyDatabase != null) {
578a867ebba6233becf2061c80e1c53d7d395a6cffcMarc Blank                mBodyDatabase.setLockingEnabled(true);
579a867ebba6233becf2061c80e1c53d7d395a6cffcMarc Blank                String bodyFileName = mBodyDatabase.getPath();
580a867ebba6233becf2061c80e1c53d7d395a6cffcMarc Blank                mDatabase.execSQL("attach \"" + bodyFileName + "\" as BodyDatabase");
581a867ebba6233becf2061c80e1c53d7d395a6cffcMarc Blank            }
582a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank        }
583ef83299b99288c00b9d661260d19715e73e6889cMarc Blank
584ef83299b99288c00b9d661260d19715e73e6889cMarc Blank        // Check for any orphaned Messages in the updated/deleted tables
585ef83299b99288c00b9d661260d19715e73e6889cMarc Blank        deleteOrphans(mDatabase, Message.UPDATED_TABLE_NAME);
586ef83299b99288c00b9d661260d19715e73e6889cMarc Blank        deleteOrphans(mDatabase, Message.DELETED_TABLE_NAME);
587ef83299b99288c00b9d661260d19715e73e6889cMarc Blank
588f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler        return mDatabase;
589f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler    }
590f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler
591ef83299b99288c00b9d661260d19715e73e6889cMarc Blank    /*package*/ static SQLiteDatabase getReadableDatabase(Context context) {
592ef83299b99288c00b9d661260d19715e73e6889cMarc Blank        DatabaseHelper helper = new EmailProvider().new DatabaseHelper(context, DATABASE_NAME);
593ef83299b99288c00b9d661260d19715e73e6889cMarc Blank        return helper.getReadableDatabase();
594ef83299b99288c00b9d661260d19715e73e6889cMarc Blank    }
595ef83299b99288c00b9d661260d19715e73e6889cMarc Blank
596ef83299b99288c00b9d661260d19715e73e6889cMarc Blank    /*package*/ static void deleteOrphans(SQLiteDatabase database, String tableName) {
597ef83299b99288c00b9d661260d19715e73e6889cMarc Blank        if (database != null) {
598ef83299b99288c00b9d661260d19715e73e6889cMarc Blank            // We'll look at all of the items in the table; there won't be many typically
599ef83299b99288c00b9d661260d19715e73e6889cMarc Blank            Cursor c = database.query(tableName, ORPHANS_PROJECTION, null, null, null, null, null);
600ef83299b99288c00b9d661260d19715e73e6889cMarc Blank            // Usually, there will be nothing in these tables, so make a quick check
601ef83299b99288c00b9d661260d19715e73e6889cMarc Blank            try {
602ef83299b99288c00b9d661260d19715e73e6889cMarc Blank                if (c.getCount() == 0) return;
603ef83299b99288c00b9d661260d19715e73e6889cMarc Blank                ArrayList<Long> foundMailboxes = new ArrayList<Long>();
604ef83299b99288c00b9d661260d19715e73e6889cMarc Blank                ArrayList<Long> notFoundMailboxes = new ArrayList<Long>();
605ef83299b99288c00b9d661260d19715e73e6889cMarc Blank                ArrayList<Long> deleteList = new ArrayList<Long>();
606ef83299b99288c00b9d661260d19715e73e6889cMarc Blank                String[] bindArray = new String[1];
607ef83299b99288c00b9d661260d19715e73e6889cMarc Blank                while (c.moveToNext()) {
608ef83299b99288c00b9d661260d19715e73e6889cMarc Blank                    // Get the mailbox key and see if we've already found this mailbox
609ef83299b99288c00b9d661260d19715e73e6889cMarc Blank                    // If so, we're fine
610ef83299b99288c00b9d661260d19715e73e6889cMarc Blank                    long mailboxId = c.getLong(ORPHANS_MAILBOX_KEY);
611ef83299b99288c00b9d661260d19715e73e6889cMarc Blank                    // If we already know this mailbox doesn't exist, mark the message for deletion
612ef83299b99288c00b9d661260d19715e73e6889cMarc Blank                    if (notFoundMailboxes.contains(mailboxId)) {
613ef83299b99288c00b9d661260d19715e73e6889cMarc Blank                        deleteList.add(c.getLong(ORPHANS_ID));
614ef83299b99288c00b9d661260d19715e73e6889cMarc Blank                    // If we don't know about this mailbox, we'll try to find it
615ef83299b99288c00b9d661260d19715e73e6889cMarc Blank                    } else if (!foundMailboxes.contains(mailboxId)) {
616ef83299b99288c00b9d661260d19715e73e6889cMarc Blank                        bindArray[0] = Long.toString(mailboxId);
617ef83299b99288c00b9d661260d19715e73e6889cMarc Blank                        Cursor boxCursor = database.query(Mailbox.TABLE_NAME,
618ef83299b99288c00b9d661260d19715e73e6889cMarc Blank                                Mailbox.ID_PROJECTION, WHERE_ID, bindArray, null, null, null);
619ef83299b99288c00b9d661260d19715e73e6889cMarc Blank                        try {
620ef83299b99288c00b9d661260d19715e73e6889cMarc Blank                            // If it exists, we'll add it to the "found" mailboxes
621ef83299b99288c00b9d661260d19715e73e6889cMarc Blank                            if (boxCursor.moveToFirst()) {
622ef83299b99288c00b9d661260d19715e73e6889cMarc Blank                                foundMailboxes.add(mailboxId);
623ef83299b99288c00b9d661260d19715e73e6889cMarc Blank                            // Otherwise, we'll add to "not found" and mark the message for deletion
624ef83299b99288c00b9d661260d19715e73e6889cMarc Blank                            } else {
625ef83299b99288c00b9d661260d19715e73e6889cMarc Blank                                notFoundMailboxes.add(mailboxId);
626ef83299b99288c00b9d661260d19715e73e6889cMarc Blank                                deleteList.add(c.getLong(ORPHANS_ID));
627ef83299b99288c00b9d661260d19715e73e6889cMarc Blank                            }
628ef83299b99288c00b9d661260d19715e73e6889cMarc Blank                        } finally {
629ef83299b99288c00b9d661260d19715e73e6889cMarc Blank                            boxCursor.close();
630ef83299b99288c00b9d661260d19715e73e6889cMarc Blank                        }
631ef83299b99288c00b9d661260d19715e73e6889cMarc Blank                    }
632ef83299b99288c00b9d661260d19715e73e6889cMarc Blank                }
633ef83299b99288c00b9d661260d19715e73e6889cMarc Blank                // Now, delete the orphan messages
634ef83299b99288c00b9d661260d19715e73e6889cMarc Blank                for (long messageId: deleteList) {
635ef83299b99288c00b9d661260d19715e73e6889cMarc Blank                    bindArray[0] = Long.toString(messageId);
636ef83299b99288c00b9d661260d19715e73e6889cMarc Blank                    database.delete(tableName, WHERE_ID, bindArray);
637ef83299b99288c00b9d661260d19715e73e6889cMarc Blank                }
638ef83299b99288c00b9d661260d19715e73e6889cMarc Blank            } finally {
639ef83299b99288c00b9d661260d19715e73e6889cMarc Blank                c.close();
640ef83299b99288c00b9d661260d19715e73e6889cMarc Blank            }
641ef83299b99288c00b9d661260d19715e73e6889cMarc Blank        }
642ef83299b99288c00b9d661260d19715e73e6889cMarc Blank    }
643ef83299b99288c00b9d661260d19715e73e6889cMarc Blank
644a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank    private class BodyDatabaseHelper extends SQLiteOpenHelper {
645a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank        BodyDatabaseHelper(Context context, String name) {
6460d00889f83fc8c1d69039a2c849b630fb4dd28ddAndrew Stadler            super(context, name, null, BODY_DATABASE_VERSION);
647a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank        }
648a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank
649a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank        @Override
650a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank        public void onCreate(SQLiteDatabase db) {
6510e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank            Log.d(TAG, "Creating EmailProviderBody database");
652a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank            createBodyTable(db);
653a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank        }
654a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank
655a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank        @Override
656a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
657a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank            upgradeBodyTable(db, oldVersion, newVersion);
658a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank        }
659f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler
660a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank        @Override
661a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank        public void onOpen(SQLiteDatabase db) {
662a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank        }
663a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank    }
664f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank
665f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler    private class DatabaseHelper extends SQLiteOpenHelper {
666e7e1ca432e1aace5b7f11a3f1684a4abc503e6b2Marc Blank        Context mContext;
667e7e1ca432e1aace5b7f11a3f1684a4abc503e6b2Marc Blank
668f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler        DatabaseHelper(Context context, String name) {
6690d00889f83fc8c1d69039a2c849b630fb4dd28ddAndrew Stadler            super(context, name, null, DATABASE_VERSION);
670e7e1ca432e1aace5b7f11a3f1684a4abc503e6b2Marc Blank            mContext = context;
671f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler        }
672f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler
673f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler        @Override
674f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler        public void onCreate(SQLiteDatabase db) {
6750e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank            Log.d(TAG, "Creating EmailProvider database");
676f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler            // Create all tables here; each class has its own method
677a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank            createMessageTable(db);
678a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank            createAttachmentTable(db);
679a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank            createMailboxTable(db);
680a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank            createHostAuthTable(db);
681a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank            createAccountTable(db);
682f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank        }
683f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler
684f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler        @Override
685f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
686657de3bfd6024811c6d6ef6fb2fb2c2750d9f54aMarc Blank            // For versions prior to 5, delete all data
687657de3bfd6024811c6d6ef6fb2fb2c2750d9f54aMarc Blank            // Versions >= 5 require that data be preserved!
688657de3bfd6024811c6d6ef6fb2fb2c2750d9f54aMarc Blank            if (oldVersion < 5) {
689faed6178b1858f0e6df388a409d14fb3f94afefaMakoto Onuki                android.accounts.Account[] accounts = AccountManager.get(mContext)
690faed6178b1858f0e6df388a409d14fb3f94afefaMakoto Onuki                        .getAccountsByType(Email.EXCHANGE_ACCOUNT_MANAGER_TYPE);
691e7e1ca432e1aace5b7f11a3f1684a4abc503e6b2Marc Blank                for (android.accounts.Account account: accounts) {
692e7e1ca432e1aace5b7f11a3f1684a4abc503e6b2Marc Blank                    AccountManager.get(mContext).removeAccount(account, null, null);
693e7e1ca432e1aace5b7f11a3f1684a4abc503e6b2Marc Blank                }
694e7e1ca432e1aace5b7f11a3f1684a4abc503e6b2Marc Blank                resetMessageTable(db, oldVersion, newVersion);
695e7e1ca432e1aace5b7f11a3f1684a4abc503e6b2Marc Blank                resetAttachmentTable(db, oldVersion, newVersion);
696e7e1ca432e1aace5b7f11a3f1684a4abc503e6b2Marc Blank                resetMailboxTable(db, oldVersion, newVersion);
697e7e1ca432e1aace5b7f11a3f1684a4abc503e6b2Marc Blank                resetHostAuthTable(db, oldVersion, newVersion);
698e7e1ca432e1aace5b7f11a3f1684a4abc503e6b2Marc Blank                resetAccountTable(db, oldVersion, newVersion);
6990d00889f83fc8c1d69039a2c849b630fb4dd28ddAndrew Stadler                return;
7000d00889f83fc8c1d69039a2c849b630fb4dd28ddAndrew Stadler            }
7010d00889f83fc8c1d69039a2c849b630fb4dd28ddAndrew Stadler            if (oldVersion == 5) {
7020d00889f83fc8c1d69039a2c849b630fb4dd28ddAndrew Stadler                // Message Tables: Add SyncColumns.SERVER_TIMESTAMP
7035fc57eccefeba517fe5e6f093786f37c6c4d50e6Marc Blank                try {
7045fc57eccefeba517fe5e6f093786f37c6c4d50e6Marc Blank                    db.execSQL("alter table " + Message.TABLE_NAME
7055fc57eccefeba517fe5e6f093786f37c6c4d50e6Marc Blank                            + " add column " + SyncColumns.SERVER_TIMESTAMP + " integer" + ";");
7065fc57eccefeba517fe5e6f093786f37c6c4d50e6Marc Blank                    db.execSQL("alter table " + Message.UPDATED_TABLE_NAME
7075fc57eccefeba517fe5e6f093786f37c6c4d50e6Marc Blank                            + " add column " + SyncColumns.SERVER_TIMESTAMP + " integer" + ";");
7085fc57eccefeba517fe5e6f093786f37c6c4d50e6Marc Blank                    db.execSQL("alter table " + Message.DELETED_TABLE_NAME
7095fc57eccefeba517fe5e6f093786f37c6c4d50e6Marc Blank                            + " add column " + SyncColumns.SERVER_TIMESTAMP + " integer" + ";");
7105fc57eccefeba517fe5e6f093786f37c6c4d50e6Marc Blank                } catch (SQLException e) {
7115fc57eccefeba517fe5e6f093786f37c6c4d50e6Marc Blank                    // Shouldn't be needed unless we're debugging and interrupt the process
7125fc57eccefeba517fe5e6f093786f37c6c4d50e6Marc Blank                    Log.w(TAG, "Exception upgrading EmailProvider.db from v5 to v6", e);
7135fc57eccefeba517fe5e6f093786f37c6c4d50e6Marc Blank                }
7140d00889f83fc8c1d69039a2c849b630fb4dd28ddAndrew Stadler                oldVersion = 6;
715e7e1ca432e1aace5b7f11a3f1684a4abc503e6b2Marc Blank            }
716ef83299b99288c00b9d661260d19715e73e6889cMarc Blank            if (oldVersion == 6) {
717ef83299b99288c00b9d661260d19715e73e6889cMarc Blank                // Use the newer mailbox_delete trigger
718367963639d4291511b7e175a208e2b553aac26c2Marc Blank                db.execSQL("drop trigger mailbox_delete;");
719ef83299b99288c00b9d661260d19715e73e6889cMarc Blank                db.execSQL(TRIGGER_MAILBOX_DELETE);
720ef83299b99288c00b9d661260d19715e73e6889cMarc Blank                oldVersion = 7;
721ef83299b99288c00b9d661260d19715e73e6889cMarc Blank            }
722fc8d943a828cd79ff71c703ced37001bd5482173Andrew Stadler            if (oldVersion == 7) {
723fc8d943a828cd79ff71c703ced37001bd5482173Andrew Stadler                // add the security (provisioning) column
724fc8d943a828cd79ff71c703ced37001bd5482173Andrew Stadler                try {
725fc8d943a828cd79ff71c703ced37001bd5482173Andrew Stadler                    db.execSQL("alter table " + Account.TABLE_NAME
726fc8d943a828cd79ff71c703ced37001bd5482173Andrew Stadler                            + " add column " + AccountColumns.SECURITY_FLAGS + " integer" + ";");
727fc8d943a828cd79ff71c703ced37001bd5482173Andrew Stadler                } catch (SQLException e) {
728fc8d943a828cd79ff71c703ced37001bd5482173Andrew Stadler                    // Shouldn't be needed unless we're debugging and interrupt the process
729fc8d943a828cd79ff71c703ced37001bd5482173Andrew Stadler                    Log.w(TAG, "Exception upgrading EmailProvider.db from 7 to 8 " + e);
730fc8d943a828cd79ff71c703ced37001bd5482173Andrew Stadler                }
731fc8d943a828cd79ff71c703ced37001bd5482173Andrew Stadler                oldVersion = 8;
732fc8d943a828cd79ff71c703ced37001bd5482173Andrew Stadler            }
733345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler            if (oldVersion == 8) {
734345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler                // accounts: add security sync key & user signature columns
735345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler                try {
736345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler                    db.execSQL("alter table " + Account.TABLE_NAME
737345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler                            + " add column " + AccountColumns.SECURITY_SYNC_KEY + " text" + ";");
738345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler                    db.execSQL("alter table " + Account.TABLE_NAME
739345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler                            + " add column " + AccountColumns.SIGNATURE + " text" + ";");
740345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler                } catch (SQLException e) {
741345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler                    // Shouldn't be needed unless we're debugging and interrupt the process
742345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler                    Log.w(TAG, "Exception upgrading EmailProvider.db from 8 to 9 " + e);
743345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler                }
744345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler                oldVersion = 9;
745345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler            }
7464006e5fc224d097450fd66a321901b6636f7d9c4Marc Blank            if (oldVersion == 9) {
7474006e5fc224d097450fd66a321901b6636f7d9c4Marc Blank                // Message: add meeting info column into Message tables
7484006e5fc224d097450fd66a321901b6636f7d9c4Marc Blank                try {
7494006e5fc224d097450fd66a321901b6636f7d9c4Marc Blank                    db.execSQL("alter table " + Message.TABLE_NAME
7504006e5fc224d097450fd66a321901b6636f7d9c4Marc Blank                            + " add column " + MessageColumns.MEETING_INFO + " text" + ";");
7514006e5fc224d097450fd66a321901b6636f7d9c4Marc Blank                    db.execSQL("alter table " + Message.UPDATED_TABLE_NAME
7524006e5fc224d097450fd66a321901b6636f7d9c4Marc Blank                            + " add column " + MessageColumns.MEETING_INFO + " text" + ";");
7534006e5fc224d097450fd66a321901b6636f7d9c4Marc Blank                    db.execSQL("alter table " + Message.DELETED_TABLE_NAME
7544006e5fc224d097450fd66a321901b6636f7d9c4Marc Blank                            + " add column " + MessageColumns.MEETING_INFO + " text" + ";");
7554006e5fc224d097450fd66a321901b6636f7d9c4Marc Blank                } catch (SQLException e) {
7564006e5fc224d097450fd66a321901b6636f7d9c4Marc Blank                    // Shouldn't be needed unless we're debugging and interrupt the process
7574006e5fc224d097450fd66a321901b6636f7d9c4Marc Blank                    Log.w(TAG, "Exception upgrading EmailProvider.db from 9 to 10 " + e);
7584006e5fc224d097450fd66a321901b6636f7d9c4Marc Blank                }
7594006e5fc224d097450fd66a321901b6636f7d9c4Marc Blank                oldVersion = 10;
7604006e5fc224d097450fd66a321901b6636f7d9c4Marc Blank            }
7613aaba9eb87db34ea0861d70d5c08f84d7ca97ab0Andrew Stadler            if (oldVersion == 10) {
7623aaba9eb87db34ea0861d70d5c08f84d7ca97ab0Andrew Stadler                // Attachment: add content and flags columns
7633aaba9eb87db34ea0861d70d5c08f84d7ca97ab0Andrew Stadler                try {
7643aaba9eb87db34ea0861d70d5c08f84d7ca97ab0Andrew Stadler                    db.execSQL("alter table " + Attachment.TABLE_NAME
7653aaba9eb87db34ea0861d70d5c08f84d7ca97ab0Andrew Stadler                            + " add column " + AttachmentColumns.CONTENT + " text" + ";");
7663aaba9eb87db34ea0861d70d5c08f84d7ca97ab0Andrew Stadler                    db.execSQL("alter table " + Attachment.TABLE_NAME
7673aaba9eb87db34ea0861d70d5c08f84d7ca97ab0Andrew Stadler                            + " add column " + AttachmentColumns.FLAGS + " integer" + ";");
7683aaba9eb87db34ea0861d70d5c08f84d7ca97ab0Andrew Stadler                } catch (SQLException e) {
7693aaba9eb87db34ea0861d70d5c08f84d7ca97ab0Andrew Stadler                    // Shouldn't be needed unless we're debugging and interrupt the process
7703aaba9eb87db34ea0861d70d5c08f84d7ca97ab0Andrew Stadler                    Log.w(TAG, "Exception upgrading EmailProvider.db from 10 to 11 " + e);
7713aaba9eb87db34ea0861d70d5c08f84d7ca97ab0Andrew Stadler                }
7723aaba9eb87db34ea0861d70d5c08f84d7ca97ab0Andrew Stadler                oldVersion = 11;
7733aaba9eb87db34ea0861d70d5c08f84d7ca97ab0Andrew Stadler            }
77420225d57609d6a5e482c088fdad60c29212d31a0Makoto Onuki            if (oldVersion == 11) {
77520225d57609d6a5e482c088fdad60c29212d31a0Makoto Onuki                // Attachment: add content_bytes
77620225d57609d6a5e482c088fdad60c29212d31a0Makoto Onuki                try {
77720225d57609d6a5e482c088fdad60c29212d31a0Makoto Onuki                    db.execSQL("alter table " + Attachment.TABLE_NAME
77820225d57609d6a5e482c088fdad60c29212d31a0Makoto Onuki                            + " add column " + AttachmentColumns.CONTENT_BYTES + " blob" + ";");
77920225d57609d6a5e482c088fdad60c29212d31a0Makoto Onuki                } catch (SQLException e) {
78020225d57609d6a5e482c088fdad60c29212d31a0Makoto Onuki                    // Shouldn't be needed unless we're debugging and interrupt the process
78120225d57609d6a5e482c088fdad60c29212d31a0Makoto Onuki                    Log.w(TAG, "Exception upgrading EmailProvider.db from 11 to 12 " + e);
78220225d57609d6a5e482c088fdad60c29212d31a0Makoto Onuki                }
78320225d57609d6a5e482c088fdad60c29212d31a0Makoto Onuki                oldVersion = 12;
78420225d57609d6a5e482c088fdad60c29212d31a0Makoto Onuki            }
785f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler        }
786f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler
787f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler        @Override
788f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler        public void onOpen(SQLiteDatabase db) {
789f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler        }
790f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler    }
791f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler
792f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler    @Override
793f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler    public int delete(Uri uri, String selection, String[] selectionArgs) {
794fb7974f5bfb6275fb856b0f7ff386ef10680c83aMihai Preda        final int match = sURIMatcher.match(uri);
795a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank        Context context = getContext();
796cba3a48f97ae2e6d875ac4284a4066da94c922d5Marc Blank        // Pick the correct database for this operation
797cba3a48f97ae2e6d875ac4284a4066da94c922d5Marc Blank        // If we're in a transaction already (which would happen during applyBatch), then the
798cba3a48f97ae2e6d875ac4284a4066da94c922d5Marc Blank        // body database is already attached to the email database and any attempt to use the
799cba3a48f97ae2e6d875ac4284a4066da94c922d5Marc Blank        // body database directly will result in a SQLiteException (the database is locked)
800a867ebba6233becf2061c80e1c53d7d395a6cffcMarc Blank        SQLiteDatabase db = getDatabase(context);
801f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler        int table = match >> BASE_SHIFT;
8022c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank        String id = "0";
803cba3a48f97ae2e6d875ac4284a4066da94c922d5Marc Blank        boolean messageDeletion = false;
804f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank
805f33986d5cc248d2eeed0707143d81e94866f8e3aMihai Preda        if (Email.LOGD) {
806f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler            Log.v(TAG, "EmailProvider.delete: uri=" + uri + ", match is " + match);
807fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blank        }
808f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler
809b6493a07ef625c0e290890c2e60256b47a066e5eMarc Blank        int result = -1;
810f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank
8112c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank        try {
8122c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank            switch (match) {
8132c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank                // These are cases in which one or more Messages might get deleted, either by
8142c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank                // cascade or explicitly
8152c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank                case MAILBOX_ID:
8162c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank                case MAILBOX:
8172c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank                case ACCOUNT_ID:
8182c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank                case ACCOUNT:
8192c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank                case MESSAGE:
820f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank                case SYNCED_MESSAGE_ID:
8212c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank                case MESSAGE_ID:
8222c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank                    // Handle lost Body records here, since this cannot be done in a trigger
8232c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank                    // The process is:
824a867ebba6233becf2061c80e1c53d7d395a6cffcMarc Blank                    //  1) Begin a transaction, ensuring that both databases are affected atomically
825a867ebba6233becf2061c80e1c53d7d395a6cffcMarc Blank                    //  2) Do the requested deletion, with cascading deletions handled in triggers
826a867ebba6233becf2061c80e1c53d7d395a6cffcMarc Blank                    //  3) End the transaction, committing all changes atomically
8276c21942ec45f561d711b3d74ecca8e62afb735c4Andrew Stadler                    //
8286c21942ec45f561d711b3d74ecca8e62afb735c4Andrew Stadler                    // Bodies are auto-deleted here;  Attachments are auto-deleted via trigger
829a867ebba6233becf2061c80e1c53d7d395a6cffcMarc Blank
830cba3a48f97ae2e6d875ac4284a4066da94c922d5Marc Blank                    messageDeletion = true;
8318587aa61211d288d05b5fb2ddf02d69cabe6a9e2Marc Blank                    db.beginTransaction();
8322c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank                    break;
8332c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank            }
8342c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank            switch (match) {
8352c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank                case BODY_ID:
836f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank                case DELETED_MESSAGE_ID:
837f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank                case SYNCED_MESSAGE_ID:
8382c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank                case MESSAGE_ID:
8392c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank                case UPDATED_MESSAGE_ID:
8402c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank                case ATTACHMENT_ID:
8412c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank                case MAILBOX_ID:
8422c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank                case ACCOUNT_ID:
8432c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank                case HOSTAUTH_ID:
8442c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank                    id = uri.getPathSegments().get(1);
845f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank                    if (match == SYNCED_MESSAGE_ID) {
846f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank                        // For synced messages, first copy the old message to the deleted table and
847f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank                        // delete it from the updated table (in case it was updated first)
848f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank                        // Note that this is all within a transaction, for atomicity
849f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank                        db.execSQL(DELETED_MESSAGE_INSERT + id);
850f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank                        db.execSQL(UPDATED_MESSAGE_DELETE + id);
851f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank                    }
8522c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank                    result = db.delete(TABLE_NAMES[table], whereWithId(id, selection),
8532c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank                            selectionArgs);
8542c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank                    break;
8556c21942ec45f561d711b3d74ecca8e62afb735c4Andrew Stadler                case ATTACHMENTS_MESSAGE_ID:
8566c21942ec45f561d711b3d74ecca8e62afb735c4Andrew Stadler                    // All attachments for the given message
8576c21942ec45f561d711b3d74ecca8e62afb735c4Andrew Stadler                    id = uri.getPathSegments().get(2);
8586c21942ec45f561d711b3d74ecca8e62afb735c4Andrew Stadler                    result = db.delete(TABLE_NAMES[table],
8596c21942ec45f561d711b3d74ecca8e62afb735c4Andrew Stadler                            whereWith(Attachment.MESSAGE_KEY + "=" + id, selection), selectionArgs);
8606c21942ec45f561d711b3d74ecca8e62afb735c4Andrew Stadler                    break;
8616c21942ec45f561d711b3d74ecca8e62afb735c4Andrew Stadler
8622c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank                case BODY:
8632c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank                case MESSAGE:
864f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank                case DELETED_MESSAGE:
8652c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank                case UPDATED_MESSAGE:
8662c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank                case ATTACHMENT:
8672c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank                case MAILBOX:
8682c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank                case ACCOUNT:
8692c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank                case HOSTAUTH:
8702c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank                    result = db.delete(TABLE_NAMES[table], selection, selectionArgs);
8712c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank                    break;
8726c21942ec45f561d711b3d74ecca8e62afb735c4Andrew Stadler
8732c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank                default:
8742c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank                    throw new IllegalArgumentException("Unknown URI " + uri);
8752c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank            }
876cba3a48f97ae2e6d875ac4284a4066da94c922d5Marc Blank            if (messageDeletion) {
877fb7974f5bfb6275fb856b0f7ff386ef10680c83aMihai Preda                if (match == MESSAGE_ID) {
8785f4dbd64389cd6540a93cde1daed304bf9392a01Andrew Stadler                    // Delete the Body record associated with the deleted message
879f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank                    db.execSQL(DELETE_BODY + id);
880fb7974f5bfb6275fb856b0f7ff386ef10680c83aMihai Preda                } else {
881fb7974f5bfb6275fb856b0f7ff386ef10680c83aMihai Preda                    // Delete any orphaned Body records
882fb7974f5bfb6275fb856b0f7ff386ef10680c83aMihai Preda                    db.execSQL(DELETE_ORPHAN_BODIES);
883cba3a48f97ae2e6d875ac4284a4066da94c922d5Marc Blank                }
8848587aa61211d288d05b5fb2ddf02d69cabe6a9e2Marc Blank                db.setTransactionSuccessful();
8855f4dbd64389cd6540a93cde1daed304bf9392a01Andrew Stadler            }
8860e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank        } catch (SQLiteException e) {
8870e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank            checkDatabases();
8880e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank            throw e;
8892c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank        } finally {
890cba3a48f97ae2e6d875ac4284a4066da94c922d5Marc Blank            if (messageDeletion) {
8918587aa61211d288d05b5fb2ddf02d69cabe6a9e2Marc Blank                db.endTransaction();
8925f4dbd64389cd6540a93cde1daed304bf9392a01Andrew Stadler            }
893f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler        }
894626f3e48a4f14c38a973dd2bea2e2debea7637a5Andrew Stadler        getContext().getContentResolver().notifyChange(uri, null);
895626f3e48a4f14c38a973dd2bea2e2debea7637a5Andrew Stadler        return result;
896f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler    }
897f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler
898f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler    @Override
899f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler    // Use the email- prefix because message, mailbox, and account are so generic (e.g. SMS, IM)
900f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler    public String getType(Uri uri) {
901f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler        int match = sURIMatcher.match(uri);
902f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler        switch (match) {
903a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank            case BODY_ID:
904a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank                return "vnd.android.cursor.item/email-body";
905a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank            case BODY:
906fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blank                return "vnd.android.cursor.dir/email-message";
907e34525d0f026a7467cee1cb5fddcf25ba6f35207Marc Blank            case UPDATED_MESSAGE_ID:
908a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank            case MESSAGE_ID:
909a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank                return "vnd.android.cursor.item/email-message";
910fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blank            case MAILBOX_MESSAGES:
911e34525d0f026a7467cee1cb5fddcf25ba6f35207Marc Blank            case UPDATED_MESSAGE:
912fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blank            case MESSAGE:
913a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank                return "vnd.android.cursor.dir/email-message";
914fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blank            case ACCOUNT_MAILBOXES:
915fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blank            case MAILBOX:
916fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blank                return "vnd.android.cursor.dir/email-mailbox";
917fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blank            case MAILBOX_ID:
918fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blank                return "vnd.android.cursor.item/email-mailbox";
919fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blank            case ACCOUNT:
920fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blank                return "vnd.android.cursor.dir/email-account";
921fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blank            case ACCOUNT_ID:
922fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blank                return "vnd.android.cursor.item/email-account";
9234119218e2fd64341ac946fb8f2cbdb796a444cb8Andrew Stadler            case ATTACHMENTS_MESSAGE_ID:
924fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blank            case ATTACHMENT:
925fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blank                return "vnd.android.cursor.dir/email-attachment";
926fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blank            case ATTACHMENT_ID:
927fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blank                return "vnd.android.cursor.item/email-attachment";
928fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blank            case HOSTAUTH:
929fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blank                return "vnd.android.cursor.dir/email-hostauth";
930fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blank            case HOSTAUTH_ID:
931fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blank                return "vnd.android.cursor.item/email-hostauth";
932fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blank            default:
933fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blank                throw new IllegalArgumentException("Unknown URI " + uri);
934f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler        }
935f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler    }
936f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler
937f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler    @Override
938f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler    public Uri insert(Uri uri, ContentValues values) {
939f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler        int match = sURIMatcher.match(uri);
940a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank        Context context = getContext();
941cba3a48f97ae2e6d875ac4284a4066da94c922d5Marc Blank        // See the comment at delete(), above
942a867ebba6233becf2061c80e1c53d7d395a6cffcMarc Blank        SQLiteDatabase db = getDatabase(context);
943f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler        int table = match >> BASE_SHIFT;
944a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank        long id;
945f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank
946f33986d5cc248d2eeed0707143d81e94866f8e3aMihai Preda        if (Email.LOGD) {
947f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler            Log.v(TAG, "EmailProvider.insert: uri=" + uri + ", match is " + match);
948fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blank        }
949f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler
950626f3e48a4f14c38a973dd2bea2e2debea7637a5Andrew Stadler        Uri resultUri = null;
951f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank
9520e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank        try {
9530e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank            switch (match) {
9540e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                case UPDATED_MESSAGE:
9550e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                case DELETED_MESSAGE:
9560e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                case BODY:
9570e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                case MESSAGE:
9580e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                case ATTACHMENT:
9590e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                case MAILBOX:
9600e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                case ACCOUNT:
9610e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                case HOSTAUTH:
9620e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                    id = db.insert(TABLE_NAMES[table], "foo", values);
9630e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                    resultUri = ContentUris.withAppendedId(uri, id);
9640e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                    // Clients shouldn't normally be adding rows to these tables, as they are
9650e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                    // maintained by triggers.  However, we need to be able to do this for unit
9660e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                    // testing, so we allow the insert and then throw the same exception that we
9670e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                    // would if this weren't allowed.
9680e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                    if (match == UPDATED_MESSAGE || match == DELETED_MESSAGE) {
9690e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                        throw new IllegalArgumentException("Unknown URL " + uri);
9700e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                    }
9710e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                    break;
9720e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                case MAILBOX_ID:
9730e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                    // This implies adding a message to a mailbox
9740e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                    // Hmm, a problem here is that we can't link the account as well, so it must be
9750e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                    // already in the values...
9760e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                    id = Long.parseLong(uri.getPathSegments().get(1));
9770e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                    values.put(MessageColumns.MAILBOX_KEY, id);
9780e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                    resultUri = insert(Message.CONTENT_URI, values);
9790e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                    break;
9800e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                case MESSAGE_ID:
9810e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                    // This implies adding an attachment to a message.
9820e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                    id = Long.parseLong(uri.getPathSegments().get(1));
9830e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                    values.put(AttachmentColumns.MESSAGE_KEY, id);
9840e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                    resultUri = insert(Attachment.CONTENT_URI, values);
9850e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                    break;
9860e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                case ACCOUNT_ID:
9870e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                    // This implies adding a mailbox to an account.
9880e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                    id = Long.parseLong(uri.getPathSegments().get(1));
9890e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                    values.put(MailboxColumns.ACCOUNT_KEY, id);
9900e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                    resultUri = insert(Mailbox.CONTENT_URI, values);
9910e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                    break;
9920e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                case ATTACHMENTS_MESSAGE_ID:
9930e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                    id = db.insert(TABLE_NAMES[table], "foo", values);
9940e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                    resultUri = ContentUris.withAppendedId(Attachment.CONTENT_URI, id);
9950e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                    break;
9960e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                default:
997ef83299b99288c00b9d661260d19715e73e6889cMarc Blank                    throw new IllegalArgumentException("Unknown URL " + uri);
9980e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank            }
9990e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank        } catch (SQLiteException e) {
10000e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank            checkDatabases();
10010e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank            throw e;
1002f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler        }
1003f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank
1004a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank        // Notify with the base uri, not the new uri (nobody is watching a new record)
1005a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank        getContext().getContentResolver().notifyChange(uri, null);
1006626f3e48a4f14c38a973dd2bea2e2debea7637a5Andrew Stadler        return resultUri;
1007f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler    }
1008f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler
1009f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler    @Override
1010f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler    public boolean onCreate() {
10110e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank        checkDatabases();
1012f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler        return false;
1013f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler    }
1014f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler
10150e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank    /**
10160e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank     * The idea here is that the two databases (EmailProvider.db and EmailProviderBody.db must
10170e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank     * always be in sync (i.e. there are two database or NO databases).  This code will delete
10180e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank     * any "orphan" database, so that both will be created together.  Note that an "orphan" database
10190e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank     * will exist after either of the individual databases is deleted due to data corruption.
10200e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank     */
10210e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank    public void checkDatabases() {
10220e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank        // Uncache the databases
10230e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank        if (mDatabase != null) {
10240e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank            mDatabase = null;
10250e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank        }
10260e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank        if (mBodyDatabase != null) {
10270e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank            mBodyDatabase = null;
10280e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank        }
10290e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank        // Look for orphans, and delete as necessary; these must always be in sync
10300e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank        File databaseFile = getContext().getDatabasePath(DATABASE_NAME);
10310e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank        File bodyFile = getContext().getDatabasePath(BODY_DATABASE_NAME);
10320e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank
10330e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank        // TODO Make sure attachments are deleted
10340e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank        if (databaseFile.exists() && !bodyFile.exists()) {
10350e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank            Log.w(TAG, "Deleting orphaned EmailProvider database...");
10360e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank            databaseFile.delete();
10370e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank        } else if (bodyFile.exists() && !databaseFile.exists()) {
10380e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank            Log.w(TAG, "Deleting orphaned EmailProviderBody database...");
10390e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank            bodyFile.delete();
10400e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank        }
10410e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank    }
10420e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank
1043f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler    @Override
1044758a532fce2f672673d38b2daa5f67eb757b118bMarc Blank    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
1045fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blank            String sortOrder) {
1046f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler        Cursor c = null;
1047a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank        Uri notificationUri = EmailContent.CONTENT_URI;
1048f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler        int match = sURIMatcher.match(uri);
1049a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank        Context context = getContext();
1050cba3a48f97ae2e6d875ac4284a4066da94c922d5Marc Blank        // See the comment at delete(), above
1051a867ebba6233becf2061c80e1c53d7d395a6cffcMarc Blank        SQLiteDatabase db = getDatabase(context);
1052f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler        int table = match >> BASE_SHIFT;
1053f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler        String id;
1054f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank
1055f33986d5cc248d2eeed0707143d81e94866f8e3aMihai Preda        if (Email.LOGD) {
1056f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler            Log.v(TAG, "EmailProvider.query: uri=" + uri + ", match is " + match);
1057fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blank        }
1058f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler
10590e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank        try {
10600e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank            switch (match) {
10610e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                case BODY:
10620e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                case MESSAGE:
10630e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                case UPDATED_MESSAGE:
10640e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                case DELETED_MESSAGE:
10650e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                case ATTACHMENT:
10660e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                case MAILBOX:
10670e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                case ACCOUNT:
10680e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                case HOSTAUTH:
10690e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                    c = db.query(TABLE_NAMES[table], projection,
10700e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                            selection, selectionArgs, null, null, sortOrder);
10710e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                    break;
10720e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                case BODY_ID:
10730e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                case MESSAGE_ID:
10740e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                case DELETED_MESSAGE_ID:
10750e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                case UPDATED_MESSAGE_ID:
10760e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                case ATTACHMENT_ID:
10770e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                case MAILBOX_ID:
10780e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                case ACCOUNT_ID:
10790e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                case HOSTAUTH_ID:
10800e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                    id = uri.getPathSegments().get(1);
10810e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                    c = db.query(TABLE_NAMES[table], projection,
10820e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                            whereWithId(id, selection), selectionArgs, null, null, sortOrder);
10830e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                    break;
10840e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                case ATTACHMENTS_MESSAGE_ID:
10850e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                    // All attachments for the given message
10860e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                    id = uri.getPathSegments().get(2);
10870e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                    c = db.query(Attachment.TABLE_NAME, projection,
10880e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                            whereWith(Attachment.MESSAGE_KEY + "=" + id, selection),
10890e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                            selectionArgs, null, null, sortOrder);
10900e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                    break;
10910e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                default:
10920e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                    throw new IllegalArgumentException("Unknown URI " + uri);
10930e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank            }
10940e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank        } catch (SQLiteException e) {
10950e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank            checkDatabases();
10960e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank            throw e;
1097f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler        }
1098f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler
1099f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler        if ((c != null) && !isTemporary()) {
1100f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler            c.setNotificationUri(getContext().getContentResolver(), notificationUri);
1101f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler        }
1102f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler        return c;
1103f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler    }
1104f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler
1105f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler    private String whereWithId(String id, String selection) {
1106f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler        StringBuilder sb = new StringBuilder(256);
1107f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler        sb.append("_id=");
1108f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler        sb.append(id);
1109f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler        if (selection != null) {
11106c21942ec45f561d711b3d74ecca8e62afb735c4Andrew Stadler            sb.append(" AND (");
1111f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler            sb.append(selection);
11126c21942ec45f561d711b3d74ecca8e62afb735c4Andrew Stadler            sb.append(')');
1113f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler        }
1114f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler        return sb.toString();
1115f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler    }
1116f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank
11176c21942ec45f561d711b3d74ecca8e62afb735c4Andrew Stadler    /**
11186c21942ec45f561d711b3d74ecca8e62afb735c4Andrew Stadler     * Combine a locally-generated selection with a user-provided selection
11196c21942ec45f561d711b3d74ecca8e62afb735c4Andrew Stadler     *
11206c21942ec45f561d711b3d74ecca8e62afb735c4Andrew Stadler     * This introduces risk that the local selection might insert incorrect chars
11216c21942ec45f561d711b3d74ecca8e62afb735c4Andrew Stadler     * into the SQL, so use caution.
11226c21942ec45f561d711b3d74ecca8e62afb735c4Andrew Stadler     *
11236c21942ec45f561d711b3d74ecca8e62afb735c4Andrew Stadler     * @param where locally-generated selection, must not be null
11246c21942ec45f561d711b3d74ecca8e62afb735c4Andrew Stadler     * @param selection user-provided selection, may be null
11256c21942ec45f561d711b3d74ecca8e62afb735c4Andrew Stadler     * @return a single selection string
11266c21942ec45f561d711b3d74ecca8e62afb735c4Andrew Stadler     */
1127f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler    private String whereWith(String where, String selection) {
11286c21942ec45f561d711b3d74ecca8e62afb735c4Andrew Stadler        if (selection == null) {
11296c21942ec45f561d711b3d74ecca8e62afb735c4Andrew Stadler            return where;
1130f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler        }
11316c21942ec45f561d711b3d74ecca8e62afb735c4Andrew Stadler        StringBuilder sb = new StringBuilder(where);
11326c21942ec45f561d711b3d74ecca8e62afb735c4Andrew Stadler        sb.append(" AND (");
11336c21942ec45f561d711b3d74ecca8e62afb735c4Andrew Stadler        sb.append(selection);
11346c21942ec45f561d711b3d74ecca8e62afb735c4Andrew Stadler        sb.append(')');
11356c21942ec45f561d711b3d74ecca8e62afb735c4Andrew Stadler
1136f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler        return sb.toString();
1137f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler    }
1138f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank
1139f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler    @Override
1140f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
1141f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler        int match = sURIMatcher.match(uri);
1142a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank        Context context = getContext();
1143cba3a48f97ae2e6d875ac4284a4066da94c922d5Marc Blank        // See the comment at delete(), above
1144a867ebba6233becf2061c80e1c53d7d395a6cffcMarc Blank        SQLiteDatabase db = getDatabase(context);
1145f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler        int table = match >> BASE_SHIFT;
1146626f3e48a4f14c38a973dd2bea2e2debea7637a5Andrew Stadler        int result;
1147a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank
1148f33986d5cc248d2eeed0707143d81e94866f8e3aMihai Preda        if (Email.LOGD) {
1149f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank            Log.v(TAG, "EmailProvider.update: uri=" + uri + ", match is " + match);
1150a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank        }
1151a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank
1152758a532fce2f672673d38b2daa5f67eb757b118bMarc Blank        // We do NOT allow setting of unreadCount via the provider
1153758a532fce2f672673d38b2daa5f67eb757b118bMarc Blank        // This column is maintained via triggers
1154758a532fce2f672673d38b2daa5f67eb757b118bMarc Blank        if (match == MAILBOX_ID || match == MAILBOX) {
1155758a532fce2f672673d38b2daa5f67eb757b118bMarc Blank            values.remove(MailboxColumns.UNREAD_COUNT);
1156758a532fce2f672673d38b2daa5f67eb757b118bMarc Blank        }
1157758a532fce2f672673d38b2daa5f67eb757b118bMarc Blank
11580e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank        // Handle this special case the fastest possible way
11590e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank        if (uri == INTEGRITY_CHECK_URI) {
11600e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank            checkDatabases();
11610e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank            return 0;
11620e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank        }
11630e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank
1164c0c9c33322deecace00a32766e0a1b355aad4b31Marc Blank        String id;
11650e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank        try {
11660e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank            switch (match) {
11670e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                case MAILBOX_ID_ADD_TO_FIELD:
11680e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                case ACCOUNT_ID_ADD_TO_FIELD:
11690e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                    db.beginTransaction();
11700e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                    id = uri.getPathSegments().get(1);
11710e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                    String field = values.getAsString(EmailContent.FIELD_COLUMN_NAME);
11720e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                    Long add = values.getAsLong(EmailContent.ADD_COLUMN_NAME);
11730e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                    if (field == null || add == null) {
11740e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                        throw new IllegalArgumentException("No field/add specified " + uri);
1175c0c9c33322deecace00a32766e0a1b355aad4b31Marc Blank                    }
11760e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                    Cursor c = db.query(TABLE_NAMES[table],
11770e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                            new String[] {EmailContent.RECORD_ID, field},
11780e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                            whereWithId(id, selection),
11790e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                            selectionArgs, null, null, null);
11800e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                    try {
11810e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                        result = 0;
11820e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                        ContentValues cv = new ContentValues();
11830e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                        String[] bind = new String[1];
11840e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                        while (c.moveToNext()) {
11850e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                            bind[0] = c.getString(0);
11860e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                            long value = c.getLong(1) + add;
11870e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                            cv.put(field, value);
11880e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                            result = db.update(TABLE_NAMES[table], cv, ID_EQUALS, bind);
11890e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                        }
11900e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                    } finally {
11910e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                        c.close();
11920e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                    }
11930e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                    db.setTransactionSuccessful();
11940e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                    db.endTransaction();
11950e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                    break;
11960e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                case BODY_ID:
11970e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                case MESSAGE_ID:
11980e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                case SYNCED_MESSAGE_ID:
11990e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                case UPDATED_MESSAGE_ID:
12000e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                case ATTACHMENT_ID:
12010e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                case MAILBOX_ID:
12020e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                case ACCOUNT_ID:
12030e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                case HOSTAUTH_ID:
12040e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                    id = uri.getPathSegments().get(1);
12050e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                    if (match == SYNCED_MESSAGE_ID) {
12060e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                        // For synced messages, first copy the old message to the updated table
12070e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                        // Note the insert or ignore semantics, guaranteeing that only the first
12080e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                        // update will be reflected in the updated message table; therefore this row
12090e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                        // will always have the "original" data
12100e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                        db.execSQL(UPDATED_MESSAGE_INSERT + id);
12110e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                    } else if (match == MESSAGE_ID) {
12120e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                        db.execSQL(UPDATED_MESSAGE_DELETE + id);
12130e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                    }
12140e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                    result = db.update(TABLE_NAMES[table], values, whereWithId(id, selection),
12150e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                            selectionArgs);
12160e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                    break;
12170e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                case BODY:
12180e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                case MESSAGE:
12190e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                case UPDATED_MESSAGE:
12200e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                case ATTACHMENT:
12210e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                case MAILBOX:
12220e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                case ACCOUNT:
12230e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                case HOSTAUTH:
12240e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                    result = db.update(TABLE_NAMES[table], values, selection, selectionArgs);
12250e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                    break;
12260e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                default:
12270e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank                    throw new IllegalArgumentException("Unknown URI " + uri);
12280e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank            }
12290e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank        } catch (SQLiteException e) {
12300e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank            checkDatabases();
12310e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank            throw e;
1232fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blank        }
1233a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank
1234626f3e48a4f14c38a973dd2bea2e2debea7637a5Andrew Stadler        getContext().getContentResolver().notifyChange(uri, null);
1235626f3e48a4f14c38a973dd2bea2e2debea7637a5Andrew Stadler        return result;
1236fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blank    }
1237f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank
1238fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blank    /* (non-Javadoc)
123984969fb580f569c0e3625a3c59a71d2909ae198dFred Quintana     * @see android.content.ContentProvider#applyBatch(android.content.ContentProviderOperation)
1240fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blank     */
1241758a532fce2f672673d38b2daa5f67eb757b118bMarc Blank    @Override
124284969fb580f569c0e3625a3c59a71d2909ae198dFred Quintana    public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations)
1243b6493a07ef625c0e290890c2e60256b47a066e5eMarc Blank            throws OperationApplicationException {
1244cba3a48f97ae2e6d875ac4284a4066da94c922d5Marc Blank        Context context = getContext();
1245cba3a48f97ae2e6d875ac4284a4066da94c922d5Marc Blank        SQLiteDatabase db = getDatabase(context);
1246fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blank        db.beginTransaction();
1247fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blank        try {
1248fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blank            ContentProviderResult[] results = super.applyBatch(operations);
1249fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blank            db.setTransactionSuccessful();
1250fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blank            return results;
1251fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blank        } finally {
1252fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blank            db.endTransaction();
1253f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler        }
1254f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler    }
1255f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler}
1256