diff --git a/res/menu/folder_list_option.xml b/res/menu/folder_list_option.xml index 06eb78b6d..f82765a9f 100644 --- a/res/menu/folder_list_option.xml +++ b/res/menu/folder_list_option.xml @@ -7,7 +7,6 @@ android:icon="@drawable/ic_menu_compose" /> diff --git a/res/values/arrays.xml b/res/values/arrays.xml index f18a098e8..4f0bee339 100644 --- a/res/values/arrays.xml +++ b/res/values/arrays.xml @@ -91,6 +91,18 @@ KEYBOARD_AVAILABLE ALWAYS + + + @string/account_settings_searchable_all + @string/account_settings_searchable_displayable + @string/account_settings_searchable_none + + + + ALL + DISPLAYABLE + NONE + @string/account_settings_folder_sync_mode_all diff --git a/res/values/strings.xml b/res/values/strings.xml index faaf1c9ff..f04a9adeb 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -678,7 +678,27 @@ Welcome to K-9 Mail setup. K-9 is an open source mail client for Android origin Use gaudy visual effects Gestures Accept gesture control - + + All unread messages + Unread messages in searchable accounts + + All starred messages + Starred messages in searchable accounts + + Integrated Inbox (unread) + All unread messages in integrated folders + + Integrated Inbox (starred) + All starred messages in integrated folders + + Integrate + Unread messages are shown in Integrated Inbox + + Folders to search + All + Displayable + None + K-9 Mail remote control Allows this application to control K-9 Mail activities and settings. diff --git a/res/xml/account_settings_preferences.xml b/res/xml/account_settings_preferences.xml index 50738ff7d..ea0a88fd2 100644 --- a/res/xml/account_settings_preferences.xml +++ b/res/xml/account_settings_preferences.xml @@ -125,6 +125,13 @@ android:entries="@array/account_settings_folder_target_mode_entries" android:entryValues="@array/account_settings_folder_target_mode_values" android:dialogTitle="@string/account_settings_folder_target_mode_label" /> + + diff --git a/res/xml/folder_settings_preferences.xml b/res/xml/folder_settings_preferences.xml index b30aeb9c9..a97903120 100644 --- a/res/xml/folder_settings_preferences.xml +++ b/res/xml/folder_settings_preferences.xml @@ -45,7 +45,10 @@ android:entryValues="@array/folder_settings_folder_push_mode_values" android:dialogTitle="@string/folder_settings_folder_push_mode_label" /> - + diff --git a/src/com/fsck/k9/Account.java b/src/com/fsck/k9/Account.java index bf563c839..a7db6b3c7 100644 --- a/src/com/fsck/k9/Account.java +++ b/src/com/fsck/k9/Account.java @@ -5,6 +5,8 @@ import android.content.Context; import android.content.SharedPreferences; import android.net.ConnectivityManager; import android.net.Uri; +import android.util.Log; + import com.fsck.k9.mail.Address; import com.fsck.k9.mail.Folder; import com.fsck.k9.mail.MessagingException; @@ -38,7 +40,8 @@ public class Account public static final String TYPE_MOBILE = "MOBILE"; public static final String TYPE_OTHER = "OTHER"; private static String[] networkTypes = { TYPE_WIFI, TYPE_MOBILE, TYPE_OTHER }; - + + /** *
      * 0 - Never (DELETE_POLICY_NEVER)
@@ -79,6 +82,7 @@ public class Account
     private String mExpungePolicy = EXPUNGE_IMMEDIATELY;
     private int mMaxPushFolders;
     private Map compressionMap = new ConcurrentHashMap(); 
+    private Searchable searchableFolders;
     // Tracks if we have sent a notification for this account for
     // current set of fetched messages
     private boolean mRingNotified;
@@ -93,9 +97,13 @@ public class Account
     public enum HideButtons
     {
         NEVER, ALWAYS, KEYBOARD_AVAILABLE;
+    } 
+    
+    public enum Searchable 
+    {
+        ALL, DISPLAYABLE, NONE
     }
 
-
     protected Account(Context context)
     {
         // TODO Change local store path to something readable / recognizable
@@ -119,6 +127,7 @@ public class Account
         mExpungePolicy = EXPUNGE_IMMEDIATELY;
         mAutoExpandFolderName = "INBOX";
         mMaxPushFolders = 10;
+        searchableFolders = Searchable.ALL;
         
         identities = new ArrayList();
 
@@ -257,6 +266,16 @@ public class Account
         {
             mFolderTargetMode = FolderMode.NOT_SECOND_CLASS;
         }
+        
+        try
+        {
+            searchableFolders = Searchable.valueOf(preferences.getPreferences().getString(mUuid  + ".searchableFolders",
+                                                   Searchable.ALL.name()));
+        }
+        catch (Exception e)
+        {
+            searchableFolders = Searchable.ALL;
+        }
 
         mIsSignatureBeforeQuotedText = preferences.getPreferences().getBoolean(mUuid  + ".signatureBeforeQuotedText", false);
         identities = loadIdentities(preferences.getPreferences());
@@ -312,6 +331,7 @@ public class Account
         editor.remove(mUuid + ".signatureBeforeQuotedText");
         editor.remove(mUuid + ".expungePolicy");
         editor.remove(mUuid + ".maxPushFolders");
+        editor.remove(mUuid  + ".searchableFolders");
         for (String type : networkTypes)
         {
             editor.remove(mUuid + ".useCompression." + type);
@@ -388,6 +408,7 @@ public class Account
         editor.putBoolean(mUuid + ".signatureBeforeQuotedText", this.mIsSignatureBeforeQuotedText);
         editor.putString(mUuid + ".expungePolicy", mExpungePolicy);
         editor.putInt(mUuid + ".maxPushFolders", mMaxPushFolders);
+        editor.putString(mUuid  + ".searchableFolders", searchableFolders.name());
         for (String type : networkTypes)
         {
             Boolean useCompression = compressionMap.get(type);
@@ -403,6 +424,7 @@ public class Account
     }
 
     //TODO: Shouldn't this live in MessagingController?
+    // Why should everything be in MessagingController? This is an Account-specific operation. --danapple0
     public int getUnreadMessageCount(Context context) throws MessagingException
     {
         int unreadMessageCount = 0;
@@ -1042,4 +1064,14 @@ public class Account
         }
         return null;
     }
+
+    public Searchable getSearchableFolders()
+    {
+        return searchableFolders;
+    }
+
+    public void setSearchableFolders(Searchable searchableFolders)
+    {
+        this.searchableFolders = searchableFolders;
+    }
 }
diff --git a/src/com/fsck/k9/MessagingController.java b/src/com/fsck/k9/MessagingController.java
index f24c3ffd1..ac4c3eacb 100644
--- a/src/com/fsck/k9/MessagingController.java
+++ b/src/com/fsck/k9/MessagingController.java
@@ -714,9 +714,9 @@ public class MessagingController implements Runnable
      * @param listener
      * @throws MessagingException
      */
