Retries: rework DB keys, and fix exinext IPv6. Bug 3086
[exim.git] / src / src / transports / smtp.c
index c205145a70f50da8383c08e441425648142198a5..a5f99edaa844f24e31364efa6cc96a6a0c4e6a75 100644 (file)
@@ -277,7 +277,7 @@ struct list
 #ifndef DISABLE_PIPE_CONNECT
     { &regex_EARLY_PIPE,       US"\\n250[\\s\\-]" EARLY_PIPE_FEATURE_NAME "(\\s|\\n|$)" },
 #endif
-#ifdef EXPERIMENTAL_ESMTP_LIMITS
+#ifndef DISABLE_ESMTP_LIMITS
     { &regex_LIMITS,           US"\\n250[\\s\\-]LIMITS\\s" },
 #endif
   };
@@ -533,7 +533,7 @@ switch(*errno_value)
 
   case ERRNO_SMTPFORMAT:       /* Handle malformed SMTP response */
     s = string_printing(buffer);
-    while (isspace(*s)) s++;
+    Uskip_whitespace(&s);
     *message = *s == 0
       ? string_sprintf("Malformed SMTP reply (an empty line) "
          "in response to %s%s", pl, smtp_command)
@@ -797,7 +797,7 @@ sx->conn_args.have_lbserver = TRUE;
 
 /******************************************************************************/
 
-#ifdef EXPERIMENTAL_ESMTP_LIMITS
+#ifndef DISABLE_ESMTP_LIMITS
 /* If TLS, or TLS not offered, called with the EHLO response in the buffer.
 Check it for a LIMITS keyword and parse values into the smtp context structure.
 
@@ -815,8 +815,7 @@ uschar * match;
 if (regex_match(regex_LIMITS, sx->buffer, -1, &match))
   for (const uschar * s = sx->buffer + Ustrlen(match); *s; )
     {
-    while (isspace(*s)) s++;
-    if (*s == '\n') break;
+    if (Uskip_whitespace(&s) == '\n') break;
 
     if (strncmpic(s, US"MAILMAX=", 8) == 0)
       {
@@ -900,7 +899,7 @@ write_ehlo_cache_entry(smtp_context * sx)
 {
 open_db dbblock, * dbm_file;
 
-# ifdef EXPERIMENTAL_ESMTP_LIMITS
+# ifndef DISABLE_ESMTP_LIMITS
 sx->ehlo_resp.limit_mail = sx->peer_limit_mail;
 sx->ehlo_resp.limit_rcpt = sx->peer_limit_rcpt;
 sx->ehlo_resp.limit_rcptdom = sx->peer_limit_rcptdom;
@@ -912,7 +911,7 @@ if ((dbm_file = dbfn_open(US"misc", O_RDWR, &dbblock, TRUE, TRUE)))
   dbdata_ehlo_resp er = { .data = sx->ehlo_resp };
 
   HDEBUG(D_transport)
-# ifdef EXPERIMENTAL_ESMTP_LIMITS
+# ifndef DISABLE_ESMTP_LIMITS
     if (sx->ehlo_resp.limit_mail || sx->ehlo_resp.limit_rcpt || sx->ehlo_resp.limit_rcptdom)
       debug_printf("writing clr %04x/%04x cry %04x/%04x lim %05d/%05d/%05d\n",
        sx->ehlo_resp.cleartext_features, sx->ehlo_resp.cleartext_auths,
@@ -979,7 +978,7 @@ else
   else
     {
     DEBUG(D_transport)
-# ifdef EXPERIMENTAL_ESMTP_LIMITS
+# ifndef DISABLE_ESMTP_LIMITS
       if (er->data.limit_mail || er->data.limit_rcpt || er->data.limit_rcptdom)
        debug_printf("EHLO response bits from cache:"
          " cleartext 0x%04x/0x%04x crypted 0x%04x/0x%04x lim %05d/%05d/%05d\n",
@@ -994,7 +993,7 @@ else
          er->data.crypted_features, er->data.crypted_auths);
 
     sx->ehlo_resp = er->data;
-# ifdef EXPERIMENTAL_ESMTP_LIMITS
+# ifndef DISABLE_ESMTP_LIMITS
     ehlo_cache_limits_apply(sx);
 # endif
     dbfn_close(dbm_file);
@@ -1088,6 +1087,7 @@ if (pending_BANNER)
   /*XXX EXPERIMENTAL_ESMTP_LIMITS ? */
 
 # ifndef DISABLE_TLS_RESUME
