aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile25
-rw-r--r--antispam-plugin.c124
-rw-r--r--antispam-plugin.h42
-rw-r--r--antispam-storage-1.0.c216
-rw-r--r--api-compat.h15
-rw-r--r--debug.c2
-rw-r--r--defconfig6
-rw-r--r--dspam-exec.c49
-rw-r--r--plugin.c448
-rw-r--r--plugin.h40
-rw-r--r--signature.c53
-rw-r--r--signature.h17
12 files changed, 517 insertions, 520 deletions
diff --git a/Makefile b/Makefile
index a2620de..74a3406 100644
--- a/Makefile
+++ b/Makefile
@@ -11,14 +11,6 @@ CFLAGS += -I$(DOVECOT)/src/lib-mail/
CFLAGS += -I$(DOVECOT)/src/lib-imap/
CFLAGS += -I$(DOVECOT)/src/imap/
-# per-backend configuration
-ifeq ("$(BACKEND)", "dspam-exec")
-CFLAGS += -DBACKEND_WANTS_SIGNATURE=1
-# can take a while, check more often
-CFLAGS += -DCOPY_CHECK_INTERVAL=10
-endif
-
-
# debug rules
ifeq ("$(DEBUG)", "stderr")
CFLAGS += -DCONFIG_DEBUG -DDEBUG_STDERR
@@ -29,18 +21,29 @@ objs += debug.o
endif
# dovecot version rules
-CFLAGS += -DDOVECOT_VER=$(DOVECOT_VERSION)
+objs += antispam-storage-$(DOVECOT_VERSION).o
+ifeq ("$(DOVECOT_VERSION)", "1.0")
+CFLAGS += -Dstr_array_length=strarray_length
+CFLAGS += "-Dmempool_unref(x)=pool_unref(*(x))"
+else
+CFLAGS += "-Dmempool_unref(x)=pool_unref(x)"
+endif
+
+# per-backend rules
+ifeq ("$(BACKEND)", "dspam-exec")
+objs += signature.o
+endif
# main make rules
CFLAGS += -fPIC -shared -Wall
CC ?= "gcc"
-objs += plugin.o $(BACKEND).o
+objs += antispam-plugin.o $(BACKEND).o
ALL = antispam
all: verify_config $(ALL)
-%.o: %.c .config
+%.o: %.c .config antispam-plugin.h
$(CC) -c $(CFLAGS) -o $@ $<
antispam: $(objs)
diff --git a/antispam-plugin.c b/antispam-plugin.c
new file mode 100644
index 0000000..556d631
--- /dev/null
+++ b/antispam-plugin.c
@@ -0,0 +1,124 @@
+/*
+ * antispam plugin for dovecot
+ *
+ * Copyright (C) 2004-2007 Johannes Berg <johannes@sipsolutions.net>
+ * 2006 Frank Cusack
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License Version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * based on the original framework http://www.dovecot.org/patches/1.0/copy_plugin.c
+ *
+ * Please see http://johannes.sipsolutions.net/wiki/Projects/dovecot-dspam-integration
+ * for more information on this code.
+ *
+ * Install the plugin in the usual dovecot module location.
+ */
+
+#include <stdlib.h>
+
+/* dovecot headers we need */
+#include "lib.h"
+#include "str.h"
+#include "client.h"
+#include "ostream.h"
+#include "imap-search.h"
+
+/* defined by imap, pop3, lda */
+extern void (*hook_mail_storage_created)(struct mail_storage *storage);
+
+/* internal stuff we need */
+#include "antispam-plugin.h"
+
+static pool_t global_pool;
+static char **trash_folders = NULL;
+static char *default_spam_folders[] = {
+ "SPAM",
+ NULL
+};
+static char **spam_folders = default_spam_folders;
+
+static bool mailbox_in_list(struct mail_storage *storage, struct mailbox *box,
+ char **list)
+{
+ if (!list)
+ return FALSE;
+
+ while (*list) {
+ if (mailbox_equals(box, storage, *list))
+ return TRUE;
+ list++;
+ }
+
+ return FALSE;
+}
+
+bool mailbox_is_spam(struct mail_storage *storage, struct mailbox *box)
+{
+ return mailbox_in_list(storage, box, spam_folders);
+}
+
+bool mailbox_is_trash(struct mail_storage *storage, struct mailbox *box)
+{
+ return mailbox_in_list(storage, box, trash_folders);
+}
+
+void antispam_init(void)
+{
+ char *tmp, **iter;
+
+ debug("antispam plugin intialising\n");
+
+ global_pool = pool_alloconly_create("antispam-pool", 1024);
+
+ tmp = getenv("ANTISPAM_TRASH");
+ if (tmp)
+ trash_folders = p_strsplit(global_pool, tmp, ";");
+
+ if (trash_folders) {
+ iter = trash_folders;
+ while (*iter) {
+ debug("antispam: \"%s\" is trash folder\n", *iter);
+ iter++;
+ }
+ } else
+ debug("antispam: no trash folders\n");
+
+ tmp = getenv("ANTISPAM_SPAM");
+ if (tmp)
+ spam_folders = p_strsplit(global_pool, tmp, ";");
+
+ if (spam_folders) {
+ iter = spam_folders;
+ while (*iter) {
+ debug("antispam: \"%s\" is spam folder\n", *iter);
+ iter++;
+ }
+ } else
+ debug("antispam: no spam folders\n");
+
+ backend_init(global_pool);
+
+ antispam_next_hook_mail_storage_created = hook_mail_storage_created;
+ hook_mail_storage_created = antispam_mail_storage_created;
+}
+
+void antispam_deinit(void)
+{
+ hook_mail_storage_created = antispam_next_hook_mail_storage_created;
+ backend_exit();
+ mempool_unref(&global_pool);
+}
+
+/* put dovecot version we built against into plugin for checking */
+const char *antispam_version = PACKAGE_VERSION;
diff --git a/antispam-plugin.h b/antispam-plugin.h
new file mode 100644
index 0000000..7d9003b
--- /dev/null
+++ b/antispam-plugin.h
@@ -0,0 +1,42 @@
+#ifndef _ANTISPAM_PLUGIN_H
+#define _ANTISPAM_PLUGIN_H
+
+#include "lib.h"
+#include "str.h"
+#include "client.h"
+#include "ostream.h"
+#include "imap-search.h"
+
+struct antispam_transaction_context;
+
+/*
+ * Call backend giving
+ * - pool: dovecot memory pool, will be freed afterwards
+ * - spam: whether mail comes from spam folder or not
+ * - sigs: signatures, next == NULL terminates list
+ * -
+ */
+void backend_init(pool_t pool);
+void backend_exit(void);
+int backend_handle_mail(struct mailbox_transaction_context *t,
+ struct antispam_transaction_context *ast,
+ struct mail *mail);
+struct antispam_transaction_context *backend_start(struct mailbox *box);
+void backend_rollback(struct antispam_transaction_context *ast);
+int backend_commit(struct antispam_transaction_context *ast);
+
+#ifdef CONFIG_DEBUG
+void debug(const char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
+#else
+static void debug(const char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
+static inline void debug(const char *fmt, ...)
+{
+}
+#endif
+
+void antispam_mail_storage_created(struct mail_storage *storage);
+void (*antispam_next_hook_mail_storage_created)(struct mail_storage *storage);
+bool mailbox_is_spam(struct mail_storage *storage, struct mailbox *box);
+bool mailbox_is_trash(struct mail_storage *storage, struct mailbox *box);
+
+#endif /* _ANTISPAM_PLUGIN_H */
diff --git a/antispam-storage-1.0.c b/antispam-storage-1.0.c
new file mode 100644
index 0000000..73a7993
--- /dev/null
+++ b/antispam-storage-1.0.c
@@ -0,0 +1,216 @@
+/*
+ * Storage implementation for antispam plugin
+ * Copyright 2007 Johannes Berg <johannes@sipsolutions.net>
+ *
+ * Derived from Quota plugin:
+ * Copyright (C) 2005 Timo Sirainen
+ */
+
+#include <sys/stat.h>
+
+#include "lib.h"
+#include "array.h"
+#include "istream.h"
+#include "mail-search.h"
+#include "mail-storage-private.h"
+
+#include "antispam-plugin.h"
+
+#define ANTISPAM_CONTEXT(obj) \
+ *((void **)array_idx_modifyable(&(obj)->module_contexts, \
+ antispam_storage_module_id))
+
+struct antispam_mail_storage {
+ struct mail_storage_vfuncs super;
+ struct antispam *antispam;
+};
+
+struct antispam_mailbox {
+ struct mailbox_vfuncs super;
+
+ unsigned int save_hack:1;
+};
+
+static unsigned int antispam_storage_module_id = 0;
+static bool antispam_storage_module_id_set = FALSE;
+
+static int
+antispam_copy(struct mailbox_transaction_context *t, struct mail *mail,
+ enum mail_flags flags, struct mail_keywords *keywords,
+ struct mail *dest_mail)
+{
+ struct antispam_mailbox *asbox = ANTISPAM_CONTEXT(t->box);
+ struct antispam_transaction_context *ast =
+ ANTISPAM_CONTEXT(t);
+ struct mail *copy_dest_mail;
+ int ret;
+
+ if (dest_mail != NULL)
+ copy_dest_mail = dest_mail;
+ else
+ copy_dest_mail = mail_alloc(t, MAIL_FETCH_PHYSICAL_SIZE, NULL);
+
+ asbox->save_hack = FALSE;
+ if (asbox->super.copy(t, mail, flags, keywords, copy_dest_mail) < 0)
+ return -1;
+
+ /*
+ * If copying used saving internally, we already have treated the mail
+ */
+ if (asbox->save_hack)
+ ret = 0;
+ else
+ ret = backend_handle_mail(t, ast, copy_dest_mail);
+
+ if (copy_dest_mail != dest_mail)
+ mail_free(&copy_dest_mail);
+ return ret;
+}
+
+static int antispam_save_finish(struct mail_save_context *ctx,
+ struct mail *dest_mail)
+{
+ struct antispam_mailbox *asbox =
+ ANTISPAM_CONTEXT(ctx->transaction->box);
+ struct antispam_transaction_context *ast =
+ ANTISPAM_CONTEXT(ctx->transaction);
+ struct mail *save_dest_mail;
+ int ret;
+
+ if (dest_mail != NULL)
+ save_dest_mail = dest_mail;
+ else
+ save_dest_mail = mail_alloc(ctx->transaction,
+ MAIL_FETCH_PHYSICAL_SIZE, NULL);
+
+ if (asbox->super.save_finish(ctx, save_dest_mail) < 0)
+ return -1;
+
+ asbox->save_hack = TRUE;
+ ret = backend_handle_mail(ctx->transaction, ast, save_dest_mail);
+
+ if (save_dest_mail != dest_mail)
+ mail_free(&save_dest_mail);
+ return ret;
+}
+
+static struct antispam_transaction_context *
+antispam_transaction_begin(struct mailbox *box)
+{
+ struct antispam_transaction_context *ast;
+
+ ast = backend_start(box);
+ i_assert(ast != NULL);
+
+ debug("antispam: transaction %p begins on %s\n", ast, box->name);
+
+ return ast;
+}
+
+static void
+antispam_transaction_rollback(struct antispam_transaction_context **_ast)
+{
+ struct antispam_transaction_context *ast = *_ast;
+
+ debug("antispam: transaction %p rolled back\n", ast);
+
+ backend_rollback(ast);
+ *_ast = NULL;
+}
+
+static int
+antispam_transaction_commit(struct antispam_transaction_context **_ast)
+{
+ struct antispam_transaction_context *ast = *_ast;
+ int ret;
+
+ ret = backend_commit(ast);
+ *_ast = NULL;
+ debug("antispam: transaction %p commit: %d\n", ast, ret);
+ return ret;
+}
+
+static struct mailbox_transaction_context *
+antispam_mailbox_transaction_begin(struct mailbox *box,
+ enum mailbox_transaction_flags flags)
+{
+ struct antispam_mailbox *asbox = ANTISPAM_CONTEXT(box);
+ struct mailbox_transaction_context *t;
+ struct antispam_transaction_context *ast;
+
+ t = asbox->super.transaction_begin(box, flags);
+ ast = antispam_transaction_begin(box);
+
+ array_idx_set(&t->module_contexts, antispam_storage_module_id, &ast);
+ return t;
+}
+
+static int
+antispam_mailbox_transaction_commit(struct mailbox_transaction_context *ctx,
+ enum mailbox_sync_flags flags)
+{
+ struct antispam_mailbox *asbox = ANTISPAM_CONTEXT(ctx->box);
+ struct antispam_transaction_context *ast = ANTISPAM_CONTEXT(ctx);
+
+ if (antispam_transaction_commit(&ast) < 0) {
+ asbox->super.transaction_rollback(ctx);
+ return -1;
+ } else
+ return asbox->super.transaction_commit(ctx, flags);
+}
+
+static void
+antispam_mailbox_transaction_rollback(struct mailbox_transaction_context *ctx)
+{
+ struct antispam_mailbox *asbox = ANTISPAM_CONTEXT(ctx->box);
+ struct antispam_transaction_context *ast = ANTISPAM_CONTEXT(ctx);
+
+ antispam_transaction_rollback(&ast);
+ asbox->super.transaction_rollback(ctx);
+}
+
+static struct mailbox *antispam_mailbox_open(struct mail_storage *storage,
+ const char *name,
+ struct istream *input,
+ enum mailbox_open_flags flags)
+{
+ struct antispam_mail_storage *as_storage = ANTISPAM_CONTEXT(storage);
+ struct mailbox *box;
+ struct antispam_mailbox *asbox;
+
+ box = as_storage->super.mailbox_open(storage, name, input, flags);
+ if (box == NULL)
+ return NULL;
+
+ asbox = p_new(box->pool, struct antispam_mailbox, 1);
+ asbox->super = box->v;
+
+ 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;
+ array_idx_set(&box->module_contexts, antispam_storage_module_id,
+ &asbox);
+ return box;
+}
+
+void antispam_mail_storage_created(struct mail_storage *storage)
+{
+ struct antispam_mail_storage *as_storage;
+
+ if (antispam_next_hook_mail_storage_created != NULL)
+ antispam_next_hook_mail_storage_created(storage);
+
+ as_storage = p_new(storage->pool, struct antispam_mail_storage, 1);
+ as_storage->super = storage->v;
+ storage->v.mailbox_open = antispam_mailbox_open;
+
+ if (!antispam_storage_module_id_set) {
+ antispam_storage_module_id = mail_storage_module_id++;
+ antispam_storage_module_id_set = TRUE;
+ }
+
+ array_idx_set(&storage->module_contexts,
+ antispam_storage_module_id, &as_storage);
+}
diff --git a/api-compat.h b/api-compat.h
deleted file mode 100644
index f0a0476..0000000
--- a/api-compat.h
+++ /dev/null
@@ -1,15 +0,0 @@
-#ifndef _ANTISPAM_API_COMPAT_H
-#define _ANTISPAM_API_COMPAT_H
-
-#if DOVECOT_VER==10000
-#define MAILBOX_TRANSACTION_FLAG_ASSIGN_UIDS 0
-#define str_array_length strarray_length
-#define IMAP_SYNC_FLAG_SAFE 0
-#define mailbox_transaction_commit(arg) mailbox_transaction_commit(arg, 0)
-#define mempool_unref(poolptr) pool_unref((*poolptr))
-#define command_register(str, func, flags) command_register(str, func)
-#else
-#define mempool_unref(poolptr) pool_unref(poolptr)
-#endif
-
-#endif /* _ANTISPAM_API_COMPAT_H */
diff --git a/debug.c b/debug.c
index 6f5de19..e2a2e09 100644
--- a/debug.c
+++ b/debug.c
@@ -2,7 +2,7 @@
#include <syslog.h>
#include <stdarg.h>
#include <stdio.h>
-#include "plugin.h"
+#include "antispam-plugin.h"
static void _debug(const char *format, va_list ap)
{
diff --git a/defconfig b/defconfig
index fdbbf17..7435dfe 100644
--- a/defconfig
+++ b/defconfig
@@ -20,8 +20,8 @@ DOVECOT=../dovecot-1.0.5
#DOVECOT=/usr/include/dovecot
# Dovecot version to build against
-DOVECOT_VERSION=10000 # version 1.0
-#DOVECOT_VERSION=10100 # version 1.1
+DOVECOT_VERSION=1.0
+#DOVECOT_VERSION=1.1 # CURRENTLY BROKEN
# backend
# - dspam-exec: direct dspam training by calling dspam executable
@@ -30,4 +30,4 @@ BACKEND=dspam-exec
# enable debugging to syslog or stderr
#DEBUG=stderr
-#DEBUG=syslog
+DEBUG=syslog
diff --git a/dspam-exec.c b/dspam-exec.c
index f6c0707..92f016c 100644
--- a/dspam-exec.c
+++ b/dspam-exec.c
@@ -18,14 +18,15 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
+#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <fcntl.h>
#include "lib.h"
-#include "plugin.h"
-#include "api-compat.h"
+#include "antispam-plugin.h"
+#include "signature.h"
static const char *dspam_binary = "/usr/bin/dspam";
static char **extra_args = NULL;
@@ -139,6 +140,47 @@ static int call_dspam(pool_t pool, const char *signature, bool is_spam)
}
}
+struct antispam_transaction_context {
+ struct siglist *siglist;
+};
+
+struct antispam_transaction_context *backend_start(struct mailbox *box)
+{
+ struct antispam_transaction_context *ast;
+
+ ast = i_new(struct antispam_transaction_context, 1);
+ ast->siglist = NULL;
+ return ast;
+}
+
+void backend_rollback(struct antispam_transaction_context *ast)
+{
+ signature_list_free(&ast->siglist);
+ i_free(ast);
+}
+
+int backend_commit(struct antispam_transaction_context *ast)
+{
+ struct siglist *item = ast->siglist;
+
+ while (item) {
+ debug("antispam: got signature %s\n", item->sig);
+ item = item->next;
+ }
+
+ signature_list_free(&ast->siglist);
+ i_free(ast);
+ return 0;
+}
+
+int backend_handle_mail(struct mailbox_transaction_context *t,
+ struct antispam_transaction_context *ast,
+ struct mail *mail)
+{
+ return signature_extract(t, mail, &ast->siglist);
+}
+
+#if 0
bool backend(pool_t pool, bool spam, struct strlist *sigs)
{
int ret;
@@ -153,6 +195,7 @@ bool backend(pool_t pool, bool spam, struct strlist *sigs)
return TRUE;
}
+#endif
void backend_init(pool_t pool)
{
@@ -174,6 +217,8 @@ void backend_init(pool_t pool)
debug("antispam: dspam extra arg %s\n",
extra_args[i]);
}
+
+ signature_init();
}
void backend_exit(void)
diff --git a/plugin.c b/plugin.c
deleted file mode 100644
index 63c853f..0000000
--- a/plugin.c
+++ /dev/null
@@ -1,448 +0,0 @@
-/*
- * antispam plugin for dovecot
- *
- * Copyright (C) 2004-2007 Johannes Berg <johannes@sipsolutions.net>
- * 2006 Frank Cusack
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License Version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
- *
- * based on the original framework http://www.dovecot.org/patches/1.0/copy_plugin.c
- *
- * Please see http://johannes.sipsolutions.net/wiki/Projects/dovecot-dspam-integration
- * for more information on this code.
- *
- * Install the plugin in the usual dovecot module location.
- */
-
-#include <stdlib.h>
-
-/* dovecot headers we need */
-#include "lib.h"
-#include "str.h"
-#include "client.h"
-#include "ostream.h"
-#include "imap-search.h"
-
-/* internal stuff we need */
-#include "plugin.h"
-#include "api-compat.h"
-
-static pool_t global_pool;
-static char **trash_folders = NULL;
-static char *default_spam_folders[] = {
- "SPAM",
- NULL
-};
-static char **spam_folders = default_spam_folders;
-#ifdef BACKEND_WANTS_SIGNATURE
-static char *signature_hdr = "X-DSPAM-Signature";
-#endif
-
-static struct strlist *list_add(pool_t pool, struct strlist *list)
-{
- struct strlist *n;
-
- n = p_malloc(pool, sizeof(struct strlist));
- n->next = list;
- n->str = NULL;
-
- return n;
-}
-
-static bool mailbox_in_list(struct mail_storage *storage, struct mailbox *box,
- char **list)
-{
- if (!list)
- return FALSE;
-
- while (*list) {
- if (mailbox_equals(box, storage, *list))
- return TRUE;
- list++;
- }
-
- return FALSE;
-}
-
-static void client_send_sendalive_if_needed(struct client *client)
-{
- time_t now, last_io;
-
- if (o_stream_get_buffer_used_size(client->output) != 0)
- return;
-
- now = time(NULL);
- last_io = I_MAX(client->last_input, client->last_output);
- if (now - last_io > MAIL_STORAGE_STAYALIVE_SECS) {
- o_stream_send_str(client->output, "* OK Hang in there..\r\n");
- o_stream_flush(client->output);
- client->last_output = now;
- }
-}
-
-#define GENERIC_ERROR -1
-#define SIGNATURE_MISSING -2
-#define BACKEND_FAILURE -3
-
-/* mostly copied from cmd-copy.c (notes added where changed) */
-/* MODIFIED: prototype to include "src_spam" */
-static int fetch_and_copy(struct client *client, struct mailbox *destbox,
- struct mailbox_transaction_context *t,
- struct mail_search_arg *search_args,
- const char **src_uidset_r,
- unsigned int *copy_count_r,
- bool src_spam)
-{
- struct mail_search_context *search_ctx;
- struct mailbox_transaction_context *src_trans;
- struct mail_keywords *keywords;
- const char *const *keywords_list;
- struct mail *mail;
- unsigned int copy_count = 0;
-#if DOVECOT_VER==10100
- struct msgset_generator_context srcset_ctx;
- string_t *src_uidset;
-#endif
- int ret;
- /* MODIFIED: new variables */
- pool_t pool = pool_alloconly_create("antispam-copy-pool", 1024);
-#ifdef BACKEND_WANTS_SIGNATURE
- const char *signature;
- struct strlist *siglist = NULL;
-#else
-#error Not implemented
-#endif
-
-#if DOVECOT_VER==10100
- src_uidset = t_str_new(256);
- msgset_generator_init(&srcset_ctx, src_uidset);
-#endif
-
- src_trans = mailbox_transaction_begin(client->mailbox, 0);
- search_ctx = mailbox_search_init(src_trans, NULL, search_args, NULL);
-
- mail = mail_alloc(src_trans, MAIL_FETCH_STREAM_HEADER |
- MAIL_FETCH_STREAM_BODY, NULL);
- ret = 1;
- while (mailbox_search_next(search_ctx, mail) > 0 && ret > 0) {
- if (mail->expunged) {
- ret = 0;
- break;
- }
-
- if ((++copy_count % COPY_CHECK_INTERVAL) == 0)
- client_send_sendalive_if_needed(client);
-
- /* MODIFIED: keep track of mail as we copy */
-#ifdef BACKEND_WANTS_SIGNATURE
-#if DOVECOT_VER==10000
- signature = mail_get_first_header(mail, signature_hdr);
-#elif DOVECOT_VER==10100
- signature = NULL;
- ret = mail_get_first_header(mail, signature_hdr, &signature);
-#endif
- /* ret can only be != 1 with new dovecot 1.1 API */
- if (ret != 1 || !signature || !signature[0]) {
- ret = SIGNATURE_MISSING;
- break;
- }
- siglist = list_add(pool, siglist);
- siglist->str = p_strdup(pool, signature);
-#else
-#error Not implemented
-#endif
-
-#if DOVECOT_VER==10000
- keywords_list = mail_get_keywords(mail);
- keywords = str_array_length(keywords_list) == 0 ? NULL :
- mailbox_keywords_create(t, keywords_list);
- if (mailbox_copy(t, mail, mail_get_flags(mail),
- keywords, NULL) < 0)
- ret = mail->expunged ? 0 : -1;
- mailbox_keywords_free(t, &keywords);
-#elif DOVECOT_VER==10100
- keywords_list = mail_get_keywords(mail);
- keywords = str_array_length(keywords_list) == 0 ? NULL :
- mailbox_keywords_create_valid(destbox, keywords_list);
- if (mailbox_copy(t, mail, mail_get_flags(mail),
- keywords, NULL) < 0)
- ret = mail->expunged ? 0 : -1;
- mailbox_keywords_free(destbox, &keywords);
-
- msgset_generator_next(&srcset_ctx, mail->uid);
-#endif
- }
- mail_free(&mail);
-#if DOVECOT_VER==10100
- msgset_generator_finish(&srcset_ctx);
-#endif
-
- if (mailbox_search_deinit(&search_ctx) < 0)
- ret = -1;
-
- if (mailbox_transaction_commit(&src_trans) < 0)
- ret = -1;
-
- /* MODIFIED: pass to backend */
-#ifdef BACKEND_WANTS_SIGNATURE
- /* got all signatures now, pass them to backend if no errors */
- if (ret > 0 && !backend(pool, src_spam, siglist))
- ret = BACKEND_FAILURE;
-#else
-#error Not implemented
-#endif
- /* MODIFIED: kill pool */
- mempool_unref(&pool);
-
-#if DOVECOT_VER==10100
- *src_uidset_r = str_c(src_uidset);
- *copy_count_r = copy_count;
-#endif
- return ret;
-}
-
-
-/* mostly copied from cmd-copy.c (notes added where changed) */
-static bool cmd_copy_antispam(struct client_command_context *cmd)
-{
- struct client *client = cmd->client;
- struct mail_storage *storage;
- struct mailbox *destbox;
- struct mailbox_transaction_context *t;
- struct mail_search_arg *search_arg;
- const char *messageset, *mailbox, *src_uidset;
- enum mailbox_sync_flags sync_flags = 0;
- unsigned int copy_count;
- enum imap_sync_flags imap_flags = 0;
-#if DOVECOT_VER==10100
- uint32_t uid_validity, uid1, uid2;
- const char *msg = NULL;
-#endif
- int ret;
- /* MODIFIED: added variables */
- bool dst_spam, src_spam;
-
- /* <message set> <mailbox> */
- if (!client_read_string_args(cmd, 2, &messageset, &mailbox))
- return FALSE;
-
- if (!client_verify_open_mailbox(cmd))
- return TRUE;
-
- /* open the destination mailbox */
- if (!client_verify_mailbox_name(cmd, mailbox, TRUE, FALSE))
- return TRUE;
-
- search_arg = imap_search_get_arg(cmd, messageset, cmd->uid);
- if (search_arg == NULL)
- return TRUE;
-
- storage = client_find_storage(cmd, &mailbox);
- if (storage == NULL)
- return TRUE;
-
- if (mailbox_equals(client->mailbox, storage, mailbox)) {
- destbox = client->mailbox;
- /* MODIFIED: don't try to reclassify on copy within folder */
- return cmd_copy(cmd);
- } else {
- destbox = mailbox_open(storage, mailbox, NULL,
- MAILBOX_OPEN_SAVEONLY |
- MAILBOX_OPEN_FAST |
- MAILBOX_OPEN_KEEP_RECENT);
- if (destbox == NULL) {
- client_send_storage_error(cmd, storage);
- return TRUE;
- }
- }
-
- /* MODIFIED: Trash detection */
- if (mailbox_in_list(storage, client->mailbox, trash_folders) ||
- mailbox_in_list(storage, destbox, trash_folders)) {
- mailbox_close(&destbox);
- return cmd_copy(cmd);
- }
-
- /* MODIFIED: from/to-SPAM detection */
- src_spam = mailbox_in_list(storage, client->mailbox, spam_folders);
- dst_spam = mailbox_in_list(storage, destbox, spam_folders);
- /*
- * "both spam" can happen with multiple spam folders,
- * "none spam" is the common case where spam folders are not involved
- */
- if ((src_spam && dst_spam) ||
- (!src_spam && !dst_spam)) {
- mailbox_close(&destbox);
- return cmd_copy(cmd);
- }
-
- t = mailbox_transaction_begin(destbox,
- MAILBOX_TRANSACTION_FLAG_EXTERNAL |
- MAILBOX_TRANSACTION_FLAG_ASSIGN_UIDS);
- ret = fetch_and_copy(client, destbox, t, search_arg,
- &src_uidset, &copy_count, src_spam);
-
- if (ret <= 0)
- mailbox_transaction_rollback(&t);
-#if DOVECOT_VER==10000
- else {
- if (mailbox_transaction_commit(&t) < 0)
- ret = -1;
- }
-#elif DOVECOT_VER==10100
- else if (mailbox_transaction_commit_get_uids(&t, &uid_validity,
- &uid1, &uid2) < 0)
- ret = -1;
- else if (copy_count == 0)
- msg = "OK No messages copied.";
- else {
- i_assert(copy_count == uid2 - uid1 + 1);
-
- if (uid1 == uid2) {
- msg = t_strdup_printf("OK [COPYUID %u %s %u] "
- "Copy completed.",
- uid_validity, src_uidset, uid1);
- } else {
- msg = t_strdup_printf("OK [COPYUID %u %s %u:%u] "
- "Copy completed.",
- uid_validity, src_uidset,
- uid1, uid2);
- }
- }
-#endif
-
- if (destbox != client->mailbox) {
- sync_flags |= MAILBOX_SYNC_FLAG_FAST;
- imap_flags |= IMAP_SYNC_FLAG_SAFE;
- mailbox_close(&destbox);
- }
-
- /* MODIFIED: extended error codes */
- if (ret > 0)
- return cmd_sync(cmd, sync_flags, imap_flags, "OK Copy completed.");
- else if (ret == 0) {
- /* some messages were expunged, sync them */
- return cmd_sync(cmd, 0, 0,
- "NO Some of the requested messages no longer exist.");
- } else if (ret == SIGNATURE_MISSING) {
- return cmd_sync(cmd, 0, 0,
- "NO Some of the requested messages have no"
- " antispam signature.");
- } else if (ret == BACKEND_FAILURE) {
- return cmd_sync(cmd, 0, 0,
- "NO Antispam backend failed to retrain.");
- } else {
- client_send_storage_error(cmd, storage);
- return TRUE;
- }
-}
-
-
-static bool cmd_append_antispam(struct client_command_context *cmd)
-{
- const char *mailbox;
- struct mail_storage *storage;
- struct mailbox *box;
-
- /* <mailbox> */
- if (!client_read_string_args(cmd, 1, &mailbox))
- return FALSE;
-
- storage = client_find_storage(cmd, &mailbox);
- if (!storage)
- return FALSE;
-
- box = mailbox_open(storage, mailbox, NULL,
- MAILBOX_OPEN_FAST | MAILBOX_OPEN_KEEP_RECENT);
- if (box) {
- if (mailbox_in_list(storage, box, spam_folders)) {
- mailbox_close(&box);
- return cmd_sync(cmd, 0, 0,
- "NO Cannot APPEND to spam folder.");
- }
-
- mailbox_close(&box);
- }
-
- return cmd_append(cmd);
-}
-
-
-void antispam_init(void)
-{
- char *tmp, **iter;
-
- debug("antispam plugin intialising\n");
-
- global_pool = pool_alloconly_create("antispam-pool", 1024);
-
- tmp = getenv("ANTISPAM_TRASH");
- if (tmp)
- trash_folders = p_strsplit(global_pool, tmp, ";");
-
- if (trash_folders) {
- iter = trash_folders;
- while (*iter) {
- debug("antispam: \"%s\" is trash folder\n", *iter);
- iter++;
- }
- } else
- debug("antispam: no trash folders\n");
-
- tmp = getenv("ANTISPAM_SPAM");
- if (tmp)
- spam_folders = p_strsplit(global_pool, tmp, ";");
-
- if (spam_folders) {
- iter = spam_folders;
- while (*iter) {
- debug("antispam: \"%s\" is spam folder\n", *iter);
- iter++;
- }
- } else
- debug("antispam: no spam folders\n");
-
-#ifdef BACKEND_WANTS_SIGNATURE
- tmp = getenv("ANTISPAM_SIGNATURE");
- if (tmp)
- signature_hdr = tmp;
- debug("antispam: signature header line is \"%s\"\n", signature_hdr);
-#endif
-
- backend_init(global_pool);
-
- command_unregister("COPY");
- command_unregister("APPEND");
- command_unregister("UID COPY");
- /*
- * i_strdup() here is a kludge to avoid crashing in commands_deinit()
- * since modules are unloaded before it's called, this "COPY" string
- * would otherwise point to nonexisting memory.
- */
- command_register(i_strdup("COPY"), cmd_copy_antispam,
- COMMAND_FLAG_USES_SEQS | COMMAND_FLAG_BREAKS_SEQS);
- command_register(i_strdup("UID COPY"), cmd_copy_antispam,
- COMMAND_FLAG_BREAKS_SEQS);
- command_register(i_strdup("APPEND"), cmd_append_antispam,
- COMMAND_FLAG_BREAKS_SEQS);
-}
-
-void antispam_deinit(void)
-{
- backend_exit();
- mempool_unref(&global_pool);
-}
-
-/* put dovecot version we built against into plugin for checking */
-const char *antispam_version = PACKAGE_VERSION;
diff --git a/plugin.h b/plugin.h
deleted file mode 100644
index c2281ad..0000000
--- a/plugin.h
+++ /dev/null
@@ -1,40 +0,0 @@
-#ifndef _ANTISPAM_PLUGIN_H
-#define _ANTISPAM_PLUGIN_H
-
-#include <unistd.h>
-#include "lib.h"
-#include "mempool.h"
-
-struct strlist {
- struct strlist *next;
- const char *str;
-};
-
-#ifdef BACKEND_WANTS_SIGNATURE
-/*
- * Call backend giving
- * - pool: dovecot memory pool, will be freed afterwards
- * - spam: whether mail comes from spam folder or not
- * - sigs: signatures, next == NULL terminates list
- * -
- */
-bool backend(pool_t pool, bool spam, struct strlist *sigs);
-#elif CONFIG_PLUGIN_WANT_MAIL
-#error TODO: no support for pristine training yet
-#else
-#error BUILD SYSTEM ERROR
-#endif
-
-void backend_init(pool_t pool);
-void backend_exit(void);
-
-#ifdef CONFIG_DEBUG
-void debug(const char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
-#else
-static void debug(const char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
-static inline void debug(const char *fmt, ...)
-{
-}
-#endif
-
-#endif /* _ANTISPAM_PLUGIN_H */
diff --git a/signature.c b/signature.c
new file mode 100644
index 0000000..df04623
--- /dev/null
+++ b/signature.c
@@ -0,0 +1,53 @@
+
+#include <stdlib.h>
+#include "antispam-plugin.h"
+#include "signature.h"
+#include "mail-storage-private.h"
+
+static char *signature_hdr = "X-DSPAM-Signature";
+
+void signature_init(void)
+{
+ char *tmp = getenv("ANTISPAM_SIGNATURE");
+ if (tmp)
+ signature_hdr = tmp;
+ debug("antispam: signature header line is \"%s\"\n", signature_hdr);
+}
+
+int signature_extract(struct mailbox_transaction_context *t,
+ struct mail *mail, struct siglist **list)
+{
+ const char *signature;
+ struct siglist *item;
+
+ signature = mail_get_first_header(mail, signature_hdr);
+ if (!signature || !signature[0]) {
+ mail_storage_set_error(t->box->storage,
+ "antispam signature not found");
+ return -1;
+ }
+
+ item = i_new(struct siglist, 1);
+ item->next = *list;
+ *list = item;
+ item->sig = i_strdup(signature);
+ return 0;
+}
+
+void signature_list_free(struct siglist **list)
+{
+ struct siglist *item, *next;
+
+ i_assert(list);
+
+ item = *list;
+
+ while (item) {
+ next = item->next;
+ i_free(item->sig);
+ i_free(item);
+ item = next;
+ if (item)
+ next = item->next;
+ }
+}
diff --git a/signature.h b/signature.h
new file mode 100644
index 0000000..ad3841a
--- /dev/null
+++ b/signature.h
@@ -0,0 +1,17 @@
+#ifndef _ANTISPAM_SIGNATURE_H
+#define _ANTISPAM_SIGNATURE_H
+
+#include "lib.h"
+#include "client.h"
+
+struct siglist {
+ struct siglist *next;
+ char *sig;
+};
+
+void signature_init(void);
+int signature_extract(struct mailbox_transaction_context *t,
+ struct mail *mail, struct siglist **list);
+void signature_list_free(struct siglist **list);
+
+#endif /* _ANTISPAM_SIGNATURE_H */