-    public void searchLocalMessages(final Account account, final String query, final MessagingListener listener)
+    public void searchLocalMessages(final String query, final Message[] messages, final boolean integrate, final Flag[] requiredFlags, final Flag[] forbiddenFlags, 
+            final MessagingListener listener)
     {
-
         if (listener == null)
         {
             return;
@@ -726,38 +726,85 @@ public class MessagingController implements Runnable
             public void run()
             {
 
-
-                Preferences prefs = Preferences.getPreferences(mApplication.getApplicationContext());
+                final Preferences prefs = Preferences.getPreferences(mApplication.getApplicationContext());
                 Account[] accounts = prefs.getAccounts();
-
-                listener.listLocalMessagesStarted(account, null);
+                List foldersToSearch = null;
+                boolean displayableOnly = false;
                 for (final Account account : accounts)
                 {
-
-
+                    Account.Searchable searchableFolders = account.getSearchableFolders();
+                    switch (searchableFolders)
+                    {
+                        case NONE:
+                            continue;
+                        case DISPLAYABLE:
+                            displayableOnly = true;
+                            break;
+                            
+                    }
+                    
+                    listener.listLocalMessagesStarted(account, null);
+                    
+                    if (integrate || displayableOnly)
+                    {
+                        List tmpFoldersToSearch = new LinkedList();
+                        try
+                        {
+                            LocalStore store = account.getLocalStore();
+                            LocalFolder[] folders = store.getPersonalNamespaces();
+                            for (LocalFolder folder : folders)
+                            {
+                                boolean include = true;
+                                folder.refresh(prefs);
+                                if (displayableOnly && modeMismatch(account.getFolderDisplayMode(), folder.getDisplayClass()))
+                                {
+                                    include = false;
+                                }
+                                if (integrate && folder.isIntegrate() == false)
+                                {
+                                    include = false;
+                                    
+                                }
+                                if (include)
+                                {
+                                    tmpFoldersToSearch.add(folder);
+                                }
+                            }
+                            foldersToSearch = tmpFoldersToSearch;
+                        }
+                        catch (MessagingException me)
+                        {
+                            Log.e(K9.LOG_TAG, "Unable to restrict search folders in Account " + account.getDescription() + ", searching all", me);
+                            addErrorMessage(account, me);
+                        }
+                        
+                    }
+                    
                     MessageRetrievalListener retrievalListener = new MessageRetrievalListener()
                     {
-
-
-                        int totalDone = 0;
-
                         public void messageStarted(String message, int number, int ofTotal) {}
                         public void messageFinished(Message message, int number, int ofTotal)
                         {
                             List messages = new ArrayList();
+                            LocalFolder localFolder = (LocalStore.LocalFolder)message.getFolder();
+                            if (localFolder.getName().equals(localFolder.getAccount().getErrorFolderName()))
+                            {
+                                return;
+                            }
+                            
                             messages.add(message);
                             listener.listLocalMessagesAddMessages(account, null, messages);
+                            
                         }
                         public void messagesFinished(int number) {}
                         private void addPendingMessages() {}
                     };
 
-
-
                     try
                     {
                         LocalStore localStore = account.getLocalStore();
-                        localStore.searchForMessages(retrievalListener, query);
+                        localStore.searchForMessages(retrievalListener, query, foldersToSearch, messages, requiredFlags, forbiddenFlags);
+                        
                     }
                     catch (Exception e)
                     {
@@ -1213,11 +1260,6 @@ public class MessagingController implements Runnable
                     if (K9.DEBUG)
                         Log.v(K9.LOG_TAG, "Message with uid " + message.getUid() + " is already locally present");
 
-                    String newPushState = remoteFolder.getNewPushState(localFolder.getPushState(), message);
-                    if (newPushState != null)
-                    {
-                        localFolder.setPushState(newPushState);
-                    }
                     if (!localMessage.isSet(Flag.X_DOWNLOADED_FULL) && !localMessage.isSet(Flag.X_DOWNLOADED_PARTIAL))
                     {
                         if (K9.DEBUG)
@@ -1228,6 +1270,11 @@ public class MessagingController implements Runnable
                     }
                     else
                     {
+                        String newPushState = remoteFolder.getNewPushState(localFolder.getPushState(), message);
+                        if (newPushState != null)
+                        {
+                            localFolder.setPushState(newPushState);
+                        }
                         syncFlagMessages.add(message);
                     }
                 }
diff --git a/src/com/fsck/k9/activity/Accounts.java b/src/com/fsck/k9/activity/Accounts.java
index 0cb9245ec..a75a7ccad 100644
--- a/src/com/fsck/k9/activity/Accounts.java
+++ b/src/com/fsck/k9/activity/Accounts.java
@@ -21,6 +21,8 @@ import com.fsck.k9.*;
 import com.fsck.k9.activity.setup.AccountSettings;
 import com.fsck.k9.activity.setup.AccountSetupBasics;
 import com.fsck.k9.activity.setup.Prefs;
+import com.fsck.k9.mail.Flag;
+
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 
@@ -36,6 +38,10 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
 
     private AccountsHandler mHandler = new AccountsHandler();
     private AccountsAdapter mAdapter;
+    private SearchAccount unreadAccount = null;
+    private SearchAccount flaggedAccount = null;
+    private SearchAccount integratedInboxAccount = null;
+    private SearchAccount integratedInboxStarredAccount = null;
 
 
     class AccountsHandler extends Handler
@@ -269,6 +275,22 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
     @Override
     public void onCreate(Bundle icicle)
     {
+        unreadAccount = new SearchAccount(this, false, null, new Flag[] { Flag.SEEN } );
+        unreadAccount.setDescription(getString(R.string.search_unread_messages_title));
+        unreadAccount.setEmail(getString(R.string.search_unread_messages_detail));
+        
+        flaggedAccount = new SearchAccount(this, false, new Flag[] { Flag.FLAGGED }, null);
+        flaggedAccount.setDescription(getString(R.string.search_starred_messages_title));
+        flaggedAccount.setEmail(getString(R.string.search_starred_messages_detail));
+        
+        integratedInboxAccount = new SearchAccount(this, true, null,  new Flag[] { Flag.SEEN });
+        integratedInboxAccount.setDescription(getString(R.string.integrated_inbox_title));
+        integratedInboxAccount.setEmail(getString(R.string.integrated_inbox_detail));
+        
+        integratedInboxStarredAccount = new SearchAccount(this, true, new Flag[] { Flag.FLAGGED },  null);
+        integratedInboxStarredAccount.setDescription(getString(R.string.integrated_inbox_starred_title));
+        integratedInboxStarredAccount.setEmail(getString(R.string.integrated_inbox_starred_detail));
+        
         super.onCreate(icicle);
 
         Account[] accounts = Preferences.getPreferences(this).getAccounts();
@@ -339,7 +361,15 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
     private void refresh()
     {
         Account[] accounts = Preferences.getPreferences(this).getAccounts();
-        mAdapter = new AccountsAdapter(accounts);
+        
+        Account[] newAccounts = new Account[accounts.length + 4];
+        newAccounts[0] = integratedInboxAccount;
+        newAccounts[1] = integratedInboxStarredAccount;
+        newAccounts[2] = unreadAccount;
+        newAccounts[3] = flaggedAccount;
+        System.arraycopy(accounts, 0, newAccounts, 4, accounts.length);
+       
+        mAdapter = new AccountsAdapter(newAccounts);
         getListView().setAdapter(mAdapter);
         if (accounts.length > 0)
         {
@@ -355,6 +385,7 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
             MessagingController.getInstance(getApplication()).getAccountUnreadCount(Accounts.this, account, mListener);
 
         }
+        
     }
 
     private void onAddNewAccount()
@@ -409,7 +440,12 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
 
     private void onOpenAccount(Account account)
     {
-        if (K9.FOLDER_NONE.equals(account.getAutoExpandFolderName()))
+        if (account instanceof SearchAccount)
+        {
+            SearchAccount searchAccount = (SearchAccount)account;
+            MessageList.actionHandle(this, searchAccount.getDescription(), "", searchAccount.isIntegrate(), searchAccount.getRequiredFlags(), searchAccount.getForbiddenFlags());
+        }
+        else if (K9.FOLDER_NONE.equals(account.getAutoExpandFolderName()))
         {
             FolderList.actionHandleAccount(this, account);
         }
@@ -649,6 +685,20 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
         super.onCreateContextMenu(menu, v, menuInfo);
         menu.setHeaderTitle(R.string.accounts_context_menu_title);
         getMenuInflater().inflate(R.menu.accounts_context, menu);
+        
+        AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo;
+        Account account = (Account) mAdapter.getItem(info.position);
+        if (account instanceof SearchAccount)
+        {
+            for (int i = 0; i < menu.size(); i++)
+            {
+                MenuItem item = menu.getItem(i);
+                if (item.getItemId() != R.id.open)
+                {
+                    item.setVisible(false);
+                }
+            }
+        }
     }
 
     class AccountsAdapter extends ArrayAdapter
@@ -701,7 +751,10 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
                 //holder.newMessageCount.setText("-");
                 holder.newMessageCount.setVisibility(View.GONE);
             }
-            holder.chip.setBackgroundResource(K9.COLOR_CHIP_RES_IDS[account.getAccountNumber() % K9.COLOR_CHIP_RES_IDS.length]);
+            if (!(account instanceof SearchAccount))
+            {
+                holder.chip.setBackgroundResource(K9.COLOR_CHIP_RES_IDS[account.getAccountNumber() % K9.COLOR_CHIP_RES_IDS.length]);
+            }
 
             if (unreadMessageCount == null)
             {
@@ -728,4 +781,43 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
             public View chip;
         }
     }
+    private class SearchAccount extends Account
+    {
+        private Flag[] mRequiredFlags = null;
+        private Flag[] mForbiddenFlags = null;
+        private String email = null;
+        private boolean mIntegrate = false;
+        
+         private SearchAccount(Context context, boolean integrate, Flag[] requiredFlags, Flag[] forbiddenFlags)
+         {
+             super(context);
+             mRequiredFlags = requiredFlags;
+             mForbiddenFlags = forbiddenFlags;
+             mIntegrate = integrate;
+         }
+        public String getEmail()
+        {
+            return email;
+        }
+        public void setEmail(String email)
+        {
+            this.email = email;
+        }
+        public Flag[] getRequiredFlags()
+        {
+            return mRequiredFlags;
+        }
+        public Flag[] getForbiddenFlags()
+        {
+            return mForbiddenFlags;
+        }
+        public boolean isIntegrate()
+        {
+            return mIntegrate;
+        }
+        public void setIntegrate(boolean integrate)
+        {
+            this.mIntegrate = integrate;
+        }
+    }
 }
diff --git a/src/com/fsck/k9/activity/FolderList.java b/src/com/fsck/k9/activity/FolderList.java
index 4bf7d1e78..79aadb393 100644
--- a/src/com/fsck/k9/activity/FolderList.java
+++ b/src/com/fsck/k9/activity/FolderList.java
@@ -812,12 +812,12 @@ public class FolderList extends K9ListActivity
                 List topFolders = new LinkedList();
 
                 Account.FolderMode aMode = account.getFolderDisplayMode();
-
+                Preferences prefs = Preferences.getPreferences(getApplication().getApplicationContext());
                 for (Folder folder : folders)
                 {
                     try
                     {
-                        folder.refresh(Preferences.getPreferences(getApplication().getApplicationContext()));
+                        folder.refresh(prefs);
 
                         Folder.FolderClass fMode = folder.getDisplayClass();
 
diff --git a/src/com/fsck/k9/activity/MessageList.java b/src/com/fsck/k9/activity/MessageList.java
index 3cd6bf3e5..8f6d6c8a0 100644
--- a/src/com/fsck/k9/activity/MessageList.java
+++ b/src/com/fsck/k9/activity/MessageList.java
@@ -66,6 +66,11 @@ public class MessageList
     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_QUERY_FLAGS = "queryFlags";
+    private static final String EXTRA_FORBIDDEN_FLAGS = "forbiddenFlags";
+    private static final String EXTRA_INTEGRATE = "integrate";
+    private static final String EXTRA_TITLE = "title";
+
 
     private ListView mListView;
 
@@ -92,6 +97,10 @@ public class MessageList
 
     /* if we're doing a search, this contains the query string */
     private String mQueryString;
+    private Flag[] mQueryFlags = null;
+    private Flag[] mForbiddenFlags = null;
+    private boolean mIntegrate = false;
+    private String mTitle;
 
     private MessageListHandler mHandler = new MessageListHandler();
 
@@ -253,7 +262,14 @@ public class MessageList
             }
             else if (mQueryString != null)
             {
-                setTitle(getString(R.string.search_results) + ": "+ mQueryString);
+                if (mTitle != null)
+                {
+                    setTitle(mTitle);
+                }
+                else
+                {
+                    setTitle(getString(R.string.search_results) + ": "+ mQueryString);
+                }
             }
         }
 
@@ -292,6 +308,24 @@ public class MessageList
         }
         return intent;
     }
