Use settings_section_[un]escape() for escaping.
config_dump_full_stdout_callback(const struct config_export_setting *set,
struct dump_context *ctx)
{
+ if (set->type == CONFIG_KEY_LIST) {
+ /* these aren't needed */
+ return;
+ }
+
if (!ctx->filter_written) {
string_t *str = t_str_new(128);
str_append(str, ":FILTER ");
ctx->filter_written = TRUE;
}
T_BEGIN {
- o_stream_nsend_str(ctx->output, t_strdup_printf(
- "%s=%s\n", set->key, str_tabescape(set->value)));
+ const struct setting_define *def =
+ &ctx->info->defines[set->key_define_idx];
+ if (def->type == SET_STRLIST || def->type == SET_BOOLLIST) {
+ const char *suffix;
+ if (!str_begins(set->key, def->key, &suffix) ||
+ suffix[0] != '/')
+ i_unreached();
+
+ suffix++;
+ o_stream_nsend_str(ctx->output,
+ t_strdup_until(set->key, suffix));
+ o_stream_nsend_str(ctx->output,
+ settings_section_escape(suffix));
+ } else {
+ o_stream_nsend_str(ctx->output, set->key);
+ }
+ o_stream_nsend_str(ctx->output, "=");
+ o_stream_nsend_str(ctx->output, str_tabescape(set->value));
+ o_stream_nsend_str(ctx->output, "\n");
} T_END;
}
suffix[0] != '/')
i_unreached();
else {
- suffix++;
+ suffix = settings_section_escape(suffix + 1);
o_stream_nsend(ctx->output, suffix,
strlen(suffix) + 1);
}
key = strchr(key, SETTINGS_SEPARATOR);
if (key == NULL)
return;
- key++;
+ key = settings_section_unescape(key + 1);
vvalue = p_strdup(ctx->set_pool, value);
if (!array_is_created(array))
}
if (quoted || str_len(elem) > 0) {
- elem_dup = p_strdup(pool, str_c(elem));
+ elem_dup = p_strdup(pool,
+ settings_section_unescape(str_c(elem)));
array_push_back(dest, &elem_dup);
str_truncate(elem, 0);
}
return -1;
}
if (quoted || str_len(elem) > 0) {
- elem_dup = p_strdup(pool, str_c(elem));
+ elem_dup = settings_section_unescape(p_strdup(pool, str_c(elem)));
array_push_back(dest, &elem_dup);
}
return 0;
boollist_null_terminate(array);
return 0;
}
- key++;
+ key = settings_section_unescape(key + 1);
bool value_bool;
if (get_bool(ctx, value, &value_bool) < 0)
void *ptr;
const void *ptr2;
const char *error;
+ int ret;
if (value == set_value_unknown) {
/* setting value is unknown - preserve the exact pointer */
return -1;
break;
case SET_STRLIST:
- settings_parse_strlist(ctx, ptr, key, value);
+ T_BEGIN {
+ settings_parse_strlist(ctx, ptr, key, value);
+ } T_END;
break;
case SET_BOOLLIST:
- if (settings_parse_boollist(ctx, ptr, key, value) < 0)
+ T_BEGIN {
+ ret = settings_parse_boollist(ctx, ptr, key, value);
+ } T_END;
+ if (ret < 0)
return -1;
break;
case SET_FILTER_ARRAY: {
offset += strlen(list_key)+1;
set_apply = set_apply &&
!settings_parse_list_has_key(ctx->parser,
- key_idx, list_key);
+ key_idx, settings_section_unescape(list_key));
} else if (ctx->info->defines[key_idx].type == SET_FILTER_ARRAY)
set_apply = TRUE;
else if (set_apply)
(invalid for strlist) */
i_assert(suffix[0] == '\0');
} else if (settings_parse_list_has_key(ctx->parser,
- key_idx, suffix + 1))
+ key_idx,
+ settings_section_unescape(suffix + 1)))
continue;
else
track_seen = FALSE;
{ "foo", (const char *const []) { "foo", NULL } },
{ "foo bar", (const char *const []) { "foo", "bar", NULL } },
{ "foo bar,baz", (const char *const []) { "foo", "bar", "baz", NULL } },
- { ", foo, , b\\\\ar ", (const char *const []) { "foo", "b\\\\ar", NULL } },
+ { ", foo, , b\\\\sa ", (const char *const []) { "foo", "b\\sa", NULL } },
+ { ", a\\s\\e\\_\\+, ", (const char *const []) { "a/= ,", NULL } },
{ "\"\"", (const char *const []) { "", NULL } },
{ "\",.\"", (const char *const []) { ",.", NULL } },
- { "\"esc\\\\str\"", (const char *const []) { "esc\\str", NULL } },
+ { "\"esc\\\\\\\\str\"", (const char *const []) { "esc\\str", NULL } },
{ "\"quotes\\\"str\"", (const char *const []) { "quotes\"str", NULL } },
{ "\"val1\", \"val2\" \"val3\"", (const char *const []) { "val1", "val2", "val3", NULL } },
+ { "\"a\\\\s\\\\e\\\\_\\\\+\"", (const char *const []) { "a/= ,", NULL } },
};
const struct {
const char *input;