quota-storage.c revision 5f5870385cff47efd2f58e7892f251cf13761528
bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2005-2012 Dovecot authors, see the included COPYING file */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen MODULE_CONTEXT(obj, quota_mailbox_list_module)
d4002fe1f64d25a792f76fb102ef7dc519cd4e24Martti Rannanjärvi struct mailbox_transaction_context *expunge_trans;
d4002fe1f64d25a792f76fb102ef7dc519cd4e24Martti Rannanjärvi struct quota_transaction_context *expunge_qt;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen MODULE_CONTEXT_INIT(&mail_user_module_register);
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainenstatic MODULE_CONTEXT_DEFINE_INIT(quota_storage_module,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic MODULE_CONTEXT_DEFINE_INIT(quota_mail_module, &mail_module_register);
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainenstatic MODULE_CONTEXT_DEFINE_INIT(quota_mailbox_list_module,
d4002fe1f64d25a792f76fb102ef7dc519cd4e24Martti Rannanjärvistatic void quota_mail_expunge(struct mail *_mail)
5b62dea2f88165f3f4d87bba9011343f3ff415ffTimo Sirainen struct mail_private *mail = (struct mail_private *)_mail;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct quota_mailbox *qbox = QUOTA_CONTEXT(_mail->box);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen union mail_module_context *qmail = QUOTA_MAIL_CONTEXT(mail);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* We need to handle the situation where multiple transactions expunged
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen the mail at the same time. In here we'll just save the message's
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen physical size and do the quota freeing later when the message was
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen known to be expunged. */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (mail_get_physical_size(_mail, &size) == 0) {
b67974c4b89ab6950c2694cce8dfb1b6561cc084Josef 'Jeff' Sipek if (!array_is_created(&qbox->expunge_uids)) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen array_append(&qbox->expunge_uids, &_mail->uid, 1);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenquota_mailbox_transaction_begin(struct mailbox *box,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct quota_mailbox *qbox = QUOTA_CONTEXT(box);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen t = qbox->module_ctx.super.transaction_begin(box, flags);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen MODULE_CONTEXT_SET(t, quota_storage_module, qt);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenquota_mailbox_transaction_commit(struct mailbox_transaction_context *ctx,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct mail_transaction_commit_changes *changes_r)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct quota_mailbox *qbox = QUOTA_CONTEXT(ctx->box);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct quota_transaction_context *qt = QUOTA_CONTEXT(ctx);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (qbox->module_ctx.super.transaction_commit(ctx, changes_r) < 0) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenquota_mailbox_transaction_rollback(struct mailbox_transaction_context *ctx)
7204b8112e005ff81dcf628f7880ef1feed1effeTimo Sirainen struct quota_mailbox *qbox = QUOTA_CONTEXT(ctx->box);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct quota_transaction_context *qt = QUOTA_CONTEXT(ctx);
767ff4367960efd5fa868f3b56f850fd4c205c8bTimo Sirainen qbox->module_ctx.super.transaction_rollback(ctx);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct quota_mailbox *qbox = QUOTA_CONTEXT(_mail->box);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct mail_private *mail = (struct mail_private *)_mail;
2d01cc1880cf2afd4fb1c8ad7fa6ce78e562e71eTimo Sirainen qmail = p_new(mail->pool, union mail_module_context, 1);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen MODULE_CONTEXT_SET_SELF(mail, quota_mail_module, qmail);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic int quota_check(struct mailbox_transaction_context *t, struct mail *mail)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct quota_transaction_context *qt = QUOTA_CONTEXT(t);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen else if (ret == 0) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mail_storage_set_error(t->box->storage, MAIL_ERROR_NOSPACE,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen "Internal quota calculation error");
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenquota_copy(struct mail_save_context *ctx, struct mail *mail)
03010dbaa74ec70f062994dfe3cd39bedc99a28bTimo Sirainen struct mailbox_transaction_context *t = ctx->transaction;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct quota_transaction_context *qt = QUOTA_CONTEXT(t);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct quota_mailbox *qbox = QUOTA_CONTEXT(t->box);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* we always want to know the mail size */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen qt->tmp_mail = mail_alloc(t, MAIL_FETCH_PHYSICAL_SIZE,
03de962febfc2ac572f9e4029463c16d29c1ed55Timo Sirainen if (qbox->module_ctx.super.copy(ctx, mail) < 0)
b67974c4b89ab6950c2694cce8dfb1b6561cc084Josef 'Jeff' Sipek /* if copying used saving internally, we already checked the quota */
03de962febfc2ac572f9e4029463c16d29c1ed55Timo Sirainen return ctx->copying_via_save ? 0 : quota_check(t, ctx->dest_mail);
03de962febfc2ac572f9e4029463c16d29c1ed55Timo Sirainenquota_save_begin(struct mail_save_context *ctx, struct istream *input)
03de962febfc2ac572f9e4029463c16d29c1ed55Timo Sirainen struct mailbox_transaction_context *t = ctx->transaction;
03de962febfc2ac572f9e4029463c16d29c1ed55Timo Sirainen struct quota_transaction_context *qt = QUOTA_CONTEXT(t);
03de962febfc2ac572f9e4029463c16d29c1ed55Timo Sirainen struct quota_mailbox *qbox = QUOTA_CONTEXT(t->box);
03de962febfc2ac572f9e4029463c16d29c1ed55Timo Sirainen if (i_stream_get_size(input, TRUE, &size) > 0) {
03de962febfc2ac572f9e4029463c16d29c1ed55Timo Sirainen /* Input size is known, check for quota immediately. This
03de962febfc2ac572f9e4029463c16d29c1ed55Timo Sirainen check isn't perfect, especially because input stream's
9865d9e7c5713e41db939222ed9c0225a11fb99eTimo Sirainen linefeeds may contain CR+LFs while physical message would
9865d9e7c5713e41db939222ed9c0225a11fb99eTimo Sirainen only contain LFs. With mbox some headers might be skipped
9865d9e7c5713e41db939222ed9c0225a11fb99eTimo Sirainen I think these don't really matter though compared to the
9865d9e7c5713e41db939222ed9c0225a11fb99eTimo Sirainen benefit of giving "out of quota" error before sending the
9865d9e7c5713e41db939222ed9c0225a11fb99eTimo Sirainen full mail. */
9865d9e7c5713e41db939222ed9c0225a11fb99eTimo Sirainen } else if (ret < 0) {
9865d9e7c5713e41db939222ed9c0225a11fb99eTimo Sirainen "Internal quota calculation error");
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen /* we always want to know the mail size */
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen qt->tmp_mail = mail_alloc(t, MAIL_FETCH_PHYSICAL_SIZE,
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return qbox->module_ctx.super.save_begin(ctx, input);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainenstatic int quota_save_finish(struct mail_save_context *ctx)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct quota_mailbox *qbox = QUOTA_CONTEXT(ctx->transaction->box);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (qbox->module_ctx.super.save_finish(ctx) < 0)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return quota_check(ctx->transaction, ctx->dest_mail);
ecd69c4e8371853667e01b0c16d436ef7f7393e2Timo Sirainenstatic void quota_mailbox_sync_cleanup(struct quota_mailbox *qbox)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (qbox->expunge_qt != NULL && qbox->expunge_qt->tmp_mail != NULL) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mailbox_transaction_rollback(&qbox->expunge_trans);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic void quota_mailbox_sync_commit(struct quota_mailbox *qbox)
306b3f41b05da642d87e7ca7a1496efce9f5902fTimo Sirainen (void)quota_transaction_commit(&qbox->expunge_qt);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic void quota_mailbox_sync_notify(struct mailbox *box, uint32_t uid,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct quota_mailbox *qbox = QUOTA_CONTEXT(box);
6de6ec228a41275ddda972d4a554699ea75cd06dTimo Sirainen unsigned int i, count;
if (uid == 0) {
i = count = 0;
for (i = 0; i < count; i++) {
if (i != count) {
int ret;
return ret;
const char *error;
int ret;
if (ret < 0) {
if (ret > 0) {
static struct quota_root *
unsigned int i, count;
for (i = 0; i < count; i++) {
return roots[i];
return NULL;
bool add;
if (add) {
const char *name;
unsigned int i, count;
for (i = 0; i < count; i++)