a4a13b04fe716471f235c15bc402702d8f4c75cd
[exim.git] / src / src / routers / rf_get_munge_headers.c
1 /*************************************************
2 *     Exim - an Internet mail transport agent    *
3 *************************************************/
4
5 /* Copyright (c) University of Cambridge 1995 - 2014 */
6 /* See the file NOTICE for conditions of use and distribution. */
7
8 #include "../exim.h"
9 #include "rf_functions.h"
10
11
12 /*************************************************
13 *      Get additional headers for a router       *
14 *************************************************/
15
16 /* This function is called by routers to sort out the additional headers
17 and header remove list for a particular address.
18
19 Arguments:
20   addr           the input address
21   rblock         the router instance
22   extra_headers  points to where to hang the header chain
23   remove_headers points to where to hang the remove list
24
25 Returns:         OK if no problem
26                  DEFER if expanding a string caused a deferment
27                    or a big disaster (e.g. expansion failure)
28 */
29
30 int
31 rf_get_munge_headers(address_item *addr, router_instance *rblock,
32   header_line **extra_headers, uschar **remove_headers)
33 {
34 /* Default is to retain existing headers */
35 *extra_headers = addr->p.extra_headers;
36
37 if (rblock->extra_headers)
38   {
39   uschar * list = rblock->extra_headers;
40   int sep = '\n';
41   uschar * s;
42   int slen;
43
44   while ((s = string_nextinlist(&list, &sep, NULL, 0)))
45     if (!(s = expand_string(s)))
46       {
47       if (!expand_string_forcedfail)
48         {
49         addr->message = string_sprintf("%s router failed to expand \"%s\": %s",
50           rblock->name, rblock->extra_headers, expand_string_message);
51         return DEFER;
52         }
53       }
54     else if ((slen = Ustrlen(s)) > 0)
55       {
56       /* Expand succeeded. Put extra headers at the start of the chain because
57       further down it may point to headers from other routers, which may be
58       shared with other addresses. The output function outputs them in reverse
59       order. */
60
61       header_line *  h = store_get(sizeof(header_line));
62
63       /* We used to use string_sprintf() to add the newline if needed, but that
64       causes problems if the header line is exceedingly long (e.g. adding
65       something to a pathologically long line). So avoid it. */
66
67       if (s[slen-1] == '\n')
68         h->text = s;
69       else
70         {
71         h->text = store_get(slen+2);
72         memcpy(h->text, s, slen);
73         h->text[slen++] = '\n';
74         h->text[slen] = 0;
75         }
76
77       h->next = *extra_headers;
78       h->type = htype_other;
79       h->slen = slen;
80       *extra_headers = h;
81       }
82   }
83
84 /* Default is to retain existing removes */
85 *remove_headers = addr->p.remove_headers;
86
87 /* Expand items from colon-sep list separately, then build new list */
88 if (rblock->remove_headers)
89   {
90   uschar * list = rblock->remove_headers;
91   int sep = ':';
92   uschar * s;
93   uschar buffer[128];
94
95   while ((s = string_nextinlist(&list, &sep, buffer, sizeof(buffer))))
96     if (!(s = expand_string(s)))
97       {
98       if (!expand_string_forcedfail)
99         {
100         addr->message = string_sprintf("%s router failed to expand \"%s\": %s",
101           rblock->name, rblock->remove_headers, expand_string_message);
102         return DEFER;
103         }
104       }
105     else if (*s)
106       *remove_headers = string_append_listele(*remove_headers, ':', s);
107   }
108
109 return OK;
110 }
111
112 /* End of rf_get_munge_headers.c */