# HG changeset patch # User Timo Sirainen # Date 1431509042 -10800 # Node ID f5749f22276b0b1a6741c1ce5c617e93bcae66cc # Parent 69dcc2c8cd9df65f39f4a516cd7050c7e3303d02 Added quota-clone plugin. diff -r 69dcc2c8cd9d -r f5749f22276b NEWS --- a/NEWS Wed May 13 05:34:16 2015 +0300 +++ b/NEWS Wed May 13 12:24:02 2015 +0300 @@ -34,6 +34,7 @@ -A parameter reading the list of users from userdb lookup. + Implemented initial Cassandra CQL support as lib-sql backend. It's only usable as dict backend currently. + + Added quota-clone plugin to copy current quota usage to a dict. - auth: If auth_master_user_separator was set, auth process could be crashed by trying to log in with empty master username. - imap-login, pop3-login: Fixed crash on handshake failures with new diff -r 69dcc2c8cd9d -r f5749f22276b configure.ac --- a/configure.ac Wed May 13 05:34:16 2015 +0300 +++ b/configure.ac Wed May 13 12:24:02 2015 +0300 @@ -2991,6 +2991,7 @@ src/plugins/notify/Makefile src/plugins/pop3-migration/Makefile src/plugins/quota/Makefile +src/plugins/quota-clone/Makefile src/plugins/imap-quota/Makefile src/plugins/replication/Makefile src/plugins/snarf/Makefile diff -r 69dcc2c8cd9d -r f5749f22276b src/plugins/Makefile.am --- a/src/plugins/Makefile.am Wed May 13 05:34:16 2015 +0300 +++ b/src/plugins/Makefile.am Wed May 13 12:24:02 2015 +0300 @@ -25,6 +25,7 @@ mail-log \ mailbox-alias \ quota \ + quota-clone \ imap-quota \ pop3-migration \ replication \ diff -r 69dcc2c8cd9d -r f5749f22276b src/plugins/quota-clone/Makefile.am --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/plugins/quota-clone/Makefile.am Wed May 13 12:24:02 2015 +0300 @@ -0,0 +1,19 @@ +AM_CPPFLAGS = \ + -I$(top_srcdir)/src/lib \ + -I$(top_srcdir)/src/lib-dict \ + -I$(top_srcdir)/src/lib-mail \ + -I$(top_srcdir)/src/lib-index \ + -I$(top_srcdir)/src/lib-storage \ + -I$(top_srcdir)/src/plugins/quota + +NOPLUGIN_LDFLAGS = +lib20_quota_clone_plugin_la_LDFLAGS = -module -avoid-version + +module_LTLIBRARIES = \ + lib20_quota_clone_plugin.la + +lib20_quota_clone_plugin_la_SOURCES = \ + quota-clone-plugin.c + +noinst_HEADERS = \ + quota-clone-plugin.h diff -r 69dcc2c8cd9d -r f5749f22276b src/plugins/quota-clone/quota-clone-plugin.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/plugins/quota-clone/quota-clone-plugin.c Wed May 13 12:24:02 2015 +0300 @@ -0,0 +1,197 @@ +/* Copyright (c) 2015 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "module-context.h" +#include "dict.h" +#include "mail-storage-private.h" +#include "quota.h" +#include "quota-clone-plugin.h" + +#define DICT_QUOTA_CLONE_PATH DICT_PATH_PRIVATE"quota/" +#define DICT_QUOTA_CLONE_BYTES_PATH DICT_QUOTA_CLONE_PATH"storage" +#define DICT_QUOTA_CLONE_COUNT_PATH DICT_QUOTA_CLONE_PATH"messages" + +#define QUOTA_CLONE_USER_CONTEXT(obj) \ + MODULE_CONTEXT(obj, quota_clone_user_module) +#define QUOTA_CLONE_CONTEXT(obj) \ + MODULE_CONTEXT(obj, quota_clone_storage_module) + +static MODULE_CONTEXT_DEFINE_INIT(quota_clone_user_module, + &mail_user_module_register); +static MODULE_CONTEXT_DEFINE_INIT(quota_clone_storage_module, + &mail_storage_module_register); + +struct quota_clone_user { + union mail_user_module_context module_ctx; + struct dict *dict; +}; + +struct quota_clone_mailbox { + union mailbox_module_context module_ctx; + bool quota_changed; +}; + +static void quota_clone_flush(struct mailbox *box) +{ + struct quota_clone_mailbox *qbox = QUOTA_CLONE_CONTEXT(box); + struct quota_clone_user *quser = + QUOTA_CLONE_USER_CONTEXT(box->storage->user); + struct dict_transaction_context *trans; + struct quota_root_iter *iter; + struct quota_root *root; + uint64_t value, limit; + int ret; + + /* we'll clone the first quota root */ + iter = quota_root_iter_init(box); + root = quota_root_iter_next(iter); + if (root == NULL) { + /* no quota roots defined for this mailbox - ignore */ + qbox->quota_changed = FALSE; + return; + } + quota_root_iter_deinit(&iter); + + trans = dict_transaction_begin(quser->dict); + /* update bytes */ + ret = quota_get_resource(root, "", QUOTA_NAME_STORAGE_BYTES, + &value, &limit); + if (ret < 0) + i_error("quota_clone_plugin: Failed to lookup current quota bytes"); + else { + dict_set(trans, DICT_QUOTA_CLONE_BYTES_PATH, + t_strdup_printf("%llu", (unsigned long long)value)); + } + /* update messages */ + ret = quota_get_resource(root, "", QUOTA_NAME_MESSAGES, + &value, &limit); + if (ret < 0) + i_error("quota_clone_plugin: Failed to lookup current quota count"); + else { + dict_set(trans, DICT_QUOTA_CLONE_COUNT_PATH, + t_strdup_printf("%llu", (unsigned long long)value)); + } + if (dict_transaction_commit(&trans) < 0) + i_error("quota_clone_plugin: Failed to commit dict update"); + else + qbox->quota_changed = FALSE; +} + +static int quota_clone_save_finish(struct mail_save_context *ctx) +{ + struct quota_clone_mailbox *qbox = + QUOTA_CLONE_CONTEXT(ctx->transaction->box); + + qbox->quota_changed = TRUE; + return qbox->module_ctx.super.save_finish(ctx); +} + +static int +quota_clone_copy(struct mail_save_context *ctx, struct mail *mail) +{ + struct quota_clone_mailbox *qbox = + QUOTA_CLONE_CONTEXT(ctx->transaction->box); + + qbox->quota_changed = TRUE; + return qbox->module_ctx.super.copy(ctx, mail); +} + +static void +quota_clone_mailbox_sync_notify(struct mailbox *box, uint32_t uid, + enum mailbox_sync_type sync_type) +{ + struct quota_clone_mailbox *qbox = QUOTA_CLONE_CONTEXT(box); + + if (qbox->module_ctx.super.sync_notify != NULL) + qbox->module_ctx.super.sync_notify(box, uid, sync_type); + + if (sync_type == MAILBOX_SYNC_TYPE_EXPUNGE) + qbox->quota_changed = TRUE; +} + +static void quota_clone_mailbox_close(struct mailbox *box) +{ + struct quota_clone_mailbox *qbox = QUOTA_CLONE_CONTEXT(box); + + qbox->module_ctx.super.close(box); + if (qbox->quota_changed) + quota_clone_flush(box); +} + +static void quota_clone_mailbox_allocated(struct mailbox *box) +{ + struct quota_clone_user *quser = + QUOTA_CLONE_USER_CONTEXT(box->storage->user); + struct mailbox_vfuncs *v = box->vlast; + struct quota_clone_mailbox *qbox; + + if (quser == NULL) + return; + + qbox = p_new(box->pool, struct quota_clone_mailbox, 1); + qbox->module_ctx.super = *v; + box->vlast = &qbox->module_ctx.super; + + v->save_finish = quota_clone_save_finish; + v->copy = quota_clone_copy; + v->sync_notify = quota_clone_mailbox_sync_notify; + v->close = quota_clone_mailbox_close; + MODULE_CONTEXT_SET(box, quota_clone_storage_module, qbox); +} + +static void quota_clone_mail_user_deinit(struct mail_user *user) +{ + struct quota_clone_user *quser = QUOTA_CLONE_USER_CONTEXT(user); + + dict_deinit(&quser->dict); + quser->module_ctx.super.deinit(user); +} + +static void quota_clone_mail_user_created(struct mail_user *user) +{ + struct quota_clone_user *quser; + struct mail_user_vfuncs *v = user->vlast; + struct dict_settings dict_set; + struct dict *dict; + const char *uri, *error; + + uri = mail_user_plugin_getenv(user, "quota_clone_dict"); + if (uri == NULL || uri[0] == '\0') { + i_error("The quota_clone_dict setting is missing from configuration"); + return; + } + + memset(&dict_set, 0, sizeof(dict_set)); + dict_set.username = user->username; + dict_set.base_dir = user->set->base_dir; + (void)mail_user_get_home(user, &dict_set.home_dir); + if (dict_init_full(uri, &dict_set, &dict, &error) < 0) { + i_error("quota_clone_dict: Failed to initialize '%s': %s", + uri, error); + return; + } + + quser = p_new(user->pool, struct quota_clone_user, 1); + quser->module_ctx.super = *v; + user->vlast = &quser->module_ctx.super; + v->deinit = quota_clone_mail_user_deinit; + quser->dict = dict; + MODULE_CONTEXT_SET(user, quota_clone_user_module, quser); +} + +static struct mail_storage_hooks quota_clone_mail_storage_hooks = { + .mailbox_allocated = quota_clone_mailbox_allocated, + .mail_user_created = quota_clone_mail_user_created +}; + +void quota_clone_plugin_init(struct module *module ATTR_UNUSED) +{ + mail_storage_hooks_add(module, "a_clone_mail_storage_hooks); +} + +void quota_clone_plugin_deinit(void) +{ + mail_storage_hooks_remove("a_clone_mail_storage_hooks); +} + +const char *quota_clone_plugin_dependencies[] = { "quota", NULL }; diff -r 69dcc2c8cd9d -r f5749f22276b src/plugins/quota-clone/quota-clone-plugin.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/plugins/quota-clone/quota-clone-plugin.h Wed May 13 12:24:02 2015 +0300 @@ -0,0 +1,7 @@ +#ifndef QUOTA_CLONE_PLUGIN_H +#define QUOTA_CLONE_PLUGIN_H + +void quota_clone_plugin_init(struct module *module); +void quota_clone_plugin_deinit(void); + +#endif