bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2007-2018 Dovecot authors, see the included COPYING file */
3320f4770d1f6c2cdd10f3c4ca5a324beb335339Timo Sirainen (MAIL_LOG_EVENT_DELETE | MAIL_LOG_EVENT_UNDELETE | \
d6cc34b076dced6ebf8af47d72c8242357288312Timo Sirainen MAIL_LOG_EVENT_EXPUNGE | MAIL_LOG_EVENT_SAVE | MAIL_LOG_EVENT_COPY | \
3320f4770d1f6c2cdd10f3c4ca5a324beb335339Timo Sirainen MAIL_LOG_EVENT_MAILBOX_DELETE | MAIL_LOG_EVENT_MAILBOX_RENAME)
4babe70b863c71ea330cbf32ac0b71876f4f9137Timo Sirainen "mailbox_create",
cb1fd563e6000153d1be76fd8722a096bd144b77Timo Sirainen "mailbox_delete",
3320f4770d1f6c2cdd10f3c4ca5a324beb335339Timo Sirainen "mailbox_rename",
3320f4770d1f6c2cdd10f3c4ca5a324beb335339Timo Sirainen "flag_change",
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen struct mail_log_message *messages, *messages_tail;
b66412da78711db8423288847ecfb08469609a03Timo Sirainenstatic MODULE_CONTEXT_DEFINE_INIT(mail_log_user_module,
cb1fd563e6000153d1be76fd8722a096bd144b77Timo Sirainenstatic enum mail_log_field mail_log_field_find(const char *name)
cb1fd563e6000153d1be76fd8722a096bd144b77Timo Sirainen unsigned int i;
cb1fd563e6000153d1be76fd8722a096bd144b77Timo Sirainen return 1 << i;
cb1fd563e6000153d1be76fd8722a096bd144b77Timo Sirainenstatic enum mail_log_event mail_log_event_find(const char *name)
cb1fd563e6000153d1be76fd8722a096bd144b77Timo Sirainen unsigned int i;
b66412da78711db8423288847ecfb08469609a03Timo Sirainen /* v1.x backwards compatibility */
cb1fd563e6000153d1be76fd8722a096bd144b77Timo Sirainen return 1 << i;
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainenstatic enum mail_log_field mail_log_parse_fields(const char *str)
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen for (tmp = t_strsplit_spaces(str, ", "); *tmp != NULL; tmp++) {
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen i_fatal("Unknown field in mail_log_fields: '%s'", *tmp);
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainenstatic enum mail_log_event mail_log_parse_events(const char *str)
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen for (tmp = t_strsplit_spaces(str, ", "); *tmp != NULL; tmp++) {
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen i_fatal("Unknown event in mail_log_events: '%s'", *tmp);
b66412da78711db8423288847ecfb08469609a03Timo Sirainenstatic void mail_log_mail_user_created(struct mail_user *user)
b66412da78711db8423288847ecfb08469609a03Timo Sirainen muser = p_new(user->pool, struct mail_log_user, 1);
b66412da78711db8423288847ecfb08469609a03Timo Sirainen MODULE_CONTEXT_SET(user, mail_log_user_module, muser);
b66412da78711db8423288847ecfb08469609a03Timo Sirainen str = mail_user_plugin_getenv(user, "mail_log_fields");
b66412da78711db8423288847ecfb08469609a03Timo Sirainen muser->fields = str == NULL ? MAIL_LOG_DEFAULT_FIELDS :
b66412da78711db8423288847ecfb08469609a03Timo Sirainen str = mail_user_plugin_getenv(user, "mail_log_events");
b66412da78711db8423288847ecfb08469609a03Timo Sirainen muser->events = str == NULL ? MAIL_LOG_DEFAULT_EVENTS :
86448bdb60ed69566bc1093dda824133448ed7a0Timo Sirainen mail_user_plugin_getenv_bool(user, "mail_log_cached_only");
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainenstatic void mail_log_append_mailbox_name(string_t *str, struct mail *mail)
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen str_sanitize(mailbox_str, MAILBOX_NAME_LOG_LEN));
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainenmail_log_append_mail_header(string_t *str, struct mail *mail,
fe219d44d016a40771117bdcb112828cdfad36a4Martti Rannanjärvi if (mail_get_first_header_utf8(mail, header, &value) <= 0)
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen str_printfa(str, "%s=%s", name, str_sanitize(value, HEADER_LOG_LEN));
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainenmail_log_append_uid(struct mail_log_mail_txn_context *ctx,
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen struct mail_log_message *msg, string_t *str, uint32_t uid)
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen /* we don't know the uid yet, assign it later */
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen msg->pretext = p_strdup(ctx->pool, str_c(str));
9c0716dfcd6b575419776848dd7157186ef58d57Timo Sirainenmail_log_update_wanted_fields(struct mail *mail, enum mail_log_field fields)
9c0716dfcd6b575419776848dd7157186ef58d57Timo Sirainen struct mailbox_header_lookup_ctx *wanted_headers = NULL;
9c0716dfcd6b575419776848dd7157186ef58d57Timo Sirainen wanted_headers = mailbox_header_lookup_init(mail->box, headers);
9c0716dfcd6b575419776848dd7157186ef58d57Timo Sirainen mail_add_temp_wanted_fields(mail, wanted_fields, wanted_headers);
ceb8c97c6c9fe0ee7eb544645c6bdb74dfcb519dJosef 'Jeff' Sipek mailbox_header_lookup_unref(&wanted_headers);
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainenmail_log_append_mail_message_real(struct mail_log_mail_txn_context *ctx,
b66412da78711db8423288847ecfb08469609a03Timo Sirainen MAIL_LOG_USER_CONTEXT(mail->box->storage->user);
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen msg = p_new(ctx->pool, struct mail_log_message, 1);
9c0716dfcd6b575419776848dd7157186ef58d57Timo Sirainen /* avoid parsing through the message multiple times */
9c0716dfcd6b575419776848dd7157186ef58d57Timo Sirainen mail_log_update_wanted_fields(mail, muser->fields);
b66412da78711db8423288847ecfb08469609a03Timo Sirainen if ((muser->fields & MAIL_LOG_FIELD_BOX) != 0) {
b66412da78711db8423288847ecfb08469609a03Timo Sirainen if ((muser->fields & MAIL_LOG_FIELD_UID) != 0) {
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen mail_log_append_uid(ctx, msg, text, mail->uid);
afb7901ecb5d5566d4cf19be969654946fbaad4bTimo Sirainen /* with mbox mail->uid contains the uid, but handle
afb7901ecb5d5566d4cf19be969654946fbaad4bTimo Sirainen this consistently with all mailbox formats */
5b79409cf50bf77dcb23083e69e04afc310c7f64Timo Sirainen /* make sure UID is assigned to this mail */
5b79409cf50bf77dcb23083e69e04afc310c7f64Timo Sirainen mail->transaction->flags |= MAILBOX_TRANSACTION_FLAG_ASSIGN_UIDS;
b66412da78711db8423288847ecfb08469609a03Timo Sirainen if ((muser->fields & MAIL_LOG_FIELD_MSGID) != 0) {
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen mail_log_append_mail_header(text, mail, "msgid", "Message-ID");
b66412da78711db8423288847ecfb08469609a03Timo Sirainen if ((muser->fields & MAIL_LOG_FIELD_PSIZE) != 0) {
b66412da78711db8423288847ecfb08469609a03Timo Sirainen if ((muser->fields & MAIL_LOG_FIELD_VSIZE) != 0) {
b66412da78711db8423288847ecfb08469609a03Timo Sirainen if ((muser->fields & MAIL_LOG_FIELD_FROM) != 0) {
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen mail_log_append_mail_header(text, mail, "from", "From");
b66412da78711db8423288847ecfb08469609a03Timo Sirainen if ((muser->fields & MAIL_LOG_FIELD_SUBJECT) != 0) {
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen mail_log_append_mail_header(text, mail, "subject", "Subject");
b66412da78711db8423288847ecfb08469609a03Timo Sirainen if ((muser->fields & MAIL_LOG_FIELD_FLAGS) != 0) {
afb7901ecb5d5566d4cf19be969654946fbaad4bTimo Sirainen DLLIST2_APPEND(&ctx->messages, &ctx->messages_tail, msg);
d6cc34b076dced6ebf8af47d72c8242357288312Timo Sirainenstatic void mail_log_add_dummy_msg(struct mail_log_mail_txn_context *ctx,
d6cc34b076dced6ebf8af47d72c8242357288312Timo Sirainen msg = p_new(ctx->pool, struct mail_log_message, 1);
d6cc34b076dced6ebf8af47d72c8242357288312Timo Sirainen DLLIST2_APPEND(&ctx->messages, &ctx->messages_tail, msg);
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainenmail_log_append_mail_message(struct mail_log_mail_txn_context *ctx,
b66412da78711db8423288847ecfb08469609a03Timo Sirainen MAIL_LOG_USER_CONTEXT(mail->box->storage->user);
86448bdb60ed69566bc1093dda824133448ed7a0Timo Sirainen enum mail_lookup_abort orig_lookup_abort = mail->lookup_abort;
86448bdb60ed69566bc1093dda824133448ed7a0Timo Sirainen if (event != MAIL_LOG_EVENT_SAVE && muser->cached_only)
86448bdb60ed69566bc1093dda824133448ed7a0Timo Sirainen mail->lookup_abort = MAIL_LOOKUP_ABORT_NOT_IN_CACHE;
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen mail_log_append_mail_message_real(ctx, mail, event, desc);
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainenmail_log_mail_transaction_begin(struct mailbox_transaction_context *t ATTR_UNUSED)
901d0f036826476cf75799a0fdda5777e51301e4Timo Sirainen pool = pool_alloconly_create("mail-log", 2048);
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen ctx = p_new(pool, struct mail_log_mail_txn_context, 1);
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainenstatic void mail_log_mail_save(void *txn, struct mail *mail)
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen mail_log_append_mail_message(ctx, mail, MAIL_LOG_EVENT_SAVE, "save");
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainenstatic void mail_log_mail_copy(void *txn, struct mail *src, struct mail *dst)
13e130c3af3032982de6b1d13c6dcddda9164848Timo Sirainen struct mail_private *src_pmail = (struct mail_private *)src;
13e130c3af3032982de6b1d13c6dcddda9164848Timo Sirainen /* copying a mail from virtual storage. src points to the
13e130c3af3032982de6b1d13c6dcddda9164848Timo Sirainen backend mail, but we want to log the virtual mailbox name. */
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainenstatic void mail_log_mail_expunge(void *txn, struct mail *mail)
7f3fe26555d38209e4072eaee4ac56e912733c25Aki Tuomi struct mail_private *p = (struct mail_private*)mail;
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen mail_log_append_mail_message(ctx, mail, MAIL_LOG_EVENT_EXPUNGE,
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainenstatic void mail_log_mail_update_flags(void *txn, struct mail *mail,
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen enum mail_flags new_flags = mail_get_flags(mail);
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen if (((old_flags ^ new_flags) & MAIL_DELETED) == 0) {
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen "flag_change");
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen mail_log_append_mail_message(ctx, mail, MAIL_LOG_EVENT_DELETE,
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen mail_log_append_mail_message(ctx, mail, MAIL_LOG_EVENT_UNDELETE,
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainenmail_log_mail_update_keywords(void *txn, struct mail *mail,
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen mail_log_append_mail_message(ctx, mail, MAIL_LOG_EVENT_FLAG_CHANGE,
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen "flag_change");
d6cc34b076dced6ebf8af47d72c8242357288312Timo Sirainenstatic void mail_log_save(const struct mail_log_message *msg, uint32_t uid)
d6cc34b076dced6ebf8af47d72c8242357288312Timo Sirainen /* not logging this save/copy */
d6cc34b076dced6ebf8af47d72c8242357288312Timo Sirainen else if (uid != 0)
d6cc34b076dced6ebf8af47d72c8242357288312Timo Sirainen i_info("%s%u%s", msg->pretext, uid, msg->text);
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen struct mail_transaction_commit_changes *changes)
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen unsigned int n = 0;
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen seq_range_array_iter_init(&iter, &changes->saved_uids);
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen for (msg = ctx->messages; msg != NULL; msg = msg->next) {
d6cc34b076dced6ebf8af47d72c8242357288312Timo Sirainen if (!seq_range_array_iter_nth(&iter, n++, &uid))
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen i_assert(!seq_range_array_iter_nth(&iter, n, &uid));
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainenstatic void mail_log_mail_transaction_rollback(void *txn)
4babe70b863c71ea330cbf32ac0b71876f4f9137Timo Sirainen struct mail_log_user *muser = MAIL_LOG_USER_CONTEXT(box->storage->user);
4babe70b863c71ea330cbf32ac0b71876f4f9137Timo Sirainen if ((muser->events & MAIL_LOG_EVENT_MAILBOX_CREATE) == 0)
bfe4a97ad6731012202b830c1219a4c10f91d72cTimo Sirainen str_sanitize(mailbox_get_vname(box), MAILBOX_NAME_LOG_LEN));
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainenmail_log_mailbox_delete_commit(void *txn ATTR_UNUSED, struct mailbox *box)
b66412da78711db8423288847ecfb08469609a03Timo Sirainen struct mail_log_user *muser = MAIL_LOG_USER_CONTEXT(box->storage->user);
b66412da78711db8423288847ecfb08469609a03Timo Sirainen if ((muser->events & MAIL_LOG_EVENT_MAILBOX_DELETE) == 0)
bfe4a97ad6731012202b830c1219a4c10f91d72cTimo Sirainen str_sanitize(mailbox_get_vname(box), MAILBOX_NAME_LOG_LEN));
71e88fae3be360e9a93b3398e743f99a6f05d2edTimo Sirainenmail_log_mailbox_rename(struct mailbox *src, struct mailbox *dest)
b66412da78711db8423288847ecfb08469609a03Timo Sirainen struct mail_log_user *muser = MAIL_LOG_USER_CONTEXT(src->storage->user);
b66412da78711db8423288847ecfb08469609a03Timo Sirainen if ((muser->events & MAIL_LOG_EVENT_MAILBOX_RENAME) == 0)
bfe4a97ad6731012202b830c1219a4c10f91d72cTimo Sirainen str_sanitize(mailbox_get_vname(src), MAILBOX_NAME_LOG_LEN),
bfe4a97ad6731012202b830c1219a4c10f91d72cTimo Sirainen str_sanitize(mailbox_get_vname(dest), MAILBOX_NAME_LOG_LEN));
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainenstatic const struct notify_vfuncs mail_log_vfuncs = {
f60ed9d5330a6167693b047d8138769fb596d41cTimo Sirainen .mail_transaction_begin = mail_log_mail_transaction_begin,
f60ed9d5330a6167693b047d8138769fb596d41cTimo Sirainen .mail_update_flags = mail_log_mail_update_flags,
f60ed9d5330a6167693b047d8138769fb596d41cTimo Sirainen .mail_update_keywords = mail_log_mail_update_keywords,
f60ed9d5330a6167693b047d8138769fb596d41cTimo Sirainen .mail_transaction_commit = mail_log_mail_transaction_commit,
f60ed9d5330a6167693b047d8138769fb596d41cTimo Sirainen .mail_transaction_rollback = mail_log_mail_transaction_rollback,
f60ed9d5330a6167693b047d8138769fb596d41cTimo Sirainen .mailbox_delete_commit = mail_log_mailbox_delete_commit,
b66412da78711db8423288847ecfb08469609a03Timo Sirainenstatic struct mail_storage_hooks mail_log_mail_storage_hooks = {
b66412da78711db8423288847ecfb08469609a03Timo Sirainen .mail_user_created = mail_log_mail_user_created
b66412da78711db8423288847ecfb08469609a03Timo Sirainenvoid mail_log_plugin_init(struct module *module)
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen mail_log_ctx = notify_register(&mail_log_vfuncs);
b66412da78711db8423288847ecfb08469609a03Timo Sirainen mail_storage_hooks_add(module, &mail_log_mail_storage_hooks);
b66412da78711db8423288847ecfb08469609a03Timo Sirainen mail_storage_hooks_remove(&mail_log_mail_storage_hooks);
23fdad6c7e2581921f511e24cd9371c9eaebcef9Timo Sirainenconst char *mail_log_plugin_dependencies[] = { "notify", NULL };