aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--Makefile1
-rw-r--r--antispam-plugin.c51
-rw-r--r--antispam-plugin.h4
-rw-r--r--antispam-storage-1.0.c144
4 files changed, 187 insertions, 13 deletions
diff --git a/Makefile b/Makefile
index 6496448..70b9900 100644
--- a/Makefile
+++ b/Makefile
@@ -16,6 +16,7 @@ CFLAGS += -I$(DOVECOT)/src/lib-storage/
CFLAGS += -I$(DOVECOT)/src/lib-mail/
CFLAGS += -I$(DOVECOT)/src/lib-imap/
CFLAGS += -I$(DOVECOT)/src/lib-dict/
+CFLAGS += -I$(DOVECOT)/src/lib-index/
CFLAGS += -I$(DOVECOT)/src/imap/
# output name
diff --git a/antispam-plugin.c b/antispam-plugin.c
index 407b909..5dd9a02 100644
--- a/antispam-plugin.c
+++ b/antispam-plugin.c
@@ -49,6 +49,11 @@ static char *default_spam_folders[] = {
static char **spam_folders = default_spam_folders;
static char **unsure_folders = NULL;
bool antispam_can_append_to_spam = FALSE;
+static char **spam_keywords = NULL;
+
+bool need_keyword_hook;
+bool need_folder_hook;
+
static bool mailbox_in_list(struct mailbox *box, char **list)
{
@@ -79,6 +84,22 @@ bool mailbox_is_unsure(struct mailbox *box)
return mailbox_in_list(box, unsure_folders);
}
+bool keyword_is_spam(const char *keyword)
+{
+ char **k = spam_keywords;
+
+ if (!spam_keywords)
+ return FALSE;
+
+ while (*k) {
+ if (strcmp(*k, keyword) == 0)
+ return TRUE;
+ k++;
+ }
+
+ return FALSE;
+}
+
const char *get_setting(const char *name)
{
const char *env;
@@ -105,6 +126,7 @@ void PLUGIN_FUNCTION(init)(void)
{
const char *tmp;
char * const *iter;
+ int spam_folder_count = 0;
debug("plugin initialising\n");
@@ -127,17 +149,12 @@ void PLUGIN_FUNCTION(init)(void)
if (tmp)
spam_folders = p_strsplit(global_pool, tmp, ";");
- tmp = get_setting("ALLOW_APPEND_TO_SPAM");
- if (tmp && strcasecmp(tmp, "yes") == 0) {
- antispam_can_append_to_spam = TRUE;
- debug("allowing APPEND to spam folders");
- }
-
if (spam_folders) {
iter = spam_folders;
while (*iter) {
debug("\"%s\" is spam folder\n", *iter);
iter++;
+ spam_folder_count++;
}
} else
debug("no spam folders\n");
@@ -155,6 +172,28 @@ void PLUGIN_FUNCTION(init)(void)
} else
debug("no unsure folders\n");
+ tmp = get_setting("ALLOW_APPEND_TO_SPAM");
+ if (tmp && strcasecmp(tmp, "yes") == 0) {
+ antispam_can_append_to_spam = TRUE;
+ debug("allowing APPEND to spam folders");
+ }
+
+ tmp = get_setting("SPAM_KEYWORDS");
+ if (tmp)
+ spam_keywords = p_strsplit(global_pool, tmp, ";");
+
+ if (spam_keywords) {
+ iter = spam_keywords;
+ while (*iter) {
+ debug("\"%s\" is spam keyword\n", *iter);
+ iter++;
+ }
+ }
+
+ /* set spam_folders to empty to only allow keywords */
+ need_folder_hook = !!spam_folder_count;
+ need_keyword_hook = !!spam_keywords;
+
backend_init(global_pool);
antispam_next_hook_mail_storage_created = hook_mail_storage_created;
diff --git a/antispam-plugin.h b/antispam-plugin.h
index 98fed8f..9869a14 100644
--- a/antispam-plugin.h
+++ b/antispam-plugin.h
@@ -51,5 +51,9 @@ bool mailbox_is_trash(struct mailbox *box);
bool mailbox_is_unsure(struct mailbox *box);
const char *get_setting(const char *name);
bool antispam_can_append_to_spam;
+bool keyword_is_spam(const char *keyword);
+
+extern bool need_keyword_hook;
+extern bool need_folder_hook;
#endif /* _ANTISPAM_PLUGIN_H */
diff --git a/antispam-storage-1.0.c b/antispam-storage-1.0.c
index e1b00fa..1949454 100644
--- a/antispam-storage-1.0.c
+++ b/antispam-storage-1.0.c
@@ -12,6 +12,7 @@
#include "array.h"
#include "istream.h"
#include "mail-search.h"
+#include "mail-index.h"
#include "mail-storage-private.h"
#include "antispam-plugin.h"
@@ -53,6 +54,10 @@ struct antispam_mailbox {
unsigned int save_hack:1;
};
+struct antispam_mail {
+ struct mail_vfuncs super;
+};
+
static unsigned int antispam_storage_module_id = 0;
static bool antispam_storage_module_id_set = FALSE;
@@ -257,6 +262,98 @@ antispam_transaction_commit(struct mailbox_transaction_context *ctx,
return ret;
}
+static int
+antispam_mail_update_keywords(struct mail *mail,
+ enum modify_type modify_type,
+ struct mail_keywords *keywords)
+{
+ struct mail_private *pmail = (struct mail_private *)mail;
+ struct antispam_mail *amail = ANTISPAM_CONTEXT(pmail);
+ int ret;
+ unsigned int i, numkwds;
+ const array_t *idxkwd = mail_index_get_keywords(keywords->index);
+ const char *const *keyword_names = array_get(idxkwd, &numkwds);
+ const char *const *orig_keywords;
+ bool previous_spam_keyword, now_spam_keyword;
+
+ switch (modify_type) {
+ case MODIFY_ADD:
+ debug("adding keyword(s)\n");
+ break;
+ case MODIFY_REMOVE:
+ debug("removing keyword(s)\n");
+ break;
+ case MODIFY_REPLACE:
+ debug("replacing keyword(s)\n");
+ break;
+ default:
+ i_assert(0);
+ }
+
+ orig_keywords = pmail->v.get_keywords(mail);
+ if (orig_keywords) {
+ debug("original keyword list:\n");
+ while (*orig_keywords) {
+ debug(" * %s\n", *orig_keywords);
+ if (keyword_is_spam(*orig_keywords))
+ previous_spam_keyword = TRUE;
+ orig_keywords++;
+ }
+ }
+
+ debug("keyword list:\n");
+
+ for (i = 0; i < keywords->count; i++) {
+ unsigned int idx = keywords->idx[i];
+
+ i_assert(idx < numkwds);
+
+ debug(" * %s\n", keyword_names[idx]);
+
+ switch (modify_type) {
+ case MODIFY_ADD:
+ case MODIFY_REPLACE:
+ if (keyword_is_spam(keyword_names[idx]))
+ now_spam_keyword = TRUE;
+ break;
+ case MODIFY_REMOVE:
+ if (keyword_is_spam(keyword_names[idx]))
+ now_spam_keyword = FALSE;
+ break;
+ default:
+ i_assert(0);
+ }
+ }
+
+ ret = amail->super.update_keywords(mail, modify_type, keywords);
+
+ debug("ret = %d\n", ret);
+
+ debug("previous-spam, now-spam: %d, %d\n",
+ previous_spam_keyword, now_spam_keyword);
+
+ if (previous_spam_keyword != now_spam_keyword) {
+ /*
+ * Call backend here.
+ *
+ * TODO: It is not clear how to roll back the
+ * keyword change if the backend fails.
+ */
+ }
+
+ return ret;
+}
+
+static void
+antispam_mail_free(struct mail *mail)
+{
+ struct mail_private *pmail = (struct mail_private *)mail;
+ struct antispam_mail *amail = ANTISPAM_CONTEXT(pmail);
+
+ amail->super.free(mail);
+ i_free(amail);
+}
+
static struct mailbox_transaction_context *
antispam_mailbox_transaction_begin(struct mailbox *box,
enum mailbox_transaction_flags flags)
@@ -296,6 +393,33 @@ antispam_mailbox_transaction_rollback(struct mailbox_transaction_context *ctx)
asbox->super.transaction_rollback(ctx);
}
+static struct mail *
+antispam_mailbox_mail_alloc(struct mailbox_transaction_context *ctx,
+ enum mail_fetch_field wanted_fields,
+ struct mailbox_header_lookup_ctx *wanted_headers)
+{
+ struct antispam_mailbox *asbox = ANTISPAM_CONTEXT(ctx->box);
+ struct antispam_mail *amail = i_new(struct antispam_mail, 1);
+ struct mail_private *pmail;
+
+ /* XXX: is this cast the right thing to do? */
+ pmail = (struct mail_private *) asbox->super.mail_alloc(
+ ctx,
+ wanted_fields,
+ wanted_headers);
+
+ amail->super = pmail->v;
+
+ array_idx_set(&pmail->module_contexts,
+ antispam_storage_module_id,
+ &amail);
+
+ pmail->v.update_keywords = antispam_mail_update_keywords;
+ pmail->v.free = antispam_mail_free;
+
+ return (struct mail *)pmail;
+}
+
static struct mailbox *antispam_mailbox_open(struct mail_storage *storage,
const char *name,
struct istream *input,
@@ -314,13 +438,19 @@ static struct mailbox *antispam_mailbox_open(struct mail_storage *storage,
asbox->save_hack = FALSE;
asbox->movetype = MMT_APPEND;
- /* override save_init to override want_mail, we need that */
- box->v.save_init = antispam_save_init;
- box->v.save_finish = antispam_save_finish;
- box->v.transaction_begin = antispam_mailbox_transaction_begin;
- box->v.transaction_commit = antispam_mailbox_transaction_commit;
- box->v.transaction_rollback = antispam_mailbox_transaction_rollback;
- box->v.copy = antispam_copy;
+ if (need_folder_hook) {
+ /* override save_init to override want_mail, we need that */
+ box->v.save_init = antispam_save_init;
+ box->v.save_finish = antispam_save_finish;
+ box->v.transaction_begin = antispam_mailbox_transaction_begin;
+ box->v.transaction_commit = antispam_mailbox_transaction_commit;
+ box->v.transaction_rollback = antispam_mailbox_transaction_rollback;
+ box->v.copy = antispam_copy;
+ }
+
+ if (need_keyword_hook)
+ box->v.mail_alloc = antispam_mailbox_mail_alloc;
+
array_idx_set(&box->module_contexts, antispam_storage_module_id,
&asbox);
return box;