diff --git a/src/com/fsck/k9/controller/MessagingController.java b/src/com/fsck/k9/controller/MessagingController.java index bc67559ae..dfb638828 100644 --- a/src/com/fsck/k9/controller/MessagingController.java +++ b/src/com/fsck/k9/controller/MessagingController.java @@ -69,6 +69,7 @@ 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; +import com.fsck.k9.search.LocalSearch; import com.fsck.k9.search.SearchSpecification; @@ -619,136 +620,39 @@ public class MessagingController implements Runnable { } } - public void searchLocalMessages(SearchSpecification searchSpecification, final Message[] messages, final MessagingListener listener) { - searchLocalMessages(searchSpecification.getAccountUuids(), searchSpecification.getFolderNames(), messages, - searchSpecification.getQuery(), searchSpecification.isIntegrate(), searchSpecification.getRequiredFlags(), searchSpecification.getForbiddenFlags(), listener); - } - - /** * Find all messages in any local account which match the query 'query' * @throws MessagingException */ - public void searchLocalMessages(final String[] accountUuids, final String[] folderNames, final Message[] messages, final String query, final boolean integrate, - final Flag[] requiredFlags, final Flag[] forbiddenFlags, final MessagingListener listener) { - if (K9.DEBUG) { - Log.i(K9.LOG_TAG, "searchLocalMessages (" - + "accountUuids=" + Utility.combine(accountUuids, ',') - + ", folderNames = " + Utility.combine(folderNames, ',') - + ", messages.size() = " + (messages != null ? messages.length : -1) - + ", query = " + query - + ", integrate = " + integrate - + ", requiredFlags = " + Utility.combine(requiredFlags, ',') - + ", forbiddenFlags = " + Utility.combine(forbiddenFlags, ',') - + ")"); - } - + public void searchLocalMessages(final LocalSearch search, final MessagingListener listener) { threadPool.execute(new Runnable() { @Override public void run() { - searchLocalMessagesSynchronous(accountUuids, folderNames, messages, query, integrate, requiredFlags, forbiddenFlags, listener); + searchLocalMessagesSynchronous(search, listener); } }); } - public void searchLocalMessagesSynchronous(final String[] accountUuids, final String[] folderNames, final Message[] messages, final String query, final boolean integrate, final Flag[] requiredFlags, final Flag[] forbiddenFlags, final MessagingListener listener) { - + + public void searchLocalMessagesSynchronous(final LocalSearch search, final MessagingListener listener) { final AccountStats stats = new AccountStats(); - final Set accountUuidsSet = new HashSet(); - if (accountUuids != null) { - accountUuidsSet.addAll(Arrays.asList(accountUuids)); - } - final Preferences prefs = Preferences.getPreferences(mApplication.getApplicationContext()); - List foldersToSearch = null; - boolean displayableOnly = false; - boolean noSpecialFolders = true; - for (final Account account : prefs.getAvailableAccounts()) { - if (accountUuids != null && !accountUuidsSet.contains(account.getUuid())) { - continue; - } - - if (accountUuids != null && accountUuidsSet.contains(account.getUuid())) { - displayableOnly = true; - noSpecialFolders = true; - } else if (!integrate && folderNames == null) { - Account.Searchable searchableFolders = account.getSearchableFolders(); - switch (searchableFolders) { - case NONE: - continue; - case DISPLAYABLE: - displayableOnly = true; - break; - - } - } - List messagesToSearch = null; - if (messages != null) { - messagesToSearch = new LinkedList(); - for (Message message : messages) { - if (message.getFolder().getAccount().getUuid().equals(account.getUuid())) { - messagesToSearch.add(message); - } - } - if (messagesToSearch.isEmpty()) { - continue; - } - } - if (listener != null) { - listener.listLocalMessagesStarted(account, null); - } - - if (integrate || displayableOnly || folderNames != null || noSpecialFolders) { - List tmpFoldersToSearch = new LinkedList(); - try { - LocalStore store = account.getLocalStore(); - List folders = store.getPersonalNamespaces(false); - Set folderNameSet = null; - if (folderNames != null) { - folderNameSet = new HashSet(); - folderNameSet.addAll(Arrays.asList(folderNames)); - } - for (Folder folder : folders) { - LocalFolder localFolder = (LocalFolder)folder; - boolean include = true; - folder.refresh(prefs); - String localFolderName = localFolder.getName(); - if (integrate) { - include = localFolder.isIntegrate(); - } else { - if (folderNameSet != null) { - if (!folderNameSet.contains(localFolderName)) - - { - include = false; - } - } - // Never exclude the INBOX (see issue 1817) - else if (noSpecialFolders && !localFolderName.equalsIgnoreCase(account.getInboxFolderName()) && - !localFolderName.equals(account.getArchiveFolderName()) && account.isSpecialFolder(localFolderName)) { - include = false; - } else if (displayableOnly && modeMismatch(account.getFolderDisplayMode(), folder.getDisplayClass())) { - include = false; - } - } - - if (include) { - tmpFoldersToSearch.add(localFolder); - } - } - if (tmpFoldersToSearch.size() < 1) { - continue; - } - foldersToSearch = tmpFoldersToSearch; - } catch (MessagingException me) { - Log.e(K9.LOG_TAG, "Unable to restrict search folders in Account " + account.getDescription() + ", searching all", me); - addErrorMessage(account, null, me); - } - - } - + final HashSet uuidSet = new HashSet(Arrays.asList(search.getAccountUuids())); + Account[] accounts = Preferences.getPreferences(mApplication.getApplicationContext()).getAccounts(); + boolean allAccounts = uuidSet.contains(SearchSpecification.ALL_ACCOUNTS); + + // for every account we want to search do the query in the localstore + for (final Account account : accounts) { + + if (!allAccounts && !uuidSet.contains(account.getUuid())) { + continue; + } + + // Collecting statistics of the search result MessageRetrievalListener retrievalListener = new MessageRetrievalListener() { @Override public void messageStarted(String message, int number, int ofTotal) {} @Override + public void messagesFinished(int number) {} + @Override public void messageFinished(Message message, int number, int ofTotal) { if (!isMessageSuppressed(message.getFolder().getAccount(), message.getFolder().getName(), message)) { List messages = new ArrayList(); @@ -760,22 +664,18 @@ public class MessagingController implements Runnable { listener.listLocalMessagesAddMessages(account, null, messages); } } - - } - @Override - public void messagesFinished(int number) { - } }; - + + // alert everyone the search has started + if (listener != null) { + listener.listLocalMessagesStarted(account, null); + } + + // build and do the query in the localstore try { - String[] queryFields = {"html_content", "subject", "sender_list"}; - LocalStore localStore = account.getLocalStore(); - localStore.searchForMessages(retrievalListener, queryFields - , query, foldersToSearch, - messagesToSearch == null ? null : messagesToSearch.toArray(EMPTY_MESSAGE_ARRAY), - requiredFlags, forbiddenFlags); - + LocalStore localStore = account.getLocalStore(); + localStore.searchForMessages(retrievalListener, search); } catch (Exception e) { if (listener != null) { listener.listLocalMessagesFailed(account, null, e.getMessage()); @@ -786,7 +686,9 @@ public class MessagingController implements Runnable { listener.listLocalMessagesFinished(account, null); } } - } + } + + // publish the total search statistics if (listener != null) { listener.searchStats(stats); } diff --git a/src/com/fsck/k9/mail/store/LocalStore.java b/src/com/fsck/k9/mail/store/LocalStore.java index 8c42b6f48..40893169e 100644 --- a/src/com/fsck/k9/mail/store/LocalStore.java +++ b/src/com/fsck/k9/mail/store/LocalStore.java @@ -69,6 +69,9 @@ import com.fsck.k9.mail.store.LockableDatabase.DbCallback; import com.fsck.k9.mail.store.LockableDatabase.WrappedException; import com.fsck.k9.mail.store.StorageManager.StorageProvider; import com.fsck.k9.provider.AttachmentProvider; +import com.fsck.k9.search.ConditionsTreeNode; +import com.fsck.k9.search.LocalSearch; +import com.fsck.k9.search.SearchSpecification.SEARCHFIELD; /** *
@@ -658,6 +661,22 @@ public class LocalStore extends Store implements Serializable {
         return new LocalFolder(name);
     }
 
+    private long getFolderId(final String name) throws MessagingException {
+        return database.execute(false, new DbCallback() {
+            @Override
+            public Long doDbWork(final SQLiteDatabase db) {
+                Cursor cursor = null;
+                try {
+                	cursor = db.rawQuery("SELECT id FROM folders WHERE name = '" + name + "'", null);
+                    cursor.moveToFirst();
+                    return cursor.getLong(0);        
+                } finally {
+                    Utility.closeQuietly(cursor);
+                }
+            }
+        });
+    }
+    
     // TODO this takes about 260-300ms, seems slow.
     @Override
     public List  getPersonalNamespaces(boolean forceListAll) throws MessagingException {
@@ -890,97 +909,57 @@ public class LocalStore extends Store implements Serializable {
         return true;
     }
 
-    public Message[] searchForMessages(MessageRetrievalListener listener, String[] queryFields, String queryString,
-                                       List folders, Message[] messages, final Flag[] requiredFlags, final Flag[] forbiddenFlags) throws MessagingException {
-        List args = new LinkedList();
-
-        StringBuilder whereClause = new StringBuilder();
-        if (queryString != null && queryString.length() > 0) {
-            boolean anyAdded = false;
-            String likeString = "%" + queryString + "%";
-            whereClause.append(" AND (");
-            for (String queryField : queryFields) {
-
-                if (anyAdded) {
-                    whereClause.append(" OR ");
+    // TODO find beter solution
+    private static boolean isFolderId(String str) {
+        if (str == null) {
+                return false;
+        }
+        int length = str.length();
+        if (length == 0) {
+                return false;
+        }
+        int i = 0;
+        if (str.charAt(0) == '-') {
+        	return false;
+        }
+        for (; i < length; i++) {
+                char c = str.charAt(i);
+                if (c <= '/' || c >= ':') {
+                        return false;
                 }
-                whereClause.append(queryField).append(" LIKE ? ");
-                args.add(likeString);
-                anyAdded = true;
-            }
-
-
-            whereClause.append(" )");
         }
-        if (folders != null && !folders.isEmpty()) {
-            whereClause.append(" AND folder_id in (");
-            boolean anyAdded = false;
-            for (LocalFolder folder : folders) {
-                if (anyAdded) {
-                    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) {
-                    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) {
-                    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) {
-                    whereClause.append(" OR ");
-                }
-                anyAdded = true;
-                whereClause.append(" flags LIKE ?");
-
-                args.add("%" + flag.toString() + "%");
-            }
-            whereClause.append(" )");
-        }
-
-        if (K9.DEBUG) {
-            Log.v(K9.LOG_TAG, "whereClause = " + whereClause.toString());
-            Log.v(K9.LOG_TAG, "args = " + args);
-        }
-        return getMessages(
-                   listener,
-                   null,
-                   "SELECT "
-                   + GET_MESSAGES_COLS
-                   + "FROM messages WHERE (empty IS NULL OR empty != 1) AND deleted = 0 " + whereClause.toString() + " ORDER BY date DESC"
-                   , args.toArray(EMPTY_STRING_ARRAY)
-               );
+        return true;
     }
+    
+	public Message[] searchForMessages(MessageRetrievalListener retrievalListener,
+										LocalSearch search) throws MessagingException {  
+		
+		// update some references in the search that have to be bound to this one store
+		for (ConditionsTreeNode node : search.getLeafSet()) {
+			if (node.mCondition.field == SEARCHFIELD.FOLDER) {	
+				// TODO find better solution
+				if (isFolderId(node.mCondition.value)) {
+					continue;
+				}
+				
+				if (node.mCondition.value.equals(LocalSearch.GENERIC_INBOX_NAME)) {
+					node.mCondition.value = mAccount.getInboxFolderName();
+				}
+				node.mCondition.value = String.valueOf(getFolderId(node.mCondition.value));
+			}
+		}
+
+    	// build sql query       
+        String sqlQuery = "SELECT " + GET_MESSAGES_COLS + "FROM messages WHERE deleted = 0 " 
+        				+ (search.getConditions() != null ? "AND (" + search.getConditions() + ")" : "") + " ORDER BY date DESC";
+        
+        if (K9.DEBUG) {
+            Log.d(K9.LOG_TAG, "Query = " + sqlQuery);
+        }
+        
+		return getMessages(retrievalListener, null, sqlQuery, new String[] {});
+	}
+	
     /*
      * Given a query string, actually do the query for the messages and
      * call the MessageRetrievalListener for each one