]> git.netwichtig.de Git - user/henk/code/exim.git/blobdiff - src/src/deliver.c
Close dangling file. Bug 1379
[user/henk/code/exim.git] / src / src / deliver.c
index 2ee69d37e93a7565e1db069b2b1395c40b52c666..5000f1cbc38a22b2f408c3798c0b1cfd431d5e92 100644 (file)
@@ -718,27 +718,27 @@ d_tlslog(uschar * s, int * sizep, int * ptrp, address_item * addr)
 
 
 
-#ifdef EXPERIMENTAL_TPDA
-int
-tpda_raise_event(uschar * action, uschar * event, uschar * ev_data)
+#ifdef EXPERIMENTAL_EVENT
+uschar *
+event_raise(uschar * action, uschar * event, uschar * ev_data)
 {
 uschar * s;
 if (action)
   {
   DEBUG(D_deliver)
-    debug_printf("TPDA(%s): tpda_event_action=|%s| tpda_delivery_IP=%s\n",
+    debug_printf("Event(%s): event_action=|%s| delivery_IP=%s\n",
       event,
       action, deliver_host_address);
 
-  tpda_event = event;
-  tpda_data =  ev_data;
+  event_name = event;
+  event_data = ev_data;
 
   if (!(s = expand_string(action)) && *expand_string_message)
     log_write(0, LOG_MAIN|LOG_PANIC,
-      "failed to expand tpda_event_action %s in %s: %s\n",
+      "failed to expand event_action %s in %s: %s\n",
       event, transport_name, expand_string_message);
 
-  tpda_event = tpda_data = NULL;
+  event_name = event_data = NULL;
 
   /* If the expansion returns anything but an empty string, flag for
   the caller to modify his normal processing
@@ -746,18 +746,19 @@ if (action)
   if (s && *s)
     {
     DEBUG(D_deliver)
-      debug_printf("TPDA(%s): event_action returned \"%s\"\n", event, s);
-    return DEFER;
+      debug_printf("Event(%s): event_action returned \"%s\"\n", event, s);
+    return s;
     }
   }
-return OK;
+return NULL;
 }
 
 static void
-tpda_msg_event(uschar * event, address_item * addr)
+msg_event_raise(uschar * event, address_item * addr)
 {
 uschar * save_domain = deliver_domain;
 uschar * save_local =  deliver_localpart;
+uschar * save_host =   deliver_host;
 
 if (!addr->transport)
   return;
@@ -766,16 +767,18 @@ router_name =    addr->router ? addr->router->name : NULL;
 transport_name = addr->transport->name;
 deliver_domain = addr->domain;
 deliver_localpart = addr->local_part;
+deliver_host =   addr->host_used ? addr->host_used->name : NULL;
 
-(void) tpda_raise_event(addr->transport->tpda_event_action, event,
+(void) event_raise(addr->transport->event_action, event,
          addr->host_used || Ustrcmp(addr->transport->driver_name, "lmtp") == 0
          ? addr->message : NULL);
 
+deliver_host =      save_host;
 deliver_localpart = save_local;
 deliver_domain =    save_domain;
 router_name = transport_name = NULL;
 }
-#endif /*EXPERIMENTAL_TPDA*/
+#endif /*EXPERIMENTAL_EVENT*/
 
 
 
@@ -795,13 +798,12 @@ int ptr = 0;            /* expanding buffer, for */
 uschar *s;              /* building log lines;   */
 void *reset_point;      /* released afterwards.  */
 
-
 /* Log the delivery on the main log. We use an extensible string to build up
 the log line, and reset the store afterwards. Remote deliveries should always
 have a pointer to the host item that succeeded; local deliveries can have a
 pointer to a single host item in their host list, for use by the transport. */
 
-#ifdef EXPERIMENTAL_TPDA
+#ifdef EXPERIMENTAL_EVENT
   /* presume no successful remote delivery */
   lookup_dnssec_authenticated = NULL;
 #endif
@@ -868,9 +870,10 @@ else
     if (continue_sequence > 1)
       s = string_cat(s, &size, &ptr, US"*", 1);
 
-#ifdef EXPERIMENTAL_TPDA
+#ifdef EXPERIMENTAL_EVENT
     deliver_host_address = addr->host_used->address;
     deliver_host_port =    addr->host_used->port;
+    deliver_host =         addr->host_used->name;
 
     /* DNS lookup status */
     lookup_dnssec_authenticated = addr->host_used->dnssec==DS_YES ? US"yes"
@@ -936,9 +939,8 @@ store we used to build the line after writing it. */
 s[ptr] = 0;
 log_write(0, flags, "%s", s);
 
-#ifdef EXPERIMENTAL_TPDA
-/*XXX cutthrough calls this also for non-delivery...*/
-tpda_msg_event(US"msg:delivery", addr);
+#ifdef EXPERIMENTAL_EVENT
+if (!msg) msg_event_raise(US"msg:delivery", addr);
 #endif
 
 store_reset(reset_point);
@@ -979,7 +981,6 @@ int ptr = 0;            /* expanding buffer, for */
 uschar *s;              /* building log lines;   */
 void *reset_point;      /* released afterwards.  */
 
-
 DEBUG(D_deliver) debug_printf("post-process %s (%d)\n", addr->address, result);
 
 /* Set up driver kind and name for logging. Disable logging if the router or
@@ -1137,7 +1138,7 @@ if (result == OK)
     child_done(addr, now);
     }
 
-  /* Certificates for logging (via TPDA) */
+  /* Certificates for logging (via events) */
 #ifdef SUPPORT_TLS
   tls_out.ourcert = addr->ourcert;
   addr->ourcert = NULL;
@@ -1255,6 +1256,11 @@ else if (result == DEFER || result == PANIC)
       s = string_append(s, &size, &ptr, 2, US": ",
         US strerror(addr->basic_errno));
 
+    if (addr->host_used)
+      s = string_append(s, &size, &ptr, 5,
+                       US" H=", addr->host_used->name,
+                       US" [",  addr->host_used->address, US"]");
+
     if (addr->message != NULL)
       s = string_append(s, &size, &ptr, 2, US": ", addr->message);
 
@@ -1375,8 +1381,8 @@ else
 
   log_write(0, LOG_MAIN, "** %s", s);
 
-#ifdef EXPERIMENTAL_TPDA
-  tpda_msg_event(US"msg:fail:delivery", addr);
+#ifdef EXPERIMENTAL_EVENT
+  msg_event_raise(US"msg:fail:delivery", addr);
 #endif
 
   store_reset(reset_point);
@@ -2988,16 +2994,15 @@ while (!done)
      to get all available data from pipe. unfinished has to be true 
      as well. */
   if (remaining < required)
+    {
     if (unfinished)
       continue;
-    else
-      {
-      msg = string_sprintf("failed to read pipe from transport process "
-        "%d for transport %s: required size=%d > remaining size=%d and unfinished=false", 
-        pid, addr->transport->driver_name, required, remaining);
-      done = TRUE;
-      break;
-      }
+    msg = string_sprintf("failed to read pipe from transport process "
+      "%d for transport %s: required size=%d > remaining size=%d and unfinished=false", 
+      pid, addr->transport->driver_name, required, remaining);
+    done = TRUE;
+    break;
+    }
 
   /* step behind the header */
   ptr += PIPE_HEADER_SIZE;
@@ -3703,7 +3708,7 @@ if (size > 99999)
 /* two write() calls would increase the complexity of reading from pipe */
 
 /* convert size to human readable string prepended by id and subid */
-header_length = snprintf(writebuffer, PIPE_HEADER_SIZE+1, "%c%c%05d", id, subid, size);
+header_length = snprintf(CS writebuffer, PIPE_HEADER_SIZE+1, "%c%c%05d", id, subid, size);
 if (header_length != PIPE_HEADER_SIZE)
 {
   log_write(0, LOG_MAIN|LOG_PANIC_DIE, "header snprintf failed\n");
@@ -3839,9 +3844,20 @@ for (delivery_count = 0; addr_remote != NULL; delivery_count++)
     }
 
   /* Get the flag which specifies whether the transport can handle different
-  domains that nevertheless resolve to the same set of hosts. */
-
-  multi_domain = tp->multi_domain;
+  domains that nevertheless resolve to the same set of hosts. If it needs
+  expanding, get variables set: $address_data, $domain_data, $localpart_data,
+  $host, $host_address, $host_port. */
+  if (tp->expand_multi_domain)
+    deliver_set_expansions(addr);
+
+  if (exp_bool(addr, US"transport", tp->name, D_transport,
+               US"multi_domain", tp->multi_domain, tp->expand_multi_domain,
+               &multi_domain) != OK)
+    {
+    deliver_set_expansions(NULL);
+    remote_post_process(addr, LOG_MAIN|LOG_PANIC, addr->message, fallback);
+    continue;
+    }
 
   /* Get the maximum it can handle in one envelope, with zero meaning
   unlimited, which is forced for the MUA wrapper case. */
@@ -3910,26 +3926,35 @@ for (delivery_count = 0; addr_remote != NULL; delivery_count++)
   entirely different domains. The host list pointers can be NULL in the case
   where the hosts are defined in the transport. There is also a configured
   maximum limit of addresses that can be handled at once (see comments above
-  for how it is computed). */
+  for how it is computed).
+  If the transport does not handle multiple domains, enforce that also,
+  and if it might need a per-address check for this, re-evaluate it.
+  */
 
   while ((next = *anchor) != NULL && address_count < address_count_max)
     {
-    if ((multi_domain || Ustrcmp(next->domain, addr->domain) == 0)
-        &&
-        tp == next->transport
-        &&
-        same_hosts(next->host_list, addr->host_list)
-        &&
-        same_strings(next->p.errors_address, addr->p.errors_address)
-        &&
-        same_headers(next->p.extra_headers, addr->p.extra_headers)
-        &&
-        same_ugid(tp, next, addr)
-        &&
-        (next->p.remove_headers == addr->p.remove_headers ||
-          (next->p.remove_headers != NULL &&
-           addr->p.remove_headers != NULL &&
-           Ustrcmp(next->p.remove_headers, addr->p.remove_headers) == 0)))
+    BOOL md;
+    if (  (multi_domain || Ustrcmp(next->domain, addr->domain) == 0)
+       && tp == next->transport
+       && same_hosts(next->host_list, addr->host_list)
+       && same_strings(next->p.errors_address, addr->p.errors_address)
+       && same_headers(next->p.extra_headers, addr->p.extra_headers)
+       && same_ugid(tp, next, addr)
+       && (  next->p.remove_headers == addr->p.remove_headers
+         || (  next->p.remove_headers != NULL
+            && addr->p.remove_headers != NULL
+            && Ustrcmp(next->p.remove_headers, addr->p.remove_headers) == 0
+         )  )
+       && (  !multi_domain
+         || (  (
+               !tp->expand_multi_domain || (deliver_set_expansions(next), 1),
+               exp_bool(addr,
+                   US"transport", next->transport->name, D_transport,
+                   US"multi_domain", next->transport->multi_domain,
+                   next->transport->expand_multi_domain, &md) == OK
+               )
+            && md
+       )  )  )
       {
       *anchor = next->next;
       next->next = NULL;
@@ -3939,6 +3964,7 @@ for (delivery_count = 0; addr_remote != NULL; delivery_count++)
       address_count++;
       }
     else anchor = &(next->next);
+    deliver_set_expansions(NULL);
     }
 
   /* If we are acting as an MUA wrapper, all addresses must go in a single
@@ -4342,9 +4368,9 @@ for (delivery_count = 0; addr_remote != NULL; delivery_count++)
 #ifndef DISABLE_PRDR
       if (addr->flags & af_prdr_used)
        rmt_dlv_checked_write(fd, 'P', '0', NULL, 0);
-      #endif
+#endif
 
-      #ifdef EXPERIMENTAL_DSN
+#ifdef EXPERIMENTAL_DSN
       memcpy(big_buffer, &addr->dsn_aware, sizeof(addr->dsn_aware));
       rmt_dlv_checked_write(fd, 'D', '0', big_buffer, sizeof(addr->dsn_aware));
       DEBUG(D_deliver) debug_printf("DSN write: addr->dsn_aware = %d\n", addr->dsn_aware);
@@ -4718,6 +4744,10 @@ if (ancestor != addr)
       string_printing(original));
   }
 
+if (addr->host_used)
+  fprintf(f, "\n    host %s [%s]",
+         addr->host_used->name, addr->host_used->address);
+
 fprintf(f, "%s", CS se);
 return yield;
 }
@@ -4784,8 +4814,56 @@ while (*s != 0)
 }
 
 
+#ifdef EXPERIMENTAL_DSN
+/***********************************************************
+*         Print Diagnostic-Code for an address             *
+************************************************************/
 
+/* This function is called to print the error information out of an address for
+a bounce or a warning message. It tries to format the message reasonably as
+required by RFC 3461 by adding a space after each newline
+
+we assume that this function is only called if addr->host_used is set and if so
+a useable addr->message is available containing some Exim description with ": \n" 
+ending, followed by the L/SMTP error message.
+
+Arguments:
+  addr         the address
+  f            the FILE to print on
 
+Returns:       nothing
+*/
+
+static void
+print_dsn_diagnostic_code(const address_item *addr, FILE *f)
+{
+uschar * s;
+
+/* check host_used, af_pass_message flag and addr->message for safety reasons */
+if (!addr->host_used && testflag(addr, af_pass_message) && addr->message)
+  return;
+
+/* search first ": ". we assume to find the remote-MTA answer there */
+DEBUG(D_deliver)
+  debug_printf("DSN Diagnostic-Code: addr->dsn_message = %s\n", addr->message);
+if (!(s = Ustrstr(addr->message, ": ")))
+  return;                              /* not found, bail out */
+
+fprintf(f, "Diagnostic-Code: smtp; ");
+
+s += 2;  /* skip ": " */
+while (*s)
+  if (*s == '\\' && s[1] == 'n')
+    {
+    fputs("\n ", f);    /* as defined in RFC 3461 */
+    s += 2;
+    }
+  else
+    fputc(*s++, f);
+
+fputc('\n', f);
+}
+#endif  /* EXPERIMENTAL_DSN */
 
 
 /*************************************************
@@ -5576,7 +5654,7 @@ if (process_recipients != RECIP_IGNORE)
         break;
         }
 
-#ifdef EXPERIMENTAL_TPDA
+#ifdef EXPERIMENTAL_EVENT
       if (process_recipients != RECIP_ACCEPT)
        {
        uschar * save_local =  deliver_localpart;
@@ -5587,7 +5665,7 @@ if (process_recipients != RECIP_IGNORE)
        deliver_domain =    expand_string(
                      string_sprintf("${domain:%s}", new->address));
 
-       (void) tpda_raise_event(delivery_event_action,
+       (void) event_raise(event_action,
                      US"msg:fail:internal", new->message);
 
        deliver_localpart = save_local;
@@ -6550,6 +6628,7 @@ if (mua_wrapper)
     {
     uschar *s = (addr_failed->user_message != NULL)?
       addr_failed->user_message : addr_failed->message;
+    host_item * host;
 
     fprintf(stderr, "Delivery failed: ");
     if (addr_failed->basic_errno > 0)
@@ -6557,6 +6636,8 @@ if (mua_wrapper)
       fprintf(stderr, "%s", strerror(addr_failed->basic_errno));
       if (s != NULL) fprintf(stderr, ": ");
       }
+    if ((host = addr_failed->host_used))
+      fprintf(stderr, "H=%s [%s]: ", host->name, host->address);
     if (s == NULL)
       {
       if (addr_failed->basic_errno <= 0) fprintf(stderr, "unknown error");
@@ -6648,14 +6729,13 @@ if (addr_senddsn != NULL)
     FILE *f = fdopen(fd, "wb");
     /* header only as required by RFC. only failure DSN needs to honor RET=FULL */
     int topt = topt_add_return_path | topt_no_body;
-    uschar boundaryStr[64];
+    uschar * bound;
      
     DEBUG(D_deliver) debug_printf("sending error message to: %s\n", sender_address);
   
     /* build unique id for MIME boundary */
-    snprintf(boundaryStr, sizeof(boundaryStr)-1, TIME_T_FMT "-eximdsn-%d",
-      time(NULL), rand());
-    DEBUG(D_deliver) debug_printf("DSN: MIME boundary: %s\n", boundaryStr);
+    bound = string_sprintf(TIME_T_FMT "-eximdsn-%d", time(NULL), rand());
+    DEBUG(D_deliver) debug_printf("DSN: MIME boundary: %s\n", bound);
   
     if (errors_reply_to)
       fprintf(f, "Reply-To: %s\n", errors_reply_to);
@@ -6672,7 +6752,7 @@ if (addr_senddsn != NULL)
    
        "This message was created automatically by mail delivery software.\n"
        " ----- The following addresses had successful delivery notifications -----\n",
-      qualify_domain_sender, sender_address, boundaryStr, boundaryStr);
+      qualify_domain_sender, sender_address, bound, bound);
 
     addr_dsntmp = addr_senddsn;
     while(addr_dsntmp)
