Blob Blame History Raw
From 13a2f6144c51c0451b20056bf92cbd0b2f338f1e Mon Sep 17 00:00:00 2001
From: Matej Muzila <mmuzila@redhat.com>
Date: Mon, 9 Apr 2018 13:46:42 +0200
Subject: [PATCH] Add libidn2 support

---
 configure.ac       | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 doc/makedoc-defs.h |  3 +++
 init.h             |  4 ++--
 main.c             | 13 ++++++++++++-
 mutt.h             |  2 +-
 mutt_idna.c        | 20 ++++++++++----------
 mutt_idna.h        |  8 ++++++--
 mutt_socket.c      |  8 ++++----
 mutt_ssl.c         |  2 +-
 9 files changed, 94 insertions(+), 21 deletions(-)

diff --git a/configure.ac b/configure.ac
index c46f72b0..5c6de33c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1293,6 +1293,25 @@ AC_ARG_WITH(idn, AS_HELP_STRING([--with-idn=@<:@PFX@:>@],[Use GNU libidn for int
 		 ],
 		 [with_idn=auto])
 
+AC_ARG_WITH(idn2, AS_HELP_STRING([--with-idn2=@<:@PFX@:>@],[Use GNU libidn2 for internationalized domain names]),
+        [
+          if test "$with_idn2" != "no" ; then
+            if test "$with_idn" = "auto"; then
+              with_idn="no"
+            fi
+
+            if test "$with_idn" != "no"; then
+              AC_MSG_ERROR([Cannot enable IDN and IDN2 support at the same time])
+            fi
+
+            if test "$with_idn2" != "yes" ; then
+              CPPFLAGS="$CPPFLAGS -I$with_idn2/include"
+              LDFLAGS="$LDFLAGS -L$with_idn2/lib"
+            fi
+          fi
+        ],
+        [with_idn2=no])
+
 if test "x$with_idn" != "xno"; then
   if test "$am_cv_func_iconv" != "yes"; then
     if test "$with_idn" != "auto"; then
@@ -1332,6 +1351,42 @@ if test "x$with_idn" != "xno"; then
   fi
 fi
 
+dnl idna2
+if test "x$with_idn2" != "xno"; then
+  if test "$am_cv_func_iconv" != "yes"; then
+    if test "$with_idn2" != "auto"; then
+      AC_MSG_ERROR([IDN2 requested but iconv is disabled or unavailable])
+    fi
+  else
+    dnl Solaris 11 has /usr/include/idn
+    have_idn2_h=no
+    AC_CHECK_HEADERS([idn2.h idn/idn2.h], [
+              have_idn2_h=yes
+              break])
+
+    mutt_save_LIBS="$LIBS"
+    LIBS=
+
+    AC_SEARCH_LIBS([idn2_check_version], [idn2], [
+      AC_DEFINE([HAVE_LIBIDN2], 1, [Define to 1 if you have the GNU idn2 library])
+      MUTTLIBS="$MUTTLIBS $LIBS"
+
+      LIBS="$LIBS $LIBICONV"
+      AC_DEFINE([HAVE_IDNA_TO_UNICODE_8Z8Z])
+      AC_DEFINE([HAVE_IDNA_TO_ASCII_8Z])
+      AC_DEFINE([HAVE_IDNA_TO_ASCII_LZ])
+    ])
+
+    LIBS="$mutt_save_LIBS"
+
+    if test "$with_idn2" != "no"; then
+      if test "$have_idn2_h" = "no" || test "$ac_cv_search_idn2_check_version" = "no"; then
+        AC_MSG_ERROR([IDN2 was requested, but libidn2 was not usable on this system])
+      fi
+    fi
+  fi
+fi
+
 dnl -- locales --
 
 AC_CHECK_HEADERS(wchar.h)
diff --git a/doc/makedoc-defs.h b/doc/makedoc-defs.h
index 2da29f48..78a4ebc0 100644
--- a/doc/makedoc-defs.h
+++ b/doc/makedoc-defs.h
@@ -52,6 +52,9 @@
 # ifndef HAVE_LIBIDN
 #  define HAVE_LIBIDN
 # endif
+# ifndef HAVE_LIBIDN2
+#  define HAVE_LIBIDN2
+# endif
 # ifndef HAVE_GETADDRINFO
 #  define HAVE_GETADDRINFO
 # endif
diff --git a/init.h b/init.h
index bdd22543..5e79786c 100644
--- a/init.h
+++ b/init.h
@@ -1177,7 +1177,7 @@ struct option_t MuttVars[] = {
   ** .pp
   ** Also see $$use_domain and $$hidden_host.
   */
-#ifdef HAVE_LIBIDN
+#if defined(HAVE_LIBIDN) || defined(HAVE_LIBIDN2)
   { "idn_decode",	DT_BOOL, R_MENU, OPTIDNDECODE, 1},
   /*
   ** .pp
@@ -1192,7 +1192,7 @@ struct option_t MuttVars[] = {
   ** IDN.  Unset this if your SMTP server can handle newer (RFC 6531)
   ** UTF-8 encoded domains. (IDN only)
   */
-#endif /* HAVE_LIBIDN */
+#endif /* defined(HAVE_LIBIDN) || defined(HAVE_LIBIDN2) */
   { "ignore_linear_white_space",    DT_BOOL, R_NONE, OPTIGNORELWS, 0 },
   /*
   ** .pp
diff --git a/main.c b/main.c
index b189c860..0d2dbac4 100644
--- a/main.c
+++ b/main.c
@@ -218,6 +218,11 @@ static void show_version (void)
 	  STRINGPREP_VERSION);
 #endif
 
+#ifdef HAVE_LIBIDN2
+  printf ("\nlibidn2: %s (compiled with %s)", idn2_check_version (NULL),
+	  IDN2_VERSION);
+#endif
+
 #ifdef USE_HCACHE
   printf ("\nhcache backend: %s", mutt_hcache_backend ());
 #endif
@@ -485,7 +490,13 @@ static void show_version (void)
 #else
 	"-HAVE_LIBIDN  "
 #endif
-	
+
+#if HAVE_LIBIDN2
+	"+HAVE_LIBIDN2  "
+#else
+	"-HAVE_LIBIDN2  "
+#endif
+
 #if HAVE_GETSID
 	"+HAVE_GETSID  "
 #else
diff --git a/mutt.h b/mutt.h
index 4fe7ce49..7372a510 100644
--- a/mutt.h
+++ b/mutt.h
@@ -492,7 +492,7 @@ enum
   OPTUSEDOMAIN,
   OPTUSEFROM,
   OPTUSEGPGAGENT,
-#ifdef HAVE_LIBIDN
+#if defined(HAVE_LIBIDN) || defined(HAVE_LIBIDN2)
   OPTIDNDECODE,
   OPTIDNENCODE,
 #endif
diff --git a/mutt_idna.c b/mutt_idna.c
index a059e867..cb231b5a 100644
--- a/mutt_idna.c
+++ b/mutt_idna.c
@@ -24,7 +24,7 @@
 #include "charset.h"
 #include "mutt_idna.h"
 
-#ifdef HAVE_LIBIDN
+#if defined(HAVE_LIBIDN) || defined(HAVE_LIBIDN2)
 static int check_idn (char *domain)
 {
   if (! domain)
@@ -41,7 +41,7 @@ static int check_idn (char *domain)
 
   return 0;
 }
-#endif /* HAVE_LIBIDN */
+#endif /* defined(HAVE_LIBIDN) || defined(HAVE_LIBIDN2) */
 
 static int mbox_to_udomain (const char *mbx, char **user, char **domain)
 {
@@ -90,14 +90,14 @@ static char *intl_to_local (char *orig_user, char *orig_domain, int flags)
   char *local_user = NULL, *local_domain = NULL, *mailbox = NULL;
   char *reversed_user = NULL, *reversed_domain = NULL;
   char *tmp = NULL;
-#ifdef HAVE_LIBIDN
+#if defined(HAVE_LIBIDN) || defined(HAVE_LIBIDN2)
   int is_idn_encoded = 0;
-#endif /* HAVE_LIBIDN */
+#endif /* defined(HAVE_LIBIDN) || defined(HAVE_LIBIDN2) */
 
   local_user = safe_strdup (orig_user);
   local_domain = safe_strdup (orig_domain);
 
-#ifdef HAVE_LIBIDN
+#if defined(HAVE_LIBIDN) || defined(HAVE_LIBIDN2)
   is_idn_encoded = check_idn (local_domain);
   if (is_idn_encoded && option (OPTIDNDECODE))
   {
@@ -106,7 +106,7 @@ static char *intl_to_local (char *orig_user, char *orig_domain, int flags)
     mutt_str_replace (&local_domain, tmp);
     FREE (&tmp);
   }
-#endif /* HAVE_LIBIDN */
+#endif /* defined(HAVE_LIBIDN) || defined(HAVE_LIBIDN2) */
 
   /* we don't want charset-hook effects, so we set flags to 0 */
   if (mutt_convert_string (&local_user, "utf-8", Charset, 0) == -1)
@@ -148,7 +148,7 @@ static char *intl_to_local (char *orig_user, char *orig_domain, int flags)
       goto cleanup;
     }
 
-#ifdef HAVE_LIBIDN
+#if defined(HAVE_LIBIDN) || defined(HAVE_LIBIDN2)
     /* If the original domain was UTF-8, idna encoding here could
      * produce a non-matching domain!  Thus we only want to do the
      * idna_to_ascii_8z() if the original domain was IDNA encoded.
@@ -164,7 +164,7 @@ static char *intl_to_local (char *orig_user, char *orig_domain, int flags)
       }
       mutt_str_replace (&reversed_domain, tmp);
     }
-#endif /* HAVE_LIBIDN */
+#endif /* defined(HAVE_LIBIDN) || defined(HAVE_LIBIDN2) */
 
     if (ascii_strcasecmp (orig_domain, reversed_domain))
     {
@@ -203,14 +203,14 @@ static char *local_to_intl (char *user, char *domain)
   if (mutt_convert_string (&intl_domain, Charset, "utf-8", 0) == -1)
     goto cleanup;
 
-#ifdef HAVE_LIBIDN
+#if defined(HAVE_LIBIDN) || defined(HAVE_LIBIDN2)
   if (option (OPTIDNENCODE))
   {
     if (idna_to_ascii_8z (intl_domain, &tmp, IDNA_ALLOW_UNASSIGNED) != IDNA_SUCCESS)
       goto cleanup;
     mutt_str_replace (&intl_domain, tmp);
   }
-#endif /* HAVE_LIBIDN */
+#endif /* defined(HAVE_LIBIDN) || defined(HAVE_LIBIDN2) */
 
   mailbox = safe_malloc (mutt_strlen (intl_user) + mutt_strlen (intl_domain) + 2);
   sprintf (mailbox, "%s@%s", NONULL(intl_user), NONULL(intl_domain)); /* __SPRINTF_CHECKED__ */
diff --git a/mutt_idna.h b/mutt_idna.h
index 192e08db..62e6e301 100644
--- a/mutt_idna.h
+++ b/mutt_idna.h
@@ -26,13 +26,17 @@
 #include <idna.h>
 #elif defined(HAVE_IDN_IDNA_H)
 #include <idn/idna.h>
+#elif defined(HAVE_IDN2_H)
+#include <idn2.h>
+#elif defined(HAVE_IDN_IDN2_H)
+#include <idn/idn2.h>
 #endif
 
 #define MI_MAY_BE_IRREVERSIBLE		(1 << 0)
 
 /* Work around incompatibilities in the libidn API */
 
-#ifdef HAVE_LIBIDN
+#if defined(HAVE_LIBIDN) || defined(HAVE_LIBIDN2)
 # if (!defined(HAVE_IDNA_TO_ASCII_8Z) && defined(HAVE_IDNA_TO_ASCII_FROM_UTF8))
 #  define idna_to_ascii_8z(a,b,c) idna_to_ascii_from_utf8(a,b,(c)&1,((c)&2)?1:0)
 # endif
@@ -42,7 +46,7 @@
 # if (!defined(HAVE_IDNA_TO_UNICODE_8Z8Z) && defined(HAVE_IDNA_TO_UNICODE_UTF8_FROM_UTF8))
 #  define idna_to_unicode_8z8z(a,b,c) idna_to_unicode_utf8_from_utf8(a,b,(c)&1,((c)&2)?1:0)
 # endif
-#endif /* HAVE_LIBIDN */
+#endif /* defined(HAVE_LIBIDN) || defined(HAVE_LIBIDN2) */
 
 
 #ifdef HAVE_ICONV
diff --git a/mutt_socket.c b/mutt_socket.c
index 16e52dce..dc845865 100644
--- a/mutt_socket.c
+++ b/mutt_socket.c
@@ -499,7 +499,7 @@ int raw_socket_open (CONNECTION* conn)
 
   snprintf (port, sizeof (port), "%d", conn->account.port);
   
-# ifdef HAVE_LIBIDN
+# if defined(HAVE_LIBIDN) || defined(HAVE_LIBIDN2)
   if (idna_to_ascii_lz (conn->account.host, &host_idna, 1) != IDNA_SUCCESS)
   {
     mutt_error (_("Bad IDN \"%s\"."), conn->account.host);
@@ -514,7 +514,7 @@ int raw_socket_open (CONNECTION* conn)
   
   rc = getaddrinfo (host_idna, port, &hints, &res);
 
-# ifdef HAVE_LIBIDN
+# if defined(HAVE_LIBIDN) || defined(HAVE_LIBIDN2)
   FREE (&host_idna);
 # endif
 
@@ -558,7 +558,7 @@ int raw_socket_open (CONNECTION* conn)
   sin.sin_port = htons (conn->account.port);
   sin.sin_family = AF_INET;
 
-# ifdef HAVE_LIBIDN
+# if defined(HAVE_LIBIDN) || defined(HAVE_LIBIDN2)
   if (idna_to_ascii_lz (conn->account.host, &host_idna, 1) != IDNA_SUCCESS)
   {
     mutt_error (_("Bad IDN \"%s\"."), conn->account.host);
@@ -573,7 +573,7 @@ int raw_socket_open (CONNECTION* conn)
 
   he = gethostbyname (host_idna);
 
-# ifdef HAVE_LIBIDN
+# if defined(HAVE_LIBIDN) || defined(HAVE_LIBIDN2)
     FREE (&host_idna);
 # endif
 
diff --git a/mutt_ssl.c b/mutt_ssl.c
index eacd1556..3467b618 100644
--- a/mutt_ssl.c
+++ b/mutt_ssl.c
@@ -935,7 +935,7 @@ static int check_host (X509 *x509cert, const char *hostname, char *err, size_t e
   /* Check if 'hostname' matches the one of the subjectAltName extensions of
    * type DNS or the Common Name (CN). */
 
-#ifdef HAVE_LIBIDN
+#if defined(HAVE_LIBIDN) || defined(HAVE_LIBIDN2)
   if (idna_to_ascii_lz(hostname, &hostname_ascii, 0) != IDNA_SUCCESS)
   {
     hostname_ascii = safe_strdup(hostname);
-- 
2.13.6