constification
[exim.git] / src / src / routers / redirect.c
index 641a5ef6ef9d147a384308d08bcbd1aa49eed413..0189d237a07b8a2394c1ae49b9e251f00a11291a 100644 (file)
@@ -1,10 +1,8 @@
-/* $Cambridge: exim/src/src/routers/redirect.c,v 1.11 2005/05/24 08:15:02 tom Exp $ */
-
 /*************************************************
 *     Exim - an Internet mail transport agent    *
 *************************************************/
 
-/* Copyright (c) University of Cambridge 1995 - 2005 */
+/* Copyright (c) University of Cambridge 1995 - 2009 */
 /* See the file NOTICE for conditions of use and distribution. */
 
 
@@ -39,6 +37,8 @@ optionlist redirect_router_options[] = {
       (void *)offsetof(redirect_router_options_block, file) },
   { "file_transport",     opt_stringptr,
       (void *)offsetof(redirect_router_options_block, file_transport_name) },
+  { "filter_prepend_home",opt_bit | (RDON_PREPEND_HOME << 16),
+      (void *)offsetof(redirect_router_options_block, bit_options) },
   { "forbid_blackhole",   opt_bit | (RDON_BLACKHOLE << 16),
       (void *)offsetof(redirect_router_options_block, bit_options) },
   { "forbid_exim_filter", opt_bit | (RDON_EXIM_FILTER << 16),
@@ -69,6 +69,8 @@ optionlist redirect_router_options[] = {
       (void *)offsetof(redirect_router_options_block, forbid_pipe) },
   { "forbid_sieve_filter",opt_bit | (RDON_SIEVE_FILTER << 16),
       (void *)offsetof(redirect_router_options_block, bit_options) },
+  { "forbid_smtp_code",     opt_bool,
+      (void *)offsetof(redirect_router_options_block, forbid_smtp_code) },
   { "hide_child_in_errmsg", opt_bool,
       (void *)offsetof(redirect_router_options_block,  hide_child_in_errmsg) },
   { "ignore_eacces",      opt_bit | (RDON_EACCES << 16),
@@ -97,6 +99,8 @@ optionlist redirect_router_options[] = {
       (void *)offsetof(redirect_router_options_block, reply_transport_name) },
   { "rewrite",            opt_bit | (RDON_REWRITE << 16),
       (void *)offsetof(redirect_router_options_block, bit_options) },
+  { "sieve_enotify_mailto_owner", opt_stringptr,
+      (void *)offsetof(redirect_router_options_block, sieve_enotify_mailto_owner) },
   { "sieve_subaddress", opt_stringptr,
       (void *)offsetof(redirect_router_options_block, sieve_subaddress) },
   { "sieve_useraddress", opt_stringptr,
@@ -147,6 +151,7 @@ redirect_router_options_block redirect_router_option_defaults = {
   NULL,        /* sieve_subaddress */
   NULL,        /* sieve_useraddress */
   NULL,        /* sieve_vacation_directory */
+  NULL,        /* sieve_enotify_mailto_owner */
   NULL,        /* syntax_errors_text */
   NULL,        /* syntax_errors_to */
   NULL,        /* qualify_domain */
@@ -160,13 +165,14 @@ redirect_router_options_block redirect_router_option_defaults = {
   NULL,        /* srs_dbselect */
 #endif
   022,         /* modemask */
-  RDO_REWRITE, /* bit_options */
+  RDO_REWRITE | RDO_PREPEND_HOME, /* bit_options */
   FALSE,       /* check_ancestor */
   TRUE_UNSET,  /* check_owner */
   TRUE_UNSET,  /* check_group */
   FALSE,       /* forbid_file */
   FALSE,       /* forbid_filter_reply */
   FALSE,       /* forbid_pipe */
+  FALSE,       /* forbid_smtp_code */
   FALSE,       /* hide_child_in_errmsg */
   FALSE,       /* one_time */
   FALSE,       /* qualify_preserve_domain */
@@ -258,7 +264,7 @@ passed on must have the original errors_address value.
 Arguments:
   rblock               the router control block
   addr                 the address being routed
-  verify               true if verifying
+  verify               v_none/v_recipient/v_sender/v_expn
   addr_prop            point to the propagated block, which is where the
                          new values are to be placed
 
@@ -268,7 +274,7 @@ Returns:    the result of rf_get_errors_address() or rf_get_munge_headers(),
 
 static int
 sort_errors_and_headers(router_instance *rblock, address_item *addr,
-  BOOL verify, address_item_propagated *addr_prop)
+  int verify, address_item_propagated *addr_prop)
 {
 int frc = rf_get_errors_address(addr, rblock, verify,
   &(addr_prop->errors_address));
@@ -329,6 +335,9 @@ while (generated != NULL)
   next->parent = addr;
   orflag(next, addr, af_ignore_error);
   next->start_router = rblock->redirect_router;
+  if (addr->child_count == SHRT_MAX)
+    log_write(0, LOG_MAIN|LOG_PANIC_DIE, "%s router generated more than %d "
+      "child addresses for <%s>", rblock->name, SHRT_MAX, addr->address);
   addr->child_count++;
 
   next->next = *addr_new;
@@ -499,7 +508,7 @@ int redirect_router_entry(
   router_instance *rblock,        /* data for this instantiation */
   address_item *addr,             /* address we are working on */
   struct passwd *pw,              /* passwd entry after check_local_user */
-  BOOL verify,                    /* TRUE when verifying */
+  int verify,                     /* v_none/v_recipient/v_sender/v_expn */
   address_item **addr_local,      /* add it to this if it's local */
   address_item **addr_remote,     /* add it to this if it's remote */
   address_item **addr_new,        /* put new addresses on here */
@@ -508,7 +517,7 @@ int redirect_router_entry(
 redirect_router_options_block *ob =
   (redirect_router_options_block *)(rblock->options_block);
 address_item *generated = NULL;
-uschar *save_qualify_domain_recipient = qualify_domain_recipient;
+const uschar *save_qualify_domain_recipient = qualify_domain_recipient;
 uschar *discarded = US"discarded";
 address_item_propagated addr_prop;
 error_block *eblock = NULL;
@@ -539,7 +548,7 @@ addr_prop.srs_sender = NULL;
 /* When verifying and testing addresses, the "logwrite" command in filters
 must be bypassed. */
 
-if (!verify && !address_test_mode) options |= RDO_REALLOG;
+if (verify == v_none && !address_test_mode) options |= RDO_REALLOG;
 
 /* Sort out the fixed or dynamic uid/gid. This uid is used (a) for reading the
 file (and interpreting a filter) and (b) for running the transports for
@@ -573,7 +582,7 @@ if (!ugid.gid_set && pw != NULL)
 
     if(usesrs)
     {
-      int srs_action, n_srs;
+      int srs_action = 0, n_srs;
       uschar *res;
       uschar *usedomain;
 
@@ -598,9 +607,10 @@ if (!ugid.gid_set && pw != NULL)
         eximsrs_init();
         if(ob->srs_dbselect)
           eximsrs_db_set(TRUE, ob->srs_dbselect);
-// Comment this out for now...
+/* Comment this out for now...
 //        else
 //          eximsrs_db_set(TRUE, NULL);
+*/
 
         if((n_srs = eximsrs_reverse(&res, addr->address)) == OK)
         {
@@ -617,16 +627,18 @@ if (!ugid.gid_set && pw != NULL)
 
       /* Forward SRS */
       /* No point in actually performing SRS if we are just verifying a recipient */
-      if((srs_action & 1) && !verify && (sender_address ? sender_address[0] != 0 : FALSE))
+      if((srs_action & 1) && verify == v_none &&
+         (sender_address ? sender_address[0] != 0 : FALSE))
       {
 
         srs_orig_sender = sender_address;
         eximsrs_init();
         if(ob->srs_dbinsert)
           eximsrs_db_set(FALSE, ob->srs_dbinsert);
-// Comment this out for now...
+/* Comment this out for now...
 //        else
 //          eximsrs_db_set(FALSE, NULL);
+*/
 
         if(ob->srs_alias != NULL ? (usedomain = expand_string(ob->srs_alias)) == NULL : 1)
           usedomain = deliver_domain;
@@ -682,10 +694,10 @@ else
   }
 
 frc = rda_interpret(&redirect, options, ob->include_directory,
-  ob->sieve_vacation_directory, ob->sieve_useraddress, ob->sieve_subaddress,
-  &ugid, &generated, &(addr->message), ob->skip_syntax_errors? &eblock : NULL,
-  &filtertype, string_sprintf("%s router (recipient is %s)", rblock->name,
-  addr->address));
+  ob->sieve_vacation_directory, ob->sieve_enotify_mailto_owner,
+  ob->sieve_useraddress, ob->sieve_subaddress, &ugid, &generated,
+  &(addr->message), ob->skip_syntax_errors? &eblock : NULL, &filtertype,
+  string_sprintf("%s router (recipient is %s)", rblock->name, addr->address));
 
 qualify_domain_recipient = save_qualify_domain_recipient;
 
@@ -706,26 +718,39 @@ switch (frc)
   break;
 
   /* FF_DEFER and FF_FAIL can arise only as a result of explicit commands
-  (:fail: in an alias file or "fail" in a filter). If a configured message was
-  supplied, allow it to be included in an SMTP response after verifying. */
+  (:defer: or :fail: in an alias file or "fail" in a filter). If a configured
+  message was supplied, allow it to be included in an SMTP response after
+  verifying. Remove any SMTP code if it is not allowed. */
 
   case FF_DEFER:
-  if (addr->message == NULL) addr->message = US"forced defer";
-    else addr->user_message = addr->message;
-  return DEFER;
+  yield = DEFER;
+  goto SORT_MESSAGE;
 
   case FF_FAIL:
   if ((xrc = sort_errors_and_headers(rblock, addr, verify, &addr_prop)) != OK)
     return xrc;
   add_generated(rblock, addr_new, addr, generated, &addr_prop, &ugid, pw);
+  yield = FAIL;
+
+  SORT_MESSAGE:
   if (addr->message == NULL)
-    addr->message = US"forced rejection";
+    addr->message = (yield == FAIL)? US"forced rejection" : US"forced defer";
   else
     {
+    int ovector[3];
+    if (ob->forbid_smtp_code &&
+        pcre_exec(regex_smtp_code, NULL, CS addr->message,
+          Ustrlen(addr->message), 0, PCRE_EOPT,
+          ovector, sizeof(ovector)/sizeof(int)) >= 0)
+      {
+      DEBUG(D_route) debug_printf("SMTP code at start of error message "
+        "is ignored because forbid_smtp_code is set\n");
+      addr->message += ovector[1];
+      }
     addr->user_message = addr->message;
     setflag(addr, af_pass_message);
     }
-  return FAIL;
+  return yield;
 
   /* As in the case of a system filter, a freeze does not happen after a manual
   thaw. In case deliveries were set up by the filter, we set the child count
@@ -799,12 +824,12 @@ dealing with it, the router declines. */
 if (eblock != NULL)
   {
   if (!moan_skipped_syntax_errors(
-        rblock->name,                           /* For message content */
-        eblock,                                 /* Ditto */
-        (verify || address_test_mode)?
-          NULL : ob->syntax_errors_to,          /* Who to mail */
-        generated != NULL,                      /* True if not all failed */
-        ob->syntax_errors_text))                /* Custom message */
+        rblock->name,                            /* For message content */
+        eblock,                                  /* Ditto */
+        (verify != v_none || address_test_mode)?
+          NULL : ob->syntax_errors_to,           /* Who to mail */
+        generated != NULL,                       /* True if not all failed */
+        ob->syntax_errors_text))                 /* Custom message */
     return DEFER;
 
   if (filtertype != FILTER_FORWARD || generated == NULL)
@@ -833,7 +858,7 @@ generated anything. Log what happened to this address, and return DISCARD. */
 
 if (frc == FF_DELIVERED)
   {
-  if (generated == NULL && !verify && !address_test_mode)
+  if (generated == NULL && verify == v_none && !address_test_mode)
     {
     log_write(0, LOG_MAIN, "=> %s <%s> R=%s", discarded, addr->address,
       rblock->name);