quota-storage.c revision a9a77f4632b1f00cc3c6664c91ef5f23746e099b
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen/* Copyright (c) 2005-2010 Dovecot authors, see the included COPYING file */
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen#include "lib.h"
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen#include "array.h"
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen#include "istream.h"
75bf6f49f6b8ee403f26a609d5c0c726a3262c54Timo Sirainen#include "mail-search-build.h"
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen#include "mail-storage-private.h"
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen#include "mailbox-list-private.h"
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen#include "maildir-storage.h"
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen#include "quota-private.h"
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen#include "quota-plugin.h"
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen#include <sys/stat.h>
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen#define QUOTA_CONTEXT(obj) \
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen MODULE_CONTEXT(obj, quota_storage_module)
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen#define QUOTA_MAIL_CONTEXT(obj) \
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen MODULE_CONTEXT(obj, quota_mail_module)
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen#define QUOTA_LIST_CONTEXT(obj) \
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen MODULE_CONTEXT(obj, quota_mailbox_list_module)
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainenstruct quota_mailbox_list {
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen union mailbox_list_module_context module_ctx;
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen};
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainenstruct quota_mailbox {
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen union mailbox_module_context module_ctx;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen struct mailbox_transaction_context *expunge_trans;
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen struct quota_transaction_context *expunge_qt;
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen ARRAY_DEFINE(expunge_uids, uint32_t);
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen ARRAY_DEFINE(expunge_sizes, uoff_t);
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen unsigned int recalculate:1;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen};
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainenstruct quota_user_module quota_user_module =
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen MODULE_CONTEXT_INIT(&mail_user_module_register);
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainenstatic MODULE_CONTEXT_DEFINE_INIT(quota_storage_module,
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen &mail_storage_module_register);
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainenstatic MODULE_CONTEXT_DEFINE_INIT(quota_mail_module, &mail_module_register);
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainenstatic MODULE_CONTEXT_DEFINE_INIT(quota_mailbox_list_module,
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen &mailbox_list_module_register);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainenstatic void quota_mail_expunge(struct mail *_mail)
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen{
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen struct mail_private *mail = (struct mail_private *)_mail;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen struct quota_mailbox *qbox = QUOTA_CONTEXT(_mail->box);
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen union mail_module_context *qmail = QUOTA_MAIL_CONTEXT(mail);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen uoff_t size;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen /* We need to handle the situation where multiple transactions expunged
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen the mail at the same time. In here we'll just save the message's
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen physical size and do the quota freeing later when the message was
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen known to be expunged. */
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen if (mail_get_physical_size(_mail, &size) == 0) {
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen if (!array_is_created(&qbox->expunge_uids)) {
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen i_array_init(&qbox->expunge_uids, 64);
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen i_array_init(&qbox->expunge_sizes, 64);
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen }
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen array_append(&qbox->expunge_uids, &_mail->uid, 1);
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen array_append(&qbox->expunge_sizes, &size, 1);
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen }
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen qmail->super.expunge(_mail);
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen}
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainenstatic struct mailbox_transaction_context *
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainenquota_mailbox_transaction_begin(struct mailbox *box,
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen enum mailbox_transaction_flags flags)
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen{
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen struct quota_mailbox *qbox = QUOTA_CONTEXT(box);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen struct mailbox_transaction_context *t;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen struct quota_transaction_context *qt;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen t = qbox->module_ctx.super.transaction_begin(box, flags);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen qt = quota_transaction_begin(box);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen MODULE_CONTEXT_SET(t, quota_storage_module, qt);
bda9a6d9b021c122a01a85cb3cee2f996263d8f0Timo Sirainen return t;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen}
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainenstatic int
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainenquota_mailbox_transaction_commit(struct mailbox_transaction_context *ctx,
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen struct mail_transaction_commit_changes *changes_r)
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen{
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen struct quota_mailbox *qbox = QUOTA_CONTEXT(ctx->box);
4d2211dac61c615c5bdfd501ea54d46c89d41b0fTimo Sirainen struct quota_transaction_context *qt = QUOTA_CONTEXT(ctx);
4d2211dac61c615c5bdfd501ea54d46c89d41b0fTimo Sirainen
4d2211dac61c615c5bdfd501ea54d46c89d41b0fTimo Sirainen if (qt->tmp_mail != NULL)
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen mail_free(&qt->tmp_mail);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen if (qbox->module_ctx.super.transaction_commit(ctx, changes_r) < 0) {
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen quota_transaction_rollback(&qt);
4d2211dac61c615c5bdfd501ea54d46c89d41b0fTimo Sirainen return -1;
4d2211dac61c615c5bdfd501ea54d46c89d41b0fTimo Sirainen } else {
4d2211dac61c615c5bdfd501ea54d46c89d41b0fTimo Sirainen (void)quota_transaction_commit(&qt);
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen return 0;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen }
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen}
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenstatic void
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainenquota_mailbox_transaction_rollback(struct mailbox_transaction_context *ctx)
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen{
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen struct quota_mailbox *qbox = QUOTA_CONTEXT(ctx->box);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen struct quota_transaction_context *qt = QUOTA_CONTEXT(ctx);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen if (qt->tmp_mail != NULL)
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen mail_free(&qt->tmp_mail);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen qbox->module_ctx.super.transaction_rollback(ctx);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen quota_transaction_rollback(&qt);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen}
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen
2ebeb22b9a8a8bb7fbe2f2e2908478a220792b87Timo Sirainenvoid quota_mail_allocated(struct mail *_mail)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen{
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen struct quota_mailbox *qbox = QUOTA_CONTEXT(_mail->box);
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen struct mail_private *mail = (struct mail_private *)_mail;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen struct mail_vfuncs *v = mail->vlast;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen union mail_module_context *qmail;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen if (qbox == NULL)
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen return;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen qmail = p_new(mail->pool, union mail_module_context, 1);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen qmail->super = *v;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen mail->vlast = &qmail->super;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen v->expunge = quota_mail_expunge;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen MODULE_CONTEXT_SET_SELF(mail, quota_mail_module, qmail);
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen}
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainenstatic int quota_check(struct mailbox_transaction_context *t, struct mail *mail)
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen{
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen struct quota_transaction_context *qt = QUOTA_CONTEXT(t);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen int ret;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen bool too_large;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen ret = quota_try_alloc(qt, mail, &too_large);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen if (ret > 0)
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen return 0;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen else if (ret == 0) {
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen mail_storage_set_error(t->box->storage, MAIL_ERROR_NOSPACE,
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen qt->quota->set->quota_exceeded_msg);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen return -1;
dcd50ecbfe796bd76f2d63483c534cc0e4e94164Timo Sirainen } else {
dcd50ecbfe796bd76f2d63483c534cc0e4e94164Timo Sirainen mail_storage_set_critical(t->box->storage,
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen "Internal quota calculation error");
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen return -1;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen }
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen}
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainenstatic int
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainenquota_copy(struct mail_save_context *ctx, struct mail *mail)
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen{
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen struct mailbox_transaction_context *t = ctx->transaction;
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen struct quota_transaction_context *qt = QUOTA_CONTEXT(t);
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen struct quota_mailbox *qbox = QUOTA_CONTEXT(t->box);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen if (ctx->dest_mail == NULL) {
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen /* we always want to know the mail size */
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen if (qt->tmp_mail == NULL) {
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen qt->tmp_mail = mail_alloc(t, MAIL_FETCH_PHYSICAL_SIZE,
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen NULL);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen }
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen ctx->dest_mail = qt->tmp_mail;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen }
2ebeb22b9a8a8bb7fbe2f2e2908478a220792b87Timo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen if (qbox->module_ctx.super.copy(ctx, mail) < 0)
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen return -1;
2ebeb22b9a8a8bb7fbe2f2e2908478a220792b87Timo Sirainen
2ebeb22b9a8a8bb7fbe2f2e2908478a220792b87Timo Sirainen /* if copying used saving internally, we already checked the quota */
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen return ctx->copying ? 0 : quota_check(t, ctx->dest_mail);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen}
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
2ebeb22b9a8a8bb7fbe2f2e2908478a220792b87Timo Sirainenstatic int
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenquota_save_begin(struct mail_save_context *ctx, struct istream *input)
2ebeb22b9a8a8bb7fbe2f2e2908478a220792b87Timo Sirainen{
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen struct mailbox_transaction_context *t = ctx->transaction;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen struct quota_transaction_context *qt = QUOTA_CONTEXT(t);
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen struct quota_mailbox *qbox = QUOTA_CONTEXT(t->box);
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen uoff_t size;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen int ret;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen if (i_stream_get_size(input, TRUE, &size) > 0) {
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen /* Input size is known, check for quota immediately. This
2ebeb22b9a8a8bb7fbe2f2e2908478a220792b87Timo Sirainen check isn't perfect, especially because input stream's
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen linefeeds may contain CR+LFs while physical message would
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen only contain LFs. With mbox some headers might be skipped
4981827cb5e32cf767b7b0e3070137e6b36f42afTimo Sirainen entirely.
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen I think these don't really matter though compared to the
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen benefit of giving "out of quota" error before sending the
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen full mail. */
2ebeb22b9a8a8bb7fbe2f2e2908478a220792b87Timo Sirainen bool too_large;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
4981827cb5e32cf767b7b0e3070137e6b36f42afTimo Sirainen ret = quota_test_alloc(qt, size, &too_large);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen if (ret == 0) {
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen mail_storage_set_error(t->box->storage,
4981827cb5e32cf767b7b0e3070137e6b36f42afTimo Sirainen MAIL_ERROR_NOSPACE,
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen qt->quota->set->quota_exceeded_msg);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen return -1;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen } else if (ret < 0) {
4981827cb5e32cf767b7b0e3070137e6b36f42afTimo Sirainen mail_storage_set_critical(t->box->storage,
4981827cb5e32cf767b7b0e3070137e6b36f42afTimo Sirainen "Internal quota calculation error");
4981827cb5e32cf767b7b0e3070137e6b36f42afTimo Sirainen return -1;
4981827cb5e32cf767b7b0e3070137e6b36f42afTimo Sirainen }
4981827cb5e32cf767b7b0e3070137e6b36f42afTimo Sirainen }
4981827cb5e32cf767b7b0e3070137e6b36f42afTimo Sirainen
4981827cb5e32cf767b7b0e3070137e6b36f42afTimo Sirainen if (ctx->dest_mail == NULL) {
4981827cb5e32cf767b7b0e3070137e6b36f42afTimo Sirainen /* we always want to know the mail size */
4981827cb5e32cf767b7b0e3070137e6b36f42afTimo Sirainen if (qt->tmp_mail == NULL) {
4981827cb5e32cf767b7b0e3070137e6b36f42afTimo Sirainen qt->tmp_mail = mail_alloc(t, MAIL_FETCH_PHYSICAL_SIZE,
4981827cb5e32cf767b7b0e3070137e6b36f42afTimo Sirainen NULL);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen }
4981827cb5e32cf767b7b0e3070137e6b36f42afTimo Sirainen ctx->dest_mail = qt->tmp_mail;
4981827cb5e32cf767b7b0e3070137e6b36f42afTimo Sirainen }
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen
4981827cb5e32cf767b7b0e3070137e6b36f42afTimo Sirainen return qbox->module_ctx.super.save_begin(ctx, input);
4981827cb5e32cf767b7b0e3070137e6b36f42afTimo Sirainen}
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenstatic int quota_save_finish(struct mail_save_context *ctx)
4981827cb5e32cf767b7b0e3070137e6b36f42afTimo Sirainen{
4981827cb5e32cf767b7b0e3070137e6b36f42afTimo Sirainen struct quota_mailbox *qbox = QUOTA_CONTEXT(ctx->transaction->box);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen if (qbox->module_ctx.super.save_finish(ctx) < 0)
2ebeb22b9a8a8bb7fbe2f2e2908478a220792b87Timo Sirainen return -1;
2ebeb22b9a8a8bb7fbe2f2e2908478a220792b87Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen return quota_check(ctx->transaction, ctx->dest_mail);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen}
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
2ebeb22b9a8a8bb7fbe2f2e2908478a220792b87Timo Sirainenstatic void quota_mailbox_sync_cleanup(struct quota_mailbox *qbox)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen{
2ebeb22b9a8a8bb7fbe2f2e2908478a220792b87Timo Sirainen if (array_is_created(&qbox->expunge_uids)) {
2ebeb22b9a8a8bb7fbe2f2e2908478a220792b87Timo Sirainen array_clear(&qbox->expunge_uids);
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen array_clear(&qbox->expunge_sizes);
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen }
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen if (qbox->expunge_qt != NULL && qbox->expunge_qt->tmp_mail != NULL) {
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen mail_free(&qbox->expunge_qt->tmp_mail);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen mailbox_transaction_rollback(&qbox->expunge_trans);
2ebeb22b9a8a8bb7fbe2f2e2908478a220792b87Timo Sirainen }
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen}
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainenstatic void quota_mailbox_sync_commit(struct quota_mailbox *qbox)
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen{
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen quota_mailbox_sync_cleanup(qbox);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen if (qbox->expunge_qt != NULL)
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen (void)quota_transaction_commit(&qbox->expunge_qt);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen qbox->recalculate = FALSE;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen}
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainenstatic void quota_mailbox_sync_notify(struct mailbox *box, uint32_t uid,
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen enum mailbox_sync_type sync_type)
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen{
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen struct quota_mailbox *qbox = QUOTA_CONTEXT(box);
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen const uint32_t *uids;
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen const uoff_t *sizep;
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen unsigned int i, count;
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen uoff_t size;
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen if (qbox->module_ctx.super.sync_notify != NULL)
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen qbox->module_ctx.super.sync_notify(box, uid, sync_type);
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen if (sync_type != MAILBOX_SYNC_TYPE_EXPUNGE || qbox->recalculate) {
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen if (uid == 0) {
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen /* free the transaction before view syncing begins,
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen otherwise it'll crash. */
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen quota_mailbox_sync_cleanup(qbox);
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen }
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen return;
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen }
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen /* we're in the middle of syncing the mailbox, so it's a bad idea to
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen try and get the message sizes at this point. Rely on sizes that
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen we saved earlier, or recalculate the whole quota if we don't know
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen the size. */
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen if (!array_is_created(&qbox->expunge_uids)) {
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen i = count = 0;
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen } else {
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen uids = array_get(&qbox->expunge_uids, &count);
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen for (i = 0; i < count; i++) {
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen if (uids[i] == uid)
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen break;
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen }
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen }
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen if (qbox->expunge_qt == NULL)
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen qbox->expunge_qt = quota_transaction_begin(box);
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen if (i != count) {
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen /* we already know the size */
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen sizep = array_idx(&qbox->expunge_sizes, i);
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen quota_free_bytes(qbox->expunge_qt, *sizep);
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen return;
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen }
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen /* try to look up the size. this works only if it's cached. */
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen if (qbox->expunge_qt->tmp_mail == NULL) {
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen qbox->expunge_trans = mailbox_transaction_begin(box, 0);
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen qbox->expunge_qt->tmp_mail =
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen mail_alloc(qbox->expunge_trans,
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen MAIL_FETCH_PHYSICAL_SIZE, NULL);
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen }
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen if (mail_set_uid(qbox->expunge_qt->tmp_mail, uid) &&
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen mail_get_physical_size(qbox->expunge_qt->tmp_mail, &size) == 0)
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen quota_free_bytes(qbox->expunge_qt, size);
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen else {
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen /* there's no way to get the size. recalculate the quota. */
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen quota_recalculate(qbox->expunge_qt);
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen qbox->recalculate = TRUE;
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen }
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen}
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainenstatic int quota_mailbox_sync_deinit(struct mailbox_sync_context *ctx,
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen struct mailbox_sync_status *status_r)
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen{
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen struct quota_mailbox *qbox = QUOTA_CONTEXT(ctx->box);
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen int ret;
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen ret = qbox->module_ctx.super.sync_deinit(ctx, status_r);
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen /* update quota only after syncing is finished. the quota commit may
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen recalculate the quota and cause all mailboxes to be synced,
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen including the one we're already syncing. */
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen quota_mailbox_sync_commit(qbox);
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen return ret;
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen}
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainenstatic void quota_mailbox_close(struct mailbox *box)
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen{
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen struct quota_mailbox *qbox = QUOTA_CONTEXT(box);
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen /* sync_notify() may be called outside sync_begin()..sync_deinit().
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen make sure we apply changes at close time at latest. */
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen quota_mailbox_sync_commit(qbox);
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen qbox->module_ctx.super.close(box);
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen}
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainenstatic int
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainenquota_mailbox_delete_shrink_quota(struct mailbox *box)
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen{
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen struct mail_search_context *ctx;
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen struct mailbox_transaction_context *t;
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen struct quota_transaction_context *qt;
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen struct mail *mail;
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen struct mail_search_args *search_args;
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen if (mailbox_mark_index_deleted(box, TRUE) < 0)
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen return -1;
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen t = mailbox_transaction_begin(box, 0);
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen qt = quota_transaction_begin(box);
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen search_args = mail_search_build_init();
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen mail_search_build_add_all(search_args);
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen ctx = mailbox_search_init(t, search_args, NULL);
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen mail_search_args_unref(&search_args);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen mail = mail_alloc(t, 0, NULL);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen while (mailbox_search_next(ctx, mail))
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen quota_free(qt, mail);
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen mail_free(&mail);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen if (mailbox_search_deinit(&ctx) < 0) {
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen /* maybe we missed some mails. */
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen quota_recalculate(qt);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen }
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen (void)quota_transaction_commit(&qt);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen mailbox_transaction_rollback(&t);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen return 0;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen}
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainenstatic int quota_mailbox_delete(struct mailbox *box)
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen{
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen struct quota_mailbox *qbox = QUOTA_CONTEXT(box);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen if (box->opened) {
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen if (quota_mailbox_delete_shrink_quota(box) < 0)
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen return -1;
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen }
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen return qbox->module_ctx.super.delete(box);
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen}
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainenstatic void quota_mailbox_free(struct mailbox *box)
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen{
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen struct quota_mailbox *qbox = QUOTA_CONTEXT(box);
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen if (array_is_created(&qbox->expunge_uids)) {
75bf6f49f6b8ee403f26a609d5c0c726a3262c54Timo Sirainen array_free(&qbox->expunge_uids);
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen array_free(&qbox->expunge_sizes);
75bf6f49f6b8ee403f26a609d5c0c726a3262c54Timo Sirainen }
75bf6f49f6b8ee403f26a609d5c0c726a3262c54Timo Sirainen i_assert(qbox->expunge_qt == NULL ||
75bf6f49f6b8ee403f26a609d5c0c726a3262c54Timo Sirainen qbox->expunge_qt->tmp_mail == NULL);
75bf6f49f6b8ee403f26a609d5c0c726a3262c54Timo Sirainen
75bf6f49f6b8ee403f26a609d5c0c726a3262c54Timo Sirainen qbox->module_ctx.super.free(box);
75bf6f49f6b8ee403f26a609d5c0c726a3262c54Timo Sirainen}
75bf6f49f6b8ee403f26a609d5c0c726a3262c54Timo Sirainen
75bf6f49f6b8ee403f26a609d5c0c726a3262c54Timo Sirainenvoid quota_mailbox_allocated(struct mailbox *box)
75bf6f49f6b8ee403f26a609d5c0c726a3262c54Timo Sirainen{
75bf6f49f6b8ee403f26a609d5c0c726a3262c54Timo Sirainen struct mailbox_vfuncs *v = box->vlast;
75bf6f49f6b8ee403f26a609d5c0c726a3262c54Timo Sirainen struct quota_mailbox *qbox;
75bf6f49f6b8ee403f26a609d5c0c726a3262c54Timo Sirainen
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen if (QUOTA_LIST_CONTEXT(box->list) == NULL)
75bf6f49f6b8ee403f26a609d5c0c726a3262c54Timo Sirainen return;
75bf6f49f6b8ee403f26a609d5c0c726a3262c54Timo Sirainen
75bf6f49f6b8ee403f26a609d5c0c726a3262c54Timo Sirainen qbox = p_new(box->pool, struct quota_mailbox, 1);
75bf6f49f6b8ee403f26a609d5c0c726a3262c54Timo Sirainen qbox->module_ctx.super = *v;
75bf6f49f6b8ee403f26a609d5c0c726a3262c54Timo Sirainen box->vlast = &qbox->module_ctx.super;
75bf6f49f6b8ee403f26a609d5c0c726a3262c54Timo Sirainen
75bf6f49f6b8ee403f26a609d5c0c726a3262c54Timo Sirainen v->transaction_begin = quota_mailbox_transaction_begin;
75bf6f49f6b8ee403f26a609d5c0c726a3262c54Timo Sirainen v->transaction_commit = quota_mailbox_transaction_commit;
75bf6f49f6b8ee403f26a609d5c0c726a3262c54Timo Sirainen v->transaction_rollback = quota_mailbox_transaction_rollback;
75bf6f49f6b8ee403f26a609d5c0c726a3262c54Timo Sirainen v->save_begin = quota_save_begin;
75bf6f49f6b8ee403f26a609d5c0c726a3262c54Timo Sirainen v->save_finish = quota_save_finish;
75bf6f49f6b8ee403f26a609d5c0c726a3262c54Timo Sirainen v->copy = quota_copy;
75bf6f49f6b8ee403f26a609d5c0c726a3262c54Timo Sirainen v->sync_notify = quota_mailbox_sync_notify;
75bf6f49f6b8ee403f26a609d5c0c726a3262c54Timo Sirainen v->sync_deinit = quota_mailbox_sync_deinit;
75bf6f49f6b8ee403f26a609d5c0c726a3262c54Timo Sirainen v->close = quota_mailbox_close;
75bf6f49f6b8ee403f26a609d5c0c726a3262c54Timo Sirainen v->delete = quota_mailbox_delete;
75bf6f49f6b8ee403f26a609d5c0c726a3262c54Timo Sirainen v->free = quota_mailbox_free;
75bf6f49f6b8ee403f26a609d5c0c726a3262c54Timo Sirainen MODULE_CONTEXT_SET(box, quota_storage_module, qbox);
75bf6f49f6b8ee403f26a609d5c0c726a3262c54Timo Sirainen}
75bf6f49f6b8ee403f26a609d5c0c726a3262c54Timo Sirainen
75bf6f49f6b8ee403f26a609d5c0c726a3262c54Timo Sirainenstatic void quota_mailbox_list_deinit(struct mailbox_list *list)
75bf6f49f6b8ee403f26a609d5c0c726a3262c54Timo Sirainen{
75bf6f49f6b8ee403f26a609d5c0c726a3262c54Timo Sirainen struct quota_mailbox_list *qlist = QUOTA_LIST_CONTEXT(list);
75bf6f49f6b8ee403f26a609d5c0c726a3262c54Timo Sirainen
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen quota_remove_user_namespace(list->ns);
75bf6f49f6b8ee403f26a609d5c0c726a3262c54Timo Sirainen qlist->module_ctx.super.deinit(list);
75bf6f49f6b8ee403f26a609d5c0c726a3262c54Timo Sirainen}
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainenstruct quota *quota_get_mail_user_quota(struct mail_user *user)
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen{
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen struct quota_user *quser = QUOTA_USER_CONTEXT(user);
bda9a6d9b021c122a01a85cb3cee2f996263d8f0Timo Sirainen
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen return quser->quota;
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen}
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainenstatic void quota_user_deinit(struct mail_user *user)
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen{
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen struct quota_user *quser = QUOTA_USER_CONTEXT(user);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen struct quota_settings *quota_set = quser->quota->set;
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen quota_deinit(&quser->quota);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen quser->module_ctx.super.deinit(user);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen quota_settings_deinit(&quota_set);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen}
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainenvoid quota_mail_user_created(struct mail_user *user)
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen{
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen struct mail_user_vfuncs *v = user->vlast;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen struct quota_user *quser;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen struct quota_settings *set;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen struct quota *quota;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen const char *error;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen int ret;
2423da95ee20fd4b3c260c1389cf2952d25f099cTimo Sirainen
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen if ((ret = quota_user_read_settings(user, &set, &error)) > 0) {
bda9a6d9b021c122a01a85cb3cee2f996263d8f0Timo Sirainen if (quota_init(set, user, &quota, &error) < 0) {
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen quota_settings_deinit(&set);
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen ret = -1;
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen }
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen }
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen if (ret < 0) {
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen user->error = p_strdup_printf(user->pool,
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen "Failed to initialize quota: %s", error);
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen return;
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen }
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen if (ret > 0) {
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen quser = p_new(user->pool, struct quota_user, 1);
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen quser->module_ctx.super = *v;
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen user->vlast = &quser->module_ctx.super;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen v->deinit = quota_user_deinit;
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen quser->quota = quota;
MODULE_CONTEXT_SET(user, quota_user_module, quser);
} else if (user->mail_debug) {
i_debug("quota: No quota setting - plugin disabled");
}
}
static struct quota_root *
quota_find_root_for_ns(struct quota *quota, struct mail_namespace *ns)
{
struct quota_root *const *roots;
unsigned int i, count;
roots = array_get(&quota->roots, &count);
for (i = 0; i < count; i++) {
if (roots[i]->ns_prefix != NULL &&
strcmp(roots[i]->ns_prefix, ns->prefix) == 0)
return roots[i];
}
return NULL;
}
void quota_mailbox_list_created(struct mailbox_list *list)
{
struct quota_mailbox_list *qlist;
struct quota *quota = NULL;
struct quota_root *root;
bool add;
if (QUOTA_USER_CONTEXT(list->ns->user) == NULL)
return;
/* see if we have a quota explicitly defined for this namespace */
quota = quota_get_mail_user_quota(list->ns->user);
root = quota_find_root_for_ns(quota, list->ns);
if (root != NULL)
root->ns = list->ns;
if ((list->ns->flags & NAMESPACE_FLAG_NOQUOTA) != 0)
add = FALSE;
else if (list->ns->owner == NULL) {
/* public namespace - add quota only if namespace is
explicitly defined for it */
add = root != NULL;
} else {
add = TRUE;
}
if (add) {
struct mailbox_list_vfuncs *v = list->vlast;
qlist = p_new(list->pool, struct quota_mailbox_list, 1);
qlist->module_ctx.super = *v;
list->vlast = &qlist->module_ctx.super;
v->deinit = quota_mailbox_list_deinit;
MODULE_CONTEXT_SET(list, quota_mailbox_list_module, qlist);
/* register to owner's quota roots */
quota = list->ns->owner != NULL ?
quota_get_mail_user_quota(list->ns->owner) :
quota_get_mail_user_quota(list->ns->user);
quota_add_user_namespace(quota, list->ns);
}
}
static void quota_root_set_namespace(struct quota_root *root,
struct mail_namespace *namespaces)
{
const struct quota_rule *rule;
const char *name;
if (root->ns_prefix != NULL && root->ns == NULL) {
root->ns = mail_namespace_find_prefix(namespaces,
root->ns_prefix);
if (root->ns == NULL) {
i_error("quota: Unknown namespace: %s",
root->ns_prefix);
}
}
array_foreach(&root->set->rules, rule) {
name = rule->mailbox_name;
if (mail_namespace_find(namespaces, &name) == NULL)
i_error("quota: Unknown namespace: %s", name);
}
}
void quota_mail_namespaces_created(struct mail_namespace *namespaces)
{
struct quota *quota;
struct quota_root *const *roots;
unsigned int i, count;
if (QUOTA_USER_CONTEXT(namespaces->user) == NULL)
return;
quota = quota_get_mail_user_quota(namespaces->user);
roots = array_get(&quota->roots, &count);
for (i = 0; i < count; i++)
quota_root_set_namespace(roots[i], namespaces);
}