+    
+    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);
+        if (flags != null)
+        {
+            intent.putExtra(EXTRA_QUERY_FLAGS, Utility.combine(flags, ','));
+        }
+        if (forbiddenFlags != null)
+        {
+            intent.putExtra(EXTRA_FORBIDDEN_FLAGS, Utility.combine(forbiddenFlags, ','));
+        }
+        intent.putExtra(EXTRA_INTEGRATE, integrate);
+        intent.putExtra(EXTRA_TITLE, title);
+        context.startActivity(intent);
+
+    }
 
     public void onItemClick(AdapterView parent, View v, int position, long id)
     {
@@ -335,7 +369,30 @@ public class MessageList
         mAccount = Preferences.getPreferences(this).getAccount(accountUuid);
         mFolderName = intent.getStringExtra(EXTRA_FOLDER);
         mQueryString = intent.getStringExtra(EXTRA_QUERY);
-
+        
+        String queryFlags = intent.getStringExtra(EXTRA_QUERY_FLAGS);
+        if (queryFlags != null)
+        {
+            String[] flagStrings = queryFlags.split(",");
+            mQueryFlags = new Flag[flagStrings.length];
+            for (int i = 0; i < flagStrings.length; i++)
+            {
+                mQueryFlags[i] = Flag.valueOf(flagStrings[i]);
+            }
+        }
+        String forbiddenFlags = intent.getStringExtra(EXTRA_FORBIDDEN_FLAGS);
+        if (forbiddenFlags != null)
+        {
+            String[] flagStrings = forbiddenFlags.split(",");
+            mForbiddenFlags = new Flag[flagStrings.length];
+            for (int i = 0; i < flagStrings.length; i++)
+            {
+                mForbiddenFlags[i] = Flag.valueOf(flagStrings[i]);
+            }
+        }
+        mIntegrate = intent.getBooleanExtra(EXTRA_INTEGRATE, false);
+        mTitle = intent.getStringExtra(EXTRA_TITLE);
+        
         // Take the initial folder into account only if we are *not* restoring the
         // activity already
 
@@ -407,8 +464,7 @@ public class MessageList
         }
         else if (mQueryString != null)
         {
-            mController.searchLocalMessages(mAccount, mQueryString,  mAdapter.mListener);
-
+            mController.searchLocalMessages(mQueryString, null, mIntegrate, mQueryFlags, mForbiddenFlags, mAdapter.mListener);
         }
 
         mHandler.refreshTitle();
