changeset 1639:d9913c1b35e7

Add support for libidn
author Mikael Berthe <mikael@lilotux.net>
date Sun, 25 Oct 2009 23:25:14 +0100
parents 3b3b5c1f8327
children bf2258e29834
files mcabber/configure.ac mcabber/src/utils.c
diffstat 2 files changed, 85 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- a/mcabber/configure.ac	Sun Oct 25 01:15:31 2009 +0200
+++ b/mcabber/configure.ac	Sun Oct 25 23:25:14 2009 +0100
@@ -152,6 +152,21 @@
 AC_SUBST(LOUDMOUTH_CFLAGS)
 AC_SUBST(LOUDMOUTH_LIBS)
 
+# Check for libidn
+AC_ARG_WITH(libidn, AC_HELP_STRING([--with-libidn=[DIR]],
+                                   [Support IDN (needs GNU Libidn)]),
+            libidn=$withval, libidn=yes)
+if test "$libidn" != "no" ; then
+  PKG_CHECK_MODULES(LIBIDN, libidn >= 0.0.0, [libidn=yes], [libidn=no])
+  if test "$libidn" != "yes" ; then
+    libidn=no
+    AC_MSG_WARN([Libidn not found])
+  else
+    libidn=yes
+    AC_DEFINE(HAVE_LIBIDN, 1, [Define to 1 if you want Libidn.])
+  fi
+fi
+
 # Check for gpgme
 AC_ARG_ENABLE(gpgme, AC_HELP_STRING([--disable-gpgme], [disable GPGME support]),
     [ if test x"$enableval" = x"no"; then
--- a/mcabber/src/utils.c	Sun Oct 25 01:15:31 2009 +0200
+++ b/mcabber/src/utils.c	Sun Oct 25 23:25:14 2009 +0100
@@ -21,11 +21,20 @@
  * USA
  */
 
+#include <config.h>
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <stdarg.h>
 
+#ifdef HAVE_LIBIDN
+#include <idna.h>
+#include <stringprep.h>
+static char idnprep[1024];
+#endif
+
+#include <glib.h>
 #include <glib/gprintf.h>
 
 /* For Cygwin (thanks go to Yitzchak Scott-Thoennes) */
@@ -38,9 +47,7 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <ctype.h>
-#include <glib.h>
 
-#include <config.h>
 #include "utils.h"
 #include "logprint.h"
 
@@ -402,6 +409,10 @@
   const char *str;
   const char *domain, *resource;
   int domlen;
+#ifdef HAVE_LIBIDN
+  char *idnpp, *ascidnp;
+  int r;
+#endif
 
   if (!fjid) return 1;
 
@@ -416,6 +427,28 @@
       return 1;
     domain++;
 
+#ifdef HAVE_LIBIDN
+    idnpp = idnprep;
+    str = fjid;
+    while (*str != JID_DOMAIN_SEPARATOR)
+      *idnpp++ = *str++;
+    *idnpp = 0;
+
+    r = stringprep(idnprep, 1023, 0, stringprep_xmpp_nodeprep);
+    if (r != STRINGPREP_OK || !idnprep[0])
+      return 1;
+
+    // check the string hasn't been modified, in which case we consider
+    // it's a failure (as fjid is read-only)
+    idnpp = idnprep;
+    str = fjid;
+    while (*idnpp) {
+      if (*idnpp++ != *str++)
+        return 1;
+    }
+    scr_LogPrint(LPRINT_LOGNORM, "Stringprep'd node: [%s]", idnprep); // XXX
+    /* the username looks okay */
+#else
     /* check for low and invalid ascii characters in the username */
     for (str = fjid; *str != JID_DOMAIN_SEPARATOR; str++) {
       if (*str <= ' ' || *str == ':' || *str == JID_DOMAIN_SEPARATOR ||
@@ -425,6 +458,7 @@
       }
     }
     /* the username is okay as far as we can tell without LIBIDN */
+#endif
   }
 
   resource = strchr(domain, JID_RESOURCE_SEPARATOR);
@@ -436,6 +470,12 @@
     /* resources may not be longer than 1023 bytes */
     if ((*resource == '\0') || strlen(resource) > 1023)
       return 1;
+#ifdef HAVE_LIBIDN
+    strncpy(idnprep, resource, sizeof(idnprep));
+    r = stringprep(idnprep, 1023, 0, stringprep_xmpp_resourceprep);
+    if (r != STRINGPREP_OK || !idnprep[0])
+      return 1;
+#endif
   } else {
     domlen = strlen(domain);
   }
@@ -446,13 +486,40 @@
   /* and it must not be longer than 1023 bytes */
   if (domlen > 1023) return 1;
 
+#ifdef HAVE_LIBIDN
+  idnpp = idnprep;
+  str = domain;
+  while (*str != '\0' && *str != JID_RESOURCE_SEPARATOR)
+    *idnpp++ = *str++;
+  *idnpp = 0;
+
+  r = stringprep_nameprep(idnprep, 1023);
+  if (r != STRINGPREP_OK || !idnprep[0])
+    return 1;
+
+  if (idna_to_ascii_8z(idnprep, &ascidnp, IDNA_USE_STD3_ASCII_RULES) !=
+      IDNA_SUCCESS)
+    return 1;
+  else
+    free(ascidnp);
+
+  // check the string hasn't been modified, in which case we consider
+  // it's a failure (as fjid is read-only)
+  idnpp = idnprep;
+  str = domain;
+  while (*idnpp) {
+    if (*idnpp++ != *str++)
+      return 1;
+  }
+#else
   /* make sure the hostname is valid characters */
   for (str = domain; *str != '\0' && *str != JID_RESOURCE_SEPARATOR; str++) {
     if (!(isalnum(*str) || *str == '.' || *str == '-' || *str == '_'))
       return 1;
   }
+#endif
 
-  /* it's okay as far as we can tell without LIBIDN */
+  /* it's okay as far as we can tell */
   return 0;
 }