From: Timo Sirainen Date: Fri, 28 Jul 2023 12:36:22 +0000 (+0300) Subject: lib-settings, config: Add support for SET_FILTER_HIERARCHY X-Git-Tag: 2.4.1~1431 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=1ca01d0f5867ac6fa0347fafa08c8ec488d2be0b;p=thirdparty%2Fdovecot%2Fcore.git lib-settings, config: Add support for SET_FILTER_HIERARCHY --- diff --git a/src/config/config-dump-full.c b/src/config/config-dump-full.c index 9664832043..7b307dd690 100644 --- a/src/config/config-dump-full.c +++ b/src/config/config-dump-full.c @@ -83,10 +83,22 @@ static int output_blob_size(struct ostream *output, uoff_t blob_size_offset) return 0; } +static void +config_filter_write_hierarchical(string_t *str, + const struct config_filter *filter) +{ + if (filter == NULL || !filter->filter_hierarchical) + return; + if (str_len(str) > 0) + str_append_c(str, '/'); + str_append(str, filter->filter_name); + config_filter_write_hierarchical(str, filter->parent); +} + static void config_dump_full_append_filter_query(string_t *str, const struct config_filter *filter, - bool leaf) + bool leaf, bool parent_hierarchical) { if (filter->service != NULL) { if (filter->service[0] != '!') { @@ -131,8 +143,23 @@ config_dump_full_append_filter_query(string_t *str, } str_append(str, " AND "); } else if (filter->filter_name != NULL) { + const char *filter_name = filter->filter_name; + + if (!parent_hierarchical && + filter->filter_hierarchical && + filter->parent->filter_hierarchical) { + /* beginning of a hierarchical filter. */ + string_t *str = t_str_new(128); + config_filter_write_hierarchical(str, filter); + filter_name = str_c(str); + } else if (parent_hierarchical && + filter->filter_hierarchical) { + /* hierarchical filter was already written. */ + return; + } + str_printfa(str, SETTINGS_EVENT_FILTER_NAME"=\"%s\" AND ", - wildcard_str_escape(filter->filter_name)); + wildcard_str_escape(filter_name)); } } @@ -141,10 +168,13 @@ config_dump_full_append_filter(string_t *str, const struct config_filter *filter) { bool leaf = TRUE; + bool parent_hierarchical = FALSE; do { - config_dump_full_append_filter_query(str, filter, leaf); + config_dump_full_append_filter_query(str, filter, leaf, + parent_hierarchical); leaf = FALSE; + parent_hierarchical = filter->filter_hierarchical; filter = filter->parent; } while (filter != NULL); diff --git a/src/config/config-filter.h b/src/config/config-filter.h index c63806ac5e..04b0dbb1d1 100644 --- a/src/config/config-filter.h +++ b/src/config/config-filter.h @@ -18,6 +18,10 @@ struct config_filter { /* named_filter { .. } */ const char *filter_name; bool filter_name_array; + /* This filter is hierarchical. If a child event is also hierarchical, + their filter_names will be merged into one filter path when dumping + the config. */ + bool filter_hierarchical; }; struct config_filter_parser { diff --git a/src/config/config-parser.c b/src/config/config-parser.c index dfacd8e893..f1d176e167 100644 --- a/src/config/config-parser.c +++ b/src/config/config-parser.c @@ -411,6 +411,7 @@ settings_value_check(struct config_parser_context *ctx, case SET_FILTER_ARRAY: break; case SET_FILTER_NAME: + case SET_FILTER_HIERARCHY: ctx->error = p_strdup_printf(ctx->pool, "Setting is a named filter, use '%s {'", def->key); return -1; @@ -432,7 +433,9 @@ config_is_filter_name(struct config_parser_context *ctx, const char *key, return FALSE; def = &all_infos[config_key->info_idx]->defines[config_key->define_idx]; - if (def->type != SET_FILTER_NAME && def->type != SET_FILTER_ARRAY) + if (def->type != SET_FILTER_NAME && + def->type != SET_FILTER_HIERARCHY && + def->type != SET_FILTER_ARRAY) return FALSE; *def_r = def; @@ -636,7 +639,8 @@ int config_apply_line(struct config_parser_context *ctx, break; struct config_module_parser *l = &ctx->cur_section->module_parsers[config_key->info_idx]; - if (l->info->defines[config_key->define_idx].type != SET_FILTER_NAME) + if (l->info->defines[config_key->define_idx].type != SET_FILTER_NAME && + l->info->defines[config_key->define_idx].type != SET_FILTER_HIERARCHY) break; ctx->cur_section->filter.filter_name = @@ -926,20 +930,16 @@ config_filter_add_new_filter(struct config_parser_context *ctx, else filter->remote_host = p_strdup(ctx->pool, value); } else if (config_is_filter_name(ctx, key, &filter_def)) { - if (filter_def->type == SET_FILTER_NAME) { + if (filter_def->type == SET_FILTER_NAME || + filter_def->type == SET_FILTER_HIERARCHY) { if (value[0] != '\0' || line->value_quoted) { ctx->error = p_strdup_printf(ctx->pool, "%s { } must not have a section name", key); return TRUE; } - if (parent->filter_name != NULL && - !parent->filter_name_array) { - ctx->error = p_strdup_printf(ctx->pool, - "Nested named filters not allowed: %s { %s { .. } }", - parent->filter_name, key); - return FALSE; - } + if (filter_def->type == SET_FILTER_HIERARCHY) + filter->filter_hierarchical = TRUE; filter->filter_name = p_strdup(ctx->pool, key); } else { if (parent->filter_name != NULL && diff --git a/src/config/config-request.c b/src/config/config-request.c index 5ac12c518d..78be50b9be 100644 --- a/src/config/config-request.c +++ b/src/config/config-request.c @@ -312,6 +312,7 @@ settings_export(struct config_export_context *ctx, break; } case SET_FILTER_NAME: + case SET_FILTER_HIERARCHY: case SET_ALIAS: break; } diff --git a/src/lib-settings/settings-parser.c b/src/lib-settings/settings-parser.c index 3272c0b2b8..cc5b9413ec 100644 --- a/src/lib-settings/settings-parser.c +++ b/src/lib-settings/settings-parser.c @@ -557,6 +557,7 @@ settings_parse(struct setting_parser_context *ctx, break; } case SET_FILTER_NAME: + case SET_FILTER_HIERARCHY: settings_parser_set_error(ctx, t_strdup_printf( "Setting is a named filter, use '%s {'", key)); return -1; @@ -575,7 +576,8 @@ settings_find_key(struct setting_parser_context *ctx, const char *key, /* try to find the exact key */ def = setting_define_find(ctx->info, key); - if (def != NULL && (def->type != SET_FILTER_NAME || + if (def != NULL && ((def->type != SET_FILTER_NAME && + def->type != SET_FILTER_HIERARCHY) || allow_filter_name)) { *def_r = def; return TRUE; diff --git a/src/lib-settings/settings-parser.h b/src/lib-settings/settings-parser.h index e79dd2fe0f..9e10e9f151 100644 --- a/src/lib-settings/settings-parser.h +++ b/src/lib-settings/settings-parser.h @@ -34,6 +34,7 @@ enum setting_type { SET_BOOLLIST, /* of type ARRAY_TYPE(const_string) - guaranteed NULL-terminted */ SET_ALIAS, /* alias name for above setting definition */ SET_FILTER_NAME, + SET_FILTER_HIERARCHY, SET_FILTER_ARRAY, }; enum setting_flags { diff --git a/src/lib-settings/settings.c b/src/lib-settings/settings.c index 25ec46d21d..30ba8915fb 100644 --- a/src/lib-settings/settings.c +++ b/src/lib-settings/settings.c @@ -1042,6 +1042,25 @@ settings_override_filter_match(struct settings_apply_ctx *ctx, str_printfa(filter_string, SETTINGS_EVENT_FILTER_NAME"=\"%s\"", wildcard_str_escape(last_filter_key)); break; + case SET_FILTER_HIERARCHY: { + /* add the full repeated hierarchy here */ + const char *next; + + str_printfa(filter_string, SETTINGS_EVENT_FILTER_NAME"=\"%s", + wildcard_str_escape(part)); + while (str_begins(p + 1, part, &next) && + next[0] == SETTINGS_SEPARATOR) { + str_append_c(filter_string, '/'); + str_append(filter_string, + wildcard_str_escape(part)); + p = next; + } + str_append_c(filter_string, '"'); + + last_filter_key = t_strdup_until(set->key, p); + last_filter_value = NULL; + break; + } case SET_FILTER_ARRAY: { const char *value = p + 1; p = strchr(value, SETTINGS_SEPARATOR); @@ -1372,6 +1391,8 @@ settings_get_full(struct event *event, filter_name_required = TRUE; } else if (filter_key != NULL) { filter_name = filter_key; + event_strlist_append(lookup_event, SETTINGS_EVENT_FILTER_NAME, + filter_name); filter_name_required = TRUE; }