@@ -6690,7 +6770,7 @@ if (addr_senddsn != NULL)
     fprintf(f, "--%s\n"
        "Content-type: message/delivery-status\n\n"
        "Reporting-MTA: dns; %s\n",
-      boundaryStr, smtp_active_hostname);
+      bound, smtp_active_hostname);
 
     if (dsn_envid != NULL) {
       /* must be decoded from xtext: see RFC 3461:6.3a */
@@ -6723,7 +6803,7 @@ if (addr_senddsn != NULL)
       fputc('\n', f);
       }
 
-    fprintf(f, "--%s\nContent-type: text/rfc822-headers\n\n", boundaryStr);
+    fprintf(f, "--%s\nContent-type: text/rfc822-headers\n\n", bound);
            
     fflush(f);
     transport_filter_argv = NULL;   /* Just in case */
@@ -6733,8 +6813,7 @@ if (addr_senddsn != NULL)
     transport_write_message(NULL, fileno(f), topt, 0, NULL, NULL, NULL, NULL, NULL, 0);
     fflush(f);
 
-    fprintf(f,"\n");       
-    fprintf(f,"--%s--\n", boundaryStr);
+    fprintf(f,"\n--%s--\n", bound);
 
     fflush(f);
     fclose(f);
@@ -6859,7 +6938,7 @@ while (addr_failed != NULL)
       int max = (bounce_return_size_limit/DELIVER_IN_BUFFER_SIZE + 1) *
         DELIVER_IN_BUFFER_SIZE;
 #ifdef EXPERIMENTAL_DSN
