storages = array_get(&root->quota->storages, &count);
for (i = 0; i < count; i++) {
+ if (!quota_root_is_storage_visible(root, storages[i]))
+ continue;
+
ret = quota_count_storage(root, storages[i], bytes_r, count_r);
if (ret < 0)
break;
#include "str.h"
#include "dict.h"
#include "mail-user.h"
+#include "mail-namespace.h"
#include "quota-private.h"
#include <stdlib.h>
username = t_strdup_until(args, p);
args = p+1;
- if (strncmp(args, "noenforcing:", 12) == 0) {
+ do {
/* FIXME: pretty ugly in here. the parameters should have
been designed to be extensible. do it in a future version */
- _root->no_enforcing = TRUE;
- args += 12;
- }
+ if (strncmp(args, "noenforcing:", 12) == 0) {
+ _root->no_enforcing = TRUE;
+ args += 12;
+ continue;
+ }
+ if (strncmp(args, "ns=", 3) == 0) {
+ p = strchr(args, ':');
+ if (p == NULL)
+ break;
+
+ _root->ns_prefix = p_strdup_until(_root->pool,
+ args + 3, p);
+ args = p + 1;
+ continue;
+ }
+ } while (0);
if (*username == '\0')
username = _root->quota->user->username;
t_array_init(&paths, 8);
storages = array_get(&root->quota->storages, &count);
for (i = 0; i < count; i++) {
+ if (!quota_root_is_storage_visible(root, storages[i]))
+ continue;
+
path = mail_storage_get_mailbox_path(storages[i], "", &is_file);
quota_count_path_add(&paths, path, FALSE);
/* count mails from all storages */
storages = array_get(&root->root.quota->storages, &count);
for (i = 0; i < count; i++) {
+ if (!quota_root_is_storage_visible(&root->root, storages[i]))
+ continue;
+
if (maildirsize_recalculate_storage(root, storages[i]) < 0) {
ret = -1;
break;
if (ret == 0) {
/* check if any of the directories have changed */
for (i = 0; i < count; i++) {
+ if (!quota_root_is_storage_visible(&root->root,
+ storages[i]))
+ continue;
+
ret = maildirs_check_have_changed(root, storages[i],
root->recalc_last_stamp);
if (ret != 0)
return &root->root;
}
+static int maildir_quota_init(struct quota_root *_root, const char *args)
+{
+ const char *const *tmp;
+
+ if (args == NULL)
+ return 0;
+
+ for (tmp = t_strsplit(args, ":"); *tmp != NULL; tmp++) {
+ if (strcmp(*tmp, "noenforcing") == 0)
+ _root->no_enforcing = TRUE;
+ else if (strncmp(*tmp, "ns=", 3) == 0)
+ _root->ns_prefix = p_strdup(_root->pool, *tmp + 3);
+ else {
+ i_error("maildir quota: Invalid parameter: %s", *tmp);
+ return -1;
+ }
+ }
+ return 0;
+}
+
static void maildir_quota_deinit(struct quota_root *_root)
{
struct maildir_quota_root *root = (struct maildir_quota_root *)_root;
roots = array_get_modifiable("a->roots, &count);
for (i = 0; i < count; i++) {
- if (roots[i]->backend.name == quota_backend_maildir.name)
+ if (roots[i]->backend.name == quota_backend_maildir.name &&
+ (roots[i]->ns_prefix == NULL ||
+ roots[i]->ns == storage->ns))
maildir_quota_root_storage_added(roots[i], storage);
}
}
{
maildir_quota_alloc,
- NULL,
+ maildir_quota_init,
maildir_quota_deinit,
maildir_quota_parse_rule,
maildir_quota_storage_added,
void (*quota_next_hook_mail_user_created)(struct mail_user *user);
void (*quota_next_hook_mail_storage_created)(struct mail_storage *storage);
void (*quota_next_hook_mailbox_list_created)(struct mailbox_list *list);
+void (*quota_next_hook_mail_namespaces_created)(struct mail_namespace *namespaces);
const char *quota_plugin_version = PACKAGE_VERSION;
quota_next_hook_mailbox_list_created = hook_mailbox_list_created;
hook_mailbox_list_created = quota_mailbox_list_created;
+
+ quota_next_hook_mail_namespaces_created = hook_mail_namespaces_created;
+ hook_mail_namespaces_created = quota_mail_namespaces_created;
}
void quota_plugin_deinit(void)
hook_mail_user_created = quota_next_hook_mail_user_created;
hook_mail_storage_created = quota_next_hook_mail_storage_created;
hook_mailbox_list_created = quota_next_hook_mailbox_list_created;
+ hook_mail_namespaces_created = quota_next_hook_mail_namespaces_created;
}
void quota_mail_user_created(struct mail_user *user);
void quota_mail_storage_created(struct mail_storage *storage);
void quota_mailbox_list_created(struct mailbox_list *list);
+void quota_mail_namespaces_created(struct mail_namespace *namespaces);
void quota_plugin_init(void);
void quota_plugin_deinit(void);
struct quota *quota;
struct quota_backend backend;
+ /* this quota root applies only to this namespace. it may also be
+ a public namespace without an owner. */
+ struct mail_namespace *ns;
+ /* this is set in quota init(), because namespaces aren't known yet */
+ const char *ns_prefix;
+
/* initially the same as set->default_rule.*_limit, but some backends
may change these by reading the limits elsewhere (e.g. Maildir++,
FS quota) */
struct quota *quota_get_mail_user_quota(struct mail_user *user);
+bool quota_root_is_storage_visible(struct quota_root *root,
+ struct mail_storage *storage);
struct quota_rule *
quota_root_rule_find(struct quota_root_settings *root_set, const char *name);
qstorage);
/* register to owner's quota roots */
- quota = quota_get_mail_user_quota(storage->ns->owner);
+ quota = storage->ns->owner != NULL ?
+ quota_get_mail_user_quota(storage->ns->owner) :
+ quota_get_mail_user_quota(storage->ns->user);
quota_add_user_storage(quota, storage);
}
quota_next_hook_mail_storage_created(storage);
}
+static struct quota_root *
+quota_find_root_for_ns(struct quota *quota, struct mail_namespace *ns)
+{
+ struct quota_root *const *roots;
+ unsigned int i, count;
+
+ roots = array_get("a->roots, &count);
+ for (i = 0; i < count; i++) {
+ if (roots[i]->ns_prefix != NULL &&
+ strcmp(roots[i]->ns_prefix, ns->prefix) == 0)
+ return roots[i];
+ }
+ return NULL;
+}
+
void quota_mailbox_list_created(struct mailbox_list *list)
{
struct quota_mailbox_list *qlist;
+ struct quota *quota;
+ struct quota_root *root;
+ bool add;
+
+ if ((list->ns->flags & NAMESPACE_FLAG_INTERNAL) != 0)
+ add = FALSE;
+ else if (list->ns->owner == NULL) {
+ /* see if we have a quota explicitly defined for
+ this namespace */
+ quota = quota_get_mail_user_quota(list->ns->user);
+ root = quota_find_root_for_ns(quota, list->ns);
+ add = root != NULL;
+ if (root != NULL)
+ root->ns = list->ns;
+ } else {
+ add = TRUE;
+ }
- if (list->ns->owner != NULL &&
- (list->ns->flags & NAMESPACE_FLAG_INTERNAL) == 0) {
+ if (add) {
qlist = p_new(list->pool, struct quota_mailbox_list, 1);
qlist->module_ctx.super = list->v;
list->v.delete_mailbox = quota_mailbox_list_delete;
if (quota_next_hook_mailbox_list_created != NULL)
quota_next_hook_mailbox_list_created(list);
}
+
+void quota_mail_namespaces_created(struct mail_namespace *namespaces)
+{
+ struct quota *quota;
+ struct quota_root *const *roots;
+ unsigned int i, count;
+
+ quota = quota_get_mail_user_quota(namespaces->user);
+ roots = array_get("a->roots, &count);
+ for (i = 0; i < count; i++) {
+ if (roots[i]->ns_prefix == NULL || roots[i]->ns != NULL)
+ continue;
+
+ roots[i]->ns = mail_namespace_find_prefix(namespaces,
+ roots[i]->ns_prefix);
+ if (roots[i]->ns == NULL) {
+ i_error("maildir quota: Unknown namespace: %s",
+ roots[i]->ns_prefix);
+ }
+ }
+}
struct mail_storage *const *storages;
unsigned int i, count;
- quota = storage->ns->owner == NULL ? NULL :
- quota_get_mail_user_quota(storage->ns->owner);
+ quota = storage->ns->owner != NULL ?
+ quota_get_mail_user_quota(storage->ns->owner) :
+ quota_get_mail_user_quota(storage->ns->user);
if (quota == NULL) {
/* no quota for this storage */
return;
struct quota_root_iter *
quota_root_iter_init(struct mailbox *box)
{
- struct mail_user *user = box->storage->ns->owner;
struct quota_root_iter *iter;
iter = i_new(struct quota_root_iter, 1);
- iter->quota = quota_get_mail_user_quota(user);
+ iter->quota = box->storage->ns->owner != NULL ?
+ quota_get_mail_user_quota(box->storage->ns->owner) :
+ quota_get_mail_user_quota(box->storage->ns->user);
iter->box = box;
return iter;
}
+bool quota_root_is_storage_visible(struct quota_root *root,
+ struct mail_storage *storage)
+{
+ if (root->ns != NULL) {
+ if (root->ns != storage->ns)
+ return FALSE;
+ } else {
+ if (storage->ns->owner == NULL)
+ return FALSE;
+ }
+ return TRUE;
+}
+
static bool
quota_root_is_visible(struct quota_root *root, struct mailbox *box,
bool enforce)
/* we don't want to include this root in quota enforcing */
return FALSE;
}
+ if (!quota_root_is_storage_visible(root, box->storage))
+ return FALSE;
if (array_count(&root->quota->roots) == 1) {
/* a single quota root: don't bother checking further */
return TRUE;
struct quota_transaction_context *quota_transaction_begin(struct mailbox *box)
{
- struct mail_user *user = box->storage->ns->owner;
struct quota_transaction_context *ctx;
ctx = i_new(struct quota_transaction_context, 1);
- ctx->quota = quota_get_mail_user_quota(user);
+ ctx->quota = box->storage->ns->owner != NULL ?
+ quota_get_mail_user_quota(box->storage->ns->owner) :
+ quota_get_mail_user_quota(box->storage->ns->user);
ctx->box = box;
ctx->bytes_left = (uint64_t)-1;
ctx->count_left = (uint64_t)-1;