]> git.netwichtig.de Git - user/henk/code/exim.git/blobdiff - src/src/deliver.c
Tidying
[user/henk/code/exim.git] / src / src / deliver.c
index 5b2baabd35390acff85acd07d01ca600aeb8e265..3f22dc91ff6c5aa7301483a2f8230ac2a1885110 100644 (file)
@@ -9,6 +9,7 @@
 
 
 #include "exim.h"
+#include <assert.h>
 
 
 /* Data block for keeping track of subprocesses for parallel remote
@@ -676,40 +677,78 @@ while (addr->parent != NULL)
 
 
 
+/*************************************************
+*      Delivery logging support functions        *
+*************************************************/
+
+/* The LOGGING() checks in d_log_interface() are complicated for backwards
+compatibility. When outgoing interface logging was originally added, it was
+conditional on just incoming_interface (which is off by default). The
+outgoing_interface option is on by default to preserve this behaviour, but
+you can enable incoming_interface and disable outgoing_interface to get I=
+fields on incoming lines only.
+
+Arguments:
+  s         The log line buffer
+  sizep     Pointer to the buffer size
+  ptrp      Pointer to current index into buffer
+  addr      The address to be logged
+
+Returns:    New value for s
+*/
 
 static uschar *
-d_hostlog(uschar * s, int * sizep, int * ptrp, address_item * addr)
+d_log_interface(uschar *s, int *sizep, int *ptrp)
 {
-  s = string_append(s, sizep, ptrp, 5, US" H=", addr->host_used->name,
-    US" [", addr->host_used->address, US"]");
-  if ((log_extra_selector & LX_outgoing_port) != 0)
-    s = string_append(s, sizep, ptrp, 2, US":", string_sprintf("%d",
-      addr->host_used->port));
-  return s;
+if (LOGGING(incoming_interface) && LOGGING(outgoing_interface)
+    && sending_ip_address != NULL)
+  {
+  s = string_append(s, sizep, ptrp, 2, US" I=[", sending_ip_address);
+  if (LOGGING(outgoing_port))
+    s = string_append(s, sizep, ptrp, 2, US"]:",
+      string_sprintf("%d", sending_port));
+  else
+    s = string_cat(s, sizep, ptrp, "]", 1);
+  }
+return s;
 }
 
+
+
+static uschar *
+d_hostlog(uschar *s, int *sizep, int *ptrp, address_item *addr)
+{
+s = string_append(s, sizep, ptrp, 5, US" H=", addr->host_used->name,
+  US" [", addr->host_used->address, US"]");
+if (LOGGING(outgoing_port))
+  s = string_append(s, sizep, ptrp, 2, US":", string_sprintf("%d",
+    addr->host_used->port));
+return d_log_interface(s, sizep, ptrp);
+}
+
+
+
 #ifdef SUPPORT_TLS
 static uschar *
 d_tlslog(uschar * s, int * sizep, int * ptrp, address_item * addr)
 {
-  if ((log_extra_selector & LX_tls_cipher) != 0 && addr->cipher != NULL)
-    s = string_append(s, sizep, ptrp, 2, US" X=", addr->cipher);
-  if ((log_extra_selector & LX_tls_certificate_verified) != 0 &&
-       addr->cipher != NULL)
-    s = string_append(s, sizep, ptrp, 2, US" CV=",
-      testflag(addr, af_cert_verified)
-      ?
+if (LOGGING(tls_cipher) && addr->cipher != NULL)
+  s = string_append(s, sizep, ptrp, 2, US" X=", addr->cipher);
+if (LOGGING(tls_certificate_verified) && addr->cipher != NULL)
+  s = string_append(s, sizep, ptrp, 2, US" CV=",
+    testflag(addr, af_cert_verified)
+    ?
 #ifdef EXPERIMENTAL_DANE
-        testflag(addr, af_dane_verified)
-      ? "dane"
-      :
+      testflag(addr, af_dane_verified)
+    ? "dane"
+    :
 #endif
-        "yes"
-      : "no");
-  if ((log_extra_selector & LX_tls_peerdn) != 0 && addr->peerdn != NULL)
-    s = string_append(s, sizep, ptrp, 3, US" DN=\"",
-      string_printing(addr->peerdn), US"\"");
-  return s;
+      "yes"
+    : "no");
+if (LOGGING(tls_peerdn) && addr->peerdn != NULL)
+  s = string_append(s, sizep, ptrp, 3, US" DN=\"",
+    string_printing(addr->peerdn), US"\"");
+return s;
 }
 #endif
 