-      uschar boundaryStr[64];
+      uschar * bound;
       uschar *dsnlimitmsg;
       uschar *dsnnotifyhdr;
       int topt;
@@ -6919,13 +6998,12 @@ while (addr_failed != NULL)
 
 #ifdef EXPERIMENTAL_DSN
       /* generate boundary string and output MIME-Headers */
-      snprintf(boundaryStr, sizeof(boundaryStr)-1, TIME_T_FMT "-eximdsn-%d",
-       time(NULL), rand());
+      bound = string_sprintf(TIME_T_FMT "-eximdsn-%d", time(NULL), rand());
 
       fprintf(f, "Content-Type: multipart/report;"
            " report-type=delivery-status; boundary=%s\n"
          "MIME-Version: 1.0\n",
-       boundaryStr);
+       bound);
 #endif
 
       /* Open a template file if one is provided. Log failure to open, but
@@ -6955,7 +7033,7 @@ while (addr_failed != NULL)
       /* output human readable part as text/plain section */
       fprintf(f, "--%s\n"
          "Content-type: text/plain; charset=us-ascii\n\n",
-       boundaryStr);
+       bound);
 #endif
 
       if ((emf_text = next_emf(emf, US"intro")))
@@ -7088,7 +7166,7 @@ wording. */
       fprintf(f, "--%s\n"
          "Content-type: message/delivery-status\n\n"
          "Reporting-MTA: dns; %s\n",
-       boundaryStr, smtp_active_hostname);
+       bound, smtp_active_hostname);
 
       if (dsn_envid)
        {
@@ -7108,8 +7186,11 @@ wording. */
            "Status: 5.0.0\n",
            addr->address);
         if (addr->host_used && addr->host_used->name)
