]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
Implemented support for per-namespace quotas. Can be used with public namespaces.
authorTimo Sirainen <tss@iki.fi>
Fri, 17 Apr 2009 01:56:54 +0000 (21:56 -0400)
committerTimo Sirainen <tss@iki.fi>
Fri, 17 Apr 2009 01:56:54 +0000 (21:56 -0400)
--HG--
branch : HEAD

src/plugins/quota/quota-count.c
src/plugins/quota/quota-dict.c
src/plugins/quota/quota-dirsize.c
src/plugins/quota/quota-maildir.c
src/plugins/quota/quota-plugin.c
src/plugins/quota/quota-plugin.h
src/plugins/quota/quota-private.h
src/plugins/quota/quota-storage.c
src/plugins/quota/quota.c

index 1c607daeb17bc74e876c824f2fab0fe24c3defa2..09f9aa3377496593cff7d4513a48cc5eade3cd3a 100644 (file)
@@ -102,6 +102,9 @@ int quota_count(struct quota_root *root, uint64_t *bytes_r, uint64_t *count_r)
 
        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;
index 7210682c41fa285c425503172c9319d9d08a96d1..ba71edbea9f4cc098f37280fb49930caeb2d03cf 100644 (file)
@@ -4,6 +4,7 @@
 #include "str.h"
 #include "dict.h"
 #include "mail-user.h"
+#include "mail-namespace.h"
 #include "quota-private.h"
 
 #include <stdlib.h>
@@ -41,12 +42,25 @@ static int dict_quota_init(struct quota_root *_root, const char *args)
        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;
index 1aaa54b83ea8f9afe1f74fe1d7c4798db4d2e60d..1b9a033509f4cba28904ec9cf1830a51cab3a6b5 100644 (file)
@@ -158,6 +158,9 @@ get_quota_root_usage(struct quota_root *root, uint64_t *value_r)
        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);
 
index 4c805f40b724bfe7dbb12a47f6c28b666a58634a..b2856f2b06967a11fd69112837a93f01c78ca335 100644 (file)
@@ -378,6 +378,9 @@ static int maildirsize_recalculate(struct maildir_quota_root *root)
        /* 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 @@ static int maildirsize_recalculate(struct maildir_quota_root *root)
        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 @@ static struct quota_root *maildir_quota_alloc(void)
        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 @@ maildir_quota_storage_added(struct quota *quota, struct mail_storage *storage)
 
        roots = array_get_modifiable(&quota->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 @@ struct quota_backend quota_backend_maildir = {
 
        {
                maildir_quota_alloc,
-               NULL,
+               maildir_quota_init,
                maildir_quota_deinit,
                maildir_quota_parse_rule,
                maildir_quota_storage_added,
index c9a0f718559a1106a8a0b08163a860c691055d72..44f3c96f58cdb1ee341cdf7032f865c484422624 100644 (file)
@@ -14,6 +14,7 @@ extern void (*hook_mail_storage_created)(struct mail_storage *storage);
 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 @@ void quota_plugin_init(void)
 
        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 @@ 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;
 }
index 3fefbed7f9901d9b689623041dae0b1ae4c5cfc3..24edb9f1ccc3d757e62b0901e8980bee195976a0 100644 (file)
@@ -24,6 +24,7 @@ extern MODULE_CONTEXT_DEFINE(quota_user_module, &mail_user_module_register);
 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);
index 24b6f557791f9f3ec9cffc8afc6ac09d4b18b5b2..45a7e3b2231759201b8a78b9e7807fbca80ec97f 100644 (file)
@@ -96,6 +96,12 @@ struct quota_root {
        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 @@ void quota_remove_user_storage(struct mail_storage *storage);
 
 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);
 
index 1297d25c85dd0a70aea8d1c867fa318168446262..2314bb59894f465a4a8db0dc19462c22f06f50d0 100644 (file)
@@ -523,7 +523,9 @@ void quota_mail_storage_created(struct mail_storage *storage)
                                        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 @@ void quota_mail_storage_created(struct mail_storage *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(&quota->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;
@@ -546,3 +579,24 @@ void quota_mailbox_list_created(struct mailbox_list *list)
        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(&quota->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);
+               }
+       }
+}
index 64093f2149afddd0b1e4c116659bfa376da0debc..fe6b943c9a0d8fe983c9abeb036685b723bfbd90 100644 (file)
@@ -595,8 +595,9 @@ void quota_remove_user_storage(struct mail_storage *storage)
        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 @@ int quota_root_add_warning_rule(struct quota_root_settings *root_set,
 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 @@ quota_root_is_visible(struct quota_root *root, struct mailbox *box,
                /* 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 @@ int quota_set_resource(struct quota_root *root ATTR_UNUSED,
 
 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;