summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJeremy Harris <jgh146exb@wizmail.org>2014-03-30 21:48:32 +0100
committerJeremy Harris <jgh146exb@wizmail.org>2014-04-09 18:00:17 +0100
commit76146973f89f0e9265d85827285b9258910a56d7 (patch)
treecdb91a1e9722f06886e17126b58f779c6b8ccd06 /src
parent1e06383a8b5eaaf67910c94c737e8d9b5d16a00a (diff)
More care with headers add/remove lists. Bug 1452
As a side-effect, playing games with newlines no longer gives an altered message body/ Testcase 0324 is questionable (though passing)
Diffstat (limited to 'src')
-rw-r--r--src/src/functions.h1
-rw-r--r--src/src/readconf.c24
-rw-r--r--src/src/routers/rf_get_munge_headers.c99
-rw-r--r--src/src/string.c44
-rw-r--r--src/src/transport.c76
5 files changed, 147 insertions, 97 deletions
diff --git a/src/src/functions.h b/src/src/functions.h
index 395961530..35500a165 100644
--- a/src/src/functions.h
+++ b/src/src/functions.h
@@ -350,6 +350,7 @@ extern int stdin_feof(void);
extern int stdin_ferror(void);
extern int stdin_ungetc(int);
extern uschar *string_append(uschar *, int *, int *, int, ...);
+extern uschar *string_append_listele(uschar *, uschar, const uschar *);
extern uschar *string_base62(unsigned long int);
extern uschar *string_cat(uschar *, int *, int *, const uschar *, int);
extern uschar *string_copy_dnsdomain(uschar *);
diff --git a/src/src/readconf.c b/src/src/readconf.c
index b41d22d2a..81e3bc267 100644
--- a/src/src/readconf.c
+++ b/src/src/readconf.c
@@ -1562,15 +1562,21 @@ 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))
- {
+ else if (ol->type & opt_rep_str)
+ {
uschar sep = Ustrncmp(name, "headers_add", 11)==0 ? '\n' : ':';
- saved_condition = *str_target;
- strtemp = saved_condition + Ustrlen(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);
- }
+ uschar * cp;
+
+ /* Strip trailing whitespace and seperators */
+ for (cp = sptr + Ustrlen(sptr) - 1;
+ cp >= sptr && (*cp == '\n' || *cp == '\t' || *cp == ' ' || *cp == sep);
+ cp--) *cp = '\0';
+
+ if (cp >= sptr)
+ *str_target = string_copy_malloc(
+ *str_target ? string_sprintf("%s%c%s", *str_target, sep, sptr)
+ : sptr);
+ }
else
{
*str_target = sptr;
@@ -4131,4 +4137,6 @@ while(next_section[0] != 0)
(void)fclose(config_file);
}
+/* vi: aw ai sw=2
+*/
/* End of readconf.c */
diff --git a/src/src/routers/rf_get_munge_headers.c b/src/src/routers/rf_get_munge_headers.c
index 76e87e9c7..c44ba70b8 100644
--- a/src/src/routers/rf_get_munge_headers.c
+++ b/src/src/routers/rf_get_munge_headers.c
@@ -13,7 +13,7 @@
* Get additional headers for a router *
*************************************************/
-/* This function is called by both routers to sort out the additional headers
+/* This function is called by routers to sort out the additional headers
and header remove list for a particular address.
Arguments:
@@ -32,83 +32,78 @@ rf_get_munge_headers(address_item *addr, router_instance *rblock,
header_line **extra_headers, uschar **remove_headers)
{
/* Default is to retain existing headers */
-
*extra_headers = addr->p.extra_headers;
-if (rblock->extra_headers != NULL)
+if (rblock->extra_headers)
{
- header_line *h;
- uschar *s = expand_string(rblock->extra_headers);
+ uschar * list = rblock->extra_headers;
+ int sep = '\n';
+ uschar * s;
+ int slen;
- if (s == NULL)
- {
- if (!expand_string_forcedfail)
+ while ((s = string_nextinlist(&list, &sep, NULL, 0)))
+ if (!(s = expand_string(s)))
{
- addr->message = string_sprintf("%s router failed to expand \"%s\": %s",
- rblock->name, rblock->extra_headers, expand_string_message);
- return DEFER;
+ if (!expand_string_forcedfail)
+ {
+ addr->message = string_sprintf("%s router failed to expand \"%s\": %s",
+ rblock->name, rblock->extra_headers, expand_string_message);
+ return DEFER;
+ }
}
- }
-
- /* Expand succeeded. Put extra header at the start of the chain because
- further down it may point to headers from other routers, which may be
- shared with other addresses. The output function outputs them in reverse
- order. */
-
- else
- {
- int slen = Ustrlen(s);
- if (slen > 0)
+ else if ((slen = Ustrlen(s)) > 0)
{
- h = store_get(sizeof(header_line));
+ /* Expand succeeded. Put extra headers at the start of the chain because
+ further down it may point to headers from other routers, which may be
+ shared with other addresses. The output function outputs them in reverse
+ order. */
+
+ header_line * h = store_get(sizeof(header_line));
/* We used to use string_sprintf() to add the newline if needed, but that
causes problems if the header line is exceedingly long (e.g. adding
something to a pathologically long line). So avoid it. */
if (s[slen-1] == '\n')
- {
- h->text = s;
- }
+ h->text = s;
else
- {
- h->text = store_get(slen+2);
- memcpy(h->text, s, slen);
- h->text[slen++] = '\n';
- h->text[slen] = 0;
- }
-
- h->next = addr->p.extra_headers;
+ {
+ h->text = store_get(slen+2);
+ memcpy(h->text, s, slen);
+ h->text[slen++] = '\n';
+ h->text[slen] = 0;
+ }
+
+ h->next = *extra_headers;
h->type = htype_other;
h->slen = slen;
*extra_headers = h;
}
- }
}
/* Default is to retain existing removes */
-
*remove_headers = addr->p.remove_headers;
-if (rblock->remove_headers != NULL)
+/* Expand items from colon-sep list separately, then build new list */
+if (rblock->remove_headers)
{
- uschar *s = expand_string(rblock->remove_headers);
- if (s == NULL)
- {
- if (!expand_string_forcedfail)
+ uschar * list = rblock->remove_headers;
+ int sep = ':';
+ uschar * s;
+ uschar buffer[128];
+
+ while ((s = string_nextinlist(&list, &sep, buffer, sizeof(buffer))))
+ if (!(s = expand_string(s)))
{
- addr->message = string_sprintf("%s router failed to expand \"%s\": %s",
- rblock->name, rblock->remove_headers, expand_string_message);
- return DEFER;
+ if (!expand_string_forcedfail)
+ {
+ addr->message = string_sprintf("%s router failed to expand \"%s\": %s",
+ rblock->name, rblock->remove_headers, expand_string_message);
+ return DEFER;
+ }
}
- }
- else if (*s != 0)
- {
- if (addr->p.remove_headers == NULL)
- *remove_headers = s;
- else
- *remove_headers = string_sprintf("%s : %s", addr->p.remove_headers, s);
- }
+ else if (*s)
+ *remove_headers = string_append_listele(*remove_headers, ':', s);
}
return OK;
diff --git a/src/src/string.c b/src/src/string.c
index 6f54cc624..eb73fae3e 100644
--- a/src/src/string.c
+++ b/src/src/string.c
@@ -966,6 +966,50 @@ return buffer;
#endif /* COMPILE_UTILITY */
+#ifndef COMPILE_UTILITY
+/************************************************
+* Add element to seperated list *
+************************************************/
+/* This function is used to build a list, returning
+an allocated null-terminated growable string. The
+given element has any embedded seperator characters
+doubled.
+
+Arguments:
+ list points to the start of the list that is being built, or NULL
+ if this is a new list that has no contents yet
+ sep list seperator charactoer
+ ele new lement to be appended to the list
+
+Returns: pointer to the start of the list, changed if copied for expansion.
+*/
+
+uschar *
+string_append_listele(uschar * list, uschar sep, const uschar * ele)
+{
+uschar * new = NULL;
+int sz = 0, off = 0;
+uschar * sp;
+
+if (list)
+ {
+ new = string_cat(new, &sz, &off, list, Ustrlen(list));
+ new = string_cat(new, &sz, &off, &sep, 1);
+ }
+
+while (sp = Ustrchr(ele, sep))
+ {
+ new = string_cat(new, &sz, &off, ele, sp-ele+1);
+ new = string_cat(new, &sz, &off, &sep, 1);
+ ele = sp+1;
+ }
+new = string_cat(new, &sz, &off, ele, Ustrlen(ele));
+new[off] = '\0';
+return new;
+}
+#endif /* COMPILE_UTILITY */
+
+
#ifndef COMPILE_UTILITY
/*************************************************
diff --git a/src/src/transport.c b/src/src/transport.c
index 549da4694..d4495393b 100644
--- a/src/src/transport.c
+++ b/src/src/transport.c
@@ -626,19 +626,9 @@ header_line *h;
/* Then the message's headers. Don't write any that are flagged as "old";
that means they were rewritten, or are a record of envelope rewriting, or
were removed (e.g. Bcc). If remove_headers is not null, skip any headers that
-match any entries therein. Then check addr->p.remove_headers too, provided that
-addr is not NULL. */
-
-if (remove_headers)
- {
- uschar *s = expand_string(remove_headers);
- if (!s && !expand_string_forcedfail)
- {
- errno = ERRNO_CHHEADER_FAIL;
- return FALSE;
- }
- remove_headers = s;
- }
+match any entries therein. It is a colon-sep list; expand the items
+separately and squash any empty ones.
+Then check addr->p.remove_headers too, provided that addr is not NULL. */
for (h = header_list; h != NULL; h = h->next) if (h->type != htype_old)
{
@@ -656,7 +646,15 @@ for (h = header_list; h != NULL; h = h->next) if (h->type != htype_old)
uschar buffer[128];
while ((s = string_nextinlist(&list, &sep, buffer, sizeof(buffer))))
{
- int len = Ustrlen(s);
+ int len;
+
+ if (i == 0)
+ if (!(s = expand_string(s)) && !expand_string_forcedfail)
+ {
+ errno = ERRNO_CHHEADER_FAIL;
+ return FALSE;
+ }
+ len = Ustrlen(s);
if (strncmpic(h->text, s, len) != 0) continue;
ss = h->text + len;
while (*ss == ' ' || *ss == '\t') ss++;
@@ -731,36 +729,40 @@ if (addr)
}
}
-/* If a string containing additional headers exists, expand it and write
-out the result. This is done last so that if it (deliberately or accidentally)
-isn't in header format, it won't mess up any other headers. An empty string
-or a forced expansion failure are noops. An added header string from a
-transport may not end with a newline; add one if it does not. */
+/* If a string containing additional headers exists it is a newline-sep
+list. Expand each item and write out the result. This is done last so that
+if it (deliberately or accidentally) isn't in header format, it won't mess
+up any other headers. An empty string or a forced expansion failure are
+noops. An added header string from a transport may not end with a newline;
+add one if it does not. */
if (add_headers)
{
- uschar *s = expand_string(add_headers);
- if (s == NULL)
- {
- if (!expand_string_forcedfail)
- { errno = ERRNO_CHHEADER_FAIL; return FALSE; }
- }
- else
- {
- int len = Ustrlen(s);
- if (len > 0)
+ int sep = '\n';
+ uschar * s;
+
+ while ((s = string_nextinlist(&add_headers, &sep, NULL, 0)))
+ if (!(s = expand_string(s)))
{
- if (!sendfn(fd, s, len, use_crlf)) return FALSE;
- if (s[len-1] != '\n' && !sendfn(fd, US"\n", 1, use_crlf))
- return FALSE;
- DEBUG(D_transport)
+ if (!expand_string_forcedfail)
+ { errno = ERRNO_CHHEADER_FAIL; return FALSE; }
+ }
+ else
+ {
+ int len = Ustrlen(s);
+ if (len > 0)
{
- debug_printf("added header line(s):\n%s", s);
- if (s[len-1] != '\n') debug_printf("\n");
- debug_printf("---\n");
+ if (!sendfn(fd, s, len, use_crlf)) return FALSE;
+ if (s[len-1] != '\n' && !sendfn(fd, US"\n", 1, use_crlf))
+ return FALSE;
+ DEBUG(D_transport)
+ {
+ debug_printf("added header line:\n%s", s);
+ if (s[len-1] != '\n') debug_printf("\n");
+ debug_printf("---\n");
+ }
}
}
- }
}
/* Separate headers from body with a blank line */