-          fprintf(f, "Remote-MTA: dns; %s\nDiagnostic-Code: smtp; %d\n",
-           addr->host_used->name, addr->basic_errno);
+          {
+          fprintf(f, "Remote-MTA: dns; %s\n",
+           addr->host_used->name);
+          print_dsn_diagnostic_code(addr, f);
+          }
         }
 #endif
 
@@ -7190,7 +7271,7 @@ wording. */
          bounce_return_size_limit is always honored.
       */
   
-      fprintf(f, "\n--%s\n", boundaryStr);
+      fprintf(f, "\n--%s\n", bound);
 
       dsnlimitmsg = US"X-Exim-DSN-Information: Due to administrative limits only headers are returned";
       dsnnotifyhdr = NULL;
@@ -7235,7 +7316,7 @@ wording. */
       if (emf)
         (void)fclose(emf);
  
-      fprintf(f, "\n--%s--\n", boundaryStr);
+      fprintf(f, "\n--%s--\n", bound);
 #endif /*EXPERIMENTAL_DSN*/
 
       /* Close the file, which should send an EOF to the child process
@@ -7352,8 +7433,8 @@ if (addr_defer == NULL)
   /* Unset deliver_freeze so that we won't try to move the spool files further down */
   deliver_freeze = FALSE;
 