diff --git a/src/com/fsck/k9/activity/setup/AccountSettings.java b/src/com/fsck/k9/activity/setup/AccountSettings.java
index cfc79e762..2603294af 100644
--- a/src/com/fsck/k9/activity/setup/AccountSettings.java
+++ b/src/com/fsck/k9/activity/setup/AccountSettings.java
@@ -47,6 +47,7 @@ public class AccountSettings extends K9PreferenceActivity
     private static final String PREFERENCE_DELETE_POLICY = "delete_policy";
     private static final String PREFERENCE_EXPUNGE_POLICY = "expunge_policy";
     private static final String PREFERENCE_AUTO_EXPAND_FOLDER = "account_setup_auto_expand_folder";
+    private static final String PREFERENCE_SEARCHABLE_FOLDERS = "searchable_folders";
 
 
     private Account mAccount;
@@ -68,6 +69,7 @@ public class AccountSettings extends K9PreferenceActivity
     private ListPreference mTargetMode;
     private ListPreference mDeletePolicy;
     private ListPreference mExpungePolicy;
+    private ListPreference mSearchableFolders;
     private Preference mAutoExpandFolder;
     private boolean mIncomingChanged = false;
 
@@ -244,6 +246,21 @@ public class AccountSettings extends K9PreferenceActivity
                 return false;
             }
         });
