struct quota_clone_user {
union mail_user_module_context module_ctx;
struct dict *dict;
- bool quota_flushing;
-};
-
-struct quota_clone_mailbox {
- union mailbox_module_context module_ctx;
struct timeout *to_quota_flush;
bool quota_changed;
+ bool quota_flushing;
};
-static void quota_clone_flush_real(struct mailbox *box)
+static void quota_clone_flush_real(struct mail_user *user)
{
- struct quota_clone_mailbox *qbox = QUOTA_CLONE_CONTEXT(box);
struct quota_clone_user *quser =
- QUOTA_CLONE_USER_CONTEXT_REQUIRE(box->storage->user);
+ QUOTA_CLONE_USER_CONTEXT_REQUIRE(user);
struct dict_transaction_context *trans;
struct quota_root_iter *iter;
struct quota_root *root;
enum quota_get_result bytes_res, count_res;
/* we'll clone the first quota root */
- iter = quota_root_iter_init(box);
+ iter = quota_root_iter_init_user(user);
root = quota_root_iter_next(iter);
quota_root_iter_deinit(&iter);
if (root == NULL) {
- /* no quota roots defined for this mailbox - ignore */
- qbox->quota_changed = FALSE;
+ /* no quota roots defined - ignore */
+ quser->quota_changed = FALSE;
return;
}
if (dict_transaction_commit(&trans, &error) < 0)
i_error("quota_clone_plugin: Failed to commit dict update: %s", error);
else
- qbox->quota_changed = FALSE;
+ quser->quota_changed = FALSE;
}
-static void quota_clone_flush(struct mailbox *box)
+static void quota_clone_flush(struct mail_user *user)
{
- struct quota_clone_mailbox *qbox = QUOTA_CLONE_CONTEXT(box);
struct quota_clone_user *quser =
- QUOTA_CLONE_USER_CONTEXT_REQUIRE(box->storage->user);
+ QUOTA_CLONE_USER_CONTEXT_REQUIRE(user);
- timeout_remove(&qbox->to_quota_flush);
+ timeout_remove(&quser->to_quota_flush);
if (quser->quota_flushing) {
/* recursing back from quota recalculation */
- } else if (qbox->quota_changed) {
+ } else if (quser->quota_changed) {
quser->quota_flushing = TRUE;
- quota_clone_flush_real(box);
+ quota_clone_flush_real(user);
quser->quota_flushing = FALSE;
}
}
+static struct mail_user *quota_mailbox_get_user(struct mailbox *box)
+{
+ struct mail_namespace *ns = mailbox_list_get_namespace(box->list);
+ return ns->owner != NULL ? ns->owner : ns->user;
+}
+
static void quota_clone_changed(struct mailbox *box)
{
- struct quota_clone_mailbox *qbox = QUOTA_CLONE_CONTEXT(box);
+ struct mail_user *user = quota_mailbox_get_user(box);
+ struct quota_clone_user *quser =
+ QUOTA_CLONE_USER_CONTEXT_REQUIRE(user);
- qbox->quota_changed = TRUE;
- if (qbox->to_quota_flush == NULL) {
- qbox->to_quota_flush = timeout_add(QUOTA_CLONE_FLUSH_DELAY_MSECS,
- quota_clone_flush, box);
+ quser->quota_changed = TRUE;
+ if (quser->to_quota_flush == NULL) {
+ quser->to_quota_flush = timeout_add(QUOTA_CLONE_FLUSH_DELAY_MSECS,
+ quota_clone_flush, user);
}
}
static int quota_clone_save_finish(struct mail_save_context *ctx)
{
- struct quota_clone_mailbox *qbox =
+ union mailbox_module_context *qbox =
QUOTA_CLONE_CONTEXT(ctx->transaction->box);
quota_clone_changed(ctx->transaction->box);
- return qbox->module_ctx.super.save_finish(ctx);
+ return qbox->super.save_finish(ctx);
}
static int
quota_clone_copy(struct mail_save_context *ctx, struct mail *mail)
{
- struct quota_clone_mailbox *qbox =
+ union mailbox_module_context *qbox =
QUOTA_CLONE_CONTEXT(ctx->transaction->box);
quota_clone_changed(ctx->transaction->box);
- return qbox->module_ctx.super.copy(ctx, mail);
+ return qbox->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);
+ union mailbox_module_context *qbox = QUOTA_CLONE_CONTEXT(box);
- if (qbox->module_ctx.super.sync_notify != NULL)
- qbox->module_ctx.super.sync_notify(box, uid, sync_type);
+ if (qbox->super.sync_notify != NULL)
+ qbox->super.sync_notify(box, uid, sync_type);
if (sync_type == MAILBOX_SYNC_TYPE_EXPUNGE)
quota_clone_changed(box);
}
-static void quota_clone_mailbox_close(struct mailbox *box)
-{
- struct quota_clone_mailbox *qbox = QUOTA_CLONE_CONTEXT(box);
-
- qbox->module_ctx.super.close(box);
-
- 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;
+ union mailbox_module_context *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;
+ qbox = p_new(box->pool, union mailbox_module_context, 1);
+ qbox->super = *v;
+ box->vlast = &qbox->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);
+ MODULE_CONTEXT_SET_SELF(box, quota_clone_storage_module, qbox);
+}
+
+static void quota_clone_mail_user_deinit_pre(struct mail_user *user)
+{
+ struct quota_clone_user *quser = QUOTA_CLONE_USER_CONTEXT_REQUIRE(user);
+
+ dict_wait(quser->dict);
+ /* Check once more if quota needs to be updated. This needs to be done
+ in deinit_pre(), because at deinit() the quota is already
+ deinitialized. */
+ if (quser->to_quota_flush != NULL) {
+ i_assert(!quser->quota_flushing);
+ quota_clone_flush(user);
+ dict_wait(quser->dict);
+ i_assert(quser->to_quota_flush == NULL);
+ }
+ quser->module_ctx.super.deinit_pre(user);
}
static void quota_clone_mail_user_deinit(struct mail_user *user)
{
struct quota_clone_user *quser = QUOTA_CLONE_USER_CONTEXT_REQUIRE(user);
+ /* wait once more, just in case something changed quota during
+ deinit_pre() */
+ dict_wait(quser->dict);
+ i_assert(quser->to_quota_flush == NULL);
dict_deinit(&quser->dict);
quser->module_ctx.super.deinit(user);
}
quser = p_new(user->pool, struct quota_clone_user, 1);
quser->module_ctx.super = *v;
user->vlast = &quser->module_ctx.super;
+ v->deinit_pre = quota_clone_mail_user_deinit_pre;
v->deinit = quota_clone_mail_user_deinit;
quser->dict = dict;
MODULE_CONTEXT_SET(user, quota_clone_user_module, quser);