mail-log-plugin.c revision 901d0f036826476cf75799a0fdda5777e51301e4
5a580c3a38ced62d4bcc95b8ac7c4f2935b5d294Timo Sirainen/* Copyright (c) 2007-2010 Dovecot authors, see the included COPYING file */
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen#include "lib.h"
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen#include "array.h"
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen#include "str.h"
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen#include "str-sanitize.h"
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen#include "imap-util.h"
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen#include "mail-storage-private.h"
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen#include "mailbox-list-private.h"
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen#include "notify-plugin.h"
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen#include "mail-log-plugin.h"
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen#include <stdlib.h>
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen#define MAILBOX_NAME_LOG_LEN 64
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen#define HEADER_LOG_LEN 80
0db42260be85e797aa9909a29b20296996f52e75Timo Sirainen
0db42260be85e797aa9909a29b20296996f52e75Timo Sirainen#define MAIL_LOG_CONTEXT(obj) \
0db42260be85e797aa9909a29b20296996f52e75Timo Sirainen MODULE_CONTEXT(obj, mail_log_storage_module)
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen#define MAIL_LOG_MAIL_CONTEXT(obj) \
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen MODULE_CONTEXT(obj, mail_log_mail_module)
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen#define MAIL_LOG_LIST_CONTEXT(obj) \
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen MODULE_CONTEXT(obj, mail_log_mailbox_list_module)
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainenenum mail_log_field {
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen MAIL_LOG_FIELD_UID = 0x01,
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen MAIL_LOG_FIELD_BOX = 0x02,
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen MAIL_LOG_FIELD_MSGID = 0x04,
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen MAIL_LOG_FIELD_PSIZE = 0x08,
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen MAIL_LOG_FIELD_VSIZE = 0x10,
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen MAIL_LOG_FIELD_FLAGS = 0x20,
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen MAIL_LOG_FIELD_FROM = 0x40,
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen MAIL_LOG_FIELD_SUBJECT = 0x80
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen};
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen#define MAIL_LOG_DEFAULT_FIELDS \
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen (MAIL_LOG_FIELD_UID | MAIL_LOG_FIELD_BOX | \
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen MAIL_LOG_FIELD_MSGID | MAIL_LOG_FIELD_PSIZE)
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainenenum mail_log_event {
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen MAIL_LOG_EVENT_DELETE = 0x01,
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen MAIL_LOG_EVENT_UNDELETE = 0x02,
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen MAIL_LOG_EVENT_EXPUNGE = 0x04,
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen MAIL_LOG_EVENT_SAVE = 0x08,
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen MAIL_LOG_EVENT_MAILBOX_DELETE = 0x10,
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen MAIL_LOG_EVENT_MAILBOX_RENAME = 0x20,
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen MAIL_LOG_EVENT_FLAG_CHANGE = 0x40
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen};
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen#define MAIL_LOG_DEFAULT_EVENTS \
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen (MAIL_LOG_EVENT_DELETE | MAIL_LOG_EVENT_UNDELETE | \
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen MAIL_LOG_EVENT_EXPUNGE | MAIL_LOG_EVENT_SAVE | \
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen MAIL_LOG_EVENT_MAILBOX_DELETE | MAIL_LOG_EVENT_MAILBOX_RENAME)
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
16cb5d65265dd0b216542803fd80c4b999ae118eTimo Sirainenstatic const char *field_names[] = {
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen "uid",
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen "box",
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen "msgid",
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen "size",
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen "vsize",
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen "flags",
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen "from",
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen "subject",
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen NULL
0ca3b9cb0f2a322a25ce7f229dc3d3a0b46be17bTimo Sirainen};
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainenstatic const char *event_names[] = {
16cb5d65265dd0b216542803fd80c4b999ae118eTimo Sirainen "delete",
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen "undelete",
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen "expunge",
16cb5d65265dd0b216542803fd80c4b999ae118eTimo Sirainen "save",
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen "mailbox_delete",
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen "mailbox_rename",
16cb5d65265dd0b216542803fd80c4b999ae118eTimo Sirainen "flag_change",
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen NULL
16cb5d65265dd0b216542803fd80c4b999ae118eTimo Sirainen};
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
16cb5d65265dd0b216542803fd80c4b999ae118eTimo Sirainenstruct mail_log_settings {
56d1345c43bbd28c36b7faa85e4163bd9e874290Timo Sirainen enum mail_log_field fields;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen enum mail_log_event events;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen};
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainenstruct mail_log_message {
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen struct mail_log_message *prev, *next;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen const char *pretext, *text;
16cb5d65265dd0b216542803fd80c4b999ae118eTimo Sirainen};
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainenstruct mail_log_mail_txn_context {
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen pool_t pool;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen struct mail_log_message *messages, *messages_tail;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen};
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainenstatic struct mail_log_settings mail_log_set;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
56aa97d74071f3a2987140c2ff1cfd5a59cb35aaTimo Sirainenstatic enum mail_log_field mail_log_field_find(const char *name)
56aa97d74071f3a2987140c2ff1cfd5a59cb35aaTimo Sirainen{
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen unsigned int i;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen for (i = 0; field_names[i] != NULL; i++) {
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen if (strcmp(name, field_names[i]) == 0)
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen return 1 << i;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen }
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen return 0;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen}
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainenstatic enum mail_log_event mail_log_event_find(const char *name)
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen{
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen unsigned int i;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen for (i = 0; event_names[i] != NULL; i++) {
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen if (strcmp(name, event_names[i]) == 0)
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen return 1 << i;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen }
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen return 0;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen}
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainenstatic enum mail_log_field mail_log_parse_fields(const char *str)
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen{
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen const char *const *tmp;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen static enum mail_log_field field, fields = 0;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
8c909e451d14075c05d90382cf8eebc4e354f569Timo Sirainen for (tmp = t_strsplit_spaces(str, ", "); *tmp != NULL; tmp++) {
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen field = mail_log_field_find(*tmp);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen if (field == 0)
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen i_fatal("Unknown field in mail_log_fields: '%s'", *tmp);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen fields |= field;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen }
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen return fields;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen}
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainenstatic enum mail_log_event mail_log_parse_events(const char *str)
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen{
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen const char *const *tmp;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen static enum mail_log_event event, events = 0;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen for (tmp = t_strsplit_spaces(str, ", "); *tmp != NULL; tmp++) {
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen event = mail_log_event_find(*tmp);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen if (event == 0)
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen i_fatal("Unknown event in mail_log_events: '%s'", *tmp);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen events |= event;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen }
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen return events;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen}
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainenstatic void mail_log_read_settings(struct mail_log_settings *set)
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen{
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen const char *str;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen memset(set, 0, sizeof(*set));
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen str = getenv("MAIL_LOG_FIELDS");
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen set->fields = str == NULL ? MAIL_LOG_DEFAULT_FIELDS :
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen mail_log_parse_fields(str);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen str = getenv("MAIL_LOG_EVENTS");
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen set->events = str == NULL ? MAIL_LOG_DEFAULT_EVENTS :
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen mail_log_parse_events(str);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen}
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainenstatic void mail_log_append_mailbox_name(string_t *str, struct mail *mail)
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen{
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen const char *mailbox_str;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen mailbox_str = mailbox_get_name(mail->box);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen str_printfa(str, "box=%s",
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen str_sanitize(mailbox_str, MAILBOX_NAME_LOG_LEN));
9a1f68e5ab08eabd352d533315cba1c69006e2c1Timo Sirainen}
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
bdb026e2dc8a7c77585ed5ba489f0056df8074d4Timo Sirainenstatic void
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainenmail_log_append_mail_header(string_t *str, struct mail *mail,
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen const char *name, const char *header)
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen{
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen const char *value;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen if (mail_get_first_header(mail, header, &value) <= 0)
16cb5d65265dd0b216542803fd80c4b999ae118eTimo Sirainen value = "";
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen str_printfa(str, "%s=%s", name, str_sanitize(value, HEADER_LOG_LEN));
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen}
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainenstatic void
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainenmail_log_append_uid(struct mail_log_mail_txn_context *ctx,
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen struct mail_log_message *msg, string_t *str, uint32_t uid)
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen{
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen if (uid != 0)
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen str_printfa(str, "uid=%u", uid);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen else {
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen /* we don't know the uid yet, assign it later */
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen str_printfa(str, "uid=");
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen msg->pretext = p_strdup(ctx->pool, str_c(str));
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen str_truncate(str, 0);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen }
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen}
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainenstatic void
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainenmail_log_append_mail_message_real(struct mail_log_mail_txn_context *ctx,
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen struct mail *mail, enum mail_log_event event,
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen const char *desc)
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen{
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen struct mail_log_message *msg;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen string_t *text;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen uoff_t size;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen msg = p_new(ctx->pool, struct mail_log_message, 1);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen text = t_str_new(128);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen str_append(text, desc);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen str_append(text, ": ");
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen if ((mail_log_set.fields & MAIL_LOG_FIELD_BOX) != 0) {
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen mail_log_append_mailbox_name(text, mail);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen str_append(text, ", ");
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen }
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen if ((mail_log_set.fields & MAIL_LOG_FIELD_UID) != 0) {
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen if (event == MAIL_LOG_EVENT_SAVE)
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen mail_log_append_uid(ctx, msg, text, 0);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen else
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen mail_log_append_uid(ctx, msg, text, mail->uid);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen str_append(text, ", ");
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen }
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen if ((mail_log_set.fields & MAIL_LOG_FIELD_MSGID) != 0) {
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen mail_log_append_mail_header(text, mail, "msgid", "Message-ID");
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen str_append(text, ", ");
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen }
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen if ((mail_log_set.fields & MAIL_LOG_FIELD_PSIZE) != 0) {
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen if (mail_get_physical_size(mail, &size) == 0)
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen str_printfa(text, "size=%"PRIuUOFF_T, size);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen else
56aa97d74071f3a2987140c2ff1cfd5a59cb35aaTimo Sirainen str_printfa(text, "size=error");
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen str_append(text, ", ");
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen }
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen if ((mail_log_set.fields & MAIL_LOG_FIELD_VSIZE) != 0) {
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen if (mail_get_virtual_size(mail, &size) == 0)
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen str_printfa(text, "vsize=%"PRIuUOFF_T, size);
c6afd726060aae56b6622c6c52aec10231c4bf1cTimo Sirainen else
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen str_printfa(text, "vsize=error");
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen str_append(text, ", ");
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen }
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen if ((mail_log_set.fields & MAIL_LOG_FIELD_FROM) != 0) {
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen mail_log_append_mail_header(text, mail, "from", "From");
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen str_append(text, ", ");
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen }
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen if ((mail_log_set.fields & MAIL_LOG_FIELD_SUBJECT) != 0) {
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen mail_log_append_mail_header(text, mail, "subject", "Subject");
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen str_append(text, ", ");
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen }
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen if ((mail_log_set.fields & MAIL_LOG_FIELD_FLAGS) != 0) {
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen str_printfa(text, "flags=(");
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen imap_write_flags(text, mail_get_flags(mail),
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen mail_get_keywords(mail));
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen str_append(text, "), ");
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen }
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen str_truncate(text, str_len(text)-2);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen msg->text = p_strdup(ctx->pool, str_c(text));
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen msg->prev = ctx->messages_tail;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen ctx->messages_tail = msg;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen if (msg->prev != NULL)
62041dfb7d6ac6e9c633a557075999cdfcff7bd5Timo Sirainen msg->prev->next = msg;
62041dfb7d6ac6e9c633a557075999cdfcff7bd5Timo Sirainen if (ctx->messages == NULL)
62041dfb7d6ac6e9c633a557075999cdfcff7bd5Timo Sirainen ctx->messages = msg;
62041dfb7d6ac6e9c633a557075999cdfcff7bd5Timo Sirainen}
62041dfb7d6ac6e9c633a557075999cdfcff7bd5Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainenstatic void
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainenmail_log_append_mail_message(struct mail_log_mail_txn_context *ctx,
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen struct mail *mail, enum mail_log_event event,
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen const char *desc)
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen{
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen if ((mail_log_set.events & event) == 0)
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen return;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen T_BEGIN {
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen mail_log_append_mail_message_real(ctx, mail, event, desc);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen } T_END;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen}
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainenstatic void *
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainenmail_log_mail_transaction_begin(struct mailbox_transaction_context *t ATTR_UNUSED)
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen{
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen pool_t pool;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen struct mail_log_mail_txn_context *ctx;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen pool = pool_alloconly_create("mail-log", 2048);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen ctx = p_new(pool, struct mail_log_mail_txn_context, 1);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen ctx->pool = pool;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen return ctx;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen}
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainenstatic void mail_log_mail_save(void *txn, struct mail *mail)
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen{
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen struct mail_log_mail_txn_context *ctx =
(struct mail_log_mail_txn_context *)txn;
mail_log_append_mail_message(ctx, mail, MAIL_LOG_EVENT_SAVE, "save");
}
static void mail_log_mail_copy(void *txn, struct mail *src, struct mail *dst)
{
struct mail_log_mail_txn_context *ctx =
(struct mail_log_mail_txn_context *)txn;
const char *desc;
desc = t_strdup_printf("copy from %s",
str_sanitize(mailbox_get_name(src->box),
MAILBOX_NAME_LOG_LEN));
mail_log_append_mail_message(ctx, dst, MAIL_LOG_EVENT_SAVE, desc);
}
static void mail_log_mail_expunge(void *txn, struct mail *mail)
{
struct mail_log_mail_txn_context *ctx =
(struct mail_log_mail_txn_context *)txn;
mail_log_append_mail_message(ctx, mail, MAIL_LOG_EVENT_EXPUNGE,
"expunge");
}
static void mail_log_mail_update_flags(void *txn, struct mail *mail,
enum mail_flags old_flags)
{
struct mail_log_mail_txn_context *ctx =
(struct mail_log_mail_txn_context *)txn;
enum mail_flags new_flags = mail_get_flags(mail);
if (((old_flags ^ new_flags) & MAIL_DELETED) == 0) {
mail_log_append_mail_message(ctx, mail,
MAIL_LOG_EVENT_FLAG_CHANGE,
"flag_change");
} else if ((old_flags & MAIL_DELETED) == 0) {
mail_log_append_mail_message(ctx, mail, MAIL_LOG_EVENT_DELETE,
"delete");
} else {
mail_log_append_mail_message(ctx, mail, MAIL_LOG_EVENT_UNDELETE,
"undelete");
}
}
static void
mail_log_mail_update_keywords(void *txn, struct mail *mail,
const char *const *old_keywords ATTR_UNUSED)
{
struct mail_log_mail_txn_context *ctx =
(struct mail_log_mail_txn_context *)txn;
mail_log_append_mail_message(ctx, mail, MAIL_LOG_EVENT_FLAG_CHANGE,
"flag_change");
}
static void
mail_log_mail_transaction_commit(void *txn,
struct mail_transaction_commit_changes *changes)
{
struct mail_log_mail_txn_context *ctx =
(struct mail_log_mail_txn_context *)txn;
struct mail_log_message *msg;
struct seq_range_iter iter;
unsigned int n = 0;
uint32_t uid;
bool ret;
seq_range_array_iter_init(&iter, &changes->saved_uids);
for (msg = ctx->messages; msg != NULL; msg = msg->next) {
if (msg->pretext == NULL) {
i_info("%s", msg->text);
} else {
ret = seq_range_array_iter_nth(&iter, n++, &uid);
i_assert(ret);
i_info("%s%u%s", msg->pretext, uid, msg->text);
}
}
i_assert(!seq_range_array_iter_nth(&iter, n, &uid));
pool_unref(&ctx->pool);
}
static void mail_log_mail_transaction_rollback(void *txn)
{
struct mail_log_mail_txn_context *ctx =
(struct mail_log_mail_txn_context *)txn;
pool_unref(&ctx->pool);
}
static void
mail_log_mailbox_delete_commit(void *txn ATTR_UNUSED, struct mailbox *box)
{
if ((mail_log_set.events & MAIL_LOG_EVENT_MAILBOX_DELETE) == 0)
return;
i_info("Mailbox deleted: %s",
str_sanitize(box->name, MAILBOX_NAME_LOG_LEN));
}
static void
mail_log_mailbox_rename(struct mailbox *src,
struct mailbox *dest, bool rename_children ATTR_UNUSED)
{
if ((mail_log_set.events & MAIL_LOG_EVENT_MAILBOX_RENAME) == 0)
return;
i_info("Mailbox renamed: %s -> %s",
str_sanitize(src->name, MAILBOX_NAME_LOG_LEN),
str_sanitize(dest->name, MAILBOX_NAME_LOG_LEN));
}
static const struct notify_vfuncs mail_log_vfuncs = {
/* mail_transaction_begin */ mail_log_mail_transaction_begin,
/* mail_save */ mail_log_mail_save,
/* mail_copy */ mail_log_mail_copy,
/* mail_expunge */ mail_log_mail_expunge,
/* mail_update_flags */ mail_log_mail_update_flags,
/* mail_update_keywords */ mail_log_mail_update_keywords,
/* mail_transaction_commit */ mail_log_mail_transaction_commit,
/* mail_transaction_rollback */ mail_log_mail_transaction_rollback,
/* mailbox_delete_begin */ notify_noop_mailbox_delete_begin,
/* mailbox_delete_commit */ mail_log_mailbox_delete_commit,
/* mailbox_delete_rollback */ notify_noop_mailbox_delete_rollback,
/* mailbox_rename */ mail_log_mailbox_rename,
};
static struct notify_context *mail_log_ctx;
void mail_log_plugin_init(struct module *module ATTR_UNUSED)
{
mail_log_read_settings(&mail_log_set);
mail_log_ctx = notify_register(&mail_log_vfuncs);
}
void mail_log_plugin_deinit(void)
{
notify_unregister(mail_log_ctx);
}
const char *mail_log_plugin_dependencies[] = { "notify", NULL };