Rename substructure for ease of debugging
[exim.git] / src / src / routers / rf_get_errors_address.c
1 /*************************************************
2 *     Exim - an Internet mail transport agent    *
3 *************************************************/
4
5 /* Copyright (c) University of Cambridge 1995 - 2009 */
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 errors address for a router         *
14 *************************************************/
15
16 /* This function is called by routers to sort out the errors address for a
17 particular address. If there is a setting in the router block, then expand and
18 verify it, and if it works, use it. Otherwise use any setting that is in the
19 address itself. This might be NULL, meaning unset (the message's sender is then
20 used). Verification isn't done when the original address is just being
21 verified, as otherwise there might be routing loops if someone sets up a silly
22 configuration.
23
24 Arguments:
25   addr         the input address
26   rblock       the router instance
27   verify       v_none / v_recipient / v_sender / v_expn
28   errors_to    point the errors address here
29
30 Returns:       OK if no problem
31                DEFER if verifying the address caused a deferment
32                  or a big disaster (e.g. expansion failure)
33 */
34
35 int
36 rf_get_errors_address(address_item *addr, router_instance *rblock,
37   int verify, uschar **errors_to)
38 {
39 uschar *s;
40
41 *errors_to = addr->prop.errors_address;
42 if (rblock->errors_to == NULL) return OK;
43
44 s = expand_string(rblock->errors_to);
45
46 if (s == NULL)
47   {
48   if (expand_string_forcedfail)
49     {
50     DEBUG(D_route)
51       debug_printf("forced expansion failure - ignoring errors_to\n");
52     return OK;
53     }
54   addr->message = string_sprintf("%s router failed to expand \"%s\": %s",
55     rblock->name, rblock->errors_to, expand_string_message);
56   return DEFER;
57   }
58
59 /* If the errors_to address is empty, it means "ignore errors" */
60
61 if (*s == 0)
62   {
63   setflag(addr, af_ignore_error);      /* For locally detected errors */
64   *errors_to = US"";                   /* Return path for SMTP */
65   return OK;
66   }
67
68 /* If we are already verifying, do not check the errors address, in order to
69 save effort (but we do verify when testing an address). When we do verify, set
70 the sender address to null, because that's what it will be when sending an
71 error message, and there are now configuration options that control the running
72 of routers by checking the sender address. When testing an address, there may
73 not be a sender address. We also need to save and restore the expansion values
74 associated with an address. */
75
76 if (verify != v_none)
77   {
78   *errors_to = s;
79   DEBUG(D_route)
80     debug_printf("skipped verify errors_to address: already verifying\n");
81   }
82 else
83   {
84   BOOL save_address_test_mode = address_test_mode;
85   int save1 = 0;
86   int i;
87   const uschar ***p;
88   const uschar *address_expansions_save[ADDRESS_EXPANSIONS_COUNT];
89   address_item *snew = deliver_make_addr(s, FALSE);
90
91   if (sender_address != NULL)
92     {
93     save1 = sender_address[0];
94     sender_address[0] = 0;
95     }
96
97   for (i = 0, p = address_expansions; *p != NULL;)
98     address_expansions_save[i++] = **p++;
99   address_test_mode = FALSE;
100
101   /* NOTE: the address is verified as a recipient, not a sender. This is
102   perhaps confusing. It isn't immediately obvious what to do: we want to have
103   some confidence that we can deliver to the address, in which case it will be
104   a recipient, but on the other hand, it will be passed on in SMTP deliveries
105   as a sender. However, I think on balance recipient is right because sender
106   verification is really about the *incoming* sender of the message.
107
108   If this code is changed, note that you must set vopt_fake_sender instead of
109   vopt_is_recipient, as otherwise sender_address may be altered because
110   verify_address() thinks it is dealing with *the* sender of the message. */
111
112   DEBUG(D_route|D_verify)
113     debug_printf("------ Verifying errors address %s ------\n", s);
114   if (verify_address(snew, NULL,
115       vopt_is_recipient /* vopt_fake_sender is the alternative */
116       | vopt_qualify, -1, -1, -1, NULL, NULL, NULL) == OK)
117     *errors_to = snew->address;
118   DEBUG(D_route|D_verify)
119     debug_printf("------ End verifying errors address %s ------\n", s);
120
121   address_test_mode = save_address_test_mode;
122   for (i = 0, p = address_expansions; *p != NULL;)
123     **p++ = address_expansions_save[i++];
124
125   if (sender_address != NULL) sender_address[0] = save1;
126   }
127
128 return OK;
129 }
130
131 /* End of rf_get_errors_address.c */