quota-storage.c revision 263e4b2733768062cb0b8b8917cad78fa2a04ff9
45312f52ff3a3d4c137447be4c7556500c2f8bf2Timo Sirainen/* Copyright (c) 2005-2009 Dovecot authors, see the included COPYING file */
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen#include "lib.h"
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen#include "array.h"
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen#include "istream.h"
c4b376dd6e0c423006d7ac83a39253bcaf8e7c47Timo Sirainen#include "mail-search-build.h"
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen#include "mail-storage-private.h"
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen#include "mailbox-list-private.h"
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen#include "maildir-storage.h"
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen#include "quota-private.h"
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen#include "quota-plugin.h"
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen#include <sys/stat.h>
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen#define QUOTA_CONTEXT(obj) \
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen MODULE_CONTEXT(obj, quota_storage_module)
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen#define QUOTA_MAIL_CONTEXT(obj) \
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen MODULE_CONTEXT(obj, quota_mail_module)
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen#define QUOTA_LIST_CONTEXT(obj) \
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen MODULE_CONTEXT(obj, quota_mailbox_list_module)
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainenstruct quota_mailbox_list {
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen union mailbox_list_module_context module_ctx;
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen};
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainenstruct quota_mailbox {
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen union mailbox_module_context module_ctx;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo 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};
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainenstruct quota_user_module quota_user_module =
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen MODULE_CONTEXT_INIT(&mail_user_module_register);
0df9428baed48afaff90b4d4f03792d2fd756a43Timo 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,
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen &mailbox_list_module_register);
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainenstatic void quota_mail_expunge(struct mail *_mail)
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen{
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen struct mail_private *mail = (struct mail_private *)_mail;
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen struct quota_mailbox *qbox = QUOTA_CONTEXT(_mail->box);
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen union mail_module_context *qmail = QUOTA_MAIL_CONTEXT(mail);
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen uoff_t size;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen /* We need to handle the situation where multiple transactions expunged
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo 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. */
83bb013a99f0936995f9c7a1077822662d8fefdbTimo 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
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen qmail->super.expunge(_mail);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen}
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo 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
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen t = qbox->module_ctx.super.transaction_begin(box, flags);
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen qt = quota_transaction_begin(box);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen MODULE_CONTEXT_SET(t, quota_storage_module, qt);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen return t;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen}
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainenstatic int
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainenquota_mailbox_transaction_commit(struct mailbox_transaction_context *ctx,
96308127e006bb3b1108093bcf4cc1fd9481cb7aTimo Sirainen struct mail_transaction_commit_changes *changes_r)
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen{
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen struct quota_mailbox *qbox = QUOTA_CONTEXT(ctx->box);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen struct quota_transaction_context *qt = QUOTA_CONTEXT(ctx);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
12ea3aeeb61df84632f04f86f47902a3750d61f8Timo Sirainen if (qt->tmp_mail != NULL)
12ea3aeeb61df84632f04f86f47902a3750d61f8Timo Sirainen mail_free(&qt->tmp_mail);
12ea3aeeb61df84632f04f86f47902a3750d61f8Timo Sirainen
96308127e006bb3b1108093bcf4cc1fd9481cb7aTimo Sirainen if (qbox->module_ctx.super.transaction_commit(ctx, changes_r) < 0) {
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen quota_transaction_rollback(&qt);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen return -1;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen } else {
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen (void)quota_transaction_commit(&qt);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen return 0;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen }
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen}
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainenstatic void
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo 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
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (qt->tmp_mail != NULL)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen mail_free(&qt->tmp_mail);
26550dc10a8c2057d09894c4e3f9dc12b124e90cTimo Sirainen
26550dc10a8c2057d09894c4e3f9dc12b124e90cTimo Sirainen qbox->module_ctx.super.transaction_rollback(ctx);
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen quota_transaction_rollback(&qt);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen}
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainenstatic struct mail *
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainenquota_mail_alloc(struct mailbox_transaction_context *t,
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen enum mail_fetch_field wanted_fields,
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen struct mailbox_header_lookup_ctx *wanted_headers)
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen{
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen struct quota_mailbox *qbox = QUOTA_CONTEXT(t->box);
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen union mail_module_context *qmail;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen struct mail *_mail;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen struct mail_private *mail;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen _mail = qbox->module_ctx.super.
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen mail_alloc(t, wanted_fields, wanted_headers);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen mail = (struct mail_private *)_mail;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen qmail = p_new(mail->pool, union mail_module_context, 1);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen qmail->super = mail->v;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen mail->v.expunge = quota_mail_expunge;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen MODULE_CONTEXT_SET_SELF(mail, quota_mail_module, qmail);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen return _mail;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen}
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainenstatic int quota_check(struct mailbox_transaction_context *t, struct mail *mail)
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen{
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen struct quota_transaction_context *qt = QUOTA_CONTEXT(t);
dcd50ecbfe796bd76f2d63483c534cc0e4e94164Timo Sirainen int ret;
dcd50ecbfe796bd76f2d63483c534cc0e4e94164Timo Sirainen bool too_large;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen ret = quota_try_alloc(qt, mail, &too_large);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen if (ret > 0)
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen return 0;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen else if (ret == 0) {
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen mail_storage_set_error(t->box->storage, MAIL_ERROR_NOSPACE,
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen qt->quota->set->quota_exceeded_msg);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen return -1;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen } else {
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen mail_storage_set_critical(t->box->storage,
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen "Internal quota calculation error");
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen return -1;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen }
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen}
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainenstatic int
bd4d0a1a7c0626452b8d82f37e3ec07267ac9896Timo Sirainenquota_copy(struct mail_save_context *ctx, struct mail *mail)
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen{
bd4d0a1a7c0626452b8d82f37e3ec07267ac9896Timo Sirainen struct mailbox_transaction_context *t = ctx->transaction;
2ebeb22b9a8a8bb7fbe2f2e2908478a220792b87Timo Sirainen struct quota_transaction_context *qt = QUOTA_CONTEXT(t);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen struct quota_mailbox *qbox = QUOTA_CONTEXT(t->box);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
bd4d0a1a7c0626452b8d82f37e3ec07267ac9896Timo Sirainen if (ctx->dest_mail == NULL) {
2ebeb22b9a8a8bb7fbe2f2e2908478a220792b87Timo Sirainen /* we always want to know the mail size */
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (qt->tmp_mail == NULL) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen qt->tmp_mail = mail_alloc(t, MAIL_FETCH_PHYSICAL_SIZE,
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen NULL);
2ebeb22b9a8a8bb7fbe2f2e2908478a220792b87Timo Sirainen }
bd4d0a1a7c0626452b8d82f37e3ec07267ac9896Timo Sirainen ctx->dest_mail = qt->tmp_mail;
2ebeb22b9a8a8bb7fbe2f2e2908478a220792b87Timo Sirainen }
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
bd4d0a1a7c0626452b8d82f37e3ec07267ac9896Timo Sirainen if (qbox->module_ctx.super.copy(ctx, mail) < 0)
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen return -1;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
263e4b2733768062cb0b8b8917cad78fa2a04ff9Timo Sirainen /* if copying used saving internally, we already checked the quota */
263e4b2733768062cb0b8b8917cad78fa2a04ff9Timo Sirainen return ctx->copying ? 0 : quota_check(t, ctx->dest_mail);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen}
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
4981827cb5e32cf767b7b0e3070137e6b36f42afTimo Sirainenstatic int
e3aeeb634245e80d4f643f8d2eea11d6b72336d8Timo Sirainenquota_save_begin(struct mail_save_context *ctx, struct istream *input)
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen{
e3aeeb634245e80d4f643f8d2eea11d6b72336d8Timo Sirainen struct mailbox_transaction_context *t = ctx->transaction;
4981827cb5e32cf767b7b0e3070137e6b36f42afTimo Sirainen struct quota_transaction_context *qt = QUOTA_CONTEXT(t);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen struct quota_mailbox *qbox = QUOTA_CONTEXT(t->box);
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen uoff_t size;
4981827cb5e32cf767b7b0e3070137e6b36f42afTimo Sirainen int ret;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen if (i_stream_get_size(input, TRUE, &size) > 0) {
4981827cb5e32cf767b7b0e3070137e6b36f42afTimo Sirainen /* Input size is known, check for quota immediately. This
4981827cb5e32cf767b7b0e3070137e6b36f42afTimo Sirainen check isn't perfect, especially because input stream's
4981827cb5e32cf767b7b0e3070137e6b36f42afTimo Sirainen linefeeds may contain CR+LFs while physical message would
4981827cb5e32cf767b7b0e3070137e6b36f42afTimo Sirainen only contain LFs. With mbox some headers might be skipped
4981827cb5e32cf767b7b0e3070137e6b36f42afTimo Sirainen entirely.
4981827cb5e32cf767b7b0e3070137e6b36f42afTimo Sirainen
4981827cb5e32cf767b7b0e3070137e6b36f42afTimo Sirainen I think these don't really matter though compared to the
4981827cb5e32cf767b7b0e3070137e6b36f42afTimo Sirainen benefit of giving "out of quota" error before sending the
4981827cb5e32cf767b7b0e3070137e6b36f42afTimo Sirainen full mail. */
4981827cb5e32cf767b7b0e3070137e6b36f42afTimo Sirainen bool too_large;
4981827cb5e32cf767b7b0e3070137e6b36f42afTimo Sirainen
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen ret = quota_test_alloc(qt, size, &too_large);
4981827cb5e32cf767b7b0e3070137e6b36f42afTimo Sirainen if (ret == 0) {
4981827cb5e32cf767b7b0e3070137e6b36f42afTimo Sirainen mail_storage_set_error(t->box->storage,
b87436ebb957a9eb182be72ba00e2c8eae59a2e4Timo Sirainen MAIL_ERROR_NOSPACE,
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen qt->quota->set->quota_exceeded_msg);
4981827cb5e32cf767b7b0e3070137e6b36f42afTimo Sirainen return -1;
4981827cb5e32cf767b7b0e3070137e6b36f42afTimo Sirainen } else if (ret < 0) {
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen mail_storage_set_critical(t->box->storage,
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen "Internal quota calculation error");
4981827cb5e32cf767b7b0e3070137e6b36f42afTimo Sirainen return -1;
4981827cb5e32cf767b7b0e3070137e6b36f42afTimo Sirainen }
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen }
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
e3aeeb634245e80d4f643f8d2eea11d6b72336d8Timo Sirainen if (ctx->dest_mail == NULL) {
2ebeb22b9a8a8bb7fbe2f2e2908478a220792b87Timo Sirainen /* we always want to know the mail size */
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (qt->tmp_mail == NULL) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen qt->tmp_mail = mail_alloc(t, MAIL_FETCH_PHYSICAL_SIZE,
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen NULL);
2ebeb22b9a8a8bb7fbe2f2e2908478a220792b87Timo Sirainen }
e3aeeb634245e80d4f643f8d2eea11d6b72336d8Timo Sirainen ctx->dest_mail = qt->tmp_mail;
2ebeb22b9a8a8bb7fbe2f2e2908478a220792b87Timo Sirainen }
2ebeb22b9a8a8bb7fbe2f2e2908478a220792b87Timo Sirainen
e3aeeb634245e80d4f643f8d2eea11d6b72336d8Timo Sirainen return qbox->module_ctx.super.save_begin(ctx, input);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen}
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
2ebeb22b9a8a8bb7fbe2f2e2908478a220792b87Timo Sirainenstatic int quota_save_finish(struct mail_save_context *ctx)
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen{
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen struct quota_mailbox *qbox = QUOTA_CONTEXT(ctx->transaction->box);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen if (qbox->module_ctx.super.save_finish(ctx) < 0)
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen return -1;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
cf942dce0253075911a96cff323b5f30eb654ae0Timo Sirainen return quota_check(ctx->transaction, ctx->dest_mail);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen}
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
3091db1d26fed038841a3a81dd5ff507d0b375ceTimo Sirainenstatic void quota_mailbox_sync_cleanup(struct quota_mailbox *qbox)
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen{
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen if (array_is_created(&qbox->expunge_uids)) {
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen array_clear(&qbox->expunge_uids);
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen array_clear(&qbox->expunge_sizes);
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen }
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen
3091db1d26fed038841a3a81dd5ff507d0b375ceTimo Sirainen if (qbox->expunge_qt != NULL && qbox->expunge_qt->tmp_mail != NULL) {
3091db1d26fed038841a3a81dd5ff507d0b375ceTimo Sirainen mail_free(&qbox->expunge_qt->tmp_mail);
3091db1d26fed038841a3a81dd5ff507d0b375ceTimo Sirainen mailbox_transaction_rollback(&qbox->expunge_trans);
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen }
3091db1d26fed038841a3a81dd5ff507d0b375ceTimo Sirainen}
3091db1d26fed038841a3a81dd5ff507d0b375ceTimo Sirainen
3091db1d26fed038841a3a81dd5ff507d0b375ceTimo Sirainenstatic void quota_mailbox_sync_commit(struct quota_mailbox *qbox)
3091db1d26fed038841a3a81dd5ff507d0b375ceTimo Sirainen{
3091db1d26fed038841a3a81dd5ff507d0b375ceTimo Sirainen quota_mailbox_sync_cleanup(qbox);
3091db1d26fed038841a3a81dd5ff507d0b375ceTimo Sirainen if (qbox->expunge_qt != NULL)
3091db1d26fed038841a3a81dd5ff507d0b375ceTimo Sirainen (void)quota_transaction_commit(&qbox->expunge_qt);
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen qbox->recalculate = FALSE;
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen}
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainenstatic void quota_mailbox_sync_notify(struct mailbox *box, uint32_t uid,
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo 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
3091db1d26fed038841a3a81dd5ff507d0b375ceTimo Sirainen if (sync_type != MAILBOX_SYNC_TYPE_EXPUNGE || qbox->recalculate) {
3091db1d26fed038841a3a81dd5ff507d0b375ceTimo Sirainen if (uid == 0) {
3091db1d26fed038841a3a81dd5ff507d0b375ceTimo Sirainen /* free the transaction before view syncing begins,
3091db1d26fed038841a3a81dd5ff507d0b375ceTimo Sirainen otherwise it'll crash. */
3091db1d26fed038841a3a81dd5ff507d0b375ceTimo Sirainen quota_mailbox_sync_cleanup(qbox);
3091db1d26fed038841a3a81dd5ff507d0b375ceTimo Sirainen }
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen return;
3091db1d26fed038841a3a81dd5ff507d0b375ceTimo 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)
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo 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 }
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen if (mail_set_uid(qbox->expunge_qt->tmp_mail, uid) &&
83bb013a99f0936995f9c7a1077822662d8fefdbTimo 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 enum mailbox_status_items status_items,
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen struct mailbox_status *status_r)
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen{
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen struct quota_mailbox *qbox = QUOTA_CONTEXT(ctx->box);
c1563f46bd9ae4ad20f37f003220443a6224fb9fTimo Sirainen int ret;
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen
c1563f46bd9ae4ad20f37f003220443a6224fb9fTimo Sirainen ret = qbox->module_ctx.super.sync_deinit(ctx, status_items, status_r);
c1563f46bd9ae4ad20f37f003220443a6224fb9fTimo Sirainen /* update quota only after syncing is finished. the quota commit may
c1563f46bd9ae4ad20f37f003220443a6224fb9fTimo Sirainen recalculate the quota and cause all mailboxes to be synced,
c1563f46bd9ae4ad20f37f003220443a6224fb9fTimo Sirainen including the one we're already syncing. */
3091db1d26fed038841a3a81dd5ff507d0b375ceTimo Sirainen quota_mailbox_sync_commit(qbox);
c1563f46bd9ae4ad20f37f003220443a6224fb9fTimo Sirainen return ret;
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen}
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainenstatic void quota_mailbox_close(struct mailbox *box)
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen{
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen struct quota_mailbox *qbox = QUOTA_CONTEXT(box);
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen if (array_is_created(&qbox->expunge_uids)) {
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen array_free(&qbox->expunge_uids);
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen array_free(&qbox->expunge_sizes);
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen }
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen i_assert(qbox->expunge_qt == NULL ||
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen qbox->expunge_qt->tmp_mail == NULL);
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen qbox->module_ctx.super.close(box);
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen}
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainenstatic struct mailbox *
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainenquota_mailbox_alloc(struct mail_storage *storage, struct mailbox_list *list,
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen const char *name, struct istream *input,
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen enum mailbox_flags flags)
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen{
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen union mail_storage_module_context *qstorage = QUOTA_CONTEXT(storage);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen struct mailbox *box;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen struct quota_mailbox *qbox;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen box = qstorage->super.mailbox_alloc(storage, list, name, input, flags);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen if (box == NULL || QUOTA_LIST_CONTEXT(list) == NULL)
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen return box;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen qbox = p_new(box->pool, struct quota_mailbox, 1);
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen qbox->module_ctx.super = box->v;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen box->v.transaction_begin = quota_mailbox_transaction_begin;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen box->v.transaction_commit = quota_mailbox_transaction_commit;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen box->v.transaction_rollback = quota_mailbox_transaction_rollback;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen box->v.mail_alloc = quota_mail_alloc;
e3aeeb634245e80d4f643f8d2eea11d6b72336d8Timo Sirainen box->v.save_begin = quota_save_begin;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen box->v.save_finish = quota_save_finish;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen box->v.copy = quota_copy;
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen box->v.sync_notify = quota_mailbox_sync_notify;
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen box->v.sync_deinit = quota_mailbox_sync_deinit;
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen box->v.close = quota_mailbox_close;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen MODULE_CONTEXT_SET(box, quota_storage_module, qbox);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen return box;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen}
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainenstatic int
6e22333f2cc2562d9bebd93803f70e7ac987f66aTimo Sirainenquota_mailbox_delete_shrink_quota(struct mailbox *box)
75bf6f49f6b8ee403f26a609d5c0c726a3262c54Timo Sirainen{
75bf6f49f6b8ee403f26a609d5c0c726a3262c54Timo Sirainen struct mail_search_context *ctx;
75bf6f49f6b8ee403f26a609d5c0c726a3262c54Timo Sirainen struct mailbox_transaction_context *t;
75bf6f49f6b8ee403f26a609d5c0c726a3262c54Timo Sirainen struct quota_transaction_context *qt;
75bf6f49f6b8ee403f26a609d5c0c726a3262c54Timo Sirainen struct mail *mail;
c4b376dd6e0c423006d7ac83a39253bcaf8e7c47Timo Sirainen struct mail_search_args *search_args;
75bf6f49f6b8ee403f26a609d5c0c726a3262c54Timo Sirainen int ret;
75bf6f49f6b8ee403f26a609d5c0c726a3262c54Timo Sirainen
6e22333f2cc2562d9bebd93803f70e7ac987f66aTimo Sirainen if (mailbox_sync(box, MAILBOX_SYNC_FLAG_FULL_READ, 0, NULL) < 0)
370c4117f854357c9ea86495fb3b4e8769b6db07Timo Sirainen return -1;
370c4117f854357c9ea86495fb3b4e8769b6db07Timo Sirainen
75bf6f49f6b8ee403f26a609d5c0c726a3262c54Timo Sirainen t = mailbox_transaction_begin(box, 0);
75bf6f49f6b8ee403f26a609d5c0c726a3262c54Timo Sirainen qt = QUOTA_CONTEXT(t);
c4b376dd6e0c423006d7ac83a39253bcaf8e7c47Timo Sirainen
c4b376dd6e0c423006d7ac83a39253bcaf8e7c47Timo Sirainen search_args = mail_search_build_init();
c4b376dd6e0c423006d7ac83a39253bcaf8e7c47Timo Sirainen mail_search_build_add_all(search_args);
c4b376dd6e0c423006d7ac83a39253bcaf8e7c47Timo Sirainen ctx = mailbox_search_init(t, search_args, NULL);
c4b376dd6e0c423006d7ac83a39253bcaf8e7c47Timo Sirainen mail_search_args_unref(&search_args);
75bf6f49f6b8ee403f26a609d5c0c726a3262c54Timo Sirainen
75bf6f49f6b8ee403f26a609d5c0c726a3262c54Timo Sirainen mail = mail_alloc(t, 0, NULL);
75bf6f49f6b8ee403f26a609d5c0c726a3262c54Timo Sirainen while (mailbox_search_next(ctx, mail) > 0)
75bf6f49f6b8ee403f26a609d5c0c726a3262c54Timo Sirainen quota_free(qt, mail);
75bf6f49f6b8ee403f26a609d5c0c726a3262c54Timo Sirainen mail_free(&mail);
75bf6f49f6b8ee403f26a609d5c0c726a3262c54Timo Sirainen
75bf6f49f6b8ee403f26a609d5c0c726a3262c54Timo Sirainen ret = mailbox_search_deinit(&ctx);
75bf6f49f6b8ee403f26a609d5c0c726a3262c54Timo Sirainen if (ret < 0)
75bf6f49f6b8ee403f26a609d5c0c726a3262c54Timo Sirainen mailbox_transaction_rollback(&t);
75bf6f49f6b8ee403f26a609d5c0c726a3262c54Timo Sirainen else
63f36c2b47217fc2dc4ed49cfc1907311d5ed366Timo Sirainen ret = mailbox_transaction_commit(&t);
6e22333f2cc2562d9bebd93803f70e7ac987f66aTimo Sirainen return ret;
6e22333f2cc2562d9bebd93803f70e7ac987f66aTimo Sirainen}
6e22333f2cc2562d9bebd93803f70e7ac987f66aTimo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainenstatic void quota_mailbox_list_deinit(struct mailbox_list *list)
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen{
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen struct quota_mailbox_list *qlist = QUOTA_LIST_CONTEXT(list);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen quota_remove_user_namespace(list->ns);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen qlist->module_ctx.super.deinit(list);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen}
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
6e22333f2cc2562d9bebd93803f70e7ac987f66aTimo Sirainenstatic int
6e22333f2cc2562d9bebd93803f70e7ac987f66aTimo Sirainenquota_mailbox_list_delete(struct mailbox_list *list, const char *name)
6e22333f2cc2562d9bebd93803f70e7ac987f66aTimo Sirainen{
6e22333f2cc2562d9bebd93803f70e7ac987f66aTimo Sirainen struct quota_mailbox_list *qlist = QUOTA_LIST_CONTEXT(list);
6e22333f2cc2562d9bebd93803f70e7ac987f66aTimo Sirainen struct mailbox *box;
6e22333f2cc2562d9bebd93803f70e7ac987f66aTimo Sirainen enum mail_error error;
6e22333f2cc2562d9bebd93803f70e7ac987f66aTimo Sirainen const char *str;
6e22333f2cc2562d9bebd93803f70e7ac987f66aTimo Sirainen int ret;
6e22333f2cc2562d9bebd93803f70e7ac987f66aTimo Sirainen
6e22333f2cc2562d9bebd93803f70e7ac987f66aTimo Sirainen /* This is a bit annoying to handle. We'll have to open the mailbox
6e22333f2cc2562d9bebd93803f70e7ac987f66aTimo Sirainen and free the quota for all the messages existing in it. Open the
6e22333f2cc2562d9bebd93803f70e7ac987f66aTimo Sirainen mailbox locked so that other processes can't mess up the quota
6e22333f2cc2562d9bebd93803f70e7ac987f66aTimo Sirainen calculations by adding/removing mails while we're doing this. */
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen box = mailbox_alloc(list, name, NULL, MAILBOX_FLAG_KEEP_RECENT |
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen MAILBOX_FLAG_KEEP_LOCKED);
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen if (mailbox_open(box) < 0) {
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen str = mail_storage_get_last_error(mailbox_get_storage(box),
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen &error);
6e22333f2cc2562d9bebd93803f70e7ac987f66aTimo Sirainen if (error != MAIL_ERROR_NOTPOSSIBLE) {
6e22333f2cc2562d9bebd93803f70e7ac987f66aTimo Sirainen ret = -1;
6e22333f2cc2562d9bebd93803f70e7ac987f66aTimo Sirainen } else {
6e22333f2cc2562d9bebd93803f70e7ac987f66aTimo Sirainen /* mailbox isn't selectable */
6e22333f2cc2562d9bebd93803f70e7ac987f66aTimo Sirainen ret = 0;
6e22333f2cc2562d9bebd93803f70e7ac987f66aTimo Sirainen }
6e22333f2cc2562d9bebd93803f70e7ac987f66aTimo Sirainen } else {
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen if ((ret = quota_mailbox_delete_shrink_quota(box)) < 0) {
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen str = mail_storage_get_last_error(box->storage, &error);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen mailbox_list_set_error(list, error, str);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen }
6e22333f2cc2562d9bebd93803f70e7ac987f66aTimo Sirainen }
6e22333f2cc2562d9bebd93803f70e7ac987f66aTimo Sirainen if (box != NULL)
6e22333f2cc2562d9bebd93803f70e7ac987f66aTimo Sirainen mailbox_close(&box);
6e22333f2cc2562d9bebd93803f70e7ac987f66aTimo Sirainen
75bf6f49f6b8ee403f26a609d5c0c726a3262c54Timo Sirainen /* FIXME: here's an unfortunate race condition */
75bf6f49f6b8ee403f26a609d5c0c726a3262c54Timo Sirainen return ret < 0 ? -1 :
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen qlist->module_ctx.super.delete_mailbox(list, name);
75bf6f49f6b8ee403f26a609d5c0c726a3262c54Timo Sirainen}
75bf6f49f6b8ee403f26a609d5c0c726a3262c54Timo Sirainen
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainenstruct quota *quota_get_mail_user_quota(struct mail_user *user)
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen{
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen struct quota_user *quser = QUOTA_USER_CONTEXT(user);
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen return quser->quota;
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen}
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainenstatic void quota_user_deinit(struct mail_user *user)
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen{
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen struct quota_user *quser = QUOTA_USER_CONTEXT(user);
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen quota_deinit(&quser->quota);
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen quser->module_ctx.super.deinit(user);
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen}
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainenvoid quota_mail_user_created(struct mail_user *user)
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen{
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen struct quota_user *quser;
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen struct quota_settings *set;
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen set = quota_user_read_settings(user);
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen if (set != NULL) {
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen quser = p_new(user->pool, struct quota_user, 1);
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen quser->module_ctx.super = user->v;
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen user->v.deinit = quota_user_deinit;
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen quser->quota = quota_init(set, user);
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen MODULE_CONTEXT_SET(user, quota_user_module, quser);
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen } else if (user->mail_debug) {
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen i_info("quota: No quota setting - plugin disabled");
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen }
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen if (quota_next_hook_mail_user_created != NULL)
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen quota_next_hook_mail_user_created(user);
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen}
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainenstatic void quota_maildir_storage_set(struct mail_storage *storage)
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen{
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen /* FIXME: a bit ugly location for this code. */
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen if (strcmp(storage->name, "maildir") == 0) {
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen /* For newly generated filenames add ,S=size. */
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen struct maildir_storage *mstorage =
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen (struct maildir_storage *)storage;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen mstorage->save_size_in_filename = TRUE;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen }
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen}
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainenvoid quota_mail_storage_created(struct mail_storage *storage)
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen{
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen union mail_storage_module_context *qstorage;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen qstorage = p_new(storage->pool, union mail_storage_module_context, 1);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen qstorage->super = storage->v;
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen storage->v.mailbox_alloc = quota_mailbox_alloc;
665bcbd1e21c77c8df4c750ad3a3d7bfb8938febTimo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen MODULE_CONTEXT_SET_SELF(storage, quota_storage_module, qstorage);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen quota_maildir_storage_set(storage);
e726bf74fcc8d24f4c9d0d83217b3db4314d9d1fTimo Sirainen
e726bf74fcc8d24f4c9d0d83217b3db4314d9d1fTimo Sirainen if (quota_next_hook_mail_storage_created != NULL)
e726bf74fcc8d24f4c9d0d83217b3db4314d9d1fTimo Sirainen quota_next_hook_mail_storage_created(storage);
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen}
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen
2d8b23805db6f06b8b38174fb6e135386694f429Timo Sirainenstatic struct quota_root *
2d8b23805db6f06b8b38174fb6e135386694f429Timo Sirainenquota_find_root_for_ns(struct quota *quota, struct mail_namespace *ns)
2d8b23805db6f06b8b38174fb6e135386694f429Timo Sirainen{
2d8b23805db6f06b8b38174fb6e135386694f429Timo Sirainen struct quota_root *const *roots;
2d8b23805db6f06b8b38174fb6e135386694f429Timo Sirainen unsigned int i, count;
2d8b23805db6f06b8b38174fb6e135386694f429Timo Sirainen
2d8b23805db6f06b8b38174fb6e135386694f429Timo Sirainen roots = array_get(&quota->roots, &count);
2d8b23805db6f06b8b38174fb6e135386694f429Timo Sirainen for (i = 0; i < count; i++) {
2d8b23805db6f06b8b38174fb6e135386694f429Timo Sirainen if (roots[i]->ns_prefix != NULL &&
2d8b23805db6f06b8b38174fb6e135386694f429Timo Sirainen strcmp(roots[i]->ns_prefix, ns->prefix) == 0)
2d8b23805db6f06b8b38174fb6e135386694f429Timo Sirainen return roots[i];
2d8b23805db6f06b8b38174fb6e135386694f429Timo Sirainen }
2d8b23805db6f06b8b38174fb6e135386694f429Timo Sirainen return NULL;
2d8b23805db6f06b8b38174fb6e135386694f429Timo Sirainen}
2d8b23805db6f06b8b38174fb6e135386694f429Timo Sirainen
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainenvoid quota_mailbox_list_created(struct mailbox_list *list)
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen{
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen struct quota_mailbox_list *qlist;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen struct quota *quota = NULL;
2d8b23805db6f06b8b38174fb6e135386694f429Timo Sirainen struct quota_root *root;
2d8b23805db6f06b8b38174fb6e135386694f429Timo Sirainen bool add;
2d8b23805db6f06b8b38174fb6e135386694f429Timo Sirainen
16db188cfddce117500a161302f17ae691b4500eTimo Sirainen if ((list->ns->flags & NAMESPACE_FLAG_NOQUOTA) != 0)
2d8b23805db6f06b8b38174fb6e135386694f429Timo Sirainen add = FALSE;
2d8b23805db6f06b8b38174fb6e135386694f429Timo Sirainen else if (list->ns->owner == NULL) {
2d8b23805db6f06b8b38174fb6e135386694f429Timo Sirainen /* see if we have a quota explicitly defined for
2d8b23805db6f06b8b38174fb6e135386694f429Timo Sirainen this namespace */
2d8b23805db6f06b8b38174fb6e135386694f429Timo Sirainen quota = quota_get_mail_user_quota(list->ns->user);
2d8b23805db6f06b8b38174fb6e135386694f429Timo Sirainen root = quota_find_root_for_ns(quota, list->ns);
2d8b23805db6f06b8b38174fb6e135386694f429Timo Sirainen add = root != NULL;
2d8b23805db6f06b8b38174fb6e135386694f429Timo Sirainen if (root != NULL)
2d8b23805db6f06b8b38174fb6e135386694f429Timo Sirainen root->ns = list->ns;
2d8b23805db6f06b8b38174fb6e135386694f429Timo Sirainen } else {
2d8b23805db6f06b8b38174fb6e135386694f429Timo Sirainen add = TRUE;
2d8b23805db6f06b8b38174fb6e135386694f429Timo Sirainen }
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen
2d8b23805db6f06b8b38174fb6e135386694f429Timo Sirainen if (add) {
f7fcdca120f1b591f885408d08fc90cfd725bf94Timo Sirainen qlist = p_new(list->pool, struct quota_mailbox_list, 1);
f7fcdca120f1b591f885408d08fc90cfd725bf94Timo Sirainen qlist->module_ctx.super = list->v;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen list->v.deinit = quota_mailbox_list_deinit;
f7fcdca120f1b591f885408d08fc90cfd725bf94Timo Sirainen list->v.delete_mailbox = quota_mailbox_list_delete;
f7fcdca120f1b591f885408d08fc90cfd725bf94Timo Sirainen MODULE_CONTEXT_SET(list, quota_mailbox_list_module, qlist);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen /* register to owner's quota roots */
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen quota = list->ns->owner != NULL ?
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen quota_get_mail_user_quota(list->ns->owner) :
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen quota_get_mail_user_quota(list->ns->user);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen quota_add_user_namespace(quota, list->ns);
f7fcdca120f1b591f885408d08fc90cfd725bf94Timo Sirainen }
e726bf74fcc8d24f4c9d0d83217b3db4314d9d1fTimo Sirainen if (quota_next_hook_mailbox_list_created != NULL)
e726bf74fcc8d24f4c9d0d83217b3db4314d9d1fTimo Sirainen quota_next_hook_mailbox_list_created(list);
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen}
2d8b23805db6f06b8b38174fb6e135386694f429Timo Sirainen
eafecb7ad0fbbde0da8be7e8ae735459b7bb688bTimo Sirainenstatic void quota_root_set_namespace(struct quota_root *root,
eafecb7ad0fbbde0da8be7e8ae735459b7bb688bTimo Sirainen struct mail_namespace *namespaces)
eafecb7ad0fbbde0da8be7e8ae735459b7bb688bTimo Sirainen{
eafecb7ad0fbbde0da8be7e8ae735459b7bb688bTimo Sirainen const struct quota_rule *rules;
eafecb7ad0fbbde0da8be7e8ae735459b7bb688bTimo Sirainen unsigned int i, count;
eafecb7ad0fbbde0da8be7e8ae735459b7bb688bTimo Sirainen const char *name;
eafecb7ad0fbbde0da8be7e8ae735459b7bb688bTimo Sirainen
eafecb7ad0fbbde0da8be7e8ae735459b7bb688bTimo Sirainen if (root->ns_prefix != NULL && root->ns == NULL) {
eafecb7ad0fbbde0da8be7e8ae735459b7bb688bTimo Sirainen root->ns = mail_namespace_find_prefix(namespaces,
eafecb7ad0fbbde0da8be7e8ae735459b7bb688bTimo Sirainen root->ns_prefix);
eafecb7ad0fbbde0da8be7e8ae735459b7bb688bTimo Sirainen if (root->ns == NULL) {
eafecb7ad0fbbde0da8be7e8ae735459b7bb688bTimo Sirainen i_error("quota: Unknown namespace: %s",
eafecb7ad0fbbde0da8be7e8ae735459b7bb688bTimo Sirainen root->ns_prefix);
eafecb7ad0fbbde0da8be7e8ae735459b7bb688bTimo Sirainen }
eafecb7ad0fbbde0da8be7e8ae735459b7bb688bTimo Sirainen }
eafecb7ad0fbbde0da8be7e8ae735459b7bb688bTimo Sirainen
eafecb7ad0fbbde0da8be7e8ae735459b7bb688bTimo Sirainen rules = array_get(&root->set->rules, &count);
eafecb7ad0fbbde0da8be7e8ae735459b7bb688bTimo Sirainen for (i = 0; i < count; i++) {
eafecb7ad0fbbde0da8be7e8ae735459b7bb688bTimo Sirainen name = rules[i].mailbox_name;
eafecb7ad0fbbde0da8be7e8ae735459b7bb688bTimo Sirainen if (mail_namespace_find(namespaces, &name) == NULL)
eafecb7ad0fbbde0da8be7e8ae735459b7bb688bTimo Sirainen i_error("quota: Unknown namespace: %s", name);
eafecb7ad0fbbde0da8be7e8ae735459b7bb688bTimo Sirainen }
eafecb7ad0fbbde0da8be7e8ae735459b7bb688bTimo Sirainen}
eafecb7ad0fbbde0da8be7e8ae735459b7bb688bTimo Sirainen
2d8b23805db6f06b8b38174fb6e135386694f429Timo Sirainenvoid quota_mail_namespaces_created(struct mail_namespace *namespaces)
2d8b23805db6f06b8b38174fb6e135386694f429Timo Sirainen{
2d8b23805db6f06b8b38174fb6e135386694f429Timo Sirainen struct quota *quota;
2d8b23805db6f06b8b38174fb6e135386694f429Timo Sirainen struct quota_root *const *roots;
2d8b23805db6f06b8b38174fb6e135386694f429Timo Sirainen unsigned int i, count;
2d8b23805db6f06b8b38174fb6e135386694f429Timo Sirainen
2d8b23805db6f06b8b38174fb6e135386694f429Timo Sirainen quota = quota_get_mail_user_quota(namespaces->user);
2d8b23805db6f06b8b38174fb6e135386694f429Timo Sirainen roots = array_get(&quota->roots, &count);
eafecb7ad0fbbde0da8be7e8ae735459b7bb688bTimo Sirainen for (i = 0; i < count; i++)
eafecb7ad0fbbde0da8be7e8ae735459b7bb688bTimo Sirainen quota_root_set_namespace(roots[i], namespaces);
2d8b23805db6f06b8b38174fb6e135386694f429Timo Sirainen}