]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
quota: Convert initial set of quota plugin settings to global settings
authorTimo Sirainen <timo.sirainen@open-xchange.com>
Tue, 13 Aug 2024 11:47:52 +0000 (14:47 +0300)
committerAki Tuomi <aki.tuomi@open-xchange.com>
Fri, 17 Jan 2025 08:39:59 +0000 (10:39 +0200)
src/plugins/quota/Makefile.am
src/plugins/quota/quota-private.h
src/plugins/quota/quota-settings.c [new file with mode: 0644]
src/plugins/quota/quota-settings.h [new file with mode: 0644]
src/plugins/quota/quota-storage.c
src/plugins/quota/quota.c

index b739a899d70732e3968d55eae37e59c9dec75cf4..9070b824c8d18eb53eade3a51c4692414ed8b1ae 100644 (file)
@@ -38,6 +38,7 @@ quota_dist_sources = \
        quota-imapc.c \
        quota-maildir.c \
         quota-plugin.c \
+       quota-settings.c \
        quota-storage.c \
        quota-util.c
 
@@ -48,6 +49,7 @@ quota_common_objects = \
        quota-imapc.lo \
        quota-maildir.lo \
         quota-plugin.lo \
+       quota-settings.lo \
        quota-storage.lo \
        quota-util.lo \
        $(RQUOTA_XDR_LO)
@@ -116,7 +118,8 @@ pkginc_lib_HEADERS = \
        quota.h \
        quota-fs.h \
        quota-plugin.h \
-       quota-private.h
+       quota-private.h \
+       quota-settings.h
 noinst_HEADERS = \
        quota-status-settings.h
 
index 0c71081ad0f331cea436f54a08408ca28fda6883..23f1f85ad04c38f07ce50396137626dba60db6fa 100644 (file)
@@ -4,6 +4,7 @@
 #include "mail-storage-private.h"
 #include "mail-namespace.h"
 #include "quota.h"
+#include "quota-settings.h"
 
 /* Modules should use do "my_id = quota_module_id++" and
    use quota_module_contexts[id] for their own purposes. */
