From 8bf95c1244e3bbde9f985b0f70ee3a135bf52e46 Mon Sep 17 00:00:00 2001 From: Vitaly Polonetsky Date: Tue, 26 Jul 2011 00:57:27 +0300 Subject: [PATCH] using sync mode, instead of GetItemEstimate, which is not reliable working read/unread sync adapters cleanups --- .../k9/controller/MessagingController.java | 4 +- src/com/fsck/k9/mail/store/EasStore.java | 158 ++- .../exchange/adapter/AbstractSyncAdapter.java | 94 -- .../exchange/adapter/AbstractSyncParser.java | 12 +- .../exchange/adapter/AccountSyncAdapter.java | 37 - .../exchange/adapter/EasEmailSyncParser.java | 564 +++++++++++ .../exchange/adapter/EmailSyncAdapter.java | 905 ------------------ .../exchange/adapter/FolderSyncParser.java | 38 +- .../adapter/GetItemEstimateParser.java | 67 -- 9 files changed, 641 insertions(+), 1238 deletions(-) delete mode 100644 src/com/fsck/k9/mail/store/exchange/adapter/AbstractSyncAdapter.java delete mode 100644 src/com/fsck/k9/mail/store/exchange/adapter/AccountSyncAdapter.java create mode 100644 src/com/fsck/k9/mail/store/exchange/adapter/EasEmailSyncParser.java delete mode 100644 src/com/fsck/k9/mail/store/exchange/adapter/EmailSyncAdapter.java delete mode 100644 src/com/fsck/k9/mail/store/exchange/adapter/GetItemEstimateParser.java diff --git a/src/com/fsck/k9/controller/MessagingController.java b/src/com/fsck/k9/controller/MessagingController.java index 5c27dee41..fdd0ffbf1 100644 --- a/src/com/fsck/k9/controller/MessagingController.java +++ b/src/com/fsck/k9/controller/MessagingController.java @@ -940,6 +940,8 @@ public class MessagingController implements Runnable { * Get the remote message count. */ int remoteMessageCount = remoteFolder.getMessageCount(); + + boolean syncMode = remoteFolder.isSyncMode(); int visibleLimit = localFolder.getVisibleLimit(); @@ -956,7 +958,7 @@ public class MessagingController implements Runnable { final Date earliestDate = account.getEarliestPollDate(); - if (remoteMessageCount > 0) { + if (remoteMessageCount > 0 || syncMode) { /* Message numbers start at 1. */ int remoteStart; if (visibleLimit > 0) { diff --git a/src/com/fsck/k9/mail/store/EasStore.java b/src/com/fsck/k9/mail/store/EasStore.java index 9955939e0..793de8cdd 100644 --- a/src/com/fsck/k9/mail/store/EasStore.java +++ b/src/com/fsck/k9/mail/store/EasStore.java @@ -22,21 +22,17 @@ import org.apache.http.Header; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.HttpStatus; -import org.apache.http.client.CookieStore; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpOptions; import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpRequestBase; -import org.apache.http.client.protocol.ClientContext; import org.apache.http.conn.scheme.Scheme; import org.apache.http.conn.scheme.SchemeRegistry; import org.apache.http.entity.ByteArrayEntity; -import org.apache.http.entity.InputStreamEntity; import org.apache.http.entity.StringEntity; -import org.apache.http.impl.client.BasicCookieStore; import org.apache.http.impl.client.DefaultHttpClient; -import org.apache.http.protocol.BasicHttpContext; -import org.apache.http.protocol.HttpContext; +import org.apache.http.params.HttpConnectionParams; +import org.apache.http.params.HttpParams; import android.content.Context; import android.text.TextUtils; @@ -54,15 +50,11 @@ import com.fsck.k9.mail.Folder; import com.fsck.k9.mail.Message; import com.fsck.k9.mail.MessagingException; import com.fsck.k9.mail.Store; -import com.fsck.k9.mail.Folder.OpenMode; import com.fsck.k9.mail.filter.EOLConvertingOutputStream; import com.fsck.k9.mail.internet.MimeMessage; import com.fsck.k9.mail.store.exchange.Eas; -import com.fsck.k9.mail.store.exchange.adapter.AbstractSyncAdapter; -import com.fsck.k9.mail.store.exchange.adapter.AccountSyncAdapter; -import com.fsck.k9.mail.store.exchange.adapter.EmailSyncAdapter; +import com.fsck.k9.mail.store.exchange.adapter.EasEmailSyncParser; import com.fsck.k9.mail.store.exchange.adapter.FolderSyncParser; -import com.fsck.k9.mail.store.exchange.adapter.GetItemEstimateParser; import com.fsck.k9.mail.store.exchange.adapter.ProvisionParser; import com.fsck.k9.mail.store.exchange.adapter.Serializer; import com.fsck.k9.mail.store.exchange.adapter.Tags; @@ -93,6 +85,8 @@ public class EasStore extends Store { // IOException is thrown. After a small added allowance, our watchdog alarm goes off (allowing // us to detect a silently dropped connection). The allowance is defined below. static private final int COMMAND_TIMEOUT = 30*1000; + // Connection timeout is the time given to connect to the server before reporting an IOException + static private final int CONNECTION_TIMEOUT = 20*1000; // This needs to be long enough to send the longest reasonable message, without being so long // as to effectively "hang" sending of mail. The standard 30 second timeout isn't long enough @@ -132,9 +126,7 @@ public class EasStore extends Store { private boolean mSecure; private HttpClient mHttpClient = null; - private HttpContext mContext = null; private String mAuthString; - private CookieStore mAuthCookies = null; private Folder mSendFolder = null; private HashMap mFolderList = new HashMap(); @@ -297,7 +289,6 @@ public class EasStore extends Store { // account.setName("%TestAccount%"); // account.setStoreUri(mUri.toString()); EasStore svc = new EasStore(mAccount); - svc.mContext = mContext; svc.mHost = hostAddress; svc.mUsername = userName; svc.mPassword = password; @@ -531,6 +522,7 @@ public class EasStore extends Store { */ protected HttpResponse executePostWithTimeout(HttpClient client, HttpPost method, int timeout, boolean isPingCommand) throws IOException { + HttpConnectionParams.setSoTimeout(method.getParams(), timeout); // synchronized(getSynchronizer()) { // mPendingPost = method; // long alarmTime = timeout + WATCHDOG_TIMEOUT_ALLOWANCE; @@ -590,10 +582,13 @@ public class EasStore extends Store { String us = makeUriString("OPTIONS", null); HttpOptions method = new HttpOptions(URI.create(us)); setHeaders(method, false); + + HttpConnectionParams.setSoTimeout(method.getParams(), COMMAND_TIMEOUT); + return client.execute(method); } - /** + /** * Set standard HTTP headers, using a policy key if required * @param method the method we are going to send * @param usePolicyKey whether or not a policy key should be sent in the headers @@ -704,7 +699,7 @@ public class EasStore extends Store { if (len != 0) { InputStream is = entity.getContent(); // Returns true if we need to sync again - if (new FolderSyncParser(is, new AccountSyncAdapter(mAccount), this, folderList) + if (new FolderSyncParser(is, this, folderList) .parse()) { throw new RuntimeException(); } @@ -784,10 +779,6 @@ public class EasStore extends Store { * Authentication related methods */ - public CookieStore getAuthCookies() { - return mAuthCookies; - } - public String getAlias() { return mAlias; } @@ -799,13 +790,14 @@ public class EasStore extends Store { public HttpClient getHttpClient() throws MessagingException { if (mHttpClient == null) { mHttpClient = new DefaultHttpClient(); + + HttpParams params = mHttpClient.getParams(); + // Disable automatDic redirects on the http client. - mHttpClient.getParams().setBooleanParameter("http.protocol.handle-redirects", false); + params.setBooleanParameter("http.protocol.handle-redirects", false); - // Setup a cookie store for forms-based authentication. - mContext = new BasicHttpContext(); - mAuthCookies = new BasicCookieStore(); - mContext.setAttribute(ClientContext.COOKIE_STORE, mAuthCookies); + HttpConnectionParams.setConnectionTimeout(params, CONNECTION_TIMEOUT); + HttpConnectionParams.setSocketBufferSize(params, 8192); SchemeRegistry reg = mHttpClient.getConnectionManager().getSchemeRegistry(); try { @@ -898,9 +890,17 @@ public class EasStore extends Store { this.mType = type; } - public String getSyncKey() { + public String getSyncKeyUnmodified() { return mSyncKey; } + + public String getSyncKey() { + if (mSyncKey == null) { + Log.d(K9.LOG_TAG, "Reset SyncKey to 0"); + mSyncKey = "0"; + } + return mSyncKey; + } public void setSyncKey(String mSyncKey) { this.mSyncKey = mSyncKey; @@ -964,45 +964,12 @@ public class EasStore extends Store { // processRequest(mFolderUrl, action, messageBody, headers, false); } - private int getMessageCount(boolean read) throws MessagingException { - Serializer s = new Serializer(); - try { - s - .start(Tags.GIE_GET_ITEM_ESTIMATE) - .start(Tags.GIE_COLLECTIONS) - .start(Tags.GIE_COLLECTION) - .data(Tags.SYNC_SYNC_KEY, "0") - .data(Tags.GIE_COLLECTION_ID, mServerId) - .end() - .end() - .end() - .done(); - - HttpResponse resp = sendHttpClientPost("GetItemEstimate", s.toByteArray()); - int code = resp.getStatusLine().getStatusCode(); - if (code == HttpStatus.SC_OK) { - HttpEntity entity = resp.getEntity(); - int len = (int)entity.getContentLength(); - if (len != 0) { - InputStream is = entity.getContent(); - GetItemEstimateParser gieParser = new GetItemEstimateParser(is); - if (gieParser.parse()) { - return gieParser.getEstimate(); - } - } - } - // On failures - throw new MessagingException("getItemEstimate call returned not OK status"); - } catch (IOException e) { - throw new MessagingException("getItemEstimate call failed", e); - } - } - @Override public int getMessageCount() throws MessagingException { open(OpenMode.READ_WRITE); - this.mMessageCount = getMessageCount(true); - return this.mMessageCount; + return -1; +// this.mMessageCount = getMessageCount(true); +// return this.mMessageCount; } @Override @@ -1060,9 +1027,9 @@ public class EasStore extends Store { public Message[] getMessages(int start, int end, Date earliestDate, MessageRetrievalListener listener) throws MessagingException { try { - EmailSyncAdapter target = getMessagesInternal(null, null, null, start, end); + EasEmailSyncParser syncParser = getMessagesInternal(null, null, null, start, end); - List messages = target.getMessages(); + List messages = syncParser.getMessages(); return messages.toArray(EMPTY_MESSAGE_ARRAY); } catch (IOException e) { @@ -1070,15 +1037,16 @@ public class EasStore extends Store { } } - private EmailSyncAdapter getMessagesInternal(Message[] messages, FetchProfile fp, MessageRetrievalListener listener, + private EasEmailSyncParser getMessagesInternal(Message[] messages, FetchProfile fp, MessageRetrievalListener listener, int start, int end) throws IOException, MessagingException { Serializer s = new Serializer(); - EmailSyncAdapter target = new EmailSyncAdapter(this, mAccount); + EasEmailSyncParser syncParser = null; +// EmailSyncAdapter target = new EmailSyncAdapter(this, mAccount); - String className = target.getCollectionName(); - String syncKey = target.getSyncKey(); + String className = "Email"; + String syncKey = getSyncKey(); // userLog("sync, sending ", className, " syncKey: ", syncKey); s.start(Tags.SYNC_SYNC) .start(Tags.SYNC_COLLECTIONS) @@ -1102,7 +1070,7 @@ public class EasStore extends Store { if (messages == null) { s.tag(Tags.SYNC_GET_CHANGES); - s.data(Tags.SYNC_WINDOW_SIZE, Integer.toString(end - start + 1)); +// s.data(Tags.SYNC_WINDOW_SIZE, Integer.toString(end - start + 1)); } // Handle options s.start(Tags.SYNC_OPTIONS); @@ -1162,22 +1130,10 @@ public class EasStore extends Store { if (code == HttpStatus.SC_OK) { InputStream is = resp.getEntity().getContent(); if (is != null) { - boolean moreAvailable = target.parse(is); -// int loopingCount = 0; -// if (target.isLooping()) { -// loopingCount ++; -// Log.d(K9.LOG_TAG, "** Looping: " + loopingCount); -// // After the maximum number of loops, we'll set moreAvailable to false and -// // allow the sync loop to terminate -// if (moreAvailable && (loopingCount > MAX_LOOPING_COUNT)) { -// Log.d(K9.LOG_TAG, "** Looping force stopped"); -// moreAvailable = false; -// } -// } else { -// loopingCount = 0; -// } - target.cleanup(); + syncParser = new EasEmailSyncParser(is, this, mAccount); + boolean moreAvailable = syncParser.parse(); + if (moreAvailable && syncKey.equals("0")) { return getMessagesInternal(messages, fp, listener, start, end); } @@ -1196,7 +1152,7 @@ public class EasStore extends Store { // return; throw new MessagingException("not ok status"); } - return target; + return syncParser; } private String getEmailFilter() { @@ -1280,8 +1236,8 @@ public class EasStore extends Store { boolean fetchBody = fp.contains(FetchProfile.Item.BODY); if (fetchBodySane || fetchBody) { try { - EmailSyncAdapter target = getMessagesInternal(messages, fp, listener, -1, -1); - messages = target.getMessages().toArray(EMPTY_MESSAGE_ARRAY); + EasEmailSyncParser syncParser = getMessagesInternal(messages, fp, listener, -1, -1); + messages = syncParser.getMessages().toArray(EMPTY_MESSAGE_ARRAY); } catch (IOException e) { throw new MessagingException("io exception while fetching messages", e); } @@ -1324,8 +1280,6 @@ public class EasStore extends Store { } private void markServerMessagesRead(final String[] uids, final boolean read) throws MessagingException { - EmailSyncAdapter target = new EmailSyncAdapter(this, mAccount); - new SyncCommand() { @Override void prepareCommand(Serializer s) throws IOException { @@ -1340,12 +1294,10 @@ public class EasStore extends Store { } s.end(); } - }.send(target, mServerId); + }.send(this); } private void deleteServerMessages(final String[] uids) throws MessagingException { - EmailSyncAdapter target = new EmailSyncAdapter(this, mAccount); - new SyncCommand() { @Override void prepareCommand(Serializer s) throws IOException { @@ -1359,7 +1311,7 @@ public class EasStore extends Store { } s.end(); } - }.send(target, mServerId); + }.send(this); } @Override @@ -1432,11 +1384,11 @@ public class EasStore extends Store { private abstract class SyncCommand { - public void send(AbstractSyncAdapter target, String folderServerId) throws MessagingException { + public void send(EasFolder folder) throws MessagingException { try { int timeout = COMMAND_TIMEOUT; - byte[] byteArr = prepare(target, folderServerId); + byte[] byteArr = prepare(folder); HttpResponse resp = sendHttpClientPost("Sync", new ByteArrayEntity(byteArr), timeout); @@ -1444,7 +1396,8 @@ public class EasStore extends Store { if (code == HttpStatus.SC_OK) { InputStream is = resp.getEntity().getContent(); if (is != null) { - target.cleanup(); + EasEmailSyncParser syncParser = new EasEmailSyncParser(is, folder, folder.getAccount()); + parseResponse(syncParser, is); } else { Log.d(K9.LOG_TAG, "Empty input stream in sync command response"); } @@ -1456,17 +1409,18 @@ public class EasStore extends Store { } } - byte[] prepare(AbstractSyncAdapter target, String folderServerId) throws IOException { + byte[] prepare(EasFolder folder) throws IOException { Serializer s = new Serializer(); - String className = target.getCollectionName(); - String syncKey = target.getSyncKey(); + String className = "Email"; + String syncKey = folder.getSyncKey(); + String folderServerId = folder.mServerId; s.start(Tags.SYNC_SYNC) .start(Tags.SYNC_COLLECTIONS) .start(Tags.SYNC_COLLECTION) .data(Tags.SYNC_CLASS, className) .data(Tags.SYNC_SYNC_KEY, syncKey) - .data(Tags.SYNC_COLLECTION_ID, folderServerId); + .data(Tags.SYNC_COLLECTION_ID, folderServerId ); prepareCommand(s); @@ -1477,6 +1431,10 @@ public class EasStore extends Store { abstract void prepareCommand(Serializer s) throws IOException; + void parseResponse(EasEmailSyncParser syncParser, InputStream is) throws IOException, MessagingException { + syncParser.parse(); + } + } } diff --git a/src/com/fsck/k9/mail/store/exchange/adapter/AbstractSyncAdapter.java b/src/com/fsck/k9/mail/store/exchange/adapter/AbstractSyncAdapter.java deleted file mode 100644 index de82a01a5..000000000 --- a/src/com/fsck/k9/mail/store/exchange/adapter/AbstractSyncAdapter.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (C) 2008-2009 Marc Blank - * Licensed to The Android Open Source Project. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.fsck.k9.mail.store.exchange.adapter; - -import java.io.IOException; -import java.io.InputStream; -import java.util.Arrays; - -import android.content.Context; -import android.util.Log; - -import com.fsck.k9.Account; -import com.fsck.k9.K9; -import com.fsck.k9.mail.MessagingException; -import com.fsck.k9.mail.store.EasStore.EasFolder; - -/** - * Parent class of all sync adapters (EasMailbox, EasCalendar, and EasContacts) - * - */ -public abstract class AbstractSyncAdapter { - - public static final int SECONDS = 1000; - public static final int MINUTES = SECONDS*60; - public static final int HOURS = MINUTES*60; - public static final int DAYS = HOURS*24; - public static final int WEEKS = DAYS*7; - - public EasFolder mFolder; - public Context mContext; - public Account mAccount; - - // Create the data for local changes that need to be sent up to the server - public abstract boolean sendLocalChanges(Serializer s) - throws IOException; - // Parse incoming data from the EAS server, creating, modifying, and deleting objects as - // required through the EmailProvider - public abstract boolean parse(InputStream is) - throws IOException, MessagingException; - // The name used to specify the collection type of the target (Email, Calendar, or Contacts) - public abstract String getCollectionName(); - public abstract void cleanup(); - public abstract boolean isSyncable(); - - public boolean isLooping() { - return false; - } - - public AbstractSyncAdapter(EasFolder folder, Account account) { - mFolder = folder; - mAccount = account; - } - - public void userLog(String ...strings) { - Log.i(K9.LOG_TAG, Arrays.toString(strings)); - } - - public void incrementChangeCount() { -// mService.mChangeCount++; - } - - /** - * Returns the current SyncKey; override if the SyncKey is stored elsewhere (as for Contacts) - * @return the current SyncKey for the Mailbox - * @throws IOException - */ - public String getSyncKey() throws IOException { - if (mFolder.getSyncKey() == null) { - userLog("Reset SyncKey to 0"); - mFolder.setSyncKey("0"); - } - return mFolder.getSyncKey(); - } - - public void setSyncKey(String syncKey, boolean inCommands) throws IOException { - mFolder.setSyncKey(syncKey); - } -} - diff --git a/src/com/fsck/k9/mail/store/exchange/adapter/AbstractSyncParser.java b/src/com/fsck/k9/mail/store/exchange/adapter/AbstractSyncParser.java index 93f6573f0..d49ecc49b 100644 --- a/src/com/fsck/k9/mail/store/exchange/adapter/AbstractSyncParser.java +++ b/src/com/fsck/k9/mail/store/exchange/adapter/AbstractSyncParser.java @@ -41,13 +41,11 @@ public abstract class AbstractSyncParser extends Parser { protected EasFolder mFolder; protected Account mAccount; protected ContentResolver mContentResolver; - protected AbstractSyncAdapter mAdapter; private boolean mLooping; - public AbstractSyncParser(InputStream in, AbstractSyncAdapter adapter, EasFolder folder, Account account) throws IOException { + public AbstractSyncParser(InputStream in, EasFolder folder, Account account) throws IOException { super(in); - mAdapter = adapter; mFolder = folder; mAccount = account; } @@ -112,7 +110,7 @@ public abstract class AbstractSyncParser extends Parser { // Status = 3 means invalid sync key if (status == 3) { // Must delete all of the data and start over with syncKey of "0" - mAdapter.setSyncKey("0", false); + mFolder.setSyncKey("0"); // Make this a push box through the first sync // TODO Make frequency conditional on user settings! MailboxAdapter.mSyncInterval = MailboxAdapter.CHECK_INTERVAL_PUSH; @@ -134,14 +132,13 @@ public abstract class AbstractSyncParser extends Parser { } else if (tag == Tags.SYNC_MORE_AVAILABLE) { moreAvailable = true; } else if (tag == Tags.SYNC_SYNC_KEY) { - if (mAdapter.getSyncKey().equals("0")) { + if (mFolder.getSyncKey().equals("0")) { moreAvailable = true; } String newKey = getValue(); userLog("Parsed key for ", mFolder.toString(), ": ", newKey); if (!newKey.equals(mFolder.getSyncKey())) { - mAdapter.setSyncKey(newKey, true); -// cv.put(MailboxColumns.SYNC_KEY, newKey); + mFolder.setSyncKey(newKey); mailboxUpdated = true; newSyncKey = true; } @@ -203,4 +200,5 @@ public abstract class AbstractSyncParser extends Parser { void userLog(String string, int num, String string2) { Log.i(K9.LOG_TAG, string + num + string2); } + } diff --git a/src/com/fsck/k9/mail/store/exchange/adapter/AccountSyncAdapter.java b/src/com/fsck/k9/mail/store/exchange/adapter/AccountSyncAdapter.java deleted file mode 100644 index 9089e1ae3..000000000 --- a/src/com/fsck/k9/mail/store/exchange/adapter/AccountSyncAdapter.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.fsck.k9.mail.store.exchange.adapter; - -import java.io.IOException; -import java.io.InputStream; - -import com.fsck.k9.Account; - -public class AccountSyncAdapter extends AbstractSyncAdapter { - - public AccountSyncAdapter(Account account) { - super(null, account); - } - - @Override - public void cleanup() { - } - - @Override - public String getCollectionName() { - return null; - } - - @Override - public boolean parse(InputStream is) throws IOException { - return false; - } - - @Override - public boolean sendLocalChanges(Serializer s) throws IOException { - return false; - } - - @Override - public boolean isSyncable() { - return true; - } -} diff --git a/src/com/fsck/k9/mail/store/exchange/adapter/EasEmailSyncParser.java b/src/com/fsck/k9/mail/store/exchange/adapter/EasEmailSyncParser.java new file mode 100644 index 000000000..d52b17732 --- /dev/null +++ b/src/com/fsck/k9/mail/store/exchange/adapter/EasEmailSyncParser.java @@ -0,0 +1,564 @@ +/** + * + */ +package com.fsck.k9.mail.store.exchange.adapter; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; + +import android.webkit.MimeTypeMap; + +import com.fsck.k9.Account; +import com.fsck.k9.mail.Address; +import com.fsck.k9.mail.Flag; +import com.fsck.k9.mail.Message; +import com.fsck.k9.mail.MessagingException; +import com.fsck.k9.mail.Message.RecipientType; +import com.fsck.k9.mail.internet.MimeUtility; +import com.fsck.k9.mail.store.EasStore.EasFolder; +import com.fsck.k9.mail.store.EasStore.EasMessage; +import com.fsck.k9.mail.store.exchange.Eas; + +public class EasEmailSyncParser extends AbstractSyncParser { + + /** + * + */ + ArrayList newEmails = new ArrayList(); + ArrayList deletedEmails = new ArrayList(); + ArrayList changedEmails = new ArrayList(); + + public EasEmailSyncParser(InputStream in, EasFolder folder, Account account) throws IOException { + super(in, folder, account); + } + + @Override + public void wipe() { +// mContentResolver.delete(Message.CONTENT_URI, +// Message.MAILBOX_KEY + "=" + mMailbox.mId, null); +// mContentResolver.delete(Message.DELETED_CONTENT_URI, +// Message.MAILBOX_KEY + "=" + mMailbox.mId, null); +// mContentResolver.delete(Message.UPDATED_CONTENT_URI, +// Message.MAILBOX_KEY + "=" + mMailbox.mId, null); + } + + public void addData (EasMessage msg) throws IOException, MessagingException { +// ArrayList atts = new ArrayList(); + + while (nextTag(Tags.SYNC_APPLICATION_DATA) != END) { + switch (tag) { + case Tags.EMAIL_ATTACHMENTS: + case Tags.BASE_ATTACHMENTS: // BASE_ATTACHMENTS is used in EAS 12.0 and up + attachmentsParser(msg); + break; + case Tags.EMAIL_TO: + msg.setRecipients(RecipientType.TO, Address.parse(getValue())); + break; + case Tags.EMAIL_FROM: + Address[] froms = Address.parse(getValue()); + if (froms != null && froms.length > 0) { +// msg.mDisplayName = froms[0].toFriendly(); + msg.setFrom(froms[0]); + } + break; + case Tags.EMAIL_CC: + msg.setRecipients(RecipientType.CC, Address.parse(getValue())); + break; + case Tags.EMAIL_REPLY_TO: + msg.setReplyTo(Address.parse(getValue())); + break; + case Tags.EMAIL_DATE_RECEIVED: + getValue(); +// Date receivedDate = Utility.parseEmailDateTimeToMillis(getValue()); +// msg.setInternalDate(receivedDate); + break; + case Tags.EMAIL_SUBJECT: + msg.setSubject(getValue()); + break; + case Tags.EMAIL_READ: + msg.setFlagInternal(Flag.SEEN, getValueInt() == 1); + break; + case Tags.BASE_BODY: + bodyParser(msg); + break; + case Tags.EMAIL_FLAG: + msg.setFlagInternal(Flag.FLAGGED, flagParser()); + break; + case Tags.EMAIL_BODY: + String body = getValue(); + InputStream bodyStream = new ByteArrayInputStream(body.getBytes()); + + try { + msg.setBody(MimeUtility.decodeBody(bodyStream, null)); + } catch (MessagingException e) { + throw new IOException(e); + } + break; + case Tags.EMAIL_MESSAGE_CLASS: + String messageClass = getValue(); +// if (messageClass.equals("IPM.Schedule.Meeting.Request")) { +// msg.mFlags |= Message.FLAG_INCOMING_MEETING_INVITE; +// } else if (messageClass.equals("IPM.Schedule.Meeting.Canceled")) { +// msg.mFlags |= Message.FLAG_INCOMING_MEETING_CANCEL; +// } + break; + case Tags.EMAIL_MEETING_REQUEST: + meetingRequestParser(msg); + break; + default: + skipTag(); + } + } + +// if (atts.size() > 0) { +// msg.mAttachments = atts; +// } + } + + /** + * Set up the meetingInfo field in the message with various pieces of information gleaned + * from MeetingRequest tags. This information will be used later to generate an appropriate + * reply email if the user chooses to respond + * @param msg the Message being built + * @throws IOException + */ + private void meetingRequestParser(Message msg) throws IOException { +// PackedString.Builder packedString = new PackedString.Builder(); + while (nextTag(Tags.EMAIL_MEETING_REQUEST) != END) { + String value; + switch (tag) { + case Tags.EMAIL_DTSTAMP: + value = getValue(); +// packedString.put(MeetingInfo.MEETING_DTSTAMP, value); + break; + case Tags.EMAIL_START_TIME: + value = getValue(); +// packedString.put(MeetingInfo.MEETING_DTSTART, value); + break; + case Tags.EMAIL_END_TIME: + value = getValue(); +// packedString.put(MeetingInfo.MEETING_DTEND, value); + break; + case Tags.EMAIL_ORGANIZER: + value = getValue(); +// packedString.put(MeetingInfo.MEETING_ORGANIZER_EMAIL, value); + break; + case Tags.EMAIL_LOCATION: + value = getValue(); +// packedString.put(MeetingInfo.MEETING_LOCATION, value); + break; + case Tags.EMAIL_GLOBAL_OBJID: + value = getValue(); +// packedString.put(MeetingInfo.MEETING_UID, +// CalendarUtilities.getUidFromGlobalObjId(value)); + break; + case Tags.EMAIL_CATEGORIES: + nullParser(); + break; + case Tags.EMAIL_RECURRENCES: + recurrencesParser(); + break; + default: + skipTag(); + } + } +// if (msg.mSubject != null) { +// packedString.put(MeetingInfo.MEETING_TITLE, msg.mSubject); +// } +// msg.mMeetingInfo = packedString.toString(); + } + + private void nullParser() throws IOException { + while (nextTag(Tags.EMAIL_CATEGORIES) != END) { + skipTag(); + } + } + + private void recurrencesParser() throws IOException { + while (nextTag(Tags.EMAIL_RECURRENCES) != END) { + switch (tag) { + case Tags.EMAIL_RECURRENCE: + nullParser(); + break; + default: + skipTag(); + } + } + } + + private void addParser(ArrayList emails) throws IOException, MessagingException { + EasMessage msg = new EasMessage(null, mFolder); +// msg.mAccountKey = mAccount.mId; +// msg.mMailboxKey = mMailbox.mId; +// msg.mFlagLoaded = Message.FLAG_LOADED_COMPLETE; + + while (nextTag(Tags.SYNC_ADD) != END) { + switch (tag) { + case Tags.SYNC_SERVER_ID: + String serverId = getValue(); + msg.setUid(serverId); + break; + case Tags.SYNC_APPLICATION_DATA: + addData(msg); + break; + default: + skipTag(); + } + } + emails.add(msg); + } + + private void fetchParser(ArrayList emails) throws IOException, MessagingException { + EasMessage msg = new EasMessage(null, mFolder); +// msg.mAccountKey = mAccount.mId; +// msg.mMailboxKey = mMailbox.mId; +// msg.mFlagLoaded = Message.FLAG_LOADED_COMPLETE; + + while (nextTag(Tags.SYNC_FETCH) != END) { + switch (tag) { + case Tags.SYNC_SERVER_ID: + String serverId = getValue(); + msg.setUid(serverId); + break; + case Tags.SYNC_APPLICATION_DATA: + addData(msg); + break; + default: + skipTag(); + } + } + emails.add(msg); + } + + // For now, we only care about the "active" state + private Boolean flagParser() throws IOException { + Boolean state = false; + while (nextTag(Tags.EMAIL_FLAG) != END) { + switch (tag) { + case Tags.EMAIL_FLAG_STATUS: + state = getValueInt() == 2; + break; + default: + skipTag(); + } + } + return state; + } + + private void bodyParser(Message msg) throws IOException { + String bodyType = Eas.BODY_PREFERENCE_TEXT; + String body = ""; + while (nextTag(Tags.EMAIL_BODY) != END) { + switch (tag) { + case Tags.BASE_TYPE: + bodyType = getValue(); + break; + case Tags.BASE_DATA: + body = getValue(); + break; + default: + skipTag(); + } + } + + // We always ask for TEXT or HTML; there's no third option +// if (bodyType.equals(Eas.BODY_PREFERENCE_HTML)) { +// msg.mHtml = body; +// } else { +// msg.mText = body; +// } + + try { + InputStream bodyStream = new ByteArrayInputStream(body.getBytes()); + //String contentTransferEncoding; +// contentTransferEncoding = msg.getHeader( +// MimeHeader.HEADER_CONTENT_TRANSFER_ENCODING)[0]; +// msg.setBody(MimeUtility.decodeBody(bodyStream, contentTransferEncoding)); + ((EasMessage) msg).parse(bodyStream); + } catch (MessagingException e) { + throw new IOException(e); + } + } + + private void attachmentsParser(Message msg) throws IOException { + while (nextTag(Tags.EMAIL_ATTACHMENTS) != END) { + switch (tag) { + case Tags.EMAIL_ATTACHMENT: + case Tags.BASE_ATTACHMENT: // BASE_ATTACHMENT is used in EAS 12.0 and up + attachmentParser(msg); + break; + default: + skipTag(); + } + } + } + + private void attachmentParser(Message msg) throws IOException { + String fileName = null; + String length = null; + String location = null; + + while (nextTag(Tags.EMAIL_ATTACHMENT) != END) { + switch (tag) { + // We handle both EAS 2.5 and 12.0+ attachments here + case Tags.EMAIL_DISPLAY_NAME: + case Tags.BASE_DISPLAY_NAME: + fileName = getValue(); + break; + case Tags.EMAIL_ATT_NAME: + case Tags.BASE_FILE_REFERENCE: + location = getValue(); + break; + case Tags.EMAIL_ATT_SIZE: + case Tags.BASE_ESTIMATED_DATA_SIZE: + length = getValue(); + break; + default: + skipTag(); + } + } + + if ((fileName != null) && (length != null) && (location != null)) { +// Attachment att = new Attachment(); +// att.mEncoding = "base64"; +// att.mSize = Long.parseLong(length); +// att.mFileName = fileName; +// att.mLocation = location; +// att.mMimeType = getMimeTypeFromFileName(fileName); +// atts.add(att); +// msg.mFlagAttachment = true; + } + } + + /** + * Try to determine a mime type from a file name, defaulting to application/x, where x + * is either the extension or (if none) octet-stream + * At the moment, this is somewhat lame, since many file types aren't recognized + * @param fileName the file name to ponder + * @return + */ + // Note: The MimeTypeMap method currently uses a very limited set of mime types + // A bug has been filed against this issue. + public String getMimeTypeFromFileName(String fileName) { + String mimeType; + int lastDot = fileName.lastIndexOf('.'); + String extension = null; + if ((lastDot > 0) && (lastDot < fileName.length() - 1)) { + extension = fileName.substring(lastDot + 1).toLowerCase(); + } + if (extension == null) { + // A reasonable default for now. + mimeType = "application/octet-stream"; + } else { + mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension); + if (mimeType == null) { + mimeType = "application/" + extension; + } + } + return mimeType; + } + +// private Cursor getServerIdCursor(String serverId, String[] projection) { +// mBindArguments[0] = serverId; +// mBindArguments[1] = mMailboxIdAsString; +// return mContentResolver.query(Message.CONTENT_URI, projection, +// WHERE_SERVER_ID_AND_MAILBOX_KEY, mBindArguments, null); +// } + + /*package*/ void deleteParser(ArrayList deletes, int entryTag) throws IOException { + while (nextTag(entryTag) != END) { + switch (tag) { + case Tags.SYNC_SERVER_ID: + String serverId = getValue(); + deletes.add(serverId); + break; + default: + skipTag(); + } + } + } + + class ServerChange { + String serverId; + Boolean read; + Boolean flag; + + ServerChange(String _serverId, Boolean _read, Boolean _flag) { + serverId = _serverId; + read = _read; + flag = _flag; + } + } + + /*package*/ void changeParser(ArrayList changes) throws IOException { + String serverId = null; + while (nextTag(Tags.SYNC_CHANGE) != END) { + switch (tag) { + case Tags.SYNC_SERVER_ID: + serverId = getValue(); + break; + case Tags.SYNC_APPLICATION_DATA: + changeApplicationDataParser(changes, serverId); + break; + default: + skipTag(); + } + } + } + + private void changeApplicationDataParser(ArrayList changes, String serverId) throws IOException { + Boolean read = null; + Boolean flag = null; + while (nextTag(Tags.SYNC_APPLICATION_DATA) != END) { + switch (tag) { + case Tags.EMAIL_READ: + read = getValueInt() == 1; + break; + case Tags.EMAIL_FLAG: + flag = flagParser(); + break; + default: + skipTag(); + } + } + changes.add(new ServerChange(serverId, read, flag)); + } + + /* (non-Javadoc) + * @see com.android.exchange.adapter.EasContentParser#commandsParser() + */ + @Override + public void commandsParser() throws IOException, MessagingException { + while (nextTag(Tags.SYNC_COMMANDS) != END) { + if (tag == Tags.SYNC_ADD) { + addParser(newEmails); +// this.emailSyncAdapter.incrementChangeCount(); + } else if (tag == Tags.SYNC_DELETE || tag == Tags.SYNC_SOFT_DELETE) { + deleteParser(deletedEmails, tag); +// this.emailSyncAdapter.incrementChangeCount(); + } else if (tag == Tags.SYNC_CHANGE) { + changeParser(changedEmails); +// this.emailSyncAdapter.incrementChangeCount(); + } else + skipTag(); + } + } + + @Override + public void responsesParser() throws IOException, MessagingException { + while (nextTag(Tags.SYNC_RESPONSES) != END) { + if (tag == Tags.SYNC_FETCH) { + fetchParser(newEmails); +// this.emailSyncAdapter.incrementChangeCount(); +// } else if (tag == Tags.SYNC_ADD) { +// deleteParser(deletedEmails, tag); +// incrementChangeCount(); +// } else if (tag == Tags.SYNC_CHANGE) { +// changeParser(changedEmails); +// incrementChangeCount(); + } else + skipTag(); + } + } + + @Override + public void commit() { +// int notifyCount = 0; +// +// // Use a batch operation to handle the changes +// // TODO New mail notifications? Who looks for these? +// ArrayList ops = new ArrayList(); +// for (Message msg: newEmails) { +// if (!msg.mFlagRead) { +// notifyCount++; +// } +// msg.addSaveOps(ops); +// } +// for (Long id : deletedEmails) { +// ops.add(ContentProviderOperation.newDelete( +// ContentUris.withAppendedId(Message.CONTENT_URI, id)).build()); +// AttachmentProvider.deleteAllAttachmentFiles(mContext, mAccount.mId, id); +// } +// if (!changedEmails.isEmpty()) { +// // Server wins in a conflict... +// for (ServerChange change : changedEmails) { +// ContentValues cv = new ContentValues(); +// if (change.read != null) { +// cv.put(MessageColumns.FLAG_READ, change.read); +// } +// if (change.flag != null) { +// cv.put(MessageColumns.FLAG_FAVORITE, change.flag); +// } +// ops.add(ContentProviderOperation.newUpdate( +// ContentUris.withAppendedId(Message.CONTENT_URI, change.id)) +// .withValues(cv) +// .build()); +// } +// } +// +// // We only want to update the sync key here +// ContentValues mailboxValues = new ContentValues(); +// mailboxValues.put(Mailbox.SYNC_KEY, mMailbox.mSyncKey); +// ops.add(ContentProviderOperation.newUpdate( +// ContentUris.withAppendedId(Mailbox.CONTENT_URI, mMailbox.mId)) +// .withValues(mailboxValues).build()); +// +// addCleanupOps(ops); +// +// // No commits if we're stopped +// synchronized (mService.getSynchronizer()) { +// if (mService.isStopped()) return; +// try { +// mContentResolver.applyBatch(EmailProvider.EMAIL_AUTHORITY, ops); +// userLog(mMailbox.mDisplayName, " SyncKey saved as: ", mMailbox.mSyncKey); +// } catch (RemoteException e) { +// // There is nothing to be done here; fail by returning null +// } catch (OperationApplicationException e) { +// // There is nothing to be done here; fail by returning null +// } +// } +// +// if (notifyCount > 0) { +// // Use the new atomic add URI in EmailProvider +// // We could add this to the operations being done, but it's not strictly +// // speaking necessary, as the previous batch preserves the integrity of the +// // database, whereas this is purely for notification purposes, and is itself atomic +// ContentValues cv = new ContentValues(); +// cv.put(EmailContent.FIELD_COLUMN_NAME, AccountColumns.NEW_MESSAGE_COUNT); +// cv.put(EmailContent.ADD_COLUMN_NAME, notifyCount); +// Uri uri = ContentUris.withAppendedId(Account.ADD_TO_FIELD_URI, mAccount.mId); +// mContentResolver.update(uri, cv, null, null); +// MailService.actionNotifyNewMessages(mContext, mAccount.mId); +// } + } + + + public List getMessages() throws MessagingException { + List messages = new ArrayList(); + + messages.addAll(newEmails); + + for (ServerChange srvChg : changedEmails) { + EasMessage msg = new EasMessage(srvChg.serverId, mFolder); + if (srvChg.read != null) { + msg.setFlag(Flag.SEEN, srvChg.read); + } + if (srvChg.flag != null) { + msg.setFlag(Flag.FLAGGED, srvChg.flag); + } + messages.add(msg); + } + + for (String serverId : deletedEmails) { + EasMessage msg = new EasMessage(serverId, mFolder); + msg.setFlag(Flag.DELETED, true); + messages.add(msg); + } + + return messages; + } + +} \ No newline at end of file diff --git a/src/com/fsck/k9/mail/store/exchange/adapter/EmailSyncAdapter.java b/src/com/fsck/k9/mail/store/exchange/adapter/EmailSyncAdapter.java deleted file mode 100644 index fa033f5b1..000000000 --- a/src/com/fsck/k9/mail/store/exchange/adapter/EmailSyncAdapter.java +++ /dev/null @@ -1,905 +0,0 @@ -/* - * Copyright (C) 2008-2009 Marc Blank - * Licensed to The Android Open Source Project. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.fsck.k9.mail.store.exchange.adapter; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.Calendar; -import java.util.List; - -import android.webkit.MimeTypeMap; - -import com.fsck.k9.Account; -import com.fsck.k9.mail.Address; -import com.fsck.k9.mail.Flag; -import com.fsck.k9.mail.Message; -import com.fsck.k9.mail.MessagingException; -import com.fsck.k9.mail.Message.RecipientType; -import com.fsck.k9.mail.internet.MimeUtility; -import com.fsck.k9.mail.store.EasStore.EasFolder; -import com.fsck.k9.mail.store.EasStore.EasMessage; -import com.fsck.k9.mail.store.exchange.Eas; - -/** - * Sync adapter for EAS email - * - */ -public class EmailSyncAdapter extends AbstractSyncAdapter { - -// private static final int UPDATES_READ_COLUMN = 0; -// private static final int UPDATES_MAILBOX_KEY_COLUMN = 1; -// private static final int UPDATES_SERVER_ID_COLUMN = 2; -// private static final int UPDATES_FLAG_COLUMN = 3; -// private static final String[] UPDATES_PROJECTION = -// {MessageColumns.FLAG_READ, MessageColumns.MAILBOX_KEY, SyncColumns.SERVER_ID, -// MessageColumns.FLAG_FAVORITE}; -// -// private static final int MESSAGE_ID_SUBJECT_ID_COLUMN = 0; -// private static final int MESSAGE_ID_SUBJECT_SUBJECT_COLUMN = 1; -// private static final String[] MESSAGE_ID_SUBJECT_PROJECTION = -// new String[] { Message.RECORD_ID, MessageColumns.SUBJECT }; -// -// private static final String WHERE_BODY_SOURCE_MESSAGE_KEY = Body.SOURCE_MESSAGE_KEY + "=?"; - - String[] mBindArguments = new String[2]; - String[] mBindArgument = new String[1]; - - ArrayList mDeletedIdList = new ArrayList(); - ArrayList mUpdatedIdList = new ArrayList(); - - // Holds the parser's value for isLooping() - boolean mIsLooping = false; - private List newEmails; - - public EmailSyncAdapter(EasFolder folder, Account account) { - super(folder, account); - } - - @Override - public boolean parse(InputStream is) throws IOException, MessagingException { - EasEmailSyncParser p = new EasEmailSyncParser(is, this, mFolder, mAccount); - boolean res = p.parse(); - // Hold on to the parser's value for isLooping() to pass back to the service - mIsLooping = p.isLooping(); - newEmails = p.newEmails; - return res; - } - - /** - * Return the value of isLooping() as returned from the parser - */ - @Override - public boolean isLooping() { - return mIsLooping; - } - - @Override - public boolean isSyncable() { - return true; - } - - public class EasEmailSyncParser extends AbstractSyncParser { - -// private static final String WHERE_SERVER_ID_AND_MAILBOX_KEY = -// SyncColumns.SERVER_ID + "=? and " + MessageColumns.MAILBOX_KEY + "=?"; - -// private String mMailboxIdAsString; - - ArrayList newEmails = new ArrayList(); - ArrayList deletedEmails = new ArrayList(); - ArrayList changedEmails = new ArrayList(); - - public EasEmailSyncParser(InputStream in, EmailSyncAdapter adapter, EasFolder folder, Account account) throws IOException { - super(in, adapter, folder, account); -// mMailboxIdAsString = Long.toString(mMailbox.mId); - } - - @Override - public void wipe() { -// mContentResolver.delete(Message.CONTENT_URI, -// Message.MAILBOX_KEY + "=" + mMailbox.mId, null); -// mContentResolver.delete(Message.DELETED_CONTENT_URI, -// Message.MAILBOX_KEY + "=" + mMailbox.mId, null); -// mContentResolver.delete(Message.UPDATED_CONTENT_URI, -// Message.MAILBOX_KEY + "=" + mMailbox.mId, null); - } - - public void addData (EasMessage msg) throws IOException, MessagingException { -// ArrayList atts = new ArrayList(); - - while (nextTag(Tags.SYNC_APPLICATION_DATA) != END) { - switch (tag) { - case Tags.EMAIL_ATTACHMENTS: - case Tags.BASE_ATTACHMENTS: // BASE_ATTACHMENTS is used in EAS 12.0 and up - attachmentsParser(msg); - break; - case Tags.EMAIL_TO: - msg.setRecipients(RecipientType.TO, Address.parse(getValue())); - break; - case Tags.EMAIL_FROM: - Address[] froms = Address.parse(getValue()); - if (froms != null && froms.length > 0) { -// msg.mDisplayName = froms[0].toFriendly(); - msg.setFrom(froms[0]); - } - break; - case Tags.EMAIL_CC: - msg.setRecipients(RecipientType.CC, Address.parse(getValue())); - break; - case Tags.EMAIL_REPLY_TO: - msg.setReplyTo(Address.parse(getValue())); - break; - case Tags.EMAIL_DATE_RECEIVED: - getValue(); -// Date receivedDate = Utility.parseEmailDateTimeToMillis(getValue()); -// msg.setInternalDate(receivedDate); - break; - case Tags.EMAIL_SUBJECT: - msg.setSubject(getValue()); - break; - case Tags.EMAIL_READ: - msg.setFlagInternal(Flag.SEEN, getValueInt() == 1); - break; - case Tags.BASE_BODY: - bodyParser(msg); - break; - case Tags.EMAIL_FLAG: - msg.setFlagInternal(Flag.FLAGGED, flagParser()); - break; - case Tags.EMAIL_BODY: - String body = getValue(); - InputStream bodyStream = new ByteArrayInputStream(body.getBytes()); - - try { - msg.setBody(MimeUtility.decodeBody(bodyStream, null)); - } catch (MessagingException e) { - throw new IOException(e); - } - break; - case Tags.EMAIL_MESSAGE_CLASS: - String messageClass = getValue(); -// if (messageClass.equals("IPM.Schedule.Meeting.Request")) { -// msg.mFlags |= Message.FLAG_INCOMING_MEETING_INVITE; -// } else if (messageClass.equals("IPM.Schedule.Meeting.Canceled")) { -// msg.mFlags |= Message.FLAG_INCOMING_MEETING_CANCEL; -// } - break; - case Tags.EMAIL_MEETING_REQUEST: - meetingRequestParser(msg); - break; - default: - skipTag(); - } - } - -// if (atts.size() > 0) { -// msg.mAttachments = atts; -// } - } - - /** - * Set up the meetingInfo field in the message with various pieces of information gleaned - * from MeetingRequest tags. This information will be used later to generate an appropriate - * reply email if the user chooses to respond - * @param msg the Message being built - * @throws IOException - */ - private void meetingRequestParser(Message msg) throws IOException { -// PackedString.Builder packedString = new PackedString.Builder(); - while (nextTag(Tags.EMAIL_MEETING_REQUEST) != END) { - String value; - switch (tag) { - case Tags.EMAIL_DTSTAMP: - value = getValue(); -// packedString.put(MeetingInfo.MEETING_DTSTAMP, value); - break; - case Tags.EMAIL_START_TIME: - value = getValue(); -// packedString.put(MeetingInfo.MEETING_DTSTART, value); - break; - case Tags.EMAIL_END_TIME: - value = getValue(); -// packedString.put(MeetingInfo.MEETING_DTEND, value); - break; - case Tags.EMAIL_ORGANIZER: - value = getValue(); -// packedString.put(MeetingInfo.MEETING_ORGANIZER_EMAIL, value); - break; - case Tags.EMAIL_LOCATION: - value = getValue(); -// packedString.put(MeetingInfo.MEETING_LOCATION, value); - break; - case Tags.EMAIL_GLOBAL_OBJID: - value = getValue(); -// packedString.put(MeetingInfo.MEETING_UID, -// CalendarUtilities.getUidFromGlobalObjId(value)); - break; - case Tags.EMAIL_CATEGORIES: - nullParser(); - break; - case Tags.EMAIL_RECURRENCES: - recurrencesParser(); - break; - default: - skipTag(); - } - } -// if (msg.mSubject != null) { -// packedString.put(MeetingInfo.MEETING_TITLE, msg.mSubject); -// } -// msg.mMeetingInfo = packedString.toString(); - } - - private void nullParser() throws IOException { - while (nextTag(Tags.EMAIL_CATEGORIES) != END) { - skipTag(); - } - } - - private void recurrencesParser() throws IOException { - while (nextTag(Tags.EMAIL_RECURRENCES) != END) { - switch (tag) { - case Tags.EMAIL_RECURRENCE: - nullParser(); - break; - default: - skipTag(); - } - } - } - - private void addParser(ArrayList emails) throws IOException, MessagingException { - EasMessage msg = new EasMessage(null, mFolder); -// msg.mAccountKey = mAccount.mId; -// msg.mMailboxKey = mMailbox.mId; -// msg.mFlagLoaded = Message.FLAG_LOADED_COMPLETE; - - while (nextTag(Tags.SYNC_ADD) != END) { - switch (tag) { - case Tags.SYNC_SERVER_ID: - String serverId = getValue(); - msg.setUid(serverId); - break; - case Tags.SYNC_APPLICATION_DATA: - addData(msg); - break; - default: - skipTag(); - } - } - emails.add(msg); - } - - private void fetchParser(ArrayList emails) throws IOException, MessagingException { - EasMessage msg = new EasMessage(null, mFolder); -// msg.mAccountKey = mAccount.mId; -// msg.mMailboxKey = mMailbox.mId; -// msg.mFlagLoaded = Message.FLAG_LOADED_COMPLETE; - - while (nextTag(Tags.SYNC_FETCH) != END) { - switch (tag) { - case Tags.SYNC_SERVER_ID: - String serverId = getValue(); - msg.setUid(serverId); - break; - case Tags.SYNC_APPLICATION_DATA: - addData(msg); - break; - default: - skipTag(); - } - } - emails.add(msg); - } - - // For now, we only care about the "active" state - private Boolean flagParser() throws IOException { - Boolean state = false; - while (nextTag(Tags.EMAIL_FLAG) != END) { - switch (tag) { - case Tags.EMAIL_FLAG_STATUS: - state = getValueInt() == 2; - break; - default: - skipTag(); - } - } - return state; - } - - private void bodyParser(Message msg) throws IOException { - String bodyType = Eas.BODY_PREFERENCE_TEXT; - String body = ""; - while (nextTag(Tags.EMAIL_BODY) != END) { - switch (tag) { - case Tags.BASE_TYPE: - bodyType = getValue(); - break; - case Tags.BASE_DATA: - body = getValue(); - break; - default: - skipTag(); - } - } - - // We always ask for TEXT or HTML; there's no third option -// if (bodyType.equals(Eas.BODY_PREFERENCE_HTML)) { -// msg.mHtml = body; -// } else { -// msg.mText = body; -// } - - try { - InputStream bodyStream = new ByteArrayInputStream(body.getBytes()); - //String contentTransferEncoding; -// contentTransferEncoding = msg.getHeader( -// MimeHeader.HEADER_CONTENT_TRANSFER_ENCODING)[0]; -// msg.setBody(MimeUtility.decodeBody(bodyStream, contentTransferEncoding)); - ((EasMessage) msg).parse(bodyStream); - } catch (MessagingException e) { - throw new IOException(e); - } - } - - private void attachmentsParser(Message msg) throws IOException { - while (nextTag(Tags.EMAIL_ATTACHMENTS) != END) { - switch (tag) { - case Tags.EMAIL_ATTACHMENT: - case Tags.BASE_ATTACHMENT: // BASE_ATTACHMENT is used in EAS 12.0 and up - attachmentParser(msg); - break; - default: - skipTag(); - } - } - } - - private void attachmentParser(Message msg) throws IOException { - String fileName = null; - String length = null; - String location = null; - - while (nextTag(Tags.EMAIL_ATTACHMENT) != END) { - switch (tag) { - // We handle both EAS 2.5 and 12.0+ attachments here - case Tags.EMAIL_DISPLAY_NAME: - case Tags.BASE_DISPLAY_NAME: - fileName = getValue(); - break; - case Tags.EMAIL_ATT_NAME: - case Tags.BASE_FILE_REFERENCE: - location = getValue(); - break; - case Tags.EMAIL_ATT_SIZE: - case Tags.BASE_ESTIMATED_DATA_SIZE: - length = getValue(); - break; - default: - skipTag(); - } - } - - if ((fileName != null) && (length != null) && (location != null)) { -// Attachment att = new Attachment(); -// att.mEncoding = "base64"; -// att.mSize = Long.parseLong(length); -// att.mFileName = fileName; -// att.mLocation = location; -// att.mMimeType = getMimeTypeFromFileName(fileName); -// atts.add(att); -// msg.mFlagAttachment = true; - } - } - - /** - * Try to determine a mime type from a file name, defaulting to application/x, where x - * is either the extension or (if none) octet-stream - * At the moment, this is somewhat lame, since many file types aren't recognized - * @param fileName the file name to ponder - * @return - */ - // Note: The MimeTypeMap method currently uses a very limited set of mime types - // A bug has been filed against this issue. - public String getMimeTypeFromFileName(String fileName) { - String mimeType; - int lastDot = fileName.lastIndexOf('.'); - String extension = null; - if ((lastDot > 0) && (lastDot < fileName.length() - 1)) { - extension = fileName.substring(lastDot + 1).toLowerCase(); - } - if (extension == null) { - // A reasonable default for now. - mimeType = "application/octet-stream"; - } else { - mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension); - if (mimeType == null) { - mimeType = "application/" + extension; - } - } - return mimeType; - } - -// private Cursor getServerIdCursor(String serverId, String[] projection) { -// mBindArguments[0] = serverId; -// mBindArguments[1] = mMailboxIdAsString; -// return mContentResolver.query(Message.CONTENT_URI, projection, -// WHERE_SERVER_ID_AND_MAILBOX_KEY, mBindArguments, null); -// } - - /*package*/ void deleteParser(ArrayList deletes, int entryTag) throws IOException { - while (nextTag(entryTag) != END) { - switch (tag) { - case Tags.SYNC_SERVER_ID: - String serverId = getValue(); - // Find the message in this mailbox with the given serverId -// Cursor c = getServerIdCursor(serverId, MESSAGE_ID_SUBJECT_PROJECTION); -// try { -// if (c.moveToFirst()) { -// deletes.add(c.getLong(MESSAGE_ID_SUBJECT_ID_COLUMN)); -// if (Eas.USER_LOG) { -// userLog("Deleting ", serverId + ", " -// + c.getString(MESSAGE_ID_SUBJECT_SUBJECT_COLUMN)); -// } -// } -// } finally { -// c.close(); -// } - break; - default: - skipTag(); - } - } - } - - class ServerChange { - long id; - Boolean read; - Boolean flag; - - ServerChange(long _id, Boolean _read, Boolean _flag) { - id = _id; - read = _read; - flag = _flag; - } - } - - /*package*/ void changeParser(ArrayList changes) throws IOException { - String serverId = null; - Boolean oldRead = false; - Boolean oldFlag = false; - long id = 0; - while (nextTag(Tags.SYNC_CHANGE) != END) { - switch (tag) { - case Tags.SYNC_SERVER_ID: - serverId = getValue(); -// Cursor c = getServerIdCursor(serverId, Message.LIST_PROJECTION); -// try { -// if (c.moveToFirst()) { -// userLog("Changing ", serverId); -// oldRead = c.getInt(Message.LIST_READ_COLUMN) == Message.READ; -// oldFlag = c.getInt(Message.LIST_FAVORITE_COLUMN) == 1; -// id = c.getLong(Message.LIST_ID_COLUMN); -// } -// } finally { -// c.close(); -// } - break; - case Tags.SYNC_APPLICATION_DATA: - changeApplicationDataParser(changes, oldRead, oldFlag, id); - break; - default: - skipTag(); - } - } - } - - private void changeApplicationDataParser(ArrayList changes, Boolean oldRead, - Boolean oldFlag, long id) throws IOException { - Boolean read = null; - Boolean flag = null; - while (nextTag(Tags.SYNC_APPLICATION_DATA) != END) { - switch (tag) { - case Tags.EMAIL_READ: - read = getValueInt() == 1; - break; - case Tags.EMAIL_FLAG: - flag = flagParser(); - break; - default: - skipTag(); - } - } - if (((read != null) && !oldRead.equals(read)) || - ((flag != null) && !oldFlag.equals(flag))) { - changes.add(new ServerChange(id, read, flag)); - } - } - - /* (non-Javadoc) - * @see com.android.exchange.adapter.EasContentParser#commandsParser() - */ - @Override - public void commandsParser() throws IOException, MessagingException { - while (nextTag(Tags.SYNC_COMMANDS) != END) { - if (tag == Tags.SYNC_ADD) { - addParser(newEmails); - incrementChangeCount(); - } else if (tag == Tags.SYNC_DELETE || tag == Tags.SYNC_SOFT_DELETE) { - deleteParser(deletedEmails, tag); - incrementChangeCount(); - } else if (tag == Tags.SYNC_CHANGE) { - changeParser(changedEmails); - incrementChangeCount(); - } else - skipTag(); - } - } - - @Override - public void responsesParser() throws IOException, MessagingException { - while (nextTag(Tags.SYNC_RESPONSES) != END) { - if (tag == Tags.SYNC_FETCH) { - fetchParser(newEmails); - incrementChangeCount(); -// } else if (tag == Tags.SYNC_ADD) { -// deleteParser(deletedEmails, tag); -// incrementChangeCount(); -// } else if (tag == Tags.SYNC_CHANGE) { -// changeParser(changedEmails); -// incrementChangeCount(); - } else - skipTag(); - } - } - - @Override - public void commit() { -// int notifyCount = 0; -// -// // Use a batch operation to handle the changes -// // TODO New mail notifications? Who looks for these? -// ArrayList ops = new ArrayList(); -// for (Message msg: newEmails) { -// if (!msg.mFlagRead) { -// notifyCount++; -// } -// msg.addSaveOps(ops); -// } -// for (Long id : deletedEmails) { -// ops.add(ContentProviderOperation.newDelete( -// ContentUris.withAppendedId(Message.CONTENT_URI, id)).build()); -// AttachmentProvider.deleteAllAttachmentFiles(mContext, mAccount.mId, id); -// } -// if (!changedEmails.isEmpty()) { -// // Server wins in a conflict... -// for (ServerChange change : changedEmails) { -// ContentValues cv = new ContentValues(); -// if (change.read != null) { -// cv.put(MessageColumns.FLAG_READ, change.read); -// } -// if (change.flag != null) { -// cv.put(MessageColumns.FLAG_FAVORITE, change.flag); -// } -// ops.add(ContentProviderOperation.newUpdate( -// ContentUris.withAppendedId(Message.CONTENT_URI, change.id)) -// .withValues(cv) -// .build()); -// } -// } -// -// // We only want to update the sync key here -// ContentValues mailboxValues = new ContentValues(); -// mailboxValues.put(Mailbox.SYNC_KEY, mMailbox.mSyncKey); -// ops.add(ContentProviderOperation.newUpdate( -// ContentUris.withAppendedId(Mailbox.CONTENT_URI, mMailbox.mId)) -// .withValues(mailboxValues).build()); -// -// addCleanupOps(ops); -// -// // No commits if we're stopped -// synchronized (mService.getSynchronizer()) { -// if (mService.isStopped()) return; -// try { -// mContentResolver.applyBatch(EmailProvider.EMAIL_AUTHORITY, ops); -// userLog(mMailbox.mDisplayName, " SyncKey saved as: ", mMailbox.mSyncKey); -// } catch (RemoteException e) { -// // There is nothing to be done here; fail by returning null -// } catch (OperationApplicationException e) { -// // There is nothing to be done here; fail by returning null -// } -// } -// -// if (notifyCount > 0) { -// // Use the new atomic add URI in EmailProvider -// // We could add this to the operations being done, but it's not strictly -// // speaking necessary, as the previous batch preserves the integrity of the -// // database, whereas this is purely for notification purposes, and is itself atomic -// ContentValues cv = new ContentValues(); -// cv.put(EmailContent.FIELD_COLUMN_NAME, AccountColumns.NEW_MESSAGE_COUNT); -// cv.put(EmailContent.ADD_COLUMN_NAME, notifyCount); -// Uri uri = ContentUris.withAppendedId(Account.ADD_TO_FIELD_URI, mAccount.mId); -// mContentResolver.update(uri, cv, null, null); -// MailService.actionNotifyNewMessages(mContext, mAccount.mId); -// } - } - } - - @Override - public String getCollectionName() { - return "Email"; - } - -// private void addCleanupOps(ArrayList ops) { -// // If we've sent local deletions, clear out the deleted table -// for (Long id: mDeletedIdList) { -// ops.add(ContentProviderOperation.newDelete( -// ContentUris.withAppendedId(Message.DELETED_CONTENT_URI, id)).build()); -// } -// // And same with the updates -// for (Long id: mUpdatedIdList) { -// ops.add(ContentProviderOperation.newDelete( -// ContentUris.withAppendedId(Message.UPDATED_CONTENT_URI, id)).build()); -// } -// } -// - @Override - public void cleanup() { -// if (!mDeletedIdList.isEmpty() || !mUpdatedIdList.isEmpty()) { -// ArrayList ops = new ArrayList(); -// addCleanupOps(ops); -// try { -// mContext.getContentResolver() -// .applyBatch(EmailProvider.EMAIL_AUTHORITY, ops); -// } catch (RemoteException e) { -// // There is nothing to be done here; fail by returning null -// } catch (OperationApplicationException e) { -// // There is nothing to be done here; fail by returning null -// } -// } - } - - private String formatTwo(int num) { - if (num < 10) { - return "0" + (char)('0' + num); - } else - return Integer.toString(num); - } - - /** - * Create date/time in RFC8601 format. Oddly enough, for calendar date/time, Microsoft uses - * a different format that excludes the punctuation (this is why I'm not putting this in a - * parent class) - */ - public String formatDateTime(Calendar calendar) { - StringBuilder sb = new StringBuilder(); - //YYYY-MM-DDTHH:MM:SS.MSSZ - sb.append(calendar.get(Calendar.YEAR)); - sb.append('-'); - sb.append(formatTwo(calendar.get(Calendar.MONTH) + 1)); - sb.append('-'); - sb.append(formatTwo(calendar.get(Calendar.DAY_OF_MONTH))); - sb.append('T'); - sb.append(formatTwo(calendar.get(Calendar.HOUR_OF_DAY))); - sb.append(':'); - sb.append(formatTwo(calendar.get(Calendar.MINUTE))); - sb.append(':'); - sb.append(formatTwo(calendar.get(Calendar.SECOND))); - sb.append(".000Z"); - return sb.toString(); - } - - /** - * Note that messages in the deleted database preserve the message's unique id; therefore, we - * can utilize this id to find references to the message. The only reference situation at this - * point is in the Body table; it is when sending messages via SmartForward and SmartReply - */ -// private boolean messageReferenced(ContentResolver cr, long id) { -// mBindArgument[0] = Long.toString(id); -// // See if this id is referenced in a body -// Cursor c = cr.query(Body.CONTENT_URI, Body.ID_PROJECTION, WHERE_BODY_SOURCE_MESSAGE_KEY, -// mBindArgument, null); -// try { -// return c.moveToFirst(); -// } finally { -// c.close(); -// } -// } - - /*private*/ /** - * Serialize commands to delete items from the server; as we find items to delete, add their - * id's to the deletedId's array - * - * @param s the Serializer we're using to create post data - * @param deletedIds ids whose deletions are being sent to the server - * @param first whether or not this is the first command being sent - * @return true if SYNC_COMMANDS hasn't been sent (false otherwise) - * @throws IOException - */ - boolean sendDeletedItems(Serializer s, ArrayList deletedIds, boolean first) - throws IOException { - -// ContentResolver cr = mContext.getContentResolver(); -// -// // Find any of our deleted items -// Cursor c = cr.query(Message.DELETED_CONTENT_URI, Message.LIST_PROJECTION, -// MessageColumns.MAILBOX_KEY + '=' + mMailbox.mId, null, null); -// // We keep track of the list of deleted item id's so that we can remove them from the -// // deleted table after the server receives our command -// deletedIds.clear(); -// try { -// while (c.moveToNext()) { -// String serverId = c.getString(Message.LIST_SERVER_ID_COLUMN); -// // Keep going if there's no serverId -// if (serverId == null) { -// continue; -// // Also check if this message is referenced elsewhere -// } else if (messageReferenced(cr, c.getLong(Message.CONTENT_ID_COLUMN))) { -// userLog("Postponing deletion of referenced message: ", serverId); -// continue; -// } else if (first) { -// s.start(Tags.SYNC_COMMANDS); -// first = false; -// } -// // Send the command to delete this message -// s.start(Tags.SYNC_DELETE).data(Tags.SYNC_SERVER_ID, serverId).end(); -// deletedIds.add(c.getLong(Message.LIST_ID_COLUMN)); -// } -// } finally { -// c.close(); -// } - - return first; - } - - @Override - public boolean sendLocalChanges(Serializer s) throws IOException { -// ContentResolver cr = mContext.getContentResolver(); -// -// // Never upsync from these folders -// if (mMailbox.mType == Mailbox.TYPE_DRAFTS || mMailbox.mType == Mailbox.TYPE_OUTBOX) { -// return false; -// } -// -// // This code is split out for unit testing purposes -// boolean firstCommand = sendDeletedItems(s, mDeletedIdList, true); -// -// // Find our trash mailbox, since deletions will have been moved there... -// long trashMailboxId = -// Mailbox.findMailboxOfType(mContext, mMailbox.mAccountKey, Mailbox.TYPE_TRASH); -// -// // Do the same now for updated items -// Cursor c = cr.query(Message.UPDATED_CONTENT_URI, Message.LIST_PROJECTION, -// MessageColumns.MAILBOX_KEY + '=' + mMailbox.mId, null, null); -// -// // We keep track of the list of updated item id's as we did above with deleted items -// mUpdatedIdList.clear(); -// try { -// while (c.moveToNext()) { -// long id = c.getLong(Message.LIST_ID_COLUMN); -// // Say we've handled this update -// mUpdatedIdList.add(id); -// // We have the id of the changed item. But first, we have to find out its current -// // state, since the updated table saves the opriginal state -// Cursor currentCursor = cr.query(ContentUris.withAppendedId(Message.CONTENT_URI, id), -// UPDATES_PROJECTION, null, null, null); -// try { -// // If this item no longer exists (shouldn't be possible), just move along -// if (!currentCursor.moveToFirst()) { -// continue; -// } -// // Keep going if there's no serverId -// String serverId = currentCursor.getString(UPDATES_SERVER_ID_COLUMN); -// if (serverId == null) { -// continue; -// } -// // If the message is now in the trash folder, it has been deleted by the user -// if (currentCursor.getLong(UPDATES_MAILBOX_KEY_COLUMN) == trashMailboxId) { -// if (firstCommand) { -// s.start(Tags.SYNC_COMMANDS); -// firstCommand = false; -// } -// // Send the command to delete this message -// s.start(Tags.SYNC_DELETE).data(Tags.SYNC_SERVER_ID, serverId).end(); -// continue; -// } -// -// boolean flagChange = false; -// boolean readChange = false; -// -// int flag = 0; -// -// // We can only send flag changes to the server in 12.0 or later -// if (mService.mProtocolVersionDouble >= Eas.SUPPORTED_PROTOCOL_EX2007_DOUBLE) { -// flag = currentCursor.getInt(UPDATES_FLAG_COLUMN); -// if (flag != c.getInt(Message.LIST_FAVORITE_COLUMN)) { -// flagChange = true; -// } -// } -// -// int read = currentCursor.getInt(UPDATES_READ_COLUMN); -// if (read != c.getInt(Message.LIST_READ_COLUMN)) { -// readChange = true; -// } -// -// if (!flagChange && !readChange) { -// // In this case, we've got nothing to send to the server -// continue; -// } -// -// if (firstCommand) { -// s.start(Tags.SYNC_COMMANDS); -// firstCommand = false; -// } -// // Send the change to "read" and "favorite" (flagged) -// s.start(Tags.SYNC_CHANGE) -// .data(Tags.SYNC_SERVER_ID, c.getString(Message.LIST_SERVER_ID_COLUMN)) -// .start(Tags.SYNC_APPLICATION_DATA); -// if (readChange) { -// s.data(Tags.EMAIL_READ, Integer.toString(read)); -// } -// // "Flag" is a relatively complex concept in EAS 12.0 and above. It is not only -// // the boolean "favorite" that we think of in Gmail, but it also represents a -// // follow up action, which can include a subject, start and due dates, and even -// // recurrences. We don't support any of this as yet, but EAS 12.0 and higher -// // require that a flag contain a status, a type, and four date fields, two each -// // for start date and end (due) date. -// if (flagChange) { -// if (flag != 0) { -// // Status 2 = set flag -// s.start(Tags.EMAIL_FLAG).data(Tags.EMAIL_FLAG_STATUS, "2"); -// // "FollowUp" is the standard type -// s.data(Tags.EMAIL_FLAG_TYPE, "FollowUp"); -// long now = System.currentTimeMillis(); -// Calendar calendar = -// GregorianCalendar.getInstance(TimeZone.getTimeZone("GMT")); -// calendar.setTimeInMillis(now); -// // Flags are required to have a start date and end date (duplicated) -// // First, we'll set the current date/time in GMT as the start time -// String utc = formatDateTime(calendar); -// s.data(Tags.TASK_START_DATE, utc).data(Tags.TASK_UTC_START_DATE, utc); -// // And then we'll use one week from today for completion date -// calendar.setTimeInMillis(now + 1*WEEKS); -// utc = formatDateTime(calendar); -// s.data(Tags.TASK_DUE_DATE, utc).data(Tags.TASK_UTC_DUE_DATE, utc); -// s.end(); -// } else { -// s.tag(Tags.EMAIL_FLAG); -// } -// } -// s.end().end(); // SYNC_APPLICATION_DATA, SYNC_CHANGE -// } finally { -// currentCursor.close(); -// } -// } -// } finally { -// c.close(); -// } -// -// if (!firstCommand) { -// s.end(); // SYNC_COMMANDS -// } - return false; - } - - public List getMessages() { - return newEmails; - } -} diff --git a/src/com/fsck/k9/mail/store/exchange/adapter/FolderSyncParser.java b/src/com/fsck/k9/mail/store/exchange/adapter/FolderSyncParser.java index 70a6fece7..73919312f 100644 --- a/src/com/fsck/k9/mail/store/exchange/adapter/FolderSyncParser.java +++ b/src/com/fsck/k9/mail/store/exchange/adapter/FolderSyncParser.java @@ -21,7 +21,6 @@ import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Arrays; -import java.util.LinkedList; import java.util.List; import android.content.ContentProviderOperation; @@ -38,7 +37,7 @@ import com.fsck.k9.mail.store.exchange.Eas; * Handles the addition, deletion, and changes to folders in the user's Exchange account. **/ -public class FolderSyncParser extends AbstractSyncParser { +public class FolderSyncParser extends Parser { public static final String TAG = "FolderSyncParser"; @@ -57,7 +56,7 @@ public class FolderSyncParser extends AbstractSyncParser { public static final int USER_MAILBOX_TYPE = 12; public static final List mValidFolderTypes = Arrays.asList(INBOX_TYPE, DRAFTS_TYPE, - DELETED_TYPE, SENT_TYPE, OUTBOX_TYPE, USER_MAILBOX_TYPE, CALENDAR_TYPE, CONTACTS_TYPE); + DELETED_TYPE, SENT_TYPE, OUTBOX_TYPE, USER_MAILBOX_TYPE);//, CALENDAR_TYPE, CONTACTS_TYPE); // public static final String ALL_BUT_ACCOUNT_MAILBOX = MailboxColumns.ACCOUNT_KEY + "=? and " + // MailboxColumns.TYPE + "!=" + Mailbox.TYPE_EAS_ACCOUNT_MAILBOX; @@ -81,8 +80,9 @@ public class FolderSyncParser extends AbstractSyncParser { private EasStore easStore; - public FolderSyncParser(InputStream in, AbstractSyncAdapter adapter, EasStore easStore, List folderList) throws IOException { - super(in, adapter, adapter.mFolder, adapter.mAccount); + public FolderSyncParser(InputStream in, EasStore easStore, List folderList) throws IOException { + super(in); + this.easStore = easStore; this.folderList = folderList; // mAccountId = mAccount.mId; @@ -118,8 +118,7 @@ public class FolderSyncParser extends AbstractSyncParser { } } } else if (tag == Tags.FOLDER_SYNC_KEY) { - getValue(); -// mAccount.mSyncKey = getValue(); + easStore.setStoreSyncKey(getValue()); userLog("New Account SyncKey: ", easStore.getStoreSyncKey()); } else if (tag == Tags.FOLDER_CHANGES) { changesParser(); @@ -367,27 +366,12 @@ public class FolderSyncParser extends AbstractSyncParser { // } } - /** - * Not needed for FolderSync parsing; everything is done within changesParser - */ - @Override - public void commandsParser() throws IOException { + void userLog(String ...strings) { + Log.i(K9.LOG_TAG, Arrays.toString(strings)); } - /** - * We don't need to implement commit() because all operations take place atomically within - * changesParser - */ - @Override - public void commit() throws IOException { + void userLog(String string, int num, String string2) { + Log.i(K9.LOG_TAG, string + num + string2); } - - @Override - public void wipe() { - } - - @Override - public void responsesParser() throws IOException { - } - + } diff --git a/src/com/fsck/k9/mail/store/exchange/adapter/GetItemEstimateParser.java b/src/com/fsck/k9/mail/store/exchange/adapter/GetItemEstimateParser.java deleted file mode 100644 index 62d4de63a..000000000 --- a/src/com/fsck/k9/mail/store/exchange/adapter/GetItemEstimateParser.java +++ /dev/null @@ -1,67 +0,0 @@ -package com.fsck.k9.mail.store.exchange.adapter; - -import java.io.IOException; -import java.io.InputStream; - -public class GetItemEstimateParser extends Parser { - - private String mCollectionId; - private int mEstimate; - - public GetItemEstimateParser(InputStream in) throws IOException { - super(in); - } - - @Override - public boolean parse() throws IOException { - boolean res = true; - if (nextTag(START_DOCUMENT) != Tags.GIE_GET_ITEM_ESTIMATE) { - throw new IOException(); - } - while (nextTag(START_DOCUMENT) != END_DOCUMENT) { - switch (tag) { - case Tags.GIE_RESPONSE: - res = parseGIEResponse() && res; - break; - default: - skipTag(); - } - } - return res; - } - - private boolean parseGIEResponse() throws IOException { - if (nextTag(Tags.GIE_RESPONSE) == Tags.GIE_STATUS) { - int status = getValueInt(); - if (status != 1) - return false; - - if (nextTag(Tags.GIE_RESPONSE) == Tags.GIE_COLLECTION) { - String collectionId; - int estimate; - - if (nextTag(Tags.GIE_COLLECTION) == Tags.GIE_COLLECTION_ID) { - collectionId = getValue(); - } else return false; - - if (nextTag(Tags.GIE_COLLECTION) == Tags.GIE_ESTIMATE) { - estimate = getValueInt(); - } else return false; - - mCollectionId = collectionId; - mEstimate = estimate; - return true; - } - } - return false; - } - - public String getCollectionId() { - return mCollectionId; - } - - public int getEstimate() { - return mEstimate; - } - -}