-#ifdef EXPERIMENTAL_TPDA
-  (void) tpda_raise_event(delivery_event_action, US"msg:complete", NULL);
+#ifdef EXPERIMENTAL_EVENT
+  (void) event_raise(event_action, US"msg:complete", NULL);
 #endif
 }
 
@@ -7541,7 +7622,7 @@ else if (addr_defer != (address_item *)(+1))
         FILE *wmf = NULL;
         FILE *f = fdopen(fd, "wb");
 #ifdef EXPERIMENTAL_DSN
-       uschar boundaryStr[64];
+       uschar * bound;
 #endif
 
         if (warn_message_file)
@@ -7565,13 +7646,12 @@ else if (addr_defer != (address_item *)(+1))
 
 #ifdef EXPERIMENTAL_DSN
         /* generated boundary string and output MIME-Headers */
-        snprintf(boundaryStr, sizeof(boundaryStr)-1,
-         TIME_T_FMT "-eximdsn-%d", time(NULL), rand());
+        bound = string_sprintf(TIME_T_FMT "-eximdsn-%d", time(NULL), rand());
 
         fprintf(f, "Content-Type: multipart/report;"
            " report-type=delivery-status; boundary=%s\n"
            "MIME-Version: 1.0\n",
-         boundaryStr);
+         bound);
 #endif
 
         if ((wmf_text = next_emf(wmf, US"header")))
