# HG changeset patch # User Timo Sirainen # Date 1239933414 14400 # Node ID f9c07af22f91cd5be0a9b1fcfd5db2f9500a3e50 # Parent be738988c8ab46999c7f35931883b36e21e284a9 Implemented support for per-namespace quotas. Can be used with public namespaces. diff -r be738988c8ab -r f9c07af22f91 src/plugins/quota/quota-count.c --- a/src/plugins/quota/quota-count.c Thu Apr 16 21:55:45 2009 -0400 +++ b/src/plugins/quota/quota-count.c Thu Apr 16 21:56:54 2009 -0400 @@ -102,6 +102,9 @@ 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; diff -r be738988c8ab -r f9c07af22f91 src/plugins/quota/quota-dict.c --- a/src/plugins/quota/quota-dict.c Thu Apr 16 21:55:45 2009 -0400 +++ b/src/plugins/quota/quota-dict.c Thu Apr 16 21:56:54 2009 -0400 @@ -4,6 +4,7 @@ #include "str.h" #include "dict.h" #include "mail-user.h" +#include "mail-namespace.h" #include "quota-private.h" #include @@ -41,12 +42,25 @@ 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; diff -r be738988c8ab -r f9c07af22f91 src/plugins/quota/quota-dirsize.c --- a/src/plugins/quota/quota-dirsize.c Thu Apr 16 21:55:45 2009 -0400 +++ b/src/plugins/quota/quota-dirsize.c Thu Apr 16 21:56:54 2009 -0400 @@ -158,6 +158,9 @@ 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); diff -r be738988c8ab -r f9c07af22f91 src/plugins/quota/quota-maildir.c --- a/src/plugins/quota/quota-maildir.c Thu Apr 16 21:55:45 2009 -0400 +++ b/src/plugins/quota/quota-maildir.c Thu Apr 16 21:56:54 2009 -0400 @@ -378,6 +378,9 @@ /* 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; @@ -387,6 +390,10 @@ 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) @@ -686,6 +693,26 @@ 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; @@ -739,7 +766,9 @@ 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); } } @@ -805,7 +834,7 @@ { maildir_quota_alloc, - NULL, + maildir_quota_init, maildir_quota_deinit, maildir_quota_parse_rule, maildir_quota_storage_added, diff -r be738988c8ab -r f9c07af22f91 src/plugins/quota/quota-plugin.c --- a/src/plugins/quota/quota-plugin.c Thu Apr 16 21:55:45 2009 -0400 +++ b/src/plugins/quota/quota-plugin.c Thu Apr 16 21:56:54 2009 -0400 @@ -14,6 +14,7 @@ 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; @@ -27,6 +28,9 @@ 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) @@ -34,4 +38,5 @@ 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; } diff -r be738988c8ab -r f9c07af22f91 src/plugins/quota/quota-plugin.h --- a/src/plugins/quota/quota-plugin.h Thu Apr 16 21:55:45 2009 -0400 +++ b/src/plugins/quota/quota-plugin.h Thu Apr 16 21:56:54 2009 -0400 @@ -24,6 +24,7 @@ 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); diff -r be738988c8ab -r f9c07af22f91 src/plugins/quota/quota-private.h --- a/src/plugins/quota/quota-private.h Thu Apr 16 21:55:45 2009 -0400 +++ b/src/plugins/quota/quota-private.h Thu Apr 16 21:56:54 2009 -0400 @@ -96,6 +96,12 @@ 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) */ @@ -133,6 +139,8 @@ 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); diff -r be738988c8ab -r f9c07af22f91 src/plugins/quota/quota-storage.c --- a/src/plugins/quota/quota-storage.c Thu Apr 16 21:55:45 2009 -0400 +++ b/src/plugins/quota/quota-storage.c Thu Apr 16 21:56:54 2009 -0400 @@ -523,7 +523,9 @@ 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); } @@ -531,12 +533,43 @@ 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->owner != NULL && - (list->ns->flags & NAMESPACE_FLAG_INTERNAL) == 0) { + 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 (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; @@ -546,3 +579,24 @@ 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); + } + } +} diff -r be738988c8ab -r f9c07af22f91 src/plugins/quota/quota.c --- a/src/plugins/quota/quota.c Thu Apr 16 21:55:45 2009 -0400 +++ b/src/plugins/quota/quota.c Thu Apr 16 21:56:54 2009 -0400 @@ -595,8 +595,9 @@ 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; @@ -654,15 +655,29 @@ 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) @@ -671,6 +686,8 @@ /* 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; @@ -796,11 +813,12 @@ 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;