quota-storage.c revision 9397d8c945b077e576657769ff5eeede78bcc228
/* Copyright (C) 2005 Timo Sirainen */
#include "lib.h"
#include "array.h"
#include "istream.h"
#include "mail-search.h"
#include "mail-storage-private.h"
#include "mailbox-list-private.h"
#include "quota-private.h"
#include "quota-plugin.h"
#define QUOTA_CONTEXT(obj) \
#define QUOTA_MAIL_CONTEXT(obj) \
#define QUOTA_LIST_CONTEXT(obj) \
struct quota_mailbox_list {
struct mail_storage *storage;
};
struct quota_mailbox {
union mailbox_module_context module_ctx;
struct mailbox_transaction_context *expunge_trans;
struct quota_transaction_context *expunge_qt;
unsigned int save_hack:1;
unsigned int recalculate:1;
};
{
return -1;
/* We need to handle the situation where multiple transactions expunged
the mail at the same time. In here we'll just save the message's
physical size and do the quota freeing later when the message was
known to be expunged. */
}
}
return 0;
}
static struct mailbox_transaction_context *
{
struct mailbox_transaction_context *t;
struct quota_transaction_context *qt;
return t;
}
static int
enum mailbox_sync_flags flags,
{
last_saved_uid_r) < 0) {
return -1;
} else {
(void)quota_transaction_commit(&qt);
return 0;
}
}
static void
{
}
static struct mail *
quota_mail_alloc(struct mailbox_transaction_context *t,
struct mailbox_header_lookup_ctx *wanted_headers)
{
union mail_module_context *qmail;
struct mail_private *mail;
return _mail;
}
{
int ret;
bool too_large;
if (ret > 0)
return 0;
else if (ret == 0) {
"Quota exceeded");
return -1;
} else {
"Internal quota calculation error");
return -1;
}
}
static int
{
/* we always want to know the mail size */
NULL);
}
}
dest_mail) < 0)
return -1;
/* if copying used saving internally, we already checked the quota
and set qbox->save_hack = TRUE. */
}
static int
quota_save_init(struct mailbox_transaction_context *t,
{
int ret;
/* Input size is known, check for quota immediately. This
check isn't perfect, especially because input stream's
linefeeds may contain CR+LFs while physical message would
only contain LFs. With mbox some headers might be skipped
entirely.
I think these don't really matter though compared to the
benefit of giving "out of quota" error before sending the
full mail. */
bool too_large;
if (ret == 0) {
MAIL_ERROR_NOSPACE, "Quota exceeded");
return -1;
} else if (ret < 0) {
"Internal quota calculation error");
return -1;
}
}
/* we always want to know the mail size */
NULL);
}
}
}
{
return -1;
}
{
}
}
}
}
enum mailbox_sync_type sync_type)
{
unsigned int i, count;
if (uid == 0)
return;
}
/* we're in the middle of syncing the mailbox, so it's a bad idea to
try and get the message sizes at this point. Rely on sizes that
we saved earlier, or recalculate the whole quota if we don't know
the size. */
i = count = 0;
} else {
for (i = 0; i < count; i++) {
break;
}
}
if (i != count) {
/* we already know the size */
return;
}
/* try to look up the size. this works only if it's cached. */
}
else
else {
/* there's no way to get the size. recalculate the quota. */
}
}
struct mailbox_status *status_r)
{
/* just in case sync_notify() wasn't called with uid=0 */
}
{
}
}
static struct mailbox *
{
struct quota_mailbox *qbox;
return NULL;
return box;
}
static int
{
struct mail_search_context *ctx;
struct mailbox_transaction_context *t;
struct quota_transaction_context *qt;
struct mail_search_arg search_arg;
int ret;
/* This is a bit annoying to handle. We'll have to open the mailbox
and free the quota for all the messages existing in it. Open the
mailbox locked so that other processes can't mess up the quota
return -1;
t = mailbox_transaction_begin(box, 0);
qt = QUOTA_CONTEXT(t);
if (ret < 0)
else
ret = mailbox_transaction_commit(&t, 0);
mailbox_close(&box);
/* FIXME: here's an unfortunate race condition */
return ret < 0 ? -1 :
}
{
}
{
union mail_storage_module_context *qstorage;
/* register to user's quota roots */
}
}
{
struct quota_mailbox_list *qlist;
}