A-label transform functions
authorJeremy Harris <jgh146exb@wizmail.org>
Sun, 29 Mar 2015 10:40:35 +0000 (11:40 +0100)
committerJeremy Harris <jgh146exb@wizmail.org>
Sun, 12 Apr 2015 18:15:20 +0000 (19:15 +0100)
TODO
doc/doc-txt/experimental-spec.txt
src/OS/Makefile-Base
src/scripts/MakeLinks
src/src/EDITME
src/src/functions.h
src/src/utf8.c [new file with mode: 0644]

diff --git a/TODO b/TODO
index 44aa80e..d2d31ef 100644 (file)
--- 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
index ce4edeb..0eeb939 100644 (file)
@@ -1276,6 +1276,7 @@ SMTPUTF8
 Internationalised mail name handling.
 RFCs 6530, 6533, 5890
 
+Compile with libidn.
 
 
 --------------------------------------------------------------
index 38d7198..63646e2 100644 (file)
@@ -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
index f68fd6f..f9cc27c 100755 (executable)
@@ -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
index d48f268..4260335 100644 (file)
@@ -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                  #
 ###############################################################################
index 7195afa..ac93c16 100644 (file)
@@ -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 (file)
index 0000000..2f8173d
--- /dev/null
@@ -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 */