diff --git a/res/layout/account_setup_incoming.xml b/res/layout/account_setup_incoming.xml index 26de1df5d..30a1fbca6 100644 --- a/res/layout/account_setup_incoming.xml +++ b/res/layout/account_setup_incoming.xml @@ -212,6 +212,49 @@ android:text="@string/account_setup_incoming_other_label" /> + + + + + + + + + 4 5 + + + @string/idle_refresh_period_1min + @string/idle_refresh_period_2min + @string/idle_refresh_period_3min + @string/idle_refresh_period_6min + @string/idle_refresh_period_12min + @string/idle_refresh_period_24min + @string/idle_refresh_period_36min + @string/idle_refresh_period_48min + @string/idle_refresh_period_60min + + + + 1 + 2 + 3 + 6 + 12 + 24 + 36 + 48 + 60 + diff --git a/res/values/strings.xml b/res/values/strings.xml index 436e7514e..e26b77043 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -405,10 +405,20 @@ Welcome to K-9 Mail setup. K-9 is an open source mail client for Android origin Every 12 hours Every 24 hours - + Poll when connecting for push Enable push mail for this account If your server supports it, new messages will appear instantly. This option can dramatically improve or hurt performance. - + Refresh IDLE connection + Every minute + Every 2 minutes + Every 3 minutes + Every 6 minutes + Every 12 minutes + Every 24 minutes + Every 36 minutes + Every 48 minutes + Every 60 minutes + Send mail from this account by default Notify me when mail arrives Notify me while mail is being checked diff --git a/res/xml/account_settings_preferences.xml b/res/xml/account_settings_preferences.xml index 610dc6179..1b28fcf2e 100644 --- a/res/xml/account_settings_preferences.xml +++ b/res/xml/account_settings_preferences.xml @@ -81,13 +81,6 @@ android:entryValues="@array/account_settings_folder_push_mode_values" android:dialogTitle="@string/account_settings_folder_push_mode_label" /> - - compressionMap = new ConcurrentHashMap(); private Searchable searchableFolders; // Tracks if we have sent a notification for this account for @@ -111,6 +113,8 @@ public class Account implements BaseAccount mUuid = UUID.randomUUID().toString(); mLocalStoreUri = "local://localhost/" + context.getDatabasePath(mUuid + ".db"); mAutomaticCheckIntervalMinutes = -1; + mIdleRefreshMinutes = 24; + mPushPollOnConnect = true; mDisplayCount = -1; mAccountNumber = -1; mNotifyNewMail = true; @@ -161,6 +165,10 @@ public class Account implements BaseAccount mAlwaysBcc = preferences.getPreferences().getString(mUuid + ".alwaysBcc", mAlwaysBcc); mAutomaticCheckIntervalMinutes = preferences.getPreferences().getInt(mUuid + ".automaticCheckIntervalMinutes", -1); + mIdleRefreshMinutes = preferences.getPreferences().getInt(mUuid + + ".idleRefreshMinutes", 24); + mPushPollOnConnect = preferences.getPreferences().getBoolean(mUuid + + ".pushPollOnConnect", true); mDisplayCount = preferences.getPreferences().getInt(mUuid + ".displayCount", -1); mLastAutomaticCheckTime = preferences.getPreferences().getLong(mUuid + ".lastAutomaticCheckTime", 0); @@ -321,6 +329,8 @@ public class Account implements BaseAccount editor.remove(mUuid + ".email"); editor.remove(mUuid + ".alwaysBcc"); editor.remove(mUuid + ".automaticCheckIntervalMinutes"); + editor.remove(mUuid + ".pushPollOnConnect"); + editor.remove(mUuid + ".idleRefreshMinutes"); editor.remove(mUuid + ".lastAutomaticCheckTime"); editor.remove(mUuid + ".notifyNewMail"); editor.remove(mUuid + ".notifySelfNewMail"); @@ -397,6 +407,8 @@ public class Account implements BaseAccount editor.putString(mUuid + ".description", mDescription); editor.putString(mUuid + ".alwaysBcc", mAlwaysBcc); editor.putInt(mUuid + ".automaticCheckIntervalMinutes", mAutomaticCheckIntervalMinutes); + editor.putInt(mUuid + ".idleRefreshMinutes", mIdleRefreshMinutes); + editor.putBoolean(mUuid + ".pushPollOnConnect", mPushPollOnConnect); editor.putInt(mUuid + ".displayCount", mDisplayCount); editor.putLong(mUuid + ".lastAutomaticCheckTime", mLastAutomaticCheckTime); editor.putBoolean(mUuid + ".notifyNewMail", mNotifyNewMail); @@ -1120,4 +1132,24 @@ public class Account implements BaseAccount { this.searchableFolders = searchableFolders; } + + public int getIdleRefreshMinutes() + { + return mIdleRefreshMinutes; + } + + public void setIdleRefreshMinutes(int idleRefreshMinutes) + { + mIdleRefreshMinutes = idleRefreshMinutes; + } + + public boolean isPushPollOnConnect() + { + return mPushPollOnConnect; + } + + public void setPushPollOnConnect(boolean pushPollOnConnect) + { + mPushPollOnConnect = pushPollOnConnect; + } } diff --git a/src/com/fsck/k9/MessagingController.java b/src/com/fsck/k9/MessagingController.java index 2c7986a78..9576899de 100644 --- a/src/com/fsck/k9/MessagingController.java +++ b/src/com/fsck/k9/MessagingController.java @@ -985,14 +985,7 @@ public class MessagingController implements Runnable { Folder remoteFolder = null; LocalFolder tLocalFolder = null; - /* - * We don't ever sync the Outbox or errors folder - */ - if (folder.equals(account.getOutboxFolderName()) || folder.equals(account.getErrorFolderName())) - { - return; - } - + if (K9.DEBUG) Log.i(K9.LOG_TAG, "Synchronizing folder " + account.getDescription() + ":" + folder); @@ -1004,6 +997,22 @@ public class MessagingController implements Runnable { listener.synchronizeMailboxStarted(account, folder); } + /* + * We don't ever sync the Outbox or errors folder + */ + if (folder.equals(account.getOutboxFolderName()) || folder.equals(account.getErrorFolderName())) + { + for (MessagingListener l : getListeners()) + { + l.synchronizeMailboxFinished(account, folder, 0, 0); + } + if (listener != null && getListeners().contains(listener) == false) + { + listener.synchronizeMailboxFinished(account, folder, 0, 0); + } + + return; + } Exception commandException = null; try diff --git a/src/com/fsck/k9/activity/setup/AccountSettings.java b/src/com/fsck/k9/activity/setup/AccountSettings.java index 7e9fe82a6..2c2f62cd7 100644 --- a/src/com/fsck/k9/activity/setup/AccountSettings.java +++ b/src/com/fsck/k9/activity/setup/AccountSettings.java @@ -43,7 +43,6 @@ public class AccountSettings extends K9PreferenceActivity private static final String PREFERENCE_DISPLAY_MODE = "folder_display_mode"; private static final String PREFERENCE_SYNC_MODE = "folder_sync_mode"; private static final String PREFERENCE_PUSH_MODE = "folder_push_mode"; - private static final String PREFERENCE_PUSH_LIMIT = "folder_push_limit"; private static final String PREFERENCE_TARGET_MODE = "folder_target_mode"; private static final String PREFERENCE_DELETE_POLICY = "delete_policy"; private static final String PREFERENCE_EXPUNGE_POLICY = "expunge_policy"; @@ -67,7 +66,6 @@ public class AccountSettings extends K9PreferenceActivity private ListPreference mDisplayMode; private ListPreference mSyncMode; private ListPreference mPushMode; - private ListPreference mPushLimit; private ListPreference mTargetMode; private ListPreference mDeletePolicy; private ListPreference mExpungePolicy; @@ -187,22 +185,6 @@ public class AccountSettings extends K9PreferenceActivity } }); - mPushLimit = (ListPreference) findPreference(PREFERENCE_PUSH_LIMIT); - mPushLimit.setEnabled(isPushCapable); - mPushLimit.setValue(String.valueOf(mAccount.getMaxPushFolders())); - mPushLimit.setSummary(mPushLimit.getEntry()); - mPushLimit.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() - { - public boolean onPreferenceChange(Preference preference, Object newValue) - { - final String summary = newValue.toString(); - int index = mPushLimit.findIndexOfValue(summary); - mPushLimit.setSummary(mPushLimit.getEntries()[index]); - mPushLimit.setValue(summary); - return false; - } - }); - mTargetMode = (ListPreference) findPreference(PREFERENCE_TARGET_MODE); mTargetMode.setValue(mAccount.getFolderTargetMode().name()); mTargetMode.setSummary(mTargetMode.getEntry()); @@ -425,7 +407,6 @@ public class AccountSettings extends K9PreferenceActivity if (mAccount.getFolderPushMode() != FolderMode.NONE) { needsPushRestart |= mAccount.setFolderDisplayMode(Account.FolderMode.valueOf(mDisplayMode.getValue())); - needsPushRestart |= mAccount.setMaxPushFolders(Integer.parseInt(mPushLimit.getValue())); needsPushRestart |= mIncomingChanged; } diff --git a/src/com/fsck/k9/activity/setup/AccountSetupIncoming.java b/src/com/fsck/k9/activity/setup/AccountSetupIncoming.java index d3d5839fb..747efae90 100644 --- a/src/com/fsck/k9/activity/setup/AccountSetupIncoming.java +++ b/src/com/fsck/k9/activity/setup/AccountSetupIncoming.java @@ -83,6 +83,9 @@ public class AccountSetupIncoming extends K9Activity implements OnClickListener private CheckBox compressionMobile; private CheckBox compressionWifi; private CheckBox compressionOther; + private CheckBox pushPollOnConnect; + private Spinner idleRefreshPeriod; + private Spinner folderPushLimit; public static void actionIncomingSettings(Activity context, Account account, boolean makeDefault) { @@ -125,7 +128,11 @@ public class AccountSetupIncoming extends K9Activity implements OnClickListener compressionMobile = (CheckBox)findViewById(R.id.compression_mobile); compressionWifi = (CheckBox)findViewById(R.id.compression_wifi); compressionOther = (CheckBox)findViewById(R.id.compression_other); + pushPollOnConnect = (CheckBox)findViewById(R.id.push_poll_on_connect); + idleRefreshPeriod = (Spinner)findViewById(R.id.idle_refresh_period); + folderPushLimit = (Spinner)findViewById(R.id.folder_push_limit); + mImapFolderDrafts.setOnClickListener(this); mImapFolderSent.setOnClickListener(this); mImapFolderTrash.setOnClickListener(this); @@ -287,6 +294,11 @@ public class AccountSetupIncoming extends K9Activity implements OnClickListener findViewById(R.id.webdav_path_debug_section).setVisibility(View.GONE); findViewById(R.id.account_auth_type).setVisibility(View.GONE); findViewById(R.id.compression_section).setVisibility(View.GONE); + findViewById(R.id.push_poll_on_connect_section).setVisibility(View.GONE); + findViewById(R.id.idle_refresh_period_label).setVisibility(View.GONE); + findViewById(R.id.idle_refresh_period).setVisibility(View.GONE); + findViewById(R.id.account_setup_push_limit_label).setVisibility(View.GONE); + findViewById(R.id.folder_push_limit).setVisibility(View.GONE); mAccount.setDeletePolicy(Account.DELETE_POLICY_NEVER); @@ -321,6 +333,11 @@ public class AccountSetupIncoming extends K9Activity implements OnClickListener findViewById(R.id.imap_path_prefix_section).setVisibility(View.GONE); findViewById(R.id.account_auth_type).setVisibility(View.GONE); findViewById(R.id.compression_section).setVisibility(View.GONE); + findViewById(R.id.push_poll_on_connect_section).setVisibility(View.GONE); + findViewById(R.id.idle_refresh_period_label).setVisibility(View.GONE); + findViewById(R.id.idle_refresh_period).setVisibility(View.GONE); + findViewById(R.id.account_setup_push_limit_label).setVisibility(View.GONE); + findViewById(R.id.folder_push_limit).setVisibility(View.GONE); if (uri.getPath() != null && uri.getPath().length() > 0) { String[] pathParts = uri.getPath().split("\\|"); @@ -383,7 +400,13 @@ public class AccountSetupIncoming extends K9Activity implements OnClickListener { updatePortFromSecurityType(); } - + pushPollOnConnect.setChecked(mAccount.isPushPollOnConnect()); + SpinnerHelper.initSpinner(this, idleRefreshPeriod, R.array.idle_refresh_period_entries, + R.array.idle_refresh_period_values, String.valueOf(mAccount.getIdleRefreshMinutes())); + + SpinnerHelper.initSpinner(this, folderPushLimit, R.array.account_settings_push_limit_entries, + R.array.account_settings_push_limit_values, String.valueOf(mAccount.getMaxPushFolders())); + validateFields(); } catch (Exception e) @@ -532,6 +555,28 @@ public class AccountSetupIncoming extends K9Activity implements OnClickListener mAccount.setCompression(Account.TYPE_MOBILE, compressionMobile.isChecked()); mAccount.setCompression(Account.TYPE_WIFI, compressionWifi.isChecked()); mAccount.setCompression(Account.TYPE_OTHER, compressionOther.isChecked()); + mAccount.setPushPollOnConnect(pushPollOnConnect.isChecked()); + String idleRefreshPeriodValue = SpinnerHelper.getSpinnerValue(idleRefreshPeriod); + try + { + mAccount.setIdleRefreshMinutes(Integer.parseInt(idleRefreshPeriodValue)); + } + catch (Exception e) + { + Log.e(K9.LOG_TAG, "Unable to parse idle refresh period value '" + idleRefreshPeriodValue + "'", e); + mAccount.setIdleRefreshMinutes(24); + } + String maxPushFoldersValue = SpinnerHelper.getSpinnerValue(folderPushLimit); + try + { + mAccount.setMaxPushFolders(Integer.parseInt(maxPushFoldersValue)); + } + catch (Exception e) + { + Log.e(K9.LOG_TAG, "Unable to parse max push folders value '" + maxPushFoldersValue + "'", e); + mAccount.setMaxPushFolders(10); + } + AccountSetupCheckSettings.actionCheckSettings(this, mAccount, true, false); } catch (Exception e) diff --git a/src/com/fsck/k9/activity/setup/SpinnerHelper.java b/src/com/fsck/k9/activity/setup/SpinnerHelper.java new file mode 100644 index 000000000..d902d3fc1 --- /dev/null +++ b/src/com/fsck/k9/activity/setup/SpinnerHelper.java @@ -0,0 +1,88 @@ +package com.fsck.k9.activity.setup; +/* + * SpinnerHelper donated to K-9 Mail by Boutique Software + */ + +import android.content.Context; +import android.widget.ArrayAdapter; +import android.widget.Spinner; + +public class SpinnerHelper +{ + public static void initSpinner(Context context, Spinner spinner, int entryRes, int valueRes, String curVal) + { + String[] entryArray = context.getResources().getStringArray(entryRes); + String[] valueArray = context.getResources().getStringArray(valueRes); + initSpinner(context, spinner, entryArray, valueArray, curVal); + } + public static void initSpinner(Context context, Spinner spinner, String[] entryArray, String[] valueArray, String curVal) + { + + if (entryArray.length != valueArray.length){ + throw new RuntimeException("Entry and value arrays are of unequal lenght"); + } + + EntryValue[] entryValues = new EntryValue[entryArray.length]; + int curSelection = 0; + for (int i = 0; i < entryArray.length; i++) + { + entryValues[i] = new EntryValue(entryArray[i], valueArray[i]); + if (valueArray[i].equals(curVal)) + { + curSelection = i; + } + } + + ArrayAdapter entryValuesAdapter = new ArrayAdapter(context, android.R.layout.simple_spinner_item, entryValues); + entryValuesAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); + spinner.setAdapter(entryValuesAdapter); + spinner.setSelection(curSelection); + } + + public static String getSpinnerValue(Spinner spinner) + { + EntryValue entryValue = (EntryValue)spinner.getSelectedItem(); + if (entryValue != null) + { + return entryValue.getValue(); + } + else + { + return null; + } + } + public static String getSpinnerEntry(Spinner spinner) + { + EntryValue entryValue = (EntryValue)spinner.getSelectedItem(); + if (entryValue != null) + { + return entryValue.getEntry(); + } + else + { + return null; + } + } + private static class EntryValue + { + final String entry; + final String value; + EntryValue(String entry, String value) + { + this.entry = entry; + this.value = value; + } + public String toString() + { + return entry; + } + public String getEntry() + { + return entry; + } + public String getValue() + { + return value; + } + } +} diff --git a/src/com/fsck/k9/mail/Pusher.java b/src/com/fsck/k9/mail/Pusher.java index 44cf5254c..42ed525ea 100644 --- a/src/com/fsck/k9/mail/Pusher.java +++ b/src/com/fsck/k9/mail/Pusher.java @@ -13,4 +13,6 @@ public interface Pusher * @return milliseconds of required refresh interval */ public int getRefreshInterval(); + public void setLastRefresh(long lastRefresh); + public long getLastRefresh(); } diff --git a/src/com/fsck/k9/mail/store/ImapResponseParser.java b/src/com/fsck/k9/mail/store/ImapResponseParser.java index 79a768948..f4afac0bf 100644 --- a/src/com/fsck/k9/mail/store/ImapResponseParser.java +++ b/src/com/fsck/k9/mail/store/ImapResponseParser.java @@ -417,7 +417,7 @@ public class ImapResponseParser { for (int i = 0, count = size(); i < count; i++) { - if (get(i).equals(key)) + if (equalsIgnoreCase(get(i), key)) { return get(i + 1); } @@ -471,7 +471,7 @@ public class ImapResponseParser for (int i = 0, count = size(); i < count; i++) { - if (key.equals(get(i))) + if (equalsIgnoreCase(key, get(i))) { return true; } @@ -483,7 +483,7 @@ public class ImapResponseParser { for (int i = 0, count = size(); i < count; i++) { - if (key.equals(get(i))) + if (equalsIgnoreCase(key, get(i))) { return i; } @@ -552,7 +552,7 @@ public class ImapResponseParser public String getAlertText() { - if (size() > 1 && "[ALERT]".equals(get(1))) + if (size() > 1 && equalsIgnoreCase("[ALERT]", get(1))) { StringBuffer sb = new StringBuffer(); for (int i = 2, count = size(); i < count; i++) @@ -574,4 +574,25 @@ public class ImapResponseParser return "#" + (mCommandContinuationRequested ? "+" : mTag) + "# " + super.toString(); } } + public static boolean equalsIgnoreCase(Object o1, Object o2) + { + if (o1 != null && o2 != null && o1 instanceof String && o2 instanceof String) + { + String s1 = (String)o1; + String s2 = (String)o2; + return s1.equalsIgnoreCase(s2); + } + else if (o1 != null) + { + return o1.equals(o2); + } + else if (o2 != null) + { + return o2.equals(o1); + } + else + { + return o1 == o2; + } + } } diff --git a/src/com/fsck/k9/mail/store/ImapStore.java b/src/com/fsck/k9/mail/store/ImapStore.java index c33d05229..895730204 100644 --- a/src/com/fsck/k9/mail/store/ImapStore.java +++ b/src/com/fsck/k9/mail/store/ImapStore.java @@ -60,8 +60,7 @@ public class ImapStore extends Store private enum AuthType { PLAIN, CRAM_MD5 }; - private static final int IDLE_READ_TIMEOUT = 29 * 60 * 1000; // 29 minutes - private static final int IDLE_REFRESH_INTERVAL = 20 * 60 * 1000; // 20 minutes + private static final int IDLE_READ_TIMEOUT_INCREMENT = 5 * 60 * 1000; private static final int IDLE_FAILURE_COUNT_LIMIT = 10; private static int MAX_DELAY_TIME = 5 * 60 * 1000; // 5 minutes private static int NORMAL_DELAY_TIME = 5000; @@ -261,7 +260,7 @@ public class ImapStore extends Store for (ImapResponse response : responses) { - if (response.get(0).equals("LIST")) + if (ImapResponseParser.equalsIgnoreCase(response.get(0), "LIST")) { boolean includeFolder = true; String folder = decodeFolderName(response.getString(3)); @@ -285,7 +284,7 @@ public class ImapStore extends Store { folder = folder.substring(getCombinedPrefix().length()); } - if (!decodeFolderName(response.getString(3)).equals(getCombinedPrefix() + folder)) + if (!decodeFolderName(response.getString(3)).equalsIgnoreCase(getCombinedPrefix() + folder)) { includeFolder = false; } @@ -794,7 +793,7 @@ public class ImapStore extends Store if (messages.length == 0) return; - if (trashFolderName == null || getName().equals(trashFolderName)) + if (trashFolderName == null || getName().equalsIgnoreCase(trashFolderName)) { setFlags(messages, new Flag[] { Flag.DELETED }, true); } @@ -850,7 +849,7 @@ public class ImapStore extends Store List responses = executeSimpleCommand(String.format("SEARCH %d:* UNSEEN NOT DELETED", start)); for (ImapResponse response : responses) { - if (response.get(0).equals("SEARCH")) + if (ImapResponseParser.equalsIgnoreCase(response.get(0), "SEARCH")) { count += response.size() - 1; } @@ -878,7 +877,7 @@ public class ImapStore extends Store List responses = executeSimpleCommand(String.format("SEARCH %d:* FLAGGED NOT DELETED", start)); for (ImapResponse response : responses) { - if (response.get(0).equals("SEARCH")) + if (ImapResponseParser.equalsIgnoreCase(response.get(0), "SEARCH")) { count += response.size() - 1; } @@ -981,7 +980,7 @@ public class ImapStore extends Store { if (response.mTag == null) { - if (response.get(0).equals("SEARCH")) + if (ImapResponseParser.equalsIgnoreCase(response.get(0), "SEARCH")) { for (int i = 1, count = response.size(); i < count; i++) { @@ -1035,7 +1034,7 @@ public class ImapStore extends Store ArrayList tempUids = new ArrayList(); for (ImapResponse response : responses) { - if (response.get(0).equals("SEARCH")) + if (ImapResponseParser.equalsIgnoreCase(response.get(0), "SEARCH")) { for (int i = 1, count = response.size(); i < count; i++) { @@ -1123,7 +1122,7 @@ public class ImapStore extends Store if (parts != null) { String partId = parts[0]; - if ("TEXT".equals(partId)) + if ("TEXT".equalsIgnoreCase(partId)) { fetchFields.add(String.format("BODY.PEEK[TEXT]<0.%d>", FETCH_BODY_SANE_SUGGESTED_SIZE)); } @@ -1149,7 +1148,7 @@ public class ImapStore extends Store if (K9.DEBUG) Log.v(K9.LOG_TAG, "response for fetch: " + response + " for " + getLogId()); - if (response.mTag == null && response.get(1).equals("FETCH")) + if (response.mTag == null && ImapResponseParser.equalsIgnoreCase(response.get(1), "FETCH")) { ImapList fetchList = (ImapList)response.getKeyedValue("FETCH"); String uid = fetchList.getKeyedString("UID"); @@ -1178,19 +1177,19 @@ public class ImapStore extends Store for (int i = 0, count = flags.size(); i < count; i++) { String flag = flags.getString(i); - if (flag.equals("\\Deleted")) + if (flag.equalsIgnoreCase("\\Deleted")) { imapMessage.setFlagInternal(Flag.DELETED, true); } - else if (flag.equals("\\Answered")) + else if (flag.equalsIgnoreCase("\\Answered")) { imapMessage.setFlagInternal(Flag.ANSWERED, true); } - else if (flag.equals("\\Seen")) + else if (flag.equalsIgnoreCase("\\Seen")) { imapMessage.setFlagInternal(Flag.SEEN, true); } - else if (flag.equals("\\Flagged")) + else if (flag.equalsIgnoreCase("\\Flagged")) { imapMessage.setFlagInternal(Flag.FLAGGED, true); } @@ -1325,7 +1324,7 @@ public class ImapStore extends Store protected void handlePossibleUidNext(ImapResponse response) { - if (response.get(0).equals("OK") && response.size() > 1) + if (ImapResponseParser.equalsIgnoreCase(response.get(0), "OK") && response.size() > 1) { Object bracketedObj = response.get(1); if (bracketedObj instanceof ImapList) @@ -1338,7 +1337,7 @@ public class ImapStore extends Store if (keyObj instanceof String) { String key = (String)keyObj; - if ("UIDNEXT".equals(key)) + if ("UIDNEXT".equalsIgnoreCase(key)) { uidNext = bracketed.getNumber(1); if (K9.DEBUG) @@ -1360,7 +1359,7 @@ public class ImapStore extends Store { if (response.mTag == null && response.size() > 1) { - if (response.get(1).equals("EXISTS")) + if (ImapResponseParser.equalsIgnoreCase(response.get(1), "EXISTS")) { mMessageCount = response.getNumber(0); if (K9.DEBUG) @@ -1368,7 +1367,7 @@ public class ImapStore extends Store } handlePossibleUidNext(response); - if (response.get(1).equals("EXPUNGE") && mMessageCount > 0) + if (ImapResponseParser.equalsIgnoreCase(response.get(1), "EXPUNGE") && mMessageCount > 0) { mMessageCount--; if (K9.DEBUG) @@ -1386,7 +1385,7 @@ public class ImapStore extends Store // if (keyObj instanceof String) // { // String key = (String)keyObj; -// if ("ALERT".equals(key)) +// if ("ALERT".equalsIgnoreCase(key)) // { // StringBuffer sb = new StringBuffer(); // for (int i = 2, count = response.size(); i < count; i++) { @@ -1424,7 +1423,7 @@ public class ImapStore extends Store * into it. */ ImapBodyPart bp = new ImapBodyPart(); - if (id.equals("TEXT")) + if (id.equalsIgnoreCase("TEXT")) { parseBodyStructure(bs.getList(i), bp, Integer.toString(i + 1)); } @@ -1671,7 +1670,7 @@ public class ImapStore extends Store String.format("UID SEARCH HEADER MESSAGE-ID %s", messageId)); for (ImapResponse response1 : responses) { - if (response1.mTag == null && response1.get(0).equals("SEARCH") + if (response1.mTag == null && ImapResponseParser.equalsIgnoreCase(response1.get(0), "SEARCH") && response1.size() > 1) { return response1.getString(1); @@ -1839,7 +1838,7 @@ public class ImapStore extends Store { if (o instanceof ImapFolder) { - return ((ImapFolder)o).getPrefixedName().equals(getPrefixedName()); + return ((ImapFolder)o).getPrefixedName().equalsIgnoreCase(getPrefixedName()); } return super.equals(o); } @@ -1888,14 +1887,14 @@ public class ImapStore extends Store for (ImapResponse response : responses) { ImapList capabilityList = null; - if (response.size() > 0 && response.get(0).equals("OK")) + if (response.size() > 0 && ImapResponseParser.equalsIgnoreCase(response.get(0), "OK")) { for (Object thisPart : response) { if (thisPart instanceof ImapList) { ImapList thisList = (ImapList)thisPart; - if (thisList.get(0).equals(CAPABILITY_CAPABILITY)) + if (ImapResponseParser.equalsIgnoreCase(thisList.get(0), CAPABILITY_CAPABILITY)) { capabilityList = thisList; break; @@ -1910,7 +1909,7 @@ public class ImapStore extends Store if (capabilityList != null) { - if (capabilityList.size() > 0 && capabilityList.get(0).equals(CAPABILITY_CAPABILITY)) + if (capabilityList.size() > 0 && ImapResponseParser.equalsIgnoreCase(capabilityList.get(0), CAPABILITY_CAPABILITY)) { if (K9.DEBUG) { @@ -2040,6 +2039,12 @@ public class ImapStore extends Store try { + if (mHost.endsWith("yahoo.com")) + { + if (K9.DEBUG) + Log.v(K9.LOG_TAG, "Found Yahoo! account. Sending proprietary commands."); + executeSimpleCommand("ID (\"GUID\" \"1\")"); + } if (mAuthType == AuthType.CRAM_MD5) { authCramMD5(); @@ -2129,7 +2134,7 @@ public class ImapStore extends Store executeSimpleCommand(COMMAND_NAMESPACE); for (ImapResponse response : namespaceResponses) { - if (response.get(0).equals(COMMAND_NAMESPACE)) + if (ImapResponseParser.equalsIgnoreCase(response.get(0), COMMAND_NAMESPACE)) { if (K9.DEBUG) Log.d(K9.LOG_TAG, "Got NAMESPACE response " + response + " on " + getLogId()); @@ -2464,7 +2469,7 @@ public class ImapStore extends Store if (K9.DEBUG) Log.v(K9.LOG_TAG, getLogId() + "<<<" + response); - if (response.mTag != null && response.mTag.equals(tag) == false) + if (response.mTag != null && response.mTag.equalsIgnoreCase(tag) == false) { Log.w(K9.LOG_TAG, "After sending tag " + tag + ", got tag response from previous command " + response + " for " + getLogId()); Iterator iter = responses.iterator(); @@ -2472,7 +2477,7 @@ public class ImapStore extends Store { ImapResponse delResponse = iter.next(); if (delResponse.mTag != null || delResponse.size() < 2 - || ("EXISTS".equals(delResponse.get(1)) == false && "EXPUNGE".equals(delResponse.get(1)) == false)) + || (ImapResponseParser.equalsIgnoreCase(delResponse.get(1), "EXISTS") == false && ImapResponseParser.equalsIgnoreCase(delResponse.get(1), "EXPUNGE") == false)) { iter.remove(); } @@ -2487,7 +2492,7 @@ public class ImapStore extends Store responses.add(response); } while (response.mTag == null); - if (response.size() < 1 || !response.get(0).equals("OK")) + if (response.size() < 1 || !ImapResponseParser.equalsIgnoreCase(response.get(0), "OK")) { throw new ImapException("Command: " + commandToLog + "; response: " + response.toString(), response.getAlertText()); } @@ -2663,7 +2668,7 @@ public class ImapStore extends Store { handleUntaggedResponses(responses); } - if (mConnection != oldConnection) + if (mAccount.isPushPollOnConnect() && mConnection != oldConnection) { receiver.syncFolder(ImapFolderPusher.this); } @@ -2681,11 +2686,11 @@ public class ImapStore extends Store if (highestUid != -1) { if (K9.DEBUG) - Log.i(K9.LOG_TAG, "highest UID = " + highestUid); + Log.d(K9.LOG_TAG, "highest UID = " + highestUid); newUidNext = highestUid + 1; if (K9.DEBUG) - Log.i(K9.LOG_TAG, "highest UID = " + highestUid - + ", set newUidNext to " + newUidNext); + Log.d(K9.LOG_TAG, "highest UID = " + highestUid + + ", set newUidNext to " + newUidNext); } } @@ -2733,7 +2738,7 @@ public class ImapStore extends Store receiver.setPushActive(getName(), true); idling.set(true); doneSent.set(false); - mConnection.setReadTimeout(IDLE_READ_TIMEOUT); + mConnection.setReadTimeout((getAccount().getIdleRefreshMinutes() * 60 * 1000) + IDLE_READ_TIMEOUT_INCREMENT); untaggedResponses = executeSimpleCommand(COMMAND_IDLE, false, ImapFolderPusher.this); idling.set(false); @@ -2815,9 +2820,9 @@ public class ImapStore extends Store if (response.mTag == null && response.size() > 1) { Object responseType = response.get(1); - if ("FETCH".equals(responseType) - || "EXPUNGE".equals(responseType) - || "EXISTS".equals(responseType)) + if (ImapResponseParser.equalsIgnoreCase(responseType, "FETCH") + || ImapResponseParser.equalsIgnoreCase(responseType, "EXPUNGE") + || ImapResponseParser.equalsIgnoreCase(responseType, "EXISTS")) { if (K9.DEBUG) Log.d(K9.LOG_TAG, "Storing response " + response + " for later processing"); @@ -2943,7 +2948,7 @@ public class ImapStore extends Store try { Object responseType = response.get(1); - if ("FETCH".equals(responseType)) + if (ImapResponseParser.equalsIgnoreCase(responseType, "FETCH")) { int msgSeq = response.getNumber(0); if (K9.DEBUG) @@ -2954,7 +2959,7 @@ public class ImapStore extends Store flagSyncMsgSeqs.add(msgSeq); } } - if ("EXPUNGE".equals(responseType)) + if (ImapResponseParser.equalsIgnoreCase(responseType, "EXPUNGE")) { int msgSeq = response.getNumber(0); if (msgSeq <= oldMessageCount) @@ -3061,8 +3066,8 @@ public class ImapStore extends Store { boolean started = false; Object responseType = response.get(1); - if ("EXISTS".equals(responseType) || "EXPUNGE".equals(responseType) || - "FETCH".equals(responseType)) + if (ImapResponseParser.equalsIgnoreCase(responseType, "EXISTS") || ImapResponseParser.equalsIgnoreCase(responseType, "EXPUNGE") || + ImapResponseParser.equalsIgnoreCase(responseType,"FETCH")) { if (started == false) { @@ -3104,6 +3109,7 @@ public class ImapStore extends Store { final ImapStore mStore; final PushReceiver mReceiver; + private long lastRefresh = -1; HashMap folderPushers = new HashMap(); @@ -3118,6 +3124,7 @@ public class ImapStore extends Store stop(); synchronized (folderPushers) { + setLastRefresh(System.currentTimeMillis()); for (String folderName : folderNames) { ImapFolderPusher pusher = folderPushers.get(folderName); @@ -3175,7 +3182,17 @@ public class ImapStore extends Store public int getRefreshInterval() { - return IDLE_REFRESH_INTERVAL; + return (getAccount().getIdleRefreshMinutes() * 60 * 1000); + } + + public long getLastRefresh() + { + return lastRefresh; + } + + public void setLastRefresh(long lastRefresh) + { + this.lastRefresh = lastRefresh; } } @@ -3204,7 +3221,7 @@ public class ImapStore extends Store { String key = thisState.nextToken(); - if ("uidNext".equals(key) && thisState.hasMoreTokens()) + if ("uidNext".equalsIgnoreCase(key) && thisState.hasMoreTokens()) { String value = thisState.nextToken(); try diff --git a/src/com/fsck/k9/service/MailService.java b/src/com/fsck/k9/service/MailService.java index 9bdd67f3f..076072a08 100644 --- a/src/com/fsck/k9/service/MailService.java +++ b/src/com/fsck/k9/service/MailService.java @@ -187,8 +187,8 @@ public class MailService extends CoreService { if (hasConnectivity && doBackground) { - schedulePushers(null); - refreshPushers(startIdObj); + refreshPushers(null); + schedulePushers(startIdObj); startIdObj = null; } } @@ -427,12 +427,33 @@ public class MailService extends CoreService { try { + long nowTime = System.currentTimeMillis(); if (K9.DEBUG) Log.i(K9.LOG_TAG, "Refreshing pushers"); Collection pushers = MessagingController.getInstance(getApplication()).getPushers(); for (Pusher pusher : pushers) { - pusher.refresh(); + long lastRefresh = pusher.getLastRefresh(); + int refreshInterval = pusher.getRefreshInterval(); + long sinceLast = nowTime - lastRefresh; + if (sinceLast + 10000 > refreshInterval) // Add 10 seconds to keep pushers in sync, avoid drift + { + if (K9.DEBUG) + { + Log.d(K9.LOG_TAG, "PUSHREFRESH: refreshing lastRefresh = " + lastRefresh + ", interval = " + refreshInterval + + ", nowTime = " + nowTime + ", sinceLast = " + sinceLast); + } + pusher.refresh(); + pusher.setLastRefresh(nowTime); + } + else + { + if (K9.DEBUG) + { + Log.d(K9.LOG_TAG, "PUSHREFRESH: NOT refreshing lastRefresh = " + lastRefresh + ", interval = " + refreshInterval + + ", nowTime = " + nowTime + ", sinceLast = " + sinceLast); + } + } } } catch (Exception e) @@ -456,7 +477,7 @@ public class MailService extends CoreService for (Pusher pusher : pushers) { int interval = pusher.getRefreshInterval(); - if (interval != -1 && (interval < minInterval || minInterval == -1)) + if (interval > 0 && (interval < minInterval || minInterval == -1)) { minInterval = interval; } @@ -465,7 +486,7 @@ public class MailService extends CoreService { Log.v(K9.LOG_TAG, "Pusher refresh interval = " + minInterval); } - if (minInterval != -1) + if (minInterval > 0) { long nextTime = System.currentTimeMillis() + minInterval; if (K9.DEBUG)