quota-clone-plugin.c revision 7ee626fd396f5549fb1fc6b0c320038638af9058
2454dfa32c93c20a8522c6ed42fe057baaac9f9aStephan Bosch/* Copyright (c) 2015-2017 Dovecot authors, see the included COPYING file */
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen#include "lib.h"
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen#include "module-context.h"
5de0c65da362236080fa699af3da03e45e480ab8Timo Sirainen#include "ioloop.h"
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen#include "dict.h"
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen#include "mail-storage-private.h"
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen#include "quota.h"
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen#include "quota-clone-plugin.h"
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen
5de0c65da362236080fa699af3da03e45e480ab8Timo Sirainen/* If mailbox is kept open for this many milliseconds after quota update,
5de0c65da362236080fa699af3da03e45e480ab8Timo Sirainen flush quota-clone. */
5de0c65da362236080fa699af3da03e45e480ab8Timo Sirainen#define QUOTA_CLONE_FLUSH_DELAY_MSECS (10*1000)
5de0c65da362236080fa699af3da03e45e480ab8Timo Sirainen
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen#define DICT_QUOTA_CLONE_PATH DICT_PATH_PRIVATE"quota/"
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen#define DICT_QUOTA_CLONE_BYTES_PATH DICT_QUOTA_CLONE_PATH"storage"
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen#define DICT_QUOTA_CLONE_COUNT_PATH DICT_QUOTA_CLONE_PATH"messages"
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen#define QUOTA_CLONE_USER_CONTEXT(obj) \
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen MODULE_CONTEXT(obj, quota_clone_user_module)
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen#define QUOTA_CLONE_CONTEXT(obj) \
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen MODULE_CONTEXT(obj, quota_clone_storage_module)
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainenstatic MODULE_CONTEXT_DEFINE_INIT(quota_clone_user_module,
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen &mail_user_module_register);
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainenstatic MODULE_CONTEXT_DEFINE_INIT(quota_clone_storage_module,
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen &mail_storage_module_register);
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainenstruct quota_clone_user {
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen union mail_user_module_context module_ctx;
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen struct dict *dict;
5da08ab71623953f248b24a21d45b02555bbb24bTimo Sirainen bool quota_flushing;
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen};
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainenstruct quota_clone_mailbox {
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen union mailbox_module_context module_ctx;
5de0c65da362236080fa699af3da03e45e480ab8Timo Sirainen struct timeout *to_quota_flush;
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen bool quota_changed;
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen};
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen
588a0579058849aed9f7b59d8259e0c58d9fd23cTimo Sirainenstatic void quota_clone_flush_real(struct mailbox *box)
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen{
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen struct quota_clone_mailbox *qbox = QUOTA_CLONE_CONTEXT(box);
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen struct quota_clone_user *quser =
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen QUOTA_CLONE_USER_CONTEXT(box->storage->user);
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen struct dict_transaction_context *trans;
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen struct quota_root_iter *iter;
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen struct quota_root *root;
d861bc0977b229cdaeb3fb77377e2a2bd9d40d3dTimo Sirainen uint64_t bytes_value, count_value, limit;
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainen const char *error;
bb11a1957aefbd2a2edf7ae25af4032899c34c41Martti Rannanjärvi enum quota_get_result bytes_res, count_res;
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen /* we'll clone the first quota root */
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen iter = quota_root_iter_init(box);
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen root = quota_root_iter_next(iter);
f39a06c378f6ea80a4ae9d257f0d79221a945a57Timo Sirainen quota_root_iter_deinit(&iter);
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen if (root == NULL) {
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen /* no quota roots defined for this mailbox - ignore */
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen qbox->quota_changed = FALSE;
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen return;
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen }
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen
d861bc0977b229cdaeb3fb77377e2a2bd9d40d3dTimo Sirainen /* get new values first */
bb11a1957aefbd2a2edf7ae25af4032899c34c41Martti Rannanjärvi bytes_res = quota_get_resource(root, "", QUOTA_NAME_STORAGE_BYTES,
cf41318871bd42358df3420e50614f5310b08c77Martti Rannanjärvi &bytes_value, &limit, &error);
bb11a1957aefbd2a2edf7ae25af4032899c34c41Martti Rannanjärvi if (bytes_res == QUOTA_GET_RESULT_INTERNAL_ERROR) {
cf41318871bd42358df3420e50614f5310b08c77Martti Rannanjärvi i_error("quota_clone_plugin: "
cf41318871bd42358df3420e50614f5310b08c77Martti Rannanjärvi "Failed to get quota resource "QUOTA_NAME_STORAGE_BYTES": %s",
cf41318871bd42358df3420e50614f5310b08c77Martti Rannanjärvi error);
d861bc0977b229cdaeb3fb77377e2a2bd9d40d3dTimo Sirainen return;
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen }
bb11a1957aefbd2a2edf7ae25af4032899c34c41Martti Rannanjärvi count_res = quota_get_resource(root, "", QUOTA_NAME_MESSAGES,
cf41318871bd42358df3420e50614f5310b08c77Martti Rannanjärvi &count_value, &limit, &error);
bb11a1957aefbd2a2edf7ae25af4032899c34c41Martti Rannanjärvi if (count_res == QUOTA_GET_RESULT_INTERNAL_ERROR) {
cf41318871bd42358df3420e50614f5310b08c77Martti Rannanjärvi i_error("quota_clone_plugin: "
cf41318871bd42358df3420e50614f5310b08c77Martti Rannanjärvi "Failed to get quota resource "QUOTA_NAME_MESSAGES": %s",
cf41318871bd42358df3420e50614f5310b08c77Martti Rannanjärvi error);
d861bc0977b229cdaeb3fb77377e2a2bd9d40d3dTimo Sirainen return;
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen }
bb11a1957aefbd2a2edf7ae25af4032899c34c41Martti Rannanjärvi if (bytes_res == QUOTA_GET_RESULT_UNKNOWN_RESOURCE &&
bb11a1957aefbd2a2edf7ae25af4032899c34c41Martti Rannanjärvi count_res == QUOTA_GET_RESULT_UNKNOWN_RESOURCE) {
2e07e3182f355cf04a1461dd7f893d0ebc818764Timo Sirainen /* quota resources don't exist - no point in updating it */
a022e47f45597650f71f00c3af3fa783982a65adTimo Sirainen return;
a022e47f45597650f71f00c3af3fa783982a65adTimo Sirainen }
7ee626fd396f5549fb1fc6b0c320038638af9058Martti Rannanjärvi if (bytes_res == QUOTA_GET_RESULT_BACKGROUND_CALC &&
7ee626fd396f5549fb1fc6b0c320038638af9058Martti Rannanjärvi count_res == QUOTA_GET_RESULT_BACKGROUND_CALC) {
7ee626fd396f5549fb1fc6b0c320038638af9058Martti Rannanjärvi /* Blocked by an ongoing quota calculation - try again later */
7ee626fd396f5549fb1fc6b0c320038638af9058Martti Rannanjärvi return;
7ee626fd396f5549fb1fc6b0c320038638af9058Martti Rannanjärvi }
d861bc0977b229cdaeb3fb77377e2a2bd9d40d3dTimo Sirainen
bb11a1957aefbd2a2edf7ae25af4032899c34c41Martti Rannanjärvi /* Then update the resources that exist. The resources' existence can't
a022e47f45597650f71f00c3af3fa783982a65adTimo Sirainen change unless the quota backend is changed, so we don't worry about
bb11a1957aefbd2a2edf7ae25af4032899c34c41Martti Rannanjärvi the special case of lookup changing from
bb11a1957aefbd2a2edf7ae25af4032899c34c41Martti Rannanjärvi RESULT_LIMITED/RESULT_UNLIMITED to RESULT_UNKNOWN_RESOURCE, which
bb11a1957aefbd2a2edf7ae25af4032899c34c41Martti Rannanjärvi leaves the old value unchanged. */
d861bc0977b229cdaeb3fb77377e2a2bd9d40d3dTimo Sirainen trans = dict_transaction_begin(quser->dict);
bb11a1957aefbd2a2edf7ae25af4032899c34c41Martti Rannanjärvi if (bytes_res == QUOTA_GET_RESULT_LIMITED ||
bb11a1957aefbd2a2edf7ae25af4032899c34c41Martti Rannanjärvi bytes_res == QUOTA_GET_RESULT_UNLIMITED) {
a022e47f45597650f71f00c3af3fa783982a65adTimo Sirainen dict_set(trans, DICT_QUOTA_CLONE_BYTES_PATH,
47a5a7e8296f3b8f2fac9a0659d4de3f2723ba4aMartti Rannanjärvi t_strdup_printf("%"PRIu64, bytes_value));
a022e47f45597650f71f00c3af3fa783982a65adTimo Sirainen }
bb11a1957aefbd2a2edf7ae25af4032899c34c41Martti Rannanjärvi if (count_res == QUOTA_GET_RESULT_LIMITED ||
bb11a1957aefbd2a2edf7ae25af4032899c34c41Martti Rannanjärvi count_res == QUOTA_GET_RESULT_UNLIMITED) {
a022e47f45597650f71f00c3af3fa783982a65adTimo Sirainen dict_set(trans, DICT_QUOTA_CLONE_COUNT_PATH,
47a5a7e8296f3b8f2fac9a0659d4de3f2723ba4aMartti Rannanjärvi t_strdup_printf("%"PRIu64, count_value));
a022e47f45597650f71f00c3af3fa783982a65adTimo Sirainen }
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainen if (dict_transaction_commit(&trans, &error) < 0)
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainen i_error("quota_clone_plugin: Failed to commit dict update: %s", error);
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen else
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen qbox->quota_changed = FALSE;
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen}
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen
588a0579058849aed9f7b59d8259e0c58d9fd23cTimo Sirainenstatic void quota_clone_flush(struct mailbox *box)
588a0579058849aed9f7b59d8259e0c58d9fd23cTimo Sirainen{
588a0579058849aed9f7b59d8259e0c58d9fd23cTimo Sirainen struct quota_clone_mailbox *qbox = QUOTA_CLONE_CONTEXT(box);
588a0579058849aed9f7b59d8259e0c58d9fd23cTimo Sirainen struct quota_clone_user *quser =
588a0579058849aed9f7b59d8259e0c58d9fd23cTimo Sirainen QUOTA_CLONE_USER_CONTEXT(box->storage->user);
588a0579058849aed9f7b59d8259e0c58d9fd23cTimo Sirainen
0d1b8b6bec79746c5d89d57dd8c1688946bd9237Josef 'Jeff' Sipek timeout_remove(&qbox->to_quota_flush);
5de0c65da362236080fa699af3da03e45e480ab8Timo Sirainen
588a0579058849aed9f7b59d8259e0c58d9fd23cTimo Sirainen if (quser->quota_flushing) {
588a0579058849aed9f7b59d8259e0c58d9fd23cTimo Sirainen /* recursing back from quota recalculation */
588a0579058849aed9f7b59d8259e0c58d9fd23cTimo Sirainen } else if (qbox->quota_changed) {
588a0579058849aed9f7b59d8259e0c58d9fd23cTimo Sirainen quser->quota_flushing = TRUE;
588a0579058849aed9f7b59d8259e0c58d9fd23cTimo Sirainen quota_clone_flush_real(box);
588a0579058849aed9f7b59d8259e0c58d9fd23cTimo Sirainen quser->quota_flushing = FALSE;
588a0579058849aed9f7b59d8259e0c58d9fd23cTimo Sirainen }
588a0579058849aed9f7b59d8259e0c58d9fd23cTimo Sirainen}
588a0579058849aed9f7b59d8259e0c58d9fd23cTimo Sirainen
5de0c65da362236080fa699af3da03e45e480ab8Timo Sirainenstatic void quota_clone_changed(struct mailbox *box)
5de0c65da362236080fa699af3da03e45e480ab8Timo Sirainen{
5de0c65da362236080fa699af3da03e45e480ab8Timo Sirainen struct quota_clone_mailbox *qbox = QUOTA_CLONE_CONTEXT(box);
5de0c65da362236080fa699af3da03e45e480ab8Timo Sirainen
5de0c65da362236080fa699af3da03e45e480ab8Timo Sirainen qbox->quota_changed = TRUE;
5de0c65da362236080fa699af3da03e45e480ab8Timo Sirainen if (qbox->to_quota_flush == NULL) {
5de0c65da362236080fa699af3da03e45e480ab8Timo Sirainen qbox->to_quota_flush = timeout_add(QUOTA_CLONE_FLUSH_DELAY_MSECS,
5de0c65da362236080fa699af3da03e45e480ab8Timo Sirainen quota_clone_flush, box);
5de0c65da362236080fa699af3da03e45e480ab8Timo Sirainen }
5de0c65da362236080fa699af3da03e45e480ab8Timo Sirainen}
5de0c65da362236080fa699af3da03e45e480ab8Timo Sirainen
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainenstatic int quota_clone_save_finish(struct mail_save_context *ctx)
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen{
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen struct quota_clone_mailbox *qbox =
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen QUOTA_CLONE_CONTEXT(ctx->transaction->box);
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen
5de0c65da362236080fa699af3da03e45e480ab8Timo Sirainen quota_clone_changed(ctx->transaction->box);
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen return qbox->module_ctx.super.save_finish(ctx);
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen}
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainenstatic int
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainenquota_clone_copy(struct mail_save_context *ctx, struct mail *mail)
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen{
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen struct quota_clone_mailbox *qbox =
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen QUOTA_CLONE_CONTEXT(ctx->transaction->box);
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen
5de0c65da362236080fa699af3da03e45e480ab8Timo Sirainen quota_clone_changed(ctx->transaction->box);
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen return qbox->module_ctx.super.copy(ctx, mail);
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen}
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainenstatic void
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainenquota_clone_mailbox_sync_notify(struct mailbox *box, uint32_t uid,
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen enum mailbox_sync_type sync_type)
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen{
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen struct quota_clone_mailbox *qbox = QUOTA_CLONE_CONTEXT(box);
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen if (qbox->module_ctx.super.sync_notify != NULL)
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen qbox->module_ctx.super.sync_notify(box, uid, sync_type);
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen if (sync_type == MAILBOX_SYNC_TYPE_EXPUNGE)
5de0c65da362236080fa699af3da03e45e480ab8Timo Sirainen quota_clone_changed(box);
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen}
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainenstatic void quota_clone_mailbox_close(struct mailbox *box)
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen{
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen struct quota_clone_mailbox *qbox = QUOTA_CLONE_CONTEXT(box);
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen qbox->module_ctx.super.close(box);
8705e45564a2e87d32bd825e0e997a8177846f77Timo Sirainen
588a0579058849aed9f7b59d8259e0c58d9fd23cTimo Sirainen quota_clone_flush(box);
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen}
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainenstatic void quota_clone_mailbox_allocated(struct mailbox *box)
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen{
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen struct quota_clone_user *quser =
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen QUOTA_CLONE_USER_CONTEXT(box->storage->user);
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen struct mailbox_vfuncs *v = box->vlast;
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen struct quota_clone_mailbox *qbox;
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen if (quser == NULL)
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen return;
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen qbox = p_new(box->pool, struct quota_clone_mailbox, 1);
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen qbox->module_ctx.super = *v;
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen box->vlast = &qbox->module_ctx.super;
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen v->save_finish = quota_clone_save_finish;
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen v->copy = quota_clone_copy;
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen v->sync_notify = quota_clone_mailbox_sync_notify;
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen v->close = quota_clone_mailbox_close;
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen MODULE_CONTEXT_SET(box, quota_clone_storage_module, qbox);
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen}
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainenstatic void quota_clone_mail_user_deinit(struct mail_user *user)
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen{
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen struct quota_clone_user *quser = QUOTA_CLONE_USER_CONTEXT(user);
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen dict_deinit(&quser->dict);
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen quser->module_ctx.super.deinit(user);
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen}
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainenstatic void quota_clone_mail_user_created(struct mail_user *user)
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen{
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen struct quota_clone_user *quser;
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen struct mail_user_vfuncs *v = user->vlast;
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen struct dict_settings dict_set;
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen struct dict *dict;
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen const char *uri, *error;
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen uri = mail_user_plugin_getenv(user, "quota_clone_dict");
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen if (uri == NULL || uri[0] == '\0') {
0d1d485939b9b7f1a0f588aea40c504e3d26e35bJ. Nick Koston if (user->mail_debug) {
0d1d485939b9b7f1a0f588aea40c504e3d26e35bJ. Nick Koston i_debug("The quota_clone_dict setting is missing from configuration");
0d1d485939b9b7f1a0f588aea40c504e3d26e35bJ. Nick Koston }
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen return;
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen }
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch i_zero(&dict_set);
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen dict_set.username = user->username;
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen dict_set.base_dir = user->set->base_dir;
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen (void)mail_user_get_home(user, &dict_set.home_dir);
20e04227229970d148801c507946666e2a9bd838Timo Sirainen if (dict_init(uri, &dict_set, &dict, &error) < 0) {
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen i_error("quota_clone_dict: Failed to initialize '%s': %s",
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen uri, error);
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen return;
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen }
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen quser = p_new(user->pool, struct quota_clone_user, 1);
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen quser->module_ctx.super = *v;
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen user->vlast = &quser->module_ctx.super;
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen v->deinit = quota_clone_mail_user_deinit;
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen quser->dict = dict;
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen MODULE_CONTEXT_SET(user, quota_clone_user_module, quser);
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen}
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainenstatic struct mail_storage_hooks quota_clone_mail_storage_hooks = {
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen .mailbox_allocated = quota_clone_mailbox_allocated,
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen .mail_user_created = quota_clone_mail_user_created
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen};
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainenvoid quota_clone_plugin_init(struct module *module ATTR_UNUSED)
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen{
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen mail_storage_hooks_add(module, &quota_clone_mail_storage_hooks);
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen}
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainenvoid quota_clone_plugin_deinit(void)
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen{
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen mail_storage_hooks_remove(&quota_clone_mail_storage_hooks);
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen}
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainen
1f2f38f518ea14d1042c98ab039e6df053f7b285Timo Sirainenconst char *quota_clone_plugin_dependencies[] = { "quota", NULL };