+        
+        mSearchableFolders = (ListPreference) findPreference(PREFERENCE_SEARCHABLE_FOLDERS);
+        mSearchableFolders.setValue(mAccount.getSearchableFolders().name());
+        mSearchableFolders.setSummary(mSearchableFolders.getEntry());
+        mSearchableFolders.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener()
+        {
+            public boolean onPreferenceChange(Preference preference, Object newValue)
+            {
+                final String summary = newValue.toString();
+                int index = mSearchableFolders.findIndexOfValue(summary);
+                mSearchableFolders.setSummary(mSearchableFolders.getEntries()[index]);
+                mSearchableFolders.setValue(summary);
+                return false;
+            }
+        });
 
         mDisplayCount = (ListPreference) findPreference(PREFERENCE_DISPLAY_COUNT);
         mDisplayCount.setValue(String.valueOf(mAccount.getDisplayCount()));
@@ -379,6 +396,7 @@ public class AccountSettings extends K9PreferenceActivity
         mAccount.setFolderTargetMode(Account.FolderMode.valueOf(mTargetMode.getValue()));
         mAccount.setDeletePolicy(Integer.parseInt(mDeletePolicy.getValue()));
         mAccount.setExpungePolicy(mExpungePolicy.getValue());
+        mAccount.setSearchableFolders(Account.Searchable.valueOf(mSearchableFolders.getValue()));
         
         boolean needsRefresh = mAccount.setAutomaticCheckIntervalMinutes(Integer.parseInt(mCheckFrequency.getValue()));
         needsRefresh |= mAccount.setFolderSyncMode(Account.FolderMode.valueOf(mSyncMode.getValue()));