@@ -7584,7 +7664,7 @@ else if (addr_defer != (address_item *)(+1))
         /* output human readable part as text/plain section */
         fprintf(f, "--%s\n"
            "Content-type: text/plain; charset=us-ascii\n\n",
-         boundaryStr);
+         bound);
 #endif
 
         if ((wmf_text = next_emf(wmf, US"intro")))
@@ -7661,7 +7741,7 @@ else if (addr_defer != (address_item *)(+1))
         fprintf(f, "\n--%s\n"
            "Content-type: message/delivery-status\n\n"
            "Reporting-MTA: dns; %s\n",
-         boundaryStr,
+         bound,
          smtp_active_hostname);
  
 
@@ -7685,14 +7765,17 @@ else if (addr_defer != (address_item *)(+1))
           fprintf(f,"Final-Recipient: rfc822;%s\n", addr_dsndefer->address);
           fprintf(f,"Status: 4.0.0\n");
           if (addr_dsndefer->host_used && addr_dsndefer->host_used->name)
-            fprintf(f,"Remote-MTA: dns; %s\nDiagnostic-Code: smtp; %d\n", 
-                   addr_dsndefer->host_used->name, addr_dsndefer->basic_errno);
+            {
+            fprintf(f,"Remote-MTA: dns; %s\n", 
+                   addr_dsndefer->host_used->name);
+            print_dsn_diagnostic_code(addr_dsndefer, f);
+            }
           addr_dsndefer = addr_dsndefer->next;
           }
 
         fprintf(f, "\n--%s\n"
            "Content-type: text/rfc822-headers\n\n",
-         boundaryStr);
+         bound);
 
         fflush(f);
         /* header only as required by RFC. only failure DSN needs to honor RET=FULL */
@@ -7703,7 +7786,7 @@ else if (addr_defer != (address_item *)(+1))
         transport_write_message(NULL, fileno(f), topt, 0, NULL, NULL, NULL, NULL, NULL, 0);
         fflush(f);
 
-        fprintf(f,"\n--%s--\n", boundaryStr);
+        fprintf(f,"\n--%s--\n", bound);
 
         fflush(f);
 #endif /*EXPERIMENTAL_DSN*/