diff options
Diffstat (limited to 'plugin.c')
-rw-r--r-- | plugin.c | 448 |
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, ©_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; |