From: Timo Sirainen Date: Fri, 22 Nov 2024 10:31:23 +0000 (+0200) Subject: lib-settings, config: Allow clearing out strlist settings with "key=" X-Git-Tag: 2.4.0~229 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=119794816745b3430f630d302d33f70f01f7d07c;p=thirdparty%2Fdovecot%2Fcore.git lib-settings, config: Allow clearing out strlist settings with "key=" If a non-empty value is given, it's an error. --- diff --git a/src/config/config-dump-full.c b/src/config/config-dump-full.c index 005222b911..ff67ddc76a 100644 --- a/src/config/config-dump-full.c +++ b/src/config/config-dump-full.c @@ -264,8 +264,9 @@ config_dump_full_stdout_callback(const struct config_export_setting *set, if (set->type != CONFIG_KEY_LIST) ; else if (set->list_count == 0 && set->value_stop_list && - set->def_type == SET_BOOLLIST) { - /* filter empties a boollist setting */ + (set->def_type == SET_BOOLLIST || + set->def_type == SET_STRLIST)) { + /* filter empties a boollist/strlist setting */ } else { /* these aren't needed */ return; @@ -297,7 +298,7 @@ config_dump_full_stdout_callback(const struct config_export_setting *set, o_stream_nsend_str(ctx->output, "="); o_stream_nsend_str(ctx->output, str_tabescape(set->value)); if (set->value_stop_list) - o_stream_nsend_str(ctx->output, " # stop boollist"); + o_stream_nsend_str(ctx->output, " # stop list"); o_stream_nsend_str(ctx->output, "\n"); } T_END; } @@ -346,8 +347,9 @@ static void config_dump_full_callback(const struct config_export_setting *set, if (set->type != CONFIG_KEY_LIST) ; else if (set->list_count == 0 && set->value_stop_list && - set->def_type == SET_BOOLLIST) { - /* filter empties a boollist setting */ + (set->def_type == SET_BOOLLIST || + set->def_type == SET_STRLIST)) { + /* filter empties a boollist/strlist setting */ } else { /* these aren't needed */ return; diff --git a/src/config/config-parser.c b/src/config/config-parser.c index 24dad6dcec..71e2874fe8 100644 --- a/src/config/config-parser.c +++ b/src/config/config-parser.c @@ -560,12 +560,26 @@ config_array_add_defaults(struct config_parser_context *ctx, static int config_apply_strlist(struct config_parser_context *ctx, const char *key, const char *value, struct config_parser_key *config_key, - ARRAY_TYPE(const_string) **strlistp) + ARRAY_TYPE(const_string) **strlistp, + bool *stop_list) { const char *suffix; suffix = strchr(key, SETTINGS_SEPARATOR); if (suffix == NULL) { + if (value[0] == '\0') { + /* clear out the whole strlist */ + if (*strlistp != NULL) + array_clear(*strlistp); + else { + *strlistp = p_new(ctx->pool, + ARRAY_TYPE(const_string), 1); + p_array_init(*strlistp, ctx->pool, 5); + } + *stop_list = TRUE; + return 0; + } + ctx->error = p_strdup_printf(ctx->pool, "Setting is a string list, use '%s {'", key); return -1; @@ -616,7 +630,7 @@ static int config_apply_boollist(struct config_parser_context *ctx, list within the same filter, and the previous setting might have wanted to stop the list already. */ return config_apply_strlist(ctx, key, value, config_key, - strlistp); + strlistp, stop_list); } /* replace the whole list */ @@ -735,7 +749,8 @@ config_apply_exact_line(struct config_parser_context *ctx, switch (l->info->defines[config_key->define_idx].type) { case SET_STRLIST: if (config_apply_strlist(ctx, key, value, config_key, - &l->settings[config_key->define_idx].array.values) < 0) + &l->settings[config_key->define_idx].array.values, + &l->settings[config_key->define_idx].array.stop_list) < 0) return -1; break; case SET_BOOLLIST: @@ -1335,6 +1350,8 @@ void config_fill_set_parser(struct setting_parser_context *parser, switch (p->info->defines[i].type) { case SET_STRLIST: case SET_BOOLLIST: { + if (p->settings[i].array.values == NULL) + break; unsigned int j, count; const char *const *strings = array_get(p->settings[i].array.values, &count); diff --git a/src/config/doveconf.c b/src/config/doveconf.c index 935f139d47..0c9aaeb6fd 100644 --- a/src/config/doveconf.c +++ b/src/config/doveconf.c @@ -88,12 +88,16 @@ config_request_get_strings(const struct config_export_setting *set, set->list_idx, p + 1, set->value); break; case CONFIG_KEY_LIST: - if (set->list_count == 0 && set->def_type == SET_BOOLLIST) { + if (set->list_count == 0 && + (set->def_type == SET_BOOLLIST || + set->def_type == SET_STRLIST)) { /* empty deflist - show as an empty string */ value = p_strdup_printf(ctx->pool, "%s=", set->key); break; } - if (set->value_stop_list && set->def_type == SET_BOOLLIST) { + if (set->value_stop_list && + (set->def_type == SET_BOOLLIST || + set->def_type == SET_STRLIST)) { value = p_strdup_printf(ctx->pool, "%s=", set->key); array_push_back(&ctx->strings, &value); } diff --git a/src/lib-settings/settings-parser.c b/src/lib-settings/settings-parser.c index fe4623693b..c5e8941b0e 100644 --- a/src/lib-settings/settings-parser.c +++ b/src/lib-settings/settings-parser.c @@ -338,19 +338,37 @@ int settings_parse_read_file(const char *path, const char *value_path, return 0; } -static void +static int settings_parse_strlist(struct setting_parser_context *ctx, ARRAY_TYPE(const_string) *array, - const char *key, const char *value) + const char *key, const char *value, const char **error_r) { const char *const *items; const char *vkey, *vvalue; unsigned int i, count; - key = strchr(key, SETTINGS_SEPARATOR); - if (key == NULL) - return; - key = settings_section_unescape(key + 1); + /* If the next element after the visible array is set_array_stop, then + the strlist should not be modified any further. */ + if (array_is_created(array)) { + items = array_get(array, &count); + if (items[count] == set_array_stop) + return 0; + } + + const char *suffix = strchr(key, SETTINGS_SEPARATOR); + if (suffix == NULL) { + if (value[0] == '\0') { + /* clear out the whole strlist */ + if (array_is_created(array)) + array_clear(array); + return 0; + } + + *error_r = t_strdup_printf( + "Setting is a string list, use %s/key=value'", key); + return -1; + } + key = settings_section_unescape(suffix + 1); vvalue = p_strdup(ctx->set_pool, value); if (!array_is_created(array)) @@ -361,13 +379,14 @@ settings_parse_strlist(struct setting_parser_context *ctx, for (i = 0; i < count; i += 2) { if (strcmp(items[i], key) == 0) { array_idx_set(array, i + 1, &vvalue); - return; + return 0; } } vkey = p_strdup(ctx->set_pool, key); array_push_back(array, &vkey); array_push_back(array, &vvalue); + return 0; } int settings_parse_boollist_string(const char *value, pool_t pool, @@ -687,8 +706,13 @@ settings_parse(struct setting_parser_context *ctx, break; case SET_STRLIST: T_BEGIN { - settings_parse_strlist(ctx, ptr, key, value); + ret = settings_parse_strlist(ctx, ptr, key, value, + &error); + if (ret < 0) + settings_parser_set_error(ctx, error); } T_END; + if (ret < 0) + return -1; break; case SET_BOOLLIST: T_BEGIN { @@ -822,7 +846,8 @@ void settings_parse_array_stop(struct setting_parser_context *ctx, unsigned int key_idx) { i_assert(ctx->info->defines[key_idx].type == SET_FILTER_ARRAY || - ctx->info->defines[key_idx].type == SET_BOOLLIST); + ctx->info->defines[key_idx].type == SET_BOOLLIST || + ctx->info->defines[key_idx].type == SET_STRLIST); ARRAY_TYPE(const_string) *arr = PTR_OFFSET(ctx->set_struct, ctx->info->defines[key_idx].offset);