mirror of
https://github.com/moparisthebest/k-9
synced 2024-12-26 01:28:50 -05:00
Add new search logic to the MessagingController and LocalStore classes.
This commit is contained in:
parent
5c6552cbf3
commit
d27f909600
@ -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<String> accountUuidsSet = new HashSet<String>();
|
||||
if (accountUuids != null) {
|
||||
accountUuidsSet.addAll(Arrays.asList(accountUuids));
|
||||
}
|
||||
final Preferences prefs = Preferences.getPreferences(mApplication.getApplicationContext());
|
||||
List<LocalFolder> 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<Message> messagesToSearch = null;
|
||||
if (messages != null) {
|
||||
messagesToSearch = new LinkedList<Message>();
|
||||
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<LocalFolder> tmpFoldersToSearch = new LinkedList<LocalFolder>();
|
||||
try {
|
||||
LocalStore store = account.getLocalStore();
|
||||
List <? extends Folder > folders = store.getPersonalNamespaces(false);
|
||||
Set<String> folderNameSet = null;
|
||||
if (folderNames != null) {
|
||||
folderNameSet = new HashSet<String>();
|
||||
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<String> uuidSet = new HashSet<String>(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<Message> messages = new ArrayList<Message>();
|
||||
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
@ -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<Long>() {
|
||||
@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 <? extends Folder > 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<LocalFolder> folders, Message[] messages, final Flag[] requiredFlags, final Flag[] forbiddenFlags) throws MessagingException {
|
||||
List<String> args = new LinkedList<String>();
|
||||
|
||||
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
|
||||
|
Loading…
Reference in New Issue
Block a user