@@ -28,11 +29,6 @@ struct quota_legacy_settings {
        pool_t pool;
 
        ARRAY(struct quota_root_settings *) root_sets;
-
-       unsigned int max_mailbox_count;
-       uoff_t max_mail_size;
-       unsigned int max_messages_per_mailbox;
-       const char *quota_exceeded_msg;
 };
 
 struct quota_rule {
@@ -163,6 +159,8 @@ struct quota_transaction_context {
        struct quota *quota;
        struct mailbox *box;
 
+       const struct quota_settings *set;
+
        int64_t bytes_used, count_used;
        /* how many bytes/mails can be saved until limit is reached.
           (set once, not updated by bytes_used/count_used).
diff --git a/src/plugins/quota/quota-settings.c b/src/plugins/quota/quota-settings.c
new file mode 100644 (file)
index 0000000..79c7aad
--- /dev/null
@@ -0,0 +1,42 @@
+/* Copyright (c) 2024 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "settings-parser.h"
+#include "quota-settings.h"
+
+#undef DEF
+#define DEF(type, name) \
+       SETTING_DEFINE_STRUCT_##type(#name, name, struct quota_settings)
+static const struct setting_define quota_setting_defines[] = {
+       DEF(UINT, quota_mailbox_count),
+       DEF(UINT, quota_mailbox_message_count),
+       DEF(SIZE, quota_mail_size),
+       DEF(STR, quota_exceeded_message),
+
+       SETTING_DEFINE_LIST_END
+};
+
+static const struct quota_settings quota_default_settings = {
+       .quota_mailbox_count = SET_UINT_UNLIMITED,
+       .quota_mail_size = SET_SIZE_UNLIMITED,
+       .quota_mailbox_message_count = SET_UINT_UNLIMITED,
+       .quota_exceeded_message = "Quota exceeded (mailbox for user is full)",
+};
+
+const struct setting_parser_info quota_setting_parser_info = {
+       .name = "quota",
+       .defines = quota_setting_defines,
+       .defaults = &quota_default_settings,
+       .struct_size = sizeof(struct quota_settings),
+       .pool_offset1 = 1 + offsetof(struct quota_settings, pool),
+};
+
+struct quota_settings *quota_get_unlimited_set(void)
+{
+       static struct quota_settings set;
+       if (set.pool == NULL) {
+               set = quota_default_settings;
+               set.pool = null_pool;
+       }
+       return &set;
+}
diff --git a/src/plugins/quota/quota-settings.h b/src/plugins/quota/quota-settings.h
new file mode 100644 (file)
index 0000000..72e66ec
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef QUOTA_SETTINGS_H
+#define QUOTA_SETTINGS_H
+
+struct quota_settings {
+       pool_t pool;
+
+       unsigned int quota_mailbox_count;
+       uoff_t quota_mail_size;
+       unsigned int quota_mailbox_message_count;
+       const char *quota_exceeded_message;
+};
+
+struct quota_settings *quota_get_unlimited_set(void);
+
+extern const struct setting_parser_info quota_setting_parser_info;
+
+#endif
index e3ed4f7b4efa8776183c9601d61bf5153d11987a..f379fc23345f0015109b0259713d76ff6de60408 100644 (file)
@@ -3,6 +3,7 @@
 #include "lib.h"
 #include "array.h"
 #include "istream.h"
+#include "settings.h"
 #include "mail-search-build.h"
 #include "mail-storage-private.h"
 #include "mailbox-list-private.h"
@@ -121,12 +122,19 @@ quota_create_box(struct mailbox *box, const struct mailbox_update *update,
                 bool directory)
 {
        struct quota_mailbox *qbox = QUOTA_CONTEXT_REQUIRE(box);
-       struct quota_user *quser =
-               QUOTA_USER_CONTEXT_REQUIRE(box->storage->user);
-       struct quota_legacy_settings *quota_set = quser->quota->set;
+       const struct quota_settings *set;
        unsigned int mailbox_count;
+       const char *error;
+
+       if (settings_get(box->event, &quota_setting_parser_info, 0,
+                        &set, &error) < 0) {
+               mailbox_set_critical(box, "%s", error);
+               return -1;
+       }
+       unsigned int quota_mailbox_count = set->quota_mailbox_count;
+       settings_free(set);
 
-       if (quota_set->max_mailbox_count == 0) {
+       if (quota_mailbox_count == SET_UINT_UNLIMITED) {
                /* no mailbox count limit */
        } else if (mailbox_is_autocreated(box)) {
                /* Always allow autocreated mailbox to be created.
@@ -134,7 +142,7 @@ quota_create_box(struct mailbox *box, const struct mailbox_update *update,
        } else if (mailbox_list_get_count(box->list, &mailbox_count) < 0) {
                mail_storage_copy_list_error(box->storage, box->list);
                return -1;
-       } else if (mailbox_count >= quota_set->max_mailbox_count) {
+       } else if (mailbox_count >= quota_mailbox_count) {
                mail_storage_set_error(box->storage, MAIL_ERROR_LIMIT,
                                       "Maximum number of mailboxes reached");
                return -1;
index b5a10329d946fd7b29d6093407558ce66fb875b4..9275167e1e0c9f6a2fe04bfdc851f01fa1ca72e3 100644 (file)
@@ -9,6 +9,7 @@
 #include "write-full.h"
 #include "eacces-error.h"
 #include "wildcard-match.h"
+#include "settings.h"
 #include "mailbox-list-private.h"
 #include "quota-private.h"
 #include "quota-fs.h"
@@ -18,9 +19,6 @@
 
 #include <sys/wait.h>
 
-#define DEFAULT_QUOTA_EXCEEDED_MSG \
-       "Quota exceeded (mailbox for user is full)"
-
 /* How many seconds after the userdb lookup do we still want to execute the
    quota_over_script. This applies to quota_over_flag_lazy_check=yes and also
    after unhibernating IMAP connections. */
@@ -264,7 +262,7 @@ const char *quota_alloc_result_errstr(enum quota_alloc_result res,
                       "server configuration";
        case QUOTA_ALLOC_RESULT_OVER_QUOTA_LIMIT:
        case QUOTA_ALLOC_RESULT_OVER_QUOTA:
-               return qt->quota->set->quota_exceeded_msg;
+               return qt->set->quota_exceeded_message;
        case QUOTA_ALLOC_RESULT_OVER_QUOTA_MAILBOX_LIMIT:
                return "Too many messages in the mailbox";
        }
@@ -284,46 +282,6 @@ int quota_user_read_settings(struct mail_user *user,
        pool = pool_alloconly_create("quota settings", 2048);
        quota_set = p_new(pool, struct quota_legacy_settings, 1);
        quota_set->pool = pool;
-       quota_set->quota_exceeded_msg =
-               mail_user_plugin_getenv(user, "quota_exceeded_message");
-       if (quota_set->quota_exceeded_msg == NULL)
-               quota_set->quota_exceeded_msg = DEFAULT_QUOTA_EXCEEDED_MSG;
-
-       const char *mailbox_count =
-               mail_user_plugin_getenv(user, "quota_mailbox_count");
-       if (mailbox_count != NULL) {
-               if (str_to_uint(mailbox_count, &quota_set->max_mailbox_count) < 0) {
-                       *error_r = "Invalid quota_mailbox_count";
-                       event_unref(&quota_set->event);
-                       pool_unref(&pool);
-                       return -1;
-               }
-       }
-
-       const char *max_size = mail_user_plugin_getenv(user, "quota_mail_size");
-       if (max_size != NULL) {
-               const char *error = NULL;
-               if (str_parse_get_size(max_size, &quota_set->max_mail_size,
-                                      &error) < 0) {
-                       *error_r = t_strdup_printf("quota_max_mail_size: %s",
-                                       error);
-                       event_unref(&quota_set->event);
-                       pool_unref(&pool);
-                       return -1;
-               }
-       }
-
-       const char *max_box_count =
-               mail_user_plugin_getenv(user, "quota_mailbox_message_count");
-       if (max_box_count != NULL) {
-               if (str_to_uint(max_box_count,
-                               &quota_set->max_messages_per_mailbox) < 0) {
-                       *error_r = "Invalid quota_mailbox_message_count";
-                       event_unref(&quota_set->event);
-                       pool_unref(&pool);
-                       return -1;
-               }
-       }
 
        p_array_init(&quota_set->root_sets, pool, 4);
        if (i_strocpy(root_name, "quota", sizeof(root_name)) < 0)
@@ -867,6 +825,7 @@ struct quota_transaction_context *quota_transaction_begin(struct mailbox *box)
        if (box->storage->user->dsyncing) {
                /* ignore quota for dsync */
                ctx->limits_set = TRUE;
+               ctx->set = quota_get_unlimited_set();
        }
        return ctx;
 }
@@ -875,7 +834,6 @@ int quota_transaction_set_limits(struct quota_transaction_context *ctx,
                                 enum quota_get_result *error_result_r,
                                 const char **error_r)
 {
-       const struct quota_legacy_settings *set = ctx->quota->set;
        struct quota_root *const *roots;
        const char *mailbox_name, *error;
        unsigned int i, count;
@@ -891,6 +849,14 @@ int quota_transaction_set_limits(struct quota_transaction_context *ctx,
        use_grace = (ctx->box->flags & MAILBOX_FLAG_POST_SESSION) != 0;
        ctx->no_quota_updates = TRUE;
 
+       i_assert(ctx->set == NULL);
+       if (settings_get(ctx->box->event, &quota_setting_parser_info,
+                        0, &ctx->set, error_r) < 0) {
+               ctx->failed = TRUE;
+               *error_result_r = QUOTA_GET_RESULT_INTERNAL_ERROR;
+               return -1;
+       }
+
        /* find the lowest quota limits from all roots and use them */
        roots = array_get(&ctx->quota->roots, &count);
        for (i = 0; i < count; i++) {
@@ -973,17 +939,17 @@ int quota_transaction_set_limits(struct quota_transaction_context *ctx,
                }
        }
 
-       if (set->max_messages_per_mailbox != 0) {
+       if (ctx->set->quota_mailbox_message_count != SET_UINT_UNLIMITED) {
                struct mailbox_status status;
                mailbox_get_open_status(ctx->box, STATUS_MESSAGES, &status);
-               if (status.messages <= set->max_messages_per_mailbox) {
-                       diff = set->max_messages_per_mailbox - status.messages;
+               if (status.messages <= ctx->set->quota_mailbox_message_count) {
+                       diff = ctx->set->quota_mailbox_message_count - status.messages;
                        if (ctx->count_ceil > diff)
                                ctx->count_ceil = diff;
                } else {
                        /* over quota */
                        ctx->count_ceil = 0;
-                       diff = status.messages - set->max_messages_per_mailbox;
+                       diff = status.messages - ctx->set->quota_mailbox_message_count;
                        if (ctx->count_over < diff)
                                ctx->count_over = diff;
                }
@@ -1148,6 +1114,7 @@ int quota_transaction_commit(struct quota_transaction_context **_ctx)
                        quota_warnings_execute(ctx, *roots);
        } T_END;
 
+       settings_free(ctx->set);
        i_free(ctx);
        return ret;
 }
@@ -1266,6 +1233,7 @@ void quota_transaction_rollback(struct quota_transaction_context **_ctx)
        struct quota_transaction_context *ctx = *_ctx;
 
        *_ctx = NULL;
+       settings_free(ctx->set);
        i_free(ctx);
 }
 
@@ -1345,7 +1313,7 @@ enum quota_alloc_result quota_test_alloc(struct quota_transaction_context *ctx,
                return QUOTA_ALLOC_RESULT_TEMPFAIL;
        }
 
-       uoff_t max_size = ctx->quota->set->max_mail_size;
+       uoff_t max_size = ctx->set->quota_mail_size;
        if (max_size > 0 && size > max_size) {
                *error_r = t_strdup_printf(
                        "Requested allocation size %"PRIuUOFF_T" exceeds max "
@@ -1372,11 +1340,11 @@ static enum quota_alloc_result quota_default_test_alloc(
        if (!quota_transaction_is_over(ctx, size))
                return QUOTA_ALLOC_RESULT_OK;
 
-       if (ctx->quota->set->max_messages_per_mailbox != 0) {
+       if (ctx->set->quota_mailbox_message_count != SET_UINT_UNLIMITED) {
                struct mailbox_status status;
                mailbox_get_open_status(ctx->box, STATUS_MESSAGES, &status);
                unsigned int new_count = status.messages + ctx->count_used;
-               if (new_count >= ctx->quota->set->max_messages_per_mailbox)
+               if (new_count >= ctx->set->quota_mailbox_message_count)
                        return QUOTA_ALLOC_RESULT_OVER_QUOTA_MAILBOX_LIMIT;
        }