From: Aki Tuomi Date: Tue, 23 Sep 2025 09:58:07 +0000 (+0300) Subject: lib-var-expand: regex - Support older back references X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=2ad89fd4c7fcbd8830588f1ca1abffae973f983a;p=thirdparty%2Fdovecot%2Fcore.git lib-var-expand: regex - Support older back references --- diff --git a/src/lib-var-expand/expansion-filter.c b/src/lib-var-expand/expansion-filter.c index 4bff618d97..a72bd1e132 100644 --- a/src/lib-var-expand/expansion-filter.c +++ b/src/lib-var-expand/expansion-filter.c @@ -750,6 +750,32 @@ static int fn_ldap_dn(const struct var_expand_statement *stmt, return 0; } +static const char *fix_replacement_pattern(const char *pattern) +{ + const char *p1, *p0 = pattern; + string_t *dest = t_str_new(strlen(pattern)); + + while ((p1 = strchr(p0, '\\')) != NULL) { + str_append_data(dest, p0, p1 - p0); + if (i_isdigit(p1[1])) { + str_append_c(dest, '$'); + str_append_c(dest, p1[1]); + p1 += 2; + } else if (p1[1] == '\\') { + str_append_c(dest, '\\'); + p1 += 2; + } else { + str_append_c(dest, *p1); + p1++; + } + p0 = p1; + } + + str_append(dest, p0); + + return str_c(dest); +} + static int fn_regexp(const struct var_expand_statement *stmt, struct var_expand_state *state, const char **error_r) { @@ -798,6 +824,11 @@ static int fn_regexp(const struct var_expand_statement *stmt, const char *input ATTR_UNUSED = str_c(state->transfer); string_t *dest = t_str_new(strlen(rep)); + if (strchr(rep, '\\') != NULL) { + /* fix replacement pattern */ + rep = fix_replacement_pattern(rep); + } + int ret = dregex_replace(pat, input, rep, dest, 0, error_r); if (ret > 0) diff --git a/src/lib-var-expand/test-var-expand.c b/src/lib-var-expand/test-var-expand.c index 6ee360c637..2e7ba232a7 100644 --- a/src/lib-var-expand/test-var-expand.c +++ b/src/lib-var-expand/test-var-expand.c @@ -199,6 +199,9 @@ static void test_var_expand_builtin_filters(void) { #ifdef HAVE_LIBPCRE /* regexp */ { .in = "%{literal('hello world') | regexp('(.*) (.*)', '$2 $1')}", .out = "world hello" }, + { .in = "%{literal('hello world') | regexp('(.*) (.*)', '\\\\2 \\\\1')}", .out = "world hello" }, + { .in = "%{literal('hello world') | regexp('(.*) (.*)', '\\\\\\\\2 \\\\\\\\1')}", .out = "\\2 \\1" }, + { .in = "%{literal('hello world') | regexp('(.*) (.*)', '\\\\\\\\\\\\2 \\\\\\\\\\\\1')}", .out = "\\world \\hello" }, #endif /* index */ { .in = "%{user | index('@',0)}", .out = "user", .ret = 0 },