]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-settings, config: Use named (non-list) filter hierarchy length also for sorting...
authorTimo Sirainen <timo.sirainen@open-xchange.com>
Sat, 25 Jan 2025 20:56:17 +0000 (22:56 +0200)
committerAki Tuomi <aki.tuomi@open-xchange.com>
Wed, 12 Feb 2025 10:34:16 +0000 (12:34 +0200)
src/config/config-filter.h
src/config/config-parser.c
src/lib-settings/settings.c

index ca0d37ee4756862538ef92d2f898fdcba7198084..4d6186b6977ad961dc734533701183a25b5a5923 100644 (file)
@@ -45,6 +45,9 @@ struct config_filter_parser {
        /* Number of filters in this parser and parent parsers that have
           filter.filter_name_array=TRUE. */
        unsigned int named_list_filter_count;
+       /* Number of filters in this parser that have non-NULL
+          filter.filter_name and filter.filter_name_array=FALSE. */
+       unsigned int named_filter_count;
 
        /* Filter parser tree. These are used only for doveconf's human output
           to write the filters in nice nested hierarchies. */
index 5d928b295ad4e22e4d21a4f72d51c996084756e6..b644efeb8a6ac354cec9ad406d71f2e418103fc2 100644 (file)
@@ -1084,8 +1084,13 @@ config_add_new_parser(struct config_parser_context *ctx,
        if (parent_filter_parser != NULL) {
                filter_parser->parent = parent_filter_parser;
                filter_parser->named_list_filter_count =
-                       parent_filter_parser->named_list_filter_count +
-                       (filter->filter_name_array ? 1 : 0);
+                       parent_filter_parser->named_list_filter_count;
+               filter_parser->named_filter_count =
+                       parent_filter_parser->named_filter_count;
+               if (filter->filter_name_array)
+                       filter_parser->named_list_filter_count++;
+               else if (filter->filter_name != NULL)
+                       filter_parser->named_filter_count++;
                DLLIST2_APPEND(&parent_filter_parser->children_head,
                               &parent_filter_parser->children_tail,
                               filter_parser);
@@ -2253,6 +2258,12 @@ static int config_parser_filter_cmp(struct config_filter_parser *const *f1,
        if (ret != 0)
                return ret;
 
+       /* After sorting by named list filter hierarchy count, sort by
+          named non-list filter hierarchy count. */
+       ret = (int)(*f1)->named_filter_count - (int)(*f2)->named_filter_count;
+       if (ret != 0)
+               return ret;
+
        /* Finally, just order them in the order of creation. */
        return (int)(*f1)->create_order - (int)(*f2)->create_order;
 }
index a66d51b3e28bd30e44b50d40981cee7be7909a9a..5eaf5a3933f40180e6f595560ef0035ff1ee293f 100644 (file)
@@ -46,6 +46,8 @@ struct settings_override {
        unsigned int path_element_count;
        /* Number of named list filter elements in this override */
        unsigned int filter_array_element_count;
+       /* Number of named (non-list) filter elements in this override */
+       unsigned int filter_element_count;
        /* key += value is used, i.e. append this value to existing value */
        bool append;
        /* TRUE once all the filter elements have been processed in "key",
@@ -1505,14 +1507,25 @@ settings_apply_override_cmp(const struct settings_apply_override *set1,
        /* We want to sort the override similarly to filters in binary config,
           i.e. primarily based on named list filter hierarchy length. This way
           for example userdb namespace/inbox/mailbox/trash/auto is handled
-          before -o mailbox/trash/auto CLI override. Only secondarily when the
-          hierarchy lengths are equal, the override type determines the
-          order. */
+          before -o mailbox/trash/auto CLI override. */
        int ret = (int)set2->set->filter_array_element_count -
                (int)set1->set->filter_array_element_count;
        if (ret != 0)
                return ret;
 
+       /* Sort by the number of named (non-list) filters. Do this only if
+          both overrides have named [list] filters, because we want e.g.
+          -o mail_path to override the default sdbox/mail_path. */
+       if (set1->set->filter_array_element_count > 0 ||
+           (set1->set->filter_element_count > 0 &&
+            set1->set->filter_element_count > 0)) {
+               ret = (int)set2->set->filter_element_count -
+                       (int)set1->set->filter_element_count;
+               if (ret != 0)
+                       return ret;
+       }
+
+       /* Next, the override type determines the order. */
        ret = (int)set2->set->type - (int)set1->set->type;
        if (ret != 0)
                return ret;
@@ -1647,6 +1660,7 @@ settings_override_filter_match(struct settings_apply_ctx *ctx,
                        event_strlist_append(set->filter_event,
                                             SETTINGS_EVENT_FILTER_NAME,
                                             last_filter_key);
+                       set->filter_element_count++;
                        break;
                case SET_FILTER_ARRAY: {
                        const char *value = p + 1;
@@ -1796,6 +1810,8 @@ settings_instance_override_add_default(struct settings_apply_ctx *ctx,
                set->path_element_count = path_element_count(set->orig_key);
                set->filter_array_element_count =
                        array_set->filter_array_element_count;
+               set->filter_element_count =
+                       array_set->filter_element_count;
                set->value = p_strdup(set->pool, items[i]);
 
                /* Get the final key we want to use in the event filter.