264 lines
7.7 KiB
Diff
264 lines
7.7 KiB
Diff
|
http://dovecot.org/list/dovecot/2007-April/021429.html
|
||
|
|
||
|
diff -ru dovecot-1.0.rc27.orig/src/plugins/quota/quota-plugin.c dovecot-1.0.rc27/src/plugins/quota/quota-plugin.c
|
||
|
--- dovecot-1.0.rc27.orig/src/plugins/quota/quota-plugin.c 2007-03-06 17:34:47.000000000 +0100
|
||
|
+++ dovecot-1.0.rc27/src/plugins/quota/quota-plugin.c 2007-03-31 22:18:55.000000000 +0200
|
||
|
@@ -21,9 +21,24 @@
|
||
|
|
||
|
env = getenv("QUOTA");
|
||
|
if (env != NULL) {
|
||
|
+ struct quota_setup *setup;
|
||
|
+ const char *name;
|
||
|
+ unsigned int i;
|
||
|
quota_set = quota_init();
|
||
|
/* Currently we support only one quota setup */
|
||
|
- (void)quota_setup_init(quota_set, env, TRUE);
|
||
|
+ setup = quota_setup_init(quota_set, env, TRUE);
|
||
|
+
|
||
|
+ name = "QUOTA_WARNING";
|
||
|
+ env = getenv(name);
|
||
|
+ i = 1;
|
||
|
+ t_push();
|
||
|
+ while (env != NULL) {
|
||
|
+ (void)quota_warning_init(setup, env);
|
||
|
+
|
||
|
+ name = t_strdup_printf("QUOTA_WARNING%u", ++i);
|
||
|
+ env = getenv(name);
|
||
|
+ }
|
||
|
+ t_pop();
|
||
|
|
||
|
quota_next_hook_mail_storage_created =
|
||
|
hook_mail_storage_created;
|
||
|
diff -ru dovecot-1.0.rc27.orig/src/plugins/quota/quota-private.h dovecot-1.0.rc27/src/plugins/quota/quota-private.h
|
||
|
--- dovecot-1.0.rc27.orig/src/plugins/quota/quota-private.h 2007-03-12 21:34:50.000000000 +0100
|
||
|
+++ dovecot-1.0.rc27/src/plugins/quota/quota-private.h 2007-03-17 00:06:23.000000000 +0100
|
||
|
@@ -22,6 +22,9 @@
|
||
|
/* List of quota roots. It's array because there shouldn't be many. */
|
||
|
array_t ARRAY_DEFINE(roots, struct quota_root *);
|
||
|
|
||
|
+ /* List of quota warnings. There should probably be few. */
|
||
|
+ array_t ARRAY_DEFINE(warnings, struct quota_warning *);
|
||
|
+
|
||
|
unsigned int user_root:1;
|
||
|
};
|
||
|
|
||
|
@@ -86,6 +89,21 @@
|
||
|
unsigned int idx;
|
||
|
};
|
||
|
|
||
|
+enum quota_warning_limit_kind {
|
||
|
+ QUOTA_WARNING_NO_LIMIT,
|
||
|
+ QUOTA_WARNING_PERCENT_LIMIT,
|
||
|
+ QUOTA_WARNING_ABSOLUTE_LIMIT
|
||
|
+};
|
||
|
+
|
||
|
+struct quota_warning {
|
||
|
+ struct quota_setup *setup;
|
||
|
+ uint64_t storage_limit;
|
||
|
+ unsigned int count_limit;
|
||
|
+ enum quota_warning_limit_kind storage_limit_kind:2;
|
||
|
+ enum quota_warning_limit_kind count_limit_kind:2;
|
||
|
+ char *command;
|
||
|
+};
|
||
|
+
|
||
|
struct quota_transaction_context {
|
||
|
array_t ARRAY_DEFINE(root_transactions,
|
||
|
struct quota_root_transaction_context *);
|
||
|
diff -ru dovecot-1.0.rc27.orig/src/plugins/quota/quota.c dovecot-1.0.rc27/src/plugins/quota/quota.c
|
||
|
--- dovecot-1.0.rc27.orig/src/plugins/quota/quota.c 2007-03-06 17:34:47.000000000 +0100
|
||
|
+++ dovecot-1.0.rc27/src/plugins/quota/quota.c 2007-03-31 22:35:22.000000000 +0200
|
||
|
@@ -6,6 +6,8 @@
|
||
|
#include "quota-private.h"
|
||
|
#include "quota-fs.h"
|
||
|
|
||
|
+#include <stdlib.h>
|
||
|
+
|
||
|
unsigned int quota_module_id = 0;
|
||
|
|
||
|
extern struct quota_backend quota_backend_dict;
|
||
|
@@ -59,6 +61,7 @@
|
||
|
setup->data = i_strdup(data);
|
||
|
setup->user_root = user_root;
|
||
|
ARRAY_CREATE(&setup->roots, default_pool, struct quota_root *, 4);
|
||
|
+ ARRAY_CREATE(&setup->warnings, default_pool, struct quota_warning *, 4);
|
||
|
|
||
|
t_push();
|
||
|
p = strchr(setup->data, ':');
|
||
|
@@ -107,6 +110,16 @@
|
||
|
}
|
||
|
|
||
|
array_free(&setup->roots);
|
||
|
+
|
||
|
+ while (array_count(&setup->warnings) > 0) {
|
||
|
+ struct quota_warning *const *warning;
|
||
|
+
|
||
|
+ warning = array_idx(&setup->warnings, 0);
|
||
|
+ quota_warning_deinit(*warning);
|
||
|
+ }
|
||
|
+
|
||
|
+ array_free(&setup->warnings);
|
||
|
+
|
||
|
i_free(setup->data);
|
||
|
i_free(setup);
|
||
|
}
|
||
|
@@ -157,6 +170,82 @@
|
||
|
array_free(&module_contexts);
|
||
|
}
|
||
|
|
||
|
+struct quota_warning *
|
||
|
+quota_warning_init(struct quota_setup *setup, const char *data)
|
||
|
+{
|
||
|
+ const char *p;
|
||
|
+ char *q;
|
||
|
+ const char *const *args;
|
||
|
+ unsigned long long val;
|
||
|
+ struct quota_warning *warning;
|
||
|
+
|
||
|
+ warning = i_new(struct quota_warning, 1);
|
||
|
+ warning->setup = setup;
|
||
|
+
|
||
|
+ p = strchr(data, ' ');
|
||
|
+ if (p == NULL)
|
||
|
+ i_fatal("quota warning: No command specified: %s", data);
|
||
|
+ warning->command = i_strdup(p+1);
|
||
|
+
|
||
|
+ t_push();
|
||
|
+
|
||
|
+ args = t_strsplit(t_strdup_until(data, p), ":");
|
||
|
+ for (; *args != '\0'; args++) {
|
||
|
+ if (strncmp(*args, "storage=", 8) == 0) {
|
||
|
+ val = strtoull(*args + 8, &q, 10);
|
||
|
+ if (q && (strcmp(q, "%") == 0)) {
|
||
|
+ warning->storage_limit = val;
|
||
|
+ warning->storage_limit_kind =
|
||
|
+ QUOTA_WARNING_PERCENT_LIMIT;
|
||
|
+ } else if (q && (strcmp(q, "k") == 0)) {
|
||
|
+ warning->storage_limit = val * 1024;
|
||
|
+ warning->storage_limit_kind =
|
||
|
+ QUOTA_WARNING_ABSOLUTE_LIMIT;
|
||
|
+ } else
|
||
|
+ i_error("quota warning: Malformed setting: %s", *args);
|
||
|
+ } else if (strncmp(*args, "messages=", 9) == 0) {
|
||
|
+ val = strtoull(*args + 8, &q, 10);
|
||
|
+ if (q && (strcmp(q, "%") == 0)) {
|
||
|
+ warning->count_limit = val;
|
||
|
+ warning->count_limit_kind =
|
||
|
+ QUOTA_WARNING_PERCENT_LIMIT;
|
||
|
+ } else if (q && (strcmp(q, "") == 0)) {
|
||
|
+ warning->count_limit = val;
|
||
|
+ warning->count_limit_kind =
|
||
|
+ QUOTA_WARNING_ABSOLUTE_LIMIT;
|
||
|
+ } else
|
||
|
+ i_error("quota warning: Malformed setting: %s", *args);
|
||
|
+ } else {
|
||
|
+ i_error("quota warning: Unknown setting: %s", *args);
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ t_pop();
|
||
|
+
|
||
|
+ array_append(&setup->warnings, &warning, 1);
|
||
|
+
|
||
|
+ return warning;
|
||
|
+}
|
||
|
+
|
||
|
+void quota_warning_deinit(struct quota_warning *warning)
|
||
|
+{
|
||
|
+ struct quota_warning *const *warnings;
|
||
|
+ unsigned int i, count;
|
||
|
+
|
||
|
+ /* remove from setup */
|
||
|
+ warnings = array_get(&warning->setup->warnings, &count);
|
||
|
+ for (i = 0; i < count; i++) {
|
||
|
+ if (warnings[i] == warning) {
|
||
|
+ array_delete(&warning->setup->warnings, i, 1);
|
||
|
+ break;
|
||
|
+ }
|
||
|
+ }
|
||
|
+ i_assert(i != count);
|
||
|
+
|
||
|
+ i_free(warning->command);
|
||
|
+ i_free(warning);
|
||
|
+}
|
||
|
+
|
||
|
void quota_add_user_storage(struct quota *quota, struct mail_storage *storage)
|
||
|
{
|
||
|
struct quota_setup *const *setups;
|
||
|
@@ -388,15 +477,62 @@
|
||
|
i_free(ctx);
|
||
|
}
|
||
|
|
||
|
+#define CHECK_PERCENT(val, cur, diff, limit) \
|
||
|
+ (100 * ((limit) - (cur) - (diff)) > (val) * (limit))
|
||
|
+#define CHECK_ABSOLUTE(val, cur, diff, limit) \
|
||
|
+ ((limit) - (cur) - (diff) > (val))
|
||
|
+
|
||
|
+#define CHECK2_PERCENT(val, cur, diff, size, limit) \
|
||
|
+ (CHECK_PERCENT(val, cur, diff, limit) \
|
||
|
+ && !CHECK_PERCENT(val, cur, (diff)+(size), limit))
|
||
|
+#define CHECK2_ABSOLUTE(val, cur, diff, size, limit) \
|
||
|
+ (CHECK_ABSOLUTE(val, cur, diff, limit) \
|
||
|
+ && !CHECK_ABSOLUTE(val, cur, (diff)+(size), limit))
|
||
|
+
|
||
|
+#define CHECK(kind, val, cur, diff, size, limit) \
|
||
|
+ ((((kind) == QUOTA_WARNING_PERCENT_LIMIT) \
|
||
|
+ && (CHECK2_PERCENT(val, cur, diff, size, limit))) \
|
||
|
+ || (((kind) == QUOTA_WARNING_ABSOLUTE_LIMIT) \
|
||
|
+ && (CHECK2_ABSOLUTE(val, cur, diff, size, limit))))
|
||
|
+
|
||
|
int quota_default_try_alloc_bytes(struct quota_root_transaction_context *ctx,
|
||
|
uoff_t size, bool *too_large_r)
|
||
|
{
|
||
|
+ struct quota_warning *const * warnings;
|
||
|
+ unsigned int i, count;
|
||
|
int ret;
|
||
|
|
||
|
ret = quota_default_test_alloc_bytes(ctx, size, too_large_r);
|
||
|
if (ret <= 0 || ctx->disabled)
|
||
|
return ret;
|
||
|
|
||
|
+ warnings = array_get(&ctx->root->setup->warnings, &count);
|
||
|
+
|
||
|
+ for (i = 0; i < count; i++) {
|
||
|
+ struct quota_warning *warning = warnings[i];
|
||
|
+ bool run_command = FALSE;
|
||
|
+
|
||
|
+ if (CHECK(warning->storage_limit_kind,
|
||
|
+ warning->storage_limit,
|
||
|
+ ctx->bytes_current,
|
||
|
+ ctx->bytes_diff,
|
||
|
+ size,
|
||
|
+ ctx->bytes_limit))
|
||
|
+ run_command = TRUE;
|
||
|
+
|
||
|
+ if (CHECK(warning->count_limit_kind,
|
||
|
+ warning->count_limit,
|
||
|
+ ctx->count_current,
|
||
|
+ ctx->count_diff,
|
||
|
+ 1,
|
||
|
+ ctx->count_limit))
|
||
|
+ run_command = TRUE;
|
||
|
+
|
||
|
+ if (run_command)
|
||
|
+ system(warning->command);
|
||
|
+
|
||
|
+ }
|
||
|
+
|
||
|
ctx->count_diff++;
|
||
|
ctx->bytes_diff += size;
|
||
|
return 1;
|
||
|
diff -ru dovecot-1.0.rc27.orig/src/plugins/quota/quota.h dovecot-1.0.rc27/src/plugins/quota/quota.h
|
||
|
--- dovecot-1.0.rc27.orig/src/plugins/quota/quota.h 2007-03-06 17:34:47.000000000 +0100
|
||
|
+++ dovecot-1.0.rc27/src/plugins/quota/quota.h 2007-03-16 23:21:33.000000000 +0100
|
||
|
@@ -31,6 +31,10 @@
|
||
|
quota_root_init(struct quota_setup *setup, const char *name);
|
||
|
void quota_root_deinit(struct quota_root *root);
|
||
|
|
||
|
+struct quota_warning *
|
||
|
+quota_warning_init(struct quota_setup *setup, const char *data);
|
||
|
+void quota_warning_deinit(struct quota_warning *warning);
|
||
|
+
|
||
|
/* List all quota roots. Returned quota roots are freed by quota_deinit(). */
|
||
|
struct quota_root_iter *quota_root_iter_init(struct mailbox *box);
|
||
|
struct quota_root *quota_root_iter_next(struct quota_root_iter *iter);
|