summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeremy Harris <jgh146exb@wizmail.org>2015-03-29 11:40:35 +0100
committerJeremy Harris <jgh146exb@wizmail.org>2015-04-12 19:15:20 +0100
commit0d7911ea3aa8124490bd9272474aeba8b4a6313e (patch)
tree921c988ca25f271379e3184113febf9eca280f0a
parentd1a13eea59347e185a8f28764115c30dfae44136 (diff)
A-label transform functions
-rw-r--r--TODO28
-rw-r--r--doc/doc-txt/experimental-spec.txt1
-rw-r--r--src/OS/Makefile-Base3
-rwxr-xr-xsrc/scripts/MakeLinks1
-rw-r--r--src/src/EDITME5
-rw-r--r--src/src/functions.h9
-rw-r--r--src/src/utf8.c125
7 files changed, 167 insertions, 5 deletions
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 <idna.h>
+#include <punycode.h>
+#include <stringprep.h>
+
+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 */