diff --git a/src/com/fsck/k9/activity/setup/FolderSettings.java b/src/com/fsck/k9/activity/setup/FolderSettings.java
index 7b444a97d..d1017d3ef 100644
--- a/src/com/fsck/k9/activity/setup/FolderSettings.java
+++ b/src/com/fsck/k9/activity/setup/FolderSettings.java
@@ -28,10 +28,12 @@ public class FolderSettings extends K9PreferenceActivity
     private static final String PREFERENCE_SYNC_CLASS = "folder_settings_folder_sync_mode";
     private static final String PREFERENCE_PUSH_CLASS = "folder_settings_folder_push_mode";
     private static final String PREFERENCE_IN_TOP_GROUP = "folder_settings_in_top_group";
+    private static final String PREFERENCE_INTEGRATE = "folder_settings_include_in_integrated_inbox";
 
     private LocalFolder mFolder;
 
     private CheckBoxPreference mInTopGroup;
+    private CheckBoxPreference mIntegrate;
     private ListPreference mDisplayClass;
     private ListPreference mSyncClass;
     private ListPreference mPushClass;
@@ -85,6 +87,8 @@ public class FolderSettings extends K9PreferenceActivity
         
         mInTopGroup = (CheckBoxPreference)findPreference(PREFERENCE_IN_TOP_GROUP);
         mInTopGroup.setChecked(mFolder.isInTopGroup());
+        mIntegrate = (CheckBoxPreference)findPreference(PREFERENCE_INTEGRATE);
+        mIntegrate.setChecked(mFolder.isIntegrate());
         
         mDisplayClass = (ListPreference) findPreference(PREFERENCE_DISPLAY_CLASS);
         mDisplayClass.setValue(mFolder.getDisplayClass().name());
