1 /*************************************************
2 * Exim - an Internet mail transport agent *
3 *************************************************/
5 /* Copyright (c) The Exim Maintainers 2020 - 2024 */
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-or-later */
13 #ifdef ROUTER_REDIRECT /* Remainder of file */
14 #include "rf_functions.h"
19 /* Options specific to the redirect router. */
20 #define LOFF(field) OPT_OFF(redirect_router_options_block, field)
22 optionlist redirect_router_options[] = {
23 { "allow_defer", opt_bit | (RDON_DEFER << 16),
25 { "allow_fail", opt_bit | (RDON_FAIL << 16),
27 { "allow_filter", opt_bit | (RDON_FILTER << 16),
29 { "allow_freeze", opt_bit | (RDON_FREEZE << 16),
31 { "check_ancestor", opt_bool, LOFF(check_ancestor) },
32 { "check_group", opt_bool, LOFF(check_group) },
33 { "check_owner", opt_bool, LOFF(check_owner) },
34 { "data", opt_stringptr, LOFF(data) },
35 { "directory_transport",opt_stringptr, LOFF(directory_transport_name) },
36 { "file", opt_stringptr, LOFF(file) },
37 { "file_transport", opt_stringptr, LOFF(file_transport_name) },
39 { "filter_prepend_home",opt_bit | (RDON_PREPEND_HOME << 16),
41 { "forbid_blackhole", opt_bit | (RDON_BLACKHOLE << 16),
43 { "forbid_exim_filter", opt_bit | (RDON_EXIM_FILTER << 16),
45 { "forbid_file", opt_bool,
47 { "forbid_filter_dlfunc", opt_bit | (RDON_DLFUNC << 16),
49 { "forbid_filter_existstest", opt_bit | (RDON_EXISTS << 16),
51 { "forbid_filter_logwrite",opt_bit | (RDON_LOG << 16),
53 { "forbid_filter_lookup", opt_bit | (RDON_LOOKUP << 16),
55 { "forbid_filter_perl", opt_bit | (RDON_PERL << 16),
57 { "forbid_filter_readfile", opt_bit | (RDON_READFILE << 16),
59 { "forbid_filter_readsocket", opt_bit | (RDON_READSOCK << 16),
61 { "forbid_filter_reply",opt_bool,
62 LOFF(forbid_filter_reply) },
63 { "forbid_filter_run", opt_bit | (RDON_RUN << 16),
65 { "forbid_include", opt_bit | (RDON_INCLUDE << 16),
67 { "forbid_pipe", opt_bool,
69 { "forbid_sieve_filter",opt_bit | (RDON_SIEVE_FILTER << 16),
71 { "forbid_smtp_code", opt_bool,
72 LOFF(forbid_smtp_code) },
73 { "hide_child_in_errmsg", opt_bool,
74 LOFF( hide_child_in_errmsg) },
75 { "ignore_eacces", opt_bit | (RDON_EACCES << 16),
77 { "ignore_enotdir", opt_bit | (RDON_ENOTDIR << 16),
80 { "include_directory", opt_stringptr, LOFF( include_directory) },
81 { "modemask", opt_octint, LOFF(modemask) },
82 { "one_time", opt_bool, LOFF(one_time) },
83 { "owners", opt_uidlist, LOFF(owners) },
84 { "owngroups", opt_gidlist, LOFF(owngroups) },
85 { "pipe_transport", opt_stringptr, LOFF(pipe_transport_name) },
86 { "qualify_domain", opt_stringptr, LOFF(qualify_domain) },
87 { "qualify_preserve_domain", opt_bool, LOFF(qualify_preserve_domain) },
88 { "repeat_use", opt_bool | opt_public, OPT_OFF(router_instance, repeat_use) },
89 { "reply_transport", opt_stringptr, LOFF(reply_transport_name) },
91 { "rewrite", opt_bit | (RDON_REWRITE << 16),
94 { "sieve_enotify_mailto_owner", opt_stringptr, LOFF(sieve_enotify_mailto_owner) },
95 { "sieve_subaddress", opt_stringptr, LOFF(sieve_subaddress) },
96 { "sieve_useraddress", opt_stringptr, LOFF(sieve_useraddress) },
97 { "sieve_vacation_directory", opt_stringptr, LOFF(sieve_vacation_directory) },
98 { "skip_syntax_errors", opt_bool, LOFF(skip_syntax_errors) },
99 { "syntax_errors_text", opt_stringptr, LOFF(syntax_errors_text) },
100 { "syntax_errors_to", opt_stringptr, LOFF(syntax_errors_to) }
103 /* Size of the options list. An extern variable has to be used so that its
104 address can appear in the tables drtables.c. */
106 int redirect_router_options_count =
107 sizeof(redirect_router_options)/sizeof(optionlist);
113 redirect_router_options_block redirect_router_option_defaults = {0};
114 void redirect_router_init(router_instance *rblock) {}
115 int redirect_router_entry(router_instance *rblock, address_item *addr,
116 struct passwd *pw, int verify, address_item **addr_local,
117 address_item **addr_remote, address_item **addr_new,
118 address_item **addr_succeed) {return 0;}
120 #else /*!MACRO_PREDEF*/
124 /* Default private options block for the redirect router.
125 Unlisted elements are 0/NULL/FALSE */
127 redirect_router_options_block redirect_router_option_defaults = {
129 .bit_options = RDO_REWRITE | RDO_PREPEND_HOME,
130 .check_owner = TRUE_UNSET,
131 .check_group = TRUE_UNSET,
136 /*************************************************
137 * Initialization entry point *
138 *************************************************/
140 /* Called for each instance, after its options have been read, to enable
141 consistency checks to be done, or anything else that needs to be set up. */
143 void redirect_router_init(router_instance *rblock)
145 redirect_router_options_block *ob =
146 (redirect_router_options_block *)(rblock->options_block);
148 /* Either file or data must be set, but not both */
150 if ((ob->file == NULL) == (ob->data == NULL))
151 log_write(0, LOG_PANIC_DIE|LOG_CONFIG_FOR, "%s router:\n "
152 "%sone of \"file\" or \"data\" must be specified",
153 rblock->name, (ob->file == NULL)? "" : "only ");
155 /* Onetime aliases can only be real addresses. Headers can't be manipulated.
156 The combination of one_time and unseen is not allowed. We can't check the
157 expansion of "unseen" here, but we assume that if it is set to anything other
158 than false, there is likely to be a problem. */
162 ob->forbid_pipe = ob->forbid_file = ob->forbid_filter_reply = TRUE;
163 if (rblock->extra_headers || rblock->remove_headers)
164 log_write(0, LOG_PANIC_DIE|LOG_CONFIG_FOR, "%s router:\n "
165 "\"headers_add\" and \"headers_remove\" are not permitted with "
166 "\"one_time\"", rblock->name);
167 if (rblock->unseen || rblock->expand_unseen)
168 log_write(0, LOG_PANIC_DIE|LOG_CONFIG_FOR, "%s router:\n "
169 "\"unseen\" may not be used with \"one_time\"", rblock->name);
172 /* The defaults for check_owner and check_group depend on other settings. The
173 defaults are: Check the owner if check_local_user or owners is set; check the
174 group if check_local_user is set without a restriction on the group write bit,
175 or if owngroups is set. */
177 if (ob->check_owner == TRUE_UNSET)
178 ob->check_owner = rblock->check_local_user ||
179 (ob->owners && ob->owners[0] != 0);
181 if (ob->check_group == TRUE_UNSET)
182 ob->check_group = (rblock->check_local_user && (ob->modemask & 020) == 0) ||
183 (ob->owngroups != NULL && ob->owngroups[0] != 0);
185 /* If explicit qualify domain set, the preserve option is locked out */
187 if (ob->qualify_domain && ob->qualify_preserve_domain)
188 log_write(0, LOG_PANIC_DIE|LOG_CONFIG_FOR, "%s router:\n "
189 "only one of \"qualify_domain\" or \"qualify_preserve_domain\" must be set",
192 /* If allow_filter is set, either user or check_local_user must be set. */
194 if (!rblock->check_local_user &&
196 rblock->expand_uid == NULL &&
197 (ob->bit_options & RDO_FILTER) != 0)
198 log_write(0, LOG_PANIC_DIE|LOG_CONFIG_FOR, "%s router:\n "
199 "\"user\" or \"check_local_user\" must be set with \"allow_filter\"",
205 /*************************************************
206 * Get errors address and header mods *
207 *************************************************/
209 /* This function is called when new addresses are generated, in order to
210 sort out errors address and header modifications. We put the errors address
211 into the parent address (even though it is never used from there because that
212 address is never transported) so that it can be retrieved if any of the
213 children gets routed by an "unseen" router. The clone of the child that is
214 passed on must have the original errors_address value.
217 rblock the router control block
218 addr the address being routed
219 verify v_none/v_recipient/v_sender/v_expn
220 addr_prop point to the propagated block, which is where the
221 new values are to be placed
223 Returns: the result of rf_get_errors_address() or rf_get_munge_headers(),
224 which is either OK or DEFER
228 sort_errors_and_headers(router_instance *rblock, address_item *addr,
229 int verify, address_item_propagated *addr_prop)
231 int frc = rf_get_errors_address(addr, rblock, verify,
232 &addr_prop->errors_address);
233 if (frc != OK) return frc;
234 addr->prop.errors_address = addr_prop->errors_address;
235 return rf_get_munge_headers(addr, rblock, &addr_prop->extra_headers,
236 &addr_prop->remove_headers);
241 /*************************************************
242 * Process a set of generated new addresses *
243 *************************************************/
245 /* This function sets up a set of newly generated child addresses and puts them
246 on the new address chain. Copy in the uid, gid and permission flags for use by
247 pipes and files, set the parent, and "or" its af_ignore_error flag. Also record
248 the setting for any starting router.
250 If the generated address is the same as one of its ancestors, and the
251 check_ancestor flag is set, do not use this generated address, but replace it
252 with a copy of the input address. This is to cope with cases where A is aliased
253 to B and B has a .forward file pointing to A, though it is usually set on the
254 forwardfile rather than the aliasfile. We can't just pass on the old
255 address by returning FAIL, because it must act as a general parent for
256 generated addresses, and only get marked "done" when all its children are
261 addr_new new address chain
262 addr original address
263 generated list of generated addresses
264 addr_prop the propagated block, containing the errors_address,
265 header modification stuff, and address_data
266 ugidptr points to uid/gid data for files, pipes, autoreplies
267 pw password entry, set if ob->check_local_user is TRUE
273 add_generated(router_instance *rblock, address_item **addr_new,
274 address_item *addr, address_item *generated,
275 address_item_propagated *addr_prop, ugid_block *ugidptr, struct passwd *pw)
277 redirect_router_options_block *ob =
278 (redirect_router_options_block *)(rblock->options_block);
282 address_item * next = generated, * parent;
283 const uschar * errors_address = next->prop.errors_address;
285 generated = next->next;
287 next->start_router = rblock->redirect_router;
288 if (addr->child_count == USHRT_MAX)
289 log_write(0, LOG_MAIN|LOG_PANIC_DIE, "%s router generated more than %d "
290 "child addresses for <%s>", rblock->name, USHRT_MAX, addr->address);
293 next->next = *addr_new;
296 /* Don't do the "one_time" thing for the first pass of a 2-stage queue run. */
298 if (ob->one_time && !f.queue_2stage)
300 for (parent = addr; parent->parent; parent = parent->parent) ;
301 next->onetime_parent = parent->address;
304 if (ob->hide_child_in_errmsg) setflag(next, af_hide_child);
306 /* If check_ancestor is set, we want to know if any ancestor of this address
307 is the address we are about to generate. The check must be done caselessly
308 unless the ancestor was routed by a case-sensitive router. */
310 if (ob->check_ancestor)
311 for (parent = addr; parent; parent = parent->parent)
312 if ((parent->router && parent->router->caseful_local_part
313 ? Ustrcmp(next->address, parent->address)
314 : strcmpic(next->address, parent->address)
317 DEBUG(D_route) debug_printf("generated parent replaced by child\n");
318 next->address = string_copy(addr->address);
322 /* A user filter may, under some circumstances, set up an errors address.
323 If so, we must take care to re-instate it when we copy in the propagated
324 data so that it overrides any errors_to setting on the router. */
327 BOOL ignore_error = next->prop.ignore_error;
328 next->prop = *addr_prop;
329 next->prop.ignore_error = ignore_error || addr->prop.ignore_error;
331 if (errors_address) next->prop.errors_address = errors_address;
333 /* For pipes, files, and autoreplies, record this router as handling them,
334 because they don't go through the routing process again. Then set up uid,
335 gid, home and current directories for transporting. */
337 if (testflag(next, af_pfr))
339 next->router = rblock;
340 rf_set_ugid(next, ugidptr); /* Will contain pw values if not overridden */
342 /* When getting the home directory out of the password information, wrap it
343 in \N...\N to avoid expansion later. In Cygwin, home directories can
344 contain $ characters. */
346 if (rblock->home_directory)
347 next->home_dir = rblock->home_directory;
348 else if (rblock->check_local_user)
349 next->home_dir = string_sprintf("\\N%s\\N", pw->pw_dir);
350 else if (rblock->router_home_directory && testflag(addr, af_home_expanded))
352 next->home_dir = deliver_home;
353 setflag(next, af_home_expanded);
356 next->current_dir = rblock->current_directory;
358 /* Permission options */
360 if (!ob->forbid_pipe) setflag(next, af_allow_pipe);
361 if (!ob->forbid_file) setflag(next, af_allow_file);
362 if (!ob->forbid_filter_reply) setflag(next, af_allow_reply);
364 /* If the transport setting fails, the error gets picked up at the outer
365 level from the setting of basic_errno in the address. */
367 if (next->address[0] == '|')
369 address_pipe = next->address;
370 GET_OPTION("pipe_transport");
371 if (rf_get_transport(ob->pipe_transport_name, &ob->pipe_transport,
372 next, rblock->name, US"pipe_transport"))
373 next->transport = ob->pipe_transport;
376 else if (next->address[0] == '>')
378 GET_OPTION("reply_transport");
379 if (rf_get_transport(ob->reply_transport_name, &ob->reply_transport,
380 next, rblock->name, US"reply_transport"))
381 next->transport = ob->reply_transport;
383 else /* must be file or directory */
385 int len = Ustrlen(next->address);
386 address_file = next->address;
387 if (next->address[len-1] == '/')
389 GET_OPTION("directory_transport");
390 if (rf_get_transport(ob->directory_transport_name,
391 &(ob->directory_transport), next, rblock->name,
392 US"directory_transport"))
393 next->transport = ob->directory_transport;
397 GET_OPTION("file_transport");
398 if (rf_get_transport(ob->file_transport_name, &ob->file_transport,
399 next, rblock->name, US"file_transport"))
400 next->transport = ob->file_transport;
408 if (!next->prop.utf8_msg)
409 next->prop.utf8_msg = string_is_utf8(next->address)
410 || (sender_address && string_is_utf8(sender_address));
415 debug_printf("%s router generated %s\n %serrors_to=%s transport=%s\n",
418 testflag(next, af_pfr)? "pipe, file, or autoreply\n " : "",
419 next->prop.errors_address,
420 (next->transport == NULL)? US"NULL" : next->transport->name);
422 if (testflag(next, af_uid_set))
423 debug_printf(" uid=%ld ", (long int)(next->uid));
425 debug_printf(" uid=unset ");
427 if (testflag(next, af_gid_set))
428 debug_printf("gid=%ld ", (long int)(next->gid));
430 debug_printf("gid=unset ");
433 if (next->prop.utf8_msg) debug_printf("utf8 ");
436 debug_printf("home=%s\n", next->home_dir);
442 /*************************************************
444 *************************************************/
446 /* See local README for interface description. This router returns:
449 . empty address list, or filter did nothing significant
452 . verifying the errors address caused a deferment or a big disaster such
453 as an expansion failure (rf_get_errors_address)
454 . expanding a headers_{add,remove} string caused a deferment or another
455 expansion error (rf_get_munge_headers)
456 . :defer: or "freeze" in a filter
457 . error in address list or filter
458 . skipped syntax errors, but failed to send the message
461 . address was :blackhole:d or "seen finish"ed
467 . new addresses added to addr_new
470 int redirect_router_entry(
471 router_instance *rblock, /* data for this instantiation */
472 address_item *addr, /* address we are working on */
473 struct passwd *pw, /* passwd entry after check_local_user */
474 int verify, /* v_none/v_recipient/v_sender/v_expn */
475 address_item **addr_local, /* add it to this if it's local */
476 address_item **addr_remote, /* add it to this if it's remote */
477 address_item **addr_new, /* put new addresses on here */
478 address_item **addr_succeed) /* put old address here on success */
480 redirect_router_options_block *ob =
481 (redirect_router_options_block *)(rblock->options_block);
482 address_item *generated = NULL;
483 const uschar *save_qualify_domain_recipient = qualify_domain_recipient;
484 uschar *discarded = US"discarded";
485 address_item_propagated addr_prop;
486 error_block *eblock = NULL;
488 redirect_block redirect;
490 int filtertype = FILTER_UNSET;
492 int options = ob->bit_options;
496 /* Initialize the data to be propagated to the children */
498 addr_prop.address_data = deliver_address_data;
499 addr_prop.domain_data = deliver_domain_data;
500 addr_prop.localpart_data = deliver_localpart_data;
501 addr_prop.errors_address = NULL;
502 addr_prop.extra_headers = NULL;
503 addr_prop.remove_headers = NULL;
504 addr_prop.variables = NULL;
505 tree_dup((tree_node **)&addr_prop.variables, addr->prop.variables);
508 addr_prop.utf8_msg = addr->prop.utf8_msg;
509 addr_prop.utf8_downcvt = addr->prop.utf8_downcvt;
510 addr_prop.utf8_downcvt_maybe = addr->prop.utf8_downcvt_maybe;
514 /* When verifying and testing addresses, the "logwrite" command in filters
517 if (verify == v_none && !f.address_test_mode) options |= RDO_REALLOG;
519 /* Sort out the fixed or dynamic uid/gid. This uid is used (a) for reading the
520 file (and interpreting a filter) and (b) for running the transports for
521 generated file and pipe addresses. It is not (necessarily) the same as the uids
522 that may own the file. Exim panics if an expanded string is not a number and
523 can't be found in the password file. Other errors set the freezing bit. */
525 if (!rf_get_ugid(rblock, addr, &ugid)) return DEFER;
527 if (!ugid.uid_set && pw != NULL)
529 ugid.uid = pw->pw_uid;
533 if (!ugid.gid_set && pw != NULL)
535 ugid.gid = pw->pw_gid;
539 /* Call the function that interprets redirection data, either inline or from a
540 file. This is a separate function so that the system filter can use it. It will
541 run the function in a subprocess if necessary. If qualify_preserve_domain is
542 set, temporarily reset qualify_domain_recipient to the current domain so that
543 any unqualified addresses get qualified with the same domain as the incoming
544 address. Otherwise, if a local qualify_domain is provided, set that up. */
546 if (ob->qualify_preserve_domain)
547 qualify_domain_recipient = addr->domain;
550 GET_OPTION("qualify_domain");
551 if (ob->qualify_domain)
553 uschar *new_qdr = rf_expand_data(addr, ob->qualify_domain, &xrc);
554 if (!new_qdr) return xrc;
555 qualify_domain_recipient = new_qdr;
559 redirect.owners = ob->owners;
560 redirect.owngroups = ob->owngroups;
561 redirect.modemask = ob->modemask;
562 redirect.check_owner = ob->check_owner;
563 redirect.check_group = ob->check_group;
566 redirect.string = (redirect.isfile = (ob->file != NULL))
567 ? ob->file : ob->data;
569 sieve.vacation_dir = ob->sieve_vacation_directory;
570 sieve.enotify_mailto_owner = ob->sieve_enotify_mailto_owner;
571 sieve.useraddress = ob->sieve_useraddress;
572 sieve.subaddress = ob->sieve_subaddress;
574 frc = rda_interpret(&redirect, options, ob->include_directory, &sieve, &ugid,
575 &generated, &addr->message, ob->skip_syntax_errors ? &eblock : NULL,
576 &filtertype, string_sprintf("%s router (recipient is %s)", rblock->name,
579 qualify_domain_recipient = save_qualify_domain_recipient;
581 /* Handle exceptional returns from filtering or processing an address list.
582 For FAIL and FREEZE we honour any previously set up deliveries by a filter. */
587 addr->message = addr->user_message = NULL;
591 DEBUG(D_route) debug_printf("address :blackhole:d\n");
593 discarded = US":blackhole:";
597 /* FF_DEFER and FF_FAIL can arise only as a result of explicit commands
598 (:defer: or :fail: in an alias file or "fail" in a filter). If a configured
599 message was supplied, allow it to be included in an SMTP response after
600 verifying. Remove any SMTP code if it is not allowed. */
607 if ((xrc = sort_errors_and_headers(rblock, addr, verify, &addr_prop)) != OK)
609 add_generated(rblock, addr_new, addr, generated, &addr_prop, &ugid, pw);
614 addr->message = yield == FAIL ? US"forced rejection" : US"forced defer";
618 if ( ob->forbid_smtp_code
619 && regex_match(regex_smtp_code, addr->message, -1, &matched))
621 DEBUG(D_route) debug_printf("SMTP code at start of error message "
622 "is ignored because forbid_smtp_code is set\n");
623 addr->message += Ustrlen(matched);
625 addr->user_message = addr->message;
626 setflag(addr, af_pass_message);
630 /* As in the case of a system filter, a freeze does not happen after a manual
631 thaw. In case deliveries were set up by the filter, we set the child count
632 high so that their completion does not mark the original address done. */
635 if (!f.deliver_manual_thaw)
637 if ((xrc = sort_errors_and_headers(rblock, addr, verify, &addr_prop))
639 add_generated(rblock, addr_new, addr, generated, &addr_prop, &ugid, pw);
640 if (addr->message == NULL) addr->message = US"frozen by filter";
641 addr->special_action = SPECIAL_FREEZE;
642 addr->child_count = 9999;
645 frc = FF_NOTDELIVERED;
648 /* Handle syntax errors and :include: failures and lookup defers */
653 /* If filtertype is still FILTER_UNSET, it means that the redirection data
654 was never inspected, so the error was an expansion failure or failure to open
655 the file, or whatever. In these cases, the existing error message is probably
658 if (filtertype == FILTER_UNSET) return DEFER;
660 /* If it was a filter and skip_syntax_errors is set, we want to set up
661 the error message so that it can be logged and mailed to somebody. */
663 if (filtertype != FILTER_FORWARD && ob->skip_syntax_errors)
665 eblock = store_get(sizeof(error_block), GET_UNTAINTED);
667 eblock->text1 = addr->message;
668 eblock->text2 = NULL;
669 addr->message = addr->user_message = NULL;
672 /* Otherwise set up the error for the address and defer. */
676 addr->basic_errno = ERRNO_BADREDIRECT;
677 addr->message = string_sprintf("error in %s %s: %s",
678 filtertype == FILTER_FORWARD ? "redirect" : "filter",
679 ob->data ? "data" : "file",
686 /* Yield is either FF_DELIVERED (significant action) or FF_NOTDELIVERED (no
687 significant action). Before dealing with these, however, we must handle the
688 effect of skip_syntax_errors.
690 If skip_syntax_errors was set and there were syntax errors in an address list,
691 error messages will be present in eblock. Log them and send a message if so
692 configured. We cannot do this earlier, because the error message must not be
693 sent as the local user. If there were no valid addresses, generated will be
694 NULL. In this case, the router declines.
696 For a filter file, the error message has been fudged into an eblock. After
697 dealing with it, the router declines. */
701 if (!moan_skipped_syntax_errors(
702 rblock->name, /* For message content */
704 (verify != v_none || f.address_test_mode)?
705 NULL : ob->syntax_errors_to, /* Who to mail */
706 generated != NULL, /* True if not all failed */
707 ob->syntax_errors_text)) /* Custom message */
710 if (filtertype != FILTER_FORWARD || !generated)
712 addr->message = US"syntax error in redirection data";
717 /* Sort out the errors address and any header modifications, and handle the
718 generated addresses, if any. If there are no generated addresses, we must avoid
719 calling sort_errors_and_headers() in case this router declines - that function
720 may modify the errors_address field in the current address, and we don't want
721 to do that for a decline. */
725 if ((xrc = sort_errors_and_headers(rblock, addr, verify, &addr_prop)) != OK)
727 add_generated(rblock, addr_new, addr, generated, &addr_prop, &ugid, pw);
730 /* FF_DELIVERED with no generated addresses is what we get when an address list
731 contains :blackhole: or a filter contains "seen finish" without having
732 generated anything. Log what happened to this address, and return DISCARD. */
734 if (frc == FF_DELIVERED)
736 if (generated == NULL && verify == v_none && !f.address_test_mode)
738 log_write(0, LOG_MAIN, "=> %s <%s> R=%s", discarded, addr->address,
744 /* For an address list, FF_NOTDELIVERED always means that no addresses were
745 generated. For a filter, addresses may or may not have been generated. If none
746 were, it's the same as an empty address list, and the router declines. However,
747 if addresses were generated, we can't just decline because successful delivery
748 of the base address gets it marked "done", so deferred generated addresses
749 never get tried again. We have to generate a new version of the base address,
750 as if there were a "deliver" command in the filter file, with the original
751 address as parent. */
757 if (generated == NULL) return DECLINE;
759 next = deliver_make_addr(addr->address, FALSE);
762 next->next = *addr_new;
765 /* Set the data that propagates. */
767 next->prop = addr_prop;
769 DEBUG(D_route) debug_printf("%s router autogenerated %s\n%s%s%s",
772 (addr_prop.errors_address != NULL)? " errors to " : "",
773 (addr_prop.errors_address != NULL)? addr_prop.errors_address : US"",
774 (addr_prop.errors_address != NULL)? "\n" : "");
777 /* Control gets here only when the address has been completely handled. Put the
778 original address onto the succeed queue so that any retry items that get
779 attached to it get processed. */
781 addr->next = *addr_succeed;
782 *addr_succeed = addr;
787 #endif /*!MACRO_PREDEF*/
788 #endif /*ROUTER_REDIRECT*/
789 /* End of routers/redirect.c */