[gmime: 2/4] Added libidn support
- From: Jeffrey Stedfast <fejj src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gmime: 2/4] Added libidn support
- Date: Sat, 8 Apr 2017 14:46:55 +0000 (UTC)
commit 826a84ac397b8be7d6a0ca1abe5385228814f765
Author: Jeffrey Stedfast <jestedfa microsoft com>
Date: Sat Apr 8 10:39:22 2017 -0400
Added libidn support
configure.ac | 20 ++++++
gmime/Makefile.am | 5 +-
gmime/gmime-utils.c | 15 +++++
gmime/internet-address.c | 152 +++++++++++++++++++++++++++++++++++++++------
gmime/internet-address.h | 6 ++-
5 files changed, 174 insertions(+), 24 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 1eac75e..b042e14 100644
--- a/configure.ac
+++ b/configure.ac
@@ -509,6 +509,25 @@ AS_IF([test "x$enable_crypto" = "xyes"], [
])
AM_CONDITIONAL(ENABLE_CRYPTO, test "x$enable_crypto" != "xno")
+dnl *****************************
+dnl *** Checks for GNU Libidn ***
+dnl *****************************
+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(LIBIDN, 1, [Define to 1 if GNU Libidn should be used.])
+ fi
+fi
+AC_MSG_CHECKING([if Libidn should be used])
+AC_MSG_RESULT($libidn)
+
dnl Check for GObject introspection and Vala binding generator
GOBJECT_INTROSPECTION_CHECK([1.30.0])
VAPIGEN_CHECK
@@ -649,6 +668,7 @@ Configuration:
Console warnings: ${enable_warnings}
PGP/MIME support: ${enable_crypto}
S/MIME support: ${enable_crypto}
+ libidn support: ${libidn}
Vala bindings: ${enable_vala}
"
diff --git a/gmime/Makefile.am b/gmime/Makefile.am
index bf25ad3..6fc6daf 100644
--- a/gmime/Makefile.am
+++ b/gmime/Makefile.am
@@ -11,7 +11,8 @@ AM_CPPFLAGS = \
-I$(top_builddir)/util \
-DG_LOG_DOMAIN=\"gmime\" \
$(GMIME_CFLAGS) \
- $(GLIB_CFLAGS)
+ $(GLIB_CFLAGS) \
+ $(LIBIDN_CFLAGS)
noinst_PROGRAMS = gen-table charset-map
@@ -173,7 +174,7 @@ install-libtool-import-lib:
uninstall-libtool-import-lib:
endif
-libgmime_3_0_la_LIBADD = $(top_builddir)/util/libutil.la $(GLIB_LIBS)
+libgmime_3_0_la_LIBADD = $(top_builddir)/util/libutil.la $(GLIB_LIBS) $(LIBIDN_LIBS)
libgmime_3_0_la_LDFLAGS = \
-version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) \
-export-dynamic $(no_undefined)
diff --git a/gmime/gmime-utils.c b/gmime/gmime-utils.c
index 39ebc1b..6dd2484 100644
--- a/gmime/gmime-utils.c
+++ b/gmime/gmime-utils.c
@@ -50,6 +50,10 @@
#include <ctype.h>
#include <errno.h>
+#ifdef LIBIDN
+#include <idna.h>
+#endif
+
#include "gmime-utils.h"
#include "gmime-common.h"
#include "gmime-internal.h"
@@ -774,6 +778,7 @@ g_mime_utils_generate_message_id (const char *fqdn)
unsigned long value;
char *name = NULL;
GString *msgid;
+ char *ascii;
int i;
if (!fqdn) {
@@ -859,7 +864,17 @@ g_mime_utils_generate_message_id (const char *fqdn)
} while (value != 0);
g_string_append_c (msgid, '@');
+
+#ifdef LIBIDN
+ if (idna_to_ascii_8z (fqdn, &ascii, 0) == IDNA_SUCCESS) {
+ g_string_append (msgid, ascii);
+ free (ascii);
+ } else {
+ g_string_append (msgid, fqdn);
+ }
+#else
g_string_append (msgid, fqdn);
+#endif
g_free (name);
diff --git a/gmime/internet-address.c b/gmime/internet-address.c
index 1dcfa7a..bbd91b6 100644
--- a/gmime/internet-address.c
+++ b/gmime/internet-address.c
@@ -24,10 +24,15 @@
#endif
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
+#ifdef LIBIDN
+#include <idna.h>
+#endif
+
#include "internet-address.h"
#include "gmime-table-private.h"
#include "gmime-parse-utils.h"
@@ -91,6 +96,7 @@ enum {
INTERNET_ADDRESS_FOLD = 1 << 1,
};
+static gboolean addrspec_parse (const char **in, const char *sentinels, char **addrspec, int *at);
static void internet_address_class_init (InternetAddressClass *klass);
static void internet_address_init (InternetAddress *ia, InternetAddressClass *klass);
@@ -331,7 +337,9 @@ internet_address_mailbox_class_init (InternetAddressMailboxClass *klass)
static void
internet_address_mailbox_init (InternetAddressMailbox *mailbox, InternetAddressMailboxClass *klass)
{
+ mailbox->idn_addr = NULL;
mailbox->addr = NULL;
+ mailbox->at = -1;
}
static void
@@ -339,11 +347,26 @@ internet_address_mailbox_finalize (GObject *object)
{
InternetAddressMailbox *mailbox = (InternetAddressMailbox *) object;
+ g_free (mailbox->idn_addr);
g_free (mailbox->addr);
G_OBJECT_CLASS (mailbox_parent_class)->finalize (object);
}
+static InternetAddress *
+_internet_address_mailbox_new (const char *name, const char *addr, int at)
+{
+ InternetAddressMailbox *mailbox;
+
+ mailbox = g_object_new (INTERNET_ADDRESS_TYPE_MAILBOX, NULL);
+ mailbox->addr = g_strdup (addr);
+ mailbox->at = at;
+
+ _internet_address_set_name ((InternetAddress *) mailbox, name);
+
+ return (InternetAddress *) mailbox;
+}
+
/**
* internet_address_mailbox_new:
@@ -361,11 +384,14 @@ InternetAddress *
internet_address_mailbox_new (const char *name, const char *addr)
{
InternetAddressMailbox *mailbox;
+ const char *inptr = addr;
g_return_val_if_fail (addr != NULL, NULL);
mailbox = g_object_new (INTERNET_ADDRESS_TYPE_MAILBOX, NULL);
- mailbox->addr = g_strdup (addr);
+
+ if (!addrspec_parse (&inptr, "", &mailbox->addr, &mailbox->at))
+ mailbox->addr = g_strdup (addr);
_internet_address_set_name ((InternetAddress *) mailbox, name);
@@ -383,13 +409,20 @@ internet_address_mailbox_new (const char *name, const char *addr)
void
internet_address_mailbox_set_addr (InternetAddressMailbox *mailbox, const char *addr)
{
+ const char *inptr = addr;
+
g_return_if_fail (INTERNET_ADDRESS_IS_MAILBOX (mailbox));
if (mailbox->addr == addr)
return;
+ g_free (mailbox->idn_addr);
+ mailbox->idn_addr = NULL;
+
g_free (mailbox->addr);
- mailbox->addr = g_strdup (addr);
+
+ if (!addrspec_parse (&inptr, "", &mailbox->addr, &mailbox->at))
+ mailbox->addr = g_strdup (addr);
g_mime_event_emit (((InternetAddress *) mailbox)->changed, NULL);
}
@@ -401,7 +434,7 @@ internet_address_mailbox_set_addr (InternetAddressMailbox *mailbox, const char *
*
* Gets the addr-spec of the internet address mailbox.
*
- * Returns: the address of the mailbox.
+ * Returns: the addr-spec string.
**/
const char *
internet_address_mailbox_get_addr (InternetAddressMailbox *mailbox)
@@ -412,6 +445,43 @@ internet_address_mailbox_get_addr (InternetAddressMailbox *mailbox)
}
+/**
+ * internet_address_mailbox_get_idn_addr:
+ * @mailbox: a #InternetAddressMailbox
+ *
+ * Gets the IDN ascii-encoded addr-spec.
+ *
+ * Returns: the encoded addr-spec string.
+ **/
+const char *
+internet_address_mailbox_get_idn_addr (InternetAddressMailbox *mailbox)
+{
+ GString *encoded;
+ char *ascii;
+
+ g_return_val_if_fail (INTERNET_ADDRESS_IS_MAILBOX (mailbox), NULL);
+
+#ifdef LIBIDN
+ if (!mailbox->idn_addr && mailbox->at > 0) {
+ encoded = g_string_new ("");
+ g_string_append_len (encoded, mailbox->addr, mailbox->at + 1);
+ if (idna_to_ascii_8z (mailbox->addr + mailbox->at + 1, &ascii, 0) == IDNA_SUCCESS) {
+ g_string_append (encoded, ascii);
+ free (ascii);
+ } else {
+ g_string_append (encoded, mailbox->addr + mailbox->at + 1);
+ }
+
+ mailbox->idn_addr = g_string_free (encoded, FALSE);
+ }
+
+ return mailbox->idn_addr ? mailbox->idn_addr : mailbox->addr;
+#else
+ return mailbox->addr;
+#endif
+}
+
+
static void internet_address_group_class_init (InternetAddressGroupClass *klass);
static void internet_address_group_init (InternetAddressGroup *group, InternetAddressGroupClass *klass);
static void internet_address_group_finalize (GObject *object);
@@ -1124,12 +1194,14 @@ mailbox_to_string (InternetAddress *ia, GMimeFormatOptions *options, guint32 fla
InternetAddressMailbox *mailbox = (InternetAddressMailbox *) ia;
gboolean encode = flags & INTERNET_ADDRESS_ENCODE;
gboolean fold = flags & INTERNET_ADDRESS_FOLD;
- const char *newline;
+ const char *newline, *addr;
char *name;
size_t len;
newline = g_mime_format_options_get_newline (options);
+ addr = internet_address_mailbox_get_idn_addr (mailbox);
+
if (ia->name && *ia->name) {
name = encoded_name (options, ia->name, encode, ia->charset);
len = strlen (name);
@@ -1157,7 +1229,7 @@ mailbox_to_string (InternetAddress *ia, GMimeFormatOptions *options, guint32 fla
g_free (name);
- len = strlen (mailbox->addr);
+ len = strlen (addr);
if (fold && (*linelen + len + 3) >= GMIME_FOLD_LEN) {
g_string_append (str, newline);
@@ -1168,18 +1240,18 @@ mailbox_to_string (InternetAddress *ia, GMimeFormatOptions *options, guint32 fla
*linelen += 2;
}
- g_string_append_len (str, mailbox->addr, len);
+ g_string_append_len (str, addr, len);
g_string_append_c (str, '>');
*linelen += len + 1;
} else {
- len = strlen (mailbox->addr);
+ len = strlen (addr);
if (fold && (*linelen + len) > GMIME_FOLD_LEN) {
linewrap (str, newline);
*linelen = 1;
}
- g_string_append_len (str, mailbox->addr, len);
+ g_string_append_len (str, addr, len);
*linelen += len;
}
}
@@ -1429,6 +1501,7 @@ dotatom_parse (GString *str, const char **in, const char *sentinels)
const char *atom, *comment;
const char *inptr = *in;
const char *start = *in;
+ GString *domain = str;
do {
if (!is_atom (*inptr))
@@ -1441,7 +1514,15 @@ dotatom_parse (GString *str, const char **in, const char *sentinels)
if (!g_utf8_validate (atom, (size_t) (inptr - atom), NULL))
goto error;
- g_string_append_len (str, atom, (size_t) (inptr - atom));
+#if LIBIDN
+ if (domain == str && !strncmp (atom, "xn--", 4)) {
+ /* from here on out, we'll use a temp domain buffer so that
+ * we can decode it once we're done parsing it */
+ domain = g_string_new ("");
+ }
+#endif
+
+ g_string_append_len (domain, atom, (size_t) (inptr - atom));
comment = inptr;
if (!skip_cfws (&inptr))
@@ -1462,14 +1543,36 @@ dotatom_parse (GString *str, const char **in, const char *sentinels)
if (*inptr == '\0' || strchr (sentinels, *inptr))
break;
- g_string_append_c (str, '.');
+ g_string_append_c (domain, '.');
} while (TRUE);
+#ifdef LIBIDN
+ if (domain != str) {
+ char *unicode;
+
+ if (idna_to_unicode_8z8z (domain->str, &unicode, 0) == IDNA_SUCCESS) {
+ g_string_append (str, unicode);
+ free (unicode);
+ } else {
+ g_string_append_len (str, domain->str, domain->len);
+ }
+
+ g_string_free (domain, TRUE);
+ }
+#endif
+
*in = inptr;
return TRUE;
error:
+#ifdef LIBIDN
+ if (domain != str) {
+ g_string_append_len (str, domain->str, domain->len);
+ g_string_free (domain, TRUE);
+ }
+#endif
+
*in = inptr;
return FALSE;
@@ -1522,11 +1625,12 @@ domain_parse (GString *str, const char **in, const char *sentinels)
}
static gboolean
-addrspec_parse (const char **in, const char *sentinels, char **addrspec)
+addrspec_parse (const char **in, const char *sentinels, char **addrspec, int *at)
{
const char *inptr = *in;
const char *start = *in;
GString *str;
+ guint domain;
str = g_string_new ("");
@@ -1536,12 +1640,14 @@ addrspec_parse (const char **in, const char *sentinels, char **addrspec)
if (*inptr == '\0' || strchr (sentinels, *inptr)) {
*addrspec = g_string_free (str, FALSE);
*in = inptr;
+ *at = -1;
return TRUE;
}
if (*inptr != '@')
goto error;
+ *at = str->len;
g_string_append_c (str, *inptr++);
if (*inptr == '\0')
@@ -1565,6 +1671,7 @@ addrspec_parse (const char **in, const char *sentinels, char **addrspec)
g_string_free (str, TRUE);
*addrspec = NULL;
*in = inptr;
+ *at = -1;
return FALSE;
}
@@ -1576,6 +1683,7 @@ mailbox_parse (GMimeParserOptions *options, const char **in, const char *name, I
GMimeRfcComplianceMode mode = g_mime_parser_options_get_address_compliance_mode (options);
const char *inptr = *in;
char *addrspec = NULL;
+ int at;
/* skip over the '<' */
inptr++;
@@ -1609,12 +1717,12 @@ mailbox_parse (GMimeParserOptions *options, const char **in, const char *name, I
goto error;
}
- // Note: The only syntactically correct sentinel token here is the '>', but alas... to deal with the
first example
- // in section 7.1.5 of rfc7103, we need to at least handle ',' as a sentinel and might as well handle
';' as well
- // in case the mailbox is within a group address.
+ // Note: The only syntactically correct sentinel token here is the '>', but alas... to deal with the
first
+ // example in section 7.1.5 of rfc7103, we need to at least handle ',' as a sentinel and might as
well handle
+ // ';' as well in case the mailbox is within a group address.
//
// Example: <third example net, fourth example net>
- if (!addrspec_parse (&inptr, COMMA_GREATER_THAN_OR_SEMICOLON, &addrspec))
+ if (!addrspec_parse (&inptr, COMMA_GREATER_THAN_OR_SEMICOLON, &addrspec, &at))
goto error;
if (!skip_cfws (&inptr))
@@ -1638,7 +1746,7 @@ mailbox_parse (GMimeParserOptions *options, const char **in, const char *name, I
}
}
- *address = internet_address_mailbox_new (name, addrspec);
+ *address = _internet_address_mailbox_new (name, addrspec, at);
g_free (addrspec);
*in = inptr;
@@ -1758,6 +1866,7 @@ address_parse (GMimeParserOptions *options, AddressParserFlags flags, const char
char sentinel = *inptr != '\0' ? *inptr : ',';
char sentinels[2] = { sentinel, 0 };
char *name, *addrspec;
+ int at;
/* rewind back to the beginning of the local-part */
inptr = start;
@@ -1765,7 +1874,7 @@ address_parse (GMimeParserOptions *options, AddressParserFlags flags, const char
if (!(flags & ALLOW_MAILBOX))
goto error;
- if (!addrspec_parse (&inptr, sentinels, &addrspec))
+ if (!addrspec_parse (&inptr, sentinels, &addrspec, &at))
goto error;
skip_lwsp (&inptr);
@@ -1791,7 +1900,7 @@ address_parse (GMimeParserOptions *options, AddressParserFlags flags, const char
inptr++;
}
- *address = internet_address_mailbox_new (name, addrspec);
+ *address = _internet_address_mailbox_new (name, addrspec, at);
g_free (addrspec);
g_free (name);
*in = inptr;
@@ -1837,11 +1946,12 @@ address_parse (GMimeParserOptions *options, AddressParserFlags flags, const char
/* we're either in the middle of an addr-spec token or we completely gobbled up
* an addr-spec w/o a domain */
char *name, *addrspec;
+ int at;
/* rewind back to the beginning of the local-part */
inptr = start;
- if (!addrspec_parse (&inptr, COMMA_GREATER_THAN_OR_SEMICOLON, &addrspec))
+ if (!addrspec_parse (&inptr, COMMA_GREATER_THAN_OR_SEMICOLON, &addrspec, &at))
goto error;
skip_lwsp (&inptr);
@@ -1867,7 +1977,7 @@ address_parse (GMimeParserOptions *options, AddressParserFlags flags, const char
}
if (*inptr == '\0') {
- *address = internet_address_mailbox_new (name, addrspec);
+ *address = _internet_address_mailbox_new (name, addrspec, at);
g_free (addrspec);
g_free (name);
*in = inptr;
@@ -1903,7 +2013,7 @@ address_parse (GMimeParserOptions *options, AddressParserFlags flags, const char
inptr++;
}
- *address = internet_address_mailbox_new (name, addrspec);
+ *address = _internet_address_mailbox_new (name, addrspec, at);
g_free (addrspec);
g_free (name);
*in = inptr;
diff --git a/gmime/internet-address.h b/gmime/internet-address.h
index f2bebef..44ad049 100644
--- a/gmime/internet-address.h
+++ b/gmime/internet-address.h
@@ -110,14 +110,18 @@ char *internet_address_to_string (InternetAddress *ia, GMimeFormatOptions *optio
/**
* InternetAddressMailbox:
* @parent_object: parent #InternetAddress
- * @addr: address string
+ * @idn_addr: the ascii-encoded version of @addr
+ * @addr: the address string
+ * @at: the index of the '@' character
*
* An RFC 2822 Mailbox address.
**/
struct _InternetAddressMailbox {
InternetAddress parent_object;
+ char *idn_addr;
char *addr;
+ int at;
};
struct _InternetAddressMailboxClass {
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]