From: Timo Sirainen Date: Sat, 25 Jan 2025 20:56:17 +0000 (+0200) Subject: lib-settings, config: Use named (non-list) filter hierarchy length also for sorting... X-Git-Tag: 2.4.1~249 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e2a3a0a6915668a44750aa30b70fa39caf22be4a;p=thirdparty%2Fdovecot%2Fcore.git lib-settings, config: Use named (non-list) filter hierarchy length also for sorting overrides --- diff --git a/src/config/config-filter.h b/src/config/config-filter.h index ca0d37ee47..4d6186b697 100644 --- a/src/config/config-filter.h +++ b/src/config/config-filter.h @@ -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. */ diff --git a/src/config/config-parser.c b/src/config/config-parser.c index 5d928b295a..b644efeb8a 100644 --- a/src/config/config-parser.c +++ b/src/config/config-parser.c @@ -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; } diff --git a/src/lib-settings/settings.c b/src/lib-settings/settings.c index a66d51b3e2..5eaf5a3933 100644 --- a/src/lib-settings/settings.c +++ b/src/lib-settings/settings.c @@ -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.