mail-log-plugin.c revision bfe4a97ad6731012202b830c1219a4c10f91d72c
2454dfa32c93c20a8522c6ed42fe057baaac9f9aStephan Bosch/* Copyright (c) 2007-2012 Dovecot authors, see the included COPYING file */
c5e62353a11087958ea4e619660e084a613e1a37Timo Sirainen (MAIL_LOG_EVENT_DELETE | MAIL_LOG_EVENT_UNDELETE | \
c5e62353a11087958ea4e619660e084a613e1a37Timo Sirainen MAIL_LOG_EVENT_EXPUNGE | MAIL_LOG_EVENT_SAVE | MAIL_LOG_EVENT_COPY | \
c5e62353a11087958ea4e619660e084a613e1a37Timo Sirainen MAIL_LOG_EVENT_MAILBOX_DELETE | MAIL_LOG_EVENT_MAILBOX_RENAME)
9132f9df4e12ed5293c70957813aa3736444a13cTimo Sirainenstatic const char *field_names[] = {
c5e62353a11087958ea4e619660e084a613e1a37Timo Sirainenstatic const char *event_names[] = {
c5e62353a11087958ea4e619660e084a613e1a37Timo Sirainen "mailbox_create",
c5e62353a11087958ea4e619660e084a613e1a37Timo Sirainen "mailbox_delete",
c5e62353a11087958ea4e619660e084a613e1a37Timo Sirainen "mailbox_rename",
c5e62353a11087958ea4e619660e084a613e1a37Timo Sirainen "flag_change",
7a94f950fd1dcc81537acfc8adb030b5e703d722Timo Sirainen struct mail_log_message *messages, *messages_tail;
7a94f950fd1dcc81537acfc8adb030b5e703d722Timo Sirainenstatic MODULE_CONTEXT_DEFINE_INIT(mail_log_user_module,
7a94f950fd1dcc81537acfc8adb030b5e703d722Timo Sirainenstatic enum mail_log_field mail_log_field_find(const char *name)
7a94f950fd1dcc81537acfc8adb030b5e703d722Timo Sirainen unsigned int i;
7a94f950fd1dcc81537acfc8adb030b5e703d722Timo Sirainen return 1 << i;
2b96880f2d789d125aff6a95eaa7b51f558a6a1cTimo Sirainenstatic enum mail_log_event mail_log_event_find(const char *name)
7a94f950fd1dcc81537acfc8adb030b5e703d722Timo Sirainen unsigned int i;
7a94f950fd1dcc81537acfc8adb030b5e703d722Timo Sirainen /* v1.x backwards compatibility */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return 1 << i;
baebb412a9a5a44b1756e01cfa3b99f5d8a846b6Timo Sirainenstatic enum mail_log_field mail_log_parse_fields(const char *str)
baebb412a9a5a44b1756e01cfa3b99f5d8a846b6Timo Sirainen const char *const *tmp;
baebb412a9a5a44b1756e01cfa3b99f5d8a846b6Timo Sirainen for (tmp = t_strsplit_spaces(str, ", "); *tmp != NULL; tmp++) {
12c6ef6f1268ed4d5b63709bb4215c481b4f078cTimo Sirainen i_fatal("Unknown field in mail_log_fields: '%s'", *tmp);
12c6ef6f1268ed4d5b63709bb4215c481b4f078cTimo Sirainenstatic enum mail_log_event mail_log_parse_events(const char *str)
12c6ef6f1268ed4d5b63709bb4215c481b4f078cTimo Sirainen const char *const *tmp;
12c6ef6f1268ed4d5b63709bb4215c481b4f078cTimo Sirainen for (tmp = t_strsplit_spaces(str, ", "); *tmp != NULL; tmp++) {
12c6ef6f1268ed4d5b63709bb4215c481b4f078cTimo Sirainen i_fatal("Unknown event in mail_log_events: '%s'", *tmp);
12c6ef6f1268ed4d5b63709bb4215c481b4f078cTimo Sirainenstatic void mail_log_mail_user_created(struct mail_user *user)
f059a046515f4b2b15a6c2a10a6f12f6166e39a5Timo Sirainen const char *str;
66ea9eaaa2d7531b3be8f633937628c94d907031Timo Sirainen muser = p_new(user->pool, struct mail_log_user, 1);
66ea9eaaa2d7531b3be8f633937628c94d907031Timo Sirainen MODULE_CONTEXT_SET(user, mail_log_user_module, muser);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen str = mail_user_plugin_getenv(user, "mail_log_fields");
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen muser->fields = str == NULL ? MAIL_LOG_DEFAULT_FIELDS :
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen str = mail_user_plugin_getenv(user, "mail_log_events");
5a250816ffc4cc5db203f9410ea99b6601c7b91aTimo Sirainen muser->events = str == NULL ? MAIL_LOG_DEFAULT_EVENTS :
46ec792dd4ccf6c34706c4774228301fafde6aa9Timo Sirainenstatic void mail_log_append_mailbox_name(string_t *str, struct mail *mail)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen str_sanitize(mailbox_str, MAILBOX_NAME_LOG_LEN));
9132f9df4e12ed5293c70957813aa3736444a13cTimo Sirainenmail_log_append_mail_header(string_t *str, struct mail *mail,
a05fec120ecd8c4ed6331c42100cba42adf22893Stephan Bosch if (mail_get_first_header(mail, header, &value) <= 0)
a05fec120ecd8c4ed6331c42100cba42adf22893Stephan Bosch str_printfa(str, "%s=%s", name, str_sanitize(value, HEADER_LOG_LEN));
c12d96f12cac9af464ab2e59046bd59b0c06b4eaTimo Sirainenmail_log_append_uid(struct mail_log_mail_txn_context *ctx,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen struct mail_log_message *msg, string_t *str, uint32_t uid)
b6fbc235f981b10333403e2fd6d333fd351c7a3cAki Tuomi /* we don't know the uid yet, assign it later */
be6e55ff7c81afdc7ed9b47c6021a4f7827e4407Timo Sirainen msg->pretext = p_strdup(ctx->pool, str_c(str));
66ea9eaaa2d7531b3be8f633937628c94d907031Timo Sirainenmail_log_update_wanted_fields(struct mail *mail, enum mail_log_field fields)
66ea9eaaa2d7531b3be8f633937628c94d907031Timo Sirainen struct mailbox_header_lookup_ctx *wanted_headers = NULL;
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen unsigned int hdr_idx = 0;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen wanted_headers = mailbox_header_lookup_init(mail->box, headers);
ad004e44be109684521494b5af2ad1da39b8bb27Timo Sirainen mail_add_temp_wanted_fields(mail, wanted_fields, wanted_headers);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenmail_log_append_mail_message_real(struct mail_log_mail_txn_context *ctx,
1a1159e589def1e32b7dc25397f15146672ef73eTimo Sirainen MAIL_LOG_USER_CONTEXT(mail->box->storage->user);
56af9dd10e7e6caeaca64395bad3f882b28ecdffTimo Sirainen msg = p_new(ctx->pool, struct mail_log_message, 1);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* avoid parsing through the message multiple times */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen mail_log_update_wanted_fields(mail, muser->fields);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if ((muser->fields & MAIL_LOG_FIELD_BOX) != 0) {
87dbf3e85526ccde5908a611eb9a798f1d0ccac3Timo Sirainen if ((muser->fields & MAIL_LOG_FIELD_UID) != 0) {
87dbf3e85526ccde5908a611eb9a798f1d0ccac3Timo Sirainen mail_log_append_uid(ctx, msg, text, mail->uid);
1312cf655d3ea22c0ab6487ce710ad4060c25905Timo Sirainen /* with mbox mail->uid contains the uid, but handle
1312cf655d3ea22c0ab6487ce710ad4060c25905Timo Sirainen this consistently with all mailbox formats */
a7efba62b6235e5efc124cbf702ddeb547ca3665Timo Sirainen if ((muser->fields & MAIL_LOG_FIELD_MSGID) != 0) {
a7efba62b6235e5efc124cbf702ddeb547ca3665Timo Sirainen mail_log_append_mail_header(text, mail, "msgid", "Message-ID");
a7efba62b6235e5efc124cbf702ddeb547ca3665Timo Sirainen if ((muser->fields & MAIL_LOG_FIELD_PSIZE) != 0) {
c7fca6cbb32388556d9f6d8313486cc4e4a3c058Timo Sirainen if ((muser->fields & MAIL_LOG_FIELD_VSIZE) != 0) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if ((muser->fields & MAIL_LOG_FIELD_FROM) != 0) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen mail_log_append_mail_header(text, mail, "from", "From");
0d1b8b6bec79746c5d89d57dd8c1688946bd9237Josef 'Jeff' Sipek if ((muser->fields & MAIL_LOG_FIELD_SUBJECT) != 0) {
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen mail_log_append_mail_header(text, mail, "subject", "Subject");
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if ((muser->fields & MAIL_LOG_FIELD_FLAGS) != 0) {
ab90f702ceedb7ba445a9a592be0b213b27cbafaStephan Bosch DLLIST2_APPEND(&ctx->messages, &ctx->messages_tail, msg);
4de2a17e0a2aed3b57a6c1057329b6a132b56ae2Timo Sirainenstatic void mail_log_add_dummy_msg(struct mail_log_mail_txn_context *ctx,
9ddd3d7d8651985e373a6c48e0ddc76b8a4ef1c7Timo Sirainen msg = p_new(ctx->pool, struct mail_log_message, 1);
54533aa265f5c87730022cc7576090bc51370f97Timo Sirainen DLLIST2_APPEND(&ctx->messages, &ctx->messages_tail, msg);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenmail_log_append_mail_message(struct mail_log_mail_txn_context *ctx,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen MAIL_LOG_USER_CONTEXT(mail->box->storage->user);
b833824981bc75af72adb844f8a4a992bd2f3ad3Timo Sirainen mail_log_append_mail_message_real(ctx, mail, event, desc);
66ea9eaaa2d7531b3be8f633937628c94d907031Timo Sirainenmail_log_mail_transaction_begin(struct mailbox_transaction_context *t ATTR_UNUSED)
66ea9eaaa2d7531b3be8f633937628c94d907031Timo Sirainen pool = pool_alloconly_create("mail-log", 2048);
66ea9eaaa2d7531b3be8f633937628c94d907031Timo Sirainen ctx = p_new(pool, struct mail_log_mail_txn_context, 1);
b84eff65e25ae86dfd6f798386577209b94838c6Timo Sirainenstatic void mail_log_mail_save(void *txn, struct mail *mail)
87dbf3e85526ccde5908a611eb9a798f1d0ccac3Timo Sirainen mail_log_append_mail_message(ctx, mail, MAIL_LOG_EVENT_SAVE, "save");
a7efba62b6235e5efc124cbf702ddeb547ca3665Timo Sirainenstatic void mail_log_mail_copy(void *txn, struct mail *src, struct mail *dst)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstatic void mail_log_mail_expunge(void *txn, struct mail *mail)
54533aa265f5c87730022cc7576090bc51370f97Timo Sirainen mail_log_append_mail_message(ctx, mail, MAIL_LOG_EVENT_EXPUNGE,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstatic void mail_log_mail_update_flags(void *txn, struct mail *mail,
b84eff65e25ae86dfd6f798386577209b94838c6Timo Sirainen enum mail_flags new_flags = mail_get_flags(mail);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (((old_flags ^ new_flags) & MAIL_DELETED) == 0) {
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen "flag_change");
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen mail_log_append_mail_message(ctx, mail, MAIL_LOG_EVENT_DELETE,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen mail_log_append_mail_message(ctx, mail, MAIL_LOG_EVENT_UNDELETE,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenmail_log_mail_update_keywords(void *txn, struct mail *mail,
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen mail_log_append_mail_message(ctx, mail, MAIL_LOG_EVENT_FLAG_CHANGE,
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen "flag_change");
717bb0dbaf4bd3f745669570647845e6d493bfe0Timo Sirainenstatic void mail_log_save(const struct mail_log_message *msg, uint32_t uid)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* not logging this save/copy */
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen else if (uid != 0)
73f021723bffa0841bbdf371882b463a449f1ea9Timo Sirainen i_info("%s%u%s", msg->pretext, uid, msg->text);
717bb0dbaf4bd3f745669570647845e6d493bfe0Timo Sirainen struct mail_transaction_commit_changes *changes)
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen unsigned int n = 0;
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen seq_range_array_iter_init(&iter, &changes->saved_uids);
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen for (msg = ctx->messages; msg != NULL; msg = msg->next) {
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen if (!seq_range_array_iter_nth(&iter, n++, &uid))
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen i_assert(!seq_range_array_iter_nth(&iter, n, &uid));
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainenstatic void mail_log_mail_transaction_rollback(void *txn)
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen struct mail_log_user *muser = MAIL_LOG_USER_CONTEXT(box->storage->user);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if ((muser->events & MAIL_LOG_EVENT_MAILBOX_CREATE) == 0)
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen str_sanitize(mailbox_get_vname(box), MAILBOX_NAME_LOG_LEN));
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainenmail_log_mailbox_delete_commit(void *txn ATTR_UNUSED, struct mailbox *box)
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen struct mail_log_user *muser = MAIL_LOG_USER_CONTEXT(box->storage->user);
b1485f2691de41ed7b5f96cebda2ebcb69a5e22fTimo Sirainen if ((muser->events & MAIL_LOG_EVENT_MAILBOX_DELETE) == 0)
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen str_sanitize(mailbox_get_vname(box), MAILBOX_NAME_LOG_LEN));
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen struct mailbox *dest, bool rename_children ATTR_UNUSED)
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen struct mail_log_user *muser = MAIL_LOG_USER_CONTEXT(src->storage->user);
b1485f2691de41ed7b5f96cebda2ebcb69a5e22fTimo Sirainen if ((muser->events & MAIL_LOG_EVENT_MAILBOX_RENAME) == 0)
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen str_sanitize(mailbox_get_vname(src), MAILBOX_NAME_LOG_LEN),
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen str_sanitize(mailbox_get_vname(dest), MAILBOX_NAME_LOG_LEN));
a1852ab4cf0a942a3fcf4ca5636a7932ebcc7970Stephan Boschstatic const struct notify_vfuncs mail_log_vfuncs = {
a1852ab4cf0a942a3fcf4ca5636a7932ebcc7970Stephan Bosch .mail_transaction_begin = mail_log_mail_transaction_begin,
b1485f2691de41ed7b5f96cebda2ebcb69a5e22fTimo Sirainen .mail_update_flags = mail_log_mail_update_flags,
b1485f2691de41ed7b5f96cebda2ebcb69a5e22fTimo Sirainen .mail_update_keywords = mail_log_mail_update_keywords,
b1485f2691de41ed7b5f96cebda2ebcb69a5e22fTimo Sirainen .mail_transaction_commit = mail_log_mail_transaction_commit,
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen .mail_transaction_rollback = mail_log_mail_transaction_rollback,
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen .mailbox_delete_commit = mail_log_mailbox_delete_commit,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstatic struct mail_storage_hooks mail_log_mail_storage_hooks = {
54533aa265f5c87730022cc7576090bc51370f97Timo Sirainen .mail_user_created = mail_log_mail_user_created
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenvoid mail_log_plugin_init(struct module *module)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen mail_log_ctx = notify_register(&mail_log_vfuncs);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen mail_storage_hooks_add(module, &mail_log_mail_storage_hooks);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen mail_storage_hooks_remove(&mail_log_mail_storage_hooks);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenconst char *mail_log_plugin_dependencies[] = { "notify", NULL };