summaryrefslogtreecommitdiffstats
path: root/src/routers/rf_get_munge_headers.c
blob: d304d11452de2b522429429301ab55033580df2f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
/*************************************************
*     Exim - an Internet mail transport agent    *
*************************************************/

/* Copyright (c) The Exim Maintainers 2021 - 2022 */
/* Copyright (c) University of Cambridge 1995 - 2018 */
/* See the file NOTICE for conditions of use and distribution. */

#include "../exim.h"
#include "rf_functions.h"


/*************************************************
*      Get additional headers for a router       *
*************************************************/

/* This function is called by routers to sort out the additional headers
and header remove list for a particular address.

Arguments:
  addr           the input address
  rblock         the router instance
  extra_headers  points to where to hang the header chain
  remove_headers points to where to hang the remove list

Returns:         OK if no problem
                 DEFER if expanding a string caused a deferment
                   or a big disaster (e.g. expansion failure)
*/

int
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->prop.extra_headers;

if (rblock->extra_headers)
  {
  const uschar * list = rblock->extra_headers;
  int sep = '\n';
  uschar * s, * t;
  int slen;

  while ((s = string_nextinlist(&list, &sep, NULL, 0)))
    if (!(s = expand_string(t = s)))
      {
      if (!f.expand_string_forcedfail)
	{
	addr->message = string_sprintf(
	  "%s router failed to expand add_headers item \"%s\": %s",
	  rblock->name, t, expand_string_message);
	return DEFER;
	}
      }
    else if ((slen = Ustrlen(s)) > 0)
      {
      /* 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), GET_UNTAINTED);

      /* 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;
      else
	{
	h->text = store_get(slen+2, s);
	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->prop.remove_headers;

/* Expand items from colon-sep list separately, then build new list */
if (rblock->remove_headers)
  {
  const uschar * list = rblock->remove_headers;
  int sep = ':';
  uschar * s, * t;
  gstring * g = NULL;

  if (*remove_headers)
    g = string_cat(NULL, *remove_headers);

  while ((s = string_nextinlist(&list, &sep, NULL, 0)))
    if (!(s = expand_string(t = s)))
      {
      if (!f.expand_string_forcedfail)
	{
	addr->message = string_sprintf(
	  "%s router failed to expand remove_headers item \"%s\": %s",
	  rblock->name, t, expand_string_message);
	return DEFER;
	}
      }
    else if (*s)
      g = string_append_listele(g, ':', s);

  if (g)
    *remove_headers = g->s;
  }

return OK;
}

/* vi: aw ai sw=2
*/
/* End of rf_get_munge_headers.c */