diff options
author | Thomas Roessler <roessler@does-not-exist.org> | 2003-03-03 14:01:06 +0000 |
---|---|---|
committer | Thomas Roessler <roessler@does-not-exist.org> | 2003-03-03 14:01:06 +0000 |
commit | d044f05207a3eea8124b2029c4b04826b9f14003 (patch) | |
tree | 096b05db63f07f52223c1215e6531dce5a9e20e8 /mutt_idna.c | |
parent | e8b857a970452e6301b3e937002b623f2684334e (diff) |
IDN support for e-mail messages. Things should work automagically
once you have the GNU IDN library available from
ftp://alpha.gnu.org/pub/gnu/libidn/ installed. For IDN's which
can't be losslessly recoded to your local character set, mutt should
automatically fall back to using the ASCII representation. There's
probably a considerable number of bugs in this, and the code may, at
this point, not even compile on machines without libidn. Will start
working on that ASAP.
Diffstat (limited to 'mutt_idna.c')
-rw-r--r-- | mutt_idna.c | 253 |
1 files changed, 253 insertions, 0 deletions
diff --git a/mutt_idna.c b/mutt_idna.c new file mode 100644 index 00000000..2d3f4c4f --- /dev/null +++ b/mutt_idna.c @@ -0,0 +1,253 @@ +/* + * Copyright (C) 2003 Thomas Roessler <roessler@does-not-exist.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ + +#include "config.h" +#include "mutt.h" +#include "charset.h" +#include "mutt_idna.h" + +/* The low-level interface we use. */ + +#ifndef HAVE_LIBIDN + +int mutt_idna_to_local (const char *in, char **out, int flags) +{ + *out = safe_strdup (in); + return 1; +} + +int mutt_local_to_idna (const char *in, char **out) +{ + *out = safe_strdup (in); + return 0; +} + +#else + +int mutt_idna_to_local (const char *in, char **out, int flags) +{ + *out = NULL; + + /* Is this the right function? Interesting effects with some bad identifiers! */ + if (idna_to_unicode_utf8_from_utf8 (in, out, 0, 1) != IDNA_SUCCESS) + goto notrans; + if (mutt_convert_string (out, "utf-8", Charset, M_ICONV_HOOK_TO) == -1) + goto notrans; + + /* + * make sure that we can convert back and come out with the same + * domain name. */ + + if ((flags & MI_MAY_BE_IRREVERSIBLE) == 0) + { + int irrev = 0; + char *t2 = NULL; + char *tmp = safe_strdup (*out); + if (mutt_convert_string (&tmp, Charset, "utf-8", M_ICONV_HOOK_FROM) == -1) + irrev = 1; + if (!irrev && idna_to_ascii_from_utf8 (tmp, &t2, 0, 1) != IDNA_SUCCESS) + irrev = 1; + if (!irrev && ascii_strcasecmp (t2, in)) + { + dprint (1, (debugfile, "mutt_idna_to_local: Not reversible. in = '%s', t2 = '%s'.\n", + in, t2)); + irrev = 1; + } + + FREE (&t2); + FREE (&tmp); + + if (irrev) + goto notrans; + } + + return 0; + + notrans: + FREE (out); + *out = safe_strdup (in); + return 1; +} + +int mutt_local_to_idna (const char *in, char **out) +{ + int rv = 0; + char *tmp = safe_strdup (in); + *out = NULL; + + if (mutt_convert_string (&tmp, Charset, "utf-8", M_ICONV_HOOK_FROM) == -1) + rv = -1; + if (!rv && idna_to_ascii_from_utf8 (tmp, out, 0, 1) != IDNA_SUCCESS) + rv = -2; + + FREE (&tmp); + if (rv < 0) + { + FREE (out); + *out = safe_strdup (in); + } + return rv; +} + +#endif + + +/* higher level functions */ + +static int mbox_to_udomain (const char *mbx, char **user, char **domain) +{ + char *scratch = safe_strdup (mbx); + *user = NULL; + *domain = NULL; + + if ((*domain = strchr (scratch, '@')) == NULL) + return -1; + + **domain = '\0'; + *domain = safe_strdup (*domain + 1); + *user = scratch; + return 0; +} + +int mutt_addrlist_to_idna (ADDRESS *a, char **err) +{ + char *user = NULL, *domain = NULL; + char *tmp = NULL; + int e = 0; + + if (err) + *err = NULL; + + for (; a; a = a->next) + { + if (!a->mailbox) + continue; + if (mbox_to_udomain (a->mailbox, &user, &domain) == -1) + continue; + + if (mutt_local_to_idna (domain, &tmp) < 0) + { + e = 1; + if (err) + *err = safe_strdup (domain); + } + else + { + safe_realloc ((void **) &a->mailbox, mutt_strlen (user) + mutt_strlen (tmp) + 2); + sprintf (a->mailbox, "%s@%s", NONULL(user), NONULL(tmp)); /* __SPRINTF_CHECKED__ */ + } + + FREE (&domain); + FREE (&user); + FREE (&tmp); + + if (e) + return -1; + } + + return 0; +} + +int mutt_addrlist_to_local (ADDRESS *a) +{ + char *user, *domain; + char *tmp = NULL; + + for (; a; a = a->next) + { + if (!a->mailbox) + continue; + if (mbox_to_udomain (a->mailbox, &user, &domain) == -1) + continue; + + if (mutt_idna_to_local (domain, &tmp, 0) == 0) + { + safe_realloc ((void **) &a->mailbox, mutt_strlen (user) + mutt_strlen (tmp) + 2); + sprintf (a->mailbox, "%s@%s", NONULL (user), NONULL (tmp)); /* __SPRINTF_CHECKED__ */ + } + + FREE (&domain); + FREE (&user); + FREE (&tmp); + } + + return 0; +} + +/* convert just for displaying purposes */ +const char *mutt_addr_for_display (ADDRESS *a) +{ + static char *buff = NULL; + char *tmp = NULL; + char *domain, *user; + + FREE (&buff); + + if (mbox_to_udomain (a->mailbox, &user, &domain) != 0) + return a->mailbox; + if (mutt_idna_to_local (domain, &tmp, MI_MAY_BE_IRREVERSIBLE) != 0) + { + FREE (&tmp); + return a->mailbox; + } + + safe_realloc ((void **) &buff, mutt_strlen (tmp) + mutt_strlen (user) + 2); + sprintf (buff, "%s@%s", NONULL(user), NONULL(tmp)); /* __SPRINTF_CHECKED__ */ + FREE (&tmp); + return buff; +} + +/* Convert an ENVELOPE structure */ + +void mutt_env_to_local (ENVELOPE *e) +{ + mutt_addrlist_to_local (e->return_path); + mutt_addrlist_to_local (e->from); + mutt_addrlist_to_local (e->to); + mutt_addrlist_to_local (e->cc); + mutt_addrlist_to_local (e->bcc); + mutt_addrlist_to_local (e->reply_to); + mutt_addrlist_to_local (e->mail_followup_to); +} + +/* + * XXX -- this macro produces warnings, but yields the right kind + * of code when preprocessed. How to fix this *without* typing the same + * code all over the place? + */ + +#define H_TO_IDNA(a) \ + if (mutt_addrlist_to_idna (env->##a, err) && !e) \ + { \ + if (tag) *tag = #a; e = 1; err = NULL; \ + } + +int mutt_env_to_idna (ENVELOPE *env, char **tag, char **err) +{ + int e = 0; + H_TO_IDNA(return_path); + H_TO_IDNA(from); + H_TO_IDNA(to); + H_TO_IDNA(cc); + H_TO_IDNA(bcc); + H_TO_IDNA(reply_to); + H_TO_IDNA(mail_followup_to); + return e; +} + +#undef H_TO_IDNA |