@@ -150,6 +154,7 @@ public class FolderSettings extends K9PreferenceActivity
     private void saveSettings()
     {
         mFolder.setInTopGroup(mInTopGroup.isChecked());
+        mFolder.setIntegrate(mIntegrate.isChecked());
         // We call getPushClass() because display class changes can affect push class when push class is set to inherit
         FolderClass oldPushClass = mFolder.getPushClass();
         FolderClass oldDisplayClass = mFolder.getDisplayClass();
diff --git a/src/com/fsck/k9/mail/Store.java b/src/com/fsck/k9/mail/Store.java
index daba084a9..7a43a4da6 100644
--- a/src/com/fsck/k9/mail/Store.java
+++ b/src/com/fsck/k9/mail/Store.java
@@ -28,7 +28,7 @@ public abstract class Store
     //Matching MessagingController.MAX_SMALL_MESSAGE_SIZE
     public static final int FETCH_BODY_SANE_SUGGESTED_SIZE = (50 * 1024);
 
-    protected static final int SOCKET_CONNECT_TIMEOUT = 10000;
+    protected static final int SOCKET_CONNECT_TIMEOUT = 30000;
     protected static final int SOCKET_READ_TIMEOUT = 60000;
 
     private static HashMap mStores = new HashMap();
diff --git a/src/com/fsck/k9/mail/store/LocalStore.java b/src/com/fsck/k9/mail/store/LocalStore.java
index cbb7b8321..2be5c7a3c 100644
--- a/src/com/fsck/k9/mail/store/LocalStore.java
+++ b/src/com/fsck/k9/mail/store/LocalStore.java
@@ -35,7 +35,7 @@ import java.util.regex.Matcher;
 public class LocalStore extends Store implements Serializable
 {
     private static final int DB_VERSION = 33;
-    private static final Flag[] PERMANENT_FLAGS = { Flag.DELETED, Flag.X_DESTROYED, Flag.SEEN };
+    private static final Flag[] PERMANENT_FLAGS = { Flag.DELETED, Flag.X_DESTROYED, Flag.SEEN, Flag.FLAGGED };
 
     private String mPath;
     private SQLiteDatabase mDb;
@@ -594,22 +594,97 @@ public class LocalStore extends Store implements Serializable
         return true;
     }
 
-    public Message[] searchForMessages(MessageRetrievalListener listener, String queryString) throws MessagingException
+    public Message[] searchForMessages(MessageRetrievalListener listener, String queryString, 
+            List folders, Message[] messages, final Flag[] requiredFlags, final Flag[] forbiddenFlags) throws MessagingException
     {
-
-        queryString = "%"+queryString+"%";
+        List args = new LinkedList();
+        
+        StringBuilder whereClause = new StringBuilder();
+        if (queryString != null && queryString.length() > 0)
+        {
+            String likeString = "%"+queryString+"%";
+            whereClause.append(" AND (html_content LIKE ? OR subject LIKE ? OR sender_list LIKE ?)");
+            args.add(likeString);
+            args.add(likeString);
+            args.add(likeString);
+        }
+        if (folders != null && folders.size() > 0)
+        {
+            whereClause.append(" AND folder_id in (");
+            boolean anyAdded = false;
+            for (LocalFolder folder : folders)
+            {
+                if (anyAdded == true)
+                {
+                    whereClause.append(",");
+                }
+                anyAdded = true;
+                whereClause.append("?");
+                args.add(Long.toString(folder.getId()));
+            }
+            whereClause.append(" )");
+        }
+        if (messages != null && messages.length > 0)
+        {
+            whereClause.append(" AND ( ");
+            boolean anyAdded = false;
+            for (Message message : messages)
+            {
+                if (anyAdded == true)
+                {
+                    whereClause.append(" OR ");
+                }
+                anyAdded = true;
+                whereClause.append(" ( uid = ? AND folder_id = ? ) ");
+                args.add(message.getUid());
+                args.add(Long.toString(((LocalFolder)message.getFolder()).getId()));
+            }
+            whereClause.append(" )");
+        }
+        if (forbiddenFlags != null && forbiddenFlags.length > 0)
+        {
+            whereClause.append(" AND (");
+            boolean anyAdded = false;
+            for (Flag flag : forbiddenFlags)
+            {
+                if (anyAdded == true)
+                {
+                    whereClause.append(" AND ");
+                }
+                anyAdded = true;
+                whereClause.append(" flags NOT LIKE ?");
+                
+                args.add("%" + flag.toString() + "%");
+            }
+            whereClause.append(" )");
+        }
+        if (requiredFlags != null && requiredFlags.length > 0)
+        {
+            whereClause.append(" AND (");
+            boolean anyAdded = false;
+            for (Flag flag : requiredFlags)
+            {
+                if (anyAdded == true)
+                {
+                    whereClause.append(" OR ");
+                }
+                anyAdded = true;
+                whereClause.append(" flags LIKE ?");
+                
+                args.add("%" + flag.toString() + "%");
+            }
+            whereClause.append(" )");
+        }
+        
+        Log.i(K9.LOG_TAG, "whereClause = " + whereClause.toString());
+        Log.i(K9.LOG_TAG, "args = " + args);
         return getMessages(
                    listener,
                    null,
                    "SELECT "
                    + GET_MESSAGES_COLS
-                   + "FROM messages WHERE deleted = 0 AND (html_content LIKE ? OR subject LIKE ? OR sender_list LIKE ?) ORDER BY date DESC"
-                   , new String[]
-                   {
-                       queryString,
-                       queryString,
-                       queryString
-                   }
+                   + "FROM messages WHERE deleted = 0 " + whereClause.toString() + " ORDER BY date DESC"
+                   , args.toArray(new String[0])
                );
     }
     /*
@@ -631,7 +706,6 @@ public class LocalStore extends Store implements Serializable
 
 
             int i = 0;
-            ArrayList messagesForHeaders = new ArrayList();
             while (cursor.moveToNext())
             {
                 LocalMessage message = new LocalMessage(null, folder);
@@ -674,6 +748,7 @@ public class LocalStore extends Store implements Serializable
         private boolean inTopGroup = false;
         private String prefId = null;
         private String mPushState = null;
+        private boolean mIntegrate = false;
 
 
         public LocalFolder(String name)
@@ -735,6 +810,7 @@ public class LocalStore extends Store implements Serializable
                 }
                 else
                 {
+                    Log.w(K9.LOG_TAG, "Creating folder " + getName() + " with existing id " + getId());
                     create(FolderType.HOLDS_MESSAGES);
                     open(mode);
                 }
@@ -1005,7 +1081,16 @@ public class LocalStore extends Store implements Serializable
         {
             this.pushClass = pushClass;
         }
-
+        
+        public boolean isIntegrate()
+        {
+            return mIntegrate;
+        }
+        public void setIntegrate(boolean integrate)
+        {
+            mIntegrate = integrate;
+        }
+        
         private String getPrefId() throws MessagingException
         {
             open(OpenMode.READ_WRITE);
@@ -1028,6 +1113,7 @@ public class LocalStore extends Store implements Serializable
             editor.remove(id + ".syncMode");
             editor.remove(id + ".pushMode");
             editor.remove(id + ".inTopGroup");
+            editor.remove(id + ".integrate");
 
             editor.commit();
         }
@@ -1066,6 +1152,8 @@ public class LocalStore extends Store implements Serializable
             }
             editor.putBoolean(id + ".inTopGroup", inTopGroup);
 
+            editor.putBoolean(id + ".integrate", mIntegrate);
+
             editor.commit();
         }
         public void refresh(Preferences preferences) throws MessagingException
@@ -1114,10 +1202,12 @@ public class LocalStore extends Store implements Serializable
 
             FolderClass defPushClass = FolderClass.SECOND_CLASS;
             boolean defInTopGroup = false;
+            boolean defIntegrate = false;
             if (K9.INBOX.equals(getName()))
             {
                 defPushClass =  FolderClass.FIRST_CLASS;
                 defInTopGroup = true;
+                defIntegrate = true;
             }
 
             try
@@ -1136,6 +1226,7 @@ public class LocalStore extends Store implements Serializable
                 pushClass = FolderClass.INHERITED;
             }
             inTopGroup = preferences.getPreferences().getBoolean(id + ".inTopGroup", defInTopGroup);
+            mIntegrate = preferences.getPreferences().getBoolean(id + ".integrate", defIntegrate);
 
         }
 
@@ -2202,6 +2293,7 @@ public class LocalStore extends Store implements Serializable
             this.setRecipients(RecipientType.CC, Address.unpack(cursor.getString(7)));
             this.setRecipients(RecipientType.BCC, Address.unpack(cursor.getString(8)));
             this.setReplyTo(Address.unpack(cursor.getString(9)));
+
             this.mAttachmentCount = cursor.getInt(10);
             this.setInternalDate(new Date(cursor.getLong(11)));
             this.setMessageId(cursor.getString(12));