summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/src/acl.c31
-rw-r--r--src/src/utf8.c32
-rw-r--r--src/src/verify.c55
-rw-r--r--test/confs/42014
l---------test/confs/42081
-rw-r--r--test/scripts/4200-International/420823
6 files changed, 124 insertions, 22 deletions
diff --git a/src/src/acl.c b/src/src/acl.c
index c1402a0ff..aa9f58f2c 100644
--- a/src/src/acl.c
+++ b/src/src/acl.c
@@ -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
diff --git a/src/src/utf8.c b/src/src/utf8.c
index 09ebdf128..738220559 100644
--- a/src/src/utf8.c
+++ b/src/src/utf8.c
@@ -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;
}
diff --git a/src/src/verify.c b/src/src/verify.c
index 28013fa35..b77978bfc 100644
--- a/src/src/verify.c
+++ b/src/src/verify.c
@@ -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)
)
diff --git a/test/confs/4201 b/test/confs/4201
index b1fb7a6ee..4145325cc 100644
--- a/test/confs/4201
+++ b/test/confs/4201
@@ -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
index 000000000..73a348fee
--- /dev/null
+++ b/test/confs/4208
@@ -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
index 000000000..0fa719019
--- /dev/null
+++ b/test/scripts/4200-International/4208
@@ -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