From 846726c5a374d833fb5211dde62ae6bceb6841c7 Mon Sep 17 00:00:00 2001 From: Jeremy Harris Date: Sun, 8 Jul 2012 22:49:18 +0100 Subject: Multiple headers_add/remove options per router/transport - fixes bug 337 --- src/src/macros.h | 4 +++- src/src/readconf.c | 32 +++++++++++++++++--------------- src/src/route.c | 6 +++--- src/src/transport.c | 4 ++-- 4 files changed, 25 insertions(+), 21 deletions(-) (limited to 'src') diff --git a/src/src/macros.h b/src/src/macros.h index d25071aae..3ec94bc6d 100644 --- a/src/src/macros.h +++ b/src/src/macros.h @@ -624,7 +624,9 @@ for booleans that are kept in one bit. */ #define opt_public 0x200 /* Stored in the main instance block */ #define opt_set 0x400 /* Option is set */ #define opt_secure 0x800 /* "hide" prefix used */ -#define opt_mask 0x0ff +#define opt_rep_con 0x1000 /* Can be appended to by a repeated line (condition) */ +#define opt_rep_str 0x2000 /* Can be appended to by a repeated line (string) */ +#define opt_mask 0x00ff /* Verify types when directing and routing */ diff --git a/src/src/readconf.c b/src/src/readconf.c index 087ab5b9b..ddd81d1d3 100644 --- a/src/src/readconf.c +++ b/src/src/readconf.c @@ -1374,7 +1374,6 @@ uid_t uid; gid_t gid; BOOL boolvalue = TRUE; BOOL freesptr = TRUE; -BOOL extra_condition = FALSE; optionlist *ol, *ol2; struct passwd *pw; void *reset_point; @@ -1437,16 +1436,9 @@ if (ol == NULL) log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN, CS unknown_txt, name); } -if ((ol->type & opt_set) != 0) - { - uschar *mname = name; - if (Ustrncmp(mname, "no_", 3) == 0) mname += 3; - if (Ustrcmp(mname, "condition") == 0) - extra_condition = TRUE; - else - log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN, - "\"%s\" option set for the second time", mname); - } +if ((ol->type & opt_set) && !(ol->type & (opt_rep_con | opt_rep_str))) + log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN, + "\"%s\" option set for the second time", name); ol->type |= opt_set | issecure; type = ol->type & opt_mask; @@ -1530,7 +1522,7 @@ switch (type) str_target = (uschar **)(ol->value); else str_target = (uschar **)((uschar *)data_block + (long int)(ol->value)); - if (extra_condition) + if (ol->type & opt_rep_con) { /* We already have a condition, we're conducting a crude hack to let multiple condition rules be chained together, despite storing them in @@ -1539,9 +1531,10 @@ switch (type) strtemp = string_sprintf("${if and{{bool_lax{%s}}{bool_lax{%s}}}}", saved_condition, sptr); *str_target = string_copy_malloc(strtemp); - /* TODO(pdp): there is a memory leak here when we set 3 or more - conditions; I still don't understand the store mechanism enough - to know what's the safe way to free content from an earlier store. + /* TODO(pdp): there is a memory leak here and just below + when we set 3 or more conditions; I still don't + understand the store mechanism enough to know + what's the safe way to free content from an earlier store. AFAICT, stores stack, so freeing an early stored item also stores all data alloc'd after it. If we knew conditions were adjacent, we could survive that, but we don't. So I *think* we need to take @@ -1552,6 +1545,15 @@ switch (type) Because we only do this once, near process start-up, I'm prepared to let this slide for the time being, even though it rankles. */ } + else if (*str_target && (ol->type & opt_rep_str)) + { + uschar sep = Ustrncmp(name, "headers_add", 11)==0 ? '\n' : ':'; + saved_condition = *str_target; + strtemp = saved_condition + strlen(saved_condition)-1; + if (*strtemp == sep) *strtemp = 0; /* eliminate trailing list-sep */ + strtemp = string_sprintf("%s%c%s", saved_condition, sep, sptr); + *str_target = string_copy_malloc(strtemp); + } else { *str_target = sptr; diff --git a/src/src/route.c b/src/src/route.c index 43ffc25a9..32dbd60ab 100644 --- a/src/src/route.c +++ b/src/src/route.c @@ -48,7 +48,7 @@ optionlist optionlist_routers[] = { (void *)(offsetof(router_instance, caseful_local_part)) }, { "check_local_user", opt_bool | opt_public, (void *)(offsetof(router_instance, check_local_user)) }, - { "condition", opt_stringptr|opt_public, + { "condition", opt_stringptr|opt_public|opt_rep_con, (void *)offsetof(router_instance, condition) }, { "debug_print", opt_stringptr | opt_public, (void *)offsetof(router_instance, debug_string) }, @@ -72,9 +72,9 @@ optionlist optionlist_routers[] = { (void *)offsetof(router_instance, fallback_hosts) }, { "group", opt_expand_gid | opt_public, (void *)(offsetof(router_instance, gid)) }, - { "headers_add", opt_stringptr|opt_public, + { "headers_add", opt_stringptr|opt_public|opt_rep_str, (void *)offsetof(router_instance, extra_headers) }, - { "headers_remove", opt_stringptr|opt_public, + { "headers_remove", opt_stringptr|opt_public|opt_rep_str, (void *)offsetof(router_instance, remove_headers) }, { "ignore_target_hosts",opt_stringptr|opt_public, (void *)offsetof(router_instance, ignore_target_hosts) }, diff --git a/src/src/transport.c b/src/src/transport.c index 9e533f63e..7c79bb009 100644 --- a/src/src/transport.c +++ b/src/src/transport.c @@ -68,11 +68,11 @@ optionlist optionlist_transports[] = { (void *)(offsetof(transport_instance, envelope_to_add)) }, { "group", opt_expand_gid|opt_public, (void *)offsetof(transport_instance, gid) }, - { "headers_add", opt_stringptr|opt_public, + { "headers_add", opt_stringptr|opt_public|opt_rep_str, (void *)offsetof(transport_instance, add_headers) }, { "headers_only", opt_bool|opt_public, (void *)offsetof(transport_instance, headers_only) }, - { "headers_remove", opt_stringptr|opt_public, + { "headers_remove", opt_stringptr|opt_public|opt_rep_str, (void *)offsetof(transport_instance, remove_headers) }, { "headers_rewrite", opt_rewrite|opt_public, (void *)offsetof(transport_instance, headers_rewrite) }, -- cgit v1.2.3