Debug: option access for expansion
[exim.git] / src / src / deliver.c
index 9d459167e68b32b90517e0c88221c4ea0fc9a8bd..70f44535f0a412e6e52d4c6c25be6d37f05340a8 100644 (file)
@@ -27,7 +27,7 @@ typedef struct pardata {
   int transport_count;         /* returned transport count value */
   BOOL done;                   /* no more data needed */
   uschar *msg;                 /* error message */
-  uschar *return_path;         /* return_path for these addresses */
+  const uschar *return_path;   /* return_path for these addresses */
 } pardata;
 
 /* Values for the process_recipients variable */
@@ -77,7 +77,7 @@ static pardata *parlist = NULL;
 static struct pollfd *parpoll;
 static int  return_count;
 static uschar *frozen_info = US"";
-static uschar *used_return_path = NULL;
+static const uschar * used_return_path = NULL;
 
 
 
@@ -144,7 +144,7 @@ Returns:      a pointer to an initialized address_item
 */
 
 address_item *
-deliver_make_addr(uschar *address, BOOL copy)
+deliver_make_addr(const uschar * address, BOOL copy)
 {
 address_item * addr = store_get(sizeof(address_item), GET_UNTAINTED);
 *addr = address_defaults;
@@ -575,7 +575,7 @@ Returns:    TRUE or FALSE
 */
 
 static BOOL
-same_strings(uschar *one, uschar *two)
+same_strings(const uschar * one, const uschar * two)
 {
 if (one == two) return TRUE;   /* Includes the case where both NULL */
 if (!one || !two) return FALSE;
@@ -898,7 +898,7 @@ void
 msg_event_raise(const uschar * event, const address_item * addr)
 {
 const uschar * save_domain = deliver_domain;
-uschar * save_local =  deliver_localpart;
+const uschar * save_local =  deliver_localpart;
 const uschar * save_host = deliver_host;
 const uschar * save_address = deliver_host_address;
 const int      save_port =   deliver_host_port;
@@ -950,13 +950,13 @@ router_name = transport_name = NULL;
 *        Generate local part for logging         *
 *************************************************/
 
-static uschar *
-string_get_lpart_sub(const address_item * addr, uschar * s)
+static const uschar *
+string_get_lpart_sub(const address_item * addr, const uschar * s)
 {
 #ifdef SUPPORT_I18N
 if (testflag(addr, af_utf8_downcvt))
   {
-  uschar * t = string_localpart_utf8_to_alabel(s, NULL);
+  const uschar * t = string_localpart_utf8_to_alabel(s, NULL);
   return t ? t : s;    /* t is NULL on a failed conversion */
   }
 #endif
@@ -975,7 +975,7 @@ Returns:      the new value of the buffer pointer
 static gstring *
 string_get_localpart(address_item * addr, gstring * yield)
 {
-uschar * s;
+const uschar * s;
 
 if (testflag(addr, af_include_affixes) && (s = addr->prefix))
   yield = string_cat(yield, string_get_lpart_sub(addr, s));
@@ -1245,6 +1245,14 @@ else
     g = string_catn(g, US" K", 2);
   }
 
+#ifndef DISABLE_DKIM
+  if (addr->dkim_used && LOGGING(dkim_verbose))
+    {
+    g = string_catn(g, US" DKIM=", 6);
+    g = string_cat(g, addr->dkim_used);
+    }
+#endif
+
 /* confirmation message (SMTP (host_used) and LMTP (driver_name)) */
 
 if (  LOGGING(smtp_confirmation)
@@ -1850,8 +1858,9 @@ if (tp->gid_set)
   }
 else if (tp->expand_gid)
   {
+  GET_OPTION("group");
   if (!route_find_expanded_group(tp->expand_gid, tp->name, US"transport", gidp,
-    &(addr->message)))
+    &addr->message))
     {
     common_error(FALSE, addr, ERRNO_GIDFAIL, NULL);
     return FALSE;
@@ -1877,6 +1886,7 @@ it does not provide a passwd value from which a gid can be taken. */
 else if (tp->expand_uid)
   {
   struct passwd *pw;
+  GET_OPTION("user");
   if (!route_find_expanded_user(tp->expand_uid, tp->name, US"transport", &pw,
        uidp, &(addr->message)))
     {
@@ -1980,6 +1990,7 @@ check_message_size(transport_instance *tp, address_item *addr)
 int rc = OK;
 int size_limit;
 
+GET_OPTION("message_size_limit");
 deliver_set_expansions(addr);
 size_limit = expand_string_integer(tp->message_size_limit, TRUE);
 deliver_set_expansions(NULL);
@@ -2142,6 +2153,7 @@ if(addr->prop.errors_address)
 else
   return_path = sender_address;
 
+GET_OPTION("return_path");
 if (tp->return_path)
   {
   uschar * new_return_path = expand_string(tp->return_path);
@@ -2171,6 +2183,7 @@ if (!findugid(addr, tp, &uid, &gid, &use_initgroups)) return;
 home directory set in the address may already be expanded; a flag is set to
 indicate that. In other cases we must expand it. */
 
+GET_OPTION("home_directory");
 if (  (deliver_home = tp->home_dir)            /* Set in transport, or */
    || (  (deliver_home = addr->home_dir)       /* Set in address and */
       && !testflag(addr, af_home_expanded)     /*   not expanded */
@@ -2200,6 +2213,7 @@ all users have access. It is necessary to be in a visible directory for some
 operating systems when running pipes, as some commands (e.g. "rm" under Solaris
 2.5) require this. */
 
+GET_OPTION("current_directory");
 working_directory = tp->current_dir ? tp->current_dir : addr->current_dir;
 if (working_directory)
   {
@@ -2597,36 +2611,40 @@ if ((status & 0xffff) != 0)
 
 /* If SPECIAL_WARN is set in the top address, send a warning message. */
 
-if (addr->special_action == SPECIAL_WARN && addr->transport->warn_message)
+if (addr->special_action == SPECIAL_WARN)
   {
-  int fd;
-  uschar *warn_message;
-  pid_t pid;
+  uschar * warn_message = addr->transport->warn_message;
+  GET_OPTION("quota_warn_message");
+  if (warn_message)
+    {
+    int fd;
+    pid_t pid;
 
-  DEBUG(D_deliver) debug_printf("Warning message requested by transport\n");
+    DEBUG(D_deliver) debug_printf("Warning message requested by transport\n");
 
-  if (!(warn_message = expand_string(addr->transport->warn_message)))
-    log_write(0, LOG_MAIN|LOG_PANIC, "Failed to expand \"%s\" (warning "
-      "message for %s transport): %s", addr->transport->warn_message,
-      addr->transport->name, expand_string_message);
+    if (!(warn_message = expand_string(warn_message)))
+      log_write(0, LOG_MAIN|LOG_PANIC, "Failed to expand \"%s\" (warning "
+       "message for %s transport): %s", addr->transport->warn_message,
+       addr->transport->name, expand_string_message);
 
-  else if ((pid = child_open_exim(&fd, US"tpt-warning-message")) > 0)
-    {
-    FILE *f = fdopen(fd, "wb");
-    if (errors_reply_to && !contains_header(US"Reply-To", warn_message))
-      fprintf(f, "Reply-To: %s\n", errors_reply_to);
-    fprintf(f, "Auto-Submitted: auto-replied\n");
-    if (!contains_header(US"From", warn_message))
-      moan_write_from(f);
-    fprintf(f, "%s", CS warn_message);
+    else if ((pid = child_open_exim(&fd, US"tpt-warning-message")) > 0)
+      {
+      FILE * f = fdopen(fd, "wb");
+      if (errors_reply_to && !contains_header(US"Reply-To", warn_message))
+       fprintf(f, "Reply-To: %s\n", errors_reply_to);
+      fprintf(f, "Auto-Submitted: auto-replied\n");
+      if (!contains_header(US"From", warn_message))
+       moan_write_from(f);
+      fprintf(f, "%s", CS warn_message);
 
-    /* Close and wait for child process to complete, without a timeout. */
+      /* Close and wait for child process to complete, without a timeout. */
 
-    (void)fclose(f);
-    (void)child_close(pid, 0);
-    }
+      (void)fclose(f);
+      (void)child_close(pid, 0);
+      }
 
-  addr->special_action = SPECIAL_NONE;
+    addr->special_action = SPECIAL_NONE;
+    }
   }
 }
 
@@ -2642,6 +2660,7 @@ tpt_parallel_check(transport_instance * tp, address_item * addr, uschar ** key)
 {
 unsigned max_parallel;
 
+GET_OPTION("max_parallel");
 if (!tp->max_parallel) return FALSE;
 
 max_parallel = (unsigned) expand_string_integer(tp->max_parallel, TRUE);
@@ -2765,6 +2784,7 @@ while (addr_local)
     /* Expand the batch_id string for comparison with other addresses.
     Expansion failure suppresses batching. */
 
+    GET_OPTION("batch_id");
     if (tp->batch_id)
       {
       deliver_set_expansions(addr);
@@ -2819,11 +2839,12 @@ while (addr_local)
 
       if (ok && batch_id)
         {
-        uschar *bid;
-        address_item *save_nextnext = next->next;
+        uschar * bid;
+        address_item * save_nextnext = next->next;
         next->next = NULL;            /* Expansion for a single address */
         deliver_set_expansions(next);
         next->next = save_nextnext;
+       GET_OPTION("batch_id");
         bid = expand_string(tp->batch_id);
         deliver_set_expansions(NULL);
         if (!bid)
@@ -3571,7 +3592,14 @@ while (!done)
 
       switch (*subid)
        {
-       case 3:         /* explicit notification of continued-connection (non)use;
+#ifndef DISABLE_DKIM
+       case '4':       /* DKIM information */
+         addr->dkim_used = string_copy(ptr);
+         while(*ptr++);
+         break;
+#endif
+
+       case '3':       /* explicit notification of continued-connection (non)use;
                        overrides caller's knowlege. */
          if (*ptr & BIT(1))      setflag(addr, af_new_conn);
          else if (*ptr & BIT(2)) setflag(addr, af_cont_conn);
@@ -4439,9 +4467,10 @@ nonmatch domains
   else
     return_path = sender_address;
 
+  GET_OPTION("return_path");
   if (tp->return_path)
     {
-    uschar *new_return_path = expand_string(tp->return_path);
+    uschar * new_return_path = expand_string(tp->return_path);
     if (new_return_path)
       return_path = new_return_path;
     else if (!f.expand_string_forcedfail)
@@ -4886,6 +4915,15 @@ all pipes, so I do not see a reason to use non-blocking IO here
         rmt_dlv_checked_write(fd, 'R', '0', big_buffer, ptr - big_buffer);
         }
 
+#ifndef DISABLE_DKIM
+      if (addr->dkim_used && LOGGING(dkim_verbose))
+       {
+       DEBUG(D_deliver) debug_printf("dkim used: %s\n", addr->dkim_used);
+       ptr = big_buffer + sprintf(CS big_buffer, "%.128s", addr->dkim_used) + 1;
+        rmt_dlv_checked_write(fd, 'A', '4', big_buffer, ptr - big_buffer);
+       }
+#endif
+
       if (testflag(addr, af_new_conn) || testflag(addr, af_cont_conn))
        {
        DEBUG(D_deliver) debug_printf("%scontinued-connection\n",
@@ -5086,7 +5124,7 @@ Returns:    OK
 int
 deliver_split_address(address_item * addr)
 {
-uschar * address = addr->address;
+const uschar * address = addr->address;
 uschar * domain;
 uschar * t;
 int len;
@@ -5103,7 +5141,7 @@ where they are locally interpreted. [The new draft "821" is more explicit on
 this, Jan 1999.] We know the syntax is valid, so this can be done by simply
 removing quoting backslashes and any unquoted doublequotes. */
 
-t = addr->cc_local_part = store_get(len+1, address);
+addr->cc_local_part = t = store_get(len+1, address);
 while(len-- > 0)
   {
   int c = *address++;
@@ -5115,7 +5153,7 @@ while(len-- > 0)
     }
   else *t++ = c;
   }
-*t = 0;
+*t = '\0';
 
 /* We do the percent hack only for those domains that are listed in
 percent_hack_domains. A loop is required, to copy with multiple %-hacks. */
@@ -5123,8 +5161,8 @@ percent_hack_domains. A loop is required, to copy with multiple %-hacks. */
 if (percent_hack_domains)
   {
   int rc;
-  uschar *new_address = NULL;
-  uschar *local_part = addr->cc_local_part;
+  uschar * new_address = NULL;
+  const uschar * local_part = addr->cc_local_part;
 
   deliver_domain = addr->domain;  /* set $domain */
 
@@ -5261,12 +5299,12 @@ Returns:       TRUE if the address is not hidden
 */
 
 static BOOL
-print_address_information(address_item *addr, FILE *f, uschar *si, uschar *sc,
-  uschar *se)
+print_address_information(address_item * addr, FILE * f, uschar * si,
+  uschar * sc, uschar * se)
 {
 BOOL yield = TRUE;
-uschar *printed = US"";
-address_item *ancestor = addr;
+const uschar * printed = US"";
+address_item * ancestor = addr;
 while (ancestor->parent) ancestor = ancestor->parent;
 
 fprintf(f, "%s", CS si);
@@ -5281,8 +5319,8 @@ else if (!testflag(addr, af_pfr) || !addr->parent)
 
 else
   {
-  uschar *s = addr->address;
-  uschar *ss;
+  const uschar * s = addr->address;
+  const uschar * ss;
 
   if (addr->address[0] == '>') { ss = US"mail"; s++; }
   else if (addr->address[0] == '|') ss = US"pipe";
@@ -5296,7 +5334,7 @@ fprintf(f, "%s", CS string_printing(printed));
 
 if (ancestor != addr)
   {
-  uschar *original = ancestor->onetime_parent;
+  const uschar * original = ancestor->onetime_parent;
   if (!original) original= ancestor->address;
   if (strcmpic(original, printed) != 0)
     fprintf(f, "%s(%sgenerated from %s)", sc,
@@ -5533,18 +5571,18 @@ return actual_time;
 
 static FILE *
 expand_open(const uschar * filename,
-  const uschar * varname, const uschar * reason)
+  const uschar * optname, const uschar * reason)
 {
 const uschar * s = expand_cstring(filename);
 FILE * fp = NULL;
 
 if (!s || !*s)
   log_write(0, LOG_MAIN|LOG_PANIC,
-    "Failed to expand %s: '%s'\n", varname, filename);
+    "Failed to expand %s: '%s'\n", optname, filename);
 else if (*s != '/' || is_tainted(s))
   log_write(0, LOG_MAIN|LOG_PANIC,
     "%s is not %s after expansion: '%s'\n",
-    varname, *s == '/' ? "untainted" : "absolute", s);
+    optname, *s == '/' ? "untainted" : "absolute", s);
 else if (!(fp = Ufopen(s, "rb")))
   log_write(0, LOG_MAIN|LOG_PANIC, "Failed to open %s for %s "
     "message texts: %s", s, reason, strerror(errno));
@@ -5675,6 +5713,7 @@ else
   /* Open a template file if one is provided. Log failure to open, but
   carry on - default texts will be used. */
 
+  GET_OPTION("bounce_message_file");
   if (bounce_message_file)
     emf = expand_open(bounce_message_file,
            US"bounce_message_file", US"error");
@@ -6034,6 +6073,7 @@ transport_ctx tctx = {{0}};
 
 if (pid <= 0) return FALSE;
 
+GET_OPTION("warn_message_file");
 if (warn_message_file)
   wmf = expand_open(warn_message_file,
          US"warn_message_file", US"warning");
@@ -6733,6 +6773,7 @@ else if (system_filter && process_recipients != RECIP_FAIL_TIMEOUT)
 
   /* Any error in the filter file causes a delivery to be abandoned. */
 
+  GET_OPTION("system_filter");
   redirect.string = system_filter;
   redirect.isfile = TRUE;
   redirect.check_owner = redirect.check_group = FALSE;
@@ -6912,12 +6953,14 @@ else if (system_filter && process_recipients != RECIP_FAIL_TIMEOUT)
         if (p->address[0] == '|')
           {
           type = US"pipe";
+         GET_OPTION("system_filter_pipe_transport");
           tpname = system_filter_pipe_transport;
           address_pipe = p->address;
           }
         else if (p->address[0] == '>')
           {
           type = US"reply";
+         GET_OPTION("system_filter_reply_transport");
           tpname = system_filter_reply_transport;
           }
         else
@@ -6925,11 +6968,13 @@ else if (system_filter && process_recipients != RECIP_FAIL_TIMEOUT)
           if (p->address[Ustrlen(p->address)-1] == '/')
             {
             type = US"directory";
+           GET_OPTION("system_filter_directory_transport");
             tpname = system_filter_directory_transport;
             }
           else
             {
             type = US"file";
+           GET_OPTION("system_filter_file_transport");
             tpname = system_filter_file_transport;
             }
           address_file = p->address;
@@ -6973,7 +7018,7 @@ else if (system_filter && process_recipients != RECIP_FAIL_TIMEOUT)
 
         if (!p->transport)
           {
-          address_item *badp = p;
+          address_item * badp = p;
           p = p->next;
           if (!addr_last) addr_new = p; else addr_last->next = p;
           badp->local_part = badp->address;   /* Needed for log line */
@@ -7114,9 +7159,10 @@ if (process_recipients != RECIP_IGNORE)
 #ifndef DISABLE_EVENT
       if (process_recipients != RECIP_ACCEPT && event_action)
        {
-       uschar * save_local =  deliver_localpart;
+       const uschar * save_local =  deliver_localpart;
        const uschar * save_domain = deliver_domain;
-       uschar * addr = new->address, * errmsg = NULL;
+       const uschar * addr = new->address;
+       uschar * errmsg = NULL;
        int start, end, dom;
 
        if (!parse_extract_address(addr, &errmsg, &start, &end, &dom, TRUE))
@@ -8365,7 +8411,7 @@ else if (addr_defer != (address_item *)(+1))
 
       for (i = 0; i < recipients_count; i++)
         {
-        uschar *r = recipients_list[i].address;
+        const uschar * r = recipients_list[i].address;
         if (Ustrcmp(otaddr->onetime_parent, r) == 0) t = i;
         if (Ustrcmp(otaddr->address, r) == 0) break;
         }
@@ -8393,7 +8439,7 @@ else if (addr_defer != (address_item *)(+1))
 
     if (sender_address[0])
       {
-      uschar * s = addr->prop.errors_address;
+      const uschar * s = addr->prop.errors_address;
       if (!s) s = sender_address;
       if (Ustrstr(recipients, s) == NULL)
        recipients = string_sprintf("%s%s%s", recipients,
@@ -8412,54 +8458,57 @@ else if (addr_defer != (address_item *)(+1))
         || addr_defer->dsn_flags & rf_notify_delay
        )
      && delay_warning[1] > 0
-     && sender_address[0] != 0
-     && (  !delay_warning_condition
-        || expand_check_condition(delay_warning_condition,
-            US"delay_warning", US"option")
-       )
-     )
+     && sender_address[0] != 0)
     {
-    int count;
-    int show_time;
-    int queue_time = time(NULL) - received_time.tv_sec;
-
-    queue_time = test_harness_fudged_queue_time(queue_time);
-
-    /* See how many warnings we should have sent by now */
+    GET_OPTION("delay_warning_condition");
+    if ( (  !delay_warning_condition
+           || expand_check_condition(delay_warning_condition,
+               US"delay_warning", US"option")
+         )
+       )
+      {
+      int count;
+      int show_time;
+      int queue_time = time(NULL) - received_time.tv_sec;
 
-    for (count = 0; count < delay_warning[1]; count++)
-      if (queue_time < delay_warning[count+2]) break;
+      queue_time = test_harness_fudged_queue_time(queue_time);
 
-    show_time = delay_warning[count+1];
+      /* See how many warnings we should have sent by now */
 
-    if (count >= delay_warning[1])
-      {
-      int extra;
-      int last_gap = show_time;
-      if (count > 1) last_gap -= delay_warning[count];
-      extra = (queue_time - delay_warning[count+1])/last_gap;
-      show_time += last_gap * extra;
-      count += extra;
-      }
+      for (count = 0; count < delay_warning[1]; count++)
+       if (queue_time < delay_warning[count+2]) break;
 
-    DEBUG(D_deliver)
-      {
-      debug_printf("time on queue = %s  id %s  addr %s\n",
-       readconf_printtime(queue_time), message_id, addr_defer->address);
-      debug_printf("warning counts: required %d done %d\n", count,
-        warning_count);
-      }
+      show_time = delay_warning[count+1];
 
-    /* We have computed the number of warnings there should have been by now.
-    If there haven't been enough, send one, and up the count to what it should
-    have been. */
+      if (count >= delay_warning[1])
+       {
+       int extra;
+       int last_gap = show_time;
+       if (count > 1) last_gap -= delay_warning[count];
+       extra = (queue_time - delay_warning[count+1])/last_gap;
+       show_time += last_gap * extra;
+       count += extra;
+       }
 
-    if (warning_count < count)
-      if (send_warning_message(recipients, queue_time, show_time))
+      DEBUG(D_deliver)
        {
-       warning_count = count;
-       update_spool = TRUE;    /* Ensure spool rewritten */
+       debug_printf("time on queue = %s  id %s  addr %s\n",
+         readconf_printtime(queue_time), message_id, addr_defer->address);
+       debug_printf("warning counts: required %d done %d\n", count,
+         warning_count);
        }
+
+      /* We have computed the number of warnings there should have been by now.
+      If there haven't been enough, send one, and up the count to what it should
+      have been. */
+
+      if (warning_count < count)
+       if (send_warning_message(recipients, queue_time, show_time))
+         {
+         warning_count = count;
+         update_spool = TRUE;    /* Ensure spool rewritten */
+         }
+      }
     }
 
   /* Clear deliver_domain */