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