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