+  GET_OPTION("host_name_extract");
   s = ((smtp_transport_options_block *)sx->conn_args.ob)->host_name_extract;
   if (!s) s = HNE_DEFAULT;
   ehlo_response_lbserver(sx, s);
@@ -1120,7 +1120,7 @@ if (pending_EHLO)
        | OPTION_CHUNKING | OPTION_PRDR | OPTION_DSN | OPTION_PIPE | OPTION_SIZE
        | OPTION_UTF8 | OPTION_EARLY_PIPE
        );
-# ifdef EXPERIMENTAL_ESMTP_LIMITS
+# ifndef DISABLE_ESMTP_LIMITS
   if (tls_out.active.sock >= 0 || !(peer_offered & OPTION_TLS))
     ehlo_response_limits_read(sx);
 # endif
@@ -1147,7 +1147,7 @@ if (pending_EHLO)
 
     return OK;         /* just carry on */
     }
-# ifdef EXPERIMENTAL_ESMTP_LIMITS
+# ifndef DISABLE_ESMTP_LIMITS
     /* If we are handling LIMITS, compare the actual EHLO LIMITS values with the
     cached values and invalidate cache if different.  OK to carry on with
     connect since values are advisory. */
@@ -1306,7 +1306,7 @@ while (count-- > 0)
 
     if (testflag(addr, af_dr_retry_exists))
       {
-      uschar *altkey = string_sprintf("%s:<%s>", addr->address_retry_key,
+      uschar * altkey = string_sprintf("%s:<%s>", addr->address_retry_key,
         sender_address);
       retry_add_item(addr, altkey, rf_delete);
       retry_add_item(addr, addr->address_retry_key, rf_delete);
@@ -1322,7 +1322,7 @@ while (count-- > 0)
 
   else if (errno == ETIMEDOUT)
     {
-    uschar *message = string_sprintf("SMTP timeout after RCPT TO:<%s>",
+    uschar * message = string_sprintf("SMTP timeout after RCPT TO:<%s>",
                transport_rcpt_address(addr, sx->conn_args.tblock->rcpt_include_affixes));
     set_errno_nohost(sx->first_addr, ETIMEDOUT, message, DEFER, FALSE, &sx->delivery_start);
     retry_add_item(addr, addr->address_retry_key, 0);
@@ -1693,8 +1693,8 @@ if (  sx->esmtp
        {
        DEBUG(D_transport) debug_printf("skipping %s authenticator: %s\n",
          au->name,
-         (au->client)? "client_condition is false" :
-                       "not configured as a client");
+         au->client ? "client_condition is false"
+                   : "not configured as a client");
        continue;
        }
 
@@ -1702,15 +1702,14 @@ if (  sx->esmtp
 
       while (*p)
        {
-       int len = Ustrlen(au->public_name);
-       int rc;
+       int len = Ustrlen(au->public_name), rc;
 
-       while (isspace(*p)) p++;
+       Uskip_whitespace(&p);
 
        if (strncmpic(au->public_name, p, len) != 0 ||
-           (p[len] != 0 && !isspace(p[len])))
+           (p[len] && !isspace(p[len])))
          {
-         while (*p != 0 && !isspace(*p)) p++;
+         while (*p && !isspace(*p)) p++;
          continue;
          }
 
@@ -1769,6 +1768,7 @@ uschar * local_authenticated_sender = authenticated_sender;
     authenticated_sender, ob->authenticated_sender, f.smtp_authenticated?"Y":"N");
 #endif
 
+GET_OPTION("authenticated_sender");
 if (ob->authenticated_sender)
   {
   uschar * new = expand_string(ob->authenticated_sender);
@@ -2305,7 +2305,7 @@ if (!continue_hostname)
 
   sx->cctx.tls_ctx = NULL;
   sx->inblock.cctx = sx->outblock.cctx = &sx->cctx;
-#ifdef EXPERIMENTAL_ESMTP_LIMITS
+#ifndef DISABLE_ESMTP_LIMITS
   sx->peer_limit_mail = sx->peer_limit_rcpt = sx->peer_limit_rcptdom =
 #endif
   sx->avoid_option = sx->peer_offered = smtp_peer_options = 0;
@@ -2374,6 +2374,7 @@ PIPE_CONNECT_RETRY:
   For early-pipe, we are ok if binding to a local interface; otherwise (if
   $sending_ip_address is seen in helo_data) we disabled early-pipe above. */
 
+  GET_OPTION("helo_data");
   if (sx->helo_data)
     if (!(sx->helo_data = expand_string(sx->helo_data)))
       if (sx->verify)
@@ -2501,6 +2502,7 @@ goto SEND_QUIT;
     an LB.  Call this anyway, so that a dummy host_name_extract option value can
     force resumption attempts. */
 
+    GET_OPTION("host_name_extract");
     if (!(s = ob->host_name_extract)) s = US"never-LB";
     ehlo_response_lbserver(sx, s);
 # endif
@@ -2607,7 +2609,7 @@ goto SEND_QUIT;
          )
 #endif
        );
-#ifdef EXPERIMENTAL_ESMTP_LIMITS
+#ifndef DISABLE_ESMTP_LIMITS
       if (tls_out.active.sock >= 0 || !(sx->peer_offered & OPTION_TLS))
        {
        ehlo_response_limits_read(sx);
@@ -2629,6 +2631,7 @@ goto SEND_QUIT;
        }
 #endif
 #ifndef DISABLE_TLS_RESUME
+      GET_OPTION("host_name_extract");
       if (!(s = ob->host_name_extract)) s = HNE_DEFAULT;
       ehlo_response_lbserver(sx, s);
 #endif
@@ -2672,7 +2675,7 @@ else
   sx->inblock.cctx = sx->outblock.cctx = &sx->cctx;
   smtp_command = big_buffer;
   sx->peer_offered = smtp_peer_options;
-#ifdef EXPERIMENTAL_ESMTP_LIMITS
+#ifndef DISABLE_ESMTP_LIMITS
   /* Limits passed by cmdline over exec. */
   ehlo_limits_apply(sx,
                    sx->peer_limit_mail = continue_limit_mail,
@@ -2837,13 +2840,17 @@ if (tls_out.active.sock >= 0)
   {
   uschar * greeting_cmd;
 
-  if (!sx->helo_data && !(sx->helo_data = expand_string(ob->helo_data)))
+  if (!sx->helo_data)
     {
-    uschar *message = string_sprintf("failed to expand helo_data: %s",
-      expand_string_message);
-    set_errno_nohost(sx->addrlist, ERRNO_EXPANDFAIL, message, DEFER, FALSE, &sx->delivery_start);
-    yield = DEFER;
-    goto SEND_QUIT;
+    GET_OPTION("helo_data");
+    if (!(sx->helo_data = expand_string(ob->helo_data)))
+      {
+      uschar *message = string_sprintf("failed to expand helo_data: %s",
+       expand_string_message);
+      set_errno_nohost(sx->addrlist, ERRNO_EXPANDFAIL, message, DEFER, FALSE, &sx->delivery_start);
+      yield = DEFER;
+      goto SEND_QUIT;
+      }
     }
 
 #ifndef DISABLE_PIPE_CONNECT
@@ -3000,7 +3007,7 @@ if (   !continue_hostname
       sx->ehlo_resp.crypted_features = sx->peer_offered;
 #endif
 
-#ifdef EXPERIMENTAL_ESMTP_LIMITS
+#ifndef DISABLE_ESMTP_LIMITS
     if (tls_out.active.sock >= 0 || !(sx->peer_offered & OPTION_TLS))
       {
       ehlo_response_limits_read(sx);
@@ -3094,6 +3101,7 @@ if (sx->addrlist->prop.utf8_msg)
   /* If the transport sets a downconversion mode it overrides any set by ACL
   for the message. */
 
+  GET_OPTION("utf8_downconvert");
   if ((s = ob->utf8_downconvert))
     {
     if (!(s = expand_string(s)))
@@ -3423,7 +3431,7 @@ sw_mrc_t
 smtp_write_mail_and_rcpt_cmds(smtp_context * sx, int * yield)
 {
 address_item * addr;
-#ifdef EXPERIMENTAL_ESMTP_LIMITS
+#ifndef DISABLE_ESMTP_LIMITS
 address_item * restart_addr = NULL;
 #endif
 int address_count, pipe_limit;
@@ -3517,7 +3525,7 @@ for (addr = sx->first_addr, address_count = 0, pipe_limit = 100;
   BOOL no_flush;
   const uschar * rcpt_addr;
 
-#ifdef EXPERIMENTAL_ESMTP_LIMITS
+#ifndef DISABLE_ESMTP_LIMITS
   if (  sx->single_rcpt_domain                                 /* restriction on domains */
      && address_count > 0                                      /* not first being sent */
      && Ustrcmp(addr->domain, sx->first_addr->domain) != 0     /* dom diff from first */
@@ -3606,7 +3614,7 @@ for (addr = sx->first_addr, address_count = 0, pipe_limit = 100;
     }
   }      /* Loop for next address */
 
-#ifdef EXPERIMENTAL_ESMTP_LIMITS
+#ifndef DISABLE_ESMTP_LIMITS
 sx->next_addr = restart_addr ? restart_addr : addr;
 #else
 sx->next_addr = addr;
@@ -3790,7 +3798,7 @@ uschar *message = NULL;
 uschar new_message_id[MESSAGE_ID_LENGTH + 1];
 smtp_context * sx = store_get(sizeof(*sx), GET_TAINTED);       /* tainted, for the data buffers */
 BOOL pass_message = FALSE;
-#ifdef EXPERIMENTAL_ESMTP_LIMITS
+#ifndef DISABLE_ESMTP_LIMITS
 BOOL mail_limit = FALSE;
 #endif
 #ifdef SUPPORT_DANE
@@ -4674,7 +4682,7 @@ DEBUG(D_transport)
     sx->send_rset, f.continue_more, yield, sx->first_addr ? "not " : "");
 
 if (sx->completed_addr && sx->ok && sx->send_quit)
-#ifdef EXPERIMENTAL_ESMTP_LIMITS
+#ifndef DISABLE_ESMTP_LIMITS
   if (mail_limit = continue_sequence >= sx->max_mail)
     {
     DEBUG(D_transport)
@@ -4735,7 +4743,7 @@ if (sx->completed_addr && sx->ok && sx->send_quit)
 
        if (sx->first_addr)             /* More addresses still to be sent */
          {                             /*   for this message              */
-#ifdef EXPERIMENTAL_ESMTP_LIMITS
+#ifndef DISABLE_ESMTP_LIMITS
          /* Any that we marked as skipped, reset to do now */
          for (address_item * a = sx->first_addr; a; a = a->next)
            if (a->transport_return == SKIP)
@@ -4810,7 +4818,7 @@ if (sx->completed_addr && sx->ok && sx->send_quit)
   */
        if (sx->ok && transport_pass_socket(tblock->name, host->name,
              host->address, new_message_id, socket_fd
-#ifdef EXPERIMENTAL_ESMTP_LIMITS
+#ifndef DISABLE_ESMTP_LIMITS
              , sx->peer_limit_mail, sx->peer_limit_rcpt, sx->peer_limit_rcptdom
 #endif
              ))
@@ -4987,7 +4995,7 @@ if (dane_held)
   }
 #endif
 
-#ifdef EXPERIMENTAL_ESMTP_LIMITS
+#ifndef DISABLE_ESMTP_LIMITS
 if (mail_limit && sx->first_addr)
   {
   /* Reset the sequence count since we closed the connection.  This is flagged
@@ -5368,7 +5376,7 @@ retry_non_continued:
     BOOL host_is_expired = FALSE, message_defer = FALSE, some_deferred = FALSE;
     address_item * first_addr = NULL;
     uschar * interface = NULL;
-    uschar * retry_host_key = NULL, * retry_message_key = NULL;
+    const uschar * retry_host_key = NULL, * retry_message_key = NULL;
     uschar * serialize_key = NULL;
 
     /* Deal slightly better with a possible Linux kernel bug that results
@@ -5565,8 +5573,9 @@ retry_non_continued:
 
     host_af = Ustrchr(host->address, ':') ? AF_INET6 : AF_INET;
       {
-      uschar * s = ob->interface;
-      if (s && *s)
+      uschar * s;
+      GET_OPTION("interface");
+      if ((s = ob->interface) && *s)
        {
        if (!smtp_get_interface(s, host_af, addrlist, &interface, tid))
          return FALSE;
@@ -5864,9 +5873,7 @@ retry_non_continued:
                  ob->expand_retry_include_ip_address, &incl_ip) != OK)
          incl_ip = TRUE;       /* error; use most-specific retry record */
 
-        retry_host_key = incl_ip
-         ? string_sprintf("T:%S:%s%s", host->name, host->address, pistring)
-         : string_sprintf("T:%S%s", host->name, pistring);
+        retry_host_key = retry_host_key_build(host, incl_ip, pistring);
         }
 
       /* If a delivery of another message over an existing SMTP connection
@@ -5912,10 +5919,8 @@ retry_non_continued:
                  ob->expand_retry_include_ip_address, &incl_ip) != OK)
          incl_ip = TRUE;       /* error; use most-specific retry record */
 
-        retry_message_key = incl_ip
-         ? string_sprintf("T:%S:%s%s:%s", host->name, host->address, pistring,
-             message_id)
-         : string_sprintf("T:%S%s:%s", host->name, pistring, message_id);
+        retry_message_key = string_sprintf("%s:%s",
+         retry_host_key_build(host, incl_ip, pistring), message_id);
         }
       retry_add_item(addrlist, retry_message_key,
         rf_message | rf_host | delete_flag);