diff options
Diffstat (limited to 'antispam-storage-1.0.c')
-rw-r--r-- | antispam-storage-1.0.c | 216 |
1 files changed, 216 insertions, 0 deletions
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(©_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); +} |