@@ -808,7 +847,7 @@ pointer to a single host item in their host list, for use by the transport. */
 
 s = reset_point = store_get(size);
 
-log_address = string_log_address(addr, (log_write_selector & L_all_parents) != 0, TRUE);
+log_address = string_log_address(addr, LOGGING(all_parents), TRUE);
 if (msg)
   s = string_append(s, &size, &ptr, 3, host_and_ident(TRUE), US" ", log_address);
 else
@@ -817,11 +856,7 @@ else
   s = string_append(s, &size, &ptr, 2, US"> ", log_address);
   }
 
-if (log_extra_selector & LX_incoming_interface  &&  sending_ip_address)
-  s = string_append(s, &size, &ptr, 3, US" I=[", sending_ip_address, US"]");
-  /* for the port:  string_sprintf("%d", sending_port) */
-
-if ((log_extra_selector & LX_sender_on_delivery) != 0  ||  msg)
+if (LOGGING(sender_on_delivery) || msg)
   s = string_append(s, &size, &ptr, 3, US" F=<",
 #ifdef EXPERIMENTAL_INTERNATIONAL
     testflag(addr, af_utf8_downcvt)
@@ -841,8 +876,7 @@ delivery; indeed, I did for some time, until this statement crashed. The case
 when it is not set is for a delivery to /dev/null which is optimised by not
 being run at all. */
 
-if (used_return_path != NULL &&
-      (log_extra_selector & LX_return_path_on_delivery) != 0)
+if (used_return_path != NULL && LOGGING(return_path_on_delivery))
   s = string_append(s, &size, &ptr, 3, US" P=<", used_return_path, US">");
 
 if (msg)
@@ -854,7 +888,7 @@ if (addr->router != NULL)
 
 s = string_append(s, &size, &ptr, 2, US" T=", addr->transport->name);
 
-if ((log_extra_selector & LX_delivery_size) != 0)
+if (LOGGING(delivery_size))
   s = string_append(s, &size, &ptr, 2, US" S=",
     string_sprintf("%d", transport_count));
 
@@ -864,6 +898,7 @@ if (addr->transport->info->local)
   {
   if (addr->host_list)
     s = string_append(s, &size, &ptr, 2, US" H=", addr->host_list->name);
+  s = d_log_interface(s, &size, &ptr);
   if (addr->shadow_message != NULL)
     s = string_cat(s, &size, &ptr, addr->shadow_message,
       Ustrlen(addr->shadow_message));
@@ -901,7 +936,7 @@ else
     if (addr->auth_id)
       {
       s = string_append(s, &size, &ptr, 2, US":", addr->auth_id);
-      if (log_extra_selector & LX_smtp_mailauth  &&  addr->auth_sndr)
+      if (LOGGING(smtp_mailauth) && addr->auth_sndr)
         s = string_append(s, &size, &ptr, 2, US":", addr->auth_sndr);
       }
     }
@@ -914,8 +949,7 @@ else
 
 /* confirmation message (SMTP (host_used) and LMTP (driver_name)) */
 
-if (log_extra_selector & LX_smtp_confirmation &&
-    addr->message &&
+if (LOGGING(smtp_confirmation) && addr->message &&
     (addr->host_used || Ustrcmp(addr->transport->driver_name, "lmtp") == 0))
   {
   unsigned i;
@@ -935,11 +969,11 @@ if (log_extra_selector & LX_smtp_confirmation &&
 
 /* Time on queue and actual time taken to deliver */
 
-if ((log_extra_selector & LX_queue_time) != 0)
+if (LOGGING(queue_time))
   s = string_append(s, &size, &ptr, 2, US" QT=",
     readconf_printtime( (int) ((long)time(NULL) - (long)received_time)) );
 
-if ((log_extra_selector & LX_deliver_time) != 0)
+if (LOGGING(deliver_time))
   s = string_append(s, &size, &ptr, 2, US" DT=",
     readconf_printtime(addr->more_errno));
 
@@ -1170,16 +1204,8 @@ if (result == OK)
   delivery_log(LOG_MAIN, addr, logchar, NULL);
 
 #ifdef SUPPORT_TLS
-  if (tls_out.ourcert)
-    {
-    tls_free_cert(tls_out.ourcert);
-    tls_out.ourcert = NULL;
-    }
-  if (tls_out.peercert)
-    {
-    tls_free_cert(tls_out.peercert);
-    tls_out.peercert = NULL;
-    }
+  tls_free_cert(&tls_out.ourcert);
+  tls_free_cert(&tls_out.peercert);
   tls_out.cipher = NULL;
   tls_out.peerdn = NULL;
   tls_out.ocsp = OCSP_NOT_REQ;
@@ -1238,8 +1264,7 @@ else if (result == DEFER || result == PANIC)
     /* Create the address string for logging. Must not do this earlier, because
     an OK result may be changed to FAIL when a pipe returns text. */
 
-    log_address = string_log_address(addr,
-      (log_write_selector & L_all_parents) != 0, result == OK);
+    log_address = string_log_address(addr, LOGGING(all_parents), result == OK);
 
     s = string_cat(s, &size, &ptr, log_address, Ustrlen(log_address));
 
@@ -1350,18 +1375,16 @@ else
   /* Create the address string for logging. Must not do this earlier, because
   an OK result may be changed to FAIL when a pipe returns text. */
 
-  log_address = string_log_address(addr,
-    (log_write_selector & L_all_parents) != 0, result == OK);
+  log_address = string_log_address(addr, LOGGING(all_parents), result == OK);
 
   s = string_cat(s, &size, &ptr, log_address, Ustrlen(log_address));
 
-  if ((log_extra_selector & LX_sender_on_delivery) != 0)
+  if (LOGGING(sender_on_delivery))
     s = string_append(s, &size, &ptr, 3, US" F=<", sender_address, US">");
 
   /* Return path may not be set if no delivery actually happened */
 
-  if (used_return_path != NULL &&
-      (log_extra_selector & LX_return_path_on_delivery) != 0)
+  if (used_return_path != NULL && LOGGING(return_path_on_delivery))
     s = string_append(s, &size, &ptr, 3, US" P=<", used_return_path, US">");
 
   if (addr->router != NULL)
@@ -3135,15 +3158,17 @@ while (!done)
       break;
 
       case '2':
-      addr->peercert = NULL;
       if (*ptr)
        (void) tls_import_cert(ptr, &addr->peercert);
+      else
+       addr->peercert = NULL;
       break;
 
       case '3':
-      addr->ourcert = NULL;
       if (*ptr)
        (void) tls_import_cert(ptr, &addr->ourcert);
+      else
+       addr->ourcert = NULL;
       break;
 
 # ifndef DISABLE_OCSP
@@ -3198,41 +3223,56 @@ while (!done)
       break;
       }
 
-    addr->transport_return = *ptr++;
-    addr->special_action = *ptr++;
-    memcpy(&(addr->basic_errno), ptr, sizeof(addr->basic_errno));
-    ptr += sizeof(addr->basic_errno);
-    memcpy(&(addr->more_errno), ptr, sizeof(addr->more_errno));
-    ptr += sizeof(addr->more_errno);
-    memcpy(&(addr->flags), ptr, sizeof(addr->flags));
-    ptr += sizeof(addr->flags);
-    addr->message = (*ptr)? string_copy(ptr) : NULL;
-    while(*ptr++);
-    addr->user_message = (*ptr)? string_copy(ptr) : NULL;
-    while(*ptr++);
-
-    /* Always two strings for host information, followed by the port number and DNSSEC mark */
-
-    if (*ptr != 0)
+    switch (subid)
       {
-      h = store_get(sizeof(host_item));
-      h->name = string_copy(ptr);
-      while (*ptr++);
-      h->address = string_copy(ptr);
-      while(*ptr++);
-      memcpy(&(h->port), ptr, sizeof(h->port));
-      ptr += sizeof(h->port);
-      h->dnssec = *ptr == '2' ? DS_YES
-               : *ptr == '1' ? DS_NO
-               : DS_UNK;
-      ptr++;
-      addr->host_used = h;
-      }
-    else ptr++;
+#ifdef EXPERIMENTAL_DSN_INFO
+      case '1':        /* must arrive before A0, and applies to that addr */
+               /* Two strings: smtp_greeting and helo_response */
+       addr->smtp_greeting = string_copy(ptr);
+       while(*ptr++);
+       addr->helo_response = string_copy(ptr);
+       while(*ptr++);
+       break;
+#endif
+
+      case '0':
+       addr->transport_return = *ptr++;
+       addr->special_action = *ptr++;
+       memcpy(&(addr->basic_errno), ptr, sizeof(addr->basic_errno));
+       ptr += sizeof(addr->basic_errno);
+       memcpy(&(addr->more_errno), ptr, sizeof(addr->more_errno));
+       ptr += sizeof(addr->more_errno);
+       memcpy(&(addr->flags), ptr, sizeof(addr->flags));
+       ptr += sizeof(addr->flags);
+       addr->message = (*ptr)? string_copy(ptr) : NULL;
+       while(*ptr++);
+       addr->user_message = (*ptr)? string_copy(ptr) : NULL;
+       while(*ptr++);
 
-    /* Finished with this address */
+       /* Always two strings for host information, followed by the port number and DNSSEC mark */
 
-    addr = addr->next;
+       if (*ptr != 0)
+         {
+         h = store_get(sizeof(host_item));
+         h->name = string_copy(ptr);
+         while (*ptr++);
+         h->address = string_copy(ptr);
+         while(*ptr++);
+         memcpy(&(h->port), ptr, sizeof(h->port));
+         ptr += sizeof(h->port);
+         h->dnssec = *ptr == '2' ? DS_YES
+                   : *ptr == '1' ? DS_NO
+                   : DS_UNK;
+         ptr++;
+         addr->host_used = h;
+         }
+       else ptr++;
+
+       /* Finished with this address */
+
+       addr = addr->next;
+       break;
+      }
     break;
 
     /* Local interface address/port */
@@ -4398,7 +4438,6 @@ for (delivery_count = 0; addr_remote != NULL; delivery_count++)
 
       for (r = addr->retries; r != NULL; r = r->next)
         {
-        uschar *ptr;
         sprintf(CS big_buffer, "%c%.500s", r->flags, r->key);
         ptr = big_buffer + Ustrlen(big_buffer+2) + 3;
         memcpy(ptr, &(r->basic_errno), sizeof(r->basic_errno));
@@ -4413,11 +4452,31 @@ for (delivery_count = 0; addr_remote != NULL; delivery_count++)
         rmt_dlv_checked_write(fd, 'R', '0', big_buffer, ptr - big_buffer);
         }
 
-      /* The rest of the information goes in an 'A' item. */
+#ifdef EXPERIMENTAL_DSN_INFO
+/*um, are they really per-addr?  Other per-conn stuff is not (auth, tls).  But host_used is! */
+      if (addr->smtp_greeting)
+       {
+       ptr = big_buffer;
+       DEBUG(D_deliver) debug_printf("smtp_greeting '%s'\n", addr->smtp_greeting);
+        sprintf(CS ptr, "%.128s", addr->smtp_greeting);
+        while(*ptr++);
+       if (addr->helo_response)
+         {
+         DEBUG(D_deliver) debug_printf("helo_response '%s'\n", addr->helo_response);
+         sprintf(CS ptr, "%.128s", addr->helo_response);
+         while(*ptr++);
+         }
+       else
+         *ptr++ = '\0';
+        rmt_dlv_checked_write(fd, 'A', '1', big_buffer, ptr - big_buffer);
+       }
+#endif
+
+      /* The rest of the information goes in an 'A0' item. */
 
-      ptr = big_buffer + 2;
       sprintf(CS big_buffer, "%c%c", addr->transport_return,
         addr->special_action);
+      ptr = big_buffer + 2;
       memcpy(ptr, &(addr->basic_errno), sizeof(addr->basic_errno));
       ptr += sizeof(addr->basic_errno);
       memcpy(ptr, &(addr->more_errno), sizeof(addr->more_errno));
@@ -4455,7 +4514,11 @@ for (delivery_count = 0; addr_remote != NULL; delivery_count++)
       }
 
     /* Local interface address/port */
-    if (log_extra_selector & LX_incoming_interface  &&  sending_ip_address)
+#ifdef EXPERIMENTAL_DSN_INFO
+    if (sending_ip_address)
+#else
+    if (LOGGING(incoming_interface) && sending_ip_address)
+#endif
       {
       uschar * ptr = big_buffer;
       sprintf(CS ptr, "%.128s", sending_ip_address);
@@ -4815,15 +4878,12 @@ print_address_error(address_item *addr, FILE *f, uschar *t)
 int count = Ustrlen(t);
 uschar *s = testflag(addr, af_pass_message)? addr->message : NULL;
 
-if (s == NULL)
-  {
-  if (addr->user_message != NULL) s = addr->user_message; else return;
-  }
+if (!s && !(s = addr->user_message))
+  return;
 
 fprintf(f, "\n    %s", t);
 
-while (*s != 0)
-  {
+while (*s)
   if (*s == '\\' && s[1] == 'n')
     {
     fprintf(f, "\n    ");
@@ -4840,7 +4900,6 @@ while (*s != 0)
       count = 0;
       }
     }
-  }
 }
 
 
