]> granicus.if.org Git - mutt/commitdiff
IDN support for e-mail messages. Things should work automagically
authorThomas Roessler <roessler@does-not-exist.org>
Mon, 3 Mar 2003 14:01:06 +0000 (14:01 +0000)
committerThomas Roessler <roessler@does-not-exist.org>
Mon, 3 Mar 2003 14:01:06 +0000 (14:01 +0000)
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.

23 files changed:
Makefile.am
addrbook.c
alias.c
charset.h
commands.c
compose.c
configure.in
copy.c
edit.c
hdrline.c
headers.c
init.c
main.c
mutt_idna.c [new file with mode: 0644]
mutt_idna.h [new file with mode: 0644]
pgpinvoke.c
protos.h
query.c
recvcmd.c
rfc822.c
rfc822.h
send.c
sendlib.c

index cf17264958f3b2ecb828f9477d8a029d880c4a84..a1bec37f8acfb0c22779a98e385ae7de4cf864a8 100644 (file)
@@ -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@
index 157a6f691c7c6139c5e1ce50c0c05d00ad972806..627c4704d1ce3938c132ef99aa12c2c5d84057ea 100644 (file)
@@ -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 fdb866d2cc8df0dc557638ff2373140d8674c70a..b605e20b5894e6a9160eb6d913ac510b87d26584 100644 (file)
--- 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 <string.h>
 #include <ctype.h>
@@ -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);
index 993f997324ff6bccb52cc3cc749f2824de24ca39..cfc2ac53e5a136637a7a639093a3424756dd6f0c 100644 (file)
--- 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 */
index cd177f9f962b2d14672122ea45142a9ab5e4451d..ed1e1ce12b739fb059ca7d4b725ff18787dd00e1 100644 (file)
@@ -27,6 +27,7 @@
 #include "mx.h"
 #include "pager.h"
 #include "mutt_crypt.h"
+#include "mutt_idna.h"
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
@@ -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);
 }
 
index 28d87a9c8bb84c6ae2b7b986a6bb621979b73778..a822824ee6eff47015c30320e0ed6bd02e904556 100644 (file)
--- 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
        {
index 8998892383e47d7c219608b8e3128998e0063bce..1d696ce6183375ed6805c71e1a82d1a40a88ddc2 100644 (file)
@@ -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 1f24d8466a680e8262bcbeedec69c8360a73c461..fc148c316b1336275539501645e26387250317ed 100644 (file)
--- a/copy.c
+++ b/copy.c
 #include "rfc2047.h"
 #include "mime.h"
 #include "mutt_crypt.h"
+#include "mutt_idna.h"
 
 #include <string.h>
 #include <stdlib.h>
 #include <ctype.h>
 #include <unistd.h> /* 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 37684939557c32b28f00aba2a8f9ac8f00c56f62..77472910d12770113d02060437a885a33044ffc8 100644 (file)
--- a/edit.c
+++ b/edit.c
@@ -20,6 +20,7 @@
 
 #include "mutt.h"
 #include "mutt_curses.h"
+#include "mutt_idna.h"
 
 #include <stdio.h>
 #include <string.h>
@@ -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);
 
index 0dd68990ccef54a3c6e3356ab01f66bd8d502239..7156ecf9eb5156f90d9cacf269c4803d9c3b88e7 100644 (file)
--- 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 <ctype.h>
 #include <stdlib.h>
@@ -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;
       }
index 7ad59fbe78982d755d3aa1c107f24a9606e216e5..a05ed63b770288a65bc9b9155becb4e323bfeed6 100644 (file)
--- a/headers.c
+++ b/headers.c
@@ -17,8 +17,8 @@
  */
 
 #include "mutt.h"
-
 #include "mutt_crypt.h"
+#include "mutt_idna.h"
 
 #include <sys/stat.h>
 #include <string.h>
@@ -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 97fa14dfbcefeb2881bd21f7f93c550974f49b9c..557eb0980883c29f884224da0b34b11734411920 100644 (file)
--- 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 21cba1f013bc651e7a5ad7de103724a64f4b5531..81062f862d7669510d614d26bb23ddc561905415 100644 (file)
--- 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 <string.h>
 #include <stdlib.h>
 #include <getopt.h>
 #endif
 
+#ifdef HAVE_LIBIDN
+#include <stringprep.h>
+#endif
+
 static const char *ReachingUs = N_("\
 To contact the developers, please mail to <mutt-dev@mutt.org>.\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 (file)
index 0000000..2d3f4c4
--- /dev/null
@@ -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
diff --git a/mutt_idna.h b/mutt_idna.h
new file mode 100644 (file)
index 0000000..270c420
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */ 
+
+#ifndef _MUTT_IDNA_H
+# define _MUTT_IDNA_H
+
+#include "config.h"
+#include "rfc822.h"
+#include "charset.h"
+
+#ifdef HAVE_LIBIDN
+#include <idna.h>
+#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
index 3ea41e19e26845a01e7396a55342b0316f7a1f2b..8bbc4f7e0b5299a45f4b08148d35e535ad6753c9 100644 (file)
@@ -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;
index 7d779b514e504e26f6a8f4e4354c233617496c42..6c53dd99a07fee2bfb3498e1c683e5cbd84643d0 100644 (file)
--- 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 08468a4779896bf878439b295218fedae13ea9e5..d15a8590c9687947af85932e79aaf8942bdce425 100644 (file)
--- 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);
       }
       
     }
index 34435d1c592ddd810da49e00d8da5c0d58b524e9..88300d612b99ee4621a254fed5892bfe75af1f03 100644 (file)
--- 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)
   /*
index 5a07ea53033f8c50cba556d4e1bff441edff41f5..b3b9397899fbde4e4a366404dd64e388193a16c9 100644 (file)
--- 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 */
index d30c5bbf24eb0bcae1121c3981f0eb9fffe75292..1e703e35abdcdf9934e11c3cc649c250bc30dd4d 100644 (file)
--- 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 31f9f331545fb34f7367f3dd3876873eab5520ab..b9452334fd4650ebf93ef78f36deb9bac850753b 100644 (file)
--- 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 <ctype.h>
 #include <stdlib.h>
@@ -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)
   {
index d6171f7d98b941d92a8415920aa281b264d0dca6..975a65fc93f3a8cf17ef9be6b951ffbd1509a9ee 100644 (file)
--- 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 <string.h>
 #include <stdlib.h>
@@ -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);