Use dsn_from for success-DSN messages. Bug 2404
[exim.git] / src / src / deliver.c
index 664d00452ab2e7175c46ac1b09f19e982fb5dddc..ada042a24e935e6579bbdc33ccfe10120733862a 100644 (file)
@@ -284,13 +284,12 @@ to the same pipe or file. */
 
 else
   {
-  address_item *addr2;
   if (testflag(addr, af_pfr))
     {
     if (testflag(addr, af_file))        address_file = addr->local_part;
     else if (addr->local_part[0] == '|') address_pipe = addr->local_part;
     }
-  for (addr2 = addr->next; addr2; addr2 = addr2->next)
+  for (address_item * addr2 = addr->next; addr2; addr2 = addr2->next)
     {
     if (deliver_domain && Ustrcmp(deliver_domain, addr2->domain) != 0)
       deliver_domain = NULL;
@@ -329,11 +328,9 @@ Returns:    a file descriptor, or -1 (with errno set)
 static int
 open_msglog_file(uschar *filename, int mode, uschar **error)
 {
-int fd, i;
-
-for (i = 2; i > 0; i--)
+for (int i = 2; i > 0; i--)
   {
-  fd = Uopen(filename,
+  int fd = Uopen(filename,
 #ifdef O_CLOEXEC
     O_CLOEXEC |
 #endif
@@ -350,7 +347,7 @@ for (i = 2; i > 0; i--)
 #ifndef O_CLOEXEC
     (void)fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
 #endif
-    if (fchown(fd, exim_uid, exim_gid) < 0)
+    if (exim_fchown(fd, exim_uid, exim_gid, filename) < 0)
       {
       *error = US"chown";
       return -1;
@@ -370,7 +367,7 @@ for (i = 2; i > 0; i--)
                        MSGLOG_DIRECTORY_MODE, TRUE);
   }
 
-*error = US"create";
+*error = US"create or open";
 return -1;
 }
 
@@ -422,8 +419,7 @@ Returns:     nothing
 static void
 replicate_status(address_item *addr)
 {
-address_item *addr2;
-for (addr2 = addr->next; addr2; addr2 = addr2->next)
+for (address_item * addr2 = addr->next; addr2; addr2 = addr2->next)
   {
   addr2->transport =       addr->transport;
   addr2->transport_return = addr->transport_return;
@@ -657,8 +653,6 @@ Returns:      nothing
 static void
 address_done(address_item *addr, uschar *now)
 {
-address_item *dup;
-
 update_spool = TRUE;        /* Ensure spool gets updated */
 
 /* Top-level address */
@@ -685,7 +679,7 @@ else tree_add_nonrecipient(addr->unique);
 /* Check the list of duplicate addresses and ensure they are now marked
 done as well. */
 
-for (dup = addr_duplicate; dup; dup = dup->next)
+for (address_item * dup = addr_duplicate; dup; dup = dup->next)
   if (Ustrcmp(addr->unique, dup->unique) == 0)
     {
     tree_add_nonrecipient(dup->unique);
@@ -716,9 +710,10 @@ Returns:    nothing
 static void
 child_done(address_item *addr, uschar *now)
 {
-address_item *aa;
 while (addr->parent)
   {
+  address_item *aa;
+
   addr = addr->parent;
   if (--addr->child_count > 0) return;   /* Incomplete parent */
   address_done(addr, now);
@@ -763,7 +758,7 @@ if (LOGGING(incoming_interface) && LOGGING(outgoing_interface)
   {
   g = string_fmt_append(g, " I=[%s]", sending_ip_address);
   if (LOGGING(outgoing_port))
-    g = string_fmt_append(g, "%d", sending_port);
+    g = string_fmt_append(g, ":%d", sending_port);
   }
 return g;
 }
@@ -806,14 +801,20 @@ return g;
 
 
 
-#ifdef SUPPORT_TLS
+#ifndef DISABLE_TLS
 static gstring *
-d_tlslog(gstring * s, address_item * addr)
+d_tlslog(gstring * g, address_item * addr)
 {
 if (LOGGING(tls_cipher) && addr->cipher)
-  s = string_append(s, 2, US" X=", addr->cipher);
+  {
+  g = string_append(g, 2, US" X=", addr->cipher);
+#ifdef EXPERIMENTAL_TLS_RESUME
+  if (LOGGING(tls_resumption) && testflag(addr, af_tls_resume))
+    g = string_catn(g, US"*", 1);
+#endif
+  }
 if (LOGGING(tls_certificate_verified) && addr->cipher)
-  s = string_append(s, 2, US" CV=",
+  g = string_append(g, 2, US" CV=",
     testflag(addr, af_cert_verified)
     ?
 #ifdef SUPPORT_DANE
@@ -824,8 +825,8 @@ if (LOGGING(tls_certificate_verified) && addr->cipher)
       "yes"
     : "no");
 if (LOGGING(tls_peerdn) && addr->peerdn)
-  s = string_append(s, 3, US" DN=\"", string_printing(addr->peerdn), US"\"");
-return s;
+  g = string_append(g, 3, US" DN=\"", string_printing(addr->peerdn), US"\"");
+return g;
 }
 #endif
 
@@ -861,6 +862,7 @@ if (action)
     {
     DEBUG(D_deliver)
       debug_printf("Event(%s): event_action returned \"%s\"\n", event, s);
+    errno = ERRNO_EVENT;
     return s;
     }
   }
@@ -1061,8 +1063,7 @@ if (  (all_parents || testflag(addr, af_pfr))
    && addr->parent != topaddr)
   {
   uschar *s = US" (";
-  address_item *addr2;
-  for (addr2 = addr->parent; addr2 != topaddr; addr2 = addr2->parent)
+  for (address_item * addr2 = addr->parent; addr2 != topaddr; addr2 = addr2->parent)
     {
     g = string_catn(g, s, 2);
     g = string_cat (g, addr2->address);
@@ -1230,7 +1231,7 @@ else
 #endif
     }
 
-#ifdef SUPPORT_TLS
+#ifndef DISABLE_TLS
   g = d_tlslog(g, addr);
 #endif
 
@@ -1249,7 +1250,7 @@ else
     {
     if (testflag(addr, af_pipelining))
       g = string_catn(g, US" L", 2);
-#ifdef EXPERIMENTAL_PIPE_CONNECT
+#ifdef SUPPORT_PIPE_CONNECT
     if (testflag(addr, af_early_pipe))
       g = string_catn(g, US"*", 1);
 #endif
@@ -1271,12 +1272,11 @@ if (  LOGGING(smtp_confirmation)
    && (addr->host_used || Ustrcmp(addr->transport->driver_name, "lmtp") == 0)
    )
   {
-  unsigned i;
   unsigned lim = big_buffer_size < 1024 ? big_buffer_size : 1024;
   uschar *p = big_buffer;
   uschar *ss = addr->message;
   *p++ = '\"';
-  for (i = 0; i < lim && ss[i] != 0; i++)      /* limit logged amount */
+  for (int i = 0; i < lim && ss[i] != 0; i++)  /* limit logged amount */
     {
     if (ss[i] == '\"' || ss[i] == '\\') *p++ = '\\'; /* quote \ and " */
     *p++ = ss[i];
@@ -1435,7 +1435,7 @@ if (addr->transport)
 if (addr->host_used)
   g = d_hostlog(g, addr);
 
-#ifdef SUPPORT_TLS
+#ifndef DISABLE_TLS
 g = d_tlslog(g, addr);
 #endif
 
@@ -1635,7 +1635,7 @@ if (result == OK)
     }
 
   /* Certificates for logging (via events) */
-#ifdef SUPPORT_TLS
+#ifndef DISABLE_TLS
   tls_out.ourcert = addr->ourcert;
   addr->ourcert = NULL;
   tls_out.peercert = addr->peercert;
@@ -1651,7 +1651,7 @@ if (result == OK)
 
   delivery_log(LOG_MAIN, addr, logchar, NULL);
 
-#ifdef SUPPORT_TLS
+#ifndef DISABLE_TLS
   tls_free_cert(&tls_out.ourcert);
   tls_free_cert(&tls_out.peercert);
   tls_out.cipher = NULL;
@@ -1782,7 +1782,6 @@ Returns:       nothing
 static void
 common_error(BOOL logit, address_item *addr, int code, uschar *format, ...)
 {
-address_item *addr2;
 addr->basic_errno = code;
 
 if (format)
@@ -1796,7 +1795,7 @@ if (format)
   addr->message = string_from_gstring(g);
   }
 
-for (addr2 = addr->next; addr2; addr2 = addr2->next)
+for (address_item * addr2 = addr->next; addr2; addr2 = addr2->next)
   {
   addr2->basic_errno = code;
   addr2->message = addr->message;
@@ -1826,9 +1825,8 @@ Returns:      TRUE if the uid is on the list
 static BOOL
 check_never_users(uid_t uid, uid_t *nusers)
 {
-int i;
 if (!nusers) return FALSE;
-for (i = 1; i <= (int)(nusers[0]); i++) if (nusers[i] == uid) return TRUE;
+for (int i = 1; i <= (int)(nusers[0]); i++) if (nusers[i] == uid) return TRUE;
 return FALSE;
 }
 
@@ -2373,9 +2371,8 @@ if ((pid = fork()) == 0)
 
   DEBUG(D_deliver)
     {
-    address_item *batched;
     debug_printf("  home=%s current=%s\n", deliver_home, working_directory);
-    for (batched = addr->next; batched; batched = batched->next)
+    for (address_item * batched = addr->next; batched; batched = batched->next)
       debug_printf("additional batched address: %s\n", batched->address);
     }
 
@@ -2909,7 +2906,7 @@ while (addr_local)
   of these checks, rather than for all local deliveries, because some local
   deliveries (e.g. to pipes) can take a substantial time. */
 
-  if (!(dbm_file = dbfn_open(US"retry", O_RDONLY, &dbblock, FALSE)))
+  if (!(dbm_file = dbfn_open(US"retry", O_RDONLY, &dbblock, FALSE, TRUE)))
     {
     DEBUG(D_deliver|D_retry|D_hints_lookup)
       debug_printf("no retry data available\n");
@@ -3113,12 +3110,7 @@ while (addr_local)
 
         DEBUG(D_deliver|D_transport)
           debug_printf("%s shadow transport returned %s for %s\n",
-            stp->name,
-            sresult == OK ?    "OK" :
-            sresult == DEFER ? "DEFER" :
-            sresult == FAIL ?  "FAIL" :
-            sresult == PANIC ? "PANIC" : "?",
-            shadow_addr->address);
+            stp->name, rc_to_string(sresult), shadow_addr->address);
         }
 
       DEBUG(D_deliver|D_transport)
@@ -3147,12 +3139,7 @@ while (addr_local)
 
     DEBUG(D_deliver|D_transport)
       debug_printf("%s transport returned %s for %s\n",
-        tp->name,
-        result == OK ?    "OK" :
-        result == DEFER ? "DEFER" :
-        result == FAIL ?  "FAIL" :
-        result == PANIC ? "PANIC" : "?",
-        addr2->address);
+        tp->name, rc_to_string(result), addr2->address);
 
     /* If there is a retry_record, or if delivery is deferred, build a retry
     item for setting a new retry time or deleting the old retry record from
@@ -3285,9 +3272,8 @@ while (  *aptr
 
 DEBUG(D_deliver)
   {
-  address_item *addr;
   debug_printf("remote addresses after sorting:\n");
-  for (addr = addr_remote; addr; addr = addr->next)
+  for (address_item * addr = addr_remote; addr; addr = addr->next)
     debug_printf("  %s\n", addr->address);
   }
 }
@@ -3519,7 +3505,7 @@ while (!done)
     it in with the other info, in order to keep each message short enough to
     guarantee it won't be split in the pipe. */
 
-#ifdef SUPPORT_TLS
+#ifndef DISABLE_TLS
     case 'X':
       if (!addr) goto ADDR_MISMATCH;          /* Below, in 'A' handler */
       switch (*subid)
@@ -3557,7 +3543,7 @@ while (!done)
        }
       while (*ptr++);
       break;
-#endif /*SUPPORT_TLS*/
+#endif /*DISABLE_TLS*/
 
     case 'C':  /* client authenticator information */
       switch (*subid)
@@ -3578,7 +3564,7 @@ while (!done)
     case 'L':
       switch (*subid)
        {
-#ifdef EXPERIMENTAL_PIPE_CONNECT
+#ifdef SUPPORT_PIPE_CONNECT
        case 2: setflag(addr, af_early_pipe);   /*FALLTHROUGH*/
 #endif
        case 1: setflag(addr, af_pipelining); break;
@@ -3792,12 +3778,10 @@ static void
 remote_post_process(address_item *addr, int logflags, uschar *msg,
   BOOL fallback)
 {
-host_item *h;
-
 /* If any host addresses were found to be unusable, add them to the unusable
 tree so that subsequent deliveries don't try them. */
 
-for (h = addr->host_list; h; h = h->next)
+for (host_item * h = addr->host_list; h; h = h->next)
   if (h->address)
     if (h->status >= hstatus_unusable) tree_add_unusable(h);
 
@@ -4231,7 +4215,6 @@ static BOOL
 do_remote_deliveries(BOOL fallback)
 {
 int parmax;
-int delivery_count;
 int poffset;
 
 parcount = 0;    /* Number of executing subprocesses */
@@ -4255,7 +4238,7 @@ if (!parlist)
 
 /* Now loop for each remote delivery */
 
-for (delivery_count = 0; addr_remote; delivery_count++)
+for (int delivery_count = 0; addr_remote; delivery_count++)
   {
   pid_t pid;
   uid_t uid;
@@ -4554,9 +4537,8 @@ for (delivery_count = 0; addr_remote; delivery_count++)
         && addr->host_list
         )
        {
-       host_item * h;
        ok = FALSE;
-       for (h = addr->host_list; h; h = h->next)
+       for (host_item * h = addr->host_list; h; h = h->next)
          if (Ustrcmp(h->name, continue_hostname) == 0)
   /*XXX should also check port here */
            { ok = TRUE; break; }
@@ -4608,12 +4590,9 @@ for (delivery_count = 0; addr_remote; delivery_count++)
     interface to the transport. */
 
     for (next = addr_remote; next && !f.continue_more; next = next->next)
-      {
-      host_item *h;
-      for (h = next->host_list; h; h = h->next)
+      for (host_item * h = next->host_list; h; h = h->next)
         if (Ustrcmp(h->name, continue_hostname) == 0)
           { f.continue_more = TRUE; break; }
-      }
     }
 
   /* The transports set up the process info themselves as they may connect
@@ -4821,9 +4800,12 @@ all pipes, so I do not see a reason to use non-blocking IO here
 #ifdef SUPPORT_DANE
       if (tls_out.dane_verified)        setflag(addr, af_dane_verified);
 #endif
+# ifdef EXPERIMENTAL_TLS_RESUME
+      if (tls_out.resumption & RESUME_USED) setflag(addr, af_tls_resume);
+# endif
 
       /* Use an X item only if there's something to send */
-#ifdef SUPPORT_TLS
+#ifndef DISABLE_TLS
       if (addr->cipher)
         {
         ptr = big_buffer + sprintf(CS big_buffer, "%.128s", addr->cipher) + 1;
@@ -4866,7 +4848,7 @@ all pipes, so I do not see a reason to use non-blocking IO here
         rmt_dlv_checked_write(fd, 'X', '4', big_buffer, ptr - big_buffer);
        }
 # endif
-#endif /*SUPPORT_TLS*/
+#endif /*DISABLE_TLS*/
 
       if (client_authenticator)
         {
@@ -4890,7 +4872,7 @@ all pipes, so I do not see a reason to use non-blocking IO here
 #endif
 
       if (testflag(addr, af_pipelining))
-#ifdef EXPERIMENTAL_PIPE_CONNECT
+#ifdef SUPPORT_PIPE_CONNECT
        if (testflag(addr, af_early_pipe))
          rmt_dlv_checked_write(fd, 'L', '2', NULL, 0);
        else
@@ -5030,7 +5012,7 @@ all pipes, so I do not see a reason to use non-blocking IO here
 
   if (cutthrough.cctx.sock >= 0 && cutthrough.callout_hold_only)
     {
-#ifdef SUPPORT_TLS
+#ifndef DISABLE_TLS
     if (cutthrough.is_tls)
       tls_close(cutthrough.cctx.tls_ctx, TLS_NO_SHUTDOWN);
 #endif
@@ -5262,15 +5244,12 @@ static int
 continue_closedown(void)
 {
 if (continue_transport)
-  {
-  transport_instance *t;
-  for (t = transports; t; t = t->next)
+  for (transport_instance * t = transports; t; t = t->next)
     if (Ustrcmp(t->name, continue_transport) == 0)
       {
       if (t->info->closedown) (t->info->closedown)(t);
       break;
       }
-  }
 return DELIVER_NOT_ATTEMPTED;
 }
 
@@ -6265,7 +6244,7 @@ if (process_recipients != RECIP_IGNORE)
         }
 
 #ifndef DISABLE_EVENT
-      if (process_recipients != RECIP_ACCEPT)
+      if (process_recipients != RECIP_ACCEPT && event_action)
        {
        uschar * save_local =  deliver_localpart;
        const uschar * save_domain = deliver_domain;
@@ -6292,9 +6271,8 @@ if (process_recipients != RECIP_IGNORE)
 
 DEBUG(D_deliver)
   {
-  address_item *p;
   debug_printf("Delivery address list:\n");
-  for (p = addr_new; p; p = p->next)
+  for (address_item * p = addr_new; p; p = p->next)
     debug_printf("  %s %s\n", p->address,
       p->onetime_parent ? p->onetime_parent : US"");
   }
@@ -6352,7 +6330,7 @@ while (addr_new)           /* Loop until all addresses dealt with */
   /* Failure to open the retry database is treated the same as if it does
   not exist. In both cases, dbm_file is NULL. */
 
-  if (!(dbm_file = dbfn_open(US"retry", O_RDONLY, &dbblock, FALSE)))
+  if (!(dbm_file = dbfn_open(US"retry", O_RDONLY, &dbblock, FALSE, TRUE)))
     DEBUG(D_deliver|D_retry|D_route|D_hints_lookup)
       debug_printf("no retry data available\n");
 
@@ -6938,22 +6916,21 @@ while (addr_new)           /* Loop until all addresses dealt with */
 
 DEBUG(D_deliver|D_retry|D_route)
   {
-  address_item *p;
   debug_printf(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
   debug_printf("After routing:\n  Local deliveries:\n");
-  for (p = addr_local; p; p = p->next)
+  for (address_item * p = addr_local; p; p = p->next)
     debug_printf("    %s\n", p->address);
 
   debug_printf("  Remote deliveries:\n");
-  for (p = addr_remote; p; p = p->next)
+  for (address_item * p = addr_remote; p; p = p->next)
     debug_printf("    %s\n", p->address);
 
   debug_printf("  Failed addresses:\n");
-  for (p = addr_failed; p; p = p->next)
+  for (address_item * p = addr_failed; p; p = p->next)
     debug_printf("    %s\n", p->address);
 
   debug_printf("  Deferred addresses:\n");
-  for (p = addr_defer; p; p = p->next)
+  for (address_item * p = addr_defer; p; p = p->next)
     debug_printf("    %s\n", p->address);
   }
 
@@ -7104,7 +7081,7 @@ if (addr_local || addr_remote)
     that the mode is correct - the group setting doesn't always seem to get
     set automatically. */
 
-    if(  fchown(journal_fd, exim_uid, exim_gid)
+    if(  exim_fchown(journal_fd, exim_uid, exim_gid, fname)
       || fchmod(journal_fd, SPOOL_MODE)
 #ifndef O_CLOEXEC
       || fcntl(journal_fd, F_SETFD, fcntl(journal_fd, F_GETFD) | FD_CLOEXEC)
@@ -7235,8 +7212,8 @@ if (mua_wrapper)
   {
   if (addr_defer)
     {
-    address_item *addr, *nextaddr;
-    for (addr = addr_defer; addr; addr = nextaddr)
+    address_item * nextaddr;
+    for (address_item * addr = addr_defer; addr; addr = nextaddr)
       {
       log_write(0, LOG_MAIN, "** %s mua_wrapper forced failure for deferred "
         "delivery", addr->address);
@@ -7365,8 +7342,8 @@ if (addr_senddsn)
     if (errors_reply_to)
       fprintf(f, "Reply-To: %s\n", errors_reply_to);
 
+    moan_write_from(f);
     fprintf(f, "Auto-Submitted: auto-generated\n"
-       "From: Mail Delivery System <Mailer-Daemon@%s>\n"
        "To: %s\n"
        "Subject: Delivery Status Notification\n"
        "Content-Type: multipart/report; report-type=delivery-status; boundary=%s\n"
@@ -7377,7 +7354,7 @@ if (addr_senddsn)
 
        "This message was created automatically by mail delivery software.\n"
        " ----- The following addresses had successful delivery notifications -----\n",
-      qualify_domain_sender, sender_address, bound, bound);
+      sender_address, bound, bound);
 
     for (addr_dsntmp = addr_senddsn; addr_dsntmp;
         addr_dsntmp = addr_dsntmp->next)
@@ -7433,7 +7410,7 @@ if (addr_senddsn)
 
     tctx.u.fd = fd;
     tctx.options = topt_add_return_path | topt_no_body;
-    /*XXX hmm, retval ignored.
+    /*XXX hmm, FALSE(fail) retval ignored.
     Could error for any number of reasons, and they are not handled. */
     transport_write_message(&tctx, 0);
     fflush(f);
@@ -8063,14 +8040,13 @@ was set just to keep the message on the spool, so there is nothing to do here.
 
 else if (addr_defer != (address_item *)(+1))
   {
-  address_item *addr;
   uschar *recipients = US"";
   BOOL want_warning_msg = FALSE;
 
   deliver_domain = testflag(addr_defer, af_pfr)
     ? addr_defer->parent->domain : addr_defer->domain;
 
-  for (addr = addr_defer; addr; addr = addr->next)
+  for (address_item * addr = addr_defer; addr; addr = addr->next)
     {
     address_item *otaddr;
 
@@ -8537,14 +8513,9 @@ if (!regex_SIZE) regex_SIZE =
 if (!regex_AUTH) regex_AUTH =
   regex_must_compile(AUTHS_REGEX, FALSE, TRUE);
 
-#ifdef SUPPORT_TLS
+#ifndef DISABLE_TLS
 if (!regex_STARTTLS) regex_STARTTLS =
   regex_must_compile(US"\\n250[\\s\\-]STARTTLS(\\s|\\n|$)", FALSE, TRUE);
-
-# ifdef EXPERIMENTAL_REQUIRETLS
-if (!regex_REQUIRETLS) regex_REQUIRETLS =
-  regex_must_compile(US"\\n250[\\s\\-]REQUIRETLS(\\s|\\n|$)", FALSE, TRUE);
-# endif
 #endif
 
 if (!regex_CHUNKING) regex_CHUNKING =
@@ -8566,7 +8537,7 @@ if (!regex_DSN) regex_DSN  =
 if (!regex_IGNOREQUOTA) regex_IGNOREQUOTA =
   regex_must_compile(US"\\n250[\\s\\-]IGNOREQUOTA(\\s|\\n|$)", FALSE, TRUE);
 
-#ifdef EXPERIMENTAL_PIPE_CONNECT
+#ifdef SUPPORT_PIPE_CONNECT
 if (!regex_EARLY_PIPE) regex_EARLY_PIPE =
   regex_must_compile(US"\\n250[\\s\\-]" EARLY_PIPE_FEATURE_NAME "(\\s|\\n|$)", FALSE, TRUE);
 #endif
@@ -8632,7 +8603,7 @@ if (cutthrough.cctx.sock >= 0 && cutthrough.callout_hold_only)
   smtp_peer_options = cutthrough.peer_options;
   continue_sequence = 0;
 
-#ifdef SUPPORT_TLS
+#ifndef DISABLE_TLS
   if (cutthrough.is_tls)
     {
     int pfd[2], pid;
@@ -8675,7 +8646,7 @@ else
   }
 return;                /* compiler quietening; control does not reach here. */
 
-#ifdef SUPPORT_TLS
+#ifndef DISABLE_TLS
 fail:
   log_write(0,
     LOG_MAIN | (exec_type == CEE_EXEC_EXIT ? LOG_PANIC : LOG_PANIC_DIE),