quota-storage.c revision 45312f52ff3a3d4c137447be4c7556500c2f8bf2
02c335c23bf5fa225a467c19f2c063fb0dc7b8c3Timo Sirainen/* Copyright (c) 2005-2009 Dovecot authors, see the included COPYING file */
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen#include "lib.h"
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen#include "array.h"
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen#include "istream.h"
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen#include "mail-search-build.h"
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen#include "mail-storage-private.h"
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen#include "mailbox-list-private.h"
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen#include "quota-private.h"
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen#include "quota-plugin.h"
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen#include <sys/stat.h>
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen#define QUOTA_CONTEXT(obj) \
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen MODULE_CONTEXT(obj, quota_storage_module)
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen#define QUOTA_MAIL_CONTEXT(obj) \
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen MODULE_CONTEXT(obj, quota_mail_module)
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen#define QUOTA_LIST_CONTEXT(obj) \
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen MODULE_CONTEXT(obj, quota_mailbox_list_module)
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen#define QUOTA_USER_CONTEXT(obj) \
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen MODULE_CONTEXT(obj, quota_user_module)
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainenstruct quota_user {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen union mail_user_module_context module_ctx;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen struct quota *quota;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen};
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainenstruct quota_mailbox_list {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen union mailbox_list_module_context module_ctx;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen struct mail_storage *storage;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen};
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainenstruct quota_mailbox {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen union mailbox_module_context module_ctx;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen struct mailbox_transaction_context *expunge_trans;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen struct quota_transaction_context *expunge_qt;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen ARRAY_DEFINE(expunge_uids, uint32_t);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen ARRAY_DEFINE(expunge_sizes, uoff_t);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen unsigned int save_hack:1;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen unsigned int recalculate:1;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen};
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainenstatic MODULE_CONTEXT_DEFINE_INIT(quota_storage_module,
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen &mail_storage_module_register);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainenstatic MODULE_CONTEXT_DEFINE_INIT(quota_mail_module, &mail_module_register);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainenstatic MODULE_CONTEXT_DEFINE_INIT(quota_mailbox_list_module,
2200adee458ca662d32b5ec0e01d8c5cba0cc0a8Timo Sirainen &mailbox_list_module_register);
b215322367dbd94df3e2e4bb643b53460e6adc51Timo Sirainenstatic MODULE_CONTEXT_DEFINE_INIT(quota_user_module,
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen &mail_user_module_register);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainenstatic void quota_mail_expunge(struct mail *_mail)
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen{
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen struct mail_private *mail = (struct mail_private *)_mail;
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen struct quota_mailbox *qbox = QUOTA_CONTEXT(_mail->box);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen union mail_module_context *qmail = QUOTA_MAIL_CONTEXT(mail);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen uoff_t size;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen /* We need to handle the situation where multiple transactions expunged
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen the mail at the same time. In here we'll just save the message's
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen physical size and do the quota freeing later when the message was
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen known to be expunged. */
35ef661bd85c64834e3e34eeeb3c393b81108760Timo Sirainen if (mail_get_physical_size(_mail, &size) == 0) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (!array_is_created(&qbox->expunge_uids)) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen i_array_init(&qbox->expunge_uids, 64);
35ef661bd85c64834e3e34eeeb3c393b81108760Timo Sirainen i_array_init(&qbox->expunge_sizes, 64);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen }
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen array_append(&qbox->expunge_uids, &_mail->uid, 1);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen array_append(&qbox->expunge_sizes, &size, 1);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen }
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen qmail->super.expunge(_mail);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen}
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainenstatic struct mailbox_transaction_context *
bd63b5b860658b01b1f46f26d406e1e4a9dc019aTimo Sirainenquota_mailbox_transaction_begin(struct mailbox *box,
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen enum mailbox_transaction_flags flags)
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen{
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen struct quota_mailbox *qbox = QUOTA_CONTEXT(box);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen struct mailbox_transaction_context *t;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen struct quota_transaction_context *qt;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen t = qbox->module_ctx.super.transaction_begin(box, flags);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen qt = quota_transaction_begin(box);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen MODULE_CONTEXT_SET(t, quota_storage_module, qt);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen return t;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen}
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainenstatic int
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainenquota_mailbox_transaction_commit(struct mailbox_transaction_context *ctx,
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen uint32_t *uid_validity_r,
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen uint32_t *first_saved_uid_r,
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen uint32_t *last_saved_uid_r)
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen{
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen struct quota_mailbox *qbox = QUOTA_CONTEXT(ctx->box);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen struct quota_transaction_context *qt = QUOTA_CONTEXT(ctx);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (qt->tmp_mail != NULL)
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen mail_free(&qt->tmp_mail);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (qbox->module_ctx.super.transaction_commit(ctx,
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen uid_validity_r,
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen first_saved_uid_r,
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen last_saved_uid_r) < 0) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen quota_transaction_rollback(&qt);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen return -1;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen } else {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen (void)quota_transaction_commit(&qt);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen return 0;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen }
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen}
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainenstatic void
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainenquota_mailbox_transaction_rollback(struct mailbox_transaction_context *ctx)
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainen{
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainen struct quota_mailbox *qbox = QUOTA_CONTEXT(ctx->box);
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainen struct quota_transaction_context *qt = QUOTA_CONTEXT(ctx);
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainen
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen if (qt->tmp_mail != NULL)
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen mail_free(&qt->tmp_mail);
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainen qbox->module_ctx.super.transaction_rollback(ctx);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen quota_transaction_rollback(&qt);
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainen}
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainen
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainenstatic struct mail *
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainenquota_mail_alloc(struct mailbox_transaction_context *t,
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainen enum mail_fetch_field wanted_fields,
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainen struct mailbox_header_lookup_ctx *wanted_headers)
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainen{
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainen struct quota_mailbox *qbox = QUOTA_CONTEXT(t->box);
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainen union mail_module_context *qmail;
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainen struct mail *_mail;
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainen struct mail_private *mail;
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainen
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainen _mail = qbox->module_ctx.super.
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainen mail_alloc(t, wanted_fields, wanted_headers);
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainen mail = (struct mail_private *)_mail;
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainen
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainen qmail = p_new(mail->pool, union mail_module_context, 1);
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainen qmail->super = mail->v;
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainen
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen mail->v.expunge = quota_mail_expunge;
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen MODULE_CONTEXT_SET_SELF(mail, quota_mail_module, qmail);
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainen return _mail;
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainen}
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainen
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainenstatic int quota_check(struct mailbox_transaction_context *t, struct mail *mail)
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen{
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen struct quota_transaction_context *qt = QUOTA_CONTEXT(t);
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen int ret;
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen bool too_large;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainen ret = quota_try_alloc(qt, mail, &too_large);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (ret > 0)
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainen return 0;
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen else if (ret == 0) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen mail_storage_set_error(t->box->storage, MAIL_ERROR_NOSPACE,
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen qt->quota->set->quota_exceeded_msg);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen return -1;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen } else {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen mail_storage_set_critical(t->box->storage,
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainen "Internal quota calculation error");
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen return -1;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen }
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen}
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
8c3872c26b18421d62c52cbfe0b81b1d79239f89Timo Sirainenstatic int
8c3872c26b18421d62c52cbfe0b81b1d79239f89Timo Sirainenquota_copy(struct mailbox_transaction_context *t, struct mail *mail,
8c3872c26b18421d62c52cbfe0b81b1d79239f89Timo Sirainen enum mail_flags flags, struct mail_keywords *keywords,
8c3872c26b18421d62c52cbfe0b81b1d79239f89Timo Sirainen struct mail *dest_mail)
8c3872c26b18421d62c52cbfe0b81b1d79239f89Timo Sirainen{
8c3872c26b18421d62c52cbfe0b81b1d79239f89Timo Sirainen struct quota_transaction_context *qt = QUOTA_CONTEXT(t);
8c3872c26b18421d62c52cbfe0b81b1d79239f89Timo Sirainen struct quota_mailbox *qbox = QUOTA_CONTEXT(t->box);
8c3872c26b18421d62c52cbfe0b81b1d79239f89Timo Sirainen
8c3872c26b18421d62c52cbfe0b81b1d79239f89Timo Sirainen if (dest_mail == NULL) {
8c3872c26b18421d62c52cbfe0b81b1d79239f89Timo Sirainen /* we always want to know the mail size */
8c3872c26b18421d62c52cbfe0b81b1d79239f89Timo Sirainen if (qt->tmp_mail == NULL) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen qt->tmp_mail = mail_alloc(t, MAIL_FETCH_PHYSICAL_SIZE,
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen NULL);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen }
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen dest_mail = qt->tmp_mail;
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen }
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen qbox->save_hack = FALSE;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (qbox->module_ctx.super.copy(t, mail, flags, keywords,
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen dest_mail) < 0)
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen return -1;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainen /* if copying used saving internally, we already checked the quota
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainen and set qbox->save_hack = TRUE. */
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen return qbox->save_hack ? 0 : quota_check(t, dest_mail);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen}
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainenstatic int
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainenquota_save_begin(struct mail_save_context *ctx, struct istream *input)
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen{
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen struct mailbox_transaction_context *t = ctx->transaction;
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen struct quota_transaction_context *qt = QUOTA_CONTEXT(t);
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen struct quota_mailbox *qbox = QUOTA_CONTEXT(t->box);
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen const struct stat *st;
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen int ret;
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen st = i_stream_stat(input, TRUE);
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen if (st != NULL && st->st_size != -1) {
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen /* Input size is known, check for quota immediately. This
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainen check isn't perfect, especially because input stream's
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainen linefeeds may contain CR+LFs while physical message would
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainen only contain LFs. With mbox some headers might be skipped
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen entirely.
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen I think these don't really matter though compared to the
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen benefit of giving "out of quota" error before sending the
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen full mail. */
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen bool too_large;
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen ret = quota_test_alloc(qt, st->st_size, &too_large);
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen if (ret == 0) {
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen mail_storage_set_error(t->box->storage,
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen MAIL_ERROR_NOSPACE,
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen qt->quota->set->quota_exceeded_msg);
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen return -1;
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen } else if (ret < 0) {
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen mail_storage_set_critical(t->box->storage,
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen "Internal quota calculation error");
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen return -1;
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainen }
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainen }
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainen
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen if (ctx->dest_mail == NULL) {
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen /* we always want to know the mail size */
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen if (qt->tmp_mail == NULL) {
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen qt->tmp_mail = mail_alloc(t, MAIL_FETCH_PHYSICAL_SIZE,
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen NULL);
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen }
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen ctx->dest_mail = qt->tmp_mail;
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen }
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainen
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainen return qbox->module_ctx.super.save_begin(ctx, input);
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainen}
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainenstatic int quota_save_finish(struct mail_save_context *ctx)
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen{
1c3dc4c08ced3948f52c3c6c171ed77310b2cbfdTimo Sirainen struct quota_mailbox *qbox = QUOTA_CONTEXT(ctx->transaction->box);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (qbox->module_ctx.super.save_finish(ctx) < 0)
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen return -1;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen qbox->save_hack = TRUE;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen return quota_check(ctx->transaction, ctx->dest_mail);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen}
1c3dc4c08ced3948f52c3c6c171ed77310b2cbfdTimo Sirainen
1c3dc4c08ced3948f52c3c6c171ed77310b2cbfdTimo Sirainenstatic void quota_mailbox_sync_cleanup(struct quota_mailbox *qbox)
1c3dc4c08ced3948f52c3c6c171ed77310b2cbfdTimo Sirainen{
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (array_is_created(&qbox->expunge_uids)) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen array_clear(&qbox->expunge_uids);
1c3dc4c08ced3948f52c3c6c171ed77310b2cbfdTimo Sirainen array_clear(&qbox->expunge_sizes);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen }
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (qbox->expunge_qt != NULL && qbox->expunge_qt->tmp_mail != NULL) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen mail_free(&qbox->expunge_qt->tmp_mail);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen mailbox_transaction_rollback(&qbox->expunge_trans);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen }
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen}
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainenstatic void quota_mailbox_sync_commit(struct quota_mailbox *qbox)
b215322367dbd94df3e2e4bb643b53460e6adc51Timo Sirainen{
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen quota_mailbox_sync_cleanup(qbox);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (qbox->expunge_qt != NULL)
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen (void)quota_transaction_commit(&qbox->expunge_qt);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen qbox->recalculate = FALSE;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen}
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainenstatic void quota_mailbox_sync_notify(struct mailbox *box, uint32_t uid,
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen enum mailbox_sync_type sync_type)
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen{
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen struct quota_mailbox *qbox = QUOTA_CONTEXT(box);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen const uint32_t *uids;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen const uoff_t *sizep;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen unsigned int i, count;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen uoff_t size;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (qbox->module_ctx.super.sync_notify != NULL)
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen qbox->module_ctx.super.sync_notify(box, uid, sync_type);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (sync_type != MAILBOX_SYNC_TYPE_EXPUNGE || qbox->recalculate) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (uid == 0) {
b215322367dbd94df3e2e4bb643b53460e6adc51Timo Sirainen /* free the transaction before view syncing begins,
b3070aca2aa0dbdcc7f30e6e2bb1f0455127a343Timo Sirainen otherwise it'll crash. */
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen quota_mailbox_sync_cleanup(qbox);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen }
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen return;
7e8bfb5b0af9606f131fc440e61f3752da335ac9Timo Sirainen }
7e8bfb5b0af9606f131fc440e61f3752da335ac9Timo Sirainen
7e8bfb5b0af9606f131fc440e61f3752da335ac9Timo Sirainen /* we're in the middle of syncing the mailbox, so it's a bad idea to
b215322367dbd94df3e2e4bb643b53460e6adc51Timo Sirainen try and get the message sizes at this point. Rely on sizes that
b215322367dbd94df3e2e4bb643b53460e6adc51Timo Sirainen we saved earlier, or recalculate the whole quota if we don't know
b215322367dbd94df3e2e4bb643b53460e6adc51Timo Sirainen the size. */
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (!array_is_created(&qbox->expunge_uids)) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen i = count = 0;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen } else {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen uids = array_get(&qbox->expunge_uids, &count);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen for (i = 0; i < count; i++) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (uids[i] == uid)
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen break;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen }
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen }
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (qbox->expunge_qt == NULL)
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen qbox->expunge_qt = quota_transaction_begin(box);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (i != count) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen /* we already know the size */
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen sizep = array_idx(&qbox->expunge_sizes, i);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen quota_free_bytes(qbox->expunge_qt, *sizep);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen return;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen }
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen /* try to look up the size. this works only if it's cached. */
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (qbox->expunge_qt->tmp_mail == NULL) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen qbox->expunge_trans = mailbox_transaction_begin(box, 0);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen qbox->expunge_qt->tmp_mail =
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen mail_alloc(qbox->expunge_trans,
ba57ea2c696f9e9aae909f073069848876a641f4Timo Sirainen MAIL_FETCH_PHYSICAL_SIZE, NULL);
ba57ea2c696f9e9aae909f073069848876a641f4Timo Sirainen }
ba57ea2c696f9e9aae909f073069848876a641f4Timo Sirainen if (mail_set_uid(qbox->expunge_qt->tmp_mail, uid) &&
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen mail_get_physical_size(qbox->expunge_qt->tmp_mail, &size) == 0)
ba57ea2c696f9e9aae909f073069848876a641f4Timo Sirainen quota_free_bytes(qbox->expunge_qt, size);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen else {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen /* there's no way to get the size. recalculate the quota. */
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen quota_recalculate(qbox->expunge_qt);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen qbox->recalculate = TRUE;
1c3dc4c08ced3948f52c3c6c171ed77310b2cbfdTimo Sirainen }
1c3dc4c08ced3948f52c3c6c171ed77310b2cbfdTimo Sirainen}
1c3dc4c08ced3948f52c3c6c171ed77310b2cbfdTimo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainenstatic int quota_mailbox_sync_deinit(struct mailbox_sync_context *ctx,
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen enum mailbox_status_items status_items,
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen struct mailbox_status *status_r)
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen{
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen struct quota_mailbox *qbox = QUOTA_CONTEXT(ctx->box);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen int ret;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen ret = qbox->module_ctx.super.sync_deinit(ctx, status_items, status_r);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen /* update quota only after syncing is finished. the quota commit may
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen recalculate the quota and cause all mailboxes to be synced,
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen including the one we're already syncing. */
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen quota_mailbox_sync_commit(qbox);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen return ret;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen}
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainenstatic int quota_mailbox_close(struct mailbox *box)
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen{
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen struct quota_mailbox *qbox = QUOTA_CONTEXT(box);
1c3dc4c08ced3948f52c3c6c171ed77310b2cbfdTimo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (array_is_created(&qbox->expunge_uids)) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen array_free(&qbox->expunge_uids);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen array_free(&qbox->expunge_sizes);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen }
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen i_assert(qbox->expunge_qt == NULL ||
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen qbox->expunge_qt->tmp_mail == NULL);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen return qbox->module_ctx.super.close(box);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen}
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainenstatic struct mailbox *
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainenquota_mailbox_open(struct mail_storage *storage, const char *name,
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen struct istream *input, enum mailbox_open_flags flags)
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen{
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen union mail_storage_module_context *qstorage = QUOTA_CONTEXT(storage);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen struct mailbox *box;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen struct quota_mailbox *qbox;
ba57ea2c696f9e9aae909f073069848876a641f4Timo Sirainen
ba57ea2c696f9e9aae909f073069848876a641f4Timo Sirainen box = qstorage->super.mailbox_open(storage, name, input, flags);
ba57ea2c696f9e9aae909f073069848876a641f4Timo Sirainen if (box == NULL)
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen return NULL;
ba57ea2c696f9e9aae909f073069848876a641f4Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen qbox = p_new(box->pool, struct quota_mailbox, 1);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen qbox->module_ctx.super = box->v;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen box->v.transaction_begin = quota_mailbox_transaction_begin;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen box->v.transaction_commit = quota_mailbox_transaction_commit;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen box->v.transaction_rollback = quota_mailbox_transaction_rollback;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen box->v.mail_alloc = quota_mail_alloc;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen box->v.save_begin = quota_save_begin;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen box->v.save_finish = quota_save_finish;
b215322367dbd94df3e2e4bb643b53460e6adc51Timo Sirainen box->v.copy = quota_copy;
b215322367dbd94df3e2e4bb643b53460e6adc51Timo Sirainen box->v.sync_notify = quota_mailbox_sync_notify;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen box->v.sync_deinit = quota_mailbox_sync_deinit;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen box->v.close = quota_mailbox_close;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen MODULE_CONTEXT_SET(box, quota_storage_module, qbox);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen return box;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen}
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
b215322367dbd94df3e2e4bb643b53460e6adc51Timo Sirainenstatic int
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainenquota_mailbox_delete_shrink_quota(struct mailbox *box)
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen{
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen struct mail_search_context *ctx;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen struct mailbox_transaction_context *t;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen struct quota_transaction_context *qt;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen struct mail *mail;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen struct mail_search_args *search_args;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen int ret;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (mailbox_sync(box, MAILBOX_SYNC_FLAG_FULL_READ, 0, NULL) < 0)
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen return -1;
b215322367dbd94df3e2e4bb643b53460e6adc51Timo Sirainen
c8c4bbf6b1415e9d0845bc8f1cd6d19b76ab0392Timo Sirainen t = mailbox_transaction_begin(box, 0);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen qt = QUOTA_CONTEXT(t);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen search_args = mail_search_build_init();
b215322367dbd94df3e2e4bb643b53460e6adc51Timo Sirainen mail_search_build_add_all(search_args);
b215322367dbd94df3e2e4bb643b53460e6adc51Timo Sirainen ctx = mailbox_search_init(t, search_args, NULL);
b215322367dbd94df3e2e4bb643b53460e6adc51Timo Sirainen mail_search_args_unref(&search_args);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen mail = mail_alloc(t, 0, NULL);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen while (mailbox_search_next(ctx, mail) > 0)
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen quota_free(qt, mail);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen mail_free(&mail);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen ret = mailbox_search_deinit(&ctx);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (ret < 0)
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen mailbox_transaction_rollback(&t);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen else
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen ret = mailbox_transaction_commit(&t);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen return ret;
ba57ea2c696f9e9aae909f073069848876a641f4Timo Sirainen}
ba57ea2c696f9e9aae909f073069848876a641f4Timo Sirainen
ba57ea2c696f9e9aae909f073069848876a641f4Timo Sirainenstatic int
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainenquota_mailbox_list_delete(struct mailbox_list *list, const char *name)
ba57ea2c696f9e9aae909f073069848876a641f4Timo Sirainen{
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen struct quota_mailbox_list *qlist = QUOTA_LIST_CONTEXT(list);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen struct mail_storage *storage;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen struct mailbox *box;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen enum mail_error error;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen const char *str;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen int ret;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen /* This is a bit annoying to handle. We'll have to open the mailbox
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen and free the quota for all the messages existing in it. Open the
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen mailbox locked so that other processes can't mess up the quota
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen calculations by adding/removing mails while we're doing this. */
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen storage = qlist->storage;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen box = mailbox_open(&storage, name, NULL, MAILBOX_OPEN_FAST |
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen MAILBOX_OPEN_KEEP_RECENT | MAILBOX_OPEN_KEEP_LOCKED);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (box == NULL) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen str = mail_storage_get_last_error(qlist->storage, &error);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (error != MAIL_ERROR_NOTPOSSIBLE) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen ret = -1;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen } else {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen /* mailbox isn't selectable */
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen ret = 0;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen }
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen } else {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen ret = quota_mailbox_delete_shrink_quota(box);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen }
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (ret < 0) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen str = mail_storage_get_last_error(qlist->storage, &error);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen mailbox_list_set_error(list, error, str);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen }
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (box != NULL)
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen mailbox_close(&box);
ba57ea2c696f9e9aae909f073069848876a641f4Timo Sirainen
ba57ea2c696f9e9aae909f073069848876a641f4Timo Sirainen /* FIXME: here's an unfortunate race condition */
ba57ea2c696f9e9aae909f073069848876a641f4Timo Sirainen return ret < 0 ? -1 :
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen qlist->module_ctx.super.delete_mailbox(list, name);
ba57ea2c696f9e9aae909f073069848876a641f4Timo Sirainen}
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainenstatic void quota_storage_destroy(struct mail_storage *storage)
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen{
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen union mail_storage_module_context *qstorage = QUOTA_CONTEXT(storage);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen quota_remove_user_storage(storage);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (qstorage->super.destroy != NULL)
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen qstorage->super.destroy(storage);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen}
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainenstruct quota *quota_get_mail_user_quota(struct mail_user *user)
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen{
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen struct quota_user *quser = QUOTA_USER_CONTEXT(user);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen return quser->quota;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen}
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainenstatic void quota_user_deinit(struct mail_user *user)
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen{
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen struct quota_user *quser = QUOTA_USER_CONTEXT(user);
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen quota_deinit(&quser->quota);
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen quser->module_ctx.super.deinit(user);
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen}
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainenvoid quota_mail_user_created(struct mail_user *user)
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen{
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen struct quota_user *quser;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen quser = p_new(user->pool, struct quota_user, 1);
ba57ea2c696f9e9aae909f073069848876a641f4Timo Sirainen quser->module_ctx.super = user->v;
ba57ea2c696f9e9aae909f073069848876a641f4Timo Sirainen user->v.deinit = quota_user_deinit;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen quser->quota = quota_init(quota_set, user);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen MODULE_CONTEXT_SET(user, quota_user_module, quser);
1c3dc4c08ced3948f52c3c6c171ed77310b2cbfdTimo Sirainen
1c3dc4c08ced3948f52c3c6c171ed77310b2cbfdTimo Sirainen if (quota_next_hook_mail_user_created != NULL)
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen quota_next_hook_mail_user_created(user);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen}
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainenvoid quota_mail_storage_created(struct mail_storage *storage)
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen{
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen struct quota_mailbox_list *qlist = QUOTA_LIST_CONTEXT(storage->list);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen union mail_storage_module_context *qstorage;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen struct quota *quota;
7faf475a2faea9ac291898a6593870b01fbc30d4Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen qlist->storage = storage;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen qstorage = p_new(storage->pool, union mail_storage_module_context, 1);
1c3dc4c08ced3948f52c3c6c171ed77310b2cbfdTimo Sirainen qstorage->super = storage->v;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen storage->v.destroy = quota_storage_destroy;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen storage->v.mailbox_open = quota_mailbox_open;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen MODULE_CONTEXT_SET_SELF(storage, quota_storage_module, qstorage);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (storage->ns->owner != NULL &&
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen (storage->ns->flags & NAMESPACE_FLAG_INTERNAL) == 0) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen /* register to owner's quota roots */
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen quota = quota_get_mail_user_quota(storage->ns->owner);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen quota_add_user_storage(quota, storage);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen }
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen if (quota_next_hook_mail_storage_created != NULL)
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen quota_next_hook_mail_storage_created(storage);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen}
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainenvoid quota_mailbox_list_created(struct mailbox_list *list)
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen{
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen struct quota_mailbox_list *qlist;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen qlist = p_new(list->pool, struct quota_mailbox_list, 1);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen qlist->module_ctx.super = list->v;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen list->v.delete_mailbox = quota_mailbox_list_delete;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen MODULE_CONTEXT_SET(list, quota_mailbox_list_module, qlist);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (quota_next_hook_mailbox_list_created != NULL)
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen quota_next_hook_mailbox_list_created(list);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen}
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen