From 8e7528fae9dd49261803a02758fb01b319c75724 Mon Sep 17 00:00:00 2001 From: Rob Bayer Date: Wed, 29 Feb 2012 11:26:39 -0800 Subject: [PATCH 01/21] Basic IMAP search working --- res/values/arrays.xml | 23 ++- res/values/strings.xml | 17 ++ res/xml/account_settings_preferences.xml | 15 +- src/com/fsck/k9/Account.java | 70 ++++++-- .../fsck/k9/activity/MessageInfoHolder.java | 4 +- src/com/fsck/k9/activity/MessageList.java | 107 +++++++++--- .../k9/activity/setup/AccountSettings.java | 33 +++- .../k9/controller/MessagingController.java | 91 +++++++++- src/com/fsck/k9/helper/MessageHelper.java | 9 +- src/com/fsck/k9/mail/Message.java | 10 ++ src/com/fsck/k9/mail/Store.java | 6 + .../fsck/k9/mail/internet/MimeMessage.java | 24 +++ src/com/fsck/k9/mail/store/ImapStore.java | 159 +++++++++++++++++- 13 files changed, 505 insertions(+), 63 deletions(-) diff --git a/res/values/arrays.xml b/res/values/arrays.xml index 8608cb3675d..4a42fc04060 100644 --- a/res/values/arrays.xml +++ b/res/values/arrays.xml @@ -46,6 +46,7 @@ 1440 + @string/account_setup_options_mail_display_count_10 @string/account_setup_options_mail_display_count_25 @@ -56,7 +57,7 @@ @string/account_setup_options_mail_display_count_1000 @string/account_setup_options_mail_display_count_all - + 10 25 @@ -662,5 +663,25 @@ HTML AUTO + + @string/account_settings_remote_search_num_results_entries_10 + @string/account_settings_remote_search_num_results_entries_25 + @string/account_settings_remote_search_num_results_entries_50 + @string/account_settings_remote_search_num_results_entries_100 + @string/account_settings_remote_search_num_results_entries_250 + @string/account_settings_remote_search_num_results_entries_500 + @string/account_settings_remote_search_num_results_entries_1000 + @string/account_settings_remote_search_num_results_entries_all + + + 10 + 25 + 50 + 100 + 250 + 500 + 1000 + 0 + diff --git a/res/values/strings.xml b/res/values/strings.xml index 51ea0c50fbe..96fbf7b3582 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -1131,4 +1131,21 @@ Welcome to K-9 Mail setup. K-9 is an open source mail client for Android origin the import operation. Please install a file manager application from Android Market Open Market Close + Allow Remote Search + Enable Remote Searching for this account + All + 10 + 25 + 50 + 100 + 250 + 500 + 1000 + Results Limit + All Local Folders + Remote Folder + Search Location + Remote Folder Searching + Can be slow + Include Body Text diff --git a/res/xml/account_settings_preferences.xml b/res/xml/account_settings_preferences.xml index 9fa5a11a6cd..8b880db1ef6 100644 --- a/res/xml/account_settings_preferences.xml +++ b/res/xml/account_settings_preferences.xml @@ -20,7 +20,7 @@ the preferences. See com.fsck.k9.preferences.Storage. --> - + - + + + + + + + + + + + @@ -465,5 +475,6 @@ android:dependency="crypto_app"/> + diff --git a/src/com/fsck/k9/Account.java b/src/com/fsck/k9/Account.java index c04e89c06bb..5e84bf5aaaf 100644 --- a/src/com/fsck/k9/Account.java +++ b/src/com/fsck/k9/Account.java @@ -1,6 +1,18 @@ package com.fsck.k9; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Calendar; +import java.util.Collections; +import java.util.Date; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Random; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; + import android.content.Context; import android.content.SharedPreferences; import android.net.ConnectivityManager; @@ -18,19 +30,6 @@ import com.fsck.k9.mail.store.StorageManager.StorageProvider; import com.fsck.k9.view.ColorChip; -import java.lang.reflect.Array; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Calendar; -import java.util.Collections; -import java.util.Date; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Random; -import java.util.UUID; -import java.util.concurrent.ConcurrentHashMap; - /** * Account stores all of the settings for a single account defined by the user. It is able to save * and delete itself given a Preferences to work with. Each account is defined by a UUID. @@ -68,6 +67,7 @@ public class Account implements BaseAccount { public static final boolean DEFAULT_QUOTED_TEXT_SHOWN = true; public static final boolean DEFAULT_REPLY_AFTER_QUOTE = false; public static final boolean DEFAULT_STRIP_SIGNATURE = true; + public static final int DEFAULT_REMOTE_SEARCH_NUM_RESULTS = 25; public static final String ACCOUNT_DESCRIPTION_KEY = "description"; public static final String STORE_URI_KEY = "storeUri"; @@ -149,7 +149,10 @@ public class Account implements BaseAccount { private String mCryptoApp; private boolean mCryptoAutoSignature; private boolean mCryptoAutoEncrypt; - + private boolean mAllowRemoteSearch; + private boolean mRemoteSearchFullText; + private int mRemoteSearchNumResults; + private CryptoProvider mCryptoProvider = null; /** @@ -235,6 +238,9 @@ protected Account(Context context) { mCryptoApp = Apg.NAME; mCryptoAutoSignature = false; mCryptoAutoEncrypt = false; + mAllowRemoteSearch = false; + mRemoteSearchFullText = false; + mRemoteSearchNumResults = DEFAULT_REMOTE_SEARCH_NUM_RESULTS; mEnabled = true; searchableFolders = Searchable.ALL; @@ -390,6 +396,10 @@ private synchronized void loadAccount(Preferences preferences) { mCryptoApp = prefs.getString(mUuid + ".cryptoApp", Apg.NAME); mCryptoAutoSignature = prefs.getBoolean(mUuid + ".cryptoAutoSignature", false); mCryptoAutoEncrypt = prefs.getBoolean(mUuid + ".cryptoAutoEncrypt", false); + mAllowRemoteSearch = prefs.getBoolean(mUuid + ".allowRemoteSearch", false); + mRemoteSearchFullText = prefs.getBoolean(mUuid + ".remoteSearchFullText", false); + mRemoteSearchNumResults = prefs.getInt(mUuid + ".remoteSearchNumResults", DEFAULT_REMOTE_SEARCH_NUM_RESULTS); + mEnabled = prefs.getBoolean(mUuid + ".enabled", true); } @@ -631,6 +641,9 @@ public synchronized void save(Preferences preferences) { editor.putString(mUuid + ".cryptoApp", mCryptoApp); editor.putBoolean(mUuid + ".cryptoAutoSignature", mCryptoAutoSignature); editor.putBoolean(mUuid + ".cryptoAutoEncrypt", mCryptoAutoEncrypt); + editor.putBoolean(mUuid + ".allowRemoteSearch", mAllowRemoteSearch); + editor.putBoolean(mUuid + ".remoteSearchFullText", mRemoteSearchFullText); + editor.putInt(mUuid + ".remoteSearchNumResults", mRemoteSearchNumResults); editor.putBoolean(mUuid + ".enabled", mEnabled); editor.putBoolean(mUuid + ".vibrate", mNotificationSetting.shouldVibrate()); @@ -1445,7 +1458,23 @@ public boolean isCryptoAutoEncrypt() { public void setCryptoAutoEncrypt(boolean cryptoAutoEncrypt) { mCryptoAutoEncrypt = cryptoAutoEncrypt; } - + + public boolean allowRemoteSearch() { + return mAllowRemoteSearch; + } + + public void setAllowRemoteSearch(boolean val){ + mAllowRemoteSearch = val; + } + + public int getRemoteSearchNumResults(){ + return mRemoteSearchNumResults; + } + + public void setRemoteSearchNumResults(int val){ + mRemoteSearchNumResults = (val >= 0 ? val : 0); + } + public String getInboxFolderName() { return mInboxFolderName; } @@ -1500,4 +1529,15 @@ public synchronized boolean isEnabled() { public synchronized void setEnabled(boolean enabled) { mEnabled = enabled; } + + public boolean getRemoteSearchFullText() { + + return mRemoteSearchFullText; + } + + public void setRemoteSearchFullText(boolean val) { + mRemoteSearchFullText = val; + } + + } diff --git a/src/com/fsck/k9/activity/MessageInfoHolder.java b/src/com/fsck/k9/activity/MessageInfoHolder.java index e19fb953acc..163184de65c 100644 --- a/src/com/fsck/k9/activity/MessageInfoHolder.java +++ b/src/com/fsck/k9/activity/MessageInfoHolder.java @@ -2,7 +2,7 @@ import java.util.Date; import com.fsck.k9.helper.MessageHelper; -import com.fsck.k9.mail.store.LocalStore.LocalMessage; +import com.fsck.k9.mail.Message; public class MessageInfoHolder { public String date; @@ -19,7 +19,7 @@ public class MessageInfoHolder { public boolean downloaded; public boolean partially_downloaded; public boolean dirty; - public LocalMessage message; + public Message message; public FolderInfoHolder folder; public boolean selected; public String account; diff --git a/src/com/fsck/k9/activity/MessageList.java b/src/com/fsck/k9/activity/MessageList.java index 867fb53fe15..8118cb4c3f2 100644 --- a/src/com/fsck/k9/activity/MessageList.java +++ b/src/com/fsck/k9/activity/MessageList.java @@ -10,7 +10,9 @@ import android.app.AlertDialog; import android.app.Dialog; +import android.app.SearchManager; import android.content.Context; +import android.content.DialogInterface; import android.content.Intent; import android.graphics.Color; import android.graphics.Typeface; @@ -52,12 +54,10 @@ import com.fsck.k9.Account; import com.fsck.k9.AccountStats; -import com.fsck.k9.BaseAccount; import com.fsck.k9.FontSizes; import com.fsck.k9.K9; import com.fsck.k9.Preferences; import com.fsck.k9.R; -import com.fsck.k9.SearchAccount; import com.fsck.k9.SearchSpecification; import com.fsck.k9.activity.setup.AccountSettings; import com.fsck.k9.activity.setup.FolderSettings; @@ -72,7 +72,6 @@ import com.fsck.k9.mail.Message; import com.fsck.k9.mail.store.LocalStore; import com.fsck.k9.mail.store.LocalStore.LocalFolder; -import com.fsck.k9.mail.store.LocalStore.LocalMessage; import com.fsck.k9.mail.store.StorageManager; @@ -171,7 +170,13 @@ public static class SenderComparator implements Comparator { @Override public int compare(MessageInfoHolder object1, MessageInfoHolder object2) { - return object1.compareCounterparty.toLowerCase().compareTo(object2.compareCounterparty.toLowerCase()); + if(object1.compareCounterparty == null){ + return (object2.compareCounterparty == null ? 0 : 1); + }else if (object2.compareCounterparty == null){ + return -1; + }else{ + return object1.compareCounterparty.toLowerCase().compareTo(object2.compareCounterparty.toLowerCase()); + } } } @@ -180,7 +185,13 @@ public static class DateComparator implements Comparator { @Override public int compare(MessageInfoHolder object1, MessageInfoHolder object2) { - return object1.compareDate.compareTo(object2.compareDate); + if(object1.compareDate == null){ + return (object2.compareDate == null ? 0 : 1); + }else if(object2.compareDate == null){ + return -1; + }else{ + return object1.compareDate.compareTo(object2.compareDate); + } } } @@ -213,7 +224,9 @@ public int compare(MessageInfoHolder arg0, MessageInfoHolder arg1) { private static final String EXTRA_ACCOUNT = "account"; private static final String EXTRA_FOLDER = "folder"; - private static final String EXTRA_QUERY = "query"; + private static final String EXTRA_REMOTE_SEARCH = "com.fsck.k9.remote_search"; + private static final String EXTRA_SEARCH_ACCOUNT = "com.fsck.k9.search_account"; + private static final String EXTRA_SEARCH_FOLDER = "com.fsck.k9.search_folder"; private static final String EXTRA_QUERY_FLAGS = "queryFlags"; private static final String EXTRA_FORBIDDEN_FLAGS = "forbiddenFlags"; private static final String EXTRA_INTEGRATE = "integrate"; @@ -227,7 +240,6 @@ public int compare(MessageInfoHolder arg0, MessageInfoHolder arg1) { * Maps a {@link SORT_TYPE} to a {@link Comparator} implementation. */ private static final Map> SORT_COMPARATORS; - static { // fill the mapping at class time loading @@ -243,6 +255,7 @@ public int compare(MessageInfoHolder arg0, MessageInfoHolder arg1) { SORT_COMPARATORS = Collections.unmodifiableMap(map); } + private ListView mListView; private boolean mTouchView = true; @@ -275,6 +288,9 @@ public int compare(MessageInfoHolder arg0, MessageInfoHolder arg1) { private String mQueryString; private Flag[] mQueryFlags = null; private Flag[] mForbiddenFlags = null; + private boolean mRemoteSearch = false; + private String mSearchAccount = null; + private String mSearchFolder = null; private boolean mIntegrate = false; private String[] mAccountUuids = null; private String[] mFolderNames = null; @@ -395,7 +411,7 @@ public void run() { } } - if (wasEmpty) { + if (wasEmpty & !mAdapter.messages.isEmpty()) { mListView.setSelection(0); } resetUnreadCountOnThread(); @@ -470,10 +486,7 @@ protected Comparator getComparator() { } } - // build the comparator chain - final Comparator chainComparator = new ComparatorChain(chain); - - return chainComparator; + return new ComparatorChain(chain); } public void folderLoading(String folder, boolean loading) { @@ -539,6 +552,7 @@ private void setWindowTitle() { setTitle(getString(R.string.search_results) + ": " + mQueryString); } } + //TODO: Update for ImapSearch } public void progress(final boolean progress) { @@ -601,7 +615,7 @@ public static Intent actionHandleFolderIntent(Context context, Account account, public static void actionHandle(Context context, String title, String queryString, boolean integrate, Flag[] flags, Flag[] forbiddenFlags) { Intent intent = new Intent(context, MessageList.class); - intent.putExtra(EXTRA_QUERY, queryString); + intent.putExtra(SearchManager.QUERY, queryString); if (flags != null) { intent.putExtra(EXTRA_QUERY_FLAGS, Utility.combine(flags, ',')); } @@ -622,7 +636,7 @@ public static void actionHandle(Context context, String title, String queryStrin public static Intent actionHandleAccountIntent(Context context, String title, SearchSpecification searchSpecification) { Intent intent = new Intent(context, MessageList.class); - intent.putExtra(EXTRA_QUERY, searchSpecification.getQuery()); + intent.putExtra(SearchManager.QUERY, searchSpecification.getQuery()); if (searchSpecification.getRequiredFlags() != null) { intent.putExtra(EXTRA_QUERY_FLAGS, Utility.combine(searchSpecification.getRequiredFlags(), ',')); } @@ -707,7 +721,7 @@ private void initializeMessageList(Intent intent, boolean create) { } mFolderName = intent.getStringExtra(EXTRA_FOLDER); - mQueryString = intent.getStringExtra(EXTRA_QUERY); + mQueryString = intent.getStringExtra(SearchManager.QUERY); String queryFlags = intent.getStringExtra(EXTRA_QUERY_FLAGS); if (queryFlags != null) { @@ -815,6 +829,7 @@ public void onResume() { mController.addListener(mAdapter.mListener); + //Cancel pending new mail notifications when we open an account Account[] accountsWithNotification; if (mAccount != null) { accountsWithNotification = new Account[] { mAccount }; @@ -822,18 +837,21 @@ public void onResume() { Preferences preferences = Preferences.getPreferences(this); accountsWithNotification = preferences.getAccounts(); } - for (Account accountWithNotification : accountsWithNotification) { mController.notifyAccountCancel(this, accountWithNotification); } + if (mAdapter.messages.isEmpty()) { - if (mFolderName != null) { + if (mRemoteSearch){ + //TODO: Support flag based search + mController.searchRemoteMessages(mSearchAccount, mSearchFolder, mQueryString, null, null, mAdapter.mListener); + } + else if (mFolderName != null) { mController.listLocalMessages(mAccount, mFolderName, mAdapter.mListener); } else if (mQueryString != null) { mController.searchLocalMessages(mAccountUuids, mFolderNames, null, mQueryString, mIntegrate, mQueryFlags, mForbiddenFlags, mAdapter.mListener); } - } else { // reread the selected date format preference in case it has changed mMessageHelper.refresh(); @@ -843,7 +861,9 @@ public void onResume() { public void run() { mAdapter.markAllMessagesAsDirty(); - if (mFolderName != null) { + if (mRemoteSearch){ + mController.searchRemoteMessagesSynchronous(mSearchAccount, mSearchFolder, mQueryString, null, null, mAdapter.mListener); + } else if (mFolderName != null) { mController.listLocalMessagesSynchronous(mAccount, mFolderName, mAdapter.mListener); } else if (mQueryString != null) { mController.searchLocalMessagesSynchronous(mAccountUuids, mFolderNames, null, mQueryString, mIntegrate, mQueryFlags, mForbiddenFlags, mAdapter.mListener); @@ -1037,6 +1057,7 @@ public boolean onKeyDown(int keyCode, KeyEvent event) { } } + //Shortcuts that only work when a message is selected boolean retval = true; int position = mListView.getSelectedItemPosition(); try { @@ -1178,6 +1199,44 @@ private void onEditPrefs() { private void onEditAccount() { AccountSettings.actionSettings(this, mAccount); } + + + @Override + public boolean onSearchRequested() { + + if(mAccount != null && mCurrentFolder != null && mAccount.allowRemoteSearch()){ + //if in a SSSable folder, ask user what they want. + //TODO: Add ability to remember selection? + final CharSequence[] items = new CharSequence[2]; + items[0] = getString(R.string.search_mode_local_all); + items[1] = getString(R.string.search_mode_remote); + + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setTitle(getString(R.string.search_mode_title)); + builder.setItems(items, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int item) { + + Bundle appData = null; + if(item == 1){ + appData = new Bundle(); + appData.putString(EXTRA_SEARCH_ACCOUNT, mAccount.getUuid()); + appData.putString(EXTRA_SEARCH_FOLDER, mCurrentFolder.name); + appData.putBoolean(EXTRA_REMOTE_SEARCH, true); + } + //else do regular search, which doesn't require any special parameter setup + + startSearch(null, false, appData, false); + } + }); + AlertDialog alert = builder.create(); + alert.show(); + + return true; + } + + startSearch(null, false, null, false); + return true; + } private void changeSort(SORT_TYPE newSortType) { if (sortType == newSortType) { @@ -1398,7 +1457,7 @@ public void onPrepareDialog(final int id, final Dialog dialog) { } private void onToggleRead(MessageInfoHolder holder) { - LocalMessage message = holder.message; + Message message = holder.message; Folder folder = message.getFolder(); Account account = folder.getAccount(); String folderName = folder.getName(); @@ -1408,7 +1467,7 @@ private void onToggleRead(MessageInfoHolder holder) { } private void onToggleFlag(MessageInfoHolder holder) { - LocalMessage message = holder.message; + Message message = holder.message; Folder folder = message.getFolder(); Account account = folder.getAccount(); String folderName = folder.getName(); @@ -1583,7 +1642,7 @@ public boolean onPrepareOptionsMenu(Menu menu) { setOpsState(menu, true, anySelected); - if (mQueryString != null) { + if (mQueryString != null || mIntegrate) { menu.findItem(R.id.mark_all_as_read).setVisible(false); menu.findItem(R.id.list_folders).setVisible(false); menu.findItem(R.id.expunge).setVisible(false); @@ -1975,9 +2034,7 @@ public void markAllMessagesAsDirty() { } public void pruneDirtyMessages() { synchronized (mAdapter.messages) { - Iterator iter = mAdapter.messages.iterator(); - while (iter.hasNext()) { - MessageInfoHolder holder = iter.next(); + for(MessageInfoHolder holder : mAdapter.messages){ if (holder.dirty) { if (holder.selected) { mSelectedCount--; diff --git a/src/com/fsck/k9/activity/setup/AccountSettings.java b/src/com/fsck/k9/activity/setup/AccountSettings.java index a7fae42e583..18698e0e9ab 100644 --- a/src/com/fsck/k9/activity/setup/AccountSettings.java +++ b/src/com/fsck/k9/activity/setup/AccountSettings.java @@ -46,7 +46,8 @@ public class AccountSettings extends K9PreferenceActivity { private static final String PREFERENCE_SCREEN_COMPOSING = "composing"; private static final String PREFERENCE_SCREEN_INCOMING = "incoming_prefs"; private static final String PREFERENCE_SCREEN_PUSH_ADVANCED = "push_advanced"; - + private static final String PREFERENCE_SCREEN_REMOTE_SEARCH = "remote_search"; + private static final String PREFERENCE_DESCRIPTION = "account_description"; private static final String PREFERENCE_COMPOSITION = "composition"; private static final String PREFERENCE_MANAGE_IDENTITIES = "manage_identities"; @@ -94,6 +95,9 @@ public class AccountSettings extends K9PreferenceActivity { private static final String PREFERENCE_CRYPTO_APP = "crypto_app"; private static final String PREFERENCE_CRYPTO_AUTO_SIGNATURE = "crypto_auto_signature"; private static final String PREFERENCE_CRYPTO_AUTO_ENCRYPT = "crypto_auto_encrypt"; + private static final String PREFERENCE_ALLOW_REMOTE_SEARCH = "account_allow_remote_search"; + private static final String PREFERENCE_REMOTE_SEARCH_NUM_RESULTS = "account_remote_search_num_results"; + private static final String PREFERENCE_REMOTE_SEARCH_FULL_TEXT = "account_remote_search_full_text"; private static final String PREFERENCE_LOCAL_STORAGE_PROVIDER = "local_storage_provider"; @@ -157,6 +161,9 @@ public class AccountSettings extends K9PreferenceActivity { private ListPreference mCryptoApp; private CheckBoxPreference mCryptoAutoSignature; private CheckBoxPreference mCryptoAutoEncrypt; + private CheckBoxPreference mAllowRemoteSearch; + private ListPreference mRemoteSearchNumResults; + private CheckBoxPreference mRemoteSearchFullText; private ListPreference mLocalStorageProvider; @@ -423,6 +430,7 @@ public boolean onPreferenceChange(Preference preference, Object newValue) { mAccountDefault.setChecked( mAccount.equals(Preferences.getPreferences(this).getDefaultAccount())); + mAccountEnableMoveButtons = (CheckBoxPreference) findPreference(PREFERENCE_ENABLE_MOVE_BUTTONS); mAccountEnableMoveButtons.setEnabled(mIsMoveCapable); mAccountEnableMoveButtons.setChecked(mAccount.getEnableMoveButtons()); @@ -465,14 +473,22 @@ public boolean onPreferenceChange(Preference preference, Object newValue) { } }); } + + // IMAP-specific preferences - + mAllowRemoteSearch = (CheckBoxPreference) findPreference(PREFERENCE_ALLOW_REMOTE_SEARCH); + mRemoteSearchNumResults = (ListPreference) findPreference(PREFERENCE_REMOTE_SEARCH_NUM_RESULTS); + mRemoteSearchFullText = (CheckBoxPreference) findPreference(PREFERENCE_REMOTE_SEARCH_FULL_TEXT); mPushPollOnConnect = (CheckBoxPreference) findPreference(PREFERENCE_PUSH_POLL_ON_CONNECT); mIdleRefreshPeriod = (ListPreference) findPreference(PREFERENCE_IDLE_REFRESH_PERIOD); mMaxPushFolders = (ListPreference) findPreference(PREFERENCE_MAX_PUSH_FOLDERS); if (mIsPushCapable) { mPushPollOnConnect.setChecked(mAccount.isPushPollOnConnect()); + mAllowRemoteSearch.setChecked(mAccount.allowRemoteSearch()); + mRemoteSearchNumResults.setValue(Integer.toString(mAccount.getRemoteSearchNumResults())); + mRemoteSearchFullText.setChecked(mAccount.getRemoteSearchFullText()); + mIdleRefreshPeriod.setValue(String.valueOf(mAccount.getIdleRefreshMinutes())); mIdleRefreshPeriod.setSummary(mIdleRefreshPeriod.getEntry()); mIdleRefreshPeriod.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { @@ -484,7 +500,7 @@ public boolean onPreferenceChange(Preference preference, Object newValue) { return false; } }); - + mMaxPushFolders.setValue(String.valueOf(mAccount.getMaxPushFolders())); mMaxPushFolders.setSummary(mMaxPushFolders.getEntry()); mMaxPushFolders.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { @@ -509,9 +525,12 @@ public boolean onPreferenceChange(Preference preference, Object newValue) { } }); } else { - PreferenceScreen incomingPrefs = (PreferenceScreen) findPreference(PREFERENCE_SCREEN_INCOMING); + final PreferenceScreen incomingPrefs = (PreferenceScreen) findPreference(PREFERENCE_SCREEN_INCOMING); incomingPrefs.removePreference( (PreferenceScreen) findPreference(PREFERENCE_SCREEN_PUSH_ADVANCED)); incomingPrefs.removePreference( (ListPreference) findPreference(PREFERENCE_PUSH_MODE)); + + ((PreferenceScreen) findPreference("main")).removePreference((PreferenceScreen) findPreference(PREFERENCE_SCREEN_REMOTE_SEARCH)); + } mAccountNotify = (CheckBoxPreference) findPreference(PREFERENCE_NOTIFY); @@ -719,11 +738,14 @@ private void saveSettings() { mAccount.setSpamFolderName(mSpamFolder.getValue()); mAccount.setTrashFolderName(mTrashFolder.getValue()); - + //IMAP stuff if (mIsPushCapable) { mAccount.setPushPollOnConnect(mPushPollOnConnect.isChecked()); mAccount.setIdleRefreshMinutes(Integer.parseInt(mIdleRefreshPeriod.getValue())); mAccount.setMaxPushFolders(Integer.parseInt(mMaxPushFolders.getValue())); + mAccount.setAllowRemoteSearch(mAllowRemoteSearch.isChecked()); + mAccount.setRemoteSearchNumResults(Integer.parseInt(mRemoteSearchNumResults.getValue())); + mAccount.setRemoteSearchFullText(mRemoteSearchFullText.isChecked()); } if (!mIsMoveCapable) { @@ -750,6 +772,7 @@ private void saveSettings() { mAccount.setShowPictures(Account.ShowPictures.valueOf(mAccountShowPictures.getValue())); + //IMAP specific stuff if (mIsPushCapable) { boolean needsPushRestart = mAccount.setFolderPushMode(Account.FolderMode.valueOf(mPushMode.getValue())); if (mAccount.getFolderPushMode() != FolderMode.NONE) { diff --git a/src/com/fsck/k9/controller/MessagingController.java b/src/com/fsck/k9/controller/MessagingController.java index 1b2b47a6bec..e273c71fa91 100644 --- a/src/com/fsck/k9/controller/MessagingController.java +++ b/src/com/fsck/k9/controller/MessagingController.java @@ -3,7 +3,18 @@ import java.io.CharArrayWriter; import java.io.PrintWriter; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; import java.util.concurrent.BlockingQueue; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArraySet; @@ -784,6 +795,84 @@ public void messagesFinished(int number) { listener.searchStats(stats); } } + + + + public void searchRemoteMessages(final String acctUuid, final String folderName, final String query, final Flag[] requiredFlags, final Flag[] forbiddenFlags, final MessagingListener listener){ + if (K9.DEBUG) { + String msg = "searchRemoteMessages (" + + "acct=" + acctUuid + + ", folderName = " + folderName + + ", query = " + query + + ")"; + Log.i(K9.LOG_TAG, msg); + } + + threadPool.execute(new Runnable() { + @Override + public void run() { + searchRemoteMessagesSynchronous(acctUuid, folderName, query, requiredFlags, forbiddenFlags, listener); + } + }); + } + public void searchRemoteMessagesSynchronous(final String acctUuid, final String folderName, final String query, + final Flag[] requiredFlags, final Flag[] forbiddenFlags, final MessagingListener listener){ + final Account acct = Preferences.getPreferences(mApplication.getApplicationContext()).getAccount(acctUuid); + final AccountStats stats = new AccountStats(); + + if (listener != null) { + listener.listLocalMessagesStarted(acct, null); + } + + MessageRetrievalListener retrievalListener = new MessageRetrievalListener() { + @Override + public void messageStarted(String message, int number, int ofTotal) {} + @Override + public void messageFinished(Message message, int number, int ofTotal) { + if (!isMessageSuppressed(message.getFolder().getAccount(), message.getFolder().getName(), message)) { + List messages = new ArrayList(); + + messages.add(message); + stats.unreadMessageCount += (!message.isSet(Flag.SEEN)) ? 1 : 0; + stats.flaggedMessageCount += (message.isSet(Flag.FLAGGED)) ? 1 : 0; + if (listener != null) { + listener.listLocalMessagesAddMessages(acct, null, messages); + + } + } + + } + @Override + public void messagesFinished(int number) { + + } + }; + + try { + String[] queryFields = {"html_content", "subject", "sender_list"}; + Store acctStore = acct.getRemoteStore(); + + //TODO: make queryFields actually do something + acctStore.searchRemoteMessages(retrievalListener, queryFields, query, folderName, requiredFlags, forbiddenFlags); + + } catch (Exception e) { + if (listener != null) { + listener.listLocalMessagesFailed(acct, null, e.getMessage()); + } + addErrorMessage(acct, null, e); + } finally { + if (listener != null) { + listener.listLocalMessagesFinished(acct, null); + } + } + + if (listener != null) { + listener.searchStats(stats); + } + + } + + public void loadMoreMessages(Account account, String folder, MessagingListener listener) { try { LocalStore localStore = account.getLocalStore(); diff --git a/src/com/fsck/k9/helper/MessageHelper.java b/src/com/fsck/k9/helper/MessageHelper.java index 43b208a775c..a2831410373 100644 --- a/src/com/fsck/k9/helper/MessageHelper.java +++ b/src/com/fsck/k9/helper/MessageHelper.java @@ -17,7 +17,6 @@ import com.fsck.k9.mail.Message; import com.fsck.k9.mail.MessagingException; import com.fsck.k9.mail.Message.RecipientType; -import com.fsck.k9.mail.store.LocalStore.LocalMessage; import com.fsck.k9.helper.DateFormatter; public class MessageHelper { @@ -43,11 +42,10 @@ private MessageHelper(final Context context) { mTodayDateFormat = android.text.format.DateFormat.getTimeFormat(mContext); } - public void populate(final MessageInfoHolder target, final Message m, + public void populate(final MessageInfoHolder target, final Message message, final FolderInfoHolder folder, final Account account) { final Contacts contactHelper = K9.showContactName() ? Contacts.getInstance(mContext) : null; try { - LocalMessage message = (LocalMessage) m; target.message = message; target.compareDate = message.getSentDate(); if (target.compareDate == null) { @@ -86,13 +84,16 @@ public void populate(final MessageInfoHolder target, final Message m, target.uid = message.getUid(); target.account = account.getDescription(); - target.uri = "email://messages/" + account.getAccountNumber() + "/" + m.getFolder().getName() + "/" + m.getUid(); + target.uri = "email://messages/" + account.getAccountNumber() + "/" + message.getFolder().getName() + "/" + message.getUid(); } catch (MessagingException me) { Log.w(K9.LOG_TAG, "Unable to load message info", me); } } public String formatDate(Date date) { + if (date==null){ + return ""; + } if (Utility.isDateToday(date)) { return mTodayDateFormat.format(date); } else { diff --git a/src/com/fsck/k9/mail/Message.java b/src/com/fsck/k9/mail/Message.java index 2a7cd5efd06..e25307bc4b8 100644 --- a/src/com/fsck/k9/mail/Message.java +++ b/src/com/fsck/k9/mail/Message.java @@ -144,6 +144,16 @@ public boolean isMimeType(String mimeType) throws MessagingException { return getContentType().startsWith(mimeType); } + public abstract boolean toMe(); + public abstract boolean ccMe(); + public abstract boolean bccMe(); + public abstract long getId(); + + public abstract String getPreview(); + public abstract boolean hasAttachments(); + + + public void delete(String trashFolderName) throws MessagingException {} /* diff --git a/src/com/fsck/k9/mail/Store.java b/src/com/fsck/k9/mail/Store.java index 5013a8f298f..28ff45924ca 100644 --- a/src/com/fsck/k9/mail/Store.java +++ b/src/com/fsck/k9/mail/Store.java @@ -5,6 +5,7 @@ import android.content.Context; import com.fsck.k9.Account; +import com.fsck.k9.controller.MessageRetrievalListener; import com.fsck.k9.mail.store.ImapStore; import com.fsck.k9.mail.store.LocalStore; import com.fsck.k9.mail.store.Pop3Store; @@ -176,4 +177,9 @@ public Pusher getPusher(PushReceiver receiver) { public Account getAccount() { return mAccount; } + + public void searchRemoteMessages(MessageRetrievalListener listener, String[] queryFields, String queryString, + String folder, final Flag[] requiredFlags, final Flag[] forbiddenFlags) throws MessagingException{ + throw new MessagingException("K-9 does not support remote searchign on this account type"); + } } diff --git a/src/com/fsck/k9/mail/internet/MimeMessage.java b/src/com/fsck/k9/mail/internet/MimeMessage.java index 0ac949524a7..05db24d045d 100644 --- a/src/com/fsck/k9/mail/internet/MimeMessage.java +++ b/src/com/fsck/k9/mail/internet/MimeMessage.java @@ -587,4 +587,28 @@ public MimeMessage clone() { copy(message); return message; } + + public boolean toMe(){ + return false; + } + + public boolean ccMe(){ + return false; + } + + public boolean bccMe(){ + return false; + } + + public long getId(){ + return Long.parseLong(mUid); //or maybe .mMessageId? + } + + public String getPreview(){ + return "my_preview"; + } + + public boolean hasAttachments(){ + return false; + } } diff --git a/src/com/fsck/k9/mail/store/ImapStore.java b/src/com/fsck/k9/mail/store/ImapStore.java index cc36817064e..72629e2e400 100644 --- a/src/com/fsck/k9/mail/store/ImapStore.java +++ b/src/com/fsck/k9/mail/store/ImapStore.java @@ -45,11 +45,15 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; +import java.util.zip.Inflater; +import java.util.zip.InflaterInputStream; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLException; import javax.net.ssl.TrustManager; +import org.apache.commons.io.IOUtils; + import android.content.Context; import android.net.ConnectivityManager; import android.net.NetworkInfo; @@ -72,13 +76,14 @@ import com.fsck.k9.mail.FetchProfile; import com.fsck.k9.mail.Flag; import com.fsck.k9.mail.Folder; +import com.fsck.k9.mail.Folder.OpenMode; import com.fsck.k9.mail.Message; import com.fsck.k9.mail.MessagingException; import com.fsck.k9.mail.Part; import com.fsck.k9.mail.PushReceiver; import com.fsck.k9.mail.Pusher; -import com.fsck.k9.mail.Store; import com.fsck.k9.mail.ServerSettings; +import com.fsck.k9.mail.Store; import com.fsck.k9.mail.filter.EOLConvertingOutputStream; import com.fsck.k9.mail.filter.FixedLengthInputStream; import com.fsck.k9.mail.filter.PeekableInputStream; @@ -89,12 +94,10 @@ import com.fsck.k9.mail.internet.MimeUtility; import com.fsck.k9.mail.store.ImapResponseParser.ImapList; import com.fsck.k9.mail.store.ImapResponseParser.ImapResponse; +import com.fsck.k9.mail.store.LocalStore.LocalFolder; import com.fsck.k9.mail.transport.imap.ImapSettings; import com.jcraft.jzlib.JZlib; import com.jcraft.jzlib.ZOutputStream; -import java.util.zip.Inflater; -import java.util.zip.InflaterInputStream; -import org.apache.commons.io.IOUtils; /** *
@@ -1168,6 +1171,83 @@ private int getRemoteMessageCount(String criteria) throws MessagingException {
 
 
         }
+        
+        public void doRemoteSearch(final String queryString, final Flag[] requiredFlags, final Flag [] forbiddenFlags, final MessageRetrievalListener listener) 
+        		throws MessagingException{
+        	ImapSearcher searcher = new ImapSearcher(){
+        		public List search() throws IOException, MessagingException {
+        			String imapQuery = "SEARCH ";
+        			if(requiredFlags != null){
+	        			for(Flag f : requiredFlags){
+	        				switch(f){
+	        				case DELETED:
+	        					imapQuery += "DELETED ";
+	        					break;
+	        					
+	        				case SEEN:
+	        					imapQuery +=  "SEEN ";
+	        					break;
+	        					
+	        				case ANSWERED:
+	        					imapQuery += "ANSWERED ";
+	        					break;
+	        					
+	        				case FLAGGED:
+	        					imapQuery += "FLAGGED ";
+	        					break;
+	        					
+	        				case DRAFT:
+	        					imapQuery += "DRAFT ";
+	        					break;
+	        					
+	        				case RECENT:
+	        					imapQuery += "RECENT ";
+	        					break;
+	        				}
+	        			}
+        			}
+        			if(forbiddenFlags != null){
+	        			for(Flag f : forbiddenFlags){
+	        				switch(f){
+	        				case DELETED:
+	        					imapQuery += "UNDELETED ";
+	        					break;
+	        					
+	        				case SEEN:
+	        					imapQuery +=  "UNSEEN ";
+	        					break;
+	        					
+	        				case ANSWERED:
+	        					imapQuery += "UNANSWERED ";
+	        					break;
+	        					
+	        				case FLAGGED:
+	        					imapQuery += "UNFLAGGED ";
+	        					break;
+	        					
+	        				case DRAFT:
+	        					imapQuery += "UNDRAFT ";
+	        					break;
+	        					
+	        				case RECENT:
+	        					imapQuery += "UNRECENT ";
+	        					break;
+	        				}
+	        			}
+        			}
+        			String encodedQry = encodeString(queryString);
+        			if(mAccount.getRemoteSearchFullText()){
+        				imapQuery += "TEXT " + encodedQry;
+        			}
+        			else{
+        				imapQuery += "OR SUBJECT " + encodedQry + " FROM " + encodedQry;
+        			}
+        			return executeSimpleCommand(imapQuery);
+        		}
+        	};
+        	
+        	search(searcher, listener, (mAccount != null ? mAccount.getRemoteSearchNumResults() : 0), true);
+        }
 
         @Override
         public int getUnreadMessageCount() throws MessagingException {
@@ -1259,6 +1339,10 @@ public List search() throws IOException, MessagingException {
         }
 
         private Message[] search(ImapSearcher searcher, MessageRetrievalListener listener) throws MessagingException {
+        	return search(searcher, listener, 0, false);
+        }
+        
+        private Message[] search(ImapSearcher searcher, MessageRetrievalListener listener, int limit, boolean getHeaders) throws MessagingException {
 
             checkOpen();
             ArrayList messages = new ArrayList();
@@ -1275,13 +1359,34 @@ private Message[] search(ImapSearcher searcher, MessageRetrievalListener listene
                     }
                 }
 
-                // Sort the uids in numerically ascending order
-                Collections.sort(uids);
-                for (int i = 0, count = uids.size(); i < count; i++) {
+                // Sort the uids in numerically decreasing order 
+                // By doing it in decreasing order, we ensure newest messages are dealt with first
+                // This makes the most sense when a limit is imposed, and also prevents UI from going
+                // crazy adding stuff at the top.
+                Collections.sort(uids, Collections.reverseOrder());
+                
+                FetchProfile fp = new FetchProfile(); 
+                if(getHeaders){
+                	fp.add(FetchProfile.Item.ENVELOPE);
+                	fp.add(FetchProfile.Item.FLAGS);
+                	fp.add(FetchProfile.Item.STRUCTURE);
+                }
+                
+                if(K9.DEBUG){
+                	Log.i("IMAP search", "Search results: " + uids.size() + ", limit: " + limit);
+                }
+                
+                for (int i = 0, count = (limit==0 ? uids.size() : Math.min(uids.size(), limit)); i < count; i++) {
                     if (listener != null) {
                         listener.messageStarted("" + uids.get(i), i, count);
                     }
                     ImapMessage message = new ImapMessage("" + uids.get(i), this);
+
+                    if(getHeaders){
+                    	Message [] msgArray = {message};
+                    	fetch(msgArray, fp, null); //don't pass the listener since we're already updating it
+                    }
+                    
                     messages.add(message);
                     if (listener != null) {
                         listener.messageFinished(message, i, count);
@@ -1290,7 +1395,17 @@ private Message[] search(ImapSearcher searcher, MessageRetrievalListener listene
             } catch (IOException ioe) {
                 throw ioExceptionHandler(mConnection, ioe);
             }
-            return messages.toArray(EMPTY_MESSAGE_ARRAY);
+            
+            Message [] msgArray = messages.toArray(EMPTY_MESSAGE_ARRAY);
+            
+            /*
+             * Doing this here makes it one batch, but the UI spends a long time with (no subject) stuff, etc.
+             * Therefore, at least for now, should fetch headers individually as we fetch the messages.
+             * 
+            if(getHeaders){
+            	fetch(msgArray, fp, listener);
+            }*/
+            return msgArray;
         }
 
 
@@ -3271,5 +3386,33 @@ public Object foundLiteral(ImapResponse response,
             return null;
         }
     }
+	
+    @Override
+	public void searchRemoteMessages(final MessageRetrievalListener listener, final String[] queryFields, final String queryString,
+            final String folderName,  final Flag[] requiredFlags, final Flag[] forbiddenFlags) throws MessagingException{
+		
+		if(!mAccount.allowRemoteSearch()){
+			throw new MessagingException("Your settings do not allow remote searching of this account");
+		}
+		
+		final ImapFolder folder = (ImapFolder) getFolder(folderName);
+		if(folder == null){
+			throw new MessagingException("Invalid folder specified");
+		}
+		
+		try{
+			folder.open(OpenMode.READ_ONLY);
+			folder.checkOpen();
+			
+			folder.doRemoteSearch(queryString, requiredFlags, forbiddenFlags, listener);
+			
+		}
+		catch(Exception e){
+			throw new MessagingException("Error during search: " + e.toString());
+		}
+		
+	}
+    
+    
 
 }

From 9dd4ca80e6d98d876161fe942054e330a3e07c8f Mon Sep 17 00:00:00 2001
From: Rob Bayer 
Date: Wed, 29 Feb 2012 13:08:44 -0800
Subject: [PATCH 02/21] Dependency for preferences

---
 res/xml/account_settings_preferences.xml | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/res/xml/account_settings_preferences.xml b/res/xml/account_settings_preferences.xml
index 8b880db1ef6..2864cfa0a36 100644
--- a/res/xml/account_settings_preferences.xml
+++ b/res/xml/account_settings_preferences.xml
@@ -439,8 +439,8 @@
 
     
         
-        
-        
+        
+        
         
         
         
@@ -450,7 +450,7 @@
     
     
+        android:key="crypto" android:dependency="account_allow_remote_search">
 
         
Date: Wed, 29 Feb 2012 14:40:27 -0800
Subject: [PATCH 03/21] Simple help info when enabling Remote Search

---
 res/values/strings.xml                        |  5 ++
 .../k9/activity/setup/AccountSettings.java    | 64 ++++++++++++++++---
 2 files changed, 59 insertions(+), 10 deletions(-)

diff --git a/res/values/strings.xml b/res/values/strings.xml
index 96fbf7b3582..8f93ed814db 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1148,4 +1148,9 @@ the import operation. Please install a file manager application from Android Mar
     Remote Folder Searching
     Can be slow
     Include Body Text
+    
+        To perform a remote search, press your device\'s Search button while viewing a folder from this account.
+        \n\nNote: Remote search is NOT available from the Unified Inbox or from a list of folders.
+    
+    Don\'t Show Again
 
diff --git a/src/com/fsck/k9/activity/setup/AccountSettings.java b/src/com/fsck/k9/activity/setup/AccountSettings.java
index 18698e0e9ab..da995689d2d 100644
--- a/src/com/fsck/k9/activity/setup/AccountSettings.java
+++ b/src/com/fsck/k9/activity/setup/AccountSettings.java
@@ -1,19 +1,30 @@
 
 package com.fsck.k9.activity.setup;
 
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import android.app.AlertDialog;
 import android.content.Context;
+import android.content.DialogInterface;
 import android.content.Intent;
 import android.content.SharedPreferences;
+import android.content.SharedPreferences.Editor;
 import android.os.AsyncTask;
 import android.os.Bundle;
 import android.os.Vibrator;
-import android.preference.*;
+import android.preference.CheckBoxPreference;
+import android.preference.EditTextPreference;
+import android.preference.ListPreference;
+import android.preference.Preference;
+import android.preference.Preference.OnPreferenceChangeListener;
+import android.preference.PreferenceScreen;
+import android.preference.RingtonePreference;
 import android.util.Log;
-
-import java.util.Iterator;
-import java.util.Map;
-import java.util.LinkedList;
-import java.util.List;
+import android.view.View;
+import android.widget.CheckBox;
 
 import com.fsck.k9.Account;
 import com.fsck.k9.Account.FolderMode;
@@ -22,18 +33,17 @@
 import com.fsck.k9.NotificationSetting;
 import com.fsck.k9.Preferences;
 import com.fsck.k9.R;
-import com.fsck.k9.mail.Folder;
 import com.fsck.k9.activity.ChooseFolder;
 import com.fsck.k9.activity.ChooseIdentity;
 import com.fsck.k9.activity.ColorPickerDialog;
 import com.fsck.k9.activity.K9PreferenceActivity;
 import com.fsck.k9.activity.ManageIdentities;
 import com.fsck.k9.crypto.Apg;
+import com.fsck.k9.mail.Folder;
 import com.fsck.k9.mail.Store;
-import com.fsck.k9.service.MailService;
-
-import com.fsck.k9.mail.store.StorageManager;
 import com.fsck.k9.mail.store.LocalStore.LocalFolder;
+import com.fsck.k9.mail.store.StorageManager;
+import com.fsck.k9.service.MailService;
 
 
 public class AccountSettings extends K9PreferenceActivity {
@@ -477,6 +487,15 @@ public boolean onPreferenceChange(Preference preference, Object newValue) {
         
         // IMAP-specific preferences
         mAllowRemoteSearch = (CheckBoxPreference) findPreference(PREFERENCE_ALLOW_REMOTE_SEARCH);
+        
+        mAllowRemoteSearch.setOnPreferenceChangeListener(new OnPreferenceChangeListener() { 
+                                                            public boolean onPreferenceChange(Preference pref, Object newVal){
+                                                                if((Boolean) newVal){
+                                                                    showRemoteSearchHelp();
+                                                                }
+                                                                return true;
+                                                            }
+                                                         });
         mRemoteSearchNumResults = (ListPreference) findPreference(PREFERENCE_REMOTE_SEARCH_NUM_RESULTS);
         mRemoteSearchFullText = (CheckBoxPreference) findPreference(PREFERENCE_REMOTE_SEARCH_FULL_TEXT);
         mPushPollOnConnect = (CheckBoxPreference) findPreference(PREFERENCE_PUSH_POLL_ON_CONNECT);
@@ -675,6 +694,31 @@ public boolean onPreferenceChange(Preference preference, Object newValue) {
         handleCryptoAppDependencies();
     }
 
+    protected void showRemoteSearchHelp() {
+        final String noShowHelpPref = "account_settings_remote_search_hide_help";
+        final SharedPreferences prefs = getPreferences(MODE_PRIVATE);
+        if(!prefs.getBoolean(noShowHelpPref, false)){
+            AlertDialog.Builder adb = new AlertDialog.Builder(this);
+            final CheckBox noShowAgain = new CheckBox(this);
+            noShowAgain.setChecked(false);
+            noShowAgain.setText(R.string.no_show_again);
+            adb.setView(noShowAgain)
+               .setMessage(getString(R.string.account_settings_allow_remote_search_help))
+               .setCancelable(false)
+               .setPositiveButton(R.string.okay_action, new DialogInterface.OnClickListener() {
+                   public void onClick(DialogInterface dialog, int which) {
+                       if(noShowAgain.isChecked()){
+                           Editor edit = prefs.edit();
+                           edit.putBoolean(noShowHelpPref, true);
+                           edit.commit();
+                       }
+                   }
+               });
+           adb.create().show();
+        }
+        
+    }
+
     private void handleCryptoAppDependencies() {
         if ("".equals(mCryptoApp.getValue())) {
             mCryptoAutoSignature.setEnabled(false);

From 4f22a1a07b51fd960fd88a56c3a1d74db78c840d Mon Sep 17 00:00:00 2001
From: Rob Bayer 
Date: Wed, 29 Feb 2012 16:04:52 -0800
Subject: [PATCH 04/21] UI improvements

---
 .../fsck/k9/activity/ActivityListener.java    |  1 +
 src/com/fsck/k9/activity/MessageList.java     | 21 ++++++++++++++-----
 .../k9/controller/MessagingController.java    | 18 +++++++++-------
 .../fsck/k9/controller/MessagingListener.java |  3 +++
 src/com/fsck/k9/mail/Store.java               | 11 +++++-----
 src/com/fsck/k9/mail/store/ImapStore.java     |  5 +++--
 6 files changed, 40 insertions(+), 19 deletions(-)

diff --git a/src/com/fsck/k9/activity/ActivityListener.java b/src/com/fsck/k9/activity/ActivityListener.java
index 803158fc0c8..06d38eb7a78 100644
--- a/src/com/fsck/k9/activity/ActivityListener.java
+++ b/src/com/fsck/k9/activity/ActivityListener.java
@@ -76,6 +76,7 @@ else if (mSendingAccountDescription != null) {
     public void informUserOfStatus() {
     }
 
+
     @Override
     public void synchronizeMailboxFinished(
         Account account,
diff --git a/src/com/fsck/k9/activity/MessageList.java b/src/com/fsck/k9/activity/MessageList.java
index 8118cb4c3f2..1eb73199d31 100644
--- a/src/com/fsck/k9/activity/MessageList.java
+++ b/src/com/fsck/k9/activity/MessageList.java
@@ -1880,6 +1880,21 @@ class MessageListAdapter extends BaseAdapter {
 
         private final ActivityListener mListener = new ActivityListener() {
 
+            @Override
+            public void remoteSearchStarted(Account acct, String folder){
+                //TODO: Update UI behavior for Remote Searching
+                //for now, just use existing UI behavior
+                synchronizeMailboxStarted(acct, folder); 
+            }
+            
+            @Override
+            public void remoteSearchFinished(Account acct, String folder, int numResults){
+                //TODO: Update UI behavior for Remote Searching
+                //TODO: Show number of results
+                //for now, just use existing UI behavior
+                synchronizeMailboxFinished(acct, folder, 0, 0);
+            }
+            
             @Override
             public void informUserOfStatus() {
                 mHandler.refreshTitle();
@@ -2012,11 +2027,7 @@ public void messageUidChanged(Account account, String folder, String oldUid, Str
         };
 
         private boolean updateForMe(Account account, String folder) {
-            if ((account.equals(mAccount) && mFolderName != null && folder.equals(mFolderName))) {
-                return true;
-            } else {
-                return false;
-            }
+            return account.equals(mAccount) && mFolderName != null && folder.equals(mFolderName);
         }
 
         private Drawable mAttachmentIcon;
diff --git a/src/com/fsck/k9/controller/MessagingController.java b/src/com/fsck/k9/controller/MessagingController.java
index e273c71fa91..58e1d3ddfc3 100644
--- a/src/com/fsck/k9/controller/MessagingController.java
+++ b/src/com/fsck/k9/controller/MessagingController.java
@@ -821,14 +821,19 @@ public void searchRemoteMessagesSynchronous(final String acctUuid, final String
         final AccountStats stats = new AccountStats();
 
         if (listener != null) {
-            listener.listLocalMessagesStarted(acct, null);
+            listener.remoteSearchStarted(acct, folderName);
         }
 
+        
         MessageRetrievalListener retrievalListener = new MessageRetrievalListener() {
             @Override
-            public void messageStarted(String message, int number, int ofTotal) {}
+            public void messageStarted(String message, int number, int ofTotal) {
+                
+            }
             @Override
-            public void messageFinished(Message message, int number, int ofTotal) {
+            public void messageFinished(Message message, int number, int ofTotal){
+                
+                
                 if (!isMessageSuppressed(message.getFolder().getAccount(), message.getFolder().getName(), message)) {
                     List messages = new ArrayList();
 
@@ -837,7 +842,7 @@ public void messageFinished(Message message, int number, int ofTotal) {
                     stats.flaggedMessageCount += (message.isSet(Flag.FLAGGED)) ? 1 : 0;
                     if (listener != null) {
                         listener.listLocalMessagesAddMessages(acct, null, messages);
-
+                        listener.synchronizeMailboxProgress(acct, null, number, ofTotal);
                     }
                 }
 
@@ -849,11 +854,9 @@ public void messagesFinished(int number) {
         };
 
         try {
-            String[] queryFields = {"html_content", "subject", "sender_list"};
             Store acctStore = acct.getRemoteStore();
 
-            //TODO: make queryFields actually do something
-            acctStore.searchRemoteMessages(retrievalListener, queryFields, query, folderName, requiredFlags, forbiddenFlags);
+            acctStore.searchRemoteMessages(retrievalListener, query, folderName, requiredFlags, forbiddenFlags);
 
         } catch (Exception e) {
             if (listener != null) {
@@ -863,6 +866,7 @@ public void messagesFinished(int number) {
         } finally {
             if (listener != null) {
                 listener.listLocalMessagesFinished(acct, null);
+                listener.remoteSearchFinished(acct, folderName, 0);
             }
         }
 
diff --git a/src/com/fsck/k9/controller/MessagingListener.java b/src/com/fsck/k9/controller/MessagingListener.java
index 49ddbf4da08..e62dc631f19 100644
--- a/src/com/fsck/k9/controller/MessagingListener.java
+++ b/src/com/fsck/k9/controller/MessagingListener.java
@@ -151,6 +151,9 @@ public void pendingCommandCompleted(Account account, String commandTitle) {}
 
     public void pendingCommandsFinished(Account account) {}
 
+    public void remoteSearchStarted(Account acct, String folder){}
+    
+    public void remoteSearchFinished(Account acct, String folder, int numResults) {}
 
     /**
      * General notification messages subclasses can override to be notified that the controller
diff --git a/src/com/fsck/k9/mail/Store.java b/src/com/fsck/k9/mail/Store.java
index 28ff45924ca..344be2aaeb9 100644
--- a/src/com/fsck/k9/mail/Store.java
+++ b/src/com/fsck/k9/mail/Store.java
@@ -1,6 +1,9 @@
 
 package com.fsck.k9.mail;
 
+import java.util.HashMap;
+import java.util.List;
+
 import android.app.Application;
 import android.content.Context;
 
@@ -9,11 +12,9 @@
 import com.fsck.k9.mail.store.ImapStore;
 import com.fsck.k9.mail.store.LocalStore;
 import com.fsck.k9.mail.store.Pop3Store;
-import com.fsck.k9.mail.store.WebDavStore;
 import com.fsck.k9.mail.store.StorageManager.StorageProvider;
-
-import java.util.HashMap;
-import java.util.List;
+import com.fsck.k9.mail.store.UnavailableStorageException;
+import com.fsck.k9.mail.store.WebDavStore;
 
 /**
  * Store is the access point for an email message store. It's location can be
@@ -178,7 +179,7 @@ public Account getAccount() {
         return mAccount;
     }
     
-    public void searchRemoteMessages(MessageRetrievalListener listener, String[] queryFields, String queryString,
+    public void searchRemoteMessages(MessageRetrievalListener listener, String queryString,
             String folder,  final Flag[] requiredFlags, final Flag[] forbiddenFlags) throws MessagingException{
     	throw new MessagingException("K-9 does not support remote searchign on this account type");
     }
diff --git a/src/com/fsck/k9/mail/store/ImapStore.java b/src/com/fsck/k9/mail/store/ImapStore.java
index 72629e2e400..6d8db36b0da 100644
--- a/src/com/fsck/k9/mail/store/ImapStore.java
+++ b/src/com/fsck/k9/mail/store/ImapStore.java
@@ -65,6 +65,7 @@
 import com.fsck.k9.K9;
 import com.fsck.k9.R;
 import com.fsck.k9.controller.MessageRetrievalListener;
+import com.fsck.k9.controller.MessagingListener;
 import com.fsck.k9.helper.Utility;
 import com.fsck.k9.helper.power.TracingPowerManager;
 import com.fsck.k9.helper.power.TracingPowerManager.TracingWakeLock;
@@ -94,7 +95,6 @@
 import com.fsck.k9.mail.internet.MimeUtility;
 import com.fsck.k9.mail.store.ImapResponseParser.ImapList;
 import com.fsck.k9.mail.store.ImapResponseParser.ImapResponse;
-import com.fsck.k9.mail.store.LocalStore.LocalFolder;
 import com.fsck.k9.mail.transport.imap.ImapSettings;
 import com.jcraft.jzlib.JZlib;
 import com.jcraft.jzlib.ZOutputStream;
@@ -3388,7 +3388,7 @@ public Object foundLiteral(ImapResponse response,
     }
 	
     @Override
-	public void searchRemoteMessages(final MessageRetrievalListener listener, final String[] queryFields, final String queryString,
+	public void searchRemoteMessages(final MessageRetrievalListener listener, final String queryString,
             final String folderName,  final Flag[] requiredFlags, final Flag[] forbiddenFlags) throws MessagingException{
 		
 		if(!mAccount.allowRemoteSearch()){
@@ -3404,6 +3404,7 @@ public void searchRemoteMessages(final MessageRetrievalListener listener, final
 			folder.open(OpenMode.READ_ONLY);
 			folder.checkOpen();
 			
+			
 			folder.doRemoteSearch(queryString, requiredFlags, forbiddenFlags, listener);
 			
 		}

From 38aebf5ab4bd50320098e5f56d8fb890bbc2ecda Mon Sep 17 00:00:00 2001
From: Rob Bayer 
Date: Wed, 29 Feb 2012 16:10:19 -0800
Subject: [PATCH 05/21] Fix stupid edits

---
 src/com/fsck/k9/activity/MessageList.java | 26 +++++++++++++++++++++--
 1 file changed, 24 insertions(+), 2 deletions(-)

diff --git a/src/com/fsck/k9/activity/MessageList.java b/src/com/fsck/k9/activity/MessageList.java
index 1eb73199d31..ea1e9f1e0e2 100644
--- a/src/com/fsck/k9/activity/MessageList.java
+++ b/src/com/fsck/k9/activity/MessageList.java
@@ -710,8 +710,32 @@ private void initializeMessageList(Intent intent, boolean create) {
             // So just leave the activity in the state it was left in.
             return;
         }
+        
+        mQueryString = intent.getStringExtra(SearchManager.QUERY);
+        mFolderName = null;
+        mRemoteSearch = false;
+        mSearchAccount = null;
+        mSearchFolder = null;
+        if(mQueryString != null){
+            if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
+                //Query was received from Search Dialog
+                Bundle appData = getIntent().getBundleExtra(SearchManager.APP_DATA);
+                if(appData != null){
+                    mSearchAccount = appData.getString(EXTRA_SEARCH_ACCOUNT);
+                    mSearchFolder = appData.getString(EXTRA_SEARCH_FOLDER);
+                    mRemoteSearch = appData.getBoolean(EXTRA_REMOTE_SEARCH);
+                }
+            }
+            else{
+                mSearchAccount = intent.getStringExtra(EXTRA_SEARCH_ACCOUNT);
+                mSearchFolder = intent.getStringExtra(EXTRA_SEARCH_FOLDER);
+                
+            }
+        }
 
         String accountUuid = intent.getStringExtra(EXTRA_ACCOUNT);
+        mFolderName = intent.getStringExtra(EXTRA_FOLDER);
+        
         mAccount = Preferences.getPreferences(this).getAccount(accountUuid);
 
         if (mAccount != null && !mAccount.isAvailable(this)) {
@@ -720,8 +744,6 @@ private void initializeMessageList(Intent intent, boolean create) {
             return;
         }
 
-        mFolderName = intent.getStringExtra(EXTRA_FOLDER);
-        mQueryString = intent.getStringExtra(SearchManager.QUERY);
 
         String queryFlags = intent.getStringExtra(EXTRA_QUERY_FLAGS);
         if (queryFlags != null) {

From e46a666f9a3979d81e19cf858e8837da2d3c43a2 Mon Sep 17 00:00:00 2001
From: Rob Bayer 
Date: Wed, 29 Feb 2012 23:38:26 -0800
Subject: [PATCH 06/21] Working IMAP search, with passable UI.

---
 res/values/strings.xml                        |   3 +
 src/com/fsck/k9/activity/MessageList.java     | 178 ++++++++++++------
 .../k9/controller/MessagingController.java    |  53 ++++--
 .../fsck/k9/controller/MessagingListener.java |  43 +++++
 src/com/fsck/k9/mail/Store.java               |   5 +-
 src/com/fsck/k9/mail/store/ImapStore.java     |  43 +++--
 6 files changed, 234 insertions(+), 91 deletions(-)

diff --git a/res/values/strings.xml b/res/values/strings.xml
index 8f93ed814db..36d1a7960df 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1152,5 +1152,8 @@ the import operation. Please install a file manager application from Android Mar
         To perform a remote search, press your device\'s Search button while viewing a folder from this account.
         \n\nNote: Remote search is NOT available from the Unified Inbox or from a list of folders.
     
+    Sending query to server
     Don\'t Show Again
+    Fetching %d results
+    Fetching %1$d of %2$d results
 
diff --git a/src/com/fsck/k9/activity/MessageList.java b/src/com/fsck/k9/activity/MessageList.java
index ea1e9f1e0e2..42878272e2c 100644
--- a/src/com/fsck/k9/activity/MessageList.java
+++ b/src/com/fsck/k9/activity/MessageList.java
@@ -70,6 +70,7 @@
 import com.fsck.k9.mail.Flag;
 import com.fsck.k9.mail.Folder;
 import com.fsck.k9.mail.Message;
+import com.fsck.k9.mail.MessagingException;
 import com.fsck.k9.mail.store.LocalStore;
 import com.fsck.k9.mail.store.LocalStore.LocalFolder;
 import com.fsck.k9.mail.store.StorageManager;
@@ -421,6 +422,25 @@ public void run() {
             });
         }
 
+        
+        public void updateFooter(final String text, final boolean progressVisible){
+            runOnUiThread(new Runnable(){
+                public void run(){
+                    FooterViewHolder holder = (FooterViewHolder) mFooterView.getTag();
+                    holder.progress.setVisibility(progressVisible ? ProgressBar.VISIBLE : ProgressBar.INVISIBLE);
+                    if(text!= null){
+                        holder.main.setText(text);
+                    }
+                }
+            });
+        }
+        
+        public void setWindowProgress(final int amt){
+            runOnUiThread(new Runnable(){public void run(){
+                getWindow().setFeatureInt(Window.FEATURE_PROGRESS, amt);
+            }});
+        }
+        
         private void resetUnreadCount() {
             runOnUiThread(new Runnable() {
                 @Override
@@ -493,11 +513,24 @@ public void folderLoading(String folder, boolean loading) {
             if (mCurrentFolder != null && mCurrentFolder.name.equals(folder)) {
                 mCurrentFolder.loading = loading;
             }
-            runOnUiThread(new Runnable() {
-                @Override public void run() {
-                    updateFooterView();
+
+            if (mCurrentFolder != null && mAccount != null) {
+                if (mCurrentFolder.loading) {
+                    updateFooter(getString(R.string.status_loading_more), true);
+                } else {
+                    if (!mCurrentFolder.lastCheckFailed) {
+                        if (mAccount.getDisplayCount() == 0) {
+                            updateFooter(getString(R.string.message_list_load_more_messages_action), false);
+                        } else {
+                            updateFooter(String.format(getString(R.string.load_more_messages_fmt), mAccount.getDisplayCount()), false);
+                        }
+                    } else {
+                        updateFooter(getString(R.string.status_loading_more_failed), false);
+                    }
                 }
-            });
+            } else {
+                updateFooter(null, false);
+            }
         }
 
         private void refreshTitle() {
@@ -511,7 +544,9 @@ public void run() {
 
         private void refreshTitleOnThread() {
             setWindowTitle();
-            setWindowProgress();
+            if(!mRemoteSearch){
+                setWindowProgress();
+            }
         }
 
         private void setWindowProgress() {
@@ -663,7 +698,7 @@ public static void actionHandle(Context context, String title,
     @Override
     public void onItemClick(AdapterView parent, View view, int position, long id) {
         if (view == mFooterView) {
-            if (mCurrentFolder != null) {
+            if (mCurrentFolder != null && !mRemoteSearch) {
                 mController.loadMoreMessages(mAccount, mFolderName, mAdapter.mListener);
             }
             return;
@@ -779,8 +814,8 @@ private void initializeMessageList(Intent intent, boolean create) {
             mCurrentFolder = mAdapter.getFolder(mFolderName, mAccount);
         }
 
-        // Hide "Load up to x more" footer for search views
-        mFooterView.setVisibility((mQueryString != null) ? View.GONE : View.VISIBLE);
+        // Hide "Load up to x more" footer for local search views
+        mFooterView.setVisibility((mQueryString != null && !mRemoteSearch) ? View.GONE : View.VISIBLE);
 
         mController = MessagingController.getInstance(getApplication());
         mListView.setAdapter(mAdapter);
@@ -881,32 +916,34 @@ else if (mFolderName != null) {
             new Thread() {
                 @Override
                 public void run() {
-                    mAdapter.markAllMessagesAsDirty();
-
-                    if (mRemoteSearch){
-                		mController.searchRemoteMessagesSynchronous(mSearchAccount, mSearchFolder, mQueryString, null, null, mAdapter.mListener);
-                	} else if (mFolderName != null) {
-                        mController.listLocalMessagesSynchronous(mAccount, mFolderName,  mAdapter.mListener);
-                    } else if (mQueryString != null) {
-                        mController.searchLocalMessagesSynchronous(mAccountUuids, mFolderNames, null, mQueryString, mIntegrate, mQueryFlags, mForbiddenFlags, mAdapter.mListener);
+                    
+
+                    if (!mRemoteSearch){
+                        mAdapter.markAllMessagesAsDirty();
+                        if (mFolderName != null) {
+                            mController.listLocalMessagesSynchronous(mAccount, mFolderName,  mAdapter.mListener);
+                        } else if (mQueryString != null) {
+                            mController.searchLocalMessagesSynchronous(mAccountUuids, mFolderNames, null, mQueryString, mIntegrate, mQueryFlags, mForbiddenFlags, mAdapter.mListener);
+                        }
+                        mAdapter.pruneDirtyMessages();
+                        runOnUiThread(new Runnable() {
+                            @Override
+                            public void run() {
+                                mAdapter.notifyDataSetChanged();
+                                restoreListState();
+                            }
+                        });
                     }
 
 
-                    mAdapter.pruneDirtyMessages();
-                    runOnUiThread(new Runnable() {
-                        @Override
-                        public void run() {
-                            mAdapter.notifyDataSetChanged();
-                            restoreListState();
-                        }
-                    });
+                    
                 }
 
             }
             .start();
         }
 
-        if (mAccount != null && mFolderName != null) {
+        if (mAccount != null && mFolderName != null && !mRemoteSearch) {
             mController.getFolderUnreadMessageCount(mAccount, mFolderName, mAdapter.mListener);
         }
         mHandler.refreshTitle();
@@ -1902,21 +1939,75 @@ class MessageListAdapter extends BaseAdapter {
 
         private final ActivityListener mListener = new ActivityListener() {
 
+            
+            @Override
+            public void remoteSearchAddMessage(Account account, String folderName, Message message, final int numDone, final int numTotal) {
+                
+                if(numTotal > 0){
+                    mHandler.setWindowProgress(Window.PROGRESS_END/numTotal * numDone);
+                }
+                else{
+                    mHandler.setWindowProgress(Window.PROGRESS_END);
+                }
+                
+                //MessageView expects messages to be in the LocalStore, so add them
+                try{
+                    LocalFolder localFolder = account.getLocalStore().getFolder(folderName);
+                    if(localFolder != null){
+                        if(localFolder.getMessage(message.getUid()) == null){
+                            Message [] messages = {message};
+                            localFolder.appendMessages(messages);
+                        }//else: the message is already in the local store so don't worry about it
+                    }//else: should never really happen
+                    
+                }
+                catch(MessagingException e){
+                    //FIXME: Do something useful here...
+                    if(K9.DEBUG){
+                        Log.d("IMAP search", "remoteSearchAddMessage caught error: " + e.toString());
+                    }
+                }
+                
+                addOrUpdateMessages(account, folderName, Collections.singletonList(message), false);
+            }
+
+            @Override
+            public void remoteSearchFailed(Account acct, String folder,
+                    final String err) {
+                //TODO: Better error handling
+                runOnUiThread(new Runnable(){public void run(){
+                    Toast.makeText(getApplication(),  err, Toast.LENGTH_LONG).show();
+                }});
+            }
+
             @Override
             public void remoteSearchStarted(Account acct, String folder){
-                //TODO: Update UI behavior for Remote Searching
-                //for now, just use existing UI behavior
-                synchronizeMailboxStarted(acct, folder); 
+                mHandler.progress(true);
+                mHandler.updateFooter(getString(R.string.remote_search_sending_query), true);
             }
             
+
             @Override
             public void remoteSearchFinished(Account acct, String folder, int numResults){
-                //TODO: Update UI behavior for Remote Searching
-                //TODO: Show number of results
-                //for now, just use existing UI behavior
-                synchronizeMailboxFinished(acct, folder, 0, 0);
+                mHandler.progress(false);
+                mHandler.updateFooter("", false);
+                mHandler.setWindowProgress(Window.PROGRESS_END);
+            }
+            
+            @Override
+            public void remoteSearchServerQueryComplete(Account account, String folderName, int numResults){ 
+                mHandler.progress(true);
+                if(account != null &&  account.getRemoteSearchNumResults() != 0 && numResults > account.getRemoteSearchNumResults()){
+                    mHandler.updateFooter(getString(R.string.remote_search_downloading_limited, account.getRemoteSearchNumResults(), numResults), true);
+                }
+                else{
+                    mHandler.updateFooter(getString(R.string.remote_search_downloading, numResults), true);
+                }
+                mHandler.setWindowProgress(Window.PROGRESS_START);
             }
             
+            
+            
             @Override
             public void informUserOfStatus() {
                 mHandler.refreshTitle();
@@ -2516,29 +2607,6 @@ private View getFooterView(ViewGroup parent) {
         return mFooterView;
     }
 
-    private void updateFooterView() {
-        FooterViewHolder holder = (FooterViewHolder) mFooterView.getTag();
-
-        if (mCurrentFolder != null && mAccount != null) {
-            if (mCurrentFolder.loading) {
-                holder.main.setText(getString(R.string.status_loading_more));
-                holder.progress.setVisibility(ProgressBar.VISIBLE);
-            } else {
-                if (!mCurrentFolder.lastCheckFailed) {
-                    if (mAccount.getDisplayCount() == 0) {
-                        holder.main.setText(getString(R.string.message_list_load_more_messages_action));
-                    } else {
-                        holder.main.setText(String.format(getString(R.string.load_more_messages_fmt), mAccount.getDisplayCount()));
-                    }
-                } else {
-                    holder.main.setText(getString(R.string.status_loading_more_failed));
-                }
-                holder.progress.setVisibility(ProgressBar.INVISIBLE);
-            }
-        } else {
-            holder.progress.setVisibility(ProgressBar.INVISIBLE);
-        }
-    }
 
     private void hideBatchButtons() {
         if (mBatchButtonArea.getVisibility() != View.GONE) {
diff --git a/src/com/fsck/k9/controller/MessagingController.java b/src/com/fsck/k9/controller/MessagingController.java
index 58e1d3ddfc3..002b8c000fb 100644
--- a/src/com/fsck/k9/controller/MessagingController.java
+++ b/src/com/fsck/k9/controller/MessagingController.java
@@ -42,11 +42,11 @@
 import com.fsck.k9.Account;
 import com.fsck.k9.AccountStats;
 import com.fsck.k9.K9;
+import com.fsck.k9.K9.Intents;
 import com.fsck.k9.NotificationSetting;
 import com.fsck.k9.Preferences;
 import com.fsck.k9.R;
 import com.fsck.k9.SearchSpecification;
-import com.fsck.k9.K9.Intents;
 import com.fsck.k9.activity.FolderList;
 import com.fsck.k9.activity.MessageList;
 import com.fsck.k9.helper.Utility;
@@ -58,8 +58,8 @@
 import com.fsck.k9.mail.Folder;
 import com.fsck.k9.mail.Folder.FolderType;
 import com.fsck.k9.mail.Folder.OpenMode;
-import com.fsck.k9.mail.Message.RecipientType;
 import com.fsck.k9.mail.Message;
+import com.fsck.k9.mail.Message.RecipientType;
 import com.fsck.k9.mail.MessagingException;
 import com.fsck.k9.mail.Part;
 import com.fsck.k9.mail.PushReceiver;
@@ -69,12 +69,12 @@
 import com.fsck.k9.mail.internet.MimeMessage;
 import com.fsck.k9.mail.internet.MimeUtility;
 import com.fsck.k9.mail.internet.TextBody;
-import com.fsck.k9.mail.store.UnavailableAccountException;
 import com.fsck.k9.mail.store.LocalStore;
-import com.fsck.k9.mail.store.UnavailableStorageException;
 import com.fsck.k9.mail.store.LocalStore.LocalFolder;
 import com.fsck.k9.mail.store.LocalStore.LocalMessage;
 import com.fsck.k9.mail.store.LocalStore.PendingCommand;
+import com.fsck.k9.mail.store.UnavailableAccountException;
+import com.fsck.k9.mail.store.UnavailableStorageException;
 
 
 /**
@@ -835,14 +835,10 @@ public void messageFinished(Message message, int number, int ofTotal){
                 
                 
                 if (!isMessageSuppressed(message.getFolder().getAccount(), message.getFolder().getName(), message)) {
-                    List messages = new ArrayList();
-
-                    messages.add(message);
                     stats.unreadMessageCount += (!message.isSet(Flag.SEEN)) ? 1 : 0;
                     stats.flaggedMessageCount += (message.isSet(Flag.FLAGGED)) ? 1 : 0;
                     if (listener != null) {
-                        listener.listLocalMessagesAddMessages(acct, null, messages);
-                        listener.synchronizeMailboxProgress(acct, null, number, ofTotal);
+                        listener.remoteSearchAddMessage(acct, folderName, message, number, ofTotal);
                     }
                 }
 
@@ -852,15 +848,32 @@ public void messagesFinished(int number) {
 
             }
         };
+        
+        SearchListener searchListener = new SearchListener(){
+
+            @Override
+            public void searchStarted() {
+                listener.remoteSearchStarted(acct, folderName);
+            }
+
+            @Override
+            public void searchFinished(int numResults) {
+                listener.remoteSearchServerQueryComplete(acct, folderName, numResults);
+            }
+        };
 
         try {
             Store acctStore = acct.getRemoteStore();
-
-            acctStore.searchRemoteMessages(retrievalListener, query, folderName, requiredFlags, forbiddenFlags);
+            if(acctStore != null){
+                acctStore.searchRemoteMessages(retrievalListener, searchListener, query, folderName, requiredFlags, forbiddenFlags);
+            }
+            else{
+                throw new MessagingException("Account has no remote store");
+            }
 
         } catch (Exception e) {
             if (listener != null) {
-                listener.listLocalMessagesFailed(acct, null, e.getMessage());
+                listener.remoteSearchFailed(acct, null, e.getMessage());
             }
             addErrorMessage(acct, null, e);
         } finally {
@@ -2809,10 +2822,10 @@ public void run() {
         });
     }
 
-    public void loadMessageForView(final Account account, final String folder, final String uid,
+    public void loadMessageForView(final Account account, final String folderName, final String uid,
                                    final MessagingListener listener) {
         for (MessagingListener l : getListeners(listener)) {
-            l.loadMessageForViewStarted(account, folder, uid);
+            l.loadMessageForViewStarted(account, folderName, uid);
         }
         threadPool.execute(new Runnable() {
             @Override
@@ -2820,13 +2833,13 @@ public void run() {
 
                 try {
                     LocalStore localStore = account.getLocalStore();
-                    LocalFolder localFolder = localStore.getFolder(folder);
+                    LocalFolder localFolder = localStore.getFolder(folderName);
                     localFolder.open(OpenMode.READ_WRITE);
 
                     LocalMessage message = (LocalMessage)localFolder.getMessage(uid);
                     if (message == null
                     || message.getId() == 0) {
-                        throw new IllegalArgumentException("Message not found: folder=" + folder + ", uid=" + uid);
+                        throw new IllegalArgumentException("Message not found: folder=" + folderName + ", uid=" + uid);
                     }
                     if (!message.isSet(Flag.SEEN)) {
                         message.setFlag(Flag.SEEN, true);
@@ -2834,7 +2847,7 @@ public void run() {
                     }
 
                     for (MessagingListener l : getListeners(listener)) {
-                        l.loadMessageForViewHeadersAvailable(account, folder, uid, message);
+                        l.loadMessageForViewHeadersAvailable(account, folderName, uid, message);
                     }
 
                     FetchProfile fp = new FetchProfile();
@@ -2846,16 +2859,16 @@ public void run() {
                     localFolder.close();
 
                     for (MessagingListener l : getListeners(listener)) {
-                        l.loadMessageForViewBodyAvailable(account, folder, uid, message);
+                        l.loadMessageForViewBodyAvailable(account, folderName, uid, message);
                     }
 
                     for (MessagingListener l : getListeners(listener)) {
-                        l.loadMessageForViewFinished(account, folder, uid, message);
+                        l.loadMessageForViewFinished(account, folderName, uid, message);
                     }
 
                 } catch (Exception e) {
                     for (MessagingListener l : getListeners(listener)) {
-                        l.loadMessageForViewFailed(account, folder, uid, e);
+                        l.loadMessageForViewFailed(account, folderName, uid, e);
                     }
                     addErrorMessage(account, null, e);
 
diff --git a/src/com/fsck/k9/controller/MessagingListener.java b/src/com/fsck/k9/controller/MessagingListener.java
index e62dc631f19..0fd87e3881a 100644
--- a/src/com/fsck/k9/controller/MessagingListener.java
+++ b/src/com/fsck/k9/controller/MessagingListener.java
@@ -151,10 +151,51 @@ public void pendingCommandCompleted(Account account, String commandTitle) {}
 
     public void pendingCommandsFinished(Account account) {}
 
+    
+    /**
+     * Called when a remote search is started
+     * 
+     * @param acct
+     * @param folder
+     */
     public void remoteSearchStarted(Account acct, String folder){}
     
+    
+    /**
+     * Called when server has responded to our query.  Messages have not yet been downloaded.
+     * 
+     * @param numResults
+     */
+    public void remoteSearchServerQueryComplete(Account account, String folderName, int numResults){ }
+    
+    
+    /**
+     * Called when a new result message is available for a remote search
+     * Can assume headers have been downloaded, but potentially not body.
+     * @param account 
+     * @param folder 
+     * @param message
+     */
+    public void remoteSearchAddMessage(Account account, String folder, Message message, int numDone, int numTotal){ }
+    
+    /**
+     * Called when Remote Search is fully complete
+     * 
+     * @param acct
+     * @param folder
+     * @param numResults
+     */
     public void remoteSearchFinished(Account acct, String folder, int numResults) {}
 
+    /**
+     * Called when there was a problem with a remote search operation.
+     * 
+     * @param acct
+     * @param folder
+     * @param err
+     */
+    public void remoteSearchFailed(Account acct, String folder, String err){ }
+    
     /**
      * General notification messages subclasses can override to be notified that the controller
      * has completed a command. This is useful for turning off progress indicators that may have
@@ -165,4 +206,6 @@ public void remoteSearchFinished(Account acct, String folder, int numResults) {}
      *         {@code false} otherwise.
      */
     public void controllerCommandCompleted(boolean moreCommandsToRun) {}
+
+
 }
diff --git a/src/com/fsck/k9/mail/Store.java b/src/com/fsck/k9/mail/Store.java
index 344be2aaeb9..86276a916ab 100644
--- a/src/com/fsck/k9/mail/Store.java
+++ b/src/com/fsck/k9/mail/Store.java
@@ -9,6 +9,7 @@
 
 import com.fsck.k9.Account;
 import com.fsck.k9.controller.MessageRetrievalListener;
+import com.fsck.k9.controller.SearchListener;
 import com.fsck.k9.mail.store.ImapStore;
 import com.fsck.k9.mail.store.LocalStore;
 import com.fsck.k9.mail.store.Pop3Store;
@@ -179,8 +180,8 @@ public Account getAccount() {
         return mAccount;
     }
     
-    public void searchRemoteMessages(MessageRetrievalListener listener, String queryString,
+    public void searchRemoteMessages(MessageRetrievalListener msgListener, SearchListener searchListener, String queryString,
             String folder,  final Flag[] requiredFlags, final Flag[] forbiddenFlags) throws MessagingException{
-    	throw new MessagingException("K-9 does not support remote searchign on this account type");
+    	throw new MessagingException("K-9 does not support remote searching on this account type");
     }
 }
diff --git a/src/com/fsck/k9/mail/store/ImapStore.java b/src/com/fsck/k9/mail/store/ImapStore.java
index 6d8db36b0da..07e5915b325 100644
--- a/src/com/fsck/k9/mail/store/ImapStore.java
+++ b/src/com/fsck/k9/mail/store/ImapStore.java
@@ -65,7 +65,7 @@
 import com.fsck.k9.K9;
 import com.fsck.k9.R;
 import com.fsck.k9.controller.MessageRetrievalListener;
-import com.fsck.k9.controller.MessagingListener;
+import com.fsck.k9.controller.SearchListener;
 import com.fsck.k9.helper.Utility;
 import com.fsck.k9.helper.power.TracingPowerManager;
 import com.fsck.k9.helper.power.TracingPowerManager.TracingWakeLock;
@@ -1172,11 +1172,11 @@ private int getRemoteMessageCount(String criteria) throws MessagingException {
 
         }
         
-        public void doRemoteSearch(final String queryString, final Flag[] requiredFlags, final Flag [] forbiddenFlags, final MessageRetrievalListener listener) 
+        public void doRemoteSearch(final String queryString, final Flag[] requiredFlags, final Flag [] forbiddenFlags, final MessageRetrievalListener msgListener, final SearchListener searchListener) 
         		throws MessagingException{
         	ImapSearcher searcher = new ImapSearcher(){
         		public List search() throws IOException, MessagingException {
-        			String imapQuery = "SEARCH ";
+        			String imapQuery = "UID SEARCH ";
         			if(requiredFlags != null){
 	        			for(Flag f : requiredFlags){
 	        				switch(f){
@@ -1246,7 +1246,7 @@ public List search() throws IOException, MessagingException {
         		}
         	};
         	
-        	search(searcher, listener, (mAccount != null ? mAccount.getRemoteSearchNumResults() : 0), true);
+        	search(searcher, msgListener, searchListener, (mAccount != null ? mAccount.getRemoteSearchNumResults() : 0), true);
         }
 
         @Override
@@ -1339,16 +1339,22 @@ public List search() throws IOException, MessagingException {
         }
 
         private Message[] search(ImapSearcher searcher, MessageRetrievalListener listener) throws MessagingException {
-        	return search(searcher, listener, 0, false);
+        	return search(searcher, listener, null, 0, false);
         }
         
-        private Message[] search(ImapSearcher searcher, MessageRetrievalListener listener, int limit, boolean getHeaders) throws MessagingException {
+        private Message[] search(ImapSearcher searcher, MessageRetrievalListener msgListener, SearchListener searchListener, int limit, boolean getHeaders) throws MessagingException {
 
             checkOpen();
             ArrayList messages = new ArrayList();
             try {
                 ArrayList uids = new ArrayList();
-                List responses = searcher.search(); //
+                
+                if(searchListener != null){
+                    searchListener.searchStarted();
+                }
+                
+                List responses = searcher.search(); 
+
                 for (ImapResponse response : responses) {
                     if (response.mTag == null) {
                         if (ImapResponseParser.equalsIgnoreCase(response.get(0), "SEARCH")) {
@@ -1358,6 +1364,10 @@ private Message[] search(ImapSearcher searcher, MessageRetrievalListener listene
                         }
                     }
                 }
+                
+                if(searchListener != null){
+                    searchListener.searchFinished(uids.size());
+                }
 
                 // Sort the uids in numerically decreasing order 
                 // By doing it in decreasing order, we ensure newest messages are dealt with first
@@ -1374,22 +1384,26 @@ private Message[] search(ImapSearcher searcher, MessageRetrievalListener listene
                 
                 if(K9.DEBUG){
                 	Log.i("IMAP search", "Search results: " + uids.size() + ", limit: " + limit);
+                	Log.i("IMAP search", "Uids: " + Arrays.toString(uids.toArray()));
                 }
                 
                 for (int i = 0, count = (limit==0 ? uids.size() : Math.min(uids.size(), limit)); i < count; i++) {
-                    if (listener != null) {
-                        listener.messageStarted("" + uids.get(i), i, count);
+                    if (msgListener != null) {
+                        msgListener.messageStarted("" + uids.get(i), i, count);
                     }
                     ImapMessage message = new ImapMessage("" + uids.get(i), this);
-
+                    
                     if(getHeaders){
                     	Message [] msgArray = {message};
+                    	if(K9.DEBUG){
+                    	    Log.i("IMAP search", "Fetching header: " + message.getUid());
+                    	}
                     	fetch(msgArray, fp, null); //don't pass the listener since we're already updating it
                     }
                     
                     messages.add(message);
-                    if (listener != null) {
-                        listener.messageFinished(message, i, count);
+                    if (msgListener != null) {
+                        msgListener.messageFinished(message, i, count);
                     }
                 }
             } catch (IOException ioe) {
@@ -3388,7 +3402,7 @@ public Object foundLiteral(ImapResponse response,
     }
 	
     @Override
-	public void searchRemoteMessages(final MessageRetrievalListener listener, final String queryString,
+	public void searchRemoteMessages(final MessageRetrievalListener msgListener, final SearchListener searchListener, final String queryString,
             final String folderName,  final Flag[] requiredFlags, final Flag[] forbiddenFlags) throws MessagingException{
 		
 		if(!mAccount.allowRemoteSearch()){
@@ -3405,10 +3419,11 @@ public void searchRemoteMessages(final MessageRetrievalListener listener, final
 			folder.checkOpen();
 			
 			
-			folder.doRemoteSearch(queryString, requiredFlags, forbiddenFlags, listener);
+			folder.doRemoteSearch(queryString, requiredFlags, forbiddenFlags, msgListener, searchListener);
 			
 		}
 		catch(Exception e){
+		    e.printStackTrace();
 			throw new MessagingException("Error during search: " + e.toString());
 		}
 		

From 8f73523b1a620d4d99c2d5de85923d89a1d50869 Mon Sep 17 00:00:00 2001
From: Rob Bayer 
Date: Wed, 29 Feb 2012 11:26:39 -0800
Subject: [PATCH 07/21] Basic IMAP search working

---
 res/values/arrays.xml                         |  23 ++-
 res/values/strings.xml                        |  17 ++
 res/xml/account_settings_preferences.xml      |  15 +-
 src/com/fsck/k9/Account.java                  |  70 ++++++--
 .../fsck/k9/activity/MessageInfoHolder.java   |   4 +-
 src/com/fsck/k9/activity/MessageList.java     | 134 ++++++++++++---
 .../k9/activity/setup/AccountSettings.java    |  33 +++-
 .../k9/controller/MessagingController.java    |  91 +++++++++-
 src/com/fsck/k9/helper/MessageHelper.java     |   9 +-
 src/com/fsck/k9/mail/Message.java             |  10 ++
 src/com/fsck/k9/mail/Store.java               |   6 +
 .../fsck/k9/mail/internet/MimeMessage.java    |  24 +++
 src/com/fsck/k9/mail/store/ImapStore.java     | 159 +++++++++++++++++-
 13 files changed, 531 insertions(+), 64 deletions(-)

diff --git a/res/values/arrays.xml b/res/values/arrays.xml
index 8608cb3675d..4a42fc04060 100644
--- a/res/values/arrays.xml
+++ b/res/values/arrays.xml
@@ -46,6 +46,7 @@
         1440
     
 
+    
     
         @string/account_setup_options_mail_display_count_10
         @string/account_setup_options_mail_display_count_25
@@ -56,7 +57,7 @@
         @string/account_setup_options_mail_display_count_1000
         @string/account_setup_options_mail_display_count_all
     
-
+    
     
         10
         25
@@ -662,5 +663,25 @@
         HTML
         AUTO
     
+    
+        @string/account_settings_remote_search_num_results_entries_10
+        @string/account_settings_remote_search_num_results_entries_25
+        @string/account_settings_remote_search_num_results_entries_50
+        @string/account_settings_remote_search_num_results_entries_100
+        @string/account_settings_remote_search_num_results_entries_250
+        @string/account_settings_remote_search_num_results_entries_500
+        @string/account_settings_remote_search_num_results_entries_1000
+        @string/account_settings_remote_search_num_results_entries_all
+    
+    
+        10
+        25
+        50
+        100
+        250
+        500
+        1000
+        0
+    
 
 
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 51ea0c50fbe..96fbf7b3582 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1131,4 +1131,21 @@ Welcome to K-9 Mail setup.  K-9 is an open source mail client for Android origin
 the import operation. Please install a file manager application from Android Market
     Open Market
     Close
+    Allow Remote Search
+    Enable Remote Searching for this account
+    All
+    10
+    25
+    50
+    100
+    250
+    500
+    1000
+    Results Limit
+    All Local Folders
+    Remote Folder
+    Search Location
+    Remote Folder Searching
+    Can be slow
+    Include Body Text
 
diff --git a/res/xml/account_settings_preferences.xml b/res/xml/account_settings_preferences.xml
index 9fa5a11a6cd..8b880db1ef6 100644
--- a/res/xml/account_settings_preferences.xml
+++ b/res/xml/account_settings_preferences.xml
@@ -20,7 +20,7 @@
   the preferences. See com.fsck.k9.preferences.Storage.
 -->
 
-
+
 
     
-
     
 
     
 
+    
+        
+        
+        
+        
+        
+        
+    
+    
+    
+    
     
@@ -465,5 +475,6 @@
             android:dependency="crypto_app"/>
 
     
+    
 
 
diff --git a/src/com/fsck/k9/Account.java b/src/com/fsck/k9/Account.java
index c04e89c06bb..5e84bf5aaaf 100644
--- a/src/com/fsck/k9/Account.java
+++ b/src/com/fsck/k9/Account.java
@@ -1,6 +1,18 @@
 
 package com.fsck.k9;
 
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.Collections;
+import java.util.Date;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+import java.util.UUID;
+import java.util.concurrent.ConcurrentHashMap;
+
 import android.content.Context;
 import android.content.SharedPreferences;
 import android.net.ConnectivityManager;
@@ -18,19 +30,6 @@
 import com.fsck.k9.mail.store.StorageManager.StorageProvider;
 import com.fsck.k9.view.ColorChip;
 
-import java.lang.reflect.Array;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Calendar;
-import java.util.Collections;
-import java.util.Date;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Random;
-import java.util.UUID;
-import java.util.concurrent.ConcurrentHashMap;
-
 /**
  * Account stores all of the settings for a single account defined by the user. It is able to save
  * and delete itself given a Preferences to work with. Each account is defined by a UUID.
@@ -68,6 +67,7 @@ public class Account implements BaseAccount {
     public static final boolean DEFAULT_QUOTED_TEXT_SHOWN = true;
     public static final boolean DEFAULT_REPLY_AFTER_QUOTE = false;
     public static final boolean DEFAULT_STRIP_SIGNATURE = true;
+    public static final int DEFAULT_REMOTE_SEARCH_NUM_RESULTS = 25;
 
     public static final String ACCOUNT_DESCRIPTION_KEY = "description";
     public static final String STORE_URI_KEY = "storeUri";
@@ -149,7 +149,10 @@ public class Account implements BaseAccount {
     private String mCryptoApp;
     private boolean mCryptoAutoSignature;
     private boolean mCryptoAutoEncrypt;
-
+    private boolean mAllowRemoteSearch;
+    private boolean mRemoteSearchFullText;
+    private int mRemoteSearchNumResults;
+    
     private CryptoProvider mCryptoProvider = null;
 
     /**
@@ -235,6 +238,9 @@ protected Account(Context context) {
         mCryptoApp = Apg.NAME;
         mCryptoAutoSignature = false;
         mCryptoAutoEncrypt = false;
+        mAllowRemoteSearch = false;
+        mRemoteSearchFullText = false;
+        mRemoteSearchNumResults = DEFAULT_REMOTE_SEARCH_NUM_RESULTS;
         mEnabled = true;
 
         searchableFolders = Searchable.ALL;
@@ -390,6 +396,10 @@ private synchronized void loadAccount(Preferences preferences) {
         mCryptoApp = prefs.getString(mUuid + ".cryptoApp", Apg.NAME);
         mCryptoAutoSignature = prefs.getBoolean(mUuid + ".cryptoAutoSignature", false);
         mCryptoAutoEncrypt = prefs.getBoolean(mUuid + ".cryptoAutoEncrypt", false);
+        mAllowRemoteSearch = prefs.getBoolean(mUuid + ".allowRemoteSearch", false);
+        mRemoteSearchFullText = prefs.getBoolean(mUuid + ".remoteSearchFullText", false);
+        mRemoteSearchNumResults = prefs.getInt(mUuid + ".remoteSearchNumResults", DEFAULT_REMOTE_SEARCH_NUM_RESULTS);
+        
         mEnabled = prefs.getBoolean(mUuid + ".enabled", true);
     }
 
@@ -631,6 +641,9 @@ public synchronized void save(Preferences preferences) {
         editor.putString(mUuid + ".cryptoApp", mCryptoApp);
         editor.putBoolean(mUuid + ".cryptoAutoSignature", mCryptoAutoSignature);
         editor.putBoolean(mUuid + ".cryptoAutoEncrypt", mCryptoAutoEncrypt);
+        editor.putBoolean(mUuid + ".allowRemoteSearch", mAllowRemoteSearch);
+        editor.putBoolean(mUuid + ".remoteSearchFullText", mRemoteSearchFullText);
+        editor.putInt(mUuid + ".remoteSearchNumResults", mRemoteSearchNumResults);
         editor.putBoolean(mUuid + ".enabled", mEnabled);
 
         editor.putBoolean(mUuid + ".vibrate", mNotificationSetting.shouldVibrate());
@@ -1445,7 +1458,23 @@ public boolean isCryptoAutoEncrypt() {
     public void setCryptoAutoEncrypt(boolean cryptoAutoEncrypt) {
         mCryptoAutoEncrypt = cryptoAutoEncrypt;
     }
-
+    
+	public boolean allowRemoteSearch() {
+		return mAllowRemoteSearch;
+	}
+	
+	public void setAllowRemoteSearch(boolean val){
+		mAllowRemoteSearch = val;
+	}
+
+	public int getRemoteSearchNumResults(){
+		return mRemoteSearchNumResults;
+	}
+	
+	public void setRemoteSearchNumResults(int val){
+		mRemoteSearchNumResults = (val >= 0 ? val : 0);
+	}
+	
     public String getInboxFolderName() {
         return mInboxFolderName;
     }
@@ -1500,4 +1529,15 @@ public synchronized boolean isEnabled() {
     public synchronized void setEnabled(boolean enabled) {
         mEnabled = enabled;
     }
+
+	public boolean getRemoteSearchFullText() {
+		
+		return mRemoteSearchFullText;
+	}
+
+	public void setRemoteSearchFullText(boolean val) {
+		mRemoteSearchFullText = val;
+	}
+
+
 }
diff --git a/src/com/fsck/k9/activity/MessageInfoHolder.java b/src/com/fsck/k9/activity/MessageInfoHolder.java
index e19fb953acc..163184de65c 100644
--- a/src/com/fsck/k9/activity/MessageInfoHolder.java
+++ b/src/com/fsck/k9/activity/MessageInfoHolder.java
@@ -2,7 +2,7 @@
 
 import java.util.Date;
 import com.fsck.k9.helper.MessageHelper;
-import com.fsck.k9.mail.store.LocalStore.LocalMessage;
+import com.fsck.k9.mail.Message;
 
 public class MessageInfoHolder {
     public String date;
@@ -19,7 +19,7 @@ public class MessageInfoHolder {
     public boolean downloaded;
     public boolean partially_downloaded;
     public boolean dirty;
-    public LocalMessage message;
+    public Message message;
     public FolderInfoHolder folder;
     public boolean selected;
     public String account;
diff --git a/src/com/fsck/k9/activity/MessageList.java b/src/com/fsck/k9/activity/MessageList.java
index 867fb53fe15..36ea428f9b5 100644
--- a/src/com/fsck/k9/activity/MessageList.java
+++ b/src/com/fsck/k9/activity/MessageList.java
@@ -10,7 +10,9 @@
 
 import android.app.AlertDialog;
 import android.app.Dialog;
+import android.app.SearchManager;
 import android.content.Context;
+import android.content.DialogInterface;
 import android.content.Intent;
 import android.graphics.Color;
 import android.graphics.Typeface;
@@ -52,12 +54,10 @@
 
 import com.fsck.k9.Account;
 import com.fsck.k9.AccountStats;
-import com.fsck.k9.BaseAccount;
 import com.fsck.k9.FontSizes;
 import com.fsck.k9.K9;
 import com.fsck.k9.Preferences;
 import com.fsck.k9.R;
-import com.fsck.k9.SearchAccount;
 import com.fsck.k9.SearchSpecification;
 import com.fsck.k9.activity.setup.AccountSettings;
 import com.fsck.k9.activity.setup.FolderSettings;
@@ -72,7 +72,6 @@
 import com.fsck.k9.mail.Message;
 import com.fsck.k9.mail.store.LocalStore;
 import com.fsck.k9.mail.store.LocalStore.LocalFolder;
-import com.fsck.k9.mail.store.LocalStore.LocalMessage;
 import com.fsck.k9.mail.store.StorageManager;
 
 
@@ -171,7 +170,13 @@ public static class SenderComparator implements Comparator {
 
         @Override
         public int compare(MessageInfoHolder object1, MessageInfoHolder object2) {
-            return object1.compareCounterparty.toLowerCase().compareTo(object2.compareCounterparty.toLowerCase());
+        	if(object1.compareCounterparty == null){
+        		return (object2.compareCounterparty == null ? 0 : 1);
+        	}else if (object2.compareCounterparty == null){
+        		return -1;
+        	}else{
+        		return object1.compareCounterparty.toLowerCase().compareTo(object2.compareCounterparty.toLowerCase());
+        	}
         }
 
     }
@@ -180,7 +185,13 @@ public static class DateComparator implements Comparator {
 
         @Override
         public int compare(MessageInfoHolder object1, MessageInfoHolder object2) {
-            return object1.compareDate.compareTo(object2.compareDate);
+        	if(object1.compareDate == null){
+        		return (object2.compareDate == null ? 0 : 1);
+        	}else if(object2.compareDate == null){
+        		return -1;
+        	}else{
+        		return object1.compareDate.compareTo(object2.compareDate);
+        	}
         }
 
     }
@@ -213,7 +224,9 @@ public int compare(MessageInfoHolder arg0, MessageInfoHolder arg1) {
 
     private static final String EXTRA_ACCOUNT = "account";
     private static final String EXTRA_FOLDER  = "folder";
-    private static final String EXTRA_QUERY = "query";
+    private static final String EXTRA_REMOTE_SEARCH = "com.fsck.k9.remote_search";
+    private static final String EXTRA_SEARCH_ACCOUNT = "com.fsck.k9.search_account";
+    private static final String EXTRA_SEARCH_FOLDER = "com.fsck.k9.search_folder";
     private static final String EXTRA_QUERY_FLAGS = "queryFlags";
     private static final String EXTRA_FORBIDDEN_FLAGS = "forbiddenFlags";
     private static final String EXTRA_INTEGRATE = "integrate";
@@ -227,7 +240,6 @@ public int compare(MessageInfoHolder arg0, MessageInfoHolder arg1) {
      * Maps a {@link SORT_TYPE} to a {@link Comparator} implementation.
      */
     private static final Map> SORT_COMPARATORS;
-
     static {
         // fill the mapping at class time loading
 
@@ -243,6 +255,7 @@ public int compare(MessageInfoHolder arg0, MessageInfoHolder arg1) {
         SORT_COMPARATORS = Collections.unmodifiableMap(map);
     }
 
+    
     private ListView mListView;
 
     private boolean mTouchView = true;
@@ -275,6 +288,9 @@ public int compare(MessageInfoHolder arg0, MessageInfoHolder arg1) {
     private String mQueryString;
     private Flag[] mQueryFlags = null;
     private Flag[] mForbiddenFlags = null;
+    private boolean mRemoteSearch = false;
+    private String mSearchAccount = null;
+    private String mSearchFolder = null;
     private boolean mIntegrate = false;
     private String[] mAccountUuids = null;
     private String[] mFolderNames = null;
@@ -395,7 +411,7 @@ public void run() {
                         }
                     }
 
-                    if (wasEmpty) {
+                    if (wasEmpty & !mAdapter.messages.isEmpty()) {
                         mListView.setSelection(0);
                     }
                     resetUnreadCountOnThread();
@@ -470,10 +486,7 @@ protected Comparator getComparator() {
                 }
             }
 
-            // build the comparator chain
-            final Comparator chainComparator = new ComparatorChain(chain);
-
-            return chainComparator;
+            return new ComparatorChain(chain);
         }
 
         public void folderLoading(String folder, boolean loading) {
@@ -539,6 +552,7 @@ private void setWindowTitle() {
                     setTitle(getString(R.string.search_results) + ": " + mQueryString);
                 }
             }
+            //TODO: Update for ImapSearch
         }
 
         public void progress(final boolean progress) {
@@ -601,7 +615,7 @@ public static Intent actionHandleFolderIntent(Context context, Account account,
 
     public static void actionHandle(Context context, String title, String queryString, boolean integrate, Flag[] flags, Flag[] forbiddenFlags) {
         Intent intent = new Intent(context, MessageList.class);
-        intent.putExtra(EXTRA_QUERY, queryString);
+        intent.putExtra(SearchManager.QUERY, queryString);
         if (flags != null) {
             intent.putExtra(EXTRA_QUERY_FLAGS, Utility.combine(flags, ','));
         }
@@ -622,7 +636,7 @@ public static void actionHandle(Context context, String title, String queryStrin
     public static Intent actionHandleAccountIntent(Context context, String title,
             SearchSpecification searchSpecification) {
         Intent intent = new Intent(context, MessageList.class);
-        intent.putExtra(EXTRA_QUERY, searchSpecification.getQuery());
+        intent.putExtra(SearchManager.QUERY, searchSpecification.getQuery());
         if (searchSpecification.getRequiredFlags() != null) {
             intent.putExtra(EXTRA_QUERY_FLAGS, Utility.combine(searchSpecification.getRequiredFlags(), ','));
         }
@@ -697,7 +711,32 @@ private void initializeMessageList(Intent intent, boolean create) {
             return;
         }
 
+        
+        mQueryString = intent.getStringExtra(SearchManager.QUERY);
+        mFolderName = null;
+        mRemoteSearch = false;
+        mSearchAccount = null;
+        mSearchFolder = null;
+        if(mQueryString != null){
+            if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
+                //Query was received from Search Dialog
+                Bundle appData = getIntent().getBundleExtra(SearchManager.APP_DATA);
+                if(appData != null){
+                    mSearchAccount = appData.getString(EXTRA_SEARCH_ACCOUNT);
+                    mSearchFolder = appData.getString(EXTRA_SEARCH_FOLDER);
+                    mRemoteSearch = appData.getBoolean(EXTRA_REMOTE_SEARCH);
+                }
+            }
+            else{
+                mSearchAccount = intent.getStringExtra(EXTRA_SEARCH_ACCOUNT);
+                mSearchFolder = intent.getStringExtra(EXTRA_SEARCH_FOLDER);
+                
+            }
+        }
+
         String accountUuid = intent.getStringExtra(EXTRA_ACCOUNT);
+        mFolderName = intent.getStringExtra(EXTRA_FOLDER);
+        
         mAccount = Preferences.getPreferences(this).getAccount(accountUuid);
 
         if (mAccount != null && !mAccount.isAvailable(this)) {
@@ -706,8 +745,8 @@ private void initializeMessageList(Intent intent, boolean create) {
             return;
         }
 
-        mFolderName = intent.getStringExtra(EXTRA_FOLDER);
-        mQueryString = intent.getStringExtra(EXTRA_QUERY);
+
+
 
         String queryFlags = intent.getStringExtra(EXTRA_QUERY_FLAGS);
         if (queryFlags != null) {
@@ -815,6 +854,7 @@ public void onResume() {
 
         mController.addListener(mAdapter.mListener);
 
+        //Cancel pending new mail notifications when we open an account
         Account[] accountsWithNotification;
         if (mAccount != null) {
             accountsWithNotification = new Account[] { mAccount };
@@ -822,18 +862,21 @@ public void onResume() {
             Preferences preferences = Preferences.getPreferences(this);
             accountsWithNotification = preferences.getAccounts();
         }
-
         for (Account accountWithNotification : accountsWithNotification) {
             mController.notifyAccountCancel(this, accountWithNotification);
         }
 
+        
         if (mAdapter.messages.isEmpty()) {
-            if (mFolderName != null) {
+        	if (mRemoteSearch){
+        		//TODO: Support flag based search
+        		mController.searchRemoteMessages(mSearchAccount, mSearchFolder, mQueryString, null, null, mAdapter.mListener);
+        	}
+        	else if (mFolderName != null) {
                 mController.listLocalMessages(mAccount, mFolderName,  mAdapter.mListener);
             } else if (mQueryString != null) {
                 mController.searchLocalMessages(mAccountUuids, mFolderNames, null, mQueryString, mIntegrate, mQueryFlags, mForbiddenFlags, mAdapter.mListener);
             }
-
         } else {
             // reread the selected date format preference in case it has changed
             mMessageHelper.refresh();
@@ -843,7 +886,9 @@ public void onResume() {
                 public void run() {
                     mAdapter.markAllMessagesAsDirty();
 
-                    if (mFolderName != null) {
+                    if (mRemoteSearch){
+                		mController.searchRemoteMessagesSynchronous(mSearchAccount, mSearchFolder, mQueryString, null, null, mAdapter.mListener);
+                	} else if (mFolderName != null) {
                         mController.listLocalMessagesSynchronous(mAccount, mFolderName,  mAdapter.mListener);
                     } else if (mQueryString != null) {
                         mController.searchLocalMessagesSynchronous(mAccountUuids, mFolderNames, null, mQueryString, mIntegrate, mQueryFlags, mForbiddenFlags, mAdapter.mListener);
@@ -1037,6 +1082,7 @@ public boolean onKeyDown(int keyCode, KeyEvent event) {
         }
         }
 
+        //Shortcuts that only work when a message is selected
         boolean retval = true;
         int position = mListView.getSelectedItemPosition();
         try {
@@ -1178,6 +1224,44 @@ private void onEditPrefs() {
     private void onEditAccount() {
         AccountSettings.actionSettings(this, mAccount);
     }
+    
+    
+    @Override
+    public boolean onSearchRequested() {
+         
+         if(mAccount != null && mCurrentFolder != null && mAccount.allowRemoteSearch()){
+        	 //if in a SSSable folder, ask user what they want.
+        	 //TODO: Add ability to remember selection?
+        	 final CharSequence[] items = new CharSequence[2];
+        	 items[0] = getString(R.string.search_mode_local_all);
+        	 items[1] = getString(R.string.search_mode_remote);
+
+        	 AlertDialog.Builder builder = new AlertDialog.Builder(this);
+        	 builder.setTitle(getString(R.string.search_mode_title));
+        	 builder.setItems(items, new DialogInterface.OnClickListener() {
+        	     public void onClick(DialogInterface dialog, int item) {
+        	    	 
+        	         Bundle appData = null;
+        	         if(item == 1){
+        	        	 appData = new Bundle();
+        	        	 appData.putString(EXTRA_SEARCH_ACCOUNT, mAccount.getUuid());
+                    	 appData.putString(EXTRA_SEARCH_FOLDER, mCurrentFolder.name);
+                    	 appData.putBoolean(EXTRA_REMOTE_SEARCH, true);
+        	         }
+        	         //else do regular search, which doesn't require any special parameter setup
+                	 
+                	 startSearch(null, false, appData, false);
+        	     }
+        	 });
+        	 AlertDialog alert = builder.create();
+        	 alert.show();
+        	 
+        	 return true;
+         }
+         
+         startSearch(null, false, null, false);
+         return true;
+     }
 
     private void changeSort(SORT_TYPE newSortType) {
         if (sortType == newSortType) {
@@ -1398,7 +1482,7 @@ public void onPrepareDialog(final int id, final Dialog dialog) {
     }
 
     private void onToggleRead(MessageInfoHolder holder) {
-        LocalMessage message = holder.message;
+        Message message = holder.message;
         Folder folder = message.getFolder();
         Account account = folder.getAccount();
         String folderName = folder.getName();
@@ -1408,7 +1492,7 @@ private void onToggleRead(MessageInfoHolder holder) {
     }
 
     private void onToggleFlag(MessageInfoHolder holder) {
-        LocalMessage message = holder.message;
+        Message message = holder.message;
         Folder folder = message.getFolder();
         Account account = folder.getAccount();
         String folderName = folder.getName();
@@ -1583,7 +1667,7 @@ public boolean onPrepareOptionsMenu(Menu menu) {
 
         setOpsState(menu, true, anySelected);
 
-        if (mQueryString != null) {
+        if (mQueryString != null || mIntegrate) {
             menu.findItem(R.id.mark_all_as_read).setVisible(false);
             menu.findItem(R.id.list_folders).setVisible(false);
             menu.findItem(R.id.expunge).setVisible(false);
@@ -1975,9 +2059,7 @@ public void markAllMessagesAsDirty() {
         }
         public void pruneDirtyMessages() {
             synchronized (mAdapter.messages) {
-                Iterator iter = mAdapter.messages.iterator();
-                while (iter.hasNext()) {
-                    MessageInfoHolder holder = iter.next();
+                for(MessageInfoHolder holder : mAdapter.messages){
                     if (holder.dirty) {
                         if (holder.selected) {
                             mSelectedCount--;
diff --git a/src/com/fsck/k9/activity/setup/AccountSettings.java b/src/com/fsck/k9/activity/setup/AccountSettings.java
index a7fae42e583..18698e0e9ab 100644
--- a/src/com/fsck/k9/activity/setup/AccountSettings.java
+++ b/src/com/fsck/k9/activity/setup/AccountSettings.java
@@ -46,7 +46,8 @@ public class AccountSettings extends K9PreferenceActivity {
     private static final String PREFERENCE_SCREEN_COMPOSING = "composing";
     private static final String PREFERENCE_SCREEN_INCOMING = "incoming_prefs";
     private static final String PREFERENCE_SCREEN_PUSH_ADVANCED = "push_advanced";
-
+    private static final String PREFERENCE_SCREEN_REMOTE_SEARCH = "remote_search";
+    
     private static final String PREFERENCE_DESCRIPTION = "account_description";
     private static final String PREFERENCE_COMPOSITION = "composition";
     private static final String PREFERENCE_MANAGE_IDENTITIES = "manage_identities";
@@ -94,6 +95,9 @@ public class AccountSettings extends K9PreferenceActivity {
     private static final String PREFERENCE_CRYPTO_APP = "crypto_app";
     private static final String PREFERENCE_CRYPTO_AUTO_SIGNATURE = "crypto_auto_signature";
     private static final String PREFERENCE_CRYPTO_AUTO_ENCRYPT = "crypto_auto_encrypt";
+    private static final String PREFERENCE_ALLOW_REMOTE_SEARCH = "account_allow_remote_search";
+    private static final String PREFERENCE_REMOTE_SEARCH_NUM_RESULTS = "account_remote_search_num_results";
+    private static final String PREFERENCE_REMOTE_SEARCH_FULL_TEXT = "account_remote_search_full_text";
 
     private static final String PREFERENCE_LOCAL_STORAGE_PROVIDER = "local_storage_provider";
 
@@ -157,6 +161,9 @@ public class AccountSettings extends K9PreferenceActivity {
     private ListPreference mCryptoApp;
     private CheckBoxPreference mCryptoAutoSignature;
     private CheckBoxPreference mCryptoAutoEncrypt;
+    private CheckBoxPreference mAllowRemoteSearch;
+    private ListPreference mRemoteSearchNumResults;
+    private CheckBoxPreference mRemoteSearchFullText;
 
     private ListPreference mLocalStorageProvider;
 
@@ -423,6 +430,7 @@ public boolean onPreferenceChange(Preference preference, Object newValue) {
         mAccountDefault.setChecked(
             mAccount.equals(Preferences.getPreferences(this).getDefaultAccount()));
 
+        
         mAccountEnableMoveButtons = (CheckBoxPreference) findPreference(PREFERENCE_ENABLE_MOVE_BUTTONS);
         mAccountEnableMoveButtons.setEnabled(mIsMoveCapable);
         mAccountEnableMoveButtons.setChecked(mAccount.getEnableMoveButtons());
@@ -465,14 +473,22 @@ public boolean onPreferenceChange(Preference preference, Object newValue) {
                 }
             });
         }
+        
+        
         // IMAP-specific preferences
-
+        mAllowRemoteSearch = (CheckBoxPreference) findPreference(PREFERENCE_ALLOW_REMOTE_SEARCH);
+        mRemoteSearchNumResults = (ListPreference) findPreference(PREFERENCE_REMOTE_SEARCH_NUM_RESULTS);
+        mRemoteSearchFullText = (CheckBoxPreference) findPreference(PREFERENCE_REMOTE_SEARCH_FULL_TEXT);
         mPushPollOnConnect = (CheckBoxPreference) findPreference(PREFERENCE_PUSH_POLL_ON_CONNECT);
         mIdleRefreshPeriod = (ListPreference) findPreference(PREFERENCE_IDLE_REFRESH_PERIOD);
         mMaxPushFolders = (ListPreference) findPreference(PREFERENCE_MAX_PUSH_FOLDERS);
         if (mIsPushCapable) {
             mPushPollOnConnect.setChecked(mAccount.isPushPollOnConnect());
 
+            mAllowRemoteSearch.setChecked(mAccount.allowRemoteSearch());
+            mRemoteSearchNumResults.setValue(Integer.toString(mAccount.getRemoteSearchNumResults()));
+            mRemoteSearchFullText.setChecked(mAccount.getRemoteSearchFullText());
+            
             mIdleRefreshPeriod.setValue(String.valueOf(mAccount.getIdleRefreshMinutes()));
             mIdleRefreshPeriod.setSummary(mIdleRefreshPeriod.getEntry());
             mIdleRefreshPeriod.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
@@ -484,7 +500,7 @@ public boolean onPreferenceChange(Preference preference, Object newValue) {
                     return false;
                 }
             });
-
+ 
             mMaxPushFolders.setValue(String.valueOf(mAccount.getMaxPushFolders()));
             mMaxPushFolders.setSummary(mMaxPushFolders.getEntry());
             mMaxPushFolders.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
@@ -509,9 +525,12 @@ public boolean onPreferenceChange(Preference preference, Object newValue) {
                 }
             });
         } else {
-            PreferenceScreen incomingPrefs = (PreferenceScreen) findPreference(PREFERENCE_SCREEN_INCOMING);
+            final PreferenceScreen incomingPrefs = (PreferenceScreen) findPreference(PREFERENCE_SCREEN_INCOMING);
             incomingPrefs.removePreference( (PreferenceScreen) findPreference(PREFERENCE_SCREEN_PUSH_ADVANCED));
             incomingPrefs.removePreference( (ListPreference) findPreference(PREFERENCE_PUSH_MODE));
+            
+            ((PreferenceScreen) findPreference("main")).removePreference((PreferenceScreen) findPreference(PREFERENCE_SCREEN_REMOTE_SEARCH));
+            
         }
 
         mAccountNotify = (CheckBoxPreference) findPreference(PREFERENCE_NOTIFY);
@@ -719,11 +738,14 @@ private void saveSettings() {
         mAccount.setSpamFolderName(mSpamFolder.getValue());
         mAccount.setTrashFolderName(mTrashFolder.getValue());
 
-
+        //IMAP stuff
         if (mIsPushCapable) {
             mAccount.setPushPollOnConnect(mPushPollOnConnect.isChecked());
             mAccount.setIdleRefreshMinutes(Integer.parseInt(mIdleRefreshPeriod.getValue()));
             mAccount.setMaxPushFolders(Integer.parseInt(mMaxPushFolders.getValue()));
+            mAccount.setAllowRemoteSearch(mAllowRemoteSearch.isChecked());
+            mAccount.setRemoteSearchNumResults(Integer.parseInt(mRemoteSearchNumResults.getValue()));
+            mAccount.setRemoteSearchFullText(mRemoteSearchFullText.isChecked());
         }
 
         if (!mIsMoveCapable) {
@@ -750,6 +772,7 @@ private void saveSettings() {
 
         mAccount.setShowPictures(Account.ShowPictures.valueOf(mAccountShowPictures.getValue()));
 
+        //IMAP specific stuff
         if (mIsPushCapable) {
             boolean needsPushRestart = mAccount.setFolderPushMode(Account.FolderMode.valueOf(mPushMode.getValue()));
             if (mAccount.getFolderPushMode() != FolderMode.NONE) {
diff --git a/src/com/fsck/k9/controller/MessagingController.java b/src/com/fsck/k9/controller/MessagingController.java
index 1b2b47a6bec..e273c71fa91 100644
--- a/src/com/fsck/k9/controller/MessagingController.java
+++ b/src/com/fsck/k9/controller/MessagingController.java
@@ -3,7 +3,18 @@
 
 import java.io.CharArrayWriter;
 import java.io.PrintWriter;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
 import java.util.concurrent.BlockingQueue;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.CopyOnWriteArraySet;
@@ -784,6 +795,84 @@ public void messagesFinished(int number) {
             listener.searchStats(stats);
         }
     }
+
+
+
+    public void searchRemoteMessages(final String acctUuid, final String folderName, final String query, final Flag[] requiredFlags, final Flag[] forbiddenFlags, final MessagingListener listener){
+        if (K9.DEBUG) {
+            String msg = "searchRemoteMessages ("
+                    + "acct=" + acctUuid
+                    + ", folderName = " + folderName
+                    + ", query = " + query
+                    + ")";
+            Log.i(K9.LOG_TAG, msg);
+        }
+
+        threadPool.execute(new Runnable() {
+            @Override
+            public void run() {
+                searchRemoteMessagesSynchronous(acctUuid, folderName, query, requiredFlags, forbiddenFlags, listener);
+            }
+        });
+    }
+    public void searchRemoteMessagesSynchronous(final String acctUuid, final String folderName, final String query, 
+            final Flag[] requiredFlags, final Flag[] forbiddenFlags, final MessagingListener listener){
+        final Account acct = Preferences.getPreferences(mApplication.getApplicationContext()).getAccount(acctUuid);
+        final AccountStats stats = new AccountStats();
+
+        if (listener != null) {
+            listener.listLocalMessagesStarted(acct, null);
+        }
+
+        MessageRetrievalListener retrievalListener = new MessageRetrievalListener() {
+            @Override
+            public void messageStarted(String message, int number, int ofTotal) {}
+            @Override
+            public void messageFinished(Message message, int number, int ofTotal) {
+                if (!isMessageSuppressed(message.getFolder().getAccount(), message.getFolder().getName(), message)) {
+                    List messages = new ArrayList();
+
+                    messages.add(message);
+                    stats.unreadMessageCount += (!message.isSet(Flag.SEEN)) ? 1 : 0;
+                    stats.flaggedMessageCount += (message.isSet(Flag.FLAGGED)) ? 1 : 0;
+                    if (listener != null) {
+                        listener.listLocalMessagesAddMessages(acct, null, messages);
+
+                    }
+                }
+
+            }
+            @Override
+            public void messagesFinished(int number) {
+
+            }
+        };
+
+        try {
+            String[] queryFields = {"html_content", "subject", "sender_list"};
+            Store acctStore = acct.getRemoteStore();
+
+            //TODO: make queryFields actually do something
+            acctStore.searchRemoteMessages(retrievalListener, queryFields, query, folderName, requiredFlags, forbiddenFlags);
+
+        } catch (Exception e) {
+            if (listener != null) {
+                listener.listLocalMessagesFailed(acct, null, e.getMessage());
+            }
+            addErrorMessage(acct, null, e);
+        } finally {
+            if (listener != null) {
+                listener.listLocalMessagesFinished(acct, null);
+            }
+        }
+
+        if (listener != null) {
+            listener.searchStats(stats);
+        }
+
+    }
+
+
     public void loadMoreMessages(Account account, String folder, MessagingListener listener) {
         try {
             LocalStore localStore = account.getLocalStore();
diff --git a/src/com/fsck/k9/helper/MessageHelper.java b/src/com/fsck/k9/helper/MessageHelper.java
index 43b208a775c..a2831410373 100644
--- a/src/com/fsck/k9/helper/MessageHelper.java
+++ b/src/com/fsck/k9/helper/MessageHelper.java
@@ -17,7 +17,6 @@
 import com.fsck.k9.mail.Message;
 import com.fsck.k9.mail.MessagingException;
 import com.fsck.k9.mail.Message.RecipientType;
-import com.fsck.k9.mail.store.LocalStore.LocalMessage;
 import com.fsck.k9.helper.DateFormatter;
 
 public class MessageHelper {
@@ -43,11 +42,10 @@ private MessageHelper(final Context context) {
         mTodayDateFormat = android.text.format.DateFormat.getTimeFormat(mContext);
     }
 
-    public void populate(final MessageInfoHolder target, final Message m,
+    public void populate(final MessageInfoHolder target, final Message message,
                          final FolderInfoHolder folder, final Account account) {
         final Contacts contactHelper = K9.showContactName() ? Contacts.getInstance(mContext) : null;
         try {
-            LocalMessage message = (LocalMessage) m;
             target.message = message;
             target.compareDate = message.getSentDate();
             if (target.compareDate == null) {
@@ -86,13 +84,16 @@ public void populate(final MessageInfoHolder target, final Message m,
             target.uid = message.getUid();
 
             target.account = account.getDescription();
-            target.uri = "email://messages/" + account.getAccountNumber() + "/" + m.getFolder().getName() + "/" + m.getUid();
+            target.uri = "email://messages/" + account.getAccountNumber() + "/" + message.getFolder().getName() + "/" + message.getUid();
 
         } catch (MessagingException me) {
             Log.w(K9.LOG_TAG, "Unable to load message info", me);
         }
     }
     public String formatDate(Date date) {
+    	if (date==null){
+    		return "";
+    	}
         if (Utility.isDateToday(date)) {
             return mTodayDateFormat.format(date);
         } else {
diff --git a/src/com/fsck/k9/mail/Message.java b/src/com/fsck/k9/mail/Message.java
index 2a7cd5efd06..e25307bc4b8 100644
--- a/src/com/fsck/k9/mail/Message.java
+++ b/src/com/fsck/k9/mail/Message.java
@@ -144,6 +144,16 @@ public boolean isMimeType(String mimeType) throws MessagingException {
         return getContentType().startsWith(mimeType);
     }
 
+    public abstract boolean toMe();
+    public abstract boolean ccMe();
+    public abstract boolean bccMe();
+    public abstract long getId();
+    
+    public abstract String getPreview();
+    public abstract boolean hasAttachments();
+    
+    
+    
     public void delete(String trashFolderName) throws MessagingException {}
 
     /*
diff --git a/src/com/fsck/k9/mail/Store.java b/src/com/fsck/k9/mail/Store.java
index 5013a8f298f..28ff45924ca 100644
--- a/src/com/fsck/k9/mail/Store.java
+++ b/src/com/fsck/k9/mail/Store.java
@@ -5,6 +5,7 @@
 import android.content.Context;
 
 import com.fsck.k9.Account;
+import com.fsck.k9.controller.MessageRetrievalListener;
 import com.fsck.k9.mail.store.ImapStore;
 import com.fsck.k9.mail.store.LocalStore;
 import com.fsck.k9.mail.store.Pop3Store;
@@ -176,4 +177,9 @@ public Pusher getPusher(PushReceiver receiver) {
     public Account getAccount() {
         return mAccount;
     }
+    
+    public void searchRemoteMessages(MessageRetrievalListener listener, String[] queryFields, String queryString,
+            String folder,  final Flag[] requiredFlags, final Flag[] forbiddenFlags) throws MessagingException{
+    	throw new MessagingException("K-9 does not support remote searchign on this account type");
+    }
 }
diff --git a/src/com/fsck/k9/mail/internet/MimeMessage.java b/src/com/fsck/k9/mail/internet/MimeMessage.java
index 0ac949524a7..05db24d045d 100644
--- a/src/com/fsck/k9/mail/internet/MimeMessage.java
+++ b/src/com/fsck/k9/mail/internet/MimeMessage.java
@@ -587,4 +587,28 @@ public MimeMessage clone() {
         copy(message);
         return message;
     }
+    
+    public boolean toMe(){
+    	return false;
+    }
+    
+    public boolean ccMe(){
+    	return false;
+    }
+    
+    public boolean bccMe(){
+    	return false;
+    }
+    
+    public long getId(){
+    	return Long.parseLong(mUid); //or maybe .mMessageId?
+    }
+    
+    public String getPreview(){
+    	return "my_preview";
+    }
+    
+    public boolean hasAttachments(){
+    	return false;
+    }
 }
diff --git a/src/com/fsck/k9/mail/store/ImapStore.java b/src/com/fsck/k9/mail/store/ImapStore.java
index cc36817064e..72629e2e400 100644
--- a/src/com/fsck/k9/mail/store/ImapStore.java
+++ b/src/com/fsck/k9/mail/store/ImapStore.java
@@ -45,11 +45,15 @@
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
+import java.util.zip.Inflater;
+import java.util.zip.InflaterInputStream;
 
 import javax.net.ssl.SSLContext;
 import javax.net.ssl.SSLException;
 import javax.net.ssl.TrustManager;
 
+import org.apache.commons.io.IOUtils;
+
 import android.content.Context;
 import android.net.ConnectivityManager;
 import android.net.NetworkInfo;
@@ -72,13 +76,14 @@
 import com.fsck.k9.mail.FetchProfile;
 import com.fsck.k9.mail.Flag;
 import com.fsck.k9.mail.Folder;
+import com.fsck.k9.mail.Folder.OpenMode;
 import com.fsck.k9.mail.Message;
 import com.fsck.k9.mail.MessagingException;
 import com.fsck.k9.mail.Part;
 import com.fsck.k9.mail.PushReceiver;
 import com.fsck.k9.mail.Pusher;
-import com.fsck.k9.mail.Store;
 import com.fsck.k9.mail.ServerSettings;
+import com.fsck.k9.mail.Store;
 import com.fsck.k9.mail.filter.EOLConvertingOutputStream;
 import com.fsck.k9.mail.filter.FixedLengthInputStream;
 import com.fsck.k9.mail.filter.PeekableInputStream;
@@ -89,12 +94,10 @@
 import com.fsck.k9.mail.internet.MimeUtility;
 import com.fsck.k9.mail.store.ImapResponseParser.ImapList;
 import com.fsck.k9.mail.store.ImapResponseParser.ImapResponse;
+import com.fsck.k9.mail.store.LocalStore.LocalFolder;
 import com.fsck.k9.mail.transport.imap.ImapSettings;
 import com.jcraft.jzlib.JZlib;
 import com.jcraft.jzlib.ZOutputStream;
-import java.util.zip.Inflater;
-import java.util.zip.InflaterInputStream;
-import org.apache.commons.io.IOUtils;
 
 /**
  * 
@@ -1168,6 +1171,83 @@ private int getRemoteMessageCount(String criteria) throws MessagingException {
 
 
         }
+        
+        public void doRemoteSearch(final String queryString, final Flag[] requiredFlags, final Flag [] forbiddenFlags, final MessageRetrievalListener listener) 
+        		throws MessagingException{
+        	ImapSearcher searcher = new ImapSearcher(){
+        		public List search() throws IOException, MessagingException {
+        			String imapQuery = "SEARCH ";
+        			if(requiredFlags != null){
+	        			for(Flag f : requiredFlags){
+	        				switch(f){
+	        				case DELETED:
+	        					imapQuery += "DELETED ";
+	        					break;
+	        					
+	        				case SEEN:
+	        					imapQuery +=  "SEEN ";
+	        					break;
+	        					
+	        				case ANSWERED:
+	        					imapQuery += "ANSWERED ";
+	        					break;
+	        					
+	        				case FLAGGED:
+	        					imapQuery += "FLAGGED ";
+	        					break;
+	        					
+	        				case DRAFT:
+	        					imapQuery += "DRAFT ";
+	        					break;
+	        					
+	        				case RECENT:
+	        					imapQuery += "RECENT ";
+	        					break;
+	        				}
+	        			}
+        			}
+        			if(forbiddenFlags != null){
+	        			for(Flag f : forbiddenFlags){
+	        				switch(f){
+	        				case DELETED:
+	        					imapQuery += "UNDELETED ";
+	        					break;
+	        					
+	        				case SEEN:
+	        					imapQuery +=  "UNSEEN ";
+	        					break;
+	        					
+	        				case ANSWERED:
+	        					imapQuery += "UNANSWERED ";
+	        					break;
+	        					
+	        				case FLAGGED:
+	        					imapQuery += "UNFLAGGED ";
+	        					break;
+	        					
+	        				case DRAFT:
+	        					imapQuery += "UNDRAFT ";
+	        					break;
+	        					
+	        				case RECENT:
+	        					imapQuery += "UNRECENT ";
+	        					break;
+	        				}
+	        			}
+        			}
+        			String encodedQry = encodeString(queryString);
+        			if(mAccount.getRemoteSearchFullText()){
+        				imapQuery += "TEXT " + encodedQry;
+        			}
+        			else{
+        				imapQuery += "OR SUBJECT " + encodedQry + " FROM " + encodedQry;
+        			}
+        			return executeSimpleCommand(imapQuery);
+        		}
+        	};
+        	
+        	search(searcher, listener, (mAccount != null ? mAccount.getRemoteSearchNumResults() : 0), true);
+        }
 
         @Override
         public int getUnreadMessageCount() throws MessagingException {
@@ -1259,6 +1339,10 @@ public List search() throws IOException, MessagingException {
         }
 
         private Message[] search(ImapSearcher searcher, MessageRetrievalListener listener) throws MessagingException {
+        	return search(searcher, listener, 0, false);
+        }
+        
+        private Message[] search(ImapSearcher searcher, MessageRetrievalListener listener, int limit, boolean getHeaders) throws MessagingException {
 
             checkOpen();
             ArrayList messages = new ArrayList();
@@ -1275,13 +1359,34 @@ private Message[] search(ImapSearcher searcher, MessageRetrievalListener listene
                     }
                 }
 
-                // Sort the uids in numerically ascending order
-                Collections.sort(uids);
-                for (int i = 0, count = uids.size(); i < count; i++) {
+                // Sort the uids in numerically decreasing order 
+                // By doing it in decreasing order, we ensure newest messages are dealt with first
+                // This makes the most sense when a limit is imposed, and also prevents UI from going
+                // crazy adding stuff at the top.
+                Collections.sort(uids, Collections.reverseOrder());
+                
+                FetchProfile fp = new FetchProfile(); 
+                if(getHeaders){
+                	fp.add(FetchProfile.Item.ENVELOPE);
+                	fp.add(FetchProfile.Item.FLAGS);
+                	fp.add(FetchProfile.Item.STRUCTURE);
+                }
+                
+                if(K9.DEBUG){
+                	Log.i("IMAP search", "Search results: " + uids.size() + ", limit: " + limit);
+                }
+                
+                for (int i = 0, count = (limit==0 ? uids.size() : Math.min(uids.size(), limit)); i < count; i++) {
                     if (listener != null) {
                         listener.messageStarted("" + uids.get(i), i, count);
                     }
                     ImapMessage message = new ImapMessage("" + uids.get(i), this);
+
+                    if(getHeaders){
+                    	Message [] msgArray = {message};
+                    	fetch(msgArray, fp, null); //don't pass the listener since we're already updating it
+                    }
+                    
                     messages.add(message);
                     if (listener != null) {
                         listener.messageFinished(message, i, count);
@@ -1290,7 +1395,17 @@ private Message[] search(ImapSearcher searcher, MessageRetrievalListener listene
             } catch (IOException ioe) {
                 throw ioExceptionHandler(mConnection, ioe);
             }
-            return messages.toArray(EMPTY_MESSAGE_ARRAY);
+            
+            Message [] msgArray = messages.toArray(EMPTY_MESSAGE_ARRAY);
+            
+            /*
+             * Doing this here makes it one batch, but the UI spends a long time with (no subject) stuff, etc.
+             * Therefore, at least for now, should fetch headers individually as we fetch the messages.
+             * 
+            if(getHeaders){
+            	fetch(msgArray, fp, listener);
+            }*/
+            return msgArray;
         }
 
 
@@ -3271,5 +3386,33 @@ public Object foundLiteral(ImapResponse response,
             return null;
         }
     }
+	
+    @Override
+	public void searchRemoteMessages(final MessageRetrievalListener listener, final String[] queryFields, final String queryString,
+            final String folderName,  final Flag[] requiredFlags, final Flag[] forbiddenFlags) throws MessagingException{
+		
+		if(!mAccount.allowRemoteSearch()){
+			throw new MessagingException("Your settings do not allow remote searching of this account");
+		}
+		
+		final ImapFolder folder = (ImapFolder) getFolder(folderName);
+		if(folder == null){
+			throw new MessagingException("Invalid folder specified");
+		}
+		
+		try{
+			folder.open(OpenMode.READ_ONLY);
+			folder.checkOpen();
+			
+			folder.doRemoteSearch(queryString, requiredFlags, forbiddenFlags, listener);
+			
+		}
+		catch(Exception e){
+			throw new MessagingException("Error during search: " + e.toString());
+		}
+		
+	}
+    
+    
 
 }

From e902ed313e70c82594af75a6506b46844359eba8 Mon Sep 17 00:00:00 2001
From: Rob Bayer 
Date: Wed, 29 Feb 2012 13:08:44 -0800
Subject: [PATCH 08/21] Dependency for preferences

---
 res/xml/account_settings_preferences.xml | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/res/xml/account_settings_preferences.xml b/res/xml/account_settings_preferences.xml
index 8b880db1ef6..2864cfa0a36 100644
--- a/res/xml/account_settings_preferences.xml
+++ b/res/xml/account_settings_preferences.xml
@@ -439,8 +439,8 @@
 
     
         
-        
-        
+        
+        
         
         
         
@@ -450,7 +450,7 @@
     
     
+        android:key="crypto" android:dependency="account_allow_remote_search">
 
         
Date: Wed, 29 Feb 2012 14:40:27 -0800
Subject: [PATCH 09/21] Simple help info when enabling Remote Search

---
 res/values/strings.xml                        |  5 ++
 .../k9/activity/setup/AccountSettings.java    | 64 ++++++++++++++++---
 2 files changed, 59 insertions(+), 10 deletions(-)

diff --git a/res/values/strings.xml b/res/values/strings.xml
index 96fbf7b3582..8f93ed814db 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1148,4 +1148,9 @@ the import operation. Please install a file manager application from Android Mar
     Remote Folder Searching
     Can be slow
     Include Body Text
+    
+        To perform a remote search, press your device\'s Search button while viewing a folder from this account.
+        \n\nNote: Remote search is NOT available from the Unified Inbox or from a list of folders.
+    
+    Don\'t Show Again
 
diff --git a/src/com/fsck/k9/activity/setup/AccountSettings.java b/src/com/fsck/k9/activity/setup/AccountSettings.java
index 18698e0e9ab..da995689d2d 100644
--- a/src/com/fsck/k9/activity/setup/AccountSettings.java
+++ b/src/com/fsck/k9/activity/setup/AccountSettings.java
@@ -1,19 +1,30 @@
 
 package com.fsck.k9.activity.setup;
 
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import android.app.AlertDialog;
 import android.content.Context;
+import android.content.DialogInterface;
 import android.content.Intent;
 import android.content.SharedPreferences;
+import android.content.SharedPreferences.Editor;
 import android.os.AsyncTask;
 import android.os.Bundle;
 import android.os.Vibrator;
-import android.preference.*;
+import android.preference.CheckBoxPreference;
+import android.preference.EditTextPreference;
+import android.preference.ListPreference;
+import android.preference.Preference;
+import android.preference.Preference.OnPreferenceChangeListener;
+import android.preference.PreferenceScreen;
+import android.preference.RingtonePreference;
 import android.util.Log;
-
-import java.util.Iterator;
-import java.util.Map;
-import java.util.LinkedList;
-import java.util.List;
+import android.view.View;
+import android.widget.CheckBox;
 
 import com.fsck.k9.Account;
 import com.fsck.k9.Account.FolderMode;
@@ -22,18 +33,17 @@
 import com.fsck.k9.NotificationSetting;
 import com.fsck.k9.Preferences;
 import com.fsck.k9.R;
-import com.fsck.k9.mail.Folder;
 import com.fsck.k9.activity.ChooseFolder;
 import com.fsck.k9.activity.ChooseIdentity;
 import com.fsck.k9.activity.ColorPickerDialog;
 import com.fsck.k9.activity.K9PreferenceActivity;
 import com.fsck.k9.activity.ManageIdentities;
 import com.fsck.k9.crypto.Apg;
+import com.fsck.k9.mail.Folder;
 import com.fsck.k9.mail.Store;
-import com.fsck.k9.service.MailService;
-
-import com.fsck.k9.mail.store.StorageManager;
 import com.fsck.k9.mail.store.LocalStore.LocalFolder;
+import com.fsck.k9.mail.store.StorageManager;
+import com.fsck.k9.service.MailService;
 
 
 public class AccountSettings extends K9PreferenceActivity {
@@ -477,6 +487,15 @@ public boolean onPreferenceChange(Preference preference, Object newValue) {
         
         // IMAP-specific preferences
         mAllowRemoteSearch = (CheckBoxPreference) findPreference(PREFERENCE_ALLOW_REMOTE_SEARCH);
+        
+        mAllowRemoteSearch.setOnPreferenceChangeListener(new OnPreferenceChangeListener() { 
+                                                            public boolean onPreferenceChange(Preference pref, Object newVal){
+                                                                if((Boolean) newVal){
+                                                                    showRemoteSearchHelp();
+                                                                }
+                                                                return true;
+                                                            }
+                                                         });
         mRemoteSearchNumResults = (ListPreference) findPreference(PREFERENCE_REMOTE_SEARCH_NUM_RESULTS);
         mRemoteSearchFullText = (CheckBoxPreference) findPreference(PREFERENCE_REMOTE_SEARCH_FULL_TEXT);
         mPushPollOnConnect = (CheckBoxPreference) findPreference(PREFERENCE_PUSH_POLL_ON_CONNECT);
@@ -675,6 +694,31 @@ public boolean onPreferenceChange(Preference preference, Object newValue) {
         handleCryptoAppDependencies();
     }
 
+    protected void showRemoteSearchHelp() {
+        final String noShowHelpPref = "account_settings_remote_search_hide_help";
+        final SharedPreferences prefs = getPreferences(MODE_PRIVATE);
+        if(!prefs.getBoolean(noShowHelpPref, false)){
+            AlertDialog.Builder adb = new AlertDialog.Builder(this);
+            final CheckBox noShowAgain = new CheckBox(this);
+            noShowAgain.setChecked(false);
+            noShowAgain.setText(R.string.no_show_again);
+            adb.setView(noShowAgain)
+               .setMessage(getString(R.string.account_settings_allow_remote_search_help))
+               .setCancelable(false)
+               .setPositiveButton(R.string.okay_action, new DialogInterface.OnClickListener() {
+                   public void onClick(DialogInterface dialog, int which) {
+                       if(noShowAgain.isChecked()){
+                           Editor edit = prefs.edit();
+                           edit.putBoolean(noShowHelpPref, true);
+                           edit.commit();
+                       }
+                   }
+               });
+           adb.create().show();
+        }
+        
+    }
+
     private void handleCryptoAppDependencies() {
         if ("".equals(mCryptoApp.getValue())) {
             mCryptoAutoSignature.setEnabled(false);

From 55a9e559e3721ab0b94293fbda4b51eb6b494f4e Mon Sep 17 00:00:00 2001
From: Rob Bayer 
Date: Wed, 29 Feb 2012 16:04:52 -0800
Subject: [PATCH 10/21] UI improvements

---
 .../fsck/k9/activity/ActivityListener.java    |  1 +
 src/com/fsck/k9/activity/MessageList.java     | 21 ++++++++++++++-----
 .../k9/controller/MessagingController.java    | 18 +++++++++-------
 .../fsck/k9/controller/MessagingListener.java |  3 +++
 src/com/fsck/k9/mail/Store.java               | 11 +++++-----
 src/com/fsck/k9/mail/store/ImapStore.java     |  5 +++--
 6 files changed, 40 insertions(+), 19 deletions(-)

diff --git a/src/com/fsck/k9/activity/ActivityListener.java b/src/com/fsck/k9/activity/ActivityListener.java
index 803158fc0c8..06d38eb7a78 100644
--- a/src/com/fsck/k9/activity/ActivityListener.java
+++ b/src/com/fsck/k9/activity/ActivityListener.java
@@ -76,6 +76,7 @@ else if (mSendingAccountDescription != null) {
     public void informUserOfStatus() {
     }
 
+
     @Override
     public void synchronizeMailboxFinished(
         Account account,
diff --git a/src/com/fsck/k9/activity/MessageList.java b/src/com/fsck/k9/activity/MessageList.java
index 36ea428f9b5..5e51305300c 100644
--- a/src/com/fsck/k9/activity/MessageList.java
+++ b/src/com/fsck/k9/activity/MessageList.java
@@ -1905,6 +1905,21 @@ class MessageListAdapter extends BaseAdapter {
 
         private final ActivityListener mListener = new ActivityListener() {
 
+            @Override
+            public void remoteSearchStarted(Account acct, String folder){
+                //TODO: Update UI behavior for Remote Searching
+                //for now, just use existing UI behavior
+                synchronizeMailboxStarted(acct, folder); 
+            }
+            
+            @Override
+            public void remoteSearchFinished(Account acct, String folder, int numResults){
+                //TODO: Update UI behavior for Remote Searching
+                //TODO: Show number of results
+                //for now, just use existing UI behavior
+                synchronizeMailboxFinished(acct, folder, 0, 0);
+            }
+            
             @Override
             public void informUserOfStatus() {
                 mHandler.refreshTitle();
@@ -2037,11 +2052,7 @@ public void messageUidChanged(Account account, String folder, String oldUid, Str
         };
 
         private boolean updateForMe(Account account, String folder) {
-            if ((account.equals(mAccount) && mFolderName != null && folder.equals(mFolderName))) {
-                return true;
-            } else {
-                return false;
-            }
+            return account.equals(mAccount) && mFolderName != null && folder.equals(mFolderName);
         }
 
         private Drawable mAttachmentIcon;
diff --git a/src/com/fsck/k9/controller/MessagingController.java b/src/com/fsck/k9/controller/MessagingController.java
index e273c71fa91..58e1d3ddfc3 100644
--- a/src/com/fsck/k9/controller/MessagingController.java
+++ b/src/com/fsck/k9/controller/MessagingController.java
@@ -821,14 +821,19 @@ public void searchRemoteMessagesSynchronous(final String acctUuid, final String
         final AccountStats stats = new AccountStats();
 
         if (listener != null) {
-            listener.listLocalMessagesStarted(acct, null);
+            listener.remoteSearchStarted(acct, folderName);
         }
 
+        
         MessageRetrievalListener retrievalListener = new MessageRetrievalListener() {
             @Override
-            public void messageStarted(String message, int number, int ofTotal) {}
+            public void messageStarted(String message, int number, int ofTotal) {
+                
+            }
             @Override
-            public void messageFinished(Message message, int number, int ofTotal) {
+            public void messageFinished(Message message, int number, int ofTotal){
+                
+                
                 if (!isMessageSuppressed(message.getFolder().getAccount(), message.getFolder().getName(), message)) {
                     List messages = new ArrayList();
 
@@ -837,7 +842,7 @@ public void messageFinished(Message message, int number, int ofTotal) {
                     stats.flaggedMessageCount += (message.isSet(Flag.FLAGGED)) ? 1 : 0;
                     if (listener != null) {
                         listener.listLocalMessagesAddMessages(acct, null, messages);
-
+                        listener.synchronizeMailboxProgress(acct, null, number, ofTotal);
                     }
                 }
 
@@ -849,11 +854,9 @@ public void messagesFinished(int number) {
         };
 
         try {
-            String[] queryFields = {"html_content", "subject", "sender_list"};
             Store acctStore = acct.getRemoteStore();
 
-            //TODO: make queryFields actually do something
-            acctStore.searchRemoteMessages(retrievalListener, queryFields, query, folderName, requiredFlags, forbiddenFlags);
+            acctStore.searchRemoteMessages(retrievalListener, query, folderName, requiredFlags, forbiddenFlags);
 
         } catch (Exception e) {
             if (listener != null) {
@@ -863,6 +866,7 @@ public void messagesFinished(int number) {
         } finally {
             if (listener != null) {
                 listener.listLocalMessagesFinished(acct, null);
+                listener.remoteSearchFinished(acct, folderName, 0);
             }
         }
 
diff --git a/src/com/fsck/k9/controller/MessagingListener.java b/src/com/fsck/k9/controller/MessagingListener.java
index 49ddbf4da08..e62dc631f19 100644
--- a/src/com/fsck/k9/controller/MessagingListener.java
+++ b/src/com/fsck/k9/controller/MessagingListener.java
@@ -151,6 +151,9 @@ public void pendingCommandCompleted(Account account, String commandTitle) {}
 
     public void pendingCommandsFinished(Account account) {}
 
+    public void remoteSearchStarted(Account acct, String folder){}
+    
+    public void remoteSearchFinished(Account acct, String folder, int numResults) {}
 
     /**
      * General notification messages subclasses can override to be notified that the controller
diff --git a/src/com/fsck/k9/mail/Store.java b/src/com/fsck/k9/mail/Store.java
index 28ff45924ca..344be2aaeb9 100644
--- a/src/com/fsck/k9/mail/Store.java
+++ b/src/com/fsck/k9/mail/Store.java
@@ -1,6 +1,9 @@
 
 package com.fsck.k9.mail;
 
+import java.util.HashMap;
+import java.util.List;
+
 import android.app.Application;
 import android.content.Context;
 
@@ -9,11 +12,9 @@
 import com.fsck.k9.mail.store.ImapStore;
 import com.fsck.k9.mail.store.LocalStore;
 import com.fsck.k9.mail.store.Pop3Store;
-import com.fsck.k9.mail.store.WebDavStore;
 import com.fsck.k9.mail.store.StorageManager.StorageProvider;
-
-import java.util.HashMap;
-import java.util.List;
+import com.fsck.k9.mail.store.UnavailableStorageException;
+import com.fsck.k9.mail.store.WebDavStore;
 
 /**
  * Store is the access point for an email message store. It's location can be
@@ -178,7 +179,7 @@ public Account getAccount() {
         return mAccount;
     }
     
-    public void searchRemoteMessages(MessageRetrievalListener listener, String[] queryFields, String queryString,
+    public void searchRemoteMessages(MessageRetrievalListener listener, String queryString,
             String folder,  final Flag[] requiredFlags, final Flag[] forbiddenFlags) throws MessagingException{
     	throw new MessagingException("K-9 does not support remote searchign on this account type");
     }
diff --git a/src/com/fsck/k9/mail/store/ImapStore.java b/src/com/fsck/k9/mail/store/ImapStore.java
index 72629e2e400..6d8db36b0da 100644
--- a/src/com/fsck/k9/mail/store/ImapStore.java
+++ b/src/com/fsck/k9/mail/store/ImapStore.java
@@ -65,6 +65,7 @@
 import com.fsck.k9.K9;
 import com.fsck.k9.R;
 import com.fsck.k9.controller.MessageRetrievalListener;
+import com.fsck.k9.controller.MessagingListener;
 import com.fsck.k9.helper.Utility;
 import com.fsck.k9.helper.power.TracingPowerManager;
 import com.fsck.k9.helper.power.TracingPowerManager.TracingWakeLock;
@@ -94,7 +95,6 @@
 import com.fsck.k9.mail.internet.MimeUtility;
 import com.fsck.k9.mail.store.ImapResponseParser.ImapList;
 import com.fsck.k9.mail.store.ImapResponseParser.ImapResponse;
-import com.fsck.k9.mail.store.LocalStore.LocalFolder;
 import com.fsck.k9.mail.transport.imap.ImapSettings;
 import com.jcraft.jzlib.JZlib;
 import com.jcraft.jzlib.ZOutputStream;
@@ -3388,7 +3388,7 @@ public Object foundLiteral(ImapResponse response,
     }
 	
     @Override
-	public void searchRemoteMessages(final MessageRetrievalListener listener, final String[] queryFields, final String queryString,
+	public void searchRemoteMessages(final MessageRetrievalListener listener, final String queryString,
             final String folderName,  final Flag[] requiredFlags, final Flag[] forbiddenFlags) throws MessagingException{
 		
 		if(!mAccount.allowRemoteSearch()){
@@ -3404,6 +3404,7 @@ public void searchRemoteMessages(final MessageRetrievalListener listener, final
 			folder.open(OpenMode.READ_ONLY);
 			folder.checkOpen();
 			
+			
 			folder.doRemoteSearch(queryString, requiredFlags, forbiddenFlags, listener);
 			
 		}

From a97c329e5d63a579bdfd49be98ccc6d256911ec1 Mon Sep 17 00:00:00 2001
From: Rob Bayer 
Date: Wed, 29 Feb 2012 23:38:26 -0800
Subject: [PATCH 11/21] Working IMAP search, with passable UI.

---
 res/values/strings.xml                        |   3 +
 src/com/fsck/k9/activity/MessageList.java     | 178 ++++++++++++------
 .../k9/controller/MessagingController.java    |  53 ++++--
 .../fsck/k9/controller/MessagingListener.java |  43 +++++
 src/com/fsck/k9/mail/Store.java               |   5 +-
 src/com/fsck/k9/mail/store/ImapStore.java     |  43 +++--
 6 files changed, 234 insertions(+), 91 deletions(-)

diff --git a/res/values/strings.xml b/res/values/strings.xml
index 8f93ed814db..36d1a7960df 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1152,5 +1152,8 @@ the import operation. Please install a file manager application from Android Mar
         To perform a remote search, press your device\'s Search button while viewing a folder from this account.
         \n\nNote: Remote search is NOT available from the Unified Inbox or from a list of folders.
     
+    Sending query to server
     Don\'t Show Again
+    Fetching %d results
+    Fetching %1$d of %2$d results
 
diff --git a/src/com/fsck/k9/activity/MessageList.java b/src/com/fsck/k9/activity/MessageList.java
index 5e51305300c..5a7996a657c 100644
--- a/src/com/fsck/k9/activity/MessageList.java
+++ b/src/com/fsck/k9/activity/MessageList.java
@@ -70,6 +70,7 @@
 import com.fsck.k9.mail.Flag;
 import com.fsck.k9.mail.Folder;
 import com.fsck.k9.mail.Message;
+import com.fsck.k9.mail.MessagingException;
 import com.fsck.k9.mail.store.LocalStore;
 import com.fsck.k9.mail.store.LocalStore.LocalFolder;
 import com.fsck.k9.mail.store.StorageManager;
@@ -421,6 +422,25 @@ public void run() {
             });
         }
 
+        
+        public void updateFooter(final String text, final boolean progressVisible){
+            runOnUiThread(new Runnable(){
+                public void run(){
+                    FooterViewHolder holder = (FooterViewHolder) mFooterView.getTag();
+                    holder.progress.setVisibility(progressVisible ? ProgressBar.VISIBLE : ProgressBar.INVISIBLE);
+                    if(text!= null){
+                        holder.main.setText(text);
+                    }
+                }
+            });
+        }
+        
+        public void setWindowProgress(final int amt){
+            runOnUiThread(new Runnable(){public void run(){
+                getWindow().setFeatureInt(Window.FEATURE_PROGRESS, amt);
+            }});
+        }
+        
         private void resetUnreadCount() {
             runOnUiThread(new Runnable() {
                 @Override
@@ -493,11 +513,24 @@ public void folderLoading(String folder, boolean loading) {
             if (mCurrentFolder != null && mCurrentFolder.name.equals(folder)) {
                 mCurrentFolder.loading = loading;
             }
-            runOnUiThread(new Runnable() {
-                @Override public void run() {
-                    updateFooterView();
+
+            if (mCurrentFolder != null && mAccount != null) {
+                if (mCurrentFolder.loading) {
+                    updateFooter(getString(R.string.status_loading_more), true);
+                } else {
+                    if (!mCurrentFolder.lastCheckFailed) {
+                        if (mAccount.getDisplayCount() == 0) {
+                            updateFooter(getString(R.string.message_list_load_more_messages_action), false);
+                        } else {
+                            updateFooter(String.format(getString(R.string.load_more_messages_fmt), mAccount.getDisplayCount()), false);
+                        }
+                    } else {
+                        updateFooter(getString(R.string.status_loading_more_failed), false);
+                    }
                 }
-            });
+            } else {
+                updateFooter(null, false);
+            }
         }
 
         private void refreshTitle() {
@@ -511,7 +544,9 @@ public void run() {
 
         private void refreshTitleOnThread() {
             setWindowTitle();
-            setWindowProgress();
+            if(!mRemoteSearch){
+                setWindowProgress();
+            }
         }
 
         private void setWindowProgress() {
@@ -663,7 +698,7 @@ public static void actionHandle(Context context, String title,
     @Override
     public void onItemClick(AdapterView parent, View view, int position, long id) {
         if (view == mFooterView) {
-            if (mCurrentFolder != null) {
+            if (mCurrentFolder != null && !mRemoteSearch) {
                 mController.loadMoreMessages(mAccount, mFolderName, mAdapter.mListener);
             }
             return;
@@ -782,8 +817,8 @@ private void initializeMessageList(Intent intent, boolean create) {
             mCurrentFolder = mAdapter.getFolder(mFolderName, mAccount);
         }
 
-        // Hide "Load up to x more" footer for search views
-        mFooterView.setVisibility((mQueryString != null) ? View.GONE : View.VISIBLE);
+        // Hide "Load up to x more" footer for local search views
+        mFooterView.setVisibility((mQueryString != null && !mRemoteSearch) ? View.GONE : View.VISIBLE);
 
         mController = MessagingController.getInstance(getApplication());
         mListView.setAdapter(mAdapter);
@@ -884,32 +919,34 @@ else if (mFolderName != null) {
             new Thread() {
                 @Override
                 public void run() {
-                    mAdapter.markAllMessagesAsDirty();
-
-                    if (mRemoteSearch){
-                		mController.searchRemoteMessagesSynchronous(mSearchAccount, mSearchFolder, mQueryString, null, null, mAdapter.mListener);
-                	} else if (mFolderName != null) {
-                        mController.listLocalMessagesSynchronous(mAccount, mFolderName,  mAdapter.mListener);
-                    } else if (mQueryString != null) {
-                        mController.searchLocalMessagesSynchronous(mAccountUuids, mFolderNames, null, mQueryString, mIntegrate, mQueryFlags, mForbiddenFlags, mAdapter.mListener);
+                    
+
+                    if (!mRemoteSearch){
+                        mAdapter.markAllMessagesAsDirty();
+                        if (mFolderName != null) {
+                            mController.listLocalMessagesSynchronous(mAccount, mFolderName,  mAdapter.mListener);
+                        } else if (mQueryString != null) {
+                            mController.searchLocalMessagesSynchronous(mAccountUuids, mFolderNames, null, mQueryString, mIntegrate, mQueryFlags, mForbiddenFlags, mAdapter.mListener);
+                        }
+                        mAdapter.pruneDirtyMessages();
+                        runOnUiThread(new Runnable() {
+                            @Override
+                            public void run() {
+                                mAdapter.notifyDataSetChanged();
+                                restoreListState();
+                            }
+                        });
                     }
 
 
-                    mAdapter.pruneDirtyMessages();
-                    runOnUiThread(new Runnable() {
-                        @Override
-                        public void run() {
-                            mAdapter.notifyDataSetChanged();
-                            restoreListState();
-                        }
-                    });
+                    
                 }
 
             }
             .start();
         }
 
-        if (mAccount != null && mFolderName != null) {
+        if (mAccount != null && mFolderName != null && !mRemoteSearch) {
             mController.getFolderUnreadMessageCount(mAccount, mFolderName, mAdapter.mListener);
         }
         mHandler.refreshTitle();
@@ -1905,21 +1942,75 @@ class MessageListAdapter extends BaseAdapter {
 
         private final ActivityListener mListener = new ActivityListener() {
 
+            
+            @Override
+            public void remoteSearchAddMessage(Account account, String folderName, Message message, final int numDone, final int numTotal) {
+                
+                if(numTotal > 0){
+                    mHandler.setWindowProgress(Window.PROGRESS_END/numTotal * numDone);
+                }
+                else{
+                    mHandler.setWindowProgress(Window.PROGRESS_END);
+                }
+                
+                //MessageView expects messages to be in the LocalStore, so add them
+                try{
+                    LocalFolder localFolder = account.getLocalStore().getFolder(folderName);
+                    if(localFolder != null){
+                        if(localFolder.getMessage(message.getUid()) == null){
+                            Message [] messages = {message};
+                            localFolder.appendMessages(messages);
+                        }//else: the message is already in the local store so don't worry about it
+                    }//else: should never really happen
+                    
+                }
+                catch(MessagingException e){
+                    //FIXME: Do something useful here...
+                    if(K9.DEBUG){
+                        Log.d("IMAP search", "remoteSearchAddMessage caught error: " + e.toString());
+                    }
+                }
+                
+                addOrUpdateMessages(account, folderName, Collections.singletonList(message), false);
+            }
+
+            @Override
+            public void remoteSearchFailed(Account acct, String folder,
+                    final String err) {
+                //TODO: Better error handling
+                runOnUiThread(new Runnable(){public void run(){
+                    Toast.makeText(getApplication(),  err, Toast.LENGTH_LONG).show();
+                }});
+            }
+
             @Override
             public void remoteSearchStarted(Account acct, String folder){
-                //TODO: Update UI behavior for Remote Searching
-                //for now, just use existing UI behavior
-                synchronizeMailboxStarted(acct, folder); 
+                mHandler.progress(true);
+                mHandler.updateFooter(getString(R.string.remote_search_sending_query), true);
             }
             
+
             @Override
             public void remoteSearchFinished(Account acct, String folder, int numResults){
-                //TODO: Update UI behavior for Remote Searching
-                //TODO: Show number of results
-                //for now, just use existing UI behavior
-                synchronizeMailboxFinished(acct, folder, 0, 0);
+                mHandler.progress(false);
+                mHandler.updateFooter("", false);
+                mHandler.setWindowProgress(Window.PROGRESS_END);
+            }
+            
+            @Override
+            public void remoteSearchServerQueryComplete(Account account, String folderName, int numResults){ 
+                mHandler.progress(true);
+                if(account != null &&  account.getRemoteSearchNumResults() != 0 && numResults > account.getRemoteSearchNumResults()){
+                    mHandler.updateFooter(getString(R.string.remote_search_downloading_limited, account.getRemoteSearchNumResults(), numResults), true);
+                }
+                else{
+                    mHandler.updateFooter(getString(R.string.remote_search_downloading, numResults), true);
+                }
+                mHandler.setWindowProgress(Window.PROGRESS_START);
             }
             
+            
+            
             @Override
             public void informUserOfStatus() {
                 mHandler.refreshTitle();
@@ -2519,29 +2610,6 @@ private View getFooterView(ViewGroup parent) {
         return mFooterView;
     }
 
-    private void updateFooterView() {
-        FooterViewHolder holder = (FooterViewHolder) mFooterView.getTag();
-
-        if (mCurrentFolder != null && mAccount != null) {
-            if (mCurrentFolder.loading) {
-                holder.main.setText(getString(R.string.status_loading_more));
-                holder.progress.setVisibility(ProgressBar.VISIBLE);
-            } else {
-                if (!mCurrentFolder.lastCheckFailed) {
-                    if (mAccount.getDisplayCount() == 0) {
-                        holder.main.setText(getString(R.string.message_list_load_more_messages_action));
-                    } else {
-                        holder.main.setText(String.format(getString(R.string.load_more_messages_fmt), mAccount.getDisplayCount()));
-                    }
-                } else {
-                    holder.main.setText(getString(R.string.status_loading_more_failed));
-                }
-                holder.progress.setVisibility(ProgressBar.INVISIBLE);
-            }
-        } else {
-            holder.progress.setVisibility(ProgressBar.INVISIBLE);
-        }
-    }
 
     private void hideBatchButtons() {
         if (mBatchButtonArea.getVisibility() != View.GONE) {
diff --git a/src/com/fsck/k9/controller/MessagingController.java b/src/com/fsck/k9/controller/MessagingController.java
index 58e1d3ddfc3..002b8c000fb 100644
--- a/src/com/fsck/k9/controller/MessagingController.java
+++ b/src/com/fsck/k9/controller/MessagingController.java
@@ -42,11 +42,11 @@
 import com.fsck.k9.Account;
 import com.fsck.k9.AccountStats;
 import com.fsck.k9.K9;
+import com.fsck.k9.K9.Intents;
 import com.fsck.k9.NotificationSetting;
 import com.fsck.k9.Preferences;
 import com.fsck.k9.R;
 import com.fsck.k9.SearchSpecification;
-import com.fsck.k9.K9.Intents;
 import com.fsck.k9.activity.FolderList;
 import com.fsck.k9.activity.MessageList;
 import com.fsck.k9.helper.Utility;
@@ -58,8 +58,8 @@
 import com.fsck.k9.mail.Folder;
 import com.fsck.k9.mail.Folder.FolderType;
 import com.fsck.k9.mail.Folder.OpenMode;
-import com.fsck.k9.mail.Message.RecipientType;
 import com.fsck.k9.mail.Message;
+import com.fsck.k9.mail.Message.RecipientType;
 import com.fsck.k9.mail.MessagingException;
 import com.fsck.k9.mail.Part;
 import com.fsck.k9.mail.PushReceiver;
@@ -69,12 +69,12 @@
 import com.fsck.k9.mail.internet.MimeMessage;
 import com.fsck.k9.mail.internet.MimeUtility;
 import com.fsck.k9.mail.internet.TextBody;
-import com.fsck.k9.mail.store.UnavailableAccountException;
 import com.fsck.k9.mail.store.LocalStore;
-import com.fsck.k9.mail.store.UnavailableStorageException;
 import com.fsck.k9.mail.store.LocalStore.LocalFolder;
 import com.fsck.k9.mail.store.LocalStore.LocalMessage;
 import com.fsck.k9.mail.store.LocalStore.PendingCommand;
+import com.fsck.k9.mail.store.UnavailableAccountException;
+import com.fsck.k9.mail.store.UnavailableStorageException;
 
 
 /**
@@ -835,14 +835,10 @@ public void messageFinished(Message message, int number, int ofTotal){
                 
                 
                 if (!isMessageSuppressed(message.getFolder().getAccount(), message.getFolder().getName(), message)) {
-                    List messages = new ArrayList();
-
-                    messages.add(message);
                     stats.unreadMessageCount += (!message.isSet(Flag.SEEN)) ? 1 : 0;
                     stats.flaggedMessageCount += (message.isSet(Flag.FLAGGED)) ? 1 : 0;
                     if (listener != null) {
-                        listener.listLocalMessagesAddMessages(acct, null, messages);
-                        listener.synchronizeMailboxProgress(acct, null, number, ofTotal);
+                        listener.remoteSearchAddMessage(acct, folderName, message, number, ofTotal);
                     }
                 }
 
@@ -852,15 +848,32 @@ public void messagesFinished(int number) {
 
             }
         };
+        
+        SearchListener searchListener = new SearchListener(){
+
+            @Override
+            public void searchStarted() {
+                listener.remoteSearchStarted(acct, folderName);
+            }
+
+            @Override
+            public void searchFinished(int numResults) {
+                listener.remoteSearchServerQueryComplete(acct, folderName, numResults);
+            }
+        };
 
         try {
             Store acctStore = acct.getRemoteStore();
-
-            acctStore.searchRemoteMessages(retrievalListener, query, folderName, requiredFlags, forbiddenFlags);
+            if(acctStore != null){
+                acctStore.searchRemoteMessages(retrievalListener, searchListener, query, folderName, requiredFlags, forbiddenFlags);
+            }
+            else{
+                throw new MessagingException("Account has no remote store");
+            }
 
         } catch (Exception e) {
             if (listener != null) {
-                listener.listLocalMessagesFailed(acct, null, e.getMessage());
+                listener.remoteSearchFailed(acct, null, e.getMessage());
             }
             addErrorMessage(acct, null, e);
         } finally {
@@ -2809,10 +2822,10 @@ public void run() {
         });
     }
 
-    public void loadMessageForView(final Account account, final String folder, final String uid,
+    public void loadMessageForView(final Account account, final String folderName, final String uid,
                                    final MessagingListener listener) {
         for (MessagingListener l : getListeners(listener)) {
-            l.loadMessageForViewStarted(account, folder, uid);
+            l.loadMessageForViewStarted(account, folderName, uid);
         }
         threadPool.execute(new Runnable() {
             @Override
@@ -2820,13 +2833,13 @@ public void run() {
 
                 try {
                     LocalStore localStore = account.getLocalStore();
-                    LocalFolder localFolder = localStore.getFolder(folder);
+                    LocalFolder localFolder = localStore.getFolder(folderName);
                     localFolder.open(OpenMode.READ_WRITE);
 
                     LocalMessage message = (LocalMessage)localFolder.getMessage(uid);
                     if (message == null
                     || message.getId() == 0) {
-                        throw new IllegalArgumentException("Message not found: folder=" + folder + ", uid=" + uid);
+                        throw new IllegalArgumentException("Message not found: folder=" + folderName + ", uid=" + uid);
                     }
                     if (!message.isSet(Flag.SEEN)) {
                         message.setFlag(Flag.SEEN, true);
@@ -2834,7 +2847,7 @@ public void run() {
                     }
 
                     for (MessagingListener l : getListeners(listener)) {
-                        l.loadMessageForViewHeadersAvailable(account, folder, uid, message);
+                        l.loadMessageForViewHeadersAvailable(account, folderName, uid, message);
                     }
 
                     FetchProfile fp = new FetchProfile();
@@ -2846,16 +2859,16 @@ public void run() {
                     localFolder.close();
 
                     for (MessagingListener l : getListeners(listener)) {
-                        l.loadMessageForViewBodyAvailable(account, folder, uid, message);
+                        l.loadMessageForViewBodyAvailable(account, folderName, uid, message);
                     }
 
                     for (MessagingListener l : getListeners(listener)) {
-                        l.loadMessageForViewFinished(account, folder, uid, message);
+                        l.loadMessageForViewFinished(account, folderName, uid, message);
                     }
 
                 } catch (Exception e) {
                     for (MessagingListener l : getListeners(listener)) {
-                        l.loadMessageForViewFailed(account, folder, uid, e);
+                        l.loadMessageForViewFailed(account, folderName, uid, e);
                     }
                     addErrorMessage(account, null, e);
 
diff --git a/src/com/fsck/k9/controller/MessagingListener.java b/src/com/fsck/k9/controller/MessagingListener.java
index e62dc631f19..0fd87e3881a 100644
--- a/src/com/fsck/k9/controller/MessagingListener.java
+++ b/src/com/fsck/k9/controller/MessagingListener.java
@@ -151,10 +151,51 @@ public void pendingCommandCompleted(Account account, String commandTitle) {}
 
     public void pendingCommandsFinished(Account account) {}
 
+    
+    /**
+     * Called when a remote search is started
+     * 
+     * @param acct
+     * @param folder
+     */
     public void remoteSearchStarted(Account acct, String folder){}
     
+    
+    /**
+     * Called when server has responded to our query.  Messages have not yet been downloaded.
+     * 
+     * @param numResults
+     */
+    public void remoteSearchServerQueryComplete(Account account, String folderName, int numResults){ }
+    
+    
+    /**
+     * Called when a new result message is available for a remote search
+     * Can assume headers have been downloaded, but potentially not body.
+     * @param account 
+     * @param folder 
+     * @param message
+     */
+    public void remoteSearchAddMessage(Account account, String folder, Message message, int numDone, int numTotal){ }
+    
+    /**
+     * Called when Remote Search is fully complete
+     * 
+     * @param acct
+     * @param folder
+     * @param numResults
+     */
     public void remoteSearchFinished(Account acct, String folder, int numResults) {}
 
+    /**
+     * Called when there was a problem with a remote search operation.
+     * 
+     * @param acct
+     * @param folder
+     * @param err
+     */
+    public void remoteSearchFailed(Account acct, String folder, String err){ }
+    
     /**
      * General notification messages subclasses can override to be notified that the controller
      * has completed a command. This is useful for turning off progress indicators that may have
@@ -165,4 +206,6 @@ public void remoteSearchFinished(Account acct, String folder, int numResults) {}
      *         {@code false} otherwise.
      */
     public void controllerCommandCompleted(boolean moreCommandsToRun) {}
+
+
 }
diff --git a/src/com/fsck/k9/mail/Store.java b/src/com/fsck/k9/mail/Store.java
index 344be2aaeb9..86276a916ab 100644
--- a/src/com/fsck/k9/mail/Store.java
+++ b/src/com/fsck/k9/mail/Store.java
@@ -9,6 +9,7 @@
 
 import com.fsck.k9.Account;
 import com.fsck.k9.controller.MessageRetrievalListener;
+import com.fsck.k9.controller.SearchListener;
 import com.fsck.k9.mail.store.ImapStore;
 import com.fsck.k9.mail.store.LocalStore;
 import com.fsck.k9.mail.store.Pop3Store;
@@ -179,8 +180,8 @@ public Account getAccount() {
         return mAccount;
     }
     
-    public void searchRemoteMessages(MessageRetrievalListener listener, String queryString,
+    public void searchRemoteMessages(MessageRetrievalListener msgListener, SearchListener searchListener, String queryString,
             String folder,  final Flag[] requiredFlags, final Flag[] forbiddenFlags) throws MessagingException{
-    	throw new MessagingException("K-9 does not support remote searchign on this account type");
+    	throw new MessagingException("K-9 does not support remote searching on this account type");
     }
 }
diff --git a/src/com/fsck/k9/mail/store/ImapStore.java b/src/com/fsck/k9/mail/store/ImapStore.java
index 6d8db36b0da..07e5915b325 100644
--- a/src/com/fsck/k9/mail/store/ImapStore.java
+++ b/src/com/fsck/k9/mail/store/ImapStore.java
@@ -65,7 +65,7 @@
 import com.fsck.k9.K9;
 import com.fsck.k9.R;
 import com.fsck.k9.controller.MessageRetrievalListener;
-import com.fsck.k9.controller.MessagingListener;
+import com.fsck.k9.controller.SearchListener;
 import com.fsck.k9.helper.Utility;
 import com.fsck.k9.helper.power.TracingPowerManager;
 import com.fsck.k9.helper.power.TracingPowerManager.TracingWakeLock;
@@ -1172,11 +1172,11 @@ private int getRemoteMessageCount(String criteria) throws MessagingException {
 
         }
         
-        public void doRemoteSearch(final String queryString, final Flag[] requiredFlags, final Flag [] forbiddenFlags, final MessageRetrievalListener listener) 
+        public void doRemoteSearch(final String queryString, final Flag[] requiredFlags, final Flag [] forbiddenFlags, final MessageRetrievalListener msgListener, final SearchListener searchListener) 
         		throws MessagingException{
         	ImapSearcher searcher = new ImapSearcher(){
         		public List search() throws IOException, MessagingException {
-        			String imapQuery = "SEARCH ";
+        			String imapQuery = "UID SEARCH ";
         			if(requiredFlags != null){
 	        			for(Flag f : requiredFlags){
 	        				switch(f){
@@ -1246,7 +1246,7 @@ public List search() throws IOException, MessagingException {
         		}
         	};
         	
-        	search(searcher, listener, (mAccount != null ? mAccount.getRemoteSearchNumResults() : 0), true);
+        	search(searcher, msgListener, searchListener, (mAccount != null ? mAccount.getRemoteSearchNumResults() : 0), true);
         }
 
         @Override
@@ -1339,16 +1339,22 @@ public List search() throws IOException, MessagingException {
         }
 
         private Message[] search(ImapSearcher searcher, MessageRetrievalListener listener) throws MessagingException {
-        	return search(searcher, listener, 0, false);
+        	return search(searcher, listener, null, 0, false);
         }
         
-        private Message[] search(ImapSearcher searcher, MessageRetrievalListener listener, int limit, boolean getHeaders) throws MessagingException {
+        private Message[] search(ImapSearcher searcher, MessageRetrievalListener msgListener, SearchListener searchListener, int limit, boolean getHeaders) throws MessagingException {
 
             checkOpen();
             ArrayList messages = new ArrayList();
             try {
                 ArrayList uids = new ArrayList();
-                List responses = searcher.search(); //
+                
+                if(searchListener != null){
+                    searchListener.searchStarted();
+                }
+                
+                List responses = searcher.search(); 
+
                 for (ImapResponse response : responses) {
                     if (response.mTag == null) {
                         if (ImapResponseParser.equalsIgnoreCase(response.get(0), "SEARCH")) {
@@ -1358,6 +1364,10 @@ private Message[] search(ImapSearcher searcher, MessageRetrievalListener listene
                         }
                     }
                 }
+                
+                if(searchListener != null){
+                    searchListener.searchFinished(uids.size());
+                }
 
                 // Sort the uids in numerically decreasing order 
                 // By doing it in decreasing order, we ensure newest messages are dealt with first
@@ -1374,22 +1384,26 @@ private Message[] search(ImapSearcher searcher, MessageRetrievalListener listene
                 
                 if(K9.DEBUG){
                 	Log.i("IMAP search", "Search results: " + uids.size() + ", limit: " + limit);
+                	Log.i("IMAP search", "Uids: " + Arrays.toString(uids.toArray()));
                 }
                 
                 for (int i = 0, count = (limit==0 ? uids.size() : Math.min(uids.size(), limit)); i < count; i++) {
-                    if (listener != null) {
-                        listener.messageStarted("" + uids.get(i), i, count);
+                    if (msgListener != null) {
+                        msgListener.messageStarted("" + uids.get(i), i, count);
                     }
                     ImapMessage message = new ImapMessage("" + uids.get(i), this);
-
+                    
                     if(getHeaders){
                     	Message [] msgArray = {message};
+                    	if(K9.DEBUG){
+                    	    Log.i("IMAP search", "Fetching header: " + message.getUid());
+                    	}
                     	fetch(msgArray, fp, null); //don't pass the listener since we're already updating it
                     }
                     
                     messages.add(message);
-                    if (listener != null) {
-                        listener.messageFinished(message, i, count);
+                    if (msgListener != null) {
+                        msgListener.messageFinished(message, i, count);
                     }
                 }
             } catch (IOException ioe) {
@@ -3388,7 +3402,7 @@ public Object foundLiteral(ImapResponse response,
     }
 	
     @Override
-	public void searchRemoteMessages(final MessageRetrievalListener listener, final String queryString,
+	public void searchRemoteMessages(final MessageRetrievalListener msgListener, final SearchListener searchListener, final String queryString,
             final String folderName,  final Flag[] requiredFlags, final Flag[] forbiddenFlags) throws MessagingException{
 		
 		if(!mAccount.allowRemoteSearch()){
@@ -3405,10 +3419,11 @@ public void searchRemoteMessages(final MessageRetrievalListener listener, final
 			folder.checkOpen();
 			
 			
-			folder.doRemoteSearch(queryString, requiredFlags, forbiddenFlags, listener);
+			folder.doRemoteSearch(queryString, requiredFlags, forbiddenFlags, msgListener, searchListener);
 			
 		}
 		catch(Exception e){
+		    e.printStackTrace();
 			throw new MessagingException("Error during search: " + e.toString());
 		}
 		

From fcf914d047509e59be40a906f68a3a604904fc08 Mon Sep 17 00:00:00 2001
From: Rob Bayer 
Date: Fri, 2 Mar 2012 11:36:37 -0800
Subject: [PATCH 12/21] add missing file

---
 src/com/fsck/k9/controller/SearchListener.java | 6 ++++++
 1 file changed, 6 insertions(+)
 create mode 100644 src/com/fsck/k9/controller/SearchListener.java

diff --git a/src/com/fsck/k9/controller/SearchListener.java b/src/com/fsck/k9/controller/SearchListener.java
new file mode 100644
index 00000000000..46ba7d3ac43
--- /dev/null
+++ b/src/com/fsck/k9/controller/SearchListener.java
@@ -0,0 +1,6 @@
+package com.fsck.k9.controller;
+
+public interface SearchListener {
+    public void searchStarted();
+    public void searchFinished(int numResults);
+}

From bf36498fe5f41845baeef70e7982e11a7fe65592 Mon Sep 17 00:00:00 2001
From: Rob Bayer 
Date: Fri, 2 Mar 2012 18:11:31 -0800
Subject: [PATCH 13/21] Fix opening of folders to be Read-Write when necessary,
 even if they were previously opened Read-Only.

---
 src/com/fsck/k9/mail/store/ImapStore.java  | 16 ++++++++++------
 src/com/fsck/k9/mail/store/LocalStore.java |  9 ++++++++-
 2 files changed, 18 insertions(+), 7 deletions(-)

diff --git a/src/com/fsck/k9/mail/store/ImapStore.java b/src/com/fsck/k9/mail/store/ImapStore.java
index 07e5915b325..d1b496561c8 100644
--- a/src/com/fsck/k9/mail/store/ImapStore.java
+++ b/src/com/fsck/k9/mail/store/ImapStore.java
@@ -1074,7 +1074,7 @@ public void copyMessages(Message[] messages, Folder folder) throws MessagingExce
                 return;
 
             ImapFolder iFolder = (ImapFolder)folder;
-            checkOpen();
+            checkOpen(); //only need READ access
             String[] uids = new String[messages.length];
             for (int i = 0, count = messages.length; i < count; i++) {
                 uids[i] = messages[i].getUid();
@@ -1153,7 +1153,7 @@ public int getMessageCount() {
 
 
         private int getRemoteMessageCount(String criteria) throws MessagingException {
-            checkOpen();
+            checkOpen(); //only need READ access
             try {
                 int count = 0;
                 int start = 1;
@@ -1344,7 +1344,7 @@ private Message[] search(ImapSearcher searcher, MessageRetrievalListener listene
         
         private Message[] search(ImapSearcher searcher, MessageRetrievalListener msgListener, SearchListener searchListener, int limit, boolean getHeaders) throws MessagingException {
 
-            checkOpen();
+            checkOpen(); //only need READ access
             ArrayList messages = new ArrayList();
             try {
                 ArrayList uids = new ArrayList();
@@ -1431,7 +1431,7 @@ public Message[] getMessages(MessageRetrievalListener listener) throws Messaging
         @Override
         public Message[] getMessages(String[] uids, MessageRetrievalListener listener)
         throws MessagingException {
-            checkOpen();
+            checkOpen(); //only need READ access
             ArrayList messages = new ArrayList();
             try {
                 if (uids == null) {
@@ -1468,7 +1468,7 @@ public void fetch(Message[] messages, FetchProfile fp, MessageRetrievalListener
             if (messages == null || messages.length == 0) {
                 return;
             }
-            checkOpen();
+            checkOpen(); //only need READ access
             List uids = new ArrayList(messages.length);
             HashMap messageMap = new HashMap();
             for (int i = 0, count = messages.length; i < count; i++) {
@@ -1593,7 +1593,7 @@ public void fetch(Message[] messages, FetchProfile fp, MessageRetrievalListener
         @Override
         public void fetchPart(Message message, Part part, MessageRetrievalListener listener)
         throws MessagingException {
-            checkOpen();
+            checkOpen(); //only need READ access
 
             String[] parts = part.getHeader(MimeHeader.HEADER_ANDROID_ATTACHMENT_STORE_DATA);
             if (parts == null) {
@@ -1986,6 +1986,7 @@ private void parseBodyStructure(ImapList bs, Part part, String id)
          */
         @Override
         public void appendMessages(Message[] messages) throws MessagingException {
+            open(OpenMode.READ_WRITE);
             checkOpen();
             try {
                 for (Message message : messages) {
@@ -2058,6 +2059,7 @@ public String getUidFromMessageId(Message message) throws MessagingException {
 
         @Override
         public void expunge() throws MessagingException {
+            open(OpenMode.READ_WRITE);
             checkOpen();
             try {
                 executeSimpleCommand("EXPUNGE");
@@ -2087,6 +2089,7 @@ private String combineFlags(Flag[] flags) {
         @Override
         public void setFlags(Flag[] flags, boolean value)
         throws MessagingException {
+            open(OpenMode.READ_WRITE);
             checkOpen();
 
 
@@ -2121,6 +2124,7 @@ public String getNewPushState(String oldPushStateS, Message message) {
         @Override
         public void setFlags(Message[] messages, Flag[] flags, boolean value)
         throws MessagingException {
+            open(OpenMode.READ_WRITE); 
             checkOpen();
             String[] uids = new String[messages.length];
             for (int i = 0, count = messages.length; i < count; i++) {
diff --git a/src/com/fsck/k9/mail/store/LocalStore.java b/src/com/fsck/k9/mail/store/LocalStore.java
index fe830ff7bad..d6ae3e0e14f 100644
--- a/src/com/fsck/k9/mail/store/LocalStore.java
+++ b/src/com/fsck/k9/mail/store/LocalStore.java
@@ -1138,9 +1138,16 @@ public long getId() {
 
         @Override
         public void open(final OpenMode mode) throws MessagingException {
-            if (isOpen()) {
+            
+            if (isOpen() && (getMode() == mode || mode==OpenMode.READ_ONLY)) {
                 return;
             }
+            else if (isOpen()){
+                //previously opened in READ_ONLY and now requesting READ_WRITE
+                //so close connection and reopen
+                close();
+            }
+            
             try {
                 database.execute(false, new DbCallback() {
                     @Override

From 757f31f18dbd73cb81757d1113b1f0d141ce23c8 Mon Sep 17 00:00:00 2001
From: Rob Bayer 
Date: Fri, 2 Mar 2012 18:29:05 -0800
Subject: [PATCH 14/21] tabs -> spaces (my bad...)

---
 src/com/fsck/k9/Account.java                  |  46 ++--
 src/com/fsck/k9/activity/ChooseFolder.java    |  76 +++---
 src/com/fsck/k9/activity/MessageList.java     |  92 +++----
 src/com/fsck/k9/helper/MessageHelper.java     |   6 +-
 src/com/fsck/k9/mail/Store.java               |   2 +-
 .../fsck/k9/mail/internet/MimeMessage.java    |  12 +-
 src/com/fsck/k9/mail/store/ImapStore.java     | 224 +++++++++---------
 7 files changed, 229 insertions(+), 229 deletions(-)

diff --git a/src/com/fsck/k9/Account.java b/src/com/fsck/k9/Account.java
index 5e84bf5aaaf..a0ffe6eabeb 100644
--- a/src/com/fsck/k9/Account.java
+++ b/src/com/fsck/k9/Account.java
@@ -1459,22 +1459,22 @@ public void setCryptoAutoEncrypt(boolean cryptoAutoEncrypt) {
         mCryptoAutoEncrypt = cryptoAutoEncrypt;
     }
     
-	public boolean allowRemoteSearch() {
-		return mAllowRemoteSearch;
-	}
-	
-	public void setAllowRemoteSearch(boolean val){
-		mAllowRemoteSearch = val;
-	}
-
-	public int getRemoteSearchNumResults(){
-		return mRemoteSearchNumResults;
-	}
-	
-	public void setRemoteSearchNumResults(int val){
-		mRemoteSearchNumResults = (val >= 0 ? val : 0);
-	}
-	
+    public boolean allowRemoteSearch() {
+        return mAllowRemoteSearch;
+    }
+    
+    public void setAllowRemoteSearch(boolean val){
+        mAllowRemoteSearch = val;
+    }
+
+    public int getRemoteSearchNumResults(){
+        return mRemoteSearchNumResults;
+    }
+    
+    public void setRemoteSearchNumResults(int val){
+        mRemoteSearchNumResults = (val >= 0 ? val : 0);
+    }
+    
     public String getInboxFolderName() {
         return mInboxFolderName;
     }
@@ -1530,14 +1530,14 @@ public synchronized void setEnabled(boolean enabled) {
         mEnabled = enabled;
     }
 
-	public boolean getRemoteSearchFullText() {
-		
-		return mRemoteSearchFullText;
-	}
+    public boolean getRemoteSearchFullText() {
+        
+        return mRemoteSearchFullText;
+    }
 
-	public void setRemoteSearchFullText(boolean val) {
-		mRemoteSearchFullText = val;
-	}
+    public void setRemoteSearchFullText(boolean val) {
+        mRemoteSearchFullText = val;
+    }
 
 
 }
diff --git a/src/com/fsck/k9/activity/ChooseFolder.java b/src/com/fsck/k9/activity/ChooseFolder.java
index dc4a8811559..dd8cc17d525 100644
--- a/src/com/fsck/k9/activity/ChooseFolder.java
+++ b/src/com/fsck/k9/activity/ChooseFolder.java
@@ -208,7 +208,7 @@ public void dataChanged() {
             return true;
         }
         case R.id.filter_folders: {
-        	onEnterFilter();
+            onEnterFilter();
         }
             return true;
         default:
@@ -228,43 +228,43 @@ private void onRefresh() {
      * Filter {@link #mAdapter} with the user-input.
      */
     private void onEnterFilter() {
-    	final AlertDialog.Builder filterAlert = new AlertDialog.Builder(this);
-
-    	final EditText input = new EditText(this);
-    	input.addTextChangedListener(new TextWatcher() {
-			
-			@Override
-			public void onTextChanged(CharSequence s, int start, int before, int count) {
-				mAdapter.getFilter().filter(input.getText().toString());
-			}
-			
-			@Override
-			public void beforeTextChanged(CharSequence s, int start, int count,
-					int after) {
-			}
-			
-			@Override
-			public void afterTextChanged(Editable s) {
-			}
-		});
-    	input.setHint(R.string.folder_list_filter_hint);
-    	filterAlert.setView(input);
-
-    	filterAlert.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
-    		public void onClick(DialogInterface dialog, int whichButton) {
-    			String value = input.getText().toString().trim();
-    			mAdapter.getFilter().filter(value);
-    		}
-    	});
-
-    	filterAlert.setNegativeButton("Cancel",
-    			new DialogInterface.OnClickListener() {
-    		public void onClick(DialogInterface dialog, int whichButton) {
-    			mAdapter.getFilter().filter("");
-    		}
-    	});
-
-    	filterAlert.show();
+        final AlertDialog.Builder filterAlert = new AlertDialog.Builder(this);
+
+        final EditText input = new EditText(this);
+        input.addTextChangedListener(new TextWatcher() {
+            
+            @Override
+            public void onTextChanged(CharSequence s, int start, int before, int count) {
+                mAdapter.getFilter().filter(input.getText().toString());
+            }
+            
+            @Override
+            public void beforeTextChanged(CharSequence s, int start, int count,
+                    int after) {
+            }
+            
+            @Override
+            public void afterTextChanged(Editable s) {
+            }
+        });
+        input.setHint(R.string.folder_list_filter_hint);
+        filterAlert.setView(input);
+
+        filterAlert.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
+            public void onClick(DialogInterface dialog, int whichButton) {
+                String value = input.getText().toString().trim();
+                mAdapter.getFilter().filter(value);
+            }
+        });
+
+        filterAlert.setNegativeButton("Cancel",
+                new DialogInterface.OnClickListener() {
+            public void onClick(DialogInterface dialog, int whichButton) {
+                mAdapter.getFilter().filter("");
+            }
+        });
+
+        filterAlert.show();
 
     }
 
diff --git a/src/com/fsck/k9/activity/MessageList.java b/src/com/fsck/k9/activity/MessageList.java
index 3a0a3faef1c..f1253ac6a8e 100644
--- a/src/com/fsck/k9/activity/MessageList.java
+++ b/src/com/fsck/k9/activity/MessageList.java
@@ -171,13 +171,13 @@ public static class SenderComparator implements Comparator {
 
         @Override
         public int compare(MessageInfoHolder object1, MessageInfoHolder object2) {
-        	if(object1.compareCounterparty == null){
-        		return (object2.compareCounterparty == null ? 0 : 1);
-        	}else if (object2.compareCounterparty == null){
-        		return -1;
-        	}else{
-        		return object1.compareCounterparty.toLowerCase().compareTo(object2.compareCounterparty.toLowerCase());
-        	}
+            if(object1.compareCounterparty == null){
+                return (object2.compareCounterparty == null ? 0 : 1);
+            }else if (object2.compareCounterparty == null){
+                return -1;
+            }else{
+                return object1.compareCounterparty.toLowerCase().compareTo(object2.compareCounterparty.toLowerCase());
+            }
         }
 
     }
@@ -186,13 +186,13 @@ public static class DateComparator implements Comparator {
 
         @Override
         public int compare(MessageInfoHolder object1, MessageInfoHolder object2) {
-        	if(object1.compareDate == null){
-        		return (object2.compareDate == null ? 0 : 1);
-        	}else if(object2.compareDate == null){
-        		return -1;
-        	}else{
-        		return object1.compareDate.compareTo(object2.compareDate);
-        	}
+            if(object1.compareDate == null){
+                return (object2.compareDate == null ? 0 : 1);
+            }else if(object2.compareDate == null){
+                return -1;
+            }else{
+                return object1.compareDate.compareTo(object2.compareDate);
+            }
         }
 
     }
@@ -925,11 +925,11 @@ public void onResume() {
 
         
         if (mAdapter.messages.isEmpty()) {
-        	if (mRemoteSearch){
-        		//TODO: Support flag based search
-        		mController.searchRemoteMessages(mSearchAccount, mSearchFolder, mQueryString, null, null, mAdapter.mListener);
-        	}
-        	else if (mFolderName != null) {
+            if (mRemoteSearch){
+                //TODO: Support flag based search
+                mController.searchRemoteMessages(mSearchAccount, mSearchFolder, mQueryString, null, null, mAdapter.mListener);
+            }
+            else if (mFolderName != null) {
                 mController.listLocalMessages(mAccount, mFolderName,  mAdapter.mListener);
             } else if (mQueryString != null) {
                 mController.searchLocalMessages(mAccountUuids, mFolderNames, null, mQueryString, mIntegrate, mQueryFlags, mForbiddenFlags, mAdapter.mListener);
@@ -1289,33 +1289,33 @@ private void onEditAccount() {
     public boolean onSearchRequested() {
          
          if(mAccount != null && mCurrentFolder != null && mAccount.allowRemoteSearch()){
-        	 //if in a SSSable folder, ask user what they want.
-        	 //TODO: Add ability to remember selection?
-        	 final CharSequence[] items = new CharSequence[2];
-        	 items[0] = getString(R.string.search_mode_local_all);
-        	 items[1] = getString(R.string.search_mode_remote);
-
-        	 AlertDialog.Builder builder = new AlertDialog.Builder(this);
-        	 builder.setTitle(getString(R.string.search_mode_title));
-        	 builder.setItems(items, new DialogInterface.OnClickListener() {
-        	     public void onClick(DialogInterface dialog, int item) {
-        	    	 
-        	         Bundle appData = null;
-        	         if(item == 1){
-        	        	 appData = new Bundle();
-        	        	 appData.putString(EXTRA_SEARCH_ACCOUNT, mAccount.getUuid());
-                    	 appData.putString(EXTRA_SEARCH_FOLDER, mCurrentFolder.name);
-                    	 appData.putBoolean(EXTRA_REMOTE_SEARCH, true);
-        	         }
-        	         //else do regular search, which doesn't require any special parameter setup
-                	 
-                	 startSearch(null, false, appData, false);
-        	     }
-        	 });
-        	 AlertDialog alert = builder.create();
-        	 alert.show();
-        	 
-        	 return true;
+             //if in a SSSable folder, ask user what they want.
+             //TODO: Add ability to remember selection?
+             final CharSequence[] items = new CharSequence[2];
+             items[0] = getString(R.string.search_mode_local_all);
+             items[1] = getString(R.string.search_mode_remote);
+
+             AlertDialog.Builder builder = new AlertDialog.Builder(this);
+             builder.setTitle(getString(R.string.search_mode_title));
+             builder.setItems(items, new DialogInterface.OnClickListener() {
+                 public void onClick(DialogInterface dialog, int item) {
+                     
+                     Bundle appData = null;
+                     if(item == 1){
+                         appData = new Bundle();
+                         appData.putString(EXTRA_SEARCH_ACCOUNT, mAccount.getUuid());
+                         appData.putString(EXTRA_SEARCH_FOLDER, mCurrentFolder.name);
+                         appData.putBoolean(EXTRA_REMOTE_SEARCH, true);
+                     }
+                     //else do regular search, which doesn't require any special parameter setup
+                     
+                     startSearch(null, false, appData, false);
+                 }
+             });
+             AlertDialog alert = builder.create();
+             alert.show();
+             
+             return true;
          }
          
          startSearch(null, false, null, false);
diff --git a/src/com/fsck/k9/helper/MessageHelper.java b/src/com/fsck/k9/helper/MessageHelper.java
index a2831410373..01d777d089f 100644
--- a/src/com/fsck/k9/helper/MessageHelper.java
+++ b/src/com/fsck/k9/helper/MessageHelper.java
@@ -91,9 +91,9 @@ public void populate(final MessageInfoHolder target, final Message message,
         }
     }
     public String formatDate(Date date) {
-    	if (date==null){
-    		return "";
-    	}
+        if (date==null){
+            return "";
+        }
         if (Utility.isDateToday(date)) {
             return mTodayDateFormat.format(date);
         } else {
diff --git a/src/com/fsck/k9/mail/Store.java b/src/com/fsck/k9/mail/Store.java
index 86276a916ab..4865810dbe7 100644
--- a/src/com/fsck/k9/mail/Store.java
+++ b/src/com/fsck/k9/mail/Store.java
@@ -182,6 +182,6 @@ public Account getAccount() {
     
     public void searchRemoteMessages(MessageRetrievalListener msgListener, SearchListener searchListener, String queryString,
             String folder,  final Flag[] requiredFlags, final Flag[] forbiddenFlags) throws MessagingException{
-    	throw new MessagingException("K-9 does not support remote searching on this account type");
+        throw new MessagingException("K-9 does not support remote searching on this account type");
     }
 }
diff --git a/src/com/fsck/k9/mail/internet/MimeMessage.java b/src/com/fsck/k9/mail/internet/MimeMessage.java
index 05db24d045d..84255bf57f2 100644
--- a/src/com/fsck/k9/mail/internet/MimeMessage.java
+++ b/src/com/fsck/k9/mail/internet/MimeMessage.java
@@ -589,26 +589,26 @@ public MimeMessage clone() {
     }
     
     public boolean toMe(){
-    	return false;
+        return false;
     }
     
     public boolean ccMe(){
-    	return false;
+        return false;
     }
     
     public boolean bccMe(){
-    	return false;
+        return false;
     }
     
     public long getId(){
-    	return Long.parseLong(mUid); //or maybe .mMessageId?
+        return Long.parseLong(mUid); //or maybe .mMessageId?
     }
     
     public String getPreview(){
-    	return "my_preview";
+        return "my_preview";
     }
     
     public boolean hasAttachments(){
-    	return false;
+        return false;
     }
 }
diff --git a/src/com/fsck/k9/mail/store/ImapStore.java b/src/com/fsck/k9/mail/store/ImapStore.java
index d1b496561c8..cb4ff838eb5 100644
--- a/src/com/fsck/k9/mail/store/ImapStore.java
+++ b/src/com/fsck/k9/mail/store/ImapStore.java
@@ -1173,80 +1173,80 @@ private int getRemoteMessageCount(String criteria) throws MessagingException {
         }
         
         public void doRemoteSearch(final String queryString, final Flag[] requiredFlags, final Flag [] forbiddenFlags, final MessageRetrievalListener msgListener, final SearchListener searchListener) 
-        		throws MessagingException{
-        	ImapSearcher searcher = new ImapSearcher(){
-        		public List search() throws IOException, MessagingException {
-        			String imapQuery = "UID SEARCH ";
-        			if(requiredFlags != null){
-	        			for(Flag f : requiredFlags){
-	        				switch(f){
-	        				case DELETED:
-	        					imapQuery += "DELETED ";
-	        					break;
-	        					
-	        				case SEEN:
-	        					imapQuery +=  "SEEN ";
-	        					break;
-	        					
-	        				case ANSWERED:
-	        					imapQuery += "ANSWERED ";
-	        					break;
-	        					
-	        				case FLAGGED:
-	        					imapQuery += "FLAGGED ";
-	        					break;
-	        					
-	        				case DRAFT:
-	        					imapQuery += "DRAFT ";
-	        					break;
-	        					
-	        				case RECENT:
-	        					imapQuery += "RECENT ";
-	        					break;
-	        				}
-	        			}
-        			}
-        			if(forbiddenFlags != null){
-	        			for(Flag f : forbiddenFlags){
-	        				switch(f){
-	        				case DELETED:
-	        					imapQuery += "UNDELETED ";
-	        					break;
-	        					
-	        				case SEEN:
-	        					imapQuery +=  "UNSEEN ";
-	        					break;
-	        					
-	        				case ANSWERED:
-	        					imapQuery += "UNANSWERED ";
-	        					break;
-	        					
-	        				case FLAGGED:
-	        					imapQuery += "UNFLAGGED ";
-	        					break;
-	        					
-	        				case DRAFT:
-	        					imapQuery += "UNDRAFT ";
-	        					break;
-	        					
-	        				case RECENT:
-	        					imapQuery += "UNRECENT ";
-	        					break;
-	        				}
-	        			}
-        			}
-        			String encodedQry = encodeString(queryString);
-        			if(mAccount.getRemoteSearchFullText()){
-        				imapQuery += "TEXT " + encodedQry;
-        			}
-        			else{
-        				imapQuery += "OR SUBJECT " + encodedQry + " FROM " + encodedQry;
-        			}
-        			return executeSimpleCommand(imapQuery);
-        		}
-        	};
-        	
-        	search(searcher, msgListener, searchListener, (mAccount != null ? mAccount.getRemoteSearchNumResults() : 0), true);
+                throws MessagingException{
+            ImapSearcher searcher = new ImapSearcher(){
+                public List search() throws IOException, MessagingException {
+                    String imapQuery = "UID SEARCH ";
+                    if(requiredFlags != null){
+                        for(Flag f : requiredFlags){
+                            switch(f){
+                            case DELETED:
+                                imapQuery += "DELETED ";
+                                break;
+                                
+                            case SEEN:
+                                imapQuery +=  "SEEN ";
+                                break;
+                                
+                            case ANSWERED:
+                                imapQuery += "ANSWERED ";
+                                break;
+                                
+                            case FLAGGED:
+                                imapQuery += "FLAGGED ";
+                                break;
+                                
+                            case DRAFT:
+                                imapQuery += "DRAFT ";
+                                break;
+                                
+                            case RECENT:
+                                imapQuery += "RECENT ";
+                                break;
+                            }
+                        }
+                    }
+                    if(forbiddenFlags != null){
+                        for(Flag f : forbiddenFlags){
+                            switch(f){
+                            case DELETED:
+                                imapQuery += "UNDELETED ";
+                                break;
+                                
+                            case SEEN:
+                                imapQuery +=  "UNSEEN ";
+                                break;
+                                
+                            case ANSWERED:
+                                imapQuery += "UNANSWERED ";
+                                break;
+                                
+                            case FLAGGED:
+                                imapQuery += "UNFLAGGED ";
+                                break;
+                                
+                            case DRAFT:
+                                imapQuery += "UNDRAFT ";
+                                break;
+                                
+                            case RECENT:
+                                imapQuery += "UNRECENT ";
+                                break;
+                            }
+                        }
+                    }
+                    String encodedQry = encodeString(queryString);
+                    if(mAccount.getRemoteSearchFullText()){
+                        imapQuery += "TEXT " + encodedQry;
+                    }
+                    else{
+                        imapQuery += "OR SUBJECT " + encodedQry + " FROM " + encodedQry;
+                    }
+                    return executeSimpleCommand(imapQuery);
+                }
+            };
+            
+            search(searcher, msgListener, searchListener, (mAccount != null ? mAccount.getRemoteSearchNumResults() : 0), true);
         }
 
         @Override
@@ -1339,7 +1339,7 @@ public List search() throws IOException, MessagingException {
         }
 
         private Message[] search(ImapSearcher searcher, MessageRetrievalListener listener) throws MessagingException {
-        	return search(searcher, listener, null, 0, false);
+            return search(searcher, listener, null, 0, false);
         }
         
         private Message[] search(ImapSearcher searcher, MessageRetrievalListener msgListener, SearchListener searchListener, int limit, boolean getHeaders) throws MessagingException {
@@ -1377,14 +1377,14 @@ private Message[] search(ImapSearcher searcher, MessageRetrievalListener msgList
                 
                 FetchProfile fp = new FetchProfile(); 
                 if(getHeaders){
-                	fp.add(FetchProfile.Item.ENVELOPE);
-                	fp.add(FetchProfile.Item.FLAGS);
-                	fp.add(FetchProfile.Item.STRUCTURE);
+                    fp.add(FetchProfile.Item.ENVELOPE);
+                    fp.add(FetchProfile.Item.FLAGS);
+                    fp.add(FetchProfile.Item.STRUCTURE);
                 }
                 
                 if(K9.DEBUG){
-                	Log.i("IMAP search", "Search results: " + uids.size() + ", limit: " + limit);
-                	Log.i("IMAP search", "Uids: " + Arrays.toString(uids.toArray()));
+                    Log.i("IMAP search", "Search results: " + uids.size() + ", limit: " + limit);
+                    Log.i("IMAP search", "Uids: " + Arrays.toString(uids.toArray()));
                 }
                 
                 for (int i = 0, count = (limit==0 ? uids.size() : Math.min(uids.size(), limit)); i < count; i++) {
@@ -1394,11 +1394,11 @@ private Message[] search(ImapSearcher searcher, MessageRetrievalListener msgList
                     ImapMessage message = new ImapMessage("" + uids.get(i), this);
                     
                     if(getHeaders){
-                    	Message [] msgArray = {message};
-                    	if(K9.DEBUG){
-                    	    Log.i("IMAP search", "Fetching header: " + message.getUid());
-                    	}
-                    	fetch(msgArray, fp, null); //don't pass the listener since we're already updating it
+                        Message [] msgArray = {message};
+                        if(K9.DEBUG){
+                            Log.i("IMAP search", "Fetching header: " + message.getUid());
+                        }
+                        fetch(msgArray, fp, null); //don't pass the listener since we're already updating it
                     }
                     
                     messages.add(message);
@@ -1417,7 +1417,7 @@ private Message[] search(ImapSearcher searcher, MessageRetrievalListener msgList
              * Therefore, at least for now, should fetch headers individually as we fetch the messages.
              * 
             if(getHeaders){
-            	fetch(msgArray, fp, listener);
+                fetch(msgArray, fp, listener);
             }*/
             return msgArray;
         }
@@ -3404,34 +3404,34 @@ public Object foundLiteral(ImapResponse response,
             return null;
         }
     }
-	
+    
     @Override
-	public void searchRemoteMessages(final MessageRetrievalListener msgListener, final SearchListener searchListener, final String queryString,
+    public void searchRemoteMessages(final MessageRetrievalListener msgListener, final SearchListener searchListener, final String queryString,
             final String folderName,  final Flag[] requiredFlags, final Flag[] forbiddenFlags) throws MessagingException{
-		
-		if(!mAccount.allowRemoteSearch()){
-			throw new MessagingException("Your settings do not allow remote searching of this account");
-		}
-		
-		final ImapFolder folder = (ImapFolder) getFolder(folderName);
-		if(folder == null){
-			throw new MessagingException("Invalid folder specified");
-		}
-		
-		try{
-			folder.open(OpenMode.READ_ONLY);
-			folder.checkOpen();
-			
-			
-			folder.doRemoteSearch(queryString, requiredFlags, forbiddenFlags, msgListener, searchListener);
-			
-		}
-		catch(Exception e){
-		    e.printStackTrace();
-			throw new MessagingException("Error during search: " + e.toString());
-		}
-		
-	}
+        
+        if(!mAccount.allowRemoteSearch()){
+            throw new MessagingException("Your settings do not allow remote searching of this account");
+        }
+        
+        final ImapFolder folder = (ImapFolder) getFolder(folderName);
+        if(folder == null){
+            throw new MessagingException("Invalid folder specified");
+        }
+        
+        try{
+            folder.open(OpenMode.READ_ONLY);
+            folder.checkOpen();
+            
+            
+            folder.doRemoteSearch(queryString, requiredFlags, forbiddenFlags, msgListener, searchListener);
+            
+        }
+        catch(Exception e){
+            e.printStackTrace();
+            throw new MessagingException("Error during search: " + e.toString());
+        }
+        
+    }
     
     
 

From 55d9ad5e10e8f690bfc280523eda13ec224dc830 Mon Sep 17 00:00:00 2001
From: Rob Bayer 
Date: Fri, 2 Mar 2012 18:46:47 -0800
Subject: [PATCH 15/21] Code Style Cleanup: Tabs -> 4 spaces Remove trailing
 whitespace from blank lines

*NO FUNCTIONAL CHANGES*
---
 src/com/fsck/k9/Account.java                  | 14 ++--
 src/com/fsck/k9/activity/ChooseFolder.java    |  6 +-
 src/com/fsck/k9/activity/MessageList.java     | 60 +++++++-------
 .../k9/activity/setup/AccountSettings.java    | 22 +++---
 .../k9/controller/MessagingController.java    | 12 +--
 .../fsck/k9/controller/MessagingListener.java | 26 +++----
 src/com/fsck/k9/mail/Message.java             |  8 +-
 src/com/fsck/k9/mail/Store.java               |  2 +-
 .../fsck/k9/mail/internet/MimeMessage.java    | 12 +--
 src/com/fsck/k9/mail/store/ImapStore.java     | 78 +++++++++----------
 src/com/fsck/k9/mail/store/LocalStore.java    |  4 +-
 src/com/fsck/k9/provider/MessageProvider.java |  2 +-
 12 files changed, 123 insertions(+), 123 deletions(-)

diff --git a/src/com/fsck/k9/Account.java b/src/com/fsck/k9/Account.java
index a0ffe6eabeb..ba32f7efa0b 100644
--- a/src/com/fsck/k9/Account.java
+++ b/src/com/fsck/k9/Account.java
@@ -152,7 +152,7 @@ public class Account implements BaseAccount {
     private boolean mAllowRemoteSearch;
     private boolean mRemoteSearchFullText;
     private int mRemoteSearchNumResults;
-    
+
     private CryptoProvider mCryptoProvider = null;
 
     /**
@@ -399,7 +399,7 @@ private synchronized void loadAccount(Preferences preferences) {
         mAllowRemoteSearch = prefs.getBoolean(mUuid + ".allowRemoteSearch", false);
         mRemoteSearchFullText = prefs.getBoolean(mUuid + ".remoteSearchFullText", false);
         mRemoteSearchNumResults = prefs.getInt(mUuid + ".remoteSearchNumResults", DEFAULT_REMOTE_SEARCH_NUM_RESULTS);
-        
+
         mEnabled = prefs.getBoolean(mUuid + ".enabled", true);
     }
 
@@ -1458,11 +1458,11 @@ public boolean isCryptoAutoEncrypt() {
     public void setCryptoAutoEncrypt(boolean cryptoAutoEncrypt) {
         mCryptoAutoEncrypt = cryptoAutoEncrypt;
     }
-    
+
     public boolean allowRemoteSearch() {
         return mAllowRemoteSearch;
     }
-    
+
     public void setAllowRemoteSearch(boolean val){
         mAllowRemoteSearch = val;
     }
@@ -1470,11 +1470,11 @@ public void setAllowRemoteSearch(boolean val){
     public int getRemoteSearchNumResults(){
         return mRemoteSearchNumResults;
     }
-    
+
     public void setRemoteSearchNumResults(int val){
         mRemoteSearchNumResults = (val >= 0 ? val : 0);
     }
-    
+
     public String getInboxFolderName() {
         return mInboxFolderName;
     }
@@ -1531,7 +1531,7 @@ public synchronized void setEnabled(boolean enabled) {
     }
 
     public boolean getRemoteSearchFullText() {
-        
+
         return mRemoteSearchFullText;
     }
 
diff --git a/src/com/fsck/k9/activity/ChooseFolder.java b/src/com/fsck/k9/activity/ChooseFolder.java
index dd8cc17d525..5f535d391b2 100644
--- a/src/com/fsck/k9/activity/ChooseFolder.java
+++ b/src/com/fsck/k9/activity/ChooseFolder.java
@@ -232,17 +232,17 @@ private void onEnterFilter() {
 
         final EditText input = new EditText(this);
         input.addTextChangedListener(new TextWatcher() {
-            
+
             @Override
             public void onTextChanged(CharSequence s, int start, int before, int count) {
                 mAdapter.getFilter().filter(input.getText().toString());
             }
-            
+
             @Override
             public void beforeTextChanged(CharSequence s, int start, int count,
                     int after) {
             }
-            
+
             @Override
             public void afterTextChanged(Editable s) {
             }
diff --git a/src/com/fsck/k9/activity/MessageList.java b/src/com/fsck/k9/activity/MessageList.java
index f1253ac6a8e..2997a48999c 100644
--- a/src/com/fsck/k9/activity/MessageList.java
+++ b/src/com/fsck/k9/activity/MessageList.java
@@ -256,7 +256,7 @@ public int compare(MessageInfoHolder arg0, MessageInfoHolder arg1) {
         SORT_COMPARATORS = Collections.unmodifiableMap(map);
     }
 
-    
+
     private ListView mListView;
 
     private boolean mTouchView = true;
@@ -422,7 +422,7 @@ public void run() {
             });
         }
 
-        
+
         public void updateFooter(final String text, final boolean progressVisible){
             runOnUiThread(new Runnable(){
                 public void run(){
@@ -434,13 +434,13 @@ public void run(){
                 }
             });
         }
-        
+
         public void setWindowProgress(final int amt){
             runOnUiThread(new Runnable(){public void run(){
                 getWindow().setFeatureInt(Window.FEATURE_PROGRESS, amt);
             }});
         }
-        
+
         private void resetUnreadCount() {
             runOnUiThread(new Runnable() {
                 @Override
@@ -745,7 +745,7 @@ private void initializeMessageList(Intent intent, boolean create) {
             // So just leave the activity in the state it was left in.
             return;
         }
-        
+
         mQueryString = intent.getStringExtra(SearchManager.QUERY);
         mFolderName = null;
         mRemoteSearch = false;
@@ -764,11 +764,11 @@ private void initializeMessageList(Intent intent, boolean create) {
             else{
                 mSearchAccount = intent.getStringExtra(EXTRA_SEARCH_ACCOUNT);
                 mSearchFolder = intent.getStringExtra(EXTRA_SEARCH_FOLDER);
-                
+
             }
         }
 
-        
+
         mQueryString = intent.getStringExtra(SearchManager.QUERY);
         mFolderName = null;
         mRemoteSearch = false;
@@ -787,13 +787,13 @@ private void initializeMessageList(Intent intent, boolean create) {
             else{
                 mSearchAccount = intent.getStringExtra(EXTRA_SEARCH_ACCOUNT);
                 mSearchFolder = intent.getStringExtra(EXTRA_SEARCH_FOLDER);
-                
+
             }
         }
 
         String accountUuid = intent.getStringExtra(EXTRA_ACCOUNT);
         mFolderName = intent.getStringExtra(EXTRA_FOLDER);
-        
+
         mAccount = Preferences.getPreferences(this).getAccount(accountUuid);
 
         if (mAccount != null && !mAccount.isAvailable(this)) {
@@ -923,7 +923,7 @@ public void onResume() {
             mController.notifyAccountCancel(this, accountWithNotification);
         }
 
-        
+
         if (mAdapter.messages.isEmpty()) {
             if (mRemoteSearch){
                 //TODO: Support flag based search
@@ -941,7 +941,7 @@ else if (mFolderName != null) {
             new Thread() {
                 @Override
                 public void run() {
-                    
+
 
                     if (!mRemoteSearch){
                         mAdapter.markAllMessagesAsDirty();
@@ -961,7 +961,7 @@ public void run() {
                     }
 
 
-                    
+
                 }
 
             }
@@ -1283,11 +1283,11 @@ private void onEditPrefs() {
     private void onEditAccount() {
         AccountSettings.actionSettings(this, mAccount);
     }
-    
-    
+
+
     @Override
     public boolean onSearchRequested() {
-         
+
          if(mAccount != null && mCurrentFolder != null && mAccount.allowRemoteSearch()){
              //if in a SSSable folder, ask user what they want.
              //TODO: Add ability to remember selection?
@@ -1299,7 +1299,7 @@ public boolean onSearchRequested() {
              builder.setTitle(getString(R.string.search_mode_title));
              builder.setItems(items, new DialogInterface.OnClickListener() {
                  public void onClick(DialogInterface dialog, int item) {
-                     
+
                      Bundle appData = null;
                      if(item == 1){
                          appData = new Bundle();
@@ -1308,16 +1308,16 @@ public void onClick(DialogInterface dialog, int item) {
                          appData.putBoolean(EXTRA_REMOTE_SEARCH, true);
                      }
                      //else do regular search, which doesn't require any special parameter setup
-                     
+
                      startSearch(null, false, appData, false);
                  }
              });
              AlertDialog alert = builder.create();
              alert.show();
-             
+
              return true;
          }
-         
+
          startSearch(null, false, null, false);
          return true;
      }
@@ -1964,17 +1964,17 @@ class MessageListAdapter extends BaseAdapter {
 
         private final ActivityListener mListener = new ActivityListener() {
 
-            
+
             @Override
             public void remoteSearchAddMessage(Account account, String folderName, Message message, final int numDone, final int numTotal) {
-                
+
                 if(numTotal > 0){
                     mHandler.setWindowProgress(Window.PROGRESS_END/numTotal * numDone);
                 }
                 else{
                     mHandler.setWindowProgress(Window.PROGRESS_END);
                 }
-                
+
                 //MessageView expects messages to be in the LocalStore, so add them
                 try{
                     LocalFolder localFolder = account.getLocalStore().getFolder(folderName);
@@ -1984,7 +1984,7 @@ public void remoteSearchAddMessage(Account account, String folderName, Message m
                             localFolder.appendMessages(messages);
                         }//else: the message is already in the local store so don't worry about it
                     }//else: should never really happen
-                    
+
                 }
                 catch(MessagingException e){
                     //FIXME: Do something useful here...
@@ -1992,7 +1992,7 @@ public void remoteSearchAddMessage(Account account, String folderName, Message m
                         Log.d("IMAP search", "remoteSearchAddMessage caught error: " + e.toString());
                     }
                 }
-                
+
                 addOrUpdateMessages(account, folderName, Collections.singletonList(message), false);
             }
 
@@ -2010,7 +2010,7 @@ public void remoteSearchStarted(Account acct, String folder){
                 mHandler.progress(true);
                 mHandler.updateFooter(getString(R.string.remote_search_sending_query), true);
             }
-            
+
 
             @Override
             public void remoteSearchFinished(Account acct, String folder, int numResults){
@@ -2018,9 +2018,9 @@ public void remoteSearchFinished(Account acct, String folder, int numResults){
                 mHandler.updateFooter("", false);
                 mHandler.setWindowProgress(Window.PROGRESS_END);
             }
-            
+
             @Override
-            public void remoteSearchServerQueryComplete(Account account, String folderName, int numResults){ 
+            public void remoteSearchServerQueryComplete(Account account, String folderName, int numResults){
                 mHandler.progress(true);
                 if(account != null &&  account.getRemoteSearchNumResults() != 0 && numResults > account.getRemoteSearchNumResults()){
                     mHandler.updateFooter(getString(R.string.remote_search_downloading_limited, account.getRemoteSearchNumResults(), numResults), true);
@@ -2030,9 +2030,9 @@ public void remoteSearchServerQueryComplete(Account account, String folderName,
                 }
                 mHandler.setWindowProgress(Window.PROGRESS_START);
             }
-            
-            
-            
+
+
+
             @Override
             public void informUserOfStatus() {
                 mHandler.refreshTitle();
diff --git a/src/com/fsck/k9/activity/setup/AccountSettings.java b/src/com/fsck/k9/activity/setup/AccountSettings.java
index da995689d2d..3193ec940b8 100644
--- a/src/com/fsck/k9/activity/setup/AccountSettings.java
+++ b/src/com/fsck/k9/activity/setup/AccountSettings.java
@@ -57,7 +57,7 @@ public class AccountSettings extends K9PreferenceActivity {
     private static final String PREFERENCE_SCREEN_INCOMING = "incoming_prefs";
     private static final String PREFERENCE_SCREEN_PUSH_ADVANCED = "push_advanced";
     private static final String PREFERENCE_SCREEN_REMOTE_SEARCH = "remote_search";
-    
+
     private static final String PREFERENCE_DESCRIPTION = "account_description";
     private static final String PREFERENCE_COMPOSITION = "composition";
     private static final String PREFERENCE_MANAGE_IDENTITIES = "manage_identities";
@@ -440,7 +440,7 @@ public boolean onPreferenceChange(Preference preference, Object newValue) {
         mAccountDefault.setChecked(
             mAccount.equals(Preferences.getPreferences(this).getDefaultAccount()));
 
-        
+
         mAccountEnableMoveButtons = (CheckBoxPreference) findPreference(PREFERENCE_ENABLE_MOVE_BUTTONS);
         mAccountEnableMoveButtons.setEnabled(mIsMoveCapable);
         mAccountEnableMoveButtons.setChecked(mAccount.getEnableMoveButtons());
@@ -483,12 +483,12 @@ public boolean onPreferenceChange(Preference preference, Object newValue) {
                 }
             });
         }
-        
-        
+
+
         // IMAP-specific preferences
         mAllowRemoteSearch = (CheckBoxPreference) findPreference(PREFERENCE_ALLOW_REMOTE_SEARCH);
-        
-        mAllowRemoteSearch.setOnPreferenceChangeListener(new OnPreferenceChangeListener() { 
+
+        mAllowRemoteSearch.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
                                                             public boolean onPreferenceChange(Preference pref, Object newVal){
                                                                 if((Boolean) newVal){
                                                                     showRemoteSearchHelp();
@@ -507,7 +507,7 @@ public boolean onPreferenceChange(Preference pref, Object newVal){
             mAllowRemoteSearch.setChecked(mAccount.allowRemoteSearch());
             mRemoteSearchNumResults.setValue(Integer.toString(mAccount.getRemoteSearchNumResults()));
             mRemoteSearchFullText.setChecked(mAccount.getRemoteSearchFullText());
-            
+
             mIdleRefreshPeriod.setValue(String.valueOf(mAccount.getIdleRefreshMinutes()));
             mIdleRefreshPeriod.setSummary(mIdleRefreshPeriod.getEntry());
             mIdleRefreshPeriod.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
@@ -519,7 +519,7 @@ public boolean onPreferenceChange(Preference preference, Object newValue) {
                     return false;
                 }
             });
- 
+
             mMaxPushFolders.setValue(String.valueOf(mAccount.getMaxPushFolders()));
             mMaxPushFolders.setSummary(mMaxPushFolders.getEntry());
             mMaxPushFolders.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
@@ -547,9 +547,9 @@ public boolean onPreferenceChange(Preference preference, Object newValue) {
             final PreferenceScreen incomingPrefs = (PreferenceScreen) findPreference(PREFERENCE_SCREEN_INCOMING);
             incomingPrefs.removePreference( (PreferenceScreen) findPreference(PREFERENCE_SCREEN_PUSH_ADVANCED));
             incomingPrefs.removePreference( (ListPreference) findPreference(PREFERENCE_PUSH_MODE));
-            
+
             ((PreferenceScreen) findPreference("main")).removePreference((PreferenceScreen) findPreference(PREFERENCE_SCREEN_REMOTE_SEARCH));
-            
+
         }
 
         mAccountNotify = (CheckBoxPreference) findPreference(PREFERENCE_NOTIFY);
@@ -716,7 +716,7 @@ public void onClick(DialogInterface dialog, int which) {
                });
            adb.create().show();
         }
-        
+
     }
 
     private void handleCryptoAppDependencies() {
diff --git a/src/com/fsck/k9/controller/MessagingController.java b/src/com/fsck/k9/controller/MessagingController.java
index 002b8c000fb..11776bf0f76 100644
--- a/src/com/fsck/k9/controller/MessagingController.java
+++ b/src/com/fsck/k9/controller/MessagingController.java
@@ -815,7 +815,7 @@ public void run() {
             }
         });
     }
-    public void searchRemoteMessagesSynchronous(final String acctUuid, final String folderName, final String query, 
+    public void searchRemoteMessagesSynchronous(final String acctUuid, final String folderName, final String query,
             final Flag[] requiredFlags, final Flag[] forbiddenFlags, final MessagingListener listener){
         final Account acct = Preferences.getPreferences(mApplication.getApplicationContext()).getAccount(acctUuid);
         final AccountStats stats = new AccountStats();
@@ -824,16 +824,16 @@ public void searchRemoteMessagesSynchronous(final String acctUuid, final String
             listener.remoteSearchStarted(acct, folderName);
         }
 
-        
+
         MessageRetrievalListener retrievalListener = new MessageRetrievalListener() {
             @Override
             public void messageStarted(String message, int number, int ofTotal) {
-                
+
             }
             @Override
             public void messageFinished(Message message, int number, int ofTotal){
-                
-                
+
+
                 if (!isMessageSuppressed(message.getFolder().getAccount(), message.getFolder().getName(), message)) {
                     stats.unreadMessageCount += (!message.isSet(Flag.SEEN)) ? 1 : 0;
                     stats.flaggedMessageCount += (message.isSet(Flag.FLAGGED)) ? 1 : 0;
@@ -848,7 +848,7 @@ public void messagesFinished(int number) {
 
             }
         };
-        
+
         SearchListener searchListener = new SearchListener(){
 
             @Override
diff --git a/src/com/fsck/k9/controller/MessagingListener.java b/src/com/fsck/k9/controller/MessagingListener.java
index 0fd87e3881a..8c7fbf6a20c 100644
--- a/src/com/fsck/k9/controller/MessagingListener.java
+++ b/src/com/fsck/k9/controller/MessagingListener.java
@@ -151,36 +151,36 @@ public void pendingCommandCompleted(Account account, String commandTitle) {}
 
     public void pendingCommandsFinished(Account account) {}
 
-    
+
     /**
      * Called when a remote search is started
-     * 
+     *
      * @param acct
      * @param folder
      */
     public void remoteSearchStarted(Account acct, String folder){}
-    
-    
+
+
     /**
      * Called when server has responded to our query.  Messages have not yet been downloaded.
-     * 
+     *
      * @param numResults
      */
     public void remoteSearchServerQueryComplete(Account account, String folderName, int numResults){ }
-    
-    
+
+
     /**
      * Called when a new result message is available for a remote search
      * Can assume headers have been downloaded, but potentially not body.
-     * @param account 
-     * @param folder 
+     * @param account
+     * @param folder
      * @param message
      */
     public void remoteSearchAddMessage(Account account, String folder, Message message, int numDone, int numTotal){ }
-    
+
     /**
      * Called when Remote Search is fully complete
-     * 
+     *
      * @param acct
      * @param folder
      * @param numResults
@@ -189,13 +189,13 @@ public void remoteSearchFinished(Account acct, String folder, int numResults) {}
 
     /**
      * Called when there was a problem with a remote search operation.
-     * 
+     *
      * @param acct
      * @param folder
      * @param err
      */
     public void remoteSearchFailed(Account acct, String folder, String err){ }
-    
+
     /**
      * General notification messages subclasses can override to be notified that the controller
      * has completed a command. This is useful for turning off progress indicators that may have
diff --git a/src/com/fsck/k9/mail/Message.java b/src/com/fsck/k9/mail/Message.java
index e25307bc4b8..67430adce75 100644
--- a/src/com/fsck/k9/mail/Message.java
+++ b/src/com/fsck/k9/mail/Message.java
@@ -148,12 +148,12 @@ public boolean isMimeType(String mimeType) throws MessagingException {
     public abstract boolean ccMe();
     public abstract boolean bccMe();
     public abstract long getId();
-    
+
     public abstract String getPreview();
     public abstract boolean hasAttachments();
-    
-    
-    
+
+
+
     public void delete(String trashFolderName) throws MessagingException {}
 
     /*
diff --git a/src/com/fsck/k9/mail/Store.java b/src/com/fsck/k9/mail/Store.java
index 4865810dbe7..50350a2d0e1 100644
--- a/src/com/fsck/k9/mail/Store.java
+++ b/src/com/fsck/k9/mail/Store.java
@@ -179,7 +179,7 @@ public Pusher getPusher(PushReceiver receiver) {
     public Account getAccount() {
         return mAccount;
     }
-    
+
     public void searchRemoteMessages(MessageRetrievalListener msgListener, SearchListener searchListener, String queryString,
             String folder,  final Flag[] requiredFlags, final Flag[] forbiddenFlags) throws MessagingException{
         throw new MessagingException("K-9 does not support remote searching on this account type");
diff --git a/src/com/fsck/k9/mail/internet/MimeMessage.java b/src/com/fsck/k9/mail/internet/MimeMessage.java
index 84255bf57f2..05a84967d6a 100644
--- a/src/com/fsck/k9/mail/internet/MimeMessage.java
+++ b/src/com/fsck/k9/mail/internet/MimeMessage.java
@@ -587,27 +587,27 @@ public MimeMessage clone() {
         copy(message);
         return message;
     }
-    
+
     public boolean toMe(){
         return false;
     }
-    
+
     public boolean ccMe(){
         return false;
     }
-    
+
     public boolean bccMe(){
         return false;
     }
-    
+
     public long getId(){
         return Long.parseLong(mUid); //or maybe .mMessageId?
     }
-    
+
     public String getPreview(){
         return "my_preview";
     }
-    
+
     public boolean hasAttachments(){
         return false;
     }
diff --git a/src/com/fsck/k9/mail/store/ImapStore.java b/src/com/fsck/k9/mail/store/ImapStore.java
index cb4ff838eb5..ed45d48d0b7 100644
--- a/src/com/fsck/k9/mail/store/ImapStore.java
+++ b/src/com/fsck/k9/mail/store/ImapStore.java
@@ -1171,8 +1171,8 @@ private int getRemoteMessageCount(String criteria) throws MessagingException {
 
 
         }
-        
-        public void doRemoteSearch(final String queryString, final Flag[] requiredFlags, final Flag [] forbiddenFlags, final MessageRetrievalListener msgListener, final SearchListener searchListener) 
+
+        public void doRemoteSearch(final String queryString, final Flag[] requiredFlags, final Flag [] forbiddenFlags, final MessageRetrievalListener msgListener, final SearchListener searchListener)
                 throws MessagingException{
             ImapSearcher searcher = new ImapSearcher(){
                 public List search() throws IOException, MessagingException {
@@ -1183,23 +1183,23 @@ public List search() throws IOException, MessagingException {
                             case DELETED:
                                 imapQuery += "DELETED ";
                                 break;
-                                
+
                             case SEEN:
                                 imapQuery +=  "SEEN ";
                                 break;
-                                
+
                             case ANSWERED:
                                 imapQuery += "ANSWERED ";
                                 break;
-                                
+
                             case FLAGGED:
                                 imapQuery += "FLAGGED ";
                                 break;
-                                
+
                             case DRAFT:
                                 imapQuery += "DRAFT ";
                                 break;
-                                
+
                             case RECENT:
                                 imapQuery += "RECENT ";
                                 break;
@@ -1212,23 +1212,23 @@ public List search() throws IOException, MessagingException {
                             case DELETED:
                                 imapQuery += "UNDELETED ";
                                 break;
-                                
+
                             case SEEN:
                                 imapQuery +=  "UNSEEN ";
                                 break;
-                                
+
                             case ANSWERED:
                                 imapQuery += "UNANSWERED ";
                                 break;
-                                
+
                             case FLAGGED:
                                 imapQuery += "UNFLAGGED ";
                                 break;
-                                
+
                             case DRAFT:
                                 imapQuery += "UNDRAFT ";
                                 break;
-                                
+
                             case RECENT:
                                 imapQuery += "UNRECENT ";
                                 break;
@@ -1245,7 +1245,7 @@ public List search() throws IOException, MessagingException {
                     return executeSimpleCommand(imapQuery);
                 }
             };
-            
+
             search(searcher, msgListener, searchListener, (mAccount != null ? mAccount.getRemoteSearchNumResults() : 0), true);
         }
 
@@ -1341,19 +1341,19 @@ public List search() throws IOException, MessagingException {
         private Message[] search(ImapSearcher searcher, MessageRetrievalListener listener) throws MessagingException {
             return search(searcher, listener, null, 0, false);
         }
-        
+
         private Message[] search(ImapSearcher searcher, MessageRetrievalListener msgListener, SearchListener searchListener, int limit, boolean getHeaders) throws MessagingException {
 
             checkOpen(); //only need READ access
             ArrayList messages = new ArrayList();
             try {
                 ArrayList uids = new ArrayList();
-                
+
                 if(searchListener != null){
                     searchListener.searchStarted();
                 }
-                
-                List responses = searcher.search(); 
+
+                List responses = searcher.search();
 
                 for (ImapResponse response : responses) {
                     if (response.mTag == null) {
@@ -1364,35 +1364,35 @@ private Message[] search(ImapSearcher searcher, MessageRetrievalListener msgList
                         }
                     }
                 }
-                
+
                 if(searchListener != null){
                     searchListener.searchFinished(uids.size());
                 }
 
-                // Sort the uids in numerically decreasing order 
+                // Sort the uids in numerically decreasing order
                 // By doing it in decreasing order, we ensure newest messages are dealt with first
                 // This makes the most sense when a limit is imposed, and also prevents UI from going
                 // crazy adding stuff at the top.
                 Collections.sort(uids, Collections.reverseOrder());
-                
-                FetchProfile fp = new FetchProfile(); 
+
+                FetchProfile fp = new FetchProfile();
                 if(getHeaders){
                     fp.add(FetchProfile.Item.ENVELOPE);
                     fp.add(FetchProfile.Item.FLAGS);
                     fp.add(FetchProfile.Item.STRUCTURE);
                 }
-                
+
                 if(K9.DEBUG){
                     Log.i("IMAP search", "Search results: " + uids.size() + ", limit: " + limit);
                     Log.i("IMAP search", "Uids: " + Arrays.toString(uids.toArray()));
                 }
-                
+
                 for (int i = 0, count = (limit==0 ? uids.size() : Math.min(uids.size(), limit)); i < count; i++) {
                     if (msgListener != null) {
                         msgListener.messageStarted("" + uids.get(i), i, count);
                     }
                     ImapMessage message = new ImapMessage("" + uids.get(i), this);
-                    
+
                     if(getHeaders){
                         Message [] msgArray = {message};
                         if(K9.DEBUG){
@@ -1400,7 +1400,7 @@ private Message[] search(ImapSearcher searcher, MessageRetrievalListener msgList
                         }
                         fetch(msgArray, fp, null); //don't pass the listener since we're already updating it
                     }
-                    
+
                     messages.add(message);
                     if (msgListener != null) {
                         msgListener.messageFinished(message, i, count);
@@ -1409,13 +1409,13 @@ private Message[] search(ImapSearcher searcher, MessageRetrievalListener msgList
             } catch (IOException ioe) {
                 throw ioExceptionHandler(mConnection, ioe);
             }
-            
+
             Message [] msgArray = messages.toArray(EMPTY_MESSAGE_ARRAY);
-            
+
             /*
              * Doing this here makes it one batch, but the UI spends a long time with (no subject) stuff, etc.
              * Therefore, at least for now, should fetch headers individually as we fetch the messages.
-             * 
+             *
             if(getHeaders){
                 fetch(msgArray, fp, listener);
             }*/
@@ -2124,7 +2124,7 @@ public String getNewPushState(String oldPushStateS, Message message) {
         @Override
         public void setFlags(Message[] messages, Flag[] flags, boolean value)
         throws MessagingException {
-            open(OpenMode.READ_WRITE); 
+            open(OpenMode.READ_WRITE);
             checkOpen();
             String[] uids = new String[messages.length];
             for (int i = 0, count = messages.length; i < count; i++) {
@@ -3404,35 +3404,35 @@ public Object foundLiteral(ImapResponse response,
             return null;
         }
     }
-    
+
     @Override
     public void searchRemoteMessages(final MessageRetrievalListener msgListener, final SearchListener searchListener, final String queryString,
             final String folderName,  final Flag[] requiredFlags, final Flag[] forbiddenFlags) throws MessagingException{
-        
+
         if(!mAccount.allowRemoteSearch()){
             throw new MessagingException("Your settings do not allow remote searching of this account");
         }
-        
+
         final ImapFolder folder = (ImapFolder) getFolder(folderName);
         if(folder == null){
             throw new MessagingException("Invalid folder specified");
         }
-        
+
         try{
             folder.open(OpenMode.READ_ONLY);
             folder.checkOpen();
-            
-            
+
+
             folder.doRemoteSearch(queryString, requiredFlags, forbiddenFlags, msgListener, searchListener);
-            
+
         }
         catch(Exception e){
             e.printStackTrace();
             throw new MessagingException("Error during search: " + e.toString());
         }
-        
+
     }
-    
-    
+
+
 
 }
diff --git a/src/com/fsck/k9/mail/store/LocalStore.java b/src/com/fsck/k9/mail/store/LocalStore.java
index d6ae3e0e14f..44794d02d5f 100644
--- a/src/com/fsck/k9/mail/store/LocalStore.java
+++ b/src/com/fsck/k9/mail/store/LocalStore.java
@@ -1138,7 +1138,7 @@ public long getId() {
 
         @Override
         public void open(final OpenMode mode) throws MessagingException {
-            
+
             if (isOpen() && (getMode() == mode || mode==OpenMode.READ_ONLY)) {
                 return;
             }
@@ -1147,7 +1147,7 @@ else if (isOpen()){
                 //so close connection and reopen
                 close();
             }
-            
+
             try {
                 database.execute(false, new DbCallback() {
                     @Override
diff --git a/src/com/fsck/k9/provider/MessageProvider.java b/src/com/fsck/k9/provider/MessageProvider.java
index f2c1ec6938c..8ea4f4847f8 100644
--- a/src/com/fsck/k9/provider/MessageProvider.java
+++ b/src/com/fsck/k9/provider/MessageProvider.java
@@ -60,7 +60,7 @@ public static interface MessageColumns extends BaseColumns {
          * 

Type: TEXT

*/ String SENDER = "sender"; - + /** *

Type: TEXT

*/ From c5d7e4e36a05d18664432d28d4b9aeac33f3b040 Mon Sep 17 00:00:00 2001 From: Rob Bayer Date: Fri, 2 Mar 2012 18:47:08 -0800 Subject: [PATCH 16/21] Don't hide Crypto when IMAPsearch disabled --- res/xml/account_settings_preferences.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/xml/account_settings_preferences.xml b/res/xml/account_settings_preferences.xml index 2864cfa0a36..86b871105dc 100644 --- a/res/xml/account_settings_preferences.xml +++ b/res/xml/account_settings_preferences.xml @@ -450,7 +450,7 @@ + android:key="crypto"> Date: Fri, 2 Mar 2012 19:10:03 -0800 Subject: [PATCH 17/21] remove duplicated code block --- src/com/fsck/k9/activity/MessageList.java | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/src/com/fsck/k9/activity/MessageList.java b/src/com/fsck/k9/activity/MessageList.java index 2997a48999c..5a10a104b86 100644 --- a/src/com/fsck/k9/activity/MessageList.java +++ b/src/com/fsck/k9/activity/MessageList.java @@ -746,29 +746,6 @@ private void initializeMessageList(Intent intent, boolean create) { return; } - mQueryString = intent.getStringExtra(SearchManager.QUERY); - mFolderName = null; - mRemoteSearch = false; - mSearchAccount = null; - mSearchFolder = null; - if(mQueryString != null){ - if (Intent.ACTION_SEARCH.equals(intent.getAction())) { - //Query was received from Search Dialog - Bundle appData = getIntent().getBundleExtra(SearchManager.APP_DATA); - if(appData != null){ - mSearchAccount = appData.getString(EXTRA_SEARCH_ACCOUNT); - mSearchFolder = appData.getString(EXTRA_SEARCH_FOLDER); - mRemoteSearch = appData.getBoolean(EXTRA_REMOTE_SEARCH); - } - } - else{ - mSearchAccount = intent.getStringExtra(EXTRA_SEARCH_ACCOUNT); - mSearchFolder = intent.getStringExtra(EXTRA_SEARCH_FOLDER); - - } - } - - mQueryString = intent.getStringExtra(SearchManager.QUERY); mFolderName = null; mRemoteSearch = false; From b3569e5790d47d4ce39374cff63afb4c1b2cf1da Mon Sep 17 00:00:00 2001 From: Rob Bayer Date: Sun, 4 Mar 2012 12:35:37 -0800 Subject: [PATCH 18/21] Prevent delete of search results while search results open --- src/com/fsck/k9/activity/MessageList.java | 23 +++++++++-- src/com/fsck/k9/activity/Search.java | 22 +++++++++- .../k9/controller/MessagingController.java | 18 +++++--- src/com/fsck/k9/mail/Message.java | 5 +-- .../fsck/k9/mail/internet/MimeMessage.java | 41 ++++++++++++------- src/com/fsck/k9/mail/store/LocalStore.java | 35 ++++++++++------ 6 files changed, 105 insertions(+), 39 deletions(-) diff --git a/src/com/fsck/k9/activity/MessageList.java b/src/com/fsck/k9/activity/MessageList.java index 5a10a104b86..675d5b893ef 100644 --- a/src/com/fsck/k9/activity/MessageList.java +++ b/src/com/fsck/k9/activity/MessageList.java @@ -877,6 +877,14 @@ public void onResume() { onAccountUnavailable(); return; } + + + if(! (this instanceof Search)){ + //necessary b/c no guarantee Search.onStop will be called before MessageList.onResume + //when returning from search results + Search.setActive(false); + } + StorageManager.getInstance(getApplication()).addListener(mStorageListener); mStars = K9.messageListStars(); @@ -1187,8 +1195,9 @@ public boolean onKeyUp(int keyCode, KeyEvent event) { // Swallow these events too to avoid the audible notification of a volume change if (K9.useVolumeKeysForListNavigationEnabled()) { if ((keyCode == KeyEvent.KEYCODE_VOLUME_UP) || (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN)) { - if (K9.DEBUG) + if (K9.DEBUG) { Log.v(K9.LOG_TAG, "Swallowed key up."); + } return true; } } @@ -1956,10 +1965,18 @@ public void remoteSearchAddMessage(Account account, String folderName, Message m try{ LocalFolder localFolder = account.getLocalStore().getFolder(folderName); if(localFolder != null){ - if(localFolder.getMessage(message.getUid()) == null){ + Message localMessage = localFolder.getMessage(message.getUid()); + if(localMessage == null){ + //add message to LocalStore so MessageView can pick it up Message [] messages = {message}; localFolder.appendMessages(messages); - }//else: the message is already in the local store so don't worry about it + message = localFolder.getMessage(message.getUid()); + } + else{ + //use LocalStore's copy as it might have body, etc downloaded + //TODO: update LocalStore's copy if ours has newer flags? + message = localMessage; + } }//else: should never really happen } diff --git a/src/com/fsck/k9/activity/Search.java b/src/com/fsck/k9/activity/Search.java index 3f2a2a07798..e022115a250 100644 --- a/src/com/fsck/k9/activity/Search.java +++ b/src/com/fsck/k9/activity/Search.java @@ -1,7 +1,27 @@ package com.fsck.k9.activity; -import com.fsck.k9.activity.MessageList; public class Search extends MessageList { + protected static boolean isActive = false; + + public static boolean isActive() { return isActive;} + + public static void setActive(boolean val){ + isActive = val; + } + + @Override + public void onStart(){ + setActive(true); + super.onStart(); + } + + @Override + public void onStop(){ + setActive(false); + super.onStop(); + } + + } diff --git a/src/com/fsck/k9/controller/MessagingController.java b/src/com/fsck/k9/controller/MessagingController.java index 11776bf0f76..59d8ac13c0d 100644 --- a/src/com/fsck/k9/controller/MessagingController.java +++ b/src/com/fsck/k9/controller/MessagingController.java @@ -280,8 +280,9 @@ public void run() { if (command != null) { commandDescription = command.description; - if (K9.DEBUG) + if (K9.DEBUG) { Log.i(K9.LOG_TAG, "Running " + (command.isForeground ? "Foreground" : "Background") + " command '" + command.description + "', seq = " + command.sequence); + } mBusy = true; try { @@ -303,9 +304,10 @@ public void run() { } .start(); } - if (K9.DEBUG) + if (K9.DEBUG) { Log.i(K9.LOG_TAG, (command.isForeground ? "Foreground" : "Background") + " Command '" + command.description + "' completed"); + } for (MessagingListener l : getListeners(command.listener)) { l.controllerCommandCompleted(!mCommands.isEmpty()); @@ -557,7 +559,7 @@ public void listLocalMessagesSynchronous(final Account account, final String fol l.listLocalMessagesStarted(account, folder); } - Folder localFolder = null; + LocalFolder localFolder = null; MessageRetrievalListener retrievalListener = new MessageRetrievalListener() { List pendingMessages = new ArrayList(); @@ -599,16 +601,20 @@ private void addPendingMessages() { try { - Store localStore = account.getLocalStore(); + LocalStore localStore = account.getLocalStore(); localFolder = localStore.getFolder(folder); localFolder.open(OpenMode.READ_WRITE); + //Purging followed by getting requires 2 DB queries. + //TODO: Fix getMessages to allow auto-pruning at visible limit? + localFolder.purgeToVisibleLimit(null); localFolder.getMessages( retrievalListener, false // Skip deleted messages ); - if (K9.DEBUG) + if (K9.DEBUG) { Log.v(K9.LOG_TAG, "Got ack that callbackRunner finished"); + } for (MessagingListener l : getListeners(listener)) { l.listLocalMessagesFinished(account, folder); @@ -3236,7 +3242,7 @@ public void sendPendingMessagesSynchronous(final Account account) { // This is a complete hack, but is worlds better than the previous // "don't even bother" functionality if (getRootCauseMessage(e).startsWith("5")) { - localFolder.moveMessages(new Message[] { message }, (LocalFolder) localStore.getFolder(account.getDraftsFolderName())); + localFolder.moveMessages(new Message[] { message }, localStore.getFolder(account.getDraftsFolderName())); } else { } diff --git a/src/com/fsck/k9/mail/Message.java b/src/com/fsck/k9/mail/Message.java index 67430adce75..511d42d6377 100644 --- a/src/com/fsck/k9/mail/Message.java +++ b/src/com/fsck/k9/mail/Message.java @@ -1,19 +1,18 @@ package com.fsck.k9.mail; +import java.io.IOException; import java.util.Date; import java.util.HashSet; import java.util.Set; -import java.io.IOException; import android.util.Log; +import com.fsck.k9.K9; import com.fsck.k9.activity.MessageReference; import com.fsck.k9.mail.filter.CountingOutputStream; import com.fsck.k9.mail.filter.EOLConvertingOutputStream; - import com.fsck.k9.mail.store.UnavailableStorageException; -import com.fsck.k9.K9; public abstract class Message implements Part, Body { diff --git a/src/com/fsck/k9/mail/internet/MimeMessage.java b/src/com/fsck/k9/mail/internet/MimeMessage.java index 05a84967d6a..8f5d2c6c2a2 100644 --- a/src/com/fsck/k9/mail/internet/MimeMessage.java +++ b/src/com/fsck/k9/mail/internet/MimeMessage.java @@ -1,24 +1,37 @@ package com.fsck.k9.mail.internet; -import com.fsck.k9.mail.*; -import com.fsck.k9.mail.store.UnavailableStorageException; +import java.io.BufferedWriter; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.LinkedList; +import java.util.Locale; +import java.util.Set; +import java.util.UUID; -import org.apache.james.mime4j.stream.BodyDescriptor; -import org.apache.james.mime4j.stream.RawField; -import org.apache.james.mime4j.parser.ContentHandler; -import org.apache.james.mime4j.io.EOLConvertingInputStream; -import org.apache.james.mime4j.parser.MimeStreamParser; -import org.apache.james.mime4j.stream.MimeEntityConfig; +import org.apache.james.mime4j.MimeException; import org.apache.james.mime4j.dom.field.DateTimeField; import org.apache.james.mime4j.dom.field.Field; import org.apache.james.mime4j.field.DefaultFieldParser; +import org.apache.james.mime4j.io.EOLConvertingInputStream; +import org.apache.james.mime4j.parser.ContentHandler; +import org.apache.james.mime4j.parser.MimeStreamParser; +import org.apache.james.mime4j.stream.BodyDescriptor; +import org.apache.james.mime4j.stream.MimeEntityConfig; +import org.apache.james.mime4j.stream.RawField; -import org.apache.james.mime4j.MimeException; - -import java.io.*; -import java.text.SimpleDateFormat; -import java.util.*; +import com.fsck.k9.mail.Address; +import com.fsck.k9.mail.Body; +import com.fsck.k9.mail.BodyPart; +import com.fsck.k9.mail.Message; +import com.fsck.k9.mail.MessagingException; +import com.fsck.k9.mail.Multipart; +import com.fsck.k9.mail.Part; +import com.fsck.k9.mail.store.UnavailableStorageException; /** * An implementation of Message that stores all of it's metadata in RFC 822 and @@ -605,7 +618,7 @@ public long getId(){ } public String getPreview(){ - return "my_preview"; + return ""; } public boolean hasAttachments(){ diff --git a/src/com/fsck/k9/mail/store/LocalStore.java b/src/com/fsck/k9/mail/store/LocalStore.java index 44794d02d5f..306b7e13c93 100644 --- a/src/com/fsck/k9/mail/store/LocalStore.java +++ b/src/com/fsck/k9/mail/store/LocalStore.java @@ -1,7 +1,15 @@ package com.fsck.k9.mail.store; -import java.io.*; +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Serializable; +import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.util.ArrayList; import java.util.Arrays; @@ -17,7 +25,6 @@ import java.util.UUID; import java.util.regex.Pattern; -import com.fsck.k9.helper.HtmlConverter; import org.apache.commons.io.IOUtils; import android.app.Application; @@ -35,8 +42,10 @@ import com.fsck.k9.K9; import com.fsck.k9.Preferences; import com.fsck.k9.R; +import com.fsck.k9.activity.Search; import com.fsck.k9.controller.MessageRemovalListener; import com.fsck.k9.controller.MessageRetrievalListener; +import com.fsck.k9.helper.HtmlConverter; import com.fsck.k9.helper.Utility; import com.fsck.k9.mail.Address; import com.fsck.k9.mail.Body; @@ -1354,17 +1363,19 @@ public int getVisibleLimit() throws MessagingException { } public void purgeToVisibleLimit(MessageRemovalListener listener) throws MessagingException { - if (mVisibleLimit == 0) { - return ; - } - open(OpenMode.READ_WRITE); - Message[] messages = getMessages(null, false); - for (int i = mVisibleLimit; i < messages.length; i++) { - if (listener != null) { - listener.messageRemoved(messages[i]); + //don't purge messages while a Search is active since it might throw away search results + if(!Search.isActive()){ + if (mVisibleLimit == 0) { + return ; + } + open(OpenMode.READ_WRITE); + Message[] messages = getMessages(null, false); + for (int i = mVisibleLimit; i < messages.length; i++) { + if (listener != null) { + listener.messageRemoved(messages[i]); + } + messages[i].destroy(); } - messages[i].destroy(); - } } From ece589d609f467e724512407dce7edc7aa0f50a4 Mon Sep 17 00:00:00 2001 From: Rob Bayer Date: Sun, 4 Mar 2012 20:11:34 -0800 Subject: [PATCH 19/21] Refactor to allow fetching of extra search results beyond original request. Most code moved out of ImapStore and ImapFolder and into MessagingController.searchRemoteMessagesSynchronous. Should make it easier to add remoteSearch for other server types. --- src/com/fsck/k9/activity/MessageList.java | 62 +++--- .../k9/controller/MessagingController.java | 157 +++++++++---- .../fsck/k9/controller/MessagingListener.java | 7 +- .../fsck/k9/controller/SearchListener.java | 6 - src/com/fsck/k9/mail/Store.java | 4 +- src/com/fsck/k9/mail/store/ImapStore.java | 208 +++++++----------- src/com/fsck/k9/mail/store/LocalStore.java | 8 +- 7 files changed, 236 insertions(+), 216 deletions(-) delete mode 100644 src/com/fsck/k9/controller/SearchListener.java diff --git a/src/com/fsck/k9/activity/MessageList.java b/src/com/fsck/k9/activity/MessageList.java index 675d5b893ef..cd999a0bc08 100644 --- a/src/com/fsck/k9/activity/MessageList.java +++ b/src/com/fsck/k9/activity/MessageList.java @@ -70,7 +70,6 @@ import com.fsck.k9.mail.Flag; import com.fsck.k9.mail.Folder; import com.fsck.k9.mail.Message; -import com.fsck.k9.mail.MessagingException; import com.fsck.k9.mail.store.LocalStore; import com.fsck.k9.mail.store.LocalStore.LocalFolder; import com.fsck.k9.mail.store.StorageManager; @@ -431,6 +430,12 @@ public void run(){ if(text!= null){ holder.main.setText(text); } + if(progressVisible || holder.main.getText().length() > 0){ + mFooterView.setVisibility(View.VISIBLE); + } + else{ + mFooterView.setVisibility(View.GONE); + } } }); } @@ -701,6 +706,20 @@ public void onItemClick(AdapterView parent, View view, int position, long id) if (mCurrentFolder != null && !mRemoteSearch) { mController.loadMoreMessages(mAccount, mFolderName, mAdapter.mListener); } + else if(mRemoteSearch && mAdapter.mExtraSearchResults != null && mAdapter.mExtraSearchResults.size() > 0 && mSearchAccount != null){ + int numResults = mAdapter.mExtraSearchResults.size(); + Account account = Preferences.getPreferences(this).getAccount(mSearchAccount); + int limit = account.getRemoteSearchNumResults(); + List toProcess = mAdapter.mExtraSearchResults; + if(limit > 0 && numResults > limit){ + toProcess = toProcess.subList(0, limit); + mAdapter.mExtraSearchResults = mAdapter.mExtraSearchResults.subList(limit, mAdapter.mExtraSearchResults.size()); + } + else{ + mAdapter.mExtraSearchResults = null; + } + mController.loadSearchResults(account, mSearchFolder, toProcess, mAdapter.mListener); + } return; } @@ -1948,45 +1967,21 @@ public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuIn class MessageListAdapter extends BaseAdapter { private final List messages = java.util.Collections.synchronizedList(new ArrayList()); + public List mExtraSearchResults; + private final ActivityListener mListener = new ActivityListener() { @Override public void remoteSearchAddMessage(Account account, String folderName, Message message, final int numDone, final int numTotal) { - if(numTotal > 0){ + if(numTotal > 0 && numDone < numTotal){ mHandler.setWindowProgress(Window.PROGRESS_END/numTotal * numDone); } else{ mHandler.setWindowProgress(Window.PROGRESS_END); } - //MessageView expects messages to be in the LocalStore, so add them - try{ - LocalFolder localFolder = account.getLocalStore().getFolder(folderName); - if(localFolder != null){ - Message localMessage = localFolder.getMessage(message.getUid()); - if(localMessage == null){ - //add message to LocalStore so MessageView can pick it up - Message [] messages = {message}; - localFolder.appendMessages(messages); - message = localFolder.getMessage(message.getUid()); - } - else{ - //use LocalStore's copy as it might have body, etc downloaded - //TODO: update LocalStore's copy if ours has newer flags? - message = localMessage; - } - }//else: should never really happen - - } - catch(MessagingException e){ - //FIXME: Do something useful here... - if(K9.DEBUG){ - Log.d("IMAP search", "remoteSearchAddMessage caught error: " + e.toString()); - } - } - addOrUpdateMessages(account, folderName, Collections.singletonList(message), false); } @@ -2007,10 +2002,17 @@ public void remoteSearchStarted(Account acct, String folder){ @Override - public void remoteSearchFinished(Account acct, String folder, int numResults){ + public void remoteSearchFinished(Account acct, String folder, int numResults, List extraResults){ mHandler.progress(false); - mHandler.updateFooter("", false); + if(extraResults != null && extraResults.size() > 0){ + mExtraSearchResults = extraResults; + mHandler.updateFooter(String.format(getString(R.string.load_more_messages_fmt), acct.getRemoteSearchNumResults()), false); + } + else{ + mHandler.updateFooter("", false); + } mHandler.setWindowProgress(Window.PROGRESS_END); + } @Override diff --git a/src/com/fsck/k9/controller/MessagingController.java b/src/com/fsck/k9/controller/MessagingController.java index 59d8ac13c0d..8afd810908a 100644 --- a/src/com/fsck/k9/controller/MessagingController.java +++ b/src/com/fsck/k9/controller/MessagingController.java @@ -7,6 +7,7 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.Comparator; import java.util.Date; import java.util.HashMap; import java.util.HashSet; @@ -135,6 +136,29 @@ public class MessagingController implements Runnable { private static final String PENDING_COMMAND_MARK_ALL_AS_READ = "com.fsck.k9.MessagingController.markAllAsRead"; private static final String PENDING_COMMAND_EXPUNGE = "com.fsck.k9.MessagingController.expunge"; + public static class UidReverseComparator implements Comparator{ + @Override + public int compare(Message o1, Message o2) { + if(o1 == null || o2 == null || o1.getUid() == null || o2.getUid() == null){ + return 0; + } + int id1, id2; + try{ + id1 = Integer.parseInt(o1.getUid()); + id2 = Integer.parseInt(o2.getUid()); + } + catch(NumberFormatException e){ + return 0; + } + //reversed intentionally. + if(id1 < id2) + return 1; + if(id1 > id2) + return -1; + return 0; + } + } + /** * Maximum number of unsynced messages to store at once */ @@ -824,58 +848,49 @@ public void run() { public void searchRemoteMessagesSynchronous(final String acctUuid, final String folderName, final String query, final Flag[] requiredFlags, final Flag[] forbiddenFlags, final MessagingListener listener){ final Account acct = Preferences.getPreferences(mApplication.getApplicationContext()).getAccount(acctUuid); - final AccountStats stats = new AccountStats(); if (listener != null) { listener.remoteSearchStarted(acct, folderName); } + List extraResults = new ArrayList(); + try { + Store remoteStore = acct.getRemoteStore(); + LocalStore localStore = acct.getLocalStore(); - MessageRetrievalListener retrievalListener = new MessageRetrievalListener() { - @Override - public void messageStarted(String message, int number, int ofTotal) { - + if(remoteStore == null || localStore == null){ + throw new MessagingException("Could not get store"); } - @Override - public void messageFinished(Message message, int number, int ofTotal){ + Folder remoteFolder = remoteStore.getFolder(folderName); + LocalFolder localFolder = localStore.getFolder(folderName); + if(remoteFolder == null || localFolder == null){ + throw new MessagingException("Folder not found"); + } - if (!isMessageSuppressed(message.getFolder().getAccount(), message.getFolder().getName(), message)) { - stats.unreadMessageCount += (!message.isSet(Flag.SEEN)) ? 1 : 0; - stats.flaggedMessageCount += (message.isSet(Flag.FLAGGED)) ? 1 : 0; - if (listener != null) { - listener.remoteSearchAddMessage(acct, folderName, message, number, ofTotal); - } - } - + if(listener != null){ + listener.remoteSearchStarted(acct, folderName); + } + List messages = remoteStore.searchRemoteMessages(query, folderName, requiredFlags, forbiddenFlags); + if(listener != null){ + listener.remoteSearchServerQueryComplete(acct, folderName, messages.size()); } - @Override - public void messagesFinished(int number) { + if(K9.DEBUG){ + Log.i("Remote Search", "Remote search got " + messages.size() + " results"); } - }; - SearchListener searchListener = new SearchListener(){ + Collections.sort(messages, new UidReverseComparator()); - @Override - public void searchStarted() { - listener.remoteSearchStarted(acct, folderName); - } - @Override - public void searchFinished(int numResults) { - listener.remoteSearchServerQueryComplete(acct, folderName, numResults); + int resultLimit = acct.getRemoteSearchNumResults(); + if(resultLimit > 0 && messages.size() > resultLimit){ + extraResults = messages.subList(resultLimit, messages.size()); + messages = messages.subList(0, resultLimit); } - }; - try { - Store acctStore = acct.getRemoteStore(); - if(acctStore != null){ - acctStore.searchRemoteMessages(retrievalListener, searchListener, query, folderName, requiredFlags, forbiddenFlags); - } - else{ - throw new MessagingException("Account has no remote store"); - } + loadSearchResultsSynchronous(messages, localFolder, remoteFolder, listener); + } catch (Exception e) { if (listener != null) { @@ -884,15 +899,64 @@ public void searchFinished(int numResults) { addErrorMessage(acct, null, e); } finally { if (listener != null) { - listener.listLocalMessagesFinished(acct, null); - listener.remoteSearchFinished(acct, folderName, 0); + listener.remoteSearchFinished(acct, folderName, 0, extraResults); } } - if (listener != null) { - listener.searchStats(stats); - } + } + + public void loadSearchResults(final Account account, final String folderName, final List messages, final MessagingListener listener){ + threadPool.execute(new Runnable(){ + @Override + public void run() { + try{ + Store remoteStore = account.getRemoteStore(); + LocalStore localStore = account.getLocalStore(); + + if(remoteStore == null || localStore == null){ + throw new MessagingException("Could not get store"); + } + + Folder remoteFolder = remoteStore.getFolder(folderName); + LocalFolder localFolder = localStore.getFolder(folderName); + if(remoteFolder == null || localFolder == null){ + throw new MessagingException("Folder not found"); + } + + loadSearchResultsSynchronous(messages, localFolder, remoteFolder, listener); + } + catch(MessagingException e){ + Log.e(K9.LOG_TAG, "Exception in loadSearchResults: " + e); + addErrorMessage(account, null, e); + } + } + }); + } + + public void loadSearchResultsSynchronous(List messages, LocalFolder localFolder, Folder remoteFolder, MessagingListener listener) throws MessagingException{ + FetchProfile fp_header = new FetchProfile(); + fp_header.add(FetchProfile.Item.FLAGS); + fp_header.add(FetchProfile.Item.ENVELOPE); + FetchProfile fp_structure = new FetchProfile(); + fp_structure.add(FetchProfile.Item.STRUCTURE); + + int i = 0; + for(Message message : messages){ + i++; + LocalMessage localMsg = localFolder.getMessage(message.getUid()); + + if(localMsg == null){ + remoteFolder.fetch(new Message [] {message}, fp_header, null); + //fun fact: ImapFolder.fetch can't handle getting STRUCTURE at same time as headers + remoteFolder.fetch(new Message [] {message}, fp_structure, null); + localFolder.appendMessages(new Message [] {message}); + localMsg = localFolder.getMessage(message.getUid()); + } + if(listener != null){ + listener.remoteSearchAddMessage(remoteFolder.getAccount(), remoteFolder.getName(), localMsg, i, messages.size()); + } + } } @@ -1339,14 +1403,17 @@ private int downloadMessages(final Account account, final Folder remoteFolder, * Reverse the order of the messages. Depending on the server this may get us * fetch results for newest to oldest. If not, no harm done. */ - Collections.reverse(unsyncedMessages); + Collections.sort(unsyncedMessages, new UidReverseComparator()); + + int visibleLimit = localFolder.getVisibleLimit(); int listSize = unsyncedMessages.size(); if ((visibleLimit > 0) && (listSize > visibleLimit)) { - unsyncedMessages = unsyncedMessages.subList(listSize - visibleLimit, listSize); + unsyncedMessages = unsyncedMessages.subList(0, visibleLimit); } + FetchProfile fp = new FetchProfile(); if (remoteFolder.supportsFetchingFlags()) { fp.add(FetchProfile.Item.FLAGS); @@ -1413,6 +1480,7 @@ private int downloadMessages(final Account account, final Folder remoteFolder, if (K9.DEBUG) Log.d(K9.LOG_TAG, "SYNC: Synced remote messages for folder " + folder + ", " + newMessages.get() + " new messages"); + localFolder.purgeToVisibleLimit(new MessageRemovalListener() { @Override public void messageRemoved(Message message) { @@ -1423,6 +1491,7 @@ public void messageRemoved(Message message) { }); + // If the oldest message seen on this sync is newer than // the oldest message seen on the previous sync, then // we want to move our high-water mark forward @@ -2077,7 +2146,7 @@ private void processPendingAppend(PendingCommand command, Account account) LocalStore localStore = account.getLocalStore(); localFolder = localStore.getFolder(folder); - LocalMessage localMessage = (LocalMessage) localFolder.getMessage(uid); + LocalMessage localMessage = localFolder.getMessage(uid); if (localMessage == null) { return; @@ -2842,7 +2911,7 @@ public void run() { LocalFolder localFolder = localStore.getFolder(folderName); localFolder.open(OpenMode.READ_WRITE); - LocalMessage message = (LocalMessage)localFolder.getMessage(uid); + LocalMessage message = localFolder.getMessage(uid); if (message == null || message.getId() == 0) { throw new IllegalArgumentException("Message not found: folder=" + folderName + ", uid=" + uid); diff --git a/src/com/fsck/k9/controller/MessagingListener.java b/src/com/fsck/k9/controller/MessagingListener.java index 8c7fbf6a20c..8edbadbea86 100644 --- a/src/com/fsck/k9/controller/MessagingListener.java +++ b/src/com/fsck/k9/controller/MessagingListener.java @@ -1,7 +1,10 @@ package com.fsck.k9.controller; +import java.util.List; + import android.content.Context; + import com.fsck.k9.Account; import com.fsck.k9.AccountStats; import com.fsck.k9.BaseAccount; @@ -9,8 +12,6 @@ import com.fsck.k9.mail.Message; import com.fsck.k9.mail.Part; -import java.util.List; - /** * Defines the interface that {@link MessagingController} will use to callback to requesters. * @@ -185,7 +186,7 @@ public void remoteSearchAddMessage(Account account, String folder, Message messa * @param folder * @param numResults */ - public void remoteSearchFinished(Account acct, String folder, int numResults) {} + public void remoteSearchFinished(Account acct, String folder, int numResults, List extraResults) {} /** * Called when there was a problem with a remote search operation. diff --git a/src/com/fsck/k9/controller/SearchListener.java b/src/com/fsck/k9/controller/SearchListener.java deleted file mode 100644 index 46ba7d3ac43..00000000000 --- a/src/com/fsck/k9/controller/SearchListener.java +++ /dev/null @@ -1,6 +0,0 @@ -package com.fsck.k9.controller; - -public interface SearchListener { - public void searchStarted(); - public void searchFinished(int numResults); -} diff --git a/src/com/fsck/k9/mail/Store.java b/src/com/fsck/k9/mail/Store.java index 50350a2d0e1..7d6644de850 100644 --- a/src/com/fsck/k9/mail/Store.java +++ b/src/com/fsck/k9/mail/Store.java @@ -8,8 +8,6 @@ import android.content.Context; import com.fsck.k9.Account; -import com.fsck.k9.controller.MessageRetrievalListener; -import com.fsck.k9.controller.SearchListener; import com.fsck.k9.mail.store.ImapStore; import com.fsck.k9.mail.store.LocalStore; import com.fsck.k9.mail.store.Pop3Store; @@ -180,7 +178,7 @@ public Account getAccount() { return mAccount; } - public void searchRemoteMessages(MessageRetrievalListener msgListener, SearchListener searchListener, String queryString, + public List searchRemoteMessages(String queryString, String folder, final Flag[] requiredFlags, final Flag[] forbiddenFlags) throws MessagingException{ throw new MessagingException("K-9 does not support remote searching on this account type"); } diff --git a/src/com/fsck/k9/mail/store/ImapStore.java b/src/com/fsck/k9/mail/store/ImapStore.java index ed45d48d0b7..64920f04263 100644 --- a/src/com/fsck/k9/mail/store/ImapStore.java +++ b/src/com/fsck/k9/mail/store/ImapStore.java @@ -65,7 +65,6 @@ import com.fsck.k9.K9; import com.fsck.k9.R; import com.fsck.k9.controller.MessageRetrievalListener; -import com.fsck.k9.controller.SearchListener; import com.fsck.k9.helper.Utility; import com.fsck.k9.helper.power.TracingPowerManager; import com.fsck.k9.helper.power.TracingPowerManager.TracingWakeLock; @@ -1172,82 +1171,6 @@ private int getRemoteMessageCount(String criteria) throws MessagingException { } - public void doRemoteSearch(final String queryString, final Flag[] requiredFlags, final Flag [] forbiddenFlags, final MessageRetrievalListener msgListener, final SearchListener searchListener) - throws MessagingException{ - ImapSearcher searcher = new ImapSearcher(){ - public List search() throws IOException, MessagingException { - String imapQuery = "UID SEARCH "; - if(requiredFlags != null){ - for(Flag f : requiredFlags){ - switch(f){ - case DELETED: - imapQuery += "DELETED "; - break; - - case SEEN: - imapQuery += "SEEN "; - break; - - case ANSWERED: - imapQuery += "ANSWERED "; - break; - - case FLAGGED: - imapQuery += "FLAGGED "; - break; - - case DRAFT: - imapQuery += "DRAFT "; - break; - - case RECENT: - imapQuery += "RECENT "; - break; - } - } - } - if(forbiddenFlags != null){ - for(Flag f : forbiddenFlags){ - switch(f){ - case DELETED: - imapQuery += "UNDELETED "; - break; - - case SEEN: - imapQuery += "UNSEEN "; - break; - - case ANSWERED: - imapQuery += "UNANSWERED "; - break; - - case FLAGGED: - imapQuery += "UNFLAGGED "; - break; - - case DRAFT: - imapQuery += "UNDRAFT "; - break; - - case RECENT: - imapQuery += "UNRECENT "; - break; - } - } - } - String encodedQry = encodeString(queryString); - if(mAccount.getRemoteSearchFullText()){ - imapQuery += "TEXT " + encodedQry; - } - else{ - imapQuery += "OR SUBJECT " + encodedQry + " FROM " + encodedQry; - } - return executeSimpleCommand(imapQuery); - } - }; - - search(searcher, msgListener, searchListener, (mAccount != null ? mAccount.getRemoteSearchNumResults() : 0), true); - } @Override public int getUnreadMessageCount() throws MessagingException { @@ -1266,7 +1189,7 @@ public List search() throws IOException, MessagingException { return executeSimpleCommand("UID SEARCH *:*"); } }; - Message[] messages = search(searcher, null); + Message[] messages = search(searcher, null).toArray(EMPTY_MESSAGE_ARRAY); if (messages.length > 0) { return Integer.parseInt(messages[0].getUid()); } @@ -1315,7 +1238,7 @@ public List search() throws IOException, MessagingException { return executeSimpleCommand(String.format("UID SEARCH %d:%d%s%s", start, end, dateSearchString, includeDeleted ? "" : " NOT DELETED")); } }; - return search(searcher, listener); + return search(searcher, listener).toArray(EMPTY_MESSAGE_ARRAY); } protected Message[] getMessages(final List mesgSeqs, final boolean includeDeleted, final MessageRetrievalListener listener) @@ -1325,7 +1248,7 @@ public List search() throws IOException, MessagingException { return executeSimpleCommand(String.format("UID SEARCH %s%s", Utility.combine(mesgSeqs.toArray(), ','), includeDeleted ? "" : " NOT DELETED")); } }; - return search(searcher, listener); + return search(searcher, listener).toArray(EMPTY_MESSAGE_ARRAY); } protected Message[] getMessagesFromUids(final List mesgUids, final boolean includeDeleted, final MessageRetrievalListener listener) @@ -1335,23 +1258,16 @@ public List search() throws IOException, MessagingException { return executeSimpleCommand(String.format("UID SEARCH UID %s%s", Utility.combine(mesgUids.toArray(), ','), includeDeleted ? "" : " NOT DELETED")); } }; - return search(searcher, listener); + return search(searcher, listener).toArray(EMPTY_MESSAGE_ARRAY); } - private Message[] search(ImapSearcher searcher, MessageRetrievalListener listener) throws MessagingException { - return search(searcher, listener, null, 0, false); - } - - private Message[] search(ImapSearcher searcher, MessageRetrievalListener msgListener, SearchListener searchListener, int limit, boolean getHeaders) throws MessagingException { + private List search(ImapSearcher searcher, MessageRetrievalListener msgListener) throws MessagingException { checkOpen(); //only need READ access ArrayList messages = new ArrayList(); try { ArrayList uids = new ArrayList(); - if(searchListener != null){ - searchListener.searchStarted(); - } List responses = searcher.search(); @@ -1365,42 +1281,18 @@ private Message[] search(ImapSearcher searcher, MessageRetrievalListener msgList } } - if(searchListener != null){ - searchListener.searchFinished(uids.size()); - } - // Sort the uids in numerically decreasing order // By doing it in decreasing order, we ensure newest messages are dealt with first // This makes the most sense when a limit is imposed, and also prevents UI from going // crazy adding stuff at the top. Collections.sort(uids, Collections.reverseOrder()); - FetchProfile fp = new FetchProfile(); - if(getHeaders){ - fp.add(FetchProfile.Item.ENVELOPE); - fp.add(FetchProfile.Item.FLAGS); - fp.add(FetchProfile.Item.STRUCTURE); - } - - if(K9.DEBUG){ - Log.i("IMAP search", "Search results: " + uids.size() + ", limit: " + limit); - Log.i("IMAP search", "Uids: " + Arrays.toString(uids.toArray())); - } - - for (int i = 0, count = (limit==0 ? uids.size() : Math.min(uids.size(), limit)); i < count; i++) { + for (int i = 0, count = uids.size(); i < count; i++) { if (msgListener != null) { msgListener.messageStarted("" + uids.get(i), i, count); } ImapMessage message = new ImapMessage("" + uids.get(i), this); - if(getHeaders){ - Message [] msgArray = {message}; - if(K9.DEBUG){ - Log.i("IMAP search", "Fetching header: " + message.getUid()); - } - fetch(msgArray, fp, null); //don't pass the listener since we're already updating it - } - messages.add(message); if (msgListener != null) { msgListener.messageFinished(message, i, count); @@ -1410,16 +1302,7 @@ private Message[] search(ImapSearcher searcher, MessageRetrievalListener msgList throw ioExceptionHandler(mConnection, ioe); } - Message [] msgArray = messages.toArray(EMPTY_MESSAGE_ARRAY); - - /* - * Doing this here makes it one batch, but the UI spends a long time with (no subject) stuff, etc. - * Therefore, at least for now, should fetch headers individually as we fetch the messages. - * - if(getHeaders){ - fetch(msgArray, fp, listener); - }*/ - return msgArray; + return messages; } @@ -3406,7 +3289,7 @@ public Object foundLiteral(ImapResponse response, } @Override - public void searchRemoteMessages(final MessageRetrievalListener msgListener, final SearchListener searchListener, final String queryString, + public List searchRemoteMessages(final String queryString, final String folderName, final Flag[] requiredFlags, final Flag[] forbiddenFlags) throws MessagingException{ if(!mAccount.allowRemoteSearch()){ @@ -3423,7 +3306,80 @@ public void searchRemoteMessages(final MessageRetrievalListener msgListener, fin folder.checkOpen(); - folder.doRemoteSearch(queryString, requiredFlags, forbiddenFlags, msgListener, searchListener); + ImapSearcher searcher = new ImapSearcher(){ + public List search() throws IOException, MessagingException { + String imapQuery = "UID SEARCH "; + if(requiredFlags != null){ + for(Flag f : requiredFlags){ + switch(f){ + case DELETED: + imapQuery += "DELETED "; + break; + + case SEEN: + imapQuery += "SEEN "; + break; + + case ANSWERED: + imapQuery += "ANSWERED "; + break; + + case FLAGGED: + imapQuery += "FLAGGED "; + break; + + case DRAFT: + imapQuery += "DRAFT "; + break; + + case RECENT: + imapQuery += "RECENT "; + break; + } + } + } + if(forbiddenFlags != null){ + for(Flag f : forbiddenFlags){ + switch(f){ + case DELETED: + imapQuery += "UNDELETED "; + break; + + case SEEN: + imapQuery += "UNSEEN "; + break; + + case ANSWERED: + imapQuery += "UNANSWERED "; + break; + + case FLAGGED: + imapQuery += "UNFLAGGED "; + break; + + case DRAFT: + imapQuery += "UNDRAFT "; + break; + + case RECENT: + imapQuery += "UNRECENT "; + break; + } + } + } + String encodedQry = encodeString(queryString); + if(mAccount.getRemoteSearchFullText()){ + imapQuery += "TEXT " + encodedQry; + } + else{ + imapQuery += "OR SUBJECT " + encodedQry + " FROM " + encodedQry; + } + return folder.executeSimpleCommand(imapQuery); + } + }; + + //don't pass listener--we don't want to add messages until we've downloaded them + return folder.search(searcher, null); } catch(Exception e){ diff --git a/src/com/fsck/k9/mail/store/LocalStore.java b/src/com/fsck/k9/mail/store/LocalStore.java index 306b7e13c93..7f2a6313d8c 100644 --- a/src/com/fsck/k9/mail/store/LocalStore.java +++ b/src/com/fsck/k9/mail/store/LocalStore.java @@ -1851,11 +1851,11 @@ public String doDbWork(final SQLiteDatabase db) throws WrappedException, Unavail } @Override - public Message getMessage(final String uid) throws MessagingException { + public LocalMessage getMessage(final String uid) throws MessagingException { try { - return database.execute(false, new DbCallback() { + return database.execute(false, new DbCallback() { @Override - public Message doDbWork(final SQLiteDatabase db) throws WrappedException, UnavailableStorageException { + public LocalMessage doDbWork(final SQLiteDatabase db) throws WrappedException, UnavailableStorageException { try { open(OpenMode.READ_WRITE); LocalMessage message = new LocalMessage(uid, LocalFolder.this); @@ -2102,7 +2102,7 @@ public Void doDbWork(final SQLiteDatabase db) throws WrappedException, Unavailab message.setUid(uid); } } else { - LocalMessage oldMessage = (LocalMessage) getMessage(uid); + LocalMessage oldMessage = getMessage(uid); if (oldMessage != null) { oldMessageId = oldMessage.getId(); From b09df2883001fd9e03cd4d95d942689ba293ed1f Mon Sep 17 00:00:00 2001 From: Rob Bayer Date: Sun, 4 Mar 2012 23:26:30 -0800 Subject: [PATCH 20/21] Code Cleanup getRemoteSearchFullText -> isRemoteSearchFullText line wraps for preference items --- res/xml/account_settings_preferences.xml | 22 ++++++++++++++++--- src/com/fsck/k9/Account.java | 3 +-- src/com/fsck/k9/activity/MessageList.java | 4 ++-- .../k9/activity/setup/AccountSettings.java | 2 +- src/com/fsck/k9/mail/store/ImapStore.java | 2 +- 5 files changed, 24 insertions(+), 9 deletions(-) diff --git a/res/xml/account_settings_preferences.xml b/res/xml/account_settings_preferences.xml index 86b871105dc..577e74479a5 100644 --- a/res/xml/account_settings_preferences.xml +++ b/res/xml/account_settings_preferences.xml @@ -438,9 +438,25 @@ - - - + + + + + diff --git a/src/com/fsck/k9/Account.java b/src/com/fsck/k9/Account.java index ba32f7efa0b..4599cfa7062 100644 --- a/src/com/fsck/k9/Account.java +++ b/src/com/fsck/k9/Account.java @@ -1530,8 +1530,7 @@ public synchronized void setEnabled(boolean enabled) { mEnabled = enabled; } - public boolean getRemoteSearchFullText() { - + public boolean isRemoteSearchFullText() { return mRemoteSearchFullText; } diff --git a/src/com/fsck/k9/activity/MessageList.java b/src/com/fsck/k9/activity/MessageList.java index cd999a0bc08..f482908edc1 100644 --- a/src/com/fsck/k9/activity/MessageList.java +++ b/src/com/fsck/k9/activity/MessageList.java @@ -411,7 +411,7 @@ public void run() { } } - if (wasEmpty & !mAdapter.messages.isEmpty()) { + if (wasEmpty && !mAdapter.messages.isEmpty()) { mListView.setSelection(0); } resetUnreadCountOnThread(); @@ -1294,7 +1294,7 @@ private void onEditAccount() { public boolean onSearchRequested() { if(mAccount != null && mCurrentFolder != null && mAccount.allowRemoteSearch()){ - //if in a SSSable folder, ask user what they want. + //if in a remote searchable folder, ask user what they want. //TODO: Add ability to remember selection? final CharSequence[] items = new CharSequence[2]; items[0] = getString(R.string.search_mode_local_all); diff --git a/src/com/fsck/k9/activity/setup/AccountSettings.java b/src/com/fsck/k9/activity/setup/AccountSettings.java index 3193ec940b8..8f19fe09e8c 100644 --- a/src/com/fsck/k9/activity/setup/AccountSettings.java +++ b/src/com/fsck/k9/activity/setup/AccountSettings.java @@ -506,7 +506,7 @@ public boolean onPreferenceChange(Preference pref, Object newVal){ mAllowRemoteSearch.setChecked(mAccount.allowRemoteSearch()); mRemoteSearchNumResults.setValue(Integer.toString(mAccount.getRemoteSearchNumResults())); - mRemoteSearchFullText.setChecked(mAccount.getRemoteSearchFullText()); + mRemoteSearchFullText.setChecked(mAccount.isRemoteSearchFullText()); mIdleRefreshPeriod.setValue(String.valueOf(mAccount.getIdleRefreshMinutes())); mIdleRefreshPeriod.setSummary(mIdleRefreshPeriod.getEntry()); diff --git a/src/com/fsck/k9/mail/store/ImapStore.java b/src/com/fsck/k9/mail/store/ImapStore.java index 64920f04263..84415bca6bf 100644 --- a/src/com/fsck/k9/mail/store/ImapStore.java +++ b/src/com/fsck/k9/mail/store/ImapStore.java @@ -3368,7 +3368,7 @@ public List search() throws IOException, MessagingException { } } String encodedQry = encodeString(queryString); - if(mAccount.getRemoteSearchFullText()){ + if(mAccount.isRemoteSearchFullText()){ imapQuery += "TEXT " + encodedQry; } else{ From ff63fc31b9f8755f73b751e135c5182dab4d75bb Mon Sep 17 00:00:00 2001 From: Rob Bayer Date: Mon, 5 Mar 2012 10:53:14 -0800 Subject: [PATCH 21/21] More cleanup --- res/values/arrays.xml | 3 +- res/values/strings.xml | 10 +- res/xml/account_settings_preferences.xml | 46 +++-- src/com/fsck/k9/Account.java | 6 +- .../fsck/k9/activity/ActivityListener.java | 1 - src/com/fsck/k9/activity/ChooseFolder.java | 76 ++++---- src/com/fsck/k9/activity/MessageList.java | 181 +++++++++--------- src/com/fsck/k9/activity/Search.java | 10 +- .../k9/activity/setup/AccountSettings.java | 30 ++- .../k9/controller/MessagingController.java | 88 ++++----- .../fsck/k9/controller/MessagingListener.java | 10 +- src/com/fsck/k9/helper/MessageHelper.java | 2 +- src/com/fsck/k9/mail/Store.java | 2 +- .../fsck/k9/mail/internet/MimeMessage.java | 12 +- src/com/fsck/k9/mail/store/ImapStore.java | 48 ++--- src/com/fsck/k9/mail/store/LocalStore.java | 7 +- src/com/fsck/k9/provider/MessageProvider.java | 2 +- 17 files changed, 256 insertions(+), 278 deletions(-) diff --git a/res/values/arrays.xml b/res/values/arrays.xml index 4a42fc04060..6393f91ec29 100644 --- a/res/values/arrays.xml +++ b/res/values/arrays.xml @@ -46,7 +46,6 @@ 1440 - @string/account_setup_options_mail_display_count_10 @string/account_setup_options_mail_display_count_25 @@ -57,7 +56,7 @@ @string/account_setup_options_mail_display_count_1000 @string/account_setup_options_mail_display_count_all - + 10 25 diff --git a/res/values/strings.xml b/res/values/strings.xml index 36d1a7960df..1501fd10a7f 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -1131,8 +1131,8 @@ Welcome to K-9 Mail setup. K-9 is an open source mail client for Android origin the import operation. Please install a file manager application from Android Market
Open Market Close - Allow Remote Search - Enable Remote Searching for this account + Allow remote search + Enable remote searching for this account All 10 25 @@ -1141,13 +1141,13 @@ the import operation. Please install a file manager application from Android Mar 250 500 1000 - Results Limit + Results limit All Local Folders Remote Folder Search Location - Remote Folder Searching + Remote folder searching Can be slow - Include Body Text + Include body text To perform a remote search, press your device\'s Search button while viewing a folder from this account. \n\nNote: Remote search is NOT available from the Unified Inbox or from a list of folders. diff --git a/res/xml/account_settings_preferences.xml b/res/xml/account_settings_preferences.xml index 577e74479a5..42ca3083cba 100644 --- a/res/xml/account_settings_preferences.xml +++ b/res/xml/account_settings_preferences.xml @@ -20,7 +20,9 @@ the preferences. See com.fsck.k9.preferences.Storage. --> - + + - - - - - - - - + - - - + @@ -491,6 +490,5 @@ android:dependency="crypto_app"/> - diff --git a/src/com/fsck/k9/Account.java b/src/com/fsck/k9/Account.java index 4599cfa7062..4baa54eb891 100644 --- a/src/com/fsck/k9/Account.java +++ b/src/com/fsck/k9/Account.java @@ -1463,15 +1463,15 @@ public boolean allowRemoteSearch() { return mAllowRemoteSearch; } - public void setAllowRemoteSearch(boolean val){ + public void setAllowRemoteSearch(boolean val) { mAllowRemoteSearch = val; } - public int getRemoteSearchNumResults(){ + public int getRemoteSearchNumResults() { return mRemoteSearchNumResults; } - public void setRemoteSearchNumResults(int val){ + public void setRemoteSearchNumResults(int val) { mRemoteSearchNumResults = (val >= 0 ? val : 0); } diff --git a/src/com/fsck/k9/activity/ActivityListener.java b/src/com/fsck/k9/activity/ActivityListener.java index 06d38eb7a78..803158fc0c8 100644 --- a/src/com/fsck/k9/activity/ActivityListener.java +++ b/src/com/fsck/k9/activity/ActivityListener.java @@ -76,7 +76,6 @@ else if (mSendingAccountDescription != null) { public void informUserOfStatus() { } - @Override public void synchronizeMailboxFinished( Account account, diff --git a/src/com/fsck/k9/activity/ChooseFolder.java b/src/com/fsck/k9/activity/ChooseFolder.java index 5f535d391b2..dc4a8811559 100644 --- a/src/com/fsck/k9/activity/ChooseFolder.java +++ b/src/com/fsck/k9/activity/ChooseFolder.java @@ -208,7 +208,7 @@ public void dataChanged() { return true; } case R.id.filter_folders: { - onEnterFilter(); + onEnterFilter(); } return true; default: @@ -228,43 +228,43 @@ private void onRefresh() { * Filter {@link #mAdapter} with the user-input. */ private void onEnterFilter() { - final AlertDialog.Builder filterAlert = new AlertDialog.Builder(this); - - final EditText input = new EditText(this); - input.addTextChangedListener(new TextWatcher() { - - @Override - public void onTextChanged(CharSequence s, int start, int before, int count) { - mAdapter.getFilter().filter(input.getText().toString()); - } - - @Override - public void beforeTextChanged(CharSequence s, int start, int count, - int after) { - } - - @Override - public void afterTextChanged(Editable s) { - } - }); - input.setHint(R.string.folder_list_filter_hint); - filterAlert.setView(input); - - filterAlert.setPositiveButton("Ok", new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int whichButton) { - String value = input.getText().toString().trim(); - mAdapter.getFilter().filter(value); - } - }); - - filterAlert.setNegativeButton("Cancel", - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int whichButton) { - mAdapter.getFilter().filter(""); - } - }); - - filterAlert.show(); + final AlertDialog.Builder filterAlert = new AlertDialog.Builder(this); + + final EditText input = new EditText(this); + input.addTextChangedListener(new TextWatcher() { + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + mAdapter.getFilter().filter(input.getText().toString()); + } + + @Override + public void beforeTextChanged(CharSequence s, int start, int count, + int after) { + } + + @Override + public void afterTextChanged(Editable s) { + } + }); + input.setHint(R.string.folder_list_filter_hint); + filterAlert.setView(input); + + filterAlert.setPositiveButton("Ok", new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int whichButton) { + String value = input.getText().toString().trim(); + mAdapter.getFilter().filter(value); + } + }); + + filterAlert.setNegativeButton("Cancel", + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int whichButton) { + mAdapter.getFilter().filter(""); + } + }); + + filterAlert.show(); } diff --git a/src/com/fsck/k9/activity/MessageList.java b/src/com/fsck/k9/activity/MessageList.java index f482908edc1..a339a2cc85d 100644 --- a/src/com/fsck/k9/activity/MessageList.java +++ b/src/com/fsck/k9/activity/MessageList.java @@ -170,11 +170,11 @@ public static class SenderComparator implements Comparator { @Override public int compare(MessageInfoHolder object1, MessageInfoHolder object2) { - if(object1.compareCounterparty == null){ + if (object1.compareCounterparty == null) { return (object2.compareCounterparty == null ? 0 : 1); - }else if (object2.compareCounterparty == null){ + } else if (object2.compareCounterparty == null) { return -1; - }else{ + } else { return object1.compareCounterparty.toLowerCase().compareTo(object2.compareCounterparty.toLowerCase()); } } @@ -185,11 +185,11 @@ public static class DateComparator implements Comparator { @Override public int compare(MessageInfoHolder object1, MessageInfoHolder object2) { - if(object1.compareDate == null){ + if (object1.compareDate == null) { return (object2.compareDate == null ? 0 : 1); - }else if(object2.compareDate == null){ + } else if (object2.compareDate == null) { return -1; - }else{ + } else { return object1.compareDate.compareTo(object2.compareDate); } } @@ -240,6 +240,7 @@ public int compare(MessageInfoHolder arg0, MessageInfoHolder arg1) { * Maps a {@link SORT_TYPE} to a {@link Comparator} implementation. */ private static final Map> SORT_COMPARATORS; + static { // fill the mapping at class time loading @@ -255,7 +256,6 @@ public int compare(MessageInfoHolder arg0, MessageInfoHolder arg1) { SORT_COMPARATORS = Collections.unmodifiableMap(map); } - private ListView mListView; private boolean mTouchView = true; @@ -422,28 +422,29 @@ public void run() { } - public void updateFooter(final String text, final boolean progressVisible){ - runOnUiThread(new Runnable(){ - public void run(){ + public void updateFooter(final String text, final boolean progressVisible) { + runOnUiThread(new Runnable() { + public void run() { FooterViewHolder holder = (FooterViewHolder) mFooterView.getTag(); holder.progress.setVisibility(progressVisible ? ProgressBar.VISIBLE : ProgressBar.INVISIBLE); - if(text!= null){ + if (text != null) { holder.main.setText(text); } - if(progressVisible || holder.main.getText().length() > 0){ + if (progressVisible || holder.main.getText().length() > 0) { mFooterView.setVisibility(View.VISIBLE); - } - else{ + } else { mFooterView.setVisibility(View.GONE); } } }); } - public void setWindowProgress(final int amt){ - runOnUiThread(new Runnable(){public void run(){ - getWindow().setFeatureInt(Window.FEATURE_PROGRESS, amt); - }}); + public void setWindowProgress(final int amt) { + runOnUiThread(new Runnable() { + public void run() { + getWindow().setFeatureInt(Window.FEATURE_PROGRESS, amt); + } + }); } private void resetUnreadCount() { @@ -549,7 +550,7 @@ public void run() { private void refreshTitleOnThread() { setWindowTitle(); - if(!mRemoteSearch){ + if (!mRemoteSearch) { setWindowProgress(); } } @@ -592,7 +593,6 @@ private void setWindowTitle() { setTitle(getString(R.string.search_results) + ": " + mQueryString); } } - //TODO: Update for ImapSearch } public void progress(final boolean progress) { @@ -705,18 +705,21 @@ public void onItemClick(AdapterView parent, View view, int position, long id) if (view == mFooterView) { if (mCurrentFolder != null && !mRemoteSearch) { mController.loadMoreMessages(mAccount, mFolderName, mAdapter.mListener); - } - else if(mRemoteSearch && mAdapter.mExtraSearchResults != null && mAdapter.mExtraSearchResults.size() > 0 && mSearchAccount != null){ + } else if (mRemoteSearch && mAdapter.mExtraSearchResults != null && mAdapter.mExtraSearchResults.size() > 0 && mSearchAccount != null) { int numResults = mAdapter.mExtraSearchResults.size(); Account account = Preferences.getPreferences(this).getAccount(mSearchAccount); + if (account == null) { + mHandler.updateFooter("", false); + return; + } int limit = account.getRemoteSearchNumResults(); List toProcess = mAdapter.mExtraSearchResults; - if(limit > 0 && numResults > limit){ + if (limit > 0 && numResults > limit) { toProcess = toProcess.subList(0, limit); mAdapter.mExtraSearchResults = mAdapter.mExtraSearchResults.subList(limit, mAdapter.mExtraSearchResults.size()); - } - else{ + } else { mAdapter.mExtraSearchResults = null; + mHandler.updateFooter("", false); } mController.loadSearchResults(account, mSearchFolder, toProcess, mAdapter.mListener); } @@ -770,17 +773,16 @@ private void initializeMessageList(Intent intent, boolean create) { mRemoteSearch = false; mSearchAccount = null; mSearchFolder = null; - if(mQueryString != null){ + if (mQueryString != null) { if (Intent.ACTION_SEARCH.equals(intent.getAction())) { //Query was received from Search Dialog Bundle appData = getIntent().getBundleExtra(SearchManager.APP_DATA); - if(appData != null){ + if (appData != null) { mSearchAccount = appData.getString(EXTRA_SEARCH_ACCOUNT); mSearchFolder = appData.getString(EXTRA_SEARCH_FOLDER); mRemoteSearch = appData.getBoolean(EXTRA_REMOTE_SEARCH); } - } - else{ + } else { mSearchAccount = intent.getStringExtra(EXTRA_SEARCH_ACCOUNT); mSearchFolder = intent.getStringExtra(EXTRA_SEARCH_FOLDER); @@ -898,7 +900,7 @@ public void onResume() { } - if(! (this instanceof Search)){ + if (!(this instanceof Search)) { //necessary b/c no guarantee Search.onStop will be called before MessageList.onResume //when returning from search results Search.setActive(false); @@ -923,17 +925,17 @@ public void onResume() { Preferences preferences = Preferences.getPreferences(this); accountsWithNotification = preferences.getAccounts(); } + for (Account accountWithNotification : accountsWithNotification) { mController.notifyAccountCancel(this, accountWithNotification); } if (mAdapter.messages.isEmpty()) { - if (mRemoteSearch){ + if (mRemoteSearch) { //TODO: Support flag based search mController.searchRemoteMessages(mSearchAccount, mSearchFolder, mQueryString, null, null, mAdapter.mListener); - } - else if (mFolderName != null) { + } else if (mFolderName != null) { mController.listLocalMessages(mAccount, mFolderName, mAdapter.mListener); } else if (mQueryString != null) { mController.searchLocalMessages(mAccountUuids, mFolderNames, null, mQueryString, mIntegrate, mQueryFlags, mForbiddenFlags, mAdapter.mListener); @@ -947,7 +949,7 @@ else if (mFolderName != null) { public void run() { - if (!mRemoteSearch){ + if (!mRemoteSearch) { mAdapter.markAllMessagesAsDirty(); if (mFolderName != null) { mController.listLocalMessagesSynchronous(mAccount, mFolderName, mAdapter.mListener); @@ -1214,9 +1216,8 @@ public boolean onKeyUp(int keyCode, KeyEvent event) { // Swallow these events too to avoid the audible notification of a volume change if (K9.useVolumeKeysForListNavigationEnabled()) { if ((keyCode == KeyEvent.KEYCODE_VOLUME_UP) || (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN)) { - if (K9.DEBUG) { + if (K9.DEBUG) Log.v(K9.LOG_TAG, "Swallowed key up."); - } return true; } } @@ -1293,39 +1294,39 @@ private void onEditAccount() { @Override public boolean onSearchRequested() { - if(mAccount != null && mCurrentFolder != null && mAccount.allowRemoteSearch()){ - //if in a remote searchable folder, ask user what they want. - //TODO: Add ability to remember selection? - final CharSequence[] items = new CharSequence[2]; - items[0] = getString(R.string.search_mode_local_all); - items[1] = getString(R.string.search_mode_remote); - - AlertDialog.Builder builder = new AlertDialog.Builder(this); - builder.setTitle(getString(R.string.search_mode_title)); - builder.setItems(items, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int item) { - - Bundle appData = null; - if(item == 1){ - appData = new Bundle(); - appData.putString(EXTRA_SEARCH_ACCOUNT, mAccount.getUuid()); - appData.putString(EXTRA_SEARCH_FOLDER, mCurrentFolder.name); - appData.putBoolean(EXTRA_REMOTE_SEARCH, true); - } - //else do regular search, which doesn't require any special parameter setup - - startSearch(null, false, appData, false); - } - }); - AlertDialog alert = builder.create(); - alert.show(); - - return true; - } - - startSearch(null, false, null, false); - return true; - } + if (mAccount != null && mCurrentFolder != null && mAccount.allowRemoteSearch()) { + //if in a remote searchable folder, ask user what they want. + //TODO: Add ability to remember selection? + final CharSequence[] items = new CharSequence[2]; + items[0] = getString(R.string.search_mode_local_all); + items[1] = getString(R.string.search_mode_remote); + + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setTitle(getString(R.string.search_mode_title)); + builder.setItems(items, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int item) { + + Bundle appData = null; + if (item == 1) { + appData = new Bundle(); + appData.putString(EXTRA_SEARCH_ACCOUNT, mAccount.getUuid()); + appData.putString(EXTRA_SEARCH_FOLDER, mCurrentFolder.name); + appData.putBoolean(EXTRA_REMOTE_SEARCH, true); + } + //else do regular search, which doesn't require any special parameter setup + + startSearch(null, false, appData, false); + } + }); + AlertDialog alert = builder.create(); + alert.show(); + + return true; + } + + startSearch(null, false, null, false); + return true; + } private void changeSort(SORT_TYPE newSortType) { if (sortType == newSortType) { @@ -1975,10 +1976,9 @@ class MessageListAdapter extends BaseAdapter { @Override public void remoteSearchAddMessage(Account account, String folderName, Message message, final int numDone, final int numTotal) { - if(numTotal > 0 && numDone < numTotal){ - mHandler.setWindowProgress(Window.PROGRESS_END/numTotal * numDone); - } - else{ + if (numTotal > 0 && numDone < numTotal) { + mHandler.setWindowProgress(Window.PROGRESS_END / numTotal * numDone); + } else { mHandler.setWindowProgress(Window.PROGRESS_END); } @@ -1986,29 +1986,29 @@ public void remoteSearchAddMessage(Account account, String folderName, Message m } @Override - public void remoteSearchFailed(Account acct, String folder, - final String err) { + public void remoteSearchFailed(Account acct, String folder, final String err) { //TODO: Better error handling - runOnUiThread(new Runnable(){public void run(){ - Toast.makeText(getApplication(), err, Toast.LENGTH_LONG).show(); - }}); + runOnUiThread(new Runnable() { + public void run() { + Toast.makeText(getApplication(), err, Toast.LENGTH_LONG).show(); + } + }); } @Override - public void remoteSearchStarted(Account acct, String folder){ + public void remoteSearchStarted(Account acct, String folder) { mHandler.progress(true); mHandler.updateFooter(getString(R.string.remote_search_sending_query), true); } @Override - public void remoteSearchFinished(Account acct, String folder, int numResults, List extraResults){ + public void remoteSearchFinished(Account acct, String folder, int numResults, List extraResults) { mHandler.progress(false); - if(extraResults != null && extraResults.size() > 0){ + if (extraResults != null && extraResults.size() > 0) { mExtraSearchResults = extraResults; mHandler.updateFooter(String.format(getString(R.string.load_more_messages_fmt), acct.getRemoteSearchNumResults()), false); - } - else{ + } else { mHandler.updateFooter("", false); } mHandler.setWindowProgress(Window.PROGRESS_END); @@ -2016,12 +2016,11 @@ public void remoteSearchFinished(Account acct, String folder, int numResults, Li } @Override - public void remoteSearchServerQueryComplete(Account account, String folderName, int numResults){ + public void remoteSearchServerQueryComplete(Account account, String folderName, int numResults) { mHandler.progress(true); - if(account != null && account.getRemoteSearchNumResults() != 0 && numResults > account.getRemoteSearchNumResults()){ + if (account != null && account.getRemoteSearchNumResults() != 0 && numResults > account.getRemoteSearchNumResults()) { mHandler.updateFooter(getString(R.string.remote_search_downloading_limited, account.getRemoteSearchNumResults(), numResults), true); - } - else{ + } else { mHandler.updateFooter(getString(R.string.remote_search_downloading, numResults), true); } mHandler.setWindowProgress(Window.PROGRESS_START); @@ -2161,7 +2160,11 @@ public void messageUidChanged(Account account, String folder, String oldUid, Str }; private boolean updateForMe(Account account, String folder) { - return account.equals(mAccount) && mFolderName != null && folder.equals(mFolderName); + if ((account.equals(mAccount) && mFolderName != null && folder.equals(mFolderName))) { + return true; + } else { + return false; + } } private Drawable mAttachmentIcon; @@ -2179,7 +2182,7 @@ public void markAllMessagesAsDirty() { } public void pruneDirtyMessages() { synchronized (mAdapter.messages) { - for(MessageInfoHolder holder : mAdapter.messages){ + for (MessageInfoHolder holder : mAdapter.messages) { if (holder.dirty) { if (holder.selected) { mSelectedCount--; diff --git a/src/com/fsck/k9/activity/Search.java b/src/com/fsck/k9/activity/Search.java index e022115a250..292ea9c7044 100644 --- a/src/com/fsck/k9/activity/Search.java +++ b/src/com/fsck/k9/activity/Search.java @@ -4,20 +4,22 @@ public class Search extends MessageList { protected static boolean isActive = false; - public static boolean isActive() { return isActive;} + public static boolean isActive() { + return isActive; + } - public static void setActive(boolean val){ + public static void setActive(boolean val) { isActive = val; } @Override - public void onStart(){ + public void onStart() { setActive(true); super.onStart(); } @Override - public void onStop(){ + public void onStop() { setActive(false); super.onStop(); } diff --git a/src/com/fsck/k9/activity/setup/AccountSettings.java b/src/com/fsck/k9/activity/setup/AccountSettings.java index 8f19fe09e8c..87a5bcd0167 100644 --- a/src/com/fsck/k9/activity/setup/AccountSettings.java +++ b/src/com/fsck/k9/activity/setup/AccountSettings.java @@ -440,7 +440,6 @@ public boolean onPreferenceChange(Preference preference, Object newValue) { mAccountDefault.setChecked( mAccount.equals(Preferences.getPreferences(this).getDefaultAccount())); - mAccountEnableMoveButtons = (CheckBoxPreference) findPreference(PREFERENCE_ENABLE_MOVE_BUTTONS); mAccountEnableMoveButtons.setEnabled(mIsMoveCapable); mAccountEnableMoveButtons.setChecked(mAccount.getEnableMoveButtons()); @@ -483,19 +482,18 @@ public boolean onPreferenceChange(Preference preference, Object newValue) { } }); } - - // IMAP-specific preferences mAllowRemoteSearch = (CheckBoxPreference) findPreference(PREFERENCE_ALLOW_REMOTE_SEARCH); - mAllowRemoteSearch.setOnPreferenceChangeListener(new OnPreferenceChangeListener() { - public boolean onPreferenceChange(Preference pref, Object newVal){ - if((Boolean) newVal){ - showRemoteSearchHelp(); - } - return true; - } - }); + mAllowRemoteSearch.setOnPreferenceChangeListener( + new OnPreferenceChangeListener() { + public boolean onPreferenceChange(Preference pref, Object newVal) { + if ((Boolean) newVal) { + showRemoteSearchHelp(); + } + return true; + } + }); mRemoteSearchNumResults = (ListPreference) findPreference(PREFERENCE_REMOTE_SEARCH_NUM_RESULTS); mRemoteSearchFullText = (CheckBoxPreference) findPreference(PREFERENCE_REMOTE_SEARCH_FULL_TEXT); mPushPollOnConnect = (CheckBoxPreference) findPreference(PREFERENCE_PUSH_POLL_ON_CONNECT); @@ -544,9 +542,9 @@ public boolean onPreferenceChange(Preference preference, Object newValue) { } }); } else { - final PreferenceScreen incomingPrefs = (PreferenceScreen) findPreference(PREFERENCE_SCREEN_INCOMING); - incomingPrefs.removePreference( (PreferenceScreen) findPreference(PREFERENCE_SCREEN_PUSH_ADVANCED)); - incomingPrefs.removePreference( (ListPreference) findPreference(PREFERENCE_PUSH_MODE)); + PreferenceScreen incomingPrefs = (PreferenceScreen) findPreference(PREFERENCE_SCREEN_INCOMING); + incomingPrefs.removePreference((PreferenceScreen) findPreference(PREFERENCE_SCREEN_PUSH_ADVANCED)); + incomingPrefs.removePreference((ListPreference) findPreference(PREFERENCE_PUSH_MODE)); ((PreferenceScreen) findPreference("main")).removePreference((PreferenceScreen) findPreference(PREFERENCE_SCREEN_REMOTE_SEARCH)); @@ -697,7 +695,7 @@ public boolean onPreferenceChange(Preference preference, Object newValue) { protected void showRemoteSearchHelp() { final String noShowHelpPref = "account_settings_remote_search_hide_help"; final SharedPreferences prefs = getPreferences(MODE_PRIVATE); - if(!prefs.getBoolean(noShowHelpPref, false)){ + if (!prefs.getBoolean(noShowHelpPref, false)) { AlertDialog.Builder adb = new AlertDialog.Builder(this); final CheckBox noShowAgain = new CheckBox(this); noShowAgain.setChecked(false); @@ -714,7 +712,7 @@ public void onClick(DialogInterface dialog, int which) { } } }); - adb.create().show(); + adb.create().show(); } } diff --git a/src/com/fsck/k9/controller/MessagingController.java b/src/com/fsck/k9/controller/MessagingController.java index 8afd810908a..b6ca7f2f2b4 100644 --- a/src/com/fsck/k9/controller/MessagingController.java +++ b/src/com/fsck/k9/controller/MessagingController.java @@ -136,24 +136,23 @@ public class MessagingController implements Runnable { private static final String PENDING_COMMAND_MARK_ALL_AS_READ = "com.fsck.k9.MessagingController.markAllAsRead"; private static final String PENDING_COMMAND_EXPUNGE = "com.fsck.k9.MessagingController.expunge"; - public static class UidReverseComparator implements Comparator{ + public static class UidReverseComparator implements Comparator { @Override public int compare(Message o1, Message o2) { - if(o1 == null || o2 == null || o1.getUid() == null || o2.getUid() == null){ + if (o1 == null || o2 == null || o1.getUid() == null || o2.getUid() == null) { return 0; } int id1, id2; - try{ + try { id1 = Integer.parseInt(o1.getUid()); id2 = Integer.parseInt(o2.getUid()); - } - catch(NumberFormatException e){ + } catch (NumberFormatException e) { return 0; } //reversed intentionally. - if(id1 < id2) + if (id1 < id2) return 1; - if(id1 > id2) + if (id1 > id2) return -1; return 0; } @@ -304,9 +303,8 @@ public void run() { if (command != null) { commandDescription = command.description; - if (K9.DEBUG) { + if (K9.DEBUG) Log.i(K9.LOG_TAG, "Running " + (command.isForeground ? "Foreground" : "Background") + " command '" + command.description + "', seq = " + command.sequence); - } mBusy = true; try { @@ -328,10 +326,9 @@ public void run() { } .start(); } - if (K9.DEBUG) { + if (K9.DEBUG) Log.i(K9.LOG_TAG, (command.isForeground ? "Foreground" : "Background") + " Command '" + command.description + "' completed"); - } for (MessagingListener l : getListeners(command.listener)) { l.controllerCommandCompleted(!mCommands.isEmpty()); @@ -636,9 +633,8 @@ private void addPendingMessages() { retrievalListener, false // Skip deleted messages ); - if (K9.DEBUG) { + if (K9.DEBUG) Log.v(K9.LOG_TAG, "Got ack that callbackRunner finished"); - } for (MessagingListener l : getListeners(listener)) { l.listLocalMessagesFinished(account, folder); @@ -828,13 +824,13 @@ public void messagesFinished(int number) { - public void searchRemoteMessages(final String acctUuid, final String folderName, final String query, final Flag[] requiredFlags, final Flag[] forbiddenFlags, final MessagingListener listener){ + public void searchRemoteMessages(final String acctUuid, final String folderName, final String query, final Flag[] requiredFlags, final Flag[] forbiddenFlags, final MessagingListener listener) { if (K9.DEBUG) { String msg = "searchRemoteMessages (" - + "acct=" + acctUuid - + ", folderName = " + folderName - + ", query = " + query - + ")"; + + "acct=" + acctUuid + + ", folderName = " + folderName + + ", query = " + query + + ")"; Log.i(K9.LOG_TAG, msg); } @@ -846,7 +842,7 @@ public void run() { }); } public void searchRemoteMessagesSynchronous(final String acctUuid, final String folderName, final String query, - final Flag[] requiredFlags, final Flag[] forbiddenFlags, final MessagingListener listener){ + final Flag[] requiredFlags, final Flag[] forbiddenFlags, final MessagingListener listener) { final Account acct = Preferences.getPreferences(mApplication.getApplicationContext()).getAccount(acctUuid); if (listener != null) { @@ -858,25 +854,25 @@ public void searchRemoteMessagesSynchronous(final String acctUuid, final String Store remoteStore = acct.getRemoteStore(); LocalStore localStore = acct.getLocalStore(); - if(remoteStore == null || localStore == null){ + if (remoteStore == null || localStore == null) { throw new MessagingException("Could not get store"); } Folder remoteFolder = remoteStore.getFolder(folderName); LocalFolder localFolder = localStore.getFolder(folderName); - if(remoteFolder == null || localFolder == null){ + if (remoteFolder == null || localFolder == null) { throw new MessagingException("Folder not found"); } - if(listener != null){ + if (listener != null) { listener.remoteSearchStarted(acct, folderName); } List messages = remoteStore.searchRemoteMessages(query, folderName, requiredFlags, forbiddenFlags); - if(listener != null){ + if (listener != null) { listener.remoteSearchServerQueryComplete(acct, folderName, messages.size()); } - if(K9.DEBUG){ + if (K9.DEBUG) { Log.i("Remote Search", "Remote search got " + messages.size() + " results"); } @@ -884,7 +880,7 @@ public void searchRemoteMessagesSynchronous(final String acctUuid, final String int resultLimit = acct.getRemoteSearchNumResults(); - if(resultLimit > 0 && messages.size() > resultLimit){ + if (resultLimit > 0 && messages.size() > resultLimit) { extraResults = messages.subList(resultLimit, messages.size()); messages = messages.subList(0, resultLimit); } @@ -905,27 +901,26 @@ public void searchRemoteMessagesSynchronous(final String acctUuid, final String } - public void loadSearchResults(final Account account, final String folderName, final List messages, final MessagingListener listener){ - threadPool.execute(new Runnable(){ + public void loadSearchResults(final Account account, final String folderName, final List messages, final MessagingListener listener) { + threadPool.execute(new Runnable() { @Override public void run() { - try{ + try { Store remoteStore = account.getRemoteStore(); LocalStore localStore = account.getLocalStore(); - if(remoteStore == null || localStore == null){ + if (remoteStore == null || localStore == null) { throw new MessagingException("Could not get store"); } Folder remoteFolder = remoteStore.getFolder(folderName); LocalFolder localFolder = localStore.getFolder(folderName); - if(remoteFolder == null || localFolder == null){ + if (remoteFolder == null || localFolder == null) { throw new MessagingException("Folder not found"); } loadSearchResultsSynchronous(messages, localFolder, remoteFolder, listener); - } - catch(MessagingException e){ + } catch (MessagingException e) { Log.e(K9.LOG_TAG, "Exception in loadSearchResults: " + e); addErrorMessage(account, null, e); } @@ -933,7 +928,7 @@ public void run() { }); } - public void loadSearchResultsSynchronous(List messages, LocalFolder localFolder, Folder remoteFolder, MessagingListener listener) throws MessagingException{ + public void loadSearchResultsSynchronous(List messages, LocalFolder localFolder, Folder remoteFolder, MessagingListener listener) throws MessagingException { FetchProfile fp_header = new FetchProfile(); fp_header.add(FetchProfile.Item.FLAGS); fp_header.add(FetchProfile.Item.ENVELOPE); @@ -941,11 +936,11 @@ public void loadSearchResultsSynchronous(List messages, LocalFolder loc fp_structure.add(FetchProfile.Item.STRUCTURE); int i = 0; - for(Message message : messages){ + for (Message message : messages) { i++; LocalMessage localMsg = localFolder.getMessage(message.getUid()); - if(localMsg == null){ + if (localMsg == null) { remoteFolder.fetch(new Message [] {message}, fp_header, null); //fun fact: ImapFolder.fetch can't handle getting STRUCTURE at same time as headers remoteFolder.fetch(new Message [] {message}, fp_structure, null); @@ -953,7 +948,7 @@ public void loadSearchResultsSynchronous(List messages, LocalFolder loc localMsg = localFolder.getMessage(message.getUid()); } - if(listener != null){ + if (listener != null) { listener.remoteSearchAddMessage(remoteFolder.getAccount(), remoteFolder.getName(), localMsg, i, messages.size()); } } @@ -1404,8 +1399,6 @@ private int downloadMessages(final Account account, final Folder remoteFolder, * fetch results for newest to oldest. If not, no harm done. */ Collections.sort(unsyncedMessages, new UidReverseComparator()); - - int visibleLimit = localFolder.getVisibleLimit(); int listSize = unsyncedMessages.size(); @@ -1413,7 +1406,6 @@ private int downloadMessages(final Account account, final Folder remoteFolder, unsyncedMessages = unsyncedMessages.subList(0, visibleLimit); } - FetchProfile fp = new FetchProfile(); if (remoteFolder.supportsFetchingFlags()) { fp.add(FetchProfile.Item.FLAGS); @@ -1480,7 +1472,6 @@ private int downloadMessages(final Account account, final Folder remoteFolder, if (K9.DEBUG) Log.d(K9.LOG_TAG, "SYNC: Synced remote messages for folder " + folder + ", " + newMessages.get() + " new messages"); - localFolder.purgeToVisibleLimit(new MessageRemovalListener() { @Override public void messageRemoved(Message message) { @@ -1491,7 +1482,6 @@ public void messageRemoved(Message message) { }); - // If the oldest message seen on this sync is newer than // the oldest message seen on the previous sync, then // we want to move our high-water mark forward @@ -2897,10 +2887,10 @@ public void run() { }); } - public void loadMessageForView(final Account account, final String folderName, final String uid, + public void loadMessageForView(final Account account, final String folder, final String uid, final MessagingListener listener) { for (MessagingListener l : getListeners(listener)) { - l.loadMessageForViewStarted(account, folderName, uid); + l.loadMessageForViewStarted(account, folder, uid); } threadPool.execute(new Runnable() { @Override @@ -2908,13 +2898,13 @@ public void run() { try { LocalStore localStore = account.getLocalStore(); - LocalFolder localFolder = localStore.getFolder(folderName); + LocalFolder localFolder = localStore.getFolder(folder); localFolder.open(OpenMode.READ_WRITE); LocalMessage message = localFolder.getMessage(uid); if (message == null || message.getId() == 0) { - throw new IllegalArgumentException("Message not found: folder=" + folderName + ", uid=" + uid); + throw new IllegalArgumentException("Message not found: folder=" + folder + ", uid=" + uid); } if (!message.isSet(Flag.SEEN)) { message.setFlag(Flag.SEEN, true); @@ -2922,7 +2912,7 @@ public void run() { } for (MessagingListener l : getListeners(listener)) { - l.loadMessageForViewHeadersAvailable(account, folderName, uid, message); + l.loadMessageForViewHeadersAvailable(account, folder, uid, message); } FetchProfile fp = new FetchProfile(); @@ -2934,16 +2924,16 @@ public void run() { localFolder.close(); for (MessagingListener l : getListeners(listener)) { - l.loadMessageForViewBodyAvailable(account, folderName, uid, message); + l.loadMessageForViewBodyAvailable(account, folder, uid, message); } for (MessagingListener l : getListeners(listener)) { - l.loadMessageForViewFinished(account, folderName, uid, message); + l.loadMessageForViewFinished(account, folder, uid, message); } } catch (Exception e) { for (MessagingListener l : getListeners(listener)) { - l.loadMessageForViewFailed(account, folderName, uid, e); + l.loadMessageForViewFailed(account, folder, uid, e); } addErrorMessage(account, null, e); diff --git a/src/com/fsck/k9/controller/MessagingListener.java b/src/com/fsck/k9/controller/MessagingListener.java index 8edbadbea86..5e1080a45ce 100644 --- a/src/com/fsck/k9/controller/MessagingListener.java +++ b/src/com/fsck/k9/controller/MessagingListener.java @@ -159,7 +159,7 @@ public void pendingCommandsFinished(Account account) {} * @param acct * @param folder */ - public void remoteSearchStarted(Account acct, String folder){} + public void remoteSearchStarted(Account acct, String folder) {} /** @@ -167,7 +167,7 @@ public void remoteSearchStarted(Account acct, String folder){} * * @param numResults */ - public void remoteSearchServerQueryComplete(Account account, String folderName, int numResults){ } + public void remoteSearchServerQueryComplete(Account account, String folderName, int numResults) { } /** @@ -177,7 +177,7 @@ public void remoteSearchServerQueryComplete(Account account, String folderName, * @param folder * @param message */ - public void remoteSearchAddMessage(Account account, String folder, Message message, int numDone, int numTotal){ } + public void remoteSearchAddMessage(Account account, String folder, Message message, int numDone, int numTotal) { } /** * Called when Remote Search is fully complete @@ -195,7 +195,7 @@ public void remoteSearchFinished(Account acct, String folder, int numResults, Li * @param folder * @param err */ - public void remoteSearchFailed(Account acct, String folder, String err){ } + public void remoteSearchFailed(Account acct, String folder, String err) { } /** * General notification messages subclasses can override to be notified that the controller @@ -207,6 +207,4 @@ public void remoteSearchFailed(Account acct, String folder, String err){ } * {@code false} otherwise. */ public void controllerCommandCompleted(boolean moreCommandsToRun) {} - - } diff --git a/src/com/fsck/k9/helper/MessageHelper.java b/src/com/fsck/k9/helper/MessageHelper.java index 01d777d089f..461d6a68ccd 100644 --- a/src/com/fsck/k9/helper/MessageHelper.java +++ b/src/com/fsck/k9/helper/MessageHelper.java @@ -91,7 +91,7 @@ public void populate(final MessageInfoHolder target, final Message message, } } public String formatDate(Date date) { - if (date==null){ + if (date == null) { return ""; } if (Utility.isDateToday(date)) { diff --git a/src/com/fsck/k9/mail/Store.java b/src/com/fsck/k9/mail/Store.java index 7d6644de850..7de55d325ce 100644 --- a/src/com/fsck/k9/mail/Store.java +++ b/src/com/fsck/k9/mail/Store.java @@ -179,7 +179,7 @@ public Account getAccount() { } public List searchRemoteMessages(String queryString, - String folder, final Flag[] requiredFlags, final Flag[] forbiddenFlags) throws MessagingException{ + String folder, final Flag[] requiredFlags, final Flag[] forbiddenFlags) throws MessagingException { throw new MessagingException("K-9 does not support remote searching on this account type"); } } diff --git a/src/com/fsck/k9/mail/internet/MimeMessage.java b/src/com/fsck/k9/mail/internet/MimeMessage.java index 8f5d2c6c2a2..161632d32b5 100644 --- a/src/com/fsck/k9/mail/internet/MimeMessage.java +++ b/src/com/fsck/k9/mail/internet/MimeMessage.java @@ -601,27 +601,27 @@ public MimeMessage clone() { return message; } - public boolean toMe(){ + public boolean toMe() { return false; } - public boolean ccMe(){ + public boolean ccMe() { return false; } - public boolean bccMe(){ + public boolean bccMe() { return false; } - public long getId(){ + public long getId() { return Long.parseLong(mUid); //or maybe .mMessageId? } - public String getPreview(){ + public String getPreview() { return ""; } - public boolean hasAttachments(){ + public boolean hasAttachments() { return false; } } diff --git a/src/com/fsck/k9/mail/store/ImapStore.java b/src/com/fsck/k9/mail/store/ImapStore.java index 84415bca6bf..0e96d27d32c 100644 --- a/src/com/fsck/k9/mail/store/ImapStore.java +++ b/src/com/fsck/k9/mail/store/ImapStore.java @@ -1171,7 +1171,6 @@ private int getRemoteMessageCount(String criteria) throws MessagingException { } - @Override public int getUnreadMessageCount() throws MessagingException { return getRemoteMessageCount("UNSEEN NOT DELETED"); @@ -1261,16 +1260,13 @@ public List search() throws IOException, MessagingException { return search(searcher, listener).toArray(EMPTY_MESSAGE_ARRAY); } - private List search(ImapSearcher searcher, MessageRetrievalListener msgListener) throws MessagingException { + private List search(ImapSearcher searcher, MessageRetrievalListener listener) throws MessagingException { checkOpen(); //only need READ access ArrayList messages = new ArrayList(); try { ArrayList uids = new ArrayList(); - - - List responses = searcher.search(); - + List responses = searcher.search(); // for (ImapResponse response : responses) { if (response.mTag == null) { if (ImapResponseParser.equalsIgnoreCase(response.get(0), "SEARCH")) { @@ -1288,20 +1284,18 @@ private List search(ImapSearcher searcher, MessageRetrievalListener msg Collections.sort(uids, Collections.reverseOrder()); for (int i = 0, count = uids.size(); i < count; i++) { - if (msgListener != null) { - msgListener.messageStarted("" + uids.get(i), i, count); + if (listener != null) { + listener.messageStarted("" + uids.get(i), i, count); } ImapMessage message = new ImapMessage("" + uids.get(i), this); - messages.add(message); - if (msgListener != null) { - msgListener.messageFinished(message, i, count); + if (listener != null) { + listener.messageFinished(message, i, count); } } } catch (IOException ioe) { throw ioExceptionHandler(mConnection, ioe); } - return messages; } @@ -3290,28 +3284,28 @@ public Object foundLiteral(ImapResponse response, @Override public List searchRemoteMessages(final String queryString, - final String folderName, final Flag[] requiredFlags, final Flag[] forbiddenFlags) throws MessagingException{ + final String folderName, final Flag[] requiredFlags, final Flag[] forbiddenFlags) throws MessagingException { - if(!mAccount.allowRemoteSearch()){ + if (!mAccount.allowRemoteSearch()) { throw new MessagingException("Your settings do not allow remote searching of this account"); } final ImapFolder folder = (ImapFolder) getFolder(folderName); - if(folder == null){ + if (folder == null) { throw new MessagingException("Invalid folder specified"); } - try{ + try { folder.open(OpenMode.READ_ONLY); folder.checkOpen(); - ImapSearcher searcher = new ImapSearcher(){ + ImapSearcher searcher = new ImapSearcher() { public List search() throws IOException, MessagingException { String imapQuery = "UID SEARCH "; - if(requiredFlags != null){ - for(Flag f : requiredFlags){ - switch(f){ + if (requiredFlags != null) { + for (Flag f : requiredFlags) { + switch (f) { case DELETED: imapQuery += "DELETED "; break; @@ -3338,9 +3332,9 @@ public List search() throws IOException, MessagingException { } } } - if(forbiddenFlags != null){ - for(Flag f : forbiddenFlags){ - switch(f){ + if (forbiddenFlags != null) { + for (Flag f : forbiddenFlags) { + switch (f) { case DELETED: imapQuery += "UNDELETED "; break; @@ -3368,10 +3362,9 @@ public List search() throws IOException, MessagingException { } } String encodedQry = encodeString(queryString); - if(mAccount.isRemoteSearchFullText()){ + if (mAccount.isRemoteSearchFullText()) { imapQuery += "TEXT " + encodedQry; - } - else{ + } else { imapQuery += "OR SUBJECT " + encodedQry + " FROM " + encodedQry; } return folder.executeSimpleCommand(imapQuery); @@ -3381,8 +3374,7 @@ public List search() throws IOException, MessagingException { //don't pass listener--we don't want to add messages until we've downloaded them return folder.search(searcher, null); - } - catch(Exception e){ + } catch (Exception e) { e.printStackTrace(); throw new MessagingException("Error during search: " + e.toString()); } diff --git a/src/com/fsck/k9/mail/store/LocalStore.java b/src/com/fsck/k9/mail/store/LocalStore.java index 7f2a6313d8c..7e8958e76d6 100644 --- a/src/com/fsck/k9/mail/store/LocalStore.java +++ b/src/com/fsck/k9/mail/store/LocalStore.java @@ -1148,10 +1148,9 @@ public long getId() { @Override public void open(final OpenMode mode) throws MessagingException { - if (isOpen() && (getMode() == mode || mode==OpenMode.READ_ONLY)) { + if (isOpen() && (getMode() == mode || mode == OpenMode.READ_ONLY)) { return; - } - else if (isOpen()){ + } else if (isOpen()) { //previously opened in READ_ONLY and now requesting READ_WRITE //so close connection and reopen close(); @@ -1364,7 +1363,7 @@ public int getVisibleLimit() throws MessagingException { public void purgeToVisibleLimit(MessageRemovalListener listener) throws MessagingException { //don't purge messages while a Search is active since it might throw away search results - if(!Search.isActive()){ + if (!Search.isActive()) { if (mVisibleLimit == 0) { return ; } diff --git a/src/com/fsck/k9/provider/MessageProvider.java b/src/com/fsck/k9/provider/MessageProvider.java index 8ea4f4847f8..f2c1ec6938c 100644 --- a/src/com/fsck/k9/provider/MessageProvider.java +++ b/src/com/fsck/k9/provider/MessageProvider.java @@ -60,7 +60,7 @@ public static interface MessageColumns extends BaseColumns { *

Type: TEXT

*/ String SENDER = "sender"; - + /** *

Type: TEXT

*/