aboutsummaryrefslogtreecommitdiffstats
path: root/plugin.c
diff options
context:
space:
mode:
Diffstat (limited to 'plugin.c')
-rw-r--r--plugin.c448
1 files changed, 0 insertions, 448 deletions
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;