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:
parent
d2d7d858db
commit
6c81fc5261
@ -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
|
||||
|
@ -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
|
||||
*
|
||||
|
@ -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");
|
||||
|
@ -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 {
|
||||
|
Loading…
Reference in New Issue
Block a user