mirror of
https://github.com/moparisthebest/k-9
synced 2025-01-07 11:48:07 -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 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
|
* 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
|
* 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();
|
messages.clear();
|
||||||
final ArrayList<Message> largeMessages = new ArrayList<Message>();
|
final ArrayList<Message> largeMessages = new ArrayList<Message>();
|
||||||
final ArrayList<Message> smallMessages = new ArrayList<Message>();
|
final ArrayList<Message> smallMessages = new ArrayList<Message>();
|
||||||
|
final Map<String, String> spamMessages = new HashMap<String, String>();
|
||||||
if (!unsyncedMessages.isEmpty()) {
|
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);
|
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 a message didn't exist, messageFinished won't be called, but we shouldn't try again
|
||||||
// If we got here, nothing failed
|
// If we got here, nothing failed
|
||||||
@ -1433,6 +1460,7 @@ public class MessagingController implements Runnable {
|
|||||||
List<Message> unsyncedMessages,
|
List<Message> unsyncedMessages,
|
||||||
final ArrayList<Message> smallMessages,
|
final ArrayList<Message> smallMessages,
|
||||||
final ArrayList<Message> largeMessages,
|
final ArrayList<Message> largeMessages,
|
||||||
|
final Map<String, String> spamMessages,
|
||||||
final AtomicInteger progress,
|
final AtomicInteger progress,
|
||||||
final int todo,
|
final int todo,
|
||||||
FetchProfile fp) throws MessagingException {
|
FetchProfile fp) throws MessagingException {
|
||||||
@ -1445,6 +1473,11 @@ public class MessagingController implements Runnable {
|
|||||||
*/
|
*/
|
||||||
final List<Message> chunk = new ArrayList<Message>(UNSYNC_CHUNK_SIZE);
|
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,
|
remoteFolder.fetch(unsyncedMessages.toArray(EMPTY_MESSAGE_ARRAY), fp,
|
||||||
new MessageRetrievalListener() {
|
new MessageRetrievalListener() {
|
||||||
@Override
|
@Override
|
||||||
@ -1472,6 +1505,15 @@ public class MessagingController implements Runnable {
|
|||||||
return;
|
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 &&
|
if (account.getMaximumAutoDownloadMessageSize() > 0 &&
|
||||||
message.getSize() > account.getMaximumAutoDownloadMessageSize()) {
|
message.getSize() > account.getMaximumAutoDownloadMessageSize()) {
|
||||||
largeMessages.add(message);
|
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
|
* Actual storing of messages
|
||||||
*
|
*
|
||||||
|
@ -1492,7 +1492,8 @@ public class ImapStore extends Store {
|
|||||||
fetchFields.add("INTERNALDATE");
|
fetchFields.add("INTERNALDATE");
|
||||||
fetchFields.add("RFC822.SIZE");
|
fetchFields.add("RFC822.SIZE");
|
||||||
fetchFields.add("BODY.PEEK[HEADER.FIELDS (date subject from content-type to cc " +
|
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)) {
|
if (fp.contains(FetchProfile.Item.STRUCTURE)) {
|
||||||
fetchFields.add("BODYSTRUCTURE");
|
fetchFields.add("BODYSTRUCTURE");
|
||||||
|
@ -2130,7 +2130,7 @@ public class LocalStore extends Store implements Serializable {
|
|||||||
if (!(folder instanceof LocalFolder)) {
|
if (!(folder instanceof LocalFolder)) {
|
||||||
throw new MessagingException("copyMessages called with incorrect Folder");
|
throw new MessagingException("copyMessages called with incorrect Folder");
|
||||||
}
|
}
|
||||||
return ((LocalFolder) folder).appendMessages(msgs, true);
|
return ((LocalFolder) folder).appendMessages(msgs, true, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -2299,7 +2299,7 @@ public class LocalStore extends Store implements Serializable {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Map<String, String> appendMessages(Message[] messages) throws MessagingException {
|
public Map<String, String> appendMessages(Message[] messages) throws MessagingException {
|
||||||
return appendMessages(messages, false);
|
return appendMessages(messages, false, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void destroyMessages(final Message[] messages) {
|
public void destroyMessages(final Message[] messages) {
|
||||||
@ -2389,6 +2389,11 @@ public class LocalStore extends Store implements Serializable {
|
|||||||
return null;
|
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
|
* 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
|
* 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).
|
* message, retrieve the appropriate local message instance first (if it already exists).
|
||||||
* @param messages
|
* @param messages
|
||||||
* @param copy
|
* @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
|
* @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);
|
open(OpenMode.READ_WRITE);
|
||||||
try {
|
try {
|
||||||
final Map<String, String> uidMap = new HashMap<String, String>();
|
final Map<String, String> uidMap = new HashMap<String, String>();
|
||||||
@ -2418,14 +2428,14 @@ public class LocalStore extends Store implements Serializable {
|
|||||||
|
|
||||||
long oldMessageId = -1;
|
long oldMessageId = -1;
|
||||||
String uid = message.getUid();
|
String uid = message.getUid();
|
||||||
if (uid == null || copy) {
|
if (uid == null || copy || createAsLocal) {
|
||||||
/*
|
/*
|
||||||
* Create a new message in the database
|
* Create a new message in the database
|
||||||
*/
|
*/
|
||||||
String randomLocalUid = K9.LOCAL_UID_PREFIX +
|
String randomLocalUid = K9.LOCAL_UID_PREFIX +
|
||||||
UUID.randomUUID().toString();
|
UUID.randomUUID().toString();
|
||||||
|
|
||||||
if (copy) {
|
if (copy || createAsLocal) {
|
||||||
// Save mapping: source UID -> target UID
|
// Save mapping: source UID -> target UID
|
||||||
uidMap.put(uid, randomLocalUid);
|
uidMap.put(uid, randomLocalUid);
|
||||||
} else {
|
} else {
|
||||||
|
Loading…
Reference in New Issue
Block a user