mail-log-plugin.c revision e8cd58b9d4fbbca77a1c83107bd8dc5307a4eb95
02c335c23bf5fa225a467c19f2c063fb0dc7b8c3Timo Sirainen/* Copyright (C) 2007 Timo Sirainen */
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen#include "lib.h"
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen#include "array.h"
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen#include "str-sanitize.h"
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen#include "mail-storage-private.h"
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen#include "mail-log-plugin.h"
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen#define MAILBOX_NAME_LOG_LEN 64
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen#define MSGID_LOG_LEN 80
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen#define MAIL_LOG_CONTEXT(obj) \
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen *((void **)array_idx_modifiable(&(obj)->module_contexts, \
8a8a3b43987b5ade914f22765e51c9e3de8179d3Timo Sirainen mail_log_storage_module_id))
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainenstruct mail_log_mail_storage {
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen struct mail_storage_vfuncs super;
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen};
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainenstruct mail_log_mailbox {
8a8a3b43987b5ade914f22765e51c9e3de8179d3Timo Sirainen struct mailbox_vfuncs super;
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen};
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainenstruct mail_log_mail {
2f4f603d4cebab2cc956c72164efb02da83515c5Timo Sirainen struct mail_vfuncs super;
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen};
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen/* defined by imap, pop3, lda */
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainenextern void (*hook_mail_storage_created)(struct mail_storage *storage);
d5e839aea288aceaddae28a1578cebda3c9e3b58Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainenconst char *mail_log_plugin_version = PACKAGE_VERSION;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainenstatic void (*mail_log_next_hook_mail_storage_created)
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen (struct mail_storage *storage);
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainenstatic unsigned int mail_log_storage_module_id = 0;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainenstatic bool mail_log_storage_module_id_set = FALSE;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainenstatic void mail_log_action(struct mail *mail, const char *action)
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen{
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen const char *msgid, *mailbox_str;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen mailbox_str = mailbox_get_name(mail->box);
2f4f603d4cebab2cc956c72164efb02da83515c5Timo Sirainen if (strcmp(mailbox_str, "INBOX") == 0) {
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen /* most operations are for INBOX, and POP3 has only INBOX,
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen so don't add it. */
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen mailbox_str = "";
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen } else {
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen mailbox_str = str_sanitize(mailbox_str, 80);
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen mailbox_str = t_strconcat(", box=", mailbox_str, NULL);
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen }
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen msgid = mail_get_first_header(mail, "Message-ID");
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen i_info("%s: uid=%u, msgid=%s%s", action, mail->uid,
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen msgid == NULL ? "(null)" : str_sanitize(msgid, MSGID_LOG_LEN),
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen mailbox_str);
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen}
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainenstatic int mail_log_mail_expunge(struct mail *_mail)
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen{
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen struct mail_private *mail = (struct mail_private *)_mail;
46b823ac3bce2c0f9f0fc73911e48d3a77b04fbeTimo Sirainen struct mail_log_mail *lmail = MAIL_LOG_CONTEXT(mail);
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen if (lmail->super.expunge(_mail) < 0)
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen return -1;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen mail_log_action(_mail, "expunged");
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen return 0;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen}
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
e245fb1302121d2bc2580f61e040c2c8a558ee9eTimo Sirainenstatic int
e245fb1302121d2bc2580f61e040c2c8a558ee9eTimo Sirainenmail_log_mail_update_flags(struct mail *_mail, enum modify_type modify_type,
e245fb1302121d2bc2580f61e040c2c8a558ee9eTimo Sirainen enum mail_flags flags)
d5e839aea288aceaddae28a1578cebda3c9e3b58Timo Sirainen{
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen struct mail_private *mail = (struct mail_private *)_mail;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen struct mail_log_mail *lmail = MAIL_LOG_CONTEXT(mail);
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen enum mail_flags old_flags, new_flags;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen old_flags = mail_get_flags(_mail);
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen if (lmail->super.update_flags(_mail, modify_type, flags) < 0)
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen return -1;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen new_flags = old_flags;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen switch (modify_type) {
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen case MODIFY_ADD:
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen new_flags |= flags;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen break;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen case MODIFY_REMOVE:
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen new_flags &= ~flags;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen break;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen case MODIFY_REPLACE:
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen new_flags = flags;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen break;
d5e839aea288aceaddae28a1578cebda3c9e3b58Timo Sirainen }
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen if (((old_flags ^ new_flags) & MAIL_DELETED) == 0)
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen return 0;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen mail_log_action(_mail, (new_flags & MAIL_DELETED) != 0 ?
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen "deleted" : "undeleted");
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen return 0;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen}
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainenstatic struct mail *
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainenmail_log_mail_alloc(struct mailbox_transaction_context *t,
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen enum mail_fetch_field wanted_fields,
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen struct mailbox_header_lookup_ctx *wanted_headers)
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen{
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen struct mail_log_mailbox *lbox = MAIL_LOG_CONTEXT(t->box);
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen struct mail_log_mail *lmail;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen struct mail *_mail;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen struct mail_private *mail;
8a8a3b43987b5ade914f22765e51c9e3de8179d3Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen _mail = lbox->super.mail_alloc(t, wanted_fields, wanted_headers);
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen mail = (struct mail_private *)_mail;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen lmail = p_new(mail->pool, struct mail_log_mail, 1);
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen lmail->super = mail->v;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen mail->v.update_flags = mail_log_mail_update_flags;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen mail->v.expunge = mail_log_mail_expunge;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen array_idx_set(&mail->module_contexts,
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen mail_log_storage_module_id, &lmail);
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen return _mail;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen}
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainenstatic int
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainenmail_log_copy(struct mailbox_transaction_context *t, struct mail *mail,
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen enum mail_flags flags, struct mail_keywords *keywords,
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen struct mail *dest_mail)
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen{
6adf683655750bcb809275cd65dc75fd12214198Timo Sirainen struct mail_log_mailbox *lbox = MAIL_LOG_CONTEXT(t->box);
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen const char *name;
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen if (lbox->super.copy(t, mail, flags, keywords, dest_mail) < 0)
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen return -1;
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen t_push();
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen name = str_sanitize(mailbox_get_name(t->box), MAILBOX_NAME_LOG_LEN);
6adf683655750bcb809275cd65dc75fd12214198Timo Sirainen mail_log_action(mail, t_strdup_printf("copy -> %s", name));
6adf683655750bcb809275cd65dc75fd12214198Timo Sirainen t_pop();
6adf683655750bcb809275cd65dc75fd12214198Timo Sirainen return 0;
6adf683655750bcb809275cd65dc75fd12214198Timo Sirainen}
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainenstatic struct mailbox *
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainenmail_log_mailbox_open(struct mail_storage *storage, const char *name,
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen struct istream *input, enum mailbox_open_flags flags)
6adf683655750bcb809275cd65dc75fd12214198Timo Sirainen{
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen struct mail_log_mail_storage *lstorage = MAIL_LOG_CONTEXT(storage);
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen struct mailbox *box;
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen struct mail_log_mailbox *lbox;
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen box = lstorage->super.mailbox_open(storage, name, input, flags);
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen if (box == NULL)
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen return NULL;
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen lbox = p_new(box->pool, struct mail_log_mailbox, 1);
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen lbox->super = box->v;
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen box->v.mail_alloc = mail_log_mail_alloc;
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen box->v.copy = mail_log_copy;
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen array_idx_set(&box->module_contexts, mail_log_storage_module_id, &lbox);
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen return box;
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen}
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainenstatic int
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainenmail_log_mailbox_delete(struct mail_storage *storage, const char *name)
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen{
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen struct mail_log_mail_storage *lstorage = MAIL_LOG_CONTEXT(storage);
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen if (lstorage->super.mailbox_delete(storage, name) < 0)
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen return -1;
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen i_info("Mailbox deleted: %s", str_sanitize(name, MAILBOX_NAME_LOG_LEN));
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen return 0;
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen}
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainenstatic void mail_log_mail_storage_created(struct mail_storage *storage)
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen{
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen struct mail_log_mail_storage *lstorage;
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen
6adf683655750bcb809275cd65dc75fd12214198Timo Sirainen if (mail_log_next_hook_mail_storage_created != NULL)
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen mail_log_next_hook_mail_storage_created(storage);
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen
6adf683655750bcb809275cd65dc75fd12214198Timo Sirainen lstorage = p_new(storage->pool, struct mail_log_mail_storage, 1);
6adf683655750bcb809275cd65dc75fd12214198Timo Sirainen lstorage->super = storage->v;
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen storage->v.mailbox_open = mail_log_mailbox_open;
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen storage->v.mailbox_delete = mail_log_mailbox_delete;
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen if (!mail_log_storage_module_id_set) {
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen mail_log_storage_module_id = mail_storage_module_id++;
6adf683655750bcb809275cd65dc75fd12214198Timo Sirainen mail_log_storage_module_id_set = TRUE;
6adf683655750bcb809275cd65dc75fd12214198Timo Sirainen }
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen array_idx_set(&storage->module_contexts,
46631c1d903c409444b1b1c4a1d41a033c09ee37Timo Sirainen mail_log_storage_module_id, &lstorage);
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen}
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen
fb176cdc122707cda985ab3c09c02ccf3cec0af1Timo Sirainenvoid mail_log_plugin_init(void)
fb176cdc122707cda985ab3c09c02ccf3cec0af1Timo Sirainen{
fb176cdc122707cda985ab3c09c02ccf3cec0af1Timo Sirainen mail_log_next_hook_mail_storage_created =
fb176cdc122707cda985ab3c09c02ccf3cec0af1Timo Sirainen hook_mail_storage_created;
fb176cdc122707cda985ab3c09c02ccf3cec0af1Timo Sirainen hook_mail_storage_created = mail_log_mail_storage_created;
fb176cdc122707cda985ab3c09c02ccf3cec0af1Timo Sirainen}
fb176cdc122707cda985ab3c09c02ccf3cec0af1Timo Sirainen
fb176cdc122707cda985ab3c09c02ccf3cec0af1Timo Sirainenvoid mail_log_plugin_deinit(void)
fb176cdc122707cda985ab3c09c02ccf3cec0af1Timo Sirainen{
fb176cdc122707cda985ab3c09c02ccf3cec0af1Timo Sirainen if (mail_log_storage_module_id_set) {
d5e839aea288aceaddae28a1578cebda3c9e3b58Timo Sirainen hook_mail_storage_created =
d5e839aea288aceaddae28a1578cebda3c9e3b58Timo Sirainen mail_log_next_hook_mail_storage_created;
d5e839aea288aceaddae28a1578cebda3c9e3b58Timo Sirainen }
d5e839aea288aceaddae28a1578cebda3c9e3b58Timo Sirainen}
d5e839aea288aceaddae28a1578cebda3c9e3b58Timo Sirainen