mail-log-plugin.c revision 15780ce9a9aaf06b585f43850a60b89bf1ea3e1f
5e0ce63bb65db34d7f48b34bbb5545fa791781c4Timo Sirainen/* Copyright (C) 2007 Timo Sirainen */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "lib.h"
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen#include "array.h"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "str-sanitize.h"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "mail-storage-private.h"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "mail-log-plugin.h"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#define MAILBOX_NAME_LOG_LEN 64
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#define MSGID_LOG_LEN 80
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen#define MAIL_LOG_CONTEXT(obj) \
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen *((void **)array_idx_modifiable(&(obj)->module_contexts, \
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen mail_log_storage_module_id))
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenstruct mail_log_mail_storage {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct mail_storage_vfuncs super;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen};
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenstruct mail_log_mailbox {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct mailbox_vfuncs super;
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen};
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenstruct mail_log_mail {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct mail_vfuncs super;
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen};
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen/* defined by imap, pop3, lda */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenextern void (*hook_mail_storage_created)(struct mail_storage *storage);
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainenconst char *mail_log_plugin_version = PACKAGE_VERSION;
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenstatic void (*mail_log_next_hook_mail_storage_created)
2c25e1360d4b5cc55eda969a3a7204d950de5a8fTimo Sirainen (struct mail_storage *storage);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenstatic unsigned int mail_log_storage_module_id = 0;
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenstatic bool mail_log_storage_module_id_set = FALSE;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenstatic void mail_log_action(struct mail *mail, const char *action)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen const char *msgid;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen msgid = mail_get_first_header(mail, "Message-ID");
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen i_info("%s: uid=%u, msgid=%s", action, mail->uid,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen msgid == NULL ? "(null)" : str_sanitize(msgid, MSGID_LOG_LEN));
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenstatic int mail_log_mail_expunge(struct mail *_mail)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct mail_private *mail = (struct mail_private *)_mail;
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen struct mail_log_mail *lmail = MAIL_LOG_CONTEXT(mail);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen if (lmail->super.expunge(_mail) < 0)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return -1;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen mail_log_action(_mail, "expunged");
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return 0;
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenstatic int
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenmail_log_mail_update_flags(struct mail *_mail, enum modify_type modify_type,
03f5c621d06d6b6d77a145196c9633a7aa64dc78Timo Sirainen enum mail_flags flags)
e11a64ffc7f08b4cb05bcc27668d154d33d0c2e0Timo Sirainen{
e11a64ffc7f08b4cb05bcc27668d154d33d0c2e0Timo Sirainen struct mail_private *mail = (struct mail_private *)_mail;
03f5c621d06d6b6d77a145196c9633a7aa64dc78Timo Sirainen struct mail_log_mail *lmail = MAIL_LOG_CONTEXT(mail);
e11a64ffc7f08b4cb05bcc27668d154d33d0c2e0Timo Sirainen enum mail_flags old_flags, new_flags;
e11a64ffc7f08b4cb05bcc27668d154d33d0c2e0Timo Sirainen
e11a64ffc7f08b4cb05bcc27668d154d33d0c2e0Timo Sirainen old_flags = mail_get_flags(_mail);
e11a64ffc7f08b4cb05bcc27668d154d33d0c2e0Timo Sirainen if (lmail->super.update_flags(_mail, modify_type, flags) < 0)
03f5c621d06d6b6d77a145196c9633a7aa64dc78Timo Sirainen return -1;
03f5c621d06d6b6d77a145196c9633a7aa64dc78Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen new_flags = old_flags;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen switch (modify_type) {
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen case MODIFY_ADD:
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen new_flags |= flags;
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen break;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen case MODIFY_REMOVE:
af81f402ddc897c74c1e85abd02879612ce44882Timo Sirainen new_flags &= ~flags;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen break;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen case MODIFY_REPLACE:
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen new_flags = flags;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen break;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen if (((old_flags ^ new_flags) & MAIL_DELETED) == 0)
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen return 0;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen mail_log_action(_mail, (new_flags & MAIL_DELETED) != 0 ?
9e095dd6a77097356aca8216356d4d71ef1bea45Timo Sirainen "deleted" : "undeleted");
9e095dd6a77097356aca8216356d4d71ef1bea45Timo Sirainen return 0;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen}
9e095dd6a77097356aca8216356d4d71ef1bea45Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenstatic struct mail *
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenmail_log_mail_alloc(struct mailbox_transaction_context *t,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen enum mail_fetch_field wanted_fields,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct mailbox_header_lookup_ctx *wanted_headers)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct mail_log_mailbox *lbox = MAIL_LOG_CONTEXT(t->box);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct mail_log_mail *lmail;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct mail *_mail;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct mail_private *mail;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen _mail = lbox->super.mail_alloc(t, wanted_fields, wanted_headers);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen mail = (struct mail_private *)_mail;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen lmail = p_new(mail->pool, struct mail_log_mail, 1);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen lmail->super = mail->v;
b3142c8e513bc78da821fa70f479016148fa95e5Timo Sirainen
af81f402ddc897c74c1e85abd02879612ce44882Timo Sirainen mail->v.update_flags = mail_log_mail_update_flags;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen mail->v.expunge = mail_log_mail_expunge;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen array_idx_set(&mail->module_contexts,
b3142c8e513bc78da821fa70f479016148fa95e5Timo Sirainen mail_log_storage_module_id, &lmail);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return _mail;
67c24901ac5e1521e38a91efc452faeb3e2135a1Timo Sirainen}
67c24901ac5e1521e38a91efc452faeb3e2135a1Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenstatic int
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenmail_log_copy(struct mailbox_transaction_context *t, struct mail *mail,
67c24901ac5e1521e38a91efc452faeb3e2135a1Timo Sirainen enum mail_flags flags, struct mail_keywords *keywords,
67c24901ac5e1521e38a91efc452faeb3e2135a1Timo Sirainen struct mail *dest_mail)
67c24901ac5e1521e38a91efc452faeb3e2135a1Timo Sirainen{
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen struct mail_log_mailbox *lbox = MAIL_LOG_CONTEXT(t->box);
67c24901ac5e1521e38a91efc452faeb3e2135a1Timo Sirainen const char *name;
67c24901ac5e1521e38a91efc452faeb3e2135a1Timo Sirainen
67c24901ac5e1521e38a91efc452faeb3e2135a1Timo Sirainen if (lbox->super.copy(t, mail, flags, keywords, dest_mail) < 0)
67c24901ac5e1521e38a91efc452faeb3e2135a1Timo Sirainen return -1;
67c24901ac5e1521e38a91efc452faeb3e2135a1Timo Sirainen
67c24901ac5e1521e38a91efc452faeb3e2135a1Timo Sirainen t_push();
67c24901ac5e1521e38a91efc452faeb3e2135a1Timo Sirainen name = str_sanitize(mailbox_get_name(t->box), MAILBOX_NAME_LOG_LEN);
67c24901ac5e1521e38a91efc452faeb3e2135a1Timo Sirainen mail_log_action(mail, t_strdup_printf("copy -> %s", name));
67c24901ac5e1521e38a91efc452faeb3e2135a1Timo Sirainen t_pop();
67c24901ac5e1521e38a91efc452faeb3e2135a1Timo Sirainen return 0;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
e11a64ffc7f08b4cb05bcc27668d154d33d0c2e0Timo Sirainenstatic struct mailbox *
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainenmail_log_mailbox_open(struct mail_storage *storage, const char *name,
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen struct istream *input, enum mailbox_open_flags flags)
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen{
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct mail_log_mail_storage *lstorage = MAIL_LOG_CONTEXT(storage);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct mailbox *box;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen struct mail_log_mailbox *lbox;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen box = lstorage->super.mailbox_open(storage, name, input, flags);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (box == NULL)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return NULL;
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen lbox = p_new(box->pool, struct mail_log_mailbox, 1);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen lbox->super = box->v;
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen box->v.mail_alloc = mail_log_mail_alloc;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen box->v.copy = mail_log_copy;
b3142c8e513bc78da821fa70f479016148fa95e5Timo Sirainen array_idx_set(&box->module_contexts, mail_log_storage_module_id, &lbox);
b3142c8e513bc78da821fa70f479016148fa95e5Timo Sirainen return box;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
b3142c8e513bc78da821fa70f479016148fa95e5Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenstatic int
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenmail_log_mailbox_delete(struct mail_storage *storage, const char *name)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
b3142c8e513bc78da821fa70f479016148fa95e5Timo Sirainen struct mail_log_mail_storage *lstorage = MAIL_LOG_CONTEXT(storage);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (lstorage->super.mailbox_delete(storage, name) < 0)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return -1;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen i_info("Mailbox deleted: %s", str_sanitize(name, MAILBOX_NAME_LOG_LEN));
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen return 0;
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen}
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainenstatic void mail_log_mail_storage_created(struct mail_storage *storage)
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen{
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen struct mail_log_mail_storage *lstorage;
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen if (mail_log_next_hook_mail_storage_created != NULL)
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen mail_log_next_hook_mail_storage_created(storage);
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen lstorage = p_new(storage->pool, struct mail_log_mail_storage, 1);
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen lstorage->super = storage->v;
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen storage->v.mailbox_open = mail_log_mailbox_open;
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen storage->v.mailbox_delete = mail_log_mailbox_delete;
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen if (!mail_log_storage_module_id_set) {
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen mail_log_storage_module_id = mail_storage_module_id++;
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen mail_log_storage_module_id_set = TRUE;
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen }
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen array_idx_set(&storage->module_contexts,
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen mail_log_storage_module_id, &lstorage);
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen}
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainenvoid mail_log_plugin_init(void)
7d207b1e77a7b5e3fda640e353acfc86d261fedfTimo Sirainen{
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen mail_log_next_hook_mail_storage_created =
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen hook_mail_storage_created;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen hook_mail_storage_created = mail_log_mail_storage_created;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen}
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainenvoid mail_log_plugin_deinit(void)
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen{
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen if (mail_log_storage_module_id_set) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen hook_mail_storage_created =
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen mail_log_next_hook_mail_storage_created;
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen }
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen}
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen