From: Thomas Roessler Date: Mon, 3 Mar 2003 14:01:06 +0000 (+0000) Subject: IDN support for e-mail messages. Things should work automagically X-Git-Tag: mutt-1-5-4-rel~37 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=d044f05207a3eea8124b2029c4b04826b9f14003;p=mutt 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. --- diff --git a/Makefile.am b/Makefile.am index cf172649..a1bec37f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -28,7 +28,7 @@ mutt_SOURCES = $(BUILT_SOURCES) \ score.c send.c sendlib.c signal.c sort.c \ status.c system.c thread.c charset.c history.c lib.c \ muttlib.c editmsg.c utf8.c mbyte.c wcwidth.c \ - url.c ascii.c + url.c ascii.c mutt_idna.c mutt_LDADD = @MUTT_LIB_OBJECTS@ @LIBOBJS@ $(LIBIMAP) $(MUTTLIBS) \ $(INTLLIBS) $(LIBICONV) @@ -61,7 +61,8 @@ CPPFLAGS=@CPPFLAGS@ -I$(includedir) EXTRA_mutt_SOURCES = account.c md5c.c mutt_sasl.c mutt_socket.c mutt_ssl.c \ mutt_tunnel.c pop.c pop_auth.c pop_lib.c smime.c pgp.c pgpinvoke.c pgpkey.c \ pgplib.c sha1.c pgpmicalg.c gnupgparse.c resize.c dotlock.c remailer.c \ - browser.h mbyte.h remailer.h url.h mutt_ssl_nss.c pgppacket.c + browser.h mbyte.h remailer.h url.h mutt_ssl_nss.c \ + pgppacket.c mutt_idna.h EXTRA_DIST = COPYRIGHT GPL OPS OPS.PGP OPS.CRYPT OPS.SMIME TODO \ configure acconfig.h account.h \ @@ -75,7 +76,7 @@ EXTRA_DIST = COPYRIGHT GPL OPS OPS.PGP OPS.CRYPT OPS.SMIME TODO \ mbyte.h lib.h extlib.c pgpewrap.c smime_keys.pl pgplib.h Muttrc.head Muttrc \ makedoc.c stamp-doc-rc README.SSL smime.h\ muttbug pgppacket.h depcomp ascii.h BEWARE PATCHES patchlist.sh \ - ChangeLog.old mkchangelog.sh cvslog2changelog.pl + ChangeLog.old mkchangelog.sh cvslog2changelog.pl mutt_idna.h mutt_dotlock_SOURCES = mutt_dotlock.c mutt_dotlock_LDADD = @LIBOBJS@ diff --git a/addrbook.c b/addrbook.c index 157a6f69..627c4704 100644 --- a/addrbook.c +++ b/addrbook.c @@ -55,7 +55,7 @@ alias_format_str (char *dest, size_t destlen, char op, const char *src, break; case 'r': adr[0] = 0; - rfc822_write_address (adr, sizeof (adr), alias->addr); + rfc822_write_address (adr, sizeof (adr), alias->addr, 1); snprintf (tmp, sizeof (tmp), "%%%ss", fmt); snprintf (dest, destlen, tmp, adr); break; @@ -222,13 +222,13 @@ new_aliases: { if (AliasTable[i]->tagged) { - rfc822_write_address (buf, buflen, AliasTable[i]->addr); + rfc822_write_address (buf, buflen, AliasTable[i]->addr, 0); t = -1; } } if(t != -1) - rfc822_write_address (buf, buflen, AliasTable[t]->addr); + rfc822_write_address (buf, buflen, AliasTable[t]->addr, 0); mutt_menuDestroy (&menu); FREE (&AliasTable); diff --git a/alias.c b/alias.c index fdb866d2..b605e20b 100644 --- a/alias.c +++ b/alias.c @@ -19,6 +19,7 @@ #include "mutt.h" #include "mutt_regex.h" #include "mutt_curses.h" +#include "mutt_idna.h" #include #include @@ -210,6 +211,7 @@ void mutt_create_alias (ENVELOPE *cur, ADDRESS *iadr) { ALIAS *new, *t; char buf[LONG_STRING], prompt[SHORT_STRING], *pc; + char *err = NULL; char fixed[LONG_STRING]; FILE *rc; ADDRESS *adr = NULL; @@ -278,6 +280,12 @@ retry_name: if((new->addr = rfc822_parse_adrlist (new->addr, buf)) == NULL) BEEP (); + if (mutt_addrlist_to_idna (new->addr, &err)) + { + mutt_error (_("Error: '%s' is a bad IDN."), err); + mutt_sleep (2); + continue; + } } while(new->addr == NULL); @@ -294,7 +302,7 @@ retry_name: new->addr->personal = safe_strdup (buf); buf[0] = 0; - rfc822_write_address (buf, sizeof (buf), new->addr); + rfc822_write_address (buf, sizeof (buf), new->addr, 1); snprintf (prompt, sizeof (prompt), _("[%s = %s] Accept?"), new->name, buf); if (mutt_yesorno (prompt, M_YES) != M_YES) { @@ -323,7 +331,7 @@ retry_name: strfcpy (buf, new->name, sizeof (buf)); fprintf (rc, "alias %s ", buf); buf[0] = 0; - rfc822_write_address (buf, sizeof (buf), new->addr); + rfc822_write_address (buf, sizeof (buf), new->addr, 0); write_safe_address (rc, buf); fputc ('\n', rc); fclose (rc); diff --git a/charset.h b/charset.h index 993f9973..cfc2ac53 100644 --- a/charset.h +++ b/charset.h @@ -49,8 +49,6 @@ void fgetconv_close (FGETCONV **); void mutt_set_langinfo_charset (void); #define M_ICONV_HOOK_FROM 1 -#if 0 #define M_ICONV_HOOK_TO 2 -#endif #endif /* _CHARSET_H */ diff --git a/commands.c b/commands.c index cd177f9f..ed1e1ce1 100644 --- a/commands.c +++ b/commands.c @@ -27,6 +27,7 @@ #include "mx.h" #include "pager.h" #include "mutt_crypt.h" +#include "mutt_idna.h" #include #include #include @@ -227,6 +228,7 @@ void ci_bounce_message (HEADER *h, int *redraw) char prompt[SHORT_STRING]; char buf[HUGE_STRING] = { 0 }; ADDRESS *adr = NULL; + char *err = NULL; int rc; if(h) @@ -253,8 +255,16 @@ void ci_bounce_message (HEADER *h, int *redraw) adr = mutt_expand_aliases (adr); + if (mutt_addrlist_to_idna (adr, &err) < 0) + { + mutt_error (_("Bad IDN: '%s'"), err); + FREE (&err); + rfc822_free_address (&adr); + return; + } + buf[0] = 0; - rfc822_write_address (buf, sizeof (buf), adr); + rfc822_write_address (buf, sizeof (buf), adr, 1); #define extra_space (15 + 7 + 2) snprintf (prompt, sizeof (prompt), @@ -590,9 +600,16 @@ void mutt_display_address (ENVELOPE *env) adr = mutt_get_address (env, &pfx); if (!adr) return; - + + /* + * Note: We don't convert IDNA to local representation this time. + * That is intentional, so the user has an opportunity to copy & + * paste the on-the-wire form of the address to other, IDN-unable + * software. + */ + buf[0] = 0; - rfc822_write_address (buf, sizeof (buf), adr); + rfc822_write_address (buf, sizeof (buf), adr, 0); mutt_message ("%s: %s", pfx, buf); } diff --git a/compose.c b/compose.c index 28d87a9c..a822824e 100644 --- a/compose.c +++ b/compose.c @@ -18,6 +18,7 @@ #include "mutt.h" #include "mutt_curses.h" +#include "mutt_idna.h" #include "mutt_menu.h" #include "rfc1524.h" #include "mime.h" @@ -363,7 +364,7 @@ static void draw_envelope_addr (int line, ADDRESS *addr) char buf[STRING]; buf[0] = 0; - rfc822_write_address (buf, sizeof (buf), addr); + rfc822_write_address (buf, sizeof (buf), addr, 1); mvprintw (line, 0, TITLE_FMT, Prompts[line - 1]); mutt_paddstr (W, buf); } @@ -399,8 +400,10 @@ static void draw_envelope (HEADER *msg, char *fcc) static int edit_address_list (int line, ADDRESS **addr) { char buf[HUGE_STRING] = ""; /* needs to be large for alias expansion */ - - rfc822_write_address (buf, sizeof (buf), *addr); + char *err = NULL; + + mutt_addrlist_to_local (*addr); + rfc822_write_address (buf, sizeof (buf), *addr, 0); if (mutt_get_field (Prompts[line - 1], buf, sizeof (buf), M_ALIAS) == 0) { rfc822_free_address (addr); @@ -414,12 +417,19 @@ static int edit_address_list (int line, ADDRESS **addr) return (REDRAW_FULL); } + if (mutt_addrlist_to_idna (*addr, &err) != 0) + { + mutt_error (_("Warning: '%s' is a bad IDN."), err); + mutt_refresh(); + FREE (&err); + } + /* redraw the expanded list so the user can see the result */ buf[0] = 0; - rfc822_write_address (buf, sizeof (buf), *addr); + rfc822_write_address (buf, sizeof (buf), *addr, 1); move (line, HDR_XOFFSET); mutt_paddstr (W, buf); - + return 0; } @@ -692,8 +702,15 @@ int mutt_compose_menu (HEADER *msg, /* structure for new message */ if (op == OP_COMPOSE_EDIT_HEADERS || (op == OP_COMPOSE_EDIT_MESSAGE && option (OPTEDITHDRS))) { + char *tag = NULL, *err = NULL; + mutt_env_to_local (msg->env); mutt_edit_headers (NONULL (Editor), msg->content->filename, msg, fcc, fcclen); + if (mutt_env_to_idna (msg->env, &tag, &err)) + { + mutt_error (_("Bad IDN in \"%s\": '%s'"), tag, err); + FREE (&err); + } } else { diff --git a/configure.in b/configure.in index 89988923..1d696ce6 100644 --- a/configure.in +++ b/configure.in @@ -677,6 +677,19 @@ AC_ARG_WITH(sasl2, [ --with-sasl2[=PFX] Use Cyrus SASL library version ]) AM_CONDITIONAL(USE_SASL, test x$need_sasl = xyes) +AC_ARG_WITH(idn, [ --with-idn=[PFX] Use GNU libidn for domain names], + [ + if test "$with_idn" != "no" ; then + if test "$with_idn" != "yes" ; then + CPPFLAGS="$CPPFLAGS -I$with_idn/include" + LDFLAGS="$LDFLAGS -L$with_idn/lib" + fi + fi + ] +) + +AC_CHECK_LIB(idn, idna_to_ascii_from_utf8) + if test "$need_md5" = "yes" then MUTT_LIB_OBJECTS="$MUTT_LIB_OBJECTS md5c.o" diff --git a/copy.c b/copy.c index 1f24d846..fc148c31 100644 --- a/copy.c +++ b/copy.c @@ -23,12 +23,14 @@ #include "rfc2047.h" #include "mime.h" #include "mutt_crypt.h" +#include "mutt_idna.h" #include #include #include #include /* needed for SEEK_SET under SunOS 4.1.4 */ +static int address_header_decode (char **str); static int copy_delete_attach (BODY *b, FILE *fpin, FILE *fpout, char *date); /* Ok, the only reason for not merging this with mutt_copy_header() @@ -47,6 +49,7 @@ mutt_copy_hdr (FILE *in, FILE *out, long off_start, long off_end, int flags, char **headers; int hdr_count; int x; + char *this_one = NULL; int error; if (ftell (in) != off_start) @@ -134,6 +137,28 @@ mutt_copy_hdr (FILE *in, FILE *out, long off_start, long off_end, int flags, /* Is it the begining of a header? */ if (nl && buf[0] != ' ' && buf[0] != '\t') { + /* Do we have anything pending? */ + if (this_one) + { + if (flags & CH_DECODE) + { + if (!address_header_decode (&this_one)) + rfc2047_decode (&this_one); + } + + if (!headers[x]) + headers[x] = this_one; + else + { + safe_realloc ((void **) &headers[x], mutt_strlen (headers[x]) + + mutt_strlen (this_one) + sizeof (char)); + strcat (headers[x], this_one); /* __STRCAT_CHECKED__ */ + FREE (&this_one); + } + + this_one = NULL; + } + ignore = 1; this_is_from = 0; if (!from && mutt_strncmp ("From ", buf, 5) == 0) @@ -181,32 +206,55 @@ mutt_copy_hdr (FILE *in, FILE *out, long off_start, long off_end, int flags, } } } - + ignore = 0; } /* If beginning of header */ if (!ignore) { dprint (2, (debugfile, "Reorder: x = %d; hdr_count = %d\n", x, hdr_count)); - /* Save the header in headers[x] */ - if (!headers[x]) - headers[x] = safe_strdup (buf); + if (!this_one) + this_one = safe_strdup (buf); else { - safe_realloc ((void **) &headers[x], - mutt_strlen (headers[x]) + mutt_strlen (buf) + sizeof (char)); - strcat (headers[x], buf); /* __STRCAT_CHECKED__ */ + safe_realloc ((void **) &this_one, + mutt_strlen (this_one) + mutt_strlen (buf) + sizeof (char)); + strcat (this_one, buf); /* __STRCAT_CHECKED__ */ } } } /* while (ftell (in) < off_end) */ + /* Do we have anything pending? -- XXX, same code as in above in the loop. */ + if (this_one) + { + if (flags & CH_DECODE) + { + if (!address_header_decode (&this_one)) + rfc2047_decode (&this_one); + } + + if (!headers[x]) + headers[x] = this_one; + else + { + safe_realloc ((void **) &headers[x], mutt_strlen (headers[x]) + + mutt_strlen (this_one) + sizeof (char)); + strcat (headers[x], this_one); /* __STRCAT_CHECKED__ */ + FREE (&this_one); + } + + this_one = NULL; + } + /* Now output the headers in order */ for (x = 0; x < hdr_count; x++) { if (headers[x]) { +#if 0 if (flags & CH_DECODE) rfc2047_decode (&headers[x]); +#endif /* We couldn't do the prefixing when reading because RFC 2047 * decoding may have concatenated lines. @@ -726,3 +774,87 @@ static int copy_delete_attach (BODY *b, FILE *fpin, FILE *fpout, char *date) return 0; } + +static int address_header_decode (char **h) +{ + char *s = *h; + int l, ll; + + ADDRESS *a = NULL; + + switch (tolower (*s)) + { + case 'r': + { + if (ascii_strncasecmp (s, "return-path:", 12) == 0) + { + l = 12; + break; + } + else if (ascii_strncasecmp (s, "reply-to:", 9) == 0) + { + l = 9; + break; + } + return 0; + } + case 'f': + { + if (ascii_strncasecmp (s, "from:", 5)) + return 0; + l = 5; + break; + } + case 'c': + { + if (ascii_strncasecmp (s, "to:", 3)) + return 0; + l = 3; + break; + + } + case 'b': + { + if (ascii_strncasecmp (s, "bcc:", 4)) + return 0; + l = 4; + break; + } + case 's': + { + if (ascii_strncasecmp (s, "sender:", 7)) + return 0; + l = 7; + break; + } + case 'm': + { + if (ascii_strncasecmp (s, "mail-followup-to:", 17)) + return 0; + l = 17; + break; + } + default: return 0; + } + + if ((a = rfc822_parse_adrlist (a, s + l + 1)) == NULL) + return 0; + + mutt_addrlist_to_local (a); + rfc2047_decode_adrlist (a); + + ll = mutt_strlen (s) * 6 + 3; /* XXX -- should be safe */ + *h = safe_calloc (1, ll); + + strncpy (*h, s, l); + strncat (*h, " ", ll); + rfc822_write_address (*h + l + 1, ll - l - 1, a, 0); + rfc822_free_address (&a); + + strncat (*h, "\n", ll); + + safe_realloc ((void **) h, mutt_strlen (*h) + 1); + + FREE (&s); + return 1; +} diff --git a/edit.c b/edit.c index 37684939..77472910 100644 --- a/edit.c +++ b/edit.c @@ -20,6 +20,7 @@ #include "mutt.h" #include "mutt_curses.h" +#include "mutt_idna.h" #include #include @@ -192,7 +193,7 @@ static void be_print_header (ENVELOPE *env) { addstr ("To: "); tmp[0] = 0; - rfc822_write_address (tmp, sizeof (tmp), env->to); + rfc822_write_address (tmp, sizeof (tmp), env->to, 1); addstr (tmp); addch ('\n'); } @@ -200,7 +201,7 @@ static void be_print_header (ENVELOPE *env) { addstr ("Cc: "); tmp[0] = 0; - rfc822_write_address (tmp, sizeof (tmp), env->cc); + rfc822_write_address (tmp, sizeof (tmp), env->cc, 1); addstr (tmp); addch ('\n'); } @@ -208,7 +209,7 @@ static void be_print_header (ENVELOPE *env) { addstr ("Bcc: "); tmp[0] = 0; - rfc822_write_address (tmp, sizeof (tmp), env->bcc); + rfc822_write_address (tmp, sizeof (tmp), env->bcc, 1); addstr (tmp); addch ('\n'); } @@ -232,7 +233,8 @@ static void be_edit_header (ENVELOPE *e, int force) addstr ("To: "); tmp[0] = 0; - rfc822_write_address (tmp, sizeof (tmp), e->to); + mutt_addrlist_to_local (e->to); + rfc822_write_address (tmp, sizeof (tmp), e->to, 0); if (!e->to || force) { if (mutt_enter_string (tmp, sizeof (tmp), LINES-1, 4, 0) == 0) @@ -240,13 +242,15 @@ static void be_edit_header (ENVELOPE *e, int force) rfc822_free_address (&e->to); e->to = mutt_parse_adrlist (e->to, tmp); e->to = mutt_expand_aliases (e->to); + mutt_addrlist_to_idna (e->to, NULL); /* XXX - IDNA error reporting? */ tmp[0] = 0; - rfc822_write_address (tmp, sizeof (tmp), e->to); + rfc822_write_address (tmp, sizeof (tmp), e->to, 1); mvaddstr (LINES - 1, 4, tmp); } } else { + mutt_addrlist_to_idna (e->to, NULL); /* XXX - IDNA error reporting? */ addstr (tmp); } addch ('\n'); @@ -264,16 +268,20 @@ static void be_edit_header (ENVELOPE *e, int force) { addstr ("Cc: "); tmp[0] = 0; - rfc822_write_address (tmp, sizeof (tmp), e->cc); + mutt_addrlist_to_local (e->cc); + rfc822_write_address (tmp, sizeof (tmp), e->cc, 0); if (mutt_enter_string (tmp, sizeof (tmp), LINES-1, 4, 0) == 0) { rfc822_free_address (&e->cc); e->cc = mutt_parse_adrlist (e->cc, tmp); e->cc = mutt_expand_aliases (e->cc); tmp[0] = 0; - rfc822_write_address (tmp, sizeof (tmp), e->cc); + mutt_addrlist_to_idna (e->cc, NULL); + rfc822_write_address (tmp, sizeof (tmp), e->cc, 1); mvaddstr (LINES - 1, 4, tmp); } + else + mutt_addrlist_to_idna (e->cc, NULL); addch ('\n'); } @@ -281,16 +289,20 @@ static void be_edit_header (ENVELOPE *e, int force) { addstr ("Bcc: "); tmp[0] = 0; - rfc822_write_address (tmp, sizeof (tmp), e->bcc); + mutt_addrlist_to_local (e->bcc); + rfc822_write_address (tmp, sizeof (tmp), e->bcc, 0); if (mutt_enter_string (tmp, sizeof (tmp), LINES-1, 5, 0) == 0) { rfc822_free_address (&e->bcc); e->bcc = mutt_parse_adrlist (e->bcc, tmp); e->bcc = mutt_expand_aliases (e->bcc); + mutt_addrlist_to_idna (e->bcc, NULL); tmp[0] = 0; - rfc822_write_address (tmp, sizeof (tmp), e->bcc); + rfc822_write_address (tmp, sizeof (tmp), e->bcc, 1); mvaddstr (LINES - 1, 5, tmp); } + else + mutt_addrlist_to_idna (e->bcc, NULL); addch ('\n'); } } @@ -415,12 +427,18 @@ int mutt_builtin_editor (const char *path, HEADER *msg, HEADER *cur) case 'v': if (be_barf_file (path, buf, buflen) == 0) { + char *tag, *err; be_free_memory (buf, buflen); buf = NULL; bufmax = buflen = 0; if (option (OPTEDITHDRS)) + { + mutt_env_to_local (msg->env); mutt_edit_headers (NONULL(Visual), path, msg, NULL, 0); + if (mutt_env_to_idna (msg->env, &tag, &err)) + printw (_("Bad IDN in %s: '%s'\n"), tag, err); + } else mutt_edit_file (NONULL(Visual), path); diff --git a/hdrline.c b/hdrline.c index 0dd68990..7156ecf9 100644 --- a/hdrline.c +++ b/hdrline.c @@ -21,6 +21,7 @@ #include "sort.h" #include "charset.h" #include "mutt_crypt.h" +#include "mutt_idna.h" #include #include @@ -261,7 +262,7 @@ hdr_format_str (char *dest, case 'A': if(hdr->env->reply_to && hdr->env->reply_to->mailbox) { - mutt_format_s (dest, destlen, prefix, hdr->env->reply_to->mailbox); + mutt_format_s (dest, destlen, prefix, mutt_addr_for_display (hdr->env->reply_to)); break; } /* fall through if 'A' returns nothing */ @@ -269,7 +270,7 @@ hdr_format_str (char *dest, case 'a': if(hdr->env->from && hdr->env->from->mailbox) { - mutt_format_s (dest, destlen, prefix, hdr->env->from->mailbox); + mutt_format_s (dest, destlen, prefix, mutt_addr_for_display (hdr->env->from)); } else dest[0] = '\0'; @@ -429,7 +430,7 @@ hdr_format_str (char *dest, case 'f': buf2[0] = 0; - rfc822_write_address (buf2, sizeof (buf2), hdr->env->from); + rfc822_write_address (buf2, sizeof (buf2), hdr->env->from, 1); mutt_format_s (dest, destlen, prefix, buf2); break; @@ -593,7 +594,7 @@ hdr_format_str (char *dest, case 'u': if (hdr->env->from && hdr->env->from->mailbox) { - strfcpy (buf2, hdr->env->from->mailbox, sizeof (buf2)); + strfcpy (buf2, mutt_addr_for_display (hdr->env->from), sizeof (buf2)); if ((p = strpbrk (buf2, "%@"))) *p = 0; } diff --git a/headers.c b/headers.c index 7ad59fbe..a05ed63b 100644 --- a/headers.c +++ b/headers.c @@ -17,8 +17,8 @@ */ #include "mutt.h" - #include "mutt_crypt.h" +#include "mutt_idna.h" #include #include @@ -46,7 +46,8 @@ void mutt_edit_headers (const char *editor, mutt_perror (path); return; } - + + mutt_env_to_local (msg->env); mutt_write_rfc822_header (ofp, msg->env, NULL, 1, 0); fputc ('\n', ofp); /* tie off the header. */ diff --git a/init.c b/init.c index 97fa14df..557eb098 100644 --- a/init.c +++ b/init.c @@ -25,6 +25,7 @@ #include "mbyte.h" #include "charset.h" #include "mutt_crypt.h" +#include "mutt_idna.h" #if defined(USE_SSL) || defined(USE_NSS) #include "mutt_ssl.h" @@ -488,7 +489,8 @@ static int parse_alias (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER *err) { ALIAS *tmp = Aliases; ALIAS *last = NULL; - + char *estr = NULL; + if (!MoreArgs (s)) { strfcpy (err->data, _("alias: no address"), err->dsize); @@ -529,6 +531,12 @@ static int parse_alias (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER *err) last->next = tmp; else Aliases = tmp; + if (mutt_addrlist_to_idna (tmp->addr, &estr)) + { + snprintf (err->data, err->dsize, _("Warning: Bad IDN '%s' in alias '%s'.\n"), + estr, tmp->name); + return -1; + } return 0; } @@ -671,7 +679,7 @@ static void mutt_set_default (struct option_t *p) { char tmp[HUGE_STRING]; *tmp = '\0'; - rfc822_write_address (tmp, sizeof (tmp), *((ADDRESS **) p->data)); + rfc822_write_address (tmp, sizeof (tmp), *((ADDRESS **) p->data), 0); p->init = (unsigned long) safe_strdup (tmp); } break; @@ -902,7 +910,7 @@ static int parse_set (BUFFER *tmp, BUFFER *s, unsigned long data, BUFFER *err) if (DTYPE (MuttVars[idx].type) == DT_ADDR) { _tmp[0] = '\0'; - rfc822_write_address (_tmp, sizeof (_tmp), *((ADDRESS **) MuttVars[idx].data)); + rfc822_write_address (_tmp, sizeof (_tmp), *((ADDRESS **) MuttVars[idx].data), 0); val = _tmp; } else @@ -1582,7 +1590,7 @@ int mutt_var_value_complete (char *buffer, size_t len, int pos) } else if (DTYPE (MuttVars[idx].type) == DT_ADDR) { - rfc822_write_address (tmp, sizeof (tmp), *((ADDRESS **) MuttVars[idx].data)); + rfc822_write_address (tmp, sizeof (tmp), *((ADDRESS **) MuttVars[idx].data), 0); } else if (DTYPE (MuttVars[idx].type) == DT_QUAD) strfcpy (tmp, vals[quadoption (MuttVars[idx].data)], sizeof (tmp)); diff --git a/main.c b/main.c index 21cba1f0..81062f86 100644 --- a/main.c +++ b/main.c @@ -25,6 +25,7 @@ #include "mailbox.h" #include "url.h" #include "mutt_crypt.h" +#include "mutt_idna.h" #include #include @@ -38,6 +39,10 @@ #include #endif +#ifdef HAVE_LIBIDN +#include +#endif + static const char *ReachingUs = N_("\ To contact the developers, please mail to .\n\ To report a bug, please use the flea(1) utility.\n"); @@ -148,6 +153,11 @@ static void show_version (void) printf (" [using libiconv %d.%d]", _LIBICONV_VERSION >> 8, _LIBICONV_VERSION & 0xff); #endif + +#ifdef HAVE_LIBIDN + printf (" [using libidn %s (compiled with %s)]", stringprep_check_version (NULL), + STRINGPREP_VERSION); +#endif puts (_("\nCompile options:")); @@ -383,6 +393,12 @@ static void show_version (void) "-ICONV_NONTRANS " #endif +#if HAVE_LIBIDN + "+HAVE_LIBIDN " +#else + "-HAVE_LIBIDN " +#endif + #if HAVE_GETSID "+HAVE_GETSID " #else @@ -647,7 +663,11 @@ int main (int argc, char **argv) for (; alias_queries; alias_queries = alias_queries->next) { if ((a = mutt_lookup_alias (alias_queries->data))) - mutt_write_address_list (a, stdout, 0); + { + /* output in machine-readable form */ + mutt_addrlist_to_idna (a, NULL); + mutt_write_address_list (a, stdout, 0, 0); + } else { rv = 1; 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 + * + * 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 diff --git a/mutt_idna.h b/mutt_idna.h new file mode 100644 index 00000000..270c4209 --- /dev/null +++ b/mutt_idna.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2003 Thomas Roessler + * + * 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. + */ + +#ifndef _MUTT_IDNA_H +# define _MUTT_IDNA_H + +#include "config.h" +#include "rfc822.h" +#include "charset.h" + +#ifdef HAVE_LIBIDN +#include +#endif + +#define MI_MAY_BE_IRREVERSIBLE (1 << 0) + +int mutt_idna_to_local (const char *, char **, int); +int mutt_local_to_idna (const char *, char **); + +int mutt_addrlist_to_idna (ADDRESS *, char **); +int mutt_addrlist_to_local (ADDRESS *); + +void mutt_env_to_local (ENVELOPE *); +int mutt_env_to_idna (ENVELOPE *, char **, char **); + +const char *mutt_addr_for_display (ADDRESS *a); + +#endif diff --git a/pgpinvoke.c b/pgpinvoke.c index 3ea41e19..8bbc4f7e 100644 --- a/pgpinvoke.c +++ b/pgpinvoke.c @@ -35,6 +35,7 @@ #include "mutt.h" #include "mutt_curses.h" +#include "mutt_idna.h" #include "pgp.h" #include "rfc822.h" @@ -287,7 +288,8 @@ void pgp_invoke_getkeys (ADDRESS *addr) addr->personal = NULL; *tmp = '\0'; - rfc822_write_address_single (tmp, sizeof (tmp), addr); + mutt_addrlist_to_local (addr); + rfc822_write_address_single (tmp, sizeof (tmp), addr, 0); mutt_quote_filename (buff, sizeof (buff), tmp); addr->personal = personal; diff --git a/protos.h b/protos.h index 7d779b51..6c53dd99 100644 --- a/protos.h +++ b/protos.h @@ -229,7 +229,7 @@ void mutt_update_encoding (BODY *a); void mutt_update_tree (ATTACHPTR **, short); void mutt_version (void); void mutt_view_attachments (HEADER *); -void mutt_write_address_list (ADDRESS *adr, FILE *fp, int linelen); +void mutt_write_address_list (ADDRESS *adr, FILE *fp, int linelen, int display); void mutt_set_virtual (CONTEXT *); int mutt_addr_is_user (ADDRESS *); diff --git a/query.c b/query.c index 08468a47..d15a8590 100644 --- a/query.c +++ b/query.c @@ -18,6 +18,7 @@ #include "mutt.h" #include "mutt_menu.h" +#include "mutt_idna.h" #include "mapping.h" #include "sort.h" @@ -64,6 +65,7 @@ static ADDRESS *result_to_addr (QUERY *r) if(!tmp.next && !tmp.personal) tmp.personal = r->name; + mutt_addrlist_to_idna (&tmp, NULL); return &tmp; } @@ -193,7 +195,7 @@ static void query_entry (char *s, size_t slen, MUTTMENU *m, int num) SecondColumn = QUERY_MIN_COLUMN_LENGHT; } - rfc822_write_address (buf, sizeof (buf), table[num].data->addr); + rfc822_write_address (buf, sizeof (buf), table[num].data->addr, 1); mutt_format_string (buf2, sizeof (buf2), FirstColumn + 2, FirstColumn + 2, @@ -222,6 +224,7 @@ static int query_tag (MUTTMENU *menu, int n, int m) int mutt_query_complete (char *buf, size_t buflen) { QUERY *results = NULL; + ADDRESS *tmpa; if (!QueryCmd) { @@ -235,8 +238,10 @@ int mutt_query_complete (char *buf, size_t buflen) /* only one response? */ if (results->next == NULL) { + tmpa = result_to_addr (results); + mutt_addrlist_to_local (tmpa); buf[0] = '\0'; - rfc822_write_address (buf, buflen, result_to_addr(results)); + rfc822_write_address (buf, buflen, tmpa, 0); mutt_clear_error (); return (0); } @@ -462,15 +467,19 @@ static void query_menu (char *buf, size_t buflen, QUERY *results, int retbuf) { if (curpos == 0) { + ADDRESS *tmpa = result_to_addr (QueryTable[i].data); + mutt_addrlist_to_local (tmpa); tagged = 1; - rfc822_write_address (buf, buflen, result_to_addr(QueryTable[i].data)); + rfc822_write_address (buf, buflen, tmpa, 0); curpos = mutt_strlen (buf); } else if (curpos + 2 < buflen) { + ADDRESS *tmpa = result_to_addr (QueryTable[i].data); + mutt_addrlist_to_local (tmpa); strcat (buf, ", "); /* __STRCAT_CHECKED__ */ rfc822_write_address ((char *) buf + curpos + 1, buflen - curpos - 1, - result_to_addr(QueryTable[i].data)); + tmpa, 0); curpos = mutt_strlen (buf); } } @@ -478,7 +487,9 @@ static void query_menu (char *buf, size_t buflen, QUERY *results, int retbuf) /* then enter current message */ if (!tagged) { - rfc822_write_address (buf, buflen, result_to_addr(QueryTable[menu->current].data)); + ADDRESS *tmpa = result_to_addr (QueryTable[menu->current].data); + mutt_addrlist_to_local (tmpa); + rfc822_write_address (buf, buflen, tmpa, 0); } } diff --git a/recvcmd.c b/recvcmd.c index 34435d1c..88300d61 100644 --- a/recvcmd.c +++ b/recvcmd.c @@ -29,7 +29,7 @@ #include "mapping.h" #include "mx.h" #include "copy.h" - +#include "mutt_idna.h" /* some helper functions to verify that we are exclusively operating * on message/rfc822 attachments @@ -128,6 +128,7 @@ void mutt_attach_bounce (FILE * fp, HEADER * hdr, short i; char prompt[STRING]; char buf[HUGE_STRING]; + char *err = NULL; ADDRESS *adr = NULL; int ret = 0; int p = 0; @@ -155,8 +156,17 @@ void mutt_attach_bounce (FILE * fp, HEADER * hdr, } adr = mutt_expand_aliases (adr); + + if (mutt_addrlist_to_idna (adr, &err) < 0) + { + mutt_error (_("Bad IDN: '%s'"), err); + FREE (&err); + rfc822_free_address (&adr); + return; + } + buf[0] = 0; - rfc822_write_address (buf, sizeof (buf), adr); + rfc822_write_address (buf, sizeof (buf), adr, 1); #define extra_space (15+7+2) /* diff --git a/rfc822.c b/rfc822.c index 5a07ea53..b3b93978 100644 --- a/rfc822.c +++ b/rfc822.c @@ -33,6 +33,8 @@ #include "rfc822.h" #endif +#include "mutt_idna.h" + #define terminate_string(a, b, c) do { if ((b) < (c)) a[(b)] = 0; else \ a[(c)] = 0; } while (0) @@ -541,7 +543,8 @@ rfc822_cat (char *buf, size_t buflen, const char *value, const char *specials) strfcpy (buf, value, buflen); } -void rfc822_write_address_single (char *buf, size_t buflen, ADDRESS *addr) +void rfc822_write_address_single (char *buf, size_t buflen, ADDRESS *addr, + int display) { size_t len; char *pbuf = buf; @@ -628,11 +631,16 @@ void rfc822_write_address_single (char *buf, size_t buflen, ADDRESS *addr) { if (!buflen) goto done; - if (ascii_strcmp (addr->mailbox, "@")) + if (ascii_strcmp (addr->mailbox, "@") && !display) { strfcpy (pbuf, addr->mailbox, buflen); len = mutt_strlen (pbuf); } + else if (ascii_strcmp (addr->mailbox, "@") && display) + { + strfcpy (pbuf, mutt_addr_for_display (addr), buflen); + len = mutt_strlen (pbuf); + } else { *pbuf = '\0'; @@ -675,7 +683,7 @@ done: } /* note: it is assumed that `buf' is nul terminated! */ -void rfc822_write_address (char *buf, size_t buflen, ADDRESS *addr) +void rfc822_write_address (char *buf, size_t buflen, ADDRESS *addr, int display) { char *pbuf = buf; size_t len = mutt_strlen (buf); @@ -703,7 +711,7 @@ void rfc822_write_address (char *buf, size_t buflen, ADDRESS *addr) { /* use buflen+1 here because we already saved space for the trailing nul char, and the subroutine can make use of it */ - rfc822_write_address_single (pbuf, buflen + 1, addr); + rfc822_write_address_single (pbuf, buflen + 1, addr, display); /* this should be safe since we always have at least 1 char passed into the above call, which means `pbuf' should always be nul terminated */ diff --git a/rfc822.h b/rfc822.h index d30c5bbf..1e703e35 100644 --- a/rfc822.h +++ b/rfc822.h @@ -50,9 +50,8 @@ ADDRESS *rfc822_parse_adrlist (ADDRESS *, const char *s); ADDRESS *rfc822_cpy_adr (ADDRESS *addr); ADDRESS *rfc822_cpy_adr_real (ADDRESS *addr); ADDRESS *rfc822_append (ADDRESS **a, ADDRESS *b); -void rfc822_write_address (char *, size_t, ADDRESS *); -void rfc822_write_address_single (char *, size_t, ADDRESS *); -void rfc822_write_list (char *, size_t, ADDRESS *); +void rfc822_write_address (char *, size_t, ADDRESS *, int); +void rfc822_write_address_single (char *, size_t, ADDRESS *, int); void rfc822_free_address (ADDRESS **addr); void rfc822_cat (char *, size_t, const char *, const char *); diff --git a/send.c b/send.c index 31f9f331..b9452334 100644 --- a/send.c +++ b/send.c @@ -25,6 +25,7 @@ #include "copy.h" #include "mx.h" #include "mutt_crypt.h" +#include "mutt_idna.h" #include #include @@ -183,13 +184,27 @@ static ADDRESS *find_mailing_lists (ADDRESS *t, ADDRESS *c) static int edit_address (ADDRESS **a, /* const */ char *field) { char buf[HUGE_STRING]; - - buf[0] = 0; - rfc822_write_address (buf, sizeof (buf), *a); - if (mutt_get_field (field, buf, sizeof (buf), M_ALIAS) != 0) - return (-1); - rfc822_free_address (a); - *a = mutt_expand_aliases (mutt_parse_adrlist (NULL, buf)); + char *err = NULL; + int idna_ok = 0; + + do + { + buf[0] = 0; + mutt_addrlist_to_local (*a); + rfc822_write_address (buf, sizeof (buf), *a, 0); + if (mutt_get_field (field, buf, sizeof (buf), M_ALIAS) != 0) + return (-1); + rfc822_free_address (a); + *a = mutt_expand_aliases (mutt_parse_adrlist (NULL, buf)); + if ((idna_ok = mutt_addrlist_to_idna (*a, &err)) != 0) + { + mutt_error (_("Error: '%s' is a bad IDN."), err); + mutt_refresh (); + mutt_sleep (2); + FREE (&err); + } + } + while (idna_ok != 0); return 0; } @@ -321,7 +336,7 @@ void mutt_forward_intro (FILE *fp, HEADER *cur) fputs ("----- Forwarded message from ", fp); buffer[0] = 0; - rfc822_write_address (buffer, sizeof (buffer), cur->env->from); + rfc822_write_address (buffer, sizeof (buffer), cur->env->from, 1); fputs (buffer, fp); fputs (" -----\n\n", fp); } @@ -406,7 +421,7 @@ static int include_reply (CONTEXT *ctx, HEADER *cur, FILE *out) cmflags |= M_CM_NOHEADER; if (option (OPTWEED)) { - chflags |= CH_WEED; + chflags |= CH_WEED | CH_REORDER; cmflags |= M_CM_WEED; } @@ -1030,6 +1045,7 @@ ci_send_message (int flags, /* send mode */ char *pgpkeylist = NULL; /* save current value of "pgp_sign_as" */ char *signas = NULL; + char *tag = NULL, *err = NULL; int rv = -1; @@ -1307,7 +1323,11 @@ ci_send_message (int flags, /* send mode */ else if (!Editor || mutt_strcmp ("builtin", Editor) == 0) mutt_builtin_editor (msg->content->filename, msg, cur); else if (option (OPTEDITHDRS)) + { + mutt_env_to_local (msg->env); mutt_edit_headers (Editor, msg->content->filename, msg, fcc, sizeof (fcc)); + mutt_env_to_idna (msg->env, NULL, NULL); + } else mutt_edit_file (Editor, msg->content->filename); } @@ -1379,6 +1399,7 @@ main_loop: encode_descriptions (msg->content, 1); mutt_prepare_envelope (msg->env, 0); + mutt_env_to_idna (msg->env, NULL, NULL); /* Handle bad IDNAs the next time. */ if (!Postponed || mutt_write_fcc (NONULL (Postponed), msg, (cur && (flags & SENDREPLY)) ? cur->env->message_id : NULL, 1, fcc) < 0) { @@ -1407,6 +1428,13 @@ main_loop: } } + if (mutt_env_to_idna (msg->env, &tag, &err)) + { + mutt_error (_("Bad IDN in \"%s\": '%s'"), tag, err); + FREE (&err); + goto main_loop; + } + if (!msg->env->subject && ! (flags & SENDBATCH) && (i = query_quadoption (OPT_SUBJECT, _("No subject, abort sending?"))) != M_NO) { diff --git a/sendlib.c b/sendlib.c index d6171f7d..975a65fc 100644 --- a/sendlib.c +++ b/sendlib.c @@ -29,6 +29,7 @@ #include "pager.h" #include "charset.h" #include "mutt_crypt.h" +#include "mutt_idna.h" #include #include @@ -1497,7 +1498,7 @@ char *mutt_make_date (char *s, size_t len) /* wrapper around mutt_write_address() so we can handle very large recipient lists without needing a huge temporary buffer in memory */ -void mutt_write_address_list (ADDRESS *adr, FILE *fp, int linelen) +void mutt_write_address_list (ADDRESS *adr, FILE *fp, int linelen, int display) { ADDRESS *tmp; char buf[LONG_STRING]; @@ -1509,7 +1510,7 @@ void mutt_write_address_list (ADDRESS *adr, FILE *fp, int linelen) tmp = adr->next; adr->next = NULL; buf[0] = 0; - rfc822_write_address (buf, sizeof (buf), adr); + rfc822_write_address (buf, sizeof (buf), adr, display); len = mutt_strlen (buf); if (count && linelen + len > 74) { @@ -1573,6 +1574,8 @@ static void write_references (LIST *r, FILE *f) /* Note: all RFC2047 encoding should be done outside of this routine, except * for the "real name." This will allow this routine to be used more than * once, if necessary. + * + * Likewise, all IDN processing should happen outside of this routine. * * mode == 1 => "lite" mode (used for edit_hdrs) * mode == 0 => normal mode. write full header + MIME headers @@ -1581,7 +1584,7 @@ static void write_references (LIST *r, FILE *f) * privacy != 0 => will omit any headers which may identify the user. * Output generated is suitable for being sent through * anonymous remailer chains. - * + * */ int mutt_write_rfc822_header (FILE *fp, ENVELOPE *env, BODY *attach, @@ -1601,14 +1604,14 @@ int mutt_write_rfc822_header (FILE *fp, ENVELOPE *env, BODY *attach, if (env->from && !privacy) { buffer[0] = 0; - rfc822_write_address (buffer, sizeof (buffer), env->from); + rfc822_write_address (buffer, sizeof (buffer), env->from, 0); fprintf (fp, "From: %s\n", buffer); } if (env->to) { fputs ("To: ", fp); - mutt_write_address_list (env->to, fp, 4); + mutt_write_address_list (env->to, fp, 4, 0); } else if (mode > 0) fputs ("To: \n", fp); @@ -1616,7 +1619,7 @@ int mutt_write_rfc822_header (FILE *fp, ENVELOPE *env, BODY *attach, if (env->cc) { fputs ("Cc: ", fp); - mutt_write_address_list (env->cc, fp, 4); + mutt_write_address_list (env->cc, fp, 4, 0); } else if (mode > 0) fputs ("Cc: \n", fp); @@ -1626,7 +1629,7 @@ int mutt_write_rfc822_header (FILE *fp, ENVELOPE *env, BODY *attach, if(mode != 0 || option(OPTWRITEBCC)) { fputs ("Bcc: ", fp); - mutt_write_address_list (env->bcc, fp, 5); + mutt_write_address_list (env->bcc, fp, 5, 0); } } else if (mode > 0) @@ -1644,7 +1647,7 @@ int mutt_write_rfc822_header (FILE *fp, ENVELOPE *env, BODY *attach, if (env->reply_to) { fputs ("Reply-To: ", fp); - mutt_write_address_list (env->reply_to, fp, 10); + mutt_write_address_list (env->reply_to, fp, 10, 0); } else if (mode > 0) fputs ("Reply-To: \n", fp); @@ -1652,7 +1655,7 @@ int mutt_write_rfc822_header (FILE *fp, ENVELOPE *env, BODY *attach, if (env->mail_followup_to) { fputs ("Mail-Followup-To: ", fp); - mutt_write_address_list (env->mail_followup_to, fp, 18); + mutt_write_address_list (env->mail_followup_to, fp, 18, 0); } if (mode <= 0) @@ -2228,7 +2231,7 @@ static int _mutt_bounce_message (FILE *fp, HEADER *h, ADDRESS *to, const char *r fprintf (f, "\nResent-%s", mutt_make_date (date, sizeof(date))); fprintf (f, "Resent-Message-ID: %s\n", mutt_gen_msgid()); fputs ("Resent-To: ", f); - mutt_write_address_list (to, f, 11); + mutt_write_address_list (to, f, 11, 0); mutt_copy_header (fp, h, f, ch_flags, NULL); fputc ('\n', f); mutt_copy_bytes (fp, f, h->content->length); @@ -2250,7 +2253,8 @@ int mutt_bounce_message (FILE *fp, HEADER *h, ADDRESS *to) const char *fqdn = mutt_fqdn (1); char resent_from[STRING]; int ret; - + char *err; + resent_from[0] = '\0'; from = mutt_default_from (); @@ -2258,8 +2262,13 @@ int mutt_bounce_message (FILE *fp, HEADER *h, ADDRESS *to) rfc822_qualify (from, fqdn); rfc2047_encode_adrlist (from, "Resent-From"); - - rfc822_write_address (resent_from, sizeof (resent_from), from); + if (mutt_addrlist_to_idna (from, &err)) + { + mutt_error (_("Bad IDN %s while preparing resent-from."), + err); + return -1; + } + rfc822_write_address (resent_from, sizeof (resent_from), from, 0); ret = _mutt_bounce_message (fp, h, to, resent_from, from);