======================
-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
Internationalised mail name handling.
RFCs 6530, 6533, 5890
+Compile with libidn.
--------------------------------------------------------------
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.
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
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
# 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 #
###############################################################################
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);
--- /dev/null
+/*************************************************
+* 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 */