1
0
mirror of https://github.com/moparisthebest/k-9 synced 2025-01-05 18:58:10 -05:00

Add spam filtering capability to MessagingController

This commit is contained in:
cketti 2013-01-13 12:44:16 +01:00
parent d2d7d858db
commit 6c81fc5261
4 changed files with 67 additions and 7 deletions

View File

@ -294,6 +294,8 @@ public class K9 extends Application {
public static final String IDENTITY_HEADER = "X-K9mail-Identity";
public static final String SPAM_FLAG_HEADER = "X-Spam-Flag";
/**
* Specifies how many messages will be shown in a folder by default. This number is set
* on each new folder and can be incremented with "Load more messages..." by the

View File

@ -1256,6 +1256,7 @@ public class MessagingController implements Runnable {
messages.clear();
final ArrayList<Message> largeMessages = new ArrayList<Message>();
final ArrayList<Message> smallMessages = new ArrayList<Message>();
final Map<String, String> spamMessages = new HashMap<String, String>();
if (!unsyncedMessages.isEmpty()) {
/*
@ -1280,7 +1281,33 @@ public class MessagingController implements Runnable {
Log.d(K9.LOG_TAG, "SYNC: About to fetch " + unsyncedMessages.size() + " unsynced messages for folder " + folder);
fetchUnsyncedMessages(account, remoteFolder, localFolder, unsyncedMessages, smallMessages, largeMessages, progress, todo, fp);
fetchUnsyncedMessages(account, remoteFolder, localFolder, unsyncedMessages, smallMessages, largeMessages, spamMessages, progress, todo, fp);
if (spamMessages.size() > 0) {
if (K9.DEBUG) {
Log.d(K9.LOG_TAG, "Moving " + spamMessages.size() +
" messages to the Spam folder.");
}
queueMoveOrCopy(account, localFolder.getName(), account.getSpamFolderName(), false,
spamMessages.keySet().toArray(EMPTY_STRING_ARRAY), spamMessages);
spamMessages.clear();
try {
processPendingCommandsSynchronous(account);
} catch (Exception e) {
addErrorMessage(account, null, e);
Log.e(K9.LOG_TAG, "Failure processing command, but continuing message sync attempt", e);
}
// FIXME: This is bad!
// ImapStore is using a cache for ImapFolder instances which causes our remoteFolder
// object to be used and later closed by processPendingMoveOrCopy(). So we have to
// re-open it here.
if (!remoteFolder.isOpen()) {
remoteFolder.open(OpenMode.READ_WRITE);
}
}
// If a message didn't exist, messageFinished won't be called, but we shouldn't try again
// If we got here, nothing failed
@ -1433,6 +1460,7 @@ public class MessagingController implements Runnable {
List<Message> unsyncedMessages,
final ArrayList<Message> smallMessages,
final ArrayList<Message> largeMessages,
final Map<String, String> spamMessages,
final AtomicInteger progress,
final int todo,
FetchProfile fp) throws MessagingException {
@ -1445,6 +1473,11 @@ public class MessagingController implements Runnable {
*/
final List<Message> chunk = new ArrayList<Message>(UNSYNC_CHUNK_SIZE);
final String spamFolderName = account.getSpamFolderName();
final LocalFolder spamFolder = account.getLocalStore().getFolder(spamFolderName);
final boolean isSpamFilterEnabled = (account.isSpamAssassinFilterEnabled() &&
!spamFolder.equals(localFolder));
remoteFolder.fetch(unsyncedMessages.toArray(EMPTY_MESSAGE_ARRAY), fp,
new MessageRetrievalListener() {
@Override
@ -1472,6 +1505,15 @@ public class MessagingController implements Runnable {
return;
}
if (isSpamFilterEnabled && isSpam(message)) {
// Write message to the local Spam folder
Map<String, String> uidMap = spamFolder.insertAsLocalMessages(
new Message[] { message });
spamMessages.putAll(uidMap);
return;
}
if (account.getMaximumAutoDownloadMessageSize() > 0 &&
message.getSize() > account.getMaximumAutoDownloadMessageSize()) {
largeMessages.add(message);
@ -1518,6 +1560,11 @@ public class MessagingController implements Runnable {
}
}
private boolean isSpam(Message message) throws MessagingException {
String[] headers = message.getHeader(K9.SPAM_FLAG_HEADER);
return (headers != null && headers.length > 0 && headers[0].equalsIgnoreCase("YES"));
}
/**
* Actual storing of messages
*

View File

@ -1492,7 +1492,8 @@ public class ImapStore extends Store {
fetchFields.add("INTERNALDATE");
fetchFields.add("RFC822.SIZE");
fetchFields.add("BODY.PEEK[HEADER.FIELDS (date subject from content-type to cc " +
"reply-to message-id references in-reply-to " + K9.IDENTITY_HEADER + ")]");
"reply-to message-id references in-reply-to " + K9.SPAM_FLAG_HEADER +
" " + K9.IDENTITY_HEADER + ")]");
}
if (fp.contains(FetchProfile.Item.STRUCTURE)) {
fetchFields.add("BODYSTRUCTURE");

View File

@ -2130,7 +2130,7 @@ public class LocalStore extends Store implements Serializable {
if (!(folder instanceof LocalFolder)) {
throw new MessagingException("copyMessages called with incorrect Folder");
}
return ((LocalFolder) folder).appendMessages(msgs, true);
return ((LocalFolder) folder).appendMessages(msgs, true, false);
}
@Override
@ -2299,7 +2299,7 @@ public class LocalStore extends Store implements Serializable {
*/
@Override
public Map<String, String> appendMessages(Message[] messages) throws MessagingException {
return appendMessages(messages, false);
return appendMessages(messages, false, false);
}
public void destroyMessages(final Message[] messages) {
@ -2389,6 +2389,11 @@ public class LocalStore extends Store implements Serializable {
return null;
}
public Map<String, String> insertAsLocalMessages(Message[] messages)
throws MessagingException {
return appendMessages(messages, false, true);
}
/**
* The method differs slightly from the contract; If an incoming message already has a uid
* assigned and it matches the uid of an existing message then this message will replace
@ -2401,9 +2406,14 @@ public class LocalStore extends Store implements Serializable {
* message, retrieve the appropriate local message instance first (if it already exists).
* @param messages
* @param copy
* @param createAsLocal
* If {@code true} the message will get a local UID. The mapping is added to the map
* that is returned by this method.
*
* @return Map<String, String> uidMap of srcUids -> destUids
*/
private Map<String, String> appendMessages(final Message[] messages, final boolean copy) throws MessagingException {
private Map<String, String> appendMessages(final Message[] messages, final boolean copy,
final boolean createAsLocal) throws MessagingException {
open(OpenMode.READ_WRITE);
try {
final Map<String, String> uidMap = new HashMap<String, String>();
@ -2418,14 +2428,14 @@ public class LocalStore extends Store implements Serializable {
long oldMessageId = -1;
String uid = message.getUid();
if (uid == null || copy) {
if (uid == null || copy || createAsLocal) {
/*
* Create a new message in the database
*/
String randomLocalUid = K9.LOCAL_UID_PREFIX +
UUID.randomUUID().toString();
if (copy) {
if (copy || createAsLocal) {
// Save mapping: source UID -> target UID
uidMap.put(uid, randomLocalUid);
} else {