]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
quota: Added support for SETQUOTA IMAP command.
authorTimo Sirainen <tss@iki.fi>
Sun, 8 Dec 2013 19:26:29 +0000 (21:26 +0200)
committerTimo Sirainen <tss@iki.fi>
Sun, 8 Dec 2013 19:26:29 +0000 (21:26 +0200)
The configuration is done via quota_set setting. Currently only dict backend
is supported. For example:

plugin {
  quota_set = dict:file:/var/lib/dovecot/quota/%u
}
The SETQUOTA command is available only for the "admin" user (userdb lookup
must return admin=y).

src/plugins/imap-quota/imap-quota-plugin.c
src/plugins/quota/quota-private.h
src/plugins/quota/quota.c

index 028a3fac2890553644f3f14583453f3408e38a71..b0d9b5c365685052a3ccceac42e3f283c265d574 100644 (file)
@@ -186,6 +186,11 @@ static bool cmd_setquota(struct client_command_context *cmd)
                return TRUE;
        }
 
+       if (!cmd->client->user->admin) {
+               client_send_tagline(cmd, "NO Quota can be changed only by admin.");
+               return TRUE;
+       }
+
        for (; !IMAP_ARG_IS_EOL(list_args); list_args += 2) {
                if (!imap_arg_get_atom(&list_args[0], &name) ||
                    !imap_arg_get_atom(&list_args[1], &value_str) ||
index 9ea27893aaf06feed31d3eb6f92a57f0d20c0c61..08085e500ed97e3d81d1118a01f8eaf06aaaea84 100644 (file)
@@ -88,6 +88,7 @@ struct quota_root_settings {
        struct quota_rule default_rule;
        ARRAY(struct quota_rule) rules;
        ARRAY(struct quota_warning_rule) warning_rules;
+       const char *limit_set;
 
        /* If user is under quota before saving a mail, allow the last mail to
           bring the user over quota by this many bytes. */
@@ -104,6 +105,7 @@ struct quota_root {
        struct quota_root_settings *set;
        struct quota *quota;
        struct quota_backend backend;
+       struct dict *limit_set_dict;
 
        /* this quota root applies only to this namespace. it may also be
           a public namespace without an owner. */
index adbd70db2d4d9410727259cb3d4033a49b4218f0..7ec20278dc3a1cb7be7494335dbc56286d1637ee 100644 (file)
@@ -7,6 +7,7 @@
 #include "net.h"
 #include "write-full.h"
 #include "eacces-error.h"
+#include "dict.h"
 #include "mailbox-list-private.h"
 #include "quota-private.h"
 #include "quota-fs.h"
@@ -20,6 +21,7 @@
        "Quota exceeded (mailbox for user is full)"
 #define RULE_NAME_DEFAULT_FORCE "*"
 #define RULE_NAME_DEFAULT_NONFORCE "?"
+#define QUOTA_LIMIT_SET_PATH DICT_PATH_PRIVATE"quota/limit/"
 
 struct quota_root_iter {
        struct quota *quota;
@@ -110,6 +112,26 @@ quota_root_add_warning_rules(struct mail_user *user, const char *root_name,
        return 0;
 }
 
+static int
+quota_root_parse_set(struct mail_user *user, const char *root_name,
+                    struct quota_root_settings *root_set,
+                    const char **error_r)
+{
+       const char *name, *value;
+
+       name = t_strconcat(root_name, "_set", NULL);
+       value = mail_user_plugin_getenv(user, name);
+       if (value == NULL)
+               return 0;
+
+       if (strncmp(value, "dict:", 5) != 0) {
+               *error_r = t_strdup_printf("%s supports only dict backend", name);
+               return -1;
+       }
+       root_set->limit_set = p_strdup(root_set->set->pool, value+5);
+       return 0;
+}
+
 static int
 quota_root_settings_init(struct quota_settings *quota_set, const char *root_def,
                         struct quota_root_settings **set_r,
@@ -182,6 +204,8 @@ quota_root_add(struct quota_settings *quota_set, struct mail_user *user,
                return -1;
        if (quota_root_parse_grace(user, root_name, root_set, error_r) < 0)
                return -1;
+       if (quota_root_parse_set(user, root_name, root_set, error_r) < 0)
+               return -1;
        return 0;
 }
 
@@ -246,6 +270,8 @@ static void quota_root_deinit(struct quota_root *root)
 {
        pool_t pool = root->pool;
 
+       if (root->limit_set_dict != NULL)
+               dict_deinit(&root->limit_set_dict);
        root->backend.v.deinit(root);
        pool_unref(&pool);
 }
@@ -972,15 +998,43 @@ int quota_get_resource(struct quota_root *root, const char *mailbox_name,
        return *limit_r == 0 ? 0 : 1;
 }
 
-int quota_set_resource(struct quota_root *root ATTR_UNUSED,
-                      const char *name ATTR_UNUSED,
-                      uint64_t value ATTR_UNUSED, const char **error_r)
+int quota_set_resource(struct quota_root *root, const char *name,
+                      uint64_t value, const char **error_r)
 {
-       /* the quota information comes from userdb (or even config file),
-          so there's really no way to support this until some major changes
-          are done */
-       *error_r = MAIL_ERRSTR_NO_PERMISSION;
-       return -1;
+       struct dict_transaction_context *trans;
+       const char *key;
+
+       if (root->set->limit_set == NULL) {
+               *error_r = MAIL_ERRSTR_NO_PERMISSION;
+               return -1;
+       }
+       if (strcasecmp(name, QUOTA_NAME_STORAGE_KILOBYTES) == 0)
+               key = "storage";
+       else if (strcasecmp(name, QUOTA_NAME_STORAGE_BYTES) == 0)
+               key = "bytes";
+       else if (strcasecmp(name, QUOTA_NAME_MESSAGES) == 0)
+               key = "messages";
+       else {
+               *error_r = t_strdup_printf("Unsupported resource name: %s", name);
+               return -1;
+       }
+
+       if (root->limit_set_dict == NULL) {
+               if (dict_init(root->set->limit_set, DICT_DATA_TYPE_STRING,
+                             root->quota->user->username,
+                             root->quota->user->set->base_dir,
+                             &root->limit_set_dict, error_r) < 0)
+                       return -1;
+       }
+
+       trans = dict_transaction_begin(root->limit_set_dict);
+       key = t_strdup_printf(QUOTA_LIMIT_SET_PATH"%s", key);
+       dict_set(trans, key, dec2str(value));
+       if (dict_transaction_commit(&trans) < 0) {
+               *error_r = "Internal quota limit update error";
+               return -1;
+       }
+       return 0;
 }
 
 struct quota_transaction_context *quota_transaction_begin(struct mailbox *box)