dovecot-2.2: quota: Added support for SETQUOTA IMAP command.

dovecot at dovecot.org dovecot at dovecot.org
Sun Dec 8 21:26:49 EET 2013


details:   http://hg.dovecot.org/dovecot-2.2/rev/fa84a2cd1dce
changeset: 17046:fa84a2cd1dce
user:      Timo Sirainen <tss at iki.fi>
date:      Sun Dec 08 21:26:29 2013 +0200
description:
quota: Added support for SETQUOTA IMAP command.
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).

diffstat:

 src/plugins/imap-quota/imap-quota-plugin.c |   5 ++
 src/plugins/quota/quota-private.h          |   2 +
 src/plugins/quota/quota.c                  |  70 ++++++++++++++++++++++++++---
 3 files changed, 69 insertions(+), 8 deletions(-)

diffs (150 lines):

diff -r 51edc7daf7f0 -r fa84a2cd1dce src/plugins/imap-quota/imap-quota-plugin.c
--- a/src/plugins/imap-quota/imap-quota-plugin.c	Sun Dec 08 21:24:10 2013 +0200
+++ b/src/plugins/imap-quota/imap-quota-plugin.c	Sun Dec 08 21:26:29 2013 +0200
@@ -186,6 +186,11 @@
 		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) ||
diff -r 51edc7daf7f0 -r fa84a2cd1dce src/plugins/quota/quota-private.h
--- a/src/plugins/quota/quota-private.h	Sun Dec 08 21:24:10 2013 +0200
+++ b/src/plugins/quota/quota-private.h	Sun Dec 08 21:26:29 2013 +0200
@@ -88,6 +88,7 @@
 	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_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. */
diff -r 51edc7daf7f0 -r fa84a2cd1dce src/plugins/quota/quota.c
--- a/src/plugins/quota/quota.c	Sun Dec 08 21:24:10 2013 +0200
+++ b/src/plugins/quota/quota.c	Sun Dec 08 21:26:29 2013 +0200
@@ -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;
@@ -111,6 +113,26 @@
 }
 
 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,
 			 const char **error_r)
@@ -182,6 +204,8 @@
 		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 @@
 {
 	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 @@
 	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)


More information about the dovecot-cvs mailing list