From: Jeremy Harris Date: Sun, 29 Mar 2015 10:40:35 +0000 (+0100) Subject: A-label transform functions X-Git-Tag: exim-4_86_RC1~88^2~18 X-Git-Url: https://git.exim.org/users/jgh/exim.git/commitdiff_plain/0d7911ea3aa8124490bd9272474aeba8b4a6313e?hp=d1a13eea59347e185a8f28764115c30dfae44136 A-label transform functions --- diff --git a/TODO b/TODO index 44aa80e90..d2d31ef07 100644 --- a/TODO +++ b/TODO @@ -14,14 +14,34 @@ destination supports the SMTPUTF8 extension ====================== -An "international" flag on the message? -An is-international expansion condition? +to-Alabel convert of helo name -helo-time option handling -dsn handling +++ An "international" flag on the message? +++ An is-international expansion condition? + +++ helo-time option handling +conversion of utf-8 domains on input rfc5890 +- deconversion on forwarding +- deconversion for trace headers +dsn handling rfc6533 logging - international msg - presentation of local-part in log +-- a log option? encoding of local_part encoding transform string-expansions Recieved-by header tracking info +- WITH protocol types get UTF8 prefix + +forwarding checks rfc6530 7.1 -3- +- rcpt-time rejects get 533 mailbox name not allowed +- mail-time rejects get 550 mailbox unavailable +- bounces (see dsn handling) + + +expansions for to- and from-Alabel ? bug1567 + +enhanced status codes? rfc5248++ + +VRFY +EXPN diff --git a/doc/doc-txt/experimental-spec.txt b/doc/doc-txt/experimental-spec.txt index ce4edeb3d..0eeb939bf 100644 --- a/doc/doc-txt/experimental-spec.txt +++ b/doc/doc-txt/experimental-spec.txt @@ -1276,6 +1276,7 @@ SMTPUTF8 Internationalised mail name handling. RFCs 6530, 6533, 5890 +Compile with libidn. -------------------------------------------------------------- diff --git a/src/OS/Makefile-Base b/src/OS/Makefile-Base index 38d719837..63646e218 100644 --- a/src/OS/Makefile-Base +++ b/src/OS/Makefile-Base @@ -295,7 +295,7 @@ convert4r4: Makefile ../src/convert4r4.src OBJ_WITH_CONTENT_SCAN = malware.o mime.o regex.o spam.o spool_mbox.o OBJ_WITH_OLD_DEMIME = demime.o -OBJ_EXPERIMENTAL = bmi_spam.o spf.o srs.o dcc.o dmarc.o dane.o +OBJ_EXPERIMENTAL = bmi_spam.o spf.o srs.o dcc.o dmarc.o dane.o utf8.o # Targets for final binaries; the main one has a build number which is # updated each time. We don't bother with that for the auxiliaries. @@ -604,6 +604,7 @@ dcc.o: $(HDRS) dcc.h dcc.c dmarc.o: $(HDRS) dmarc.h dmarc.c spf.o: $(HDRS) spf.h spf.c srs.o: $(HDRS) srs.h srs.c +utf8.o: $(HDRS) utf8.c # The module containing tables of available lookups, routers, auths, and # transports must be rebuilt if any of them are. However, because the makefiles diff --git a/src/scripts/MakeLinks b/src/scripts/MakeLinks index f68fd6f4b..f9cc27c2e 100755 --- a/src/scripts/MakeLinks +++ b/src/scripts/MakeLinks @@ -276,6 +276,7 @@ ln -s ../src/dane.c dane.c ln -s ../src/dane-gnu.c dane-gnu.c ln -s ../src/dane-openssl.c dane-openssl.c ln -s ../src/danessl.h danessl.h +ln -s ../src/utf8.c utf8.c # End of MakeLinks diff --git a/src/src/EDITME b/src/src/EDITME index d48f268b9..426033577 100644 --- a/src/src/EDITME +++ b/src/src/EDITME @@ -497,6 +497,11 @@ EXIM_MONITOR=eximon.bin # Uncomment the following line to add SOCKS support # EXPERIMENTAL_SOCKS=yes +# Uncomment the following to add Internationalisation features. You need to +# have the IDN library installed. +EXPERIMENTAL_INTERNATIONAL=yes +LDFLAGS += -lidn + ############################################################################### # THESE ARE THINGS YOU MIGHT WANT TO SPECIFY # ############################################################################### diff --git a/src/src/functions.h b/src/src/functions.h index 7195afa88..ac93c1635 100644 --- a/src/src/functions.h +++ b/src/src/functions.h @@ -412,12 +412,21 @@ extern BOOL string_format(uschar *, int, const char *, ...) ALMOST_PRINTF(3,4 extern uschar *string_format_size(int, uschar *); extern int string_interpret_escape(const uschar **); extern int string_is_ip_address(const uschar *, int *); +#ifdef EXPERIMENTAL_INTERNATIONAL +extern BOOL string_is_utf8(const uschar *); +#endif extern uschar *string_log_address(address_item *, BOOL, BOOL); extern uschar *string_nextinlist(const uschar **, int *, uschar *, int); extern uschar *string_open_failed(int, const char *, ...) PRINTF_FUNCTION(2,3); extern const uschar *string_printing2(const uschar *, BOOL); extern uschar *string_split_message(uschar *); extern uschar *string_unprinting(uschar *); +#ifdef EXPERIMENTAL_INTERNATIONAL +extern uschar *string_domain_alabel_to_utf8(const uschar *, uschar **); +extern uschar *string_domain_utf8_to_alabel(const uschar *, uschar **); +extern uschar *string_localpart_alabel_to_utf8(const uschar *, uschar **); +extern uschar *string_localpart_utf8_to_alabel(const uschar *, uschar **); +#endif extern BOOL string_vformat(uschar *, int, const char *, va_list); extern int strcmpic(const uschar *, const uschar *); extern int strncmpic(const uschar *, const uschar *, int); diff --git a/src/src/utf8.c b/src/src/utf8.c new file mode 100644 index 000000000..2f8173dc1 --- /dev/null +++ b/src/src/utf8.c @@ -0,0 +1,125 @@ +/************************************************* +* Exim - an Internet mail transport agent * +*************************************************/ + +/* Copyright (c) Jeremy Harris 2015 */ +/* See the file NOTICE for conditions of use and distribution. */ + + +#include "exim.h" + +#ifdef EXPERIMENTAL_INTERNATIONAL + +#include +#include +#include + +BOOL +string_is_utf8(const uschar * s) +{ +uschar c; +while ((c = *s++)) if (c & 0x80) return TRUE; +return FALSE; +} + +/**************************************************/ +/* Domain conversions */ + +uschar * +string_domain_utf8_to_alabel(const uschar * utf8, uschar ** err) +{ +uschar * s1; +uschar * s; +int rc; + +s = US stringprep_utf8_nfkc_normalize(CCS utf8, -1); +if ( (rc = idna_to_ascii_8z(CCS s, CSS &s1, IDNA_USE_STD3_ASCII_RULES)) + != IDNA_SUCCESS) + { + free(s); + if (err) *err = US idna_strerror(rc); + return NULL; + } +free(s); +s = string_copy(s1); +free(s1); +return s; +} + + + +uschar * +string_domain_alabel_to_utf8(const uschar * alabel, uschar ** err) +{ +uschar * s1; +uschar * s; +int rc; +if ( (rc = idna_to_unicode_8z8z(CCS alabel, CSS &s1, IDNA_USE_STD3_ASCII_RULES)) + != IDNA_SUCCESS) + { + if (err) *err = US idna_strerror(rc); + return NULL; + } +s = string_copy(s1); +free(s1); +return s; +} + +/**************************************************/ +/* localpart conversions */ + + +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); +int rc; + +res[0] = 'x'; res[1] = 'n'; res[2] = res[3] = '-'; + +if ((rc = punycode_encode(ucs4_len, p, NULL, &p_len, res+4)) != PUNYCODE_SUCCESS) + { + free(p); + if (err) *err = US punycode_strerror(rc); + return NULL; + } +free(p); +res[p_len] = '\0'; +return res; +} + + +uschar * +string_localpart_alabel_to_utf8(const uschar * alabel, uschar ** err) +{ +size_t p_len = strlen(alabel); +punycode_uint * p; +int rc; + +if (alabel[0] != 'x' || alabel[1] != 'n' || alabel[2] != '-' || alabel[3] != '-') + { + if (err) *err = US"bad alabel prefix"; + return NULL; + } +p_len -= 4; + +p = (punycode_uint *) store_get((p_len+1) * sizeof(*p)); + +if ((rc = punycode_decode(p_len, CCS alabel+4, &p_len, p, NULL)) != PUNYCODE_SUCCESS) + { + if (err) *err = US punycode_strerror(rc); + return NULL; + } +p[p_len] = 0; +return US p; +} + + +#endif /* whole file */ + +/* vi: aw ai sw=2 +*/ +/* End of utf8.c */