diff options
-rw-r--r-- | src/src/acl.c | 31 | ||||
-rw-r--r-- | src/src/utf8.c | 32 | ||||
-rw-r--r-- | src/src/verify.c | 55 | ||||
-rw-r--r-- | test/confs/4201 | 4 | ||||
l--------- | test/confs/4208 | 1 | ||||
-rw-r--r-- | test/scripts/4200-International/4208 | 23 |
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 |