Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also compare across forks.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also compare across forks.
base fork: rbayer/k-9
...
head fork: rbayer/k-9
  • 2 commits
  • 10 files changed
  • 0 commit comments
  • 1 contributor
Commits on Mar 04, 2012
@rbayer Prevent delete of search results while search results open b3569e5
Commits on Mar 05, 2012
@rbayer Refactor to allow fetching of extra search results beyond original re…
…quest. Most code moved out of ImapStore and ImapFolder and into MessagingController.searchRemoteMessagesSynchronous. Should make it easier to add remoteSearch for other server types.
ece589d
View
65 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<Message> 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;
}
@@ -877,6 +896,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 +1214,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;
}
}
@@ -1939,37 +1967,21 @@ public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuIn
class MessageListAdapter extends BaseAdapter {
private final List<MessageInfoHolder> messages = java.util.Collections.synchronizedList(new ArrayList<MessageInfoHolder>());
+ public List<Message> 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){
- 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);
}
@@ -1990,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<Message> 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
View
22 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();
+ }
+
+
}
View
175 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 @@
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<Message>{
+ @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
*/
@@ -280,8 +304,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 +328,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 +583,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<Message> pendingMessages = new ArrayList<Message>();
@@ -599,16 +625,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);
@@ -818,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<Message> extraResults = new ArrayList<Message>();
+ 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){
-
- 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);
- }
- }
+ Folder remoteFolder = remoteStore.getFolder(folderName);
+ LocalFolder localFolder = localStore.getFolder(folderName);
+ if(remoteFolder == null || localFolder == null){
+ throw new MessagingException("Folder not found");
+ }
+ if(listener != null){
+ listener.remoteSearchStarted(acct, folderName);
+ }
+ List<Message> 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) {
@@ -878,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<Message> 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<Message> 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());
+ }
+ }
}
@@ -1333,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);
@@ -1407,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) {
@@ -1417,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
@@ -2071,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;
@@ -2836,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);
@@ -3236,7 +3311,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 {
}
View
7 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<Message> extraResults) {}
/**
* Called when there was a problem with a remote search operation.
View
6 src/com/fsck/k9/controller/SearchListener.java
@@ -1,6 +0,0 @@
-package com.fsck.k9.controller;
-
-public interface SearchListener {
- public void searchStarted();
- public void searchFinished(int numResults);
-}
View
5 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 {
View
4 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<Message> 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");
}
View
41 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(){
View
208 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<ImapResponse> 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 @@ protected int getHighestUid() {
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 Message getMessage(String uid) throws 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<Integer> mesgSeqs, final boolean includeDeleted, final MessageRetrievalListener listener)
@@ -1325,7 +1248,7 @@ public Message getMessage(String uid) throws 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<String> mesgUids, final boolean includeDeleted, final MessageRetrievalListener listener)
@@ -1335,23 +1258,16 @@ public Message getMessage(String uid) throws 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<Message> search(ImapSearcher searcher, MessageRetrievalListener msgListener) throws MessagingException {
checkOpen(); //only need READ access
ArrayList<Message> messages = new ArrayList<Message>();
try {
ArrayList<Integer> uids = new ArrayList<Integer>();
- if(searchListener != null){
- searchListener.searchStarted();
- }
List<ImapResponse> responses = searcher.search();
@@ -1365,42 +1281,18 @@ public Message getMessage(String uid) throws MessagingException {
}
}
- 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 @@ public Message getMessage(String uid) throws MessagingException {
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<Message> 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<ImapResponse> 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){
View
43 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();
-
}
}
@@ -1840,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<Message>() {
+ return database.execute(false, new DbCallback<LocalMessage>() {
@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);
@@ -2091,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();

No commit comments for this range

Something went wrong with that request. Please try again.