EmailSyncAdapter.java revision ab30d429e0c6069604aead9b5e6845b6b91b6a02
1ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank/* 2ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank * Copyright (C) 2008-2009 Marc Blank 3ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank * Licensed to The Android Open Source Project. 4ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank * 5ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank * Licensed under the Apache License, Version 2.0 (the "License"); 6ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank * you may not use this file except in compliance with the License. 7ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank * You may obtain a copy of the License at 8ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank * 9ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank * http://www.apache.org/licenses/LICENSE-2.0 10ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank * 11ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank * Unless required by applicable law or agreed to in writing, software 12ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank * distributed under the License is distributed on an "AS IS" BASIS, 13ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank * See the License for the specific language governing permissions and 15ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank * limitations under the License. 16ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank */ 17ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank 18ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blankpackage com.android.exchange.adapter; 19ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank 20ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blankimport java.io.ByteArrayInputStream; 21ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blankimport java.io.IOException; 22ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blankimport java.io.InputStream; 23ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blankimport java.util.ArrayList; 24ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blankimport java.util.GregorianCalendar; 25ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blankimport java.util.TimeZone; 26ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank 27ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blankimport android.content.ContentProviderOperation; 28ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blankimport android.content.ContentResolver; 29ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blankimport android.content.ContentUris; 30ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blankimport android.content.ContentValues; 31ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blankimport android.content.OperationApplicationException; 32ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blankimport android.database.Cursor; 33ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blankimport android.os.RemoteException; 34ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank 35ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blankimport com.android.email.provider.EmailProvider; 36ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blankimport com.android.exchange.EasSyncService; 37ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blankimport com.android.exchange.EmailContent.Attachment; 38ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blankimport com.android.exchange.EmailContent.Mailbox; 39ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blankimport com.android.exchange.EmailContent.Message; 40ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blankimport com.android.exchange.EmailContent.MessageColumns; 41ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blankimport com.android.exchange.EmailContent.SyncColumns; 42ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank 43ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank/** 44ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank * Sync adapter for EAS email 45ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank * 46ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank */ 47ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blankpublic class EasEmailSyncAdapter extends EasSyncAdapter { 48ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank 49ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank private static final String[] UPDATES_PROJECTION = {MessageColumns.FLAG_READ}; 50ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank 51ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank ArrayList<Long> mDeletedIdList = new ArrayList<Long>(); 52ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank 53ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank ArrayList<Long> mUpdatedIdList = new ArrayList<Long>(); 54ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank 55ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank public EasEmailSyncAdapter(Mailbox mailbox) { 56ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank super(mailbox); 57ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 58ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank 59ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank @Override 60ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank public boolean parse(ByteArrayInputStream is, EasSyncService service) throws IOException { 61ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank EasEmailSyncParser p = new EasEmailSyncParser(is, service); 62ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank return p.parse(); 63ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 64ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank 65ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank class EasEmailSyncParser extends EasContentParser { 66ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank 67ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank private static final String WHERE_SERVER_ID_AND_MAILBOX_KEY = 68ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank SyncColumns.SERVER_ID + "=? and " + MessageColumns.MAILBOX_KEY + "=?"; 69ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank 70ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank private String mMailboxIdAsString; 71ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank 72ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank String[] bindArguments = new String[2]; 73ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank 74ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank public EasEmailSyncParser(InputStream in, EasSyncService service) throws IOException { 75ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank super(in, service); 76ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank mMailboxIdAsString = Long.toString(mMailbox.mId); 77ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank //setDebug(true); // DON'T CHECK IN WITH THIS 78ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 79ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank 80ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank public void wipe() { 81ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank mContentResolver.delete(Message.CONTENT_URI, 82ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank Message.MAILBOX_KEY + "=" + mMailbox.mId, null); 83ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank mContentResolver.delete(Message.DELETED_CONTENT_URI, 84ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank Message.MAILBOX_KEY + "=" + mMailbox.mId, null); 85ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank mContentResolver.delete(Message.UPDATED_CONTENT_URI, 86ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank Message.MAILBOX_KEY + "=" + mMailbox.mId, null); 87ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 88ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank 89ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank public void addData (Message msg) throws IOException { 90ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank String to = ""; 91ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank String from = ""; 92ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank String cc = ""; 93ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank String replyTo = ""; 94ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank int size = 0; 95ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank 96ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank ArrayList<Attachment> atts = new ArrayList<Attachment>(); 97ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank 98ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank while (nextTag(EasTags.SYNC_APPLICATION_DATA) != END) { 99ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank switch (tag) { 100ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank case EasTags.EMAIL_ATTACHMENTS: 101ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank break; 102ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank case EasTags.EMAIL_ATTACHMENT: 103ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank attachmentParser(atts, msg); 104ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank break; 105ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank case EasTags.EMAIL_TO: 106ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank to = getValue(); 107ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank break; 108ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank case EasTags.EMAIL_FROM: 109ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank from = getValue(); 110ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank String sender = from; 111ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank int q = from.indexOf('\"'); 112ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank if (q >= 0) { 113ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank int qq = from.indexOf('\"', q + 1); 114ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank if (qq > 0) { 115ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank sender = from.substring(q + 1, qq); 116ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 117ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 118ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank msg.mDisplayName = sender; 119ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank break; 120ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank case EasTags.EMAIL_CC: 121ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank cc = getValue(); 122ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank break; 123ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank case EasTags.EMAIL_REPLY_TO: 124ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank replyTo = getValue(); 125ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank break; 126ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank case EasTags.EMAIL_DATE_RECEIVED: 127ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank String date = getValue(); 128ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank // 2009-02-11T18:03:03.627Z 129ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank GregorianCalendar cal = new GregorianCalendar(); 130ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank cal.set(Integer.parseInt(date.substring(0, 4)), Integer.parseInt(date 131ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank .substring(5, 7)) - 1, Integer.parseInt(date.substring(8, 10)), 132ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank Integer.parseInt(date.substring(11, 13)), Integer.parseInt(date 133ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank .substring(14, 16)), Integer.parseInt(date 134ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank .substring(17, 19))); 135ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank cal.setTimeZone(TimeZone.getTimeZone("GMT")); 136ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank msg.mTimeStamp = cal.getTimeInMillis(); 137ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank break; 138ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank case EasTags.EMAIL_SUBJECT: 139ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank msg.mSubject = getValue(); 140ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank break; 141ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank case EasTags.EMAIL_READ: 142ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank msg.mFlagRead = getValueInt() == 1; 143ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank break; 144ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank case EasTags.EMAIL_BODY: 145ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank msg.mTextInfo = "X;X;8;" + size; // location;encoding;charset;size 146ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank msg.mText = getValue(); 147ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank // For now... 148ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank msg.mPreview = "Fake preview"; // Messages.previewFromText(body); 149ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank break; 150ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank default: 151ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank skipTag(); 152ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 153ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 154ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank 155ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank msg.mTo = to; 156ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank msg.mFrom = from; 157ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank msg.mCc = cc; 158ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank msg.mReplyTo = replyTo; 159ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank if (atts.size() > 0) { 160ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank msg.mAttachments = atts; 161ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 162ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank 163ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 164ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank 165ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank public void addParser(ArrayList<Message> emails) throws IOException { 166ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank Message msg = new Message(); 167ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank msg.mAccountKey = mAccount.mId; 168ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank msg.mMailboxKey = mMailbox.mId; 169ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank msg.mFlagLoaded = Message.LOADED; 170ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank 171ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank while (nextTag(EasTags.SYNC_ADD) != END) { 172ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank switch (tag) { 173ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank case EasTags.SYNC_SERVER_ID: 174ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank msg.mServerId = getValue(); 175ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank break; 176ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank case EasTags.SYNC_APPLICATION_DATA: 177ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank addData(msg); 178ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank break; 179ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank default: 180ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank skipTag(); 181ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 182ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 183ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank 184ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank // Tell the provider that this is synced back 185ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank msg.mServerVersion = mMailbox.mSyncKey; 186ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank emails.add(msg); 187ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 188ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank 189ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank public void attachmentParser(ArrayList<Attachment> atts, Message msg) throws IOException { 190ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank String fileName = null; 191ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank String length = null; 192ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank String lvl = null; 193ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank 194ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank while (nextTag(EasTags.EMAIL_ATTACHMENT) != END) { 195ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank switch (tag) { 196ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank case EasTags.EMAIL_DISPLAY_NAME: 197ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank fileName = getValue(); 198ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank break; 199ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank case EasTags.EMAIL_ATT_NAME: 200ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank lvl = getValue(); 201ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank break; 202ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank case EasTags.EMAIL_ATT_SIZE: 203ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank length = getValue(); 204ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank break; 205ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank default: 206ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank skipTag(); 207ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 208ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 209ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank 210ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank if (fileName != null && length != null && lvl != null) { 211ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank Attachment att = new Attachment(); 212ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank att.mEncoding = "base64"; 213ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank att.mSize = Long.parseLong(length); 214ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank att.mFileName = fileName; 215ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank atts.add(att); 216ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank msg.mFlagAttachment = true; 217ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 218ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 219ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank 220ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank private Cursor getServerIdCursor(String serverId, String[] projection) { 221ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank bindArguments[0] = serverId; 222ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank bindArguments[1] = mMailboxIdAsString; 223ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank return mContentResolver.query(Message.CONTENT_URI, projection, 224ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank WHERE_SERVER_ID_AND_MAILBOX_KEY, bindArguments, null); 225ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 226ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank 227ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank public void deleteParser(ArrayList<Long> deletes) throws IOException { 228ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank while (nextTag(EasTags.SYNC_DELETE) != END) { 229ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank switch (tag) { 230ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank case EasTags.SYNC_SERVER_ID: 231ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank String serverId = getValue(); 232ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank // Find the message in this mailbox with the given serverId 233ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank Cursor c = getServerIdCursor(serverId, Message.ID_COLUMN_PROJECTION); 234ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank try { 235ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank if (c.moveToFirst()) { 236ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank mService.userLog("Deleting " + serverId); 237ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank deletes.add(c.getLong(Message.ID_COLUMNS_ID_COLUMN)); 238ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 239ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } finally { 240ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank c.close(); 241ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 242ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank break; 243ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank default: 244ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank skipTag(); 245ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 246ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 247ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 248ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank 249ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank class ServerChange { 250ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank long id; 251ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank boolean read; 252ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank 253ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank ServerChange(long _id, boolean _read) { 254ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank id = _id; 255ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank read = _read; 256ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 257ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 258ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank 259ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank public void changeParser(ArrayList<ServerChange> changes) throws IOException { 260ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank String serverId = null; 261ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank boolean oldRead = false; 262ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank boolean read = true; 263ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank long id = 0; 264ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank while (nextTag(EasTags.SYNC_CHANGE) != END) { 265ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank switch (tag) { 266ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank case EasTags.SYNC_SERVER_ID: 267ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank serverId = getValue(); 268ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank Cursor c = getServerIdCursor(serverId, Message.LIST_PROJECTION); 269ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank try { 270ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank if (c.moveToFirst()) { 271ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank mService.userLog("Changing " + serverId); 272ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank oldRead = c.getInt(Message.LIST_READ_COLUMN) == Message.READ; 273ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank id = c.getLong(Message.LIST_ID_COLUMN); 274ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 275ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } finally { 276ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank c.close(); 277ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 278ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank break; 279ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank case EasTags.EMAIL_READ: 280ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank read = getValueInt() == 1; 281ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank break; 282ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank case EasTags.SYNC_APPLICATION_DATA: 283ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank break; 284ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank default: 285ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank skipTag(); 286ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 287ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 288ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank if (oldRead != read) { 289ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank changes.add(new ServerChange(id, read)); 290ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 291ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 292ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank 293ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank public void commandsParser() throws IOException { 294ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank ArrayList<Message> newEmails = new ArrayList<Message>(); 295ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank ArrayList<Long> deletedEmails = new ArrayList<Long>(); 296ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank ArrayList<ServerChange> changedEmails = new ArrayList<ServerChange>(); 297ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank 298ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank while (nextTag(EasTags.SYNC_COMMANDS) != END) { 299ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank if (tag == EasTags.SYNC_ADD) { 300ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank addParser(newEmails); 301ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } else if (tag == EasTags.SYNC_DELETE) { 302ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank deleteParser(deletedEmails); 303ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } else if (tag == EasTags.SYNC_CHANGE) { 304ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank changeParser(changedEmails); 305ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } else 306ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank skipTag(); 307ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 308ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank 309ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank // Use a batch operation to handle the changes 310ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank // TODO New mail notifications? Who looks for these? 311ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>(); 312ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank for (Message content : newEmails) { 313ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank content.addSaveOps(ops); 314ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 315ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank for (Long id : deletedEmails) { 316ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank ops.add(ContentProviderOperation.newDelete( 317ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank ContentUris.withAppendedId(Message.CONTENT_URI, id)).build()); 318ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 319ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank if (!changedEmails.isEmpty()) { 320ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank // Server wins in a conflict... 321ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank for (ServerChange change : changedEmails) { 322ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank // For now, don't handle read->unread 323ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank ContentValues cv = new ContentValues(); 324ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank cv.put(MessageColumns.FLAG_READ, change.read); 325ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank ops.add(ContentProviderOperation.newUpdate( 326ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank ContentUris.withAppendedId(Message.CONTENT_URI, change.id)) 327ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank .withValues(cv) 328ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank .build()); 329ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 330ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 331ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank ops.add(ContentProviderOperation.newUpdate( 332ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank ContentUris.withAppendedId(Mailbox.CONTENT_URI, mMailbox.mId)).withValues( 333ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank mMailbox.toContentValues()).build()); 334ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank 335ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank // If we've sent local deletions, clear out the deleted table 336ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank for (Long id: mDeletedIdList) { 337ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank ops.add(ContentProviderOperation.newDelete( 338ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank ContentUris.withAppendedId(Message.DELETED_CONTENT_URI, id)).build()); 339ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 340ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank 341ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank try { 342ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank mService.mContext.getContentResolver() 343ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank .applyBatch(EmailProvider.EMAIL_AUTHORITY, ops); 344ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } catch (RemoteException e) { 345ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank // There is nothing to be done here; fail by returning null 346ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } catch (OperationApplicationException e) { 347ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank // There is nothing to be done here; fail by returning null 348ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 349ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank 350ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank mService.userLog("SyncKey confirmed as: " + mMailbox.mSyncKey); 351ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 352ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 353ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank 354ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank @Override 355ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank public String getCollectionName() { 356ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank return "Email"; 357ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 358ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank 359ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank @Override 360ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank public boolean sendLocalChanges(EasSerializer s, EasSyncService service) throws IOException { 361ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank ContentResolver cr = service.mContext.getContentResolver(); 362ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank 363ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank // Find any of our deleted items 364ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank Cursor c = cr.query(Message.DELETED_CONTENT_URI, Message.LIST_PROJECTION, 365ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank MessageColumns.MAILBOX_KEY + '=' + mMailbox.mId, null, null); 366ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank boolean first = true; 367ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank // We keep track of the list of deleted item id's so that we can remove them from the 368ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank // deleted table after the server receives our command 369ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank mDeletedIdList.clear(); 370ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank try { 371ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank while (c.moveToNext()) { 372ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank if (first) { 373ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank s.start("Commands"); 374ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank first = false; 375ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 376ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank // Send the command to delete this message 377ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank s.start("Delete") 378ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank .data("ServerId", c.getString(Message.LIST_SERVER_ID_COLUMN)) 379ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank .end("Delete"); 380ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank mDeletedIdList.add(c.getLong(Message.LIST_ID_COLUMN)); 381ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 382ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } finally { 383ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank c.close(); 384ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 385ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank 386ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank // Do the same now for updated items 387ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank c = cr.query(Message.UPDATED_CONTENT_URI, Message.LIST_PROJECTION, 388ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank MessageColumns.MAILBOX_KEY + '=' + mMailbox.mId, null, null); 389ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank // We keep track of the list of updated item id's so that we can remove them from the 390ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank // deleted table after the server receives our command 391ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank mUpdatedIdList.clear(); 392ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank try { 393ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank while (c.moveToNext()) { 394ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank long id = c.getLong(Message.LIST_ID_COLUMN); 395ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank // Say we've handled this update 396ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank mUpdatedIdList.add(id); 397ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank // We have the id of the changed item. But first, we have to find out its current 398ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank // state, since the updated table saves the opriginal state 399ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank Cursor currentCursor = cr.query(ContentUris.withAppendedId(Message.CONTENT_URI, id), 400ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank UPDATES_PROJECTION, null, null, null); 401ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank try { 402ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank // If this item no longer exists (shouldn't be possible), just move along 403ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank if (!currentCursor.moveToFirst()) { 404ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank continue; 405ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 406ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank int read = currentCursor.getInt(0); 407ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank if (read == c.getInt(Message.LIST_READ_COLUMN)) { 408ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank // The read state hasn't really changed, so move on... 409ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank continue; 410ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 411ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank if (first) { 412ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank s.start("Commands"); 413ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank first = false; 414ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 415ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank // Send the change to "read". We'll do "flagged" here eventually as well 416ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank // TODO Add support for flags here (EAS 12.0 and above) 417ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank s.start("Change") 418ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank .data("ServerId", c.getString(Message.LIST_SERVER_ID_COLUMN)) 419ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank .start("ApplicationData") 420ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank .data("Read", Integer.toString(read)) 421ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank .end("ApplicationData") 422ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank .end("Change"); 423ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } finally { 424ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank currentCursor.close(); 425ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 426ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 427ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } finally { 428ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank c.close(); 429ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 430ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank 431ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank if (!first) { 432ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank s.end("Commands"); 433ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 434ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank return false; 435ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 436ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank} 437