[evolution-data-server] Bug 486018 - Implement IDNA (Internationalized Domain Names in Applications)
- From: Milan Crha <mcrha src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution-data-server] Bug 486018 - Implement IDNA (Internationalized Domain Names in Applications)
- Date: Wed, 27 Aug 2014 12:08:06 +0000 (UTC)
commit b068eb4c76f56e13573e4388a536df02f2beb5aa
Author: Milan Crha <mcrha redhat com>
Date: Wed Aug 27 14:07:23 2014 +0200
Bug 486018 - Implement IDNA (Internationalized Domain Names in Applications)
camel/camel-internet-address.c | 66 ++++++++++++++++++++++++++++++++
camel/camel-internet-address.h | 2 +
camel/camel-net-utils.c | 81 +++++++++++++++++++++++++++++++++++++++-
camel/camel-net-utils.h | 2 +
camel/camel-network-service.c | 2 +-
camel/camel-network-settings.c | 35 +++++++++++++++++
camel/camel-network-settings.h | 2 +
camel/camel-transport.c | 14 ++++++-
configure.ac | 2 +-
9 files changed, 201 insertions(+), 5 deletions(-)
---
diff --git a/camel/camel-internet-address.c b/camel/camel-internet-address.c
index 99435ee..44c8d39 100644
--- a/camel/camel-internet-address.c
+++ b/camel/camel-internet-address.c
@@ -21,6 +21,7 @@
#include "camel-internet-address.h"
#include "camel-mime-utils.h"
+#include "camel-net-utils.h"
#define d(x)
@@ -348,6 +349,71 @@ camel_internet_address_find_name (CamelInternetAddress *addr,
return -1;
}
+static gboolean
+domain_contains_only_ascii (const gchar *address,
+ gint *at_pos)
+{
+ gint pos;
+ gboolean all_ascii = TRUE;
+
+ g_return_val_if_fail (address != NULL, TRUE);
+ g_return_val_if_fail (at_pos != NULL, TRUE);
+
+ *at_pos = -1;
+ for (pos = 0; address[pos]; pos++) {
+ all_ascii = all_ascii && address[pos] > 0;
+ if (*at_pos == -1 && address[pos] == '@') {
+ *at_pos = pos;
+ all_ascii = TRUE;
+ }
+ }
+
+ /* Do not change anything when there is no domain part
+ of the email address */
+ return all_ascii || *at_pos == -1;
+}
+
+/**
+ * camel_internet_address_ensure_ascii_domains:
+ * @addr: a #CamelInternetAddress
+ *
+ * Ensures that all email address' domains will be ASCII encoded,
+ * which means that any non-ASCII letters will be properly encoded.
+ * This includes IDN (Internationalized Domain Names).
+ *
+ * Since: 3.14
+ **/
+void
+camel_internet_address_ensure_ascii_domains (CamelInternetAddress *addr)
+{
+ struct _address *a;
+ gint i, len;
+
+ g_return_if_fail (CAMEL_IS_INTERNET_ADDRESS (addr));
+
+ len = ((CamelAddress *) addr)->addresses->len;
+ for (i = 0; i < len; i++) {
+ gint at_pos = -1;
+ a = g_ptr_array_index (((CamelAddress *) addr)->addresses, i);
+ if (a->address && !domain_contains_only_ascii (a->address, &at_pos)) {
+ gchar *address, *domain;
+
+ domain = camel_host_idna_to_ascii (a->address + at_pos + 1);
+ if (at_pos >= 0) {
+ gchar *name = g_strndup (a->address, at_pos);
+ address = g_strconcat (name, "@", domain, NULL);
+ } else {
+ address = domain;
+ domain = NULL;
+ }
+
+ g_free (domain);
+ g_free (a->address);
+ a->address = address;
+ }
+ }
+}
+
/**
* camel_internet_address_find_address:
* @addr: a #CamelInternetAddress object
diff --git a/camel/camel-internet-address.h b/camel/camel-internet-address.h
index ce9288b..4253abb 100644
--- a/camel/camel-internet-address.h
+++ b/camel/camel-internet-address.h
@@ -77,6 +77,8 @@ gint camel_internet_address_find_address
(CamelInternetAddress *addr,
const gchar *address,
const gchar **namep);
+void camel_internet_address_ensure_ascii_domains
+ (CamelInternetAddress *addr);
/* utility functions, for network/display formatting */
gchar * camel_internet_address_encode_address
diff --git a/camel/camel-net-utils.c b/camel/camel-net-utils.c
index d22f5b9..1af3229 100644
--- a/camel/camel-net-utils.c
+++ b/camel/camel-net-utils.c
@@ -27,6 +27,8 @@
#include <stdio.h>
#include <glib/gi18n-lib.h>
+#include <unicode/uidna.h>
+#include <unicode/ustring.h>
#include "camel-msgport.h"
#include "camel-net-utils.h"
@@ -693,6 +695,8 @@ camel_getaddrinfo (const gchar *name,
#ifndef ENABLE_IPv6
struct addrinfo myhints;
#endif
+ gchar *ascii_name;
+
g_return_val_if_fail (name != NULL, NULL);
if (g_cancellable_set_error_if_cancelled (cancellable, error))
@@ -712,8 +716,10 @@ camel_getaddrinfo (const gchar *name,
hints = &myhints;
#endif
+ ascii_name = camel_host_idna_to_ascii (name);
+
msg = g_malloc0 (sizeof (*msg));
- msg->name = name;
+ msg->name = ascii_name;
msg->service = service;
msg->hints = hints;
msg->res = &res;
@@ -739,6 +745,7 @@ camel_getaddrinfo (const gchar *name,
res = NULL;
cs_freeinfo (msg);
+ g_free (ascii_name);
camel_operation_pop_message (cancellable);
@@ -767,3 +774,75 @@ camel_freeaddrinfo (struct addrinfo *host)
#endif
}
+/**
+ * camel_host_idna_to_ascii:
+ * @host: Host name, with or without non-ascii letters in utf8
+ *
+ * Converts IDN (Internationalized Domain Name) into ASCII representation.
+ * If there's a failure or the @host has only ASCII letters, then a copy
+ * of @host is returned.
+ *
+ * Returns: Newly allocated string with only ASCII letters describing the @host.
+ * Free it with g_free() when done with it.
+ *
+ * Since: 3.14
+ **/
+gchar *
+camel_host_idna_to_ascii (const gchar *host)
+{
+ UErrorCode uerror = U_ZERO_ERROR;
+ int32_t uhost_len = 0;
+ const gchar *ptr;
+ gchar *ascii = NULL;
+
+ g_return_val_if_fail (host != NULL, NULL);
+
+ ptr = host;
+ while (*ptr > 0)
+ ptr++;
+
+ if (!*ptr) {
+ /* Did read whole buffer, it should be ASCII string already */
+ return g_strdup (host);
+ }
+
+ u_strFromUTF8 (NULL, 0, &uhost_len, host, -1, &uerror);
+ if (uhost_len > 0) {
+ UChar *uhost = g_new0 (UChar, uhost_len + 2);
+
+ uerror = U_ZERO_ERROR;
+ u_strFromUTF8 (uhost, uhost_len + 1, &uhost_len, host, -1, &uerror);
+ if (uerror == U_ZERO_ERROR && uhost_len > 0) {
+ int32_t buffer_len = uhost_len * 6 + 6, nconverted;
+ UChar *buffer = g_new0 (UChar, buffer_len);
+
+ nconverted = uidna_IDNToASCII (uhost, uhost_len, buffer, buffer_len,
UIDNA_ALLOW_UNASSIGNED, 0, &uerror);
+ if (uerror == U_ZERO_ERROR && nconverted > 0) {
+ int32_t ascii_len = 0;
+
+ u_strToUTF8 (NULL, 0, &ascii_len, buffer, nconverted, &uerror);
+ if (ascii_len > 0) {
+ uerror = U_ZERO_ERROR;
+ ascii = g_new0 (gchar, ascii_len + 2);
+
+ u_strToUTF8 (ascii, ascii_len + 1, &ascii_len, buffer, nconverted,
&uerror);
+ if (uerror == U_ZERO_ERROR && ascii_len > 0) {
+ ascii[ascii_len] = '\0';
+ } else {
+ g_free (ascii);
+ ascii = NULL;
+ }
+ }
+ }
+
+ g_free (buffer);
+ }
+
+ g_free (uhost);
+ }
+
+ if (!ascii)
+ ascii = g_strdup (host);
+
+ return ascii;
+}
diff --git a/camel/camel-net-utils.h b/camel/camel-net-utils.h
index 000f55c..8090263 100644
--- a/camel/camel-net-utils.h
+++ b/camel/camel-net-utils.h
@@ -94,6 +94,8 @@ struct addrinfo *
GError **error);
void camel_freeaddrinfo (struct addrinfo *host);
+gchar * camel_host_idna_to_ascii (const gchar *host);
+
G_END_DECLS
#ifdef _WIN32
diff --git a/camel/camel-network-service.c b/camel/camel-network-service.c
index 0654ba6..4f80c3c 100644
--- a/camel/camel-network-service.c
+++ b/camel/camel-network-service.c
@@ -662,7 +662,7 @@ network_service_new_connectable (CamelNetworkService *service)
g_return_val_if_fail (CAMEL_IS_NETWORK_SETTINGS (settings), NULL);
network_settings = CAMEL_NETWORK_SETTINGS (settings);
- host = camel_network_settings_dup_host (network_settings);
+ host = camel_network_settings_dup_host_ensure_ascii (network_settings);
port = camel_network_settings_get_port (network_settings);
if (host && *host && g_ascii_strcasecmp (host, "localhost") != 0)
diff --git a/camel/camel-network-settings.c b/camel/camel-network-settings.c
index 0e7f801..33d6ef3 100644
--- a/camel/camel-network-settings.c
+++ b/camel/camel-network-settings.c
@@ -19,6 +19,7 @@
#include <camel/camel-enumtypes.h>
#include <camel/camel-settings.h>
+#include <camel/camel-net-utils.h>
#define AUTH_MECHANISM_KEY "CamelNetworkSettings:auth-mechanism"
#define HOST_KEY "CamelNetworkSettings:host"
@@ -234,6 +235,40 @@ camel_network_settings_dup_host (CamelNetworkSettings *settings)
}
/**
+ * camel_network_settings_dup_host_ensure_ascii:
+ * @settings: a #CamelNetworkSettings
+ *
+ * Just like camel_network_settings_dup_host(), only makes sure that
+ * the returned host name will be converted into its ASCII form in case
+ * of IDNA value.
+ *
+ * Returns: a newly-allocated copy of #CamelNetworkSettings:host with
+ * only ASCII letters.
+ *
+ * Since: 3.14
+ **/
+gchar *
+camel_network_settings_dup_host_ensure_ascii (CamelNetworkSettings *settings)
+{
+ const gchar *protected;
+ gchar *duplicate;
+
+ g_return_val_if_fail (CAMEL_IS_NETWORK_SETTINGS (settings), NULL);
+
+ G_LOCK (property_lock);
+
+ protected = camel_network_settings_get_host (settings);
+ if (protected && *protected)
+ duplicate = camel_host_idna_to_ascii (protected);
+ else
+ duplicate = g_strdup (protected);
+
+ G_UNLOCK (property_lock);
+
+ return duplicate;
+}
+
+/**
* camel_network_settings_set_host:
* @settings: a #CamelNetworkSettings
* @host: a host name, or %NULL
diff --git a/camel/camel-network-settings.h b/camel/camel-network-settings.h
index acade27..db79485 100644
--- a/camel/camel-network-settings.h
+++ b/camel/camel-network-settings.h
@@ -71,6 +71,8 @@ const gchar * camel_network_settings_get_host
(CamelNetworkSettings *settings);
gchar * camel_network_settings_dup_host
(CamelNetworkSettings *settings);
+gchar * camel_network_settings_dup_host_ensure_ascii
+ (CamelNetworkSettings *settings);
void camel_network_settings_set_host
(CamelNetworkSettings *settings,
const gchar *host);
diff --git a/camel/camel-transport.c b/camel/camel-transport.c
index 76a619d..38ad3db 100644
--- a/camel/camel-transport.c
+++ b/camel/camel-transport.c
@@ -200,8 +200,18 @@ camel_transport_send_to (CamelTransport *transport,
service = CAMEL_SERVICE (transport);
async_context = g_slice_new0 (AsyncContext);
- async_context->from = g_object_ref (from);
- async_context->recipients = g_object_ref (recipients);
+ if (CAMEL_IS_INTERNET_ADDRESS (from)) {
+ async_context->from = camel_address_new_clone (from);
+ camel_internet_address_ensure_ascii_domains (CAMEL_INTERNET_ADDRESS (async_context->from));
+ } else {
+ async_context->from = g_object_ref (from);
+ }
+ if (CAMEL_IS_INTERNET_ADDRESS (recipients)) {
+ async_context->recipients = camel_address_new_clone (recipients);
+ camel_internet_address_ensure_ascii_domains (CAMEL_INTERNET_ADDRESS
(async_context->recipients));
+ } else {
+ async_context->recipients = g_object_ref (recipients);
+ }
async_context->message = g_object_ref (message);
task = g_task_new (transport, cancellable, callback, user_data);
diff --git a/configure.ac b/configure.ac
index fb78a04..93fa65a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1608,7 +1608,7 @@ fi
AM_CONDITIONAL(ENABLE_LARGEFILE, [test "x$enable_largefile" = "xyes"])
-EVO_SET_COMPILE_FLAGS(CAMEL, gio-2.0 gmodule-2.0 $mozilla_nss $mozilla_nspr sqlite3 >=
sqlite_minimum_version, $KRB5_CFLAGS $MANUAL_NSS_CFLAGS $MANUAL_NSPR_CFLAGS $LARGEFILE_CFLAGS, -lz $KRB5_LIBS
$MANUAL_NSS_LIBS $MANUAL_NSPR_LIBS)
+EVO_SET_COMPILE_FLAGS(CAMEL, gio-2.0 gmodule-2.0 $mozilla_nss $mozilla_nspr sqlite3 >=
sqlite_minimum_version, $KRB5_CFLAGS $MANUAL_NSS_CFLAGS $MANUAL_NSPR_CFLAGS $LARGEFILE_CFLAGS $ICU_CFLAGS,
-lz $KRB5_LIBS $MANUAL_NSS_LIBS $MANUAL_NSPR_LIBS $ICU_LIBS)
AC_SUBST(CAMEL_CFLAGS)
AC_SUBST(CAMEL_LIBS)
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]