mail-log-plugin.c revision 1f6c210c30992e95b806d2f517e2b3625ed941c5
5a580c3a38ced62d4bcc95b8ac7c4f2935b5d294Timo Sirainen/* Copyright (c) 2007-2008 Dovecot authors, see the included COPYING file */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "lib.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "array.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "str.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "str-sanitize.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "imap-util.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "mail-storage-private.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "mailbox-list-private.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "mail-log-plugin.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include <stdlib.h>
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#define MAILBOX_NAME_LOG_LEN 64
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#define HEADER_LOG_LEN 80
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#define MAIL_LOG_CONTEXT(obj) \
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen MODULE_CONTEXT(obj, mail_log_storage_module)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#define MAIL_LOG_MAIL_CONTEXT(obj) \
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen MODULE_CONTEXT(obj, mail_log_mail_module)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#define MAIL_LOG_LIST_CONTEXT(obj) \
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen MODULE_CONTEXT(obj, mail_log_mailbox_list_module)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenenum mail_log_field {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen MAIL_LOG_FIELD_UID = 0x01,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen MAIL_LOG_FIELD_BOX = 0x02,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen MAIL_LOG_FIELD_MSGID = 0x04,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen MAIL_LOG_FIELD_PSIZE = 0x08,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen MAIL_LOG_FIELD_VSIZE = 0x10,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen MAIL_LOG_FIELD_FLAGS = 0x20,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen MAIL_LOG_FIELD_FROM = 0x40,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen MAIL_LOG_FIELD_SUBJECT = 0x80
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen};
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#define MAIL_LOG_DEFAULT_FIELDS \
0001f76bf725c5cf403bade8556f142dd43144eeTimo Sirainen (MAIL_LOG_FIELD_UID | MAIL_LOG_FIELD_BOX | \
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen MAIL_LOG_FIELD_MSGID | MAIL_LOG_FIELD_PSIZE)
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenenum mail_log_event {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen MAIL_LOG_EVENT_DELETE = 0x01,
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen MAIL_LOG_EVENT_UNDELETE = 0x02,
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen MAIL_LOG_EVENT_EXPUNGE = 0x04,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen MAIL_LOG_EVENT_COPY = 0x08,
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen MAIL_LOG_EVENT_MAILBOX_DELETE = 0x10,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen MAIL_LOG_EVENT_MAILBOX_RENAME = 0x20,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen MAIL_LOG_EVENT_FLAG_CHANGE = 0x40,
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen MAIL_LOG_EVENT_APPEND = 0x80
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen};
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen#define MAIL_LOG_DEFAULT_EVENTS \
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen (MAIL_LOG_EVENT_DELETE | MAIL_LOG_EVENT_UNDELETE | \
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen MAIL_LOG_EVENT_EXPUNGE | MAIL_LOG_EVENT_COPY | \
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen MAIL_LOG_EVENT_MAILBOX_DELETE | MAIL_LOG_EVENT_MAILBOX_RENAME)
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainenstatic const char *field_names[] = {
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen "uid",
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen "box",
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen "msgid",
cd83124e5d070a016c590bb0b1096d7828c7b6adTimo Sirainen "size",
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen "vsize",
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen "flags",
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen "from",
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen "subject",
714c6a150480112eb1a5f309d0cc39b60613a719Timo Sirainen NULL
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen};
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainenstatic const char *event_names[] = {
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen "delete",
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen "undelete",
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen "expunge",
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen "copy",
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen "mailbox_delete",
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen "mailbox_rename",
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen "flag_change",
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen "append",
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen NULL
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen};
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstruct mail_log_settings {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen enum mail_log_field fields;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen enum mail_log_event events;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
9a02317c852face76737763fa6ec43b444688de5Timo Sirainen unsigned int group_events:1;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen};
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainenstruct mail_log_group_changes {
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen enum mail_log_event event;
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen const char *data;
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen ARRAY_TYPE(seq_range) uids;
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen uoff_t psize_total, vsize_total;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen};
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstruct mail_log_transaction_context {
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen union mailbox_transaction_module_context module_ctx;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen pool_t pool;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct mail *tmp_mail;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen ARRAY_DEFINE(group_changes, struct mail_log_group_changes);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen unsigned int changes;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen};
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenconst char *mail_log_plugin_version = PACKAGE_VERSION;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic struct mail_log_settings mail_log_set;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic void (*mail_log_next_hook_mail_storage_created)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen (struct mail_storage *storage);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic void (*mail_log_next_hook_mailbox_list_created)
0001f76bf725c5cf403bade8556f142dd43144eeTimo Sirainen (struct mailbox_list *list);
e2eac5bb5637c2d4aaf453389750740931822b92Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic MODULE_CONTEXT_DEFINE_INIT(mail_log_storage_module,
e2bdacc34dde56aa664059ab56e8b77e82bd1805Timo Sirainen &mail_storage_module_register);
e2bdacc34dde56aa664059ab56e8b77e82bd1805Timo Sirainenstatic MODULE_CONTEXT_DEFINE_INIT(mail_log_mail_module, &mail_module_register);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic MODULE_CONTEXT_DEFINE_INIT(mail_log_mailbox_list_module,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen &mailbox_list_module_register);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic enum mail_log_field mail_log_field_find(const char *name)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
cd83124e5d070a016c590bb0b1096d7828c7b6adTimo Sirainen unsigned int i;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen for (i = 0; field_names[i] != NULL; i++) {
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen if (strcmp(name, field_names[i]) == 0)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return 1 << i;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return 0;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic enum mail_log_event mail_log_event_find(const char *name)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen unsigned int i;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen for (i = 0; event_names[i] != NULL; i++) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (strcmp(name, event_names[i]) == 0)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return 1 << i;
5e702db5540b2303e25554dee21bbf35a4813381Timo Sirainen }
5e702db5540b2303e25554dee21bbf35a4813381Timo Sirainen return 0;
5e702db5540b2303e25554dee21bbf35a4813381Timo Sirainen}
5e702db5540b2303e25554dee21bbf35a4813381Timo Sirainen
5e702db5540b2303e25554dee21bbf35a4813381Timo Sirainenstatic const char *mail_log_event_get_name(enum mail_log_event event)
46908da82cd45dd90ca7e438c8453bc9669868ecTimo Sirainen{
46908da82cd45dd90ca7e438c8453bc9669868ecTimo Sirainen unsigned int i;
5e702db5540b2303e25554dee21bbf35a4813381Timo Sirainen
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen for (i = 0; event_names[i] != NULL; i++) {
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen if ((unsigned)event == (unsigned)(1 << i))
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen return event_names[i];
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen i_unreached();
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return NULL;
e6440616c02bb1404dc35debf45d9741260c7831Timo Sirainen}
e6440616c02bb1404dc35debf45d9741260c7831Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic struct mail_log_group_changes *
0001f76bf725c5cf403bade8556f142dd43144eeTimo Sirainenmail_log_action_get_group(struct mail_log_transaction_context *lt,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen enum mail_log_event event, const char *data)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct mail_log_group_changes *group;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen unsigned int i, count;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (!array_is_created(&lt->group_changes))
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen p_array_init(&lt->group_changes, lt->pool, 8);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen group = array_get_modifiable(&lt->group_changes, &count);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen for (i = 0; i < count; i++) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (group[i].event == event &&
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen null_strcmp(data, group[i].data) == 0)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return &group[i];
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
de62ce819d59a529530da4b57be1b8d6dad13d6bTimo Sirainen group = array_append_space(&lt->group_changes);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen group->event = event;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen group->data = p_strdup(lt->pool, data);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return group;
e6440616c02bb1404dc35debf45d9741260c7831Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic void
e6440616c02bb1404dc35debf45d9741260c7831Timo Sirainenmail_log_action_add_group(struct mail_log_transaction_context *lt,
1f19649986397419d014febd1337c6eb7b530f26Timo Sirainen struct mail *mail, enum mail_log_event event,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen const char *data)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct mail_log_group_changes *group;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen uoff_t size;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen group = mail_log_action_get_group(lt, event, data);
e6440616c02bb1404dc35debf45d9741260c7831Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if ((mail_log_set.fields & MAIL_LOG_FIELD_UID) != 0) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (!array_is_created(&group->uids))
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen p_array_init(&group->uids, lt->pool, 32);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen seq_range_array_add(&group->uids, 0, mail->uid);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if ((mail_log_set.fields & MAIL_LOG_FIELD_PSIZE) != 0 &&
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen (event & (MAIL_LOG_EVENT_EXPUNGE | MAIL_LOG_EVENT_COPY)) != 0) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (mail_get_physical_size(mail, &size) == 0)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen group->psize_total += size;
06eb8c1371aa06478d8840b1373cab7c2752d5edTimo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if ((mail_log_set.fields & MAIL_LOG_FIELD_VSIZE) != 0 &&
e6440616c02bb1404dc35debf45d9741260c7831Timo Sirainen (event & (MAIL_LOG_EVENT_EXPUNGE | MAIL_LOG_EVENT_COPY)) != 0) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (mail_get_virtual_size(mail, &size) == 0)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen group->vsize_total += size;
e6440616c02bb1404dc35debf45d9741260c7831Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
06eb8c1371aa06478d8840b1373cab7c2752d5edTimo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic void mail_log_append_mailbox_name(string_t *str, struct mailbox *box)
06eb8c1371aa06478d8840b1373cab7c2752d5edTimo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen const char *mailbox_str;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen /* most operations are for INBOX, and POP3 has only INBOX,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen so don't add it. */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mailbox_str = mailbox_get_name(box);
06eb8c1371aa06478d8840b1373cab7c2752d5edTimo Sirainen if (strcmp(mailbox_str, "INBOX") != 0) {
06eb8c1371aa06478d8840b1373cab7c2752d5edTimo Sirainen str_printfa(str, "box=%s, ",
06eb8c1371aa06478d8840b1373cab7c2752d5edTimo Sirainen str_sanitize(mailbox_str, MAILBOX_NAME_LOG_LEN));
06eb8c1371aa06478d8840b1373cab7c2752d5edTimo Sirainen }
06eb8c1371aa06478d8840b1373cab7c2752d5edTimo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic void
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenmail_log_group(struct mailbox *box, const struct mail_log_group_changes *group)
9047d770bfbb93ab6af5363dedb2d01363877243Timo Sirainen{
836e57b1e7817d008f8ae05cd4b506f420fed80dTimo Sirainen const struct seq_range *range;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen unsigned int i, count;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen string_t *str;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen str = t_str_new(128);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen str_printfa(str, "%s: ", mail_log_event_get_name(group->event));
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if ((mail_log_set.fields & MAIL_LOG_FIELD_UID) != 0 &&
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen array_is_created(&group->uids)) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen str_append(str, "uids=");
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen range = array_get(&group->uids, &count);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen for (i = 0; i < count; i++) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (i != 0)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen str_append_c(str, ',');
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen str_printfa(str, "%u", range[i].seq1);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (range[i].seq1 != range[i].seq2)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen str_printfa(str, "-%u", range[i].seq2);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen str_append(str, ", ");
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if ((mail_log_set.fields & MAIL_LOG_FIELD_BOX) != 0)
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen mail_log_append_mailbox_name(str, box);
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen if (group->event == MAIL_LOG_EVENT_COPY)
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen str_printfa(str, "dest=%s, ", group->data);
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen if (group->psize_total != 0)
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen str_printfa(str, "size=%"PRIuUOFF_T", ", group->psize_total);
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen if (group->vsize_total != 0)
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen str_printfa(str, "size=%"PRIuUOFF_T", ", group->vsize_total);
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen str_truncate(str, str_len(str)-2);
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen i_info("%s", str_c(str));
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen}
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainenstatic void
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainenmail_log_group_changes(struct mailbox *box,
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen struct mail_log_transaction_context *lt)
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen{
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen const struct mail_log_group_changes *group;
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen unsigned int i, count;
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen group = array_get(&lt->group_changes, &count);
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen for (i = 0; i < count; i++) {
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen T_BEGIN {
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen mail_log_group(box, &group[i]);
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen } T_END;
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen }
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen}
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainenstatic void mail_log_add_hdr(struct mail *mail, string_t *str,
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen const char *name, const char *header)
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen{
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen const char *value;
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen if (mail_get_first_header(mail, header, &value) <= 0)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen value = "";
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen str_printfa(str, "%s=%s, ", name, str_sanitize(value, HEADER_LOG_LEN));
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic void mail_log_action(struct mailbox_transaction_context *dest_trans,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct mail *mail, enum mail_log_event event,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen const char *data)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct mail_log_transaction_context *lt = MAIL_LOG_CONTEXT(dest_trans);
ddedc8b77c5bccc8d224ab5f8716d9874f5d8512Timo Sirainen uoff_t size;
ddedc8b77c5bccc8d224ab5f8716d9874f5d8512Timo Sirainen string_t *str;
ddedc8b77c5bccc8d224ab5f8716d9874f5d8512Timo Sirainen
ddedc8b77c5bccc8d224ab5f8716d9874f5d8512Timo Sirainen if ((mail_log_set.events & event) == 0)
ddedc8b77c5bccc8d224ab5f8716d9874f5d8512Timo Sirainen return;
ddedc8b77c5bccc8d224ab5f8716d9874f5d8512Timo Sirainen
f1612f8421207632e1dc9addd6c23e7f7098a54cTimo Sirainen lt->changes++;
56aa9083e1742d0083885aaf0c5b8581577731aeTimo Sirainen
56aa9083e1742d0083885aaf0c5b8581577731aeTimo Sirainen if (mail_log_set.group_events) {
f1612f8421207632e1dc9addd6c23e7f7098a54cTimo Sirainen mail_log_action_add_group(lt, mail, event, data);
56aa9083e1742d0083885aaf0c5b8581577731aeTimo Sirainen return;
f71c2d4e6b802bf8e622bcd5df29286262d05d5aTimo Sirainen }
f71c2d4e6b802bf8e622bcd5df29286262d05d5aTimo Sirainen
f71c2d4e6b802bf8e622bcd5df29286262d05d5aTimo Sirainen str = t_str_new(128);
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen str_printfa(str, "%s: ", mail_log_event_get_name(event));
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen
f71c2d4e6b802bf8e622bcd5df29286262d05d5aTimo Sirainen if ((mail_log_set.fields & MAIL_LOG_FIELD_UID) != 0 && mail->uid != 0)
f71c2d4e6b802bf8e622bcd5df29286262d05d5aTimo Sirainen str_printfa(str, "uid=%u, ", mail->uid);
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen if ((mail_log_set.fields & MAIL_LOG_FIELD_BOX) != 0)
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen mail_log_append_mailbox_name(str, mail->box);
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen if ((mail_log_set.fields & MAIL_LOG_FIELD_FLAGS) != 0) {
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen str_printfa(str, "flags=(");
3c40cf45bb10548bf434aea0fca32b99acc99a35Timo Sirainen imap_write_flags(str, mail_get_flags(mail),
3c40cf45bb10548bf434aea0fca32b99acc99a35Timo Sirainen mail_get_keywords(mail));
3c40cf45bb10548bf434aea0fca32b99acc99a35Timo Sirainen str_append(str, "), ");
3c40cf45bb10548bf434aea0fca32b99acc99a35Timo Sirainen }
3c40cf45bb10548bf434aea0fca32b99acc99a35Timo Sirainen if (event == MAIL_LOG_EVENT_COPY)
3c40cf45bb10548bf434aea0fca32b99acc99a35Timo Sirainen str_printfa(str, "dest=%s, ", data);
3c40cf45bb10548bf434aea0fca32b99acc99a35Timo Sirainen
3c40cf45bb10548bf434aea0fca32b99acc99a35Timo Sirainen if ((mail_log_set.fields & MAIL_LOG_FIELD_MSGID) != 0)
3c40cf45bb10548bf434aea0fca32b99acc99a35Timo Sirainen mail_log_add_hdr(mail, str, "msgid", "Message-ID");
3c40cf45bb10548bf434aea0fca32b99acc99a35Timo Sirainen if ((mail_log_set.fields & MAIL_LOG_FIELD_FROM) != 0)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mail_log_add_hdr(mail, str, "from", "From");
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if ((mail_log_set.fields & MAIL_LOG_FIELD_SUBJECT) != 0)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mail_log_add_hdr(mail, str, "subject", "Subject");
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if ((mail_log_set.fields & MAIL_LOG_FIELD_PSIZE) != 0 &&
fb5efc6ed69da679d9da31ef62daa7024de18212Timo Sirainen (event & (MAIL_LOG_EVENT_EXPUNGE | MAIL_LOG_EVENT_COPY)) != 0) {
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen if (mail_get_physical_size(mail, &size) == 0)
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen str_printfa(str, "size=%"PRIuUOFF_T", ", size);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if ((mail_log_set.fields & MAIL_LOG_FIELD_VSIZE) != 0 &&
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen (event & (MAIL_LOG_EVENT_EXPUNGE | MAIL_LOG_EVENT_COPY)) != 0) {
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen if (mail_get_virtual_size(mail, &size) == 0)
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen str_printfa(str, "vsize=%"PRIuUOFF_T", ", size);
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen str_truncate(str, str_len(str)-2);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen i_info("%s", str_c(str));
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic void mail_log_mail_expunge(struct mail *_mail)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct mail_private *mail = (struct mail_private *)_mail;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen union mail_module_context *lmail = MAIL_LOG_MAIL_CONTEXT(mail);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen T_BEGIN {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mail_log_action(_mail->transaction, _mail,
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen MAIL_LOG_EVENT_EXPUNGE, NULL);
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen } T_END;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen lmail->super.expunge(_mail);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
b780aa272b742a43579cdb523cc79cc8d4521306Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic void
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenmail_log_mail_update_flags(struct mail *_mail, enum modify_type modify_type,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen enum mail_flags flags)
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen{
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen struct mail_private *mail = (struct mail_private *)_mail;
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen union mail_module_context *lmail = MAIL_LOG_MAIL_CONTEXT(mail);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen enum mail_flags old_flags, new_flags;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen old_flags = mail_get_flags(_mail);
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen lmail->super.update_flags(_mail, modify_type, flags);
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen new_flags = old_flags;
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen switch (modify_type) {
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen case MODIFY_ADD:
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen new_flags |= flags;
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen break;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen case MODIFY_REMOVE:
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen new_flags &= ~flags;
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen break;
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen case MODIFY_REPLACE:
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen new_flags = flags;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen break;
b780aa272b742a43579cdb523cc79cc8d4521306Timo Sirainen }
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen if (((old_flags ^ new_flags) & MAIL_DELETED) != 0) T_BEGIN {
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen mail_log_action(_mail->transaction, _mail,
b780aa272b742a43579cdb523cc79cc8d4521306Timo Sirainen (new_flags & MAIL_DELETED) != 0 ?
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen MAIL_LOG_EVENT_DELETE :
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen MAIL_LOG_EVENT_UNDELETE, NULL);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen } T_END;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if ((old_flags & ~MAIL_DELETED) != (new_flags & ~MAIL_DELETED)) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mail_log_action(_mail->transaction, _mail,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen MAIL_LOG_EVENT_FLAG_CHANGE, NULL);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic void
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenmail_log_mail_update_keywords(struct mail *_mail, enum modify_type modify_type,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct mail_keywords *keywords)
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct mail_private *mail = (struct mail_private *)_mail;
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen union mail_module_context *lmail = MAIL_LOG_MAIL_CONTEXT(mail);
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen const char *const *old_keywords, *const *new_keywords;
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen unsigned int i;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen old_keywords = mail_get_keywords(_mail);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen lmail->super.update_keywords(_mail, modify_type, keywords);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen new_keywords = mail_get_keywords(_mail);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen for (i = 0; old_keywords[i] != NULL && new_keywords[i] != NULL; i++) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (strcmp(old_keywords[i], new_keywords[i]) != 0)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen break;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (old_keywords[i] != NULL || new_keywords[i] != NULL) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mail_log_action(_mail->transaction, _mail,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen MAIL_LOG_EVENT_FLAG_CHANGE, NULL);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic struct mail *
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenmail_log_mail_alloc(struct mailbox_transaction_context *t,
553cf4f8a8850efffdc714ec1d1ae45a5fc7905dTimo Sirainen enum mail_fetch_field wanted_fields,
553cf4f8a8850efffdc714ec1d1ae45a5fc7905dTimo Sirainen struct mailbox_header_lookup_ctx *wanted_headers)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen union mailbox_module_context *lbox = MAIL_LOG_CONTEXT(t->box);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen union mail_module_context *lmail;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct mail *_mail;
7f735cb86b2d8abd8f230089065eacfc24e9e5d6Timo Sirainen struct mail_private *mail;
553cf4f8a8850efffdc714ec1d1ae45a5fc7905dTimo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen _mail = lbox->super.mail_alloc(t, wanted_fields, wanted_headers);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mail = (struct mail_private *)_mail;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen lmail = p_new(mail->pool, union mail_module_context, 1);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen lmail->super = mail->v;
767ff4367960efd5fa868f3b56f850fd4c205c8bTimo Sirainen
08df28a63b3efb0f0ee30c3e7ef44c0a1e7bb459Timo Sirainen mail->v.update_flags = mail_log_mail_update_flags;
08df28a63b3efb0f0ee30c3e7ef44c0a1e7bb459Timo Sirainen mail->v.update_keywords = mail_log_mail_update_keywords;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mail->v.expunge = mail_log_mail_expunge;
08df28a63b3efb0f0ee30c3e7ef44c0a1e7bb459Timo Sirainen MODULE_CONTEXT_SET_SELF(mail, mail_log_mail_module, lmail);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return _mail;
553cf4f8a8850efffdc714ec1d1ae45a5fc7905dTimo Sirainen}
553cf4f8a8850efffdc714ec1d1ae45a5fc7905dTimo Sirainen
553cf4f8a8850efffdc714ec1d1ae45a5fc7905dTimo Sirainenstatic int
553cf4f8a8850efffdc714ec1d1ae45a5fc7905dTimo Sirainenmail_log_copy(struct mailbox_transaction_context *t, struct mail *mail,
553cf4f8a8850efffdc714ec1d1ae45a5fc7905dTimo Sirainen enum mail_flags flags, struct mail_keywords *keywords,
553cf4f8a8850efffdc714ec1d1ae45a5fc7905dTimo Sirainen struct mail *dest_mail)
61279c3c77aa4a6f8d1de82b468ab01b14418318Timo Sirainen{
61279c3c77aa4a6f8d1de82b468ab01b14418318Timo Sirainen union mailbox_module_context *lbox = MAIL_LOG_CONTEXT(t->box);
553cf4f8a8850efffdc714ec1d1ae45a5fc7905dTimo Sirainen const char *name;
553cf4f8a8850efffdc714ec1d1ae45a5fc7905dTimo Sirainen
553cf4f8a8850efffdc714ec1d1ae45a5fc7905dTimo Sirainen if (lbox->super.copy(t, mail, flags, keywords, dest_mail) < 0)
553cf4f8a8850efffdc714ec1d1ae45a5fc7905dTimo Sirainen return -1;
553cf4f8a8850efffdc714ec1d1ae45a5fc7905dTimo Sirainen
553cf4f8a8850efffdc714ec1d1ae45a5fc7905dTimo Sirainen T_BEGIN {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen name = str_sanitize(mailbox_get_name(t->box),
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen MAILBOX_NAME_LOG_LEN);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mail_log_action(t, mail, MAIL_LOG_EVENT_COPY, name);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen } T_END;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return 0;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic int
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenmail_log_save_begin(struct mail_save_context *ctx, struct istream *input)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
553cf4f8a8850efffdc714ec1d1ae45a5fc7905dTimo Sirainen struct mail_log_transaction_context *lt =
553cf4f8a8850efffdc714ec1d1ae45a5fc7905dTimo Sirainen MAIL_LOG_CONTEXT(ctx->transaction);
1554bed8d2b4e4286c10f7d6bcf716b246bd5bafTimo Sirainen union mailbox_module_context *lbox =
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen MAIL_LOG_CONTEXT(ctx->transaction->box);
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen if (ctx->dest_mail == NULL) {
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen if (lt->tmp_mail == NULL)
7631f16156aca373004953fe6b01a7f343fb47e0Timo Sirainen lt->tmp_mail = mail_alloc(ctx->transaction, 0, NULL);
7631f16156aca373004953fe6b01a7f343fb47e0Timo Sirainen ctx->dest_mail = lt->tmp_mail;
08df28a63b3efb0f0ee30c3e7ef44c0a1e7bb459Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return lbox->super.save_begin(ctx, input);
}
static int mail_log_save_finish(struct mail_save_context *ctx)
{
union mailbox_module_context *lbox =
MAIL_LOG_CONTEXT(ctx->transaction->box);
if (lbox->super.save_finish(ctx) < 0)
return -1;
T_BEGIN {
mail_log_action(ctx->transaction, ctx->dest_mail,
MAIL_LOG_EVENT_APPEND, NULL);
} T_END;
return 0;
}
static struct mailbox_transaction_context *
mail_log_transaction_begin(struct mailbox *box,
enum mailbox_transaction_flags flags)
{
union mailbox_module_context *lbox = MAIL_LOG_CONTEXT(box);
struct mailbox_transaction_context *t;
struct mail_log_transaction_context *lt;
pool_t pool;
t = lbox->super.transaction_begin(box, flags);
pool = pool_alloconly_create("mail log transaction", 1024);
lt = p_new(pool, struct mail_log_transaction_context, 1);
lt->pool = pool;
MODULE_CONTEXT_SET(t, mail_log_storage_module, lt);
return t;
}
static int
mail_log_transaction_commit(struct mailbox_transaction_context *t,
uint32_t *uid_validity_r,
uint32_t *first_saved_uid_r,
uint32_t *last_saved_uid_r)
{
struct mail_log_transaction_context *lt = MAIL_LOG_CONTEXT(t);
union mailbox_module_context *lbox = MAIL_LOG_CONTEXT(t->box);
if (lt->changes > 0 && mail_log_set.group_events)
mail_log_group_changes(t->box, lt);
if (lt->tmp_mail != NULL)
mail_free(&lt->tmp_mail);
pool_unref(&lt->pool);
return lbox->super.transaction_commit(t, uid_validity_r,
first_saved_uid_r,
last_saved_uid_r);
}
static void
mail_log_transaction_rollback(struct mailbox_transaction_context *t)
{
struct mail_log_transaction_context *lt = MAIL_LOG_CONTEXT(t);
union mailbox_module_context *lbox = MAIL_LOG_CONTEXT(t->box);
if (lt->changes > 0 && !mail_log_set.group_events) {
i_info("Transaction rolled back: "
"Ignore last %u changes", lt->changes);
}
if (lt->tmp_mail != NULL)
mail_free(&lt->tmp_mail);
pool_unref(&lt->pool);
lbox->super.transaction_rollback(t);
}
static struct mailbox *
mail_log_mailbox_open(struct mail_storage *storage, const char *name,
struct istream *input, enum mailbox_open_flags flags)
{
union mail_storage_module_context *lstorage = MAIL_LOG_CONTEXT(storage);
struct mailbox *box;
union mailbox_module_context *lbox;
box = lstorage->super.mailbox_open(storage, name, input, flags);
if (box == NULL)
return NULL;
lbox = p_new(box->pool, union mailbox_module_context, 1);
lbox->super = box->v;
box->v.mail_alloc = mail_log_mail_alloc;
box->v.copy = mail_log_copy;
box->v.save_begin = mail_log_save_begin;
box->v.save_finish = mail_log_save_finish;
box->v.transaction_begin = mail_log_transaction_begin;
box->v.transaction_commit = mail_log_transaction_commit;
box->v.transaction_rollback = mail_log_transaction_rollback;
MODULE_CONTEXT_SET_SELF(box, mail_log_storage_module, lbox);
return box;
}
static int
mail_log_mailbox_list_delete(struct mailbox_list *list, const char *name)
{
union mailbox_list_module_context *llist = MAIL_LOG_LIST_CONTEXT(list);
if (llist->super.delete_mailbox(list, name) < 0)
return -1;
if ((mail_log_set.events & MAIL_LOG_EVENT_MAILBOX_DELETE) == 0)
return 0;
i_info("Mailbox deleted: %s", str_sanitize(name, MAILBOX_NAME_LOG_LEN));
return 0;
}
static int
mail_log_mailbox_list_rename(struct mailbox_list *list, const char *oldname,
const char *newname)
{
union mailbox_list_module_context *llist = MAIL_LOG_LIST_CONTEXT(list);
if (llist->super.rename_mailbox(list, oldname, newname) < 0)
return -1;
if ((mail_log_set.events & MAIL_LOG_EVENT_MAILBOX_RENAME) == 0)
return 0;
i_info("Mailbox renamed: %s -> %s",
str_sanitize(oldname, MAILBOX_NAME_LOG_LEN),
str_sanitize(newname, MAILBOX_NAME_LOG_LEN));
return 0;
}
static void mail_log_mail_storage_created(struct mail_storage *storage)
{
union mail_storage_module_context *lstorage;
lstorage = p_new(storage->pool, union mail_storage_module_context, 1);
lstorage->super = storage->v;
storage->v.mailbox_open = mail_log_mailbox_open;
MODULE_CONTEXT_SET_SELF(storage, mail_log_storage_module, lstorage);
if (mail_log_next_hook_mail_storage_created != NULL)
mail_log_next_hook_mail_storage_created(storage);
}
static void mail_log_mailbox_list_created(struct mailbox_list *list)
{
union mailbox_list_module_context *llist;
llist = p_new(list->pool, union mailbox_list_module_context, 1);
llist->super = list->v;
list->v.delete_mailbox = mail_log_mailbox_list_delete;
list->v.rename_mailbox = mail_log_mailbox_list_rename;
MODULE_CONTEXT_SET_SELF(list, mail_log_mailbox_list_module, llist);
if (mail_log_next_hook_mailbox_list_created != NULL)
mail_log_next_hook_mailbox_list_created(list);
}
static enum mail_log_field mail_log_parse_fields(const char *str)
{
const char *const *tmp;
static enum mail_log_field field, fields = 0;
for (tmp = t_strsplit_spaces(str, ", "); *tmp != NULL; tmp++) {
field = mail_log_field_find(*tmp);
if (field == 0)
i_fatal("Unknown field in mail_log_fields: '%s'", *tmp);
fields |= field;
}
return fields;
}
static enum mail_log_event mail_log_parse_events(const char *str)
{
const char *const *tmp;
static enum mail_log_event event, events = 0;
for (tmp = t_strsplit_spaces(str, ", "); *tmp != NULL; tmp++) {
event = mail_log_event_find(*tmp);
if (event == 0)
i_fatal("Unknown event in mail_log_events: '%s'", *tmp);
events |= event;
}
return events;
}
static void mail_log_read_settings(struct mail_log_settings *set)
{
const char *str;
memset(set, 0, sizeof(*set));
str = getenv("MAIL_LOG_FIELDS");
set->fields = str == NULL ? MAIL_LOG_DEFAULT_FIELDS :
mail_log_parse_fields(str);
str = getenv("MAIL_LOG_EVENTS");
set->events = str == NULL ? MAIL_LOG_DEFAULT_EVENTS :
mail_log_parse_events(str);
set->group_events = getenv("MAIL_LOG_GROUP_EVENTS") != NULL;
}
void mail_log_plugin_init(void)
{
mail_log_read_settings(&mail_log_set);
mail_log_next_hook_mail_storage_created = hook_mail_storage_created;
hook_mail_storage_created = mail_log_mail_storage_created;
mail_log_next_hook_mailbox_list_created = hook_mailbox_list_created;
hook_mailbox_list_created = mail_log_mailbox_list_created;
}
void mail_log_plugin_deinit(void)
{
hook_mail_storage_created = mail_log_next_hook_mail_storage_created;
hook_mailbox_list_created = mail_log_next_hook_mailbox_list_created;
}