]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-settings, config: Allow clearing out strlist settings with "key="
authorTimo Sirainen <timo.sirainen@open-xchange.com>
Fri, 22 Nov 2024 10:31:23 +0000 (12:31 +0200)
committerAki Tuomi <aki.tuomi@open-xchange.com>
Fri, 17 Jan 2025 08:40:01 +0000 (10:40 +0200)
If a non-empty value is given, it's an error.

src/config/config-dump-full.c
src/config/config-parser.c
src/config/doveconf.c
src/lib-settings/settings-parser.c

index 005222b911b0a86a79e940dd806b8e8b57566579..ff67ddc76ac4e5c2c6165d8c298adb7999c0eecd 100644 (file)
@@ -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;
index 24dad6dcec7558b4147bdc5190c731d614e53fb6..71e2874fe8ea8efa1a300201fdf26725ace76699 100644 (file)
@@ -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);
index 935f139d47cfe63b3152646a0233dde76102e489..0c9aaeb6fd6e249a33e95dcb47a9282ac5eedb45 100644 (file)
@@ -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);
                }
index fe4623693b0e29ac12300c8281036a3075bee6ad..c5e8941b0e19667579d91925f9a3cec6aa6b6925 100644 (file)
@@ -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);