UTF8: MSA callouts
authorJeremy Harris <jgh146exb@wizmail.org>
Tue, 21 Apr 2015 21:40:43 +0000 (22:40 +0100)
committerJeremy Harris <jgh146exb@wizmail.org>
Tue, 21 Apr 2015 21:40:43 +0000 (22:40 +0100)
src/src/acl.c
src/src/utf8.c
src/src/verify.c
test/confs/4201
test/confs/4208 [new symlink]
test/scripts/4200-International/4208 [new file with mode: 0644]

index c1402a0ffe5c04c436071d77500d89d8678221ad..aa9f58f2c3e45f913255278d18b616593b58be3b 100644 (file)
@@ -3399,15 +3399,38 @@ for (; cb != NULL; cb = cb->next)
        case CONTROL_UTF8_DOWNCONVERT:
        if (*p == '/')
          {
-         if (p[1] == '1') { message_utf8_downconvert = 1; p += 2; break; }
-         if (p[1] == '0') { message_utf8_downconvert = 0; p += 2; break; }
+         if (p[1] == '1')
+           {
+           message_utf8_downconvert = 1;
+           addr->prop.utf8_downcvt = TRUE;
+           addr->prop.utf8_downcvt_maybe = FALSE;
+           p += 2;
+           break;
+           }
+         if (p[1] == '0')
+           {
+           message_utf8_downconvert = 0;
+           addr->prop.utf8_downcvt = FALSE;
+           addr->prop.utf8_downcvt_maybe = FALSE;
+           p += 2;
+           break;
+           }
          if (p[1] == '-' && p[2] == '1')
-                          { message_utf8_downconvert = -1; p += 3; break; }
+           {
+           message_utf8_downconvert = -1;
+           addr->prop.utf8_downcvt = FALSE;
+           addr->prop.utf8_downcvt_maybe = TRUE;
+           p += 3;
+           break;
+           }
          *log_msgptr = US"bad option value for control=utf8_downconvert";
          }
        else
          {
-         message_utf8_downconvert = 1; break;
+         message_utf8_downconvert = 1;
+         addr->prop.utf8_downcvt = TRUE;
+         addr->prop.utf8_downcvt_maybe = FALSE;
+         break;
          }
        return ERROR;
     #endif
index 09ebdf128a082f7eac2e0f3450bd2e8cdb127885..7382205598f3681999e4bca2ae5d50c8340a85e0 100644 (file)
@@ -76,11 +76,17 @@ uschar *
 string_localpart_utf8_to_alabel(const uschar * utf8, uschar ** err)
 {
 size_t ucs4_len;
-punycode_uint * p = (punycode_uint *) stringprep_utf8_to_ucs4(CCS utf8, -1, &ucs4_len);
-size_t p_len = ucs4_len*4;     /* this multiplier is pure guesswork */
-uschar * res = store_get(p_len+5);
+punycode_uint * p;
+size_t p_len;
+uschar * res;
 int rc;
 
+if (!string_is_utf8(utf8)) return string_copy(utf8);
+
+p = (punycode_uint *) stringprep_utf8_to_ucs4(CCS utf8, -1, &ucs4_len);
+p_len = ucs4_len*4;    /* this multiplier is pure guesswork */
+res = store_get(p_len+5);
+
 res[0] = 'x'; res[1] = 'n'; res[2] = res[3] = '-';
 
 if ((rc = punycode_encode(ucs4_len, p, NULL, &p_len, res+4)) != PUNYCODE_SUCCESS)
@@ -139,16 +145,26 @@ const uschar * s;
 uschar * l;
 uschar * d;
 
+if (!*utf8) return string_copy(utf8);
+
+DEBUG(D_expand) debug_printf("addr from utf8 <%s>", utf8);
+
 for (s = utf8; *s; s++)
   if (*s == '@')
     {
     l = string_copyn(utf8, s - utf8);
-    return   (l = string_localpart_utf8_to_alabel(l, err), err && *err)
-         || (d = string_domain_utf8_to_alabel(++s, err),  err && *err)
-      ? NULL
-      : string_sprintf("%s@%s", l, d);
+    if (  (l = string_localpart_utf8_to_alabel(l, err), err && *err)
+       || (d = string_domain_utf8_to_alabel(++s, err),  err && *err)
+       )
+      return NULL;
+    l = string_sprintf("%s@%s", l, d);
+    DEBUG(D_expand) debug_printf(" -> <%s>\n", l);
+    return l;
     }
-return string_localpart_utf8_to_alabel(utf8, err);
+
+l =  string_localpart_utf8_to_alabel(utf8, err);
+DEBUG(D_expand) debug_printf(" -> <%s>\n", l);
+return l;
 }
 
 