@@ -4852,9 +4911,9 @@ while (*s != 0)
 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.
+it uses the same logic as print_address_error() above. if af_pass_message is true
+and addr->message is set it uses the remote host answer. if not addr->user_message
+is used instead if available.
 
 Arguments:
   addr         the address
@@ -4866,21 +4925,23 @@ 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;
+uschar *s = testflag(addr, af_pass_message) ? addr->message : NULL;
 
-/* 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 */
+/* af_pass_message and addr->message set ? print remote host answer */
+if (s)
+  {
+  DEBUG(D_deliver)
+    debug_printf("DSN Diagnostic-Code: addr->message = %s\n", addr->message);
 
-fprintf(f, "Diagnostic-Code: smtp; ");
+  /* search first ": ". we assume to find the remote-MTA answer there */
+  if (!(s = Ustrstr(addr->message, ": ")))
+    return;                            /* not found, bail out */
+  s += 2;  /* skip ": " */
+  fprintf(f, "Diagnostic-Code: smtp; ");
+  }
+/* no message available. do nothing */
+else return;
 
-s += 2;  /* skip ": " */
 while (*s)
   if (*s == '\\' && s[1] == 'n')
     {
@@ -7186,16 +7247,32 @@ wording. */
  
       for (addr = handled_addr; addr; addr = addr->next)
         {
+       host_item * hu;
         fprintf(f, "Action: failed\n"
            "Final-Recipient: rfc822;%s\n"
            "Status: 5.0.0\n",
            addr->address);
-        if (addr->host_used && addr->host_used->name)
-          {
-          fprintf(f, "Remote-MTA: dns; %s\n",
-           addr->host_used->name);
-          print_dsn_diagnostic_code(addr, f);
-          }
+        if ((hu = addr->host_used) && hu->name)
+         {
+         const uschar * s;
+         fprintf(f, "Remote-MTA: dns; %s\n",
+           hu->name);
+#ifdef EXPERIMENTAL_DSN_INFO
+         if (hu->address)
+           {
+           uschar * p = hu->port == 25
+             ? US"" : string_sprintf(":%d", hu->port);
+           fprintf(f, "Remote-MTA: X-ip; [%s]%s\n", hu->address, p);
+           }
+         if ((s = addr->smtp_greeting) && *s)
+           fprintf(f, "X-Remote-MTA-smtp-greeting: X-str; %s\n", s);
+         if ((s = addr->helo_response) && *s)
+           fprintf(f, "X-Remote-MTA-helo-response: X-str; %s\n", s);
+         if ((s = addr->message) && *s)
+           fprintf(f, "X-Exim-Diagnostic: X-str; %s\n", s);
+#endif
+         print_dsn_diagnostic_code(addr, f);
+         }
        fputc('\n', f);
         }
 
@@ -7373,7 +7450,7 @@ if (addr_defer == NULL)
 
   /* Log the end of this message, with queue time if requested. */
 
-  if ((log_extra_selector & LX_queue_time_overall) != 0)
+  if (LOGGING(queue_time_overall))
     log_write(0, LOG_MAIN, "Completed QT=%s",
       readconf_printtime( (int) ((long)time(NULL) - (long)received_time)) );
   else
@@ -7912,17 +7989,36 @@ if (!regex_IGNOREQUOTA) regex_IGNOREQUOTA =
 uschar *
 deliver_get_sender_address (uschar * id)
 {
+int rc;
+uschar * new_sender_address,
+       * save_sender_address;
+
 if (!spool_open_datafile(id))
   return NULL;
 
+/* Save and restore the global sender_address.  I'm not sure if we should
+not save/restore all the other global variables too, because
+spool_read_header() may change all of them. But OTOH, when this
+deliver_get_sender_address() gets called, the current message is done
+already and nobody needs the globals anymore. (HS12, 2015-08-21) */
+
 sprintf(CS spoolname, "%s-H", id);
-if (spool_read_header(spoolname, TRUE, TRUE) != spool_read_OK)
+save_sender_address = sender_address;
+
+rc = spool_read_header(spoolname, TRUE, TRUE);
+
+new_sender_address = sender_address;
+sender_address = save_sender_address;
+
+if (rc != spool_read_OK)
   return NULL;
 
+assert(new_sender_address);
+
 (void)close(deliver_datafile);
 deliver_datafile = -1;
 
-return sender_address;
+return new_sender_address;
 }
 
 /* vi: aw ai sw=2