index 28013fa35c152da357f17b643392f653b8c8b03d..b77978bfcaeb57d32e3589d3ac7e2337d571841c 100644 (file)
@@ -945,9 +945,11 @@ can do it there for the non-rcpt-verify case.  For this we keep an addresscount.
       }
     else if (  addr->prop.utf8_msg
            && (addr->prop.utf8_downcvt || !utf8_offered)
-           && (from_address = string_address_utf8_to_alabel(from_address,
-                                     &addr->message), addr->message)
-           )
+           && (setflag(addr, af_utf8_downcvt),
+               from_address = string_address_utf8_to_alabel(from_address,
+                                     &addr->message),
+               addr->message
+           )  )
       {
       errno = ERRNO_EXPANDFAIL;
       setflag(addr, af_verify_nsfail);
@@ -974,7 +976,7 @@ can do it there for the non-rcpt-verify case.  For this we keep an addresscount.
     /* Send the MAIL command */
         (smtp_write_command(&outblock, FALSE,
 #ifdef EXPERIMENTAL_INTERNATIONAL
-         addr->prop.utf8_msg
+         addr->prop.utf8_msg && !addr->prop.utf8_downcvt
          ? "MAIL FROM:<%s>%s SMTPUTF8\r\n"
          :
 #endif
@@ -1017,6 +1019,23 @@ can do it there for the non-rcpt-verify case.  For this we keep an addresscount.
 
     else
       {
+      const uschar * rcpt_domain = addr->domain;
+
+#ifdef EXPERIMENTAL_INTERNATIONAL
+      uschar * errstr = NULL;
+      if (  testflag(addr, af_utf8_downcvt)
+        && (rcpt_domain = string_domain_utf8_to_alabel(rcpt_domain,
+                                   &errstr), errstr)
+        )
+       {
+       addr->message = errstr;
+       errno = ERRNO_EXPANDFAIL;
+       setflag(addr, af_verify_nsfail);
+       done = FALSE;
+       rcpt_domain = US"";  /*XXX errorhandling! */
+       }
+#endif
+
       new_domain_record.result =
         (old_domain_cache_result == ccache_reject_mfnull)?
           ccache_reject_mfnull: ccache_accept;
@@ -1029,7 +1048,7 @@ can do it there for the non-rcpt-verify case.  For this we keep an addresscount.
         BOOL random_ok =
           smtp_write_command(&outblock, FALSE,
             "RCPT TO:<%.1000s@%.1000s>\r\n", random_local_part,
-            addr->domain) >= 0 &&
+            rcpt_domain) >= 0 &&
           smtp_read_response(&inblock, randombuffer,
             sizeof(randombuffer), '2', callout);
 
@@ -1065,7 +1084,7 @@ can do it there for the non-rcpt-verify case.  For this we keep an addresscount.
 
             smtp_write_command(&outblock, FALSE,
 #ifdef EXPERIMENTAL_INTERNATIONAL
-             addr->prop.utf8_msg
+             addr->prop.utf8_msg && !addr->prop.utf8_downcvt
              ? "MAIL FROM:<%s> SMTPUTF8\r\n"
              :
 #endif
@@ -1101,11 +1120,27 @@ can do it there for the non-rcpt-verify case.  For this we keep an addresscount.
         /* Get the rcpt_include_affixes flag from the transport if there is one,
         but assume FALSE if there is not. */
 
+       uschar * rcpt = transport_rcpt_address(addr,
+              addr->transport ? addr->transport->rcpt_include_affixes : FALSE);
+
+#ifdef EXPERIMENTAL_INTERNATIONAL
+       /*XXX should the conversion be moved into transport_rcpt_address() ? */
+       uschar * dummy_errstr = NULL;
+       if (  testflag(addr, af_utf8_downcvt)
+          && (rcpt = string_address_utf8_to_alabel(rcpt, &dummy_errstr),
+              dummy_errstr
+          )  )
+       {
+       errno = ERRNO_EXPANDFAIL;
+       *failure_ptr = US"recipient";
+       done = FALSE;
+       }
+       else
+#endif
+
         done =
           smtp_write_command(&outblock, FALSE, "RCPT TO:<%.1000s>\r\n",
-            transport_rcpt_address(addr,
-              (addr->transport == NULL)? FALSE :
-               addr->transport->rcpt_include_affixes)) >= 0 &&
+            rcpt) >= 0 &&
           smtp_read_response(&inblock, responsebuffer, sizeof(responsebuffer),
             '2', callout);
 
@@ -1142,7 +1177,7 @@ can do it there for the non-rcpt-verify case.  For this we keep an addresscount.
 
             ((
             smtp_write_command(&outblock, FALSE,
-              "RCPT TO:<postmaster@%.1000s>\r\n", addr->domain) >= 0 &&
+              "RCPT TO:<postmaster@%.1000s>\r\n", rcpt_domain) >= 0 &&
             smtp_read_response(&inblock, responsebuffer,
               sizeof(responsebuffer), '2', callout)
             )
index b1fb7a6ee473701d7b8a2f925a47f1dfc552ae5e..4145325cc391fd6d0b5dedd67d0d94019ecfc3e8 100644 (file)
@@ -3,6 +3,7 @@
 
 OPTION = *
 CONTROL =
+INSERT =
 
 exim_path = EXIM_PATH
 host_lookup_order = bydns
@@ -45,6 +46,9 @@ check_recipient:
 .else
 
 sub:
+.ifdef INSERT
+  require INSERT
+.endif
 .ifdef CONTROL
   require CONTROL
 .endif
diff --git a/test/confs/4208 b/test/confs/4208
new file mode 120000 (symlink)
index 0000000..73a348f
--- /dev/null
@@ -0,0 +1 @@
+4201
\ No newline at end of file
diff --git a/test/scripts/4200-International/4208 b/test/scripts/4200-International/4208
new file mode 100644 (file)
index 0000000..0fa7190
--- /dev/null
@@ -0,0 +1,23 @@
+# Internationalised mail: utf8_downconvert and callouts
+# Exim test configuration 4208
+#
+exim -DSERVER=server -DOPTION="" -bd -oX PORT_D
+****
+#
+# Recipient verify callout, pass only due to downconvert
+exim -bs -odi -DINSERT="control=utf8_downconvert" -DCONTROL="verify=recipient/callout"
+EHLO client.ffail
+MAIL FROM: <CALLER@spanish.PorquénopuedensimplementehablarenEspañol.local> SMTPUTF8
+RCPT TO: <userS@test.ex>
+QUIT
+****
+
+# Recipient+random verify callout, pass only due to downconvert
+exim -d+all -bs -odi -DINSERT="control=utf8_downconvert" -DCONTROL="verify=recipient/callout=random"
+EHLO client.ffail
+MAIL FROM: <CALLER@vietnamese.TạisaohọkhôngthểchỉnóitiếngViệt.local> SMTPUTF8
+RCPT TO: <userT@test.ex>
+QUIT
+****
+#
+killdaemon