changeset: 6520:a6919571eb59
user:      Kevin McCarthy <ke...@8t8.us>
date:      Sun Oct 18 19:45:51 2015 +0800
link:      http://dev.mutt.org/hg/mutt/rev/a6919571eb59

Fix next_token() oob read.  (closes #3787)

With specially crafted input to 'mutt -H', the line "Return-Path:<() "
is read and passed to mutt_parse_rfc822_line(). "<() " is then passed
through to rfc822_parse_adrlist().

Eventually, inside next_token(), is_special(*s) is called when s
points to the end of the string ('\0').  This macro calls strchr,
which will actually match and return a pointer to the trailing '\0' in
RFC822Specials!  This causes "s + 1" to be returned, skipping past the
end of string inside parse_mailboxdomain().

This patch adds a check to make sure *s is non-null before calling
is_special(*s).

changeset: 6521:41af5a753d6f
user:      Kevin McCarthy <ke...@8t8.us>
date:      Sun Oct 18 20:05:37 2015 +0800
link:      http://dev.mutt.org/hg/mutt/rev/41af5a753d6f

merge stable

diffs (truncated from 13180 to 950 lines):

diff -r 590ff6eebe1a -r 41af5a753d6f UPDATING
--- a/UPDATING  Wed Sep 30 11:21:06 2015 +0800
+++ b/UPDATING  Sun Oct 18 20:05:37 2015 +0800
@@ -4,6 +4,10 @@
 The keys used are:
   !: modified feature, -: deleted feature, +: new feature
 
+default (unreleased):
+  + New expandos %r and %R for comma separated list of To: and Cc:
+    recipients respectively
+
 1.5.24 (2015-08-31):
 
   + terminal status-line (TS) support, a.k.a. xterm title. see the
diff -r 590ff6eebe1a -r 41af5a753d6f alias.c
--- a/alias.c   Wed Sep 30 11:21:06 2015 +0800
+++ b/alias.c   Sun Oct 18 20:05:37 2015 +0800
@@ -256,7 +256,7 @@
   mutt_check_alias_name (tmp, buf, sizeof (buf));
   
 retry_name:
-  /* add a new alias */
+  /* L10N: prompt to add a new alias */
   if (mutt_get_field (_("Alias as: "), buf, sizeof (buf), 0) != 0 || !buf[0])
     return;
 
diff -r 590ff6eebe1a -r 41af5a753d6f browser.c
--- a/browser.c Wed Sep 30 11:21:06 2015 +0800
+++ b/browser.c Sun Oct 18 20:05:37 2015 +0800
@@ -896,7 +896,7 @@
        else
          set_option (OPTIMAPLSUB);
 
-       mutt_ungetch (0, OP_CHECK_NEW);
+       mutt_unget_event (0, OP_CHECK_NEW);
        break;
 
       case OP_CREATE_MAILBOX:
diff -r 590ff6eebe1a -r 41af5a753d6f commands.c
--- a/commands.c        Wed Sep 30 11:21:06 2015 +0800
+++ b/commands.c        Sun Oct 18 20:05:37 2015 +0800
@@ -228,7 +228,7 @@
       mutt_set_flag (Context, cur, M_READ, 1);
     if (r != -1 && option (OPTPROMPTAFTER))
     {
-      mutt_ungetch (mutt_any_key_to_continue _("Command: "), 0);
+      mutt_unget_event (mutt_any_key_to_continue _("Command: "), 0);
       rc = km_dokey (MENU_PAGER);
     }
     else
diff -r 590ff6eebe1a -r 41af5a753d6f compose.c
--- a/compose.c Wed Sep 30 11:21:06 2015 +0800
+++ b/compose.c Sun Oct 18 20:05:37 2015 +0800
@@ -754,7 +754,7 @@
          ctx = mx_open_mailbox (fname, M_READONLY, NULL);
          if (ctx == NULL)
          {
-           mutt_perror (fname);
+           mutt_error (_("Unable to open mailbox %s"), fname);
            break;
          }
 
@@ -1023,6 +1023,8 @@
        {
          if (stat(idx[menu->current]->content->filename, &st) == -1)
          {
+            /* L10N:
+               "stat" is a system call. Do "man 2 stat" for more information. 
*/
            mutt_error (_("Can't stat %s: %s"), fname, strerror (errno));
            break;
          }
@@ -1234,14 +1236,20 @@
        if ((WithCrypto & APPLICATION_SMIME)
             && (msg->security & APPLICATION_SMIME))
        {
-         if (mutt_yesorno (_("S/MIME already selected. Clear & continue ? "),
-                            M_YES) != M_YES)
-         {
-           mutt_clear_error ();
-           break;
-         }
+          if (msg->security & (ENCRYPT | SIGN))
+          {
+            if (mutt_yesorno (_("S/MIME already selected. Clear & continue ? 
"),
+                              M_YES) != M_YES)
+            {
+              mutt_clear_error ();
+              break;
+            }
+            msg->security &= ~(ENCRYPT | SIGN);
+          }
          msg->security &= ~APPLICATION_SMIME;
          msg->security |= APPLICATION_PGP;
+          crypt_opportunistic_encrypt (msg);
+          redraw_crypt_lines (msg);
        }
        msg->security = crypt_pgp_send_menu (msg, &menu->redraw);
        redraw_crypt_lines (msg);
@@ -1261,14 +1269,20 @@
        if ((WithCrypto & APPLICATION_PGP)
             && (msg->security & APPLICATION_PGP))
        {
-         if (mutt_yesorno (_("PGP already selected. Clear & continue ? "),
-                             M_YES) != M_YES)
-         {
-            mutt_clear_error ();
-            break;
-         }
+          if (msg->security & (ENCRYPT | SIGN))
+          {
+            if (mutt_yesorno (_("PGP already selected. Clear & continue ? "),
+                                M_YES) != M_YES)
+            {
+              mutt_clear_error ();
+              break;
+            }
+            msg->security &= ~(ENCRYPT | SIGN);
+          }
          msg->security &= ~APPLICATION_PGP;
          msg->security |= APPLICATION_SMIME;
+          crypt_opportunistic_encrypt (msg);
+          redraw_crypt_lines (msg);
        }
        msg->security = crypt_smime_send_menu(msg, &menu->redraw);
        redraw_crypt_lines (msg);
diff -r 590ff6eebe1a -r 41af5a753d6f crypt-gpgme.c
--- a/crypt-gpgme.c     Wed Sep 30 11:21:06 2015 +0800
+++ b/crypt-gpgme.c     Sun Oct 18 20:05:37 2015 +0800
@@ -1362,6 +1362,8 @@
        continue;
       if (aka)
       {
+        /* TODO: need to account for msg wide characters
+         * and "aka" translation length */
        msglen = mutt_strlen (msg) - 4;
        for (i = 0; i < msglen; i++)
          state_attach_puts(" ", s);
@@ -1381,6 +1383,8 @@
   }
 
   msglen = mutt_strlen (msg) - 8;
+  /* TODO: need to account for msg wide characters
+   * and "created" translation length */
   for (i = 0; i < msglen; i++)
     state_attach_puts(" ", s);
   state_attach_puts (_("created: "), s);
@@ -1404,6 +1408,7 @@
   gpgme_verify_result_t result;
   gpgme_signature_t sig;
   gpgme_error_t err = GPG_ERR_NO_ERROR;
+  char buf[LONG_STRING];
 
   result = gpgme_op_verify_result (ctx);
   if (result)
@@ -1453,11 +1458,10 @@
        ; /* No state information so no way to print anything. */
       else if (err)
        {
-          state_attach_puts (_("Error getting key information for KeyID "), s);
-         state_attach_puts ( fpr, s );
-          state_attach_puts (_(": "), s);
-          state_attach_puts ( gpgme_strerror (err), s );
-          state_attach_puts ("\n", s);
+          snprintf (buf, sizeof (buf),
+              _("Error getting key information for KeyID %s: %s\n"),
+              fpr, gpgme_strerror (err));
+          state_attach_puts (buf, s);
           anybad = 1;
        }
       else if ((sum & GPGME_SIGSUM_GREEN))
@@ -1489,6 +1493,9 @@
        /* 0 indicates no expiration */
        if (sig->exp_timestamp)
        {
+          /* L10N:
+             This is trying to match the width of the
+             "Problem signature from:" translation just above. */
          state_attach_puts (_("               expires: "), s);
          print_time (sig->exp_timestamp, s);
          state_attach_puts ("\n", s);
@@ -3366,6 +3373,10 @@
         continue;
 
       s = uid->uid;
+      /* L10N:
+         Fill dots to make the DOTFILL entries the same length.
+         In English, msgid "Fingerprint: " is the longest entry for this menu.
+         Your language may vary. */
       fputs (idx ? _(" aka ......: ") :_("Name ......: "), fp);
       if (uid->invalid)
         {
@@ -3389,6 +3400,7 @@
 #else
       strftime (shortbuf, sizeof shortbuf, "%c", tm);
 #endif
+      /* L10N: DOTFILL */
       fprintf (fp, _("Valid From : %s\n"), shortbuf);
     }
   
@@ -3402,6 +3414,7 @@
 #else
       strftime (shortbuf, sizeof shortbuf, "%c", tm);
 #endif
+      /* L10N: DOTFILL */
       fprintf (fp, _("Valid To ..: %s\n"), shortbuf);
     }
 
@@ -3415,8 +3428,10 @@
   if (key->subkeys)
     aval = key->subkeys->length;
 
+  /* L10N: DOTFILL */
   fprintf (fp, _("Key Type ..: %s, %lu bit %s\n"), s2, aval, s);
 
+  /* L10N: DOTFILL */
   fprintf (fp, _("Key Usage .: "));
   delim = "";
 
@@ -3440,6 +3455,7 @@
   if (key->subkeys)
     {
       s = key->subkeys->fpr;
+      /* L10N: DOTFILL */
       fputs (_("Fingerprint: "), fp);
       if (is_pgp && strlen (s) == 40)
         {
@@ -3472,6 +3488,7 @@
     {
       s = key->issuer_serial;
       if (s)
+        /* L10N: DOTFILL */
        fprintf (fp, _("Serial-No .: 0x%s\n"), s);
     }
 
@@ -3480,6 +3497,7 @@
       s = key->issuer_name;
       if (s)
        {
+          /* L10N: DOTFILL */
          fprintf (fp, _("Issued By .: "));
          parse_and_print_user_id (fp, s);
          putc ('\n', fp);
@@ -3499,6 +3517,7 @@
           putc ('\n', fp);
           if ( strlen (s) == 16)
             s += 8; /* display only the short keyID */
+          /* L10N: DOTFILL */
           fprintf (fp, _("Subkey ....: 0x%s"), s);
          if (subkey->revoked)
             {
@@ -3532,6 +3551,7 @@
 #else
               strftime (shortbuf, sizeof shortbuf, "%c", tm);
 #endif
+              /* L10N: DOTFILL */
               fprintf (fp, _("Valid From : %s\n"), shortbuf);
             }
 
@@ -3545,6 +3565,7 @@
 #else
               strftime (shortbuf, sizeof shortbuf, "%c", tm);
 #endif
+              /* L10N: DOTFILL */
               fprintf (fp, _("Valid To ..: %s\n"), shortbuf);
             }
 
@@ -3558,8 +3579,10 @@
          else
            aval = 0;
 
+          /* L10N: DOTFILL */
           fprintf (fp, _("Key Type ..: %s, %lu bit %s\n"), "PGP", aval, s);
 
+          /* L10N: DOTFILL */
           fprintf (fp, _("Key Usage .: "));
           delim = "";
 
@@ -4010,8 +4033,14 @@
       ts = _("keys matching");
 
     if (p)
+      /* L10N:
+         %1$s is one of the previous four entries.
+         %2$s is an address.
+         e.g. "S/MIME keys matching <m...@mutt.org>." */
       snprintf (buf, sizeof (buf), _("%s <%s>."), ts, p->mailbox);
     else
+      /* L10N:
+         e.g. 'S/MIME keys matching "Michael Elkins".' */
       snprintf (buf, sizeof (buf), _("%s \"%s\"."), ts, s);
     menu->title = buf; 
   }
@@ -4590,6 +4619,10 @@
   att->use_disp = 0;
   att->type = TYPEAPPLICATION;
   att->subtype = safe_strdup ("pgp-keys");
+  /* L10N:
+     MIME description for exported (attached) keys.
+     You can translate this entry to a non-ASCII string (it will be encoded),
+     but it may be safer to keep it untranslated. */
   snprintf (buff, sizeof (buff), _("PGP Key 0x%s."), crypt_keyid (key));
   att->description = safe_strdup (buff);
   mutt_update_encoding (att);
@@ -4678,6 +4711,10 @@
     if (is_smime)
     {
       prompt = _("S/MIME (s)ign, sign (a)s, (p)gp, (c)lear, or (o)ppenc mode 
off? ");
+      /* L10N: The 'f' is from "forget it", an old undocumented synonym of
+         'clear'.  Please use a corresponding letter in your language.
+         Alternatively, you may duplicate the letter 'c' is translated to.
+         This comment also applies to the five following letter sequences. */
       letters = _("sapfco");
       choices = "SapFCo";
     }
diff -r 590ff6eebe1a -r 41af5a753d6f curs_lib.c
--- a/curs_lib.c        Wed Sep 30 11:21:06 2015 +0800
+++ b/curs_lib.c        Sun Oct 18 20:05:37 2015 +0800
@@ -48,9 +48,20 @@
  * is impossible to unget function keys in SLang, so roll our own input
  * buffering routines.
  */
-size_t UngetCount = 0;
-static size_t UngetBufLen = 0;
-static event_t *KeyEvent;
+
+/* These are used for macros and exec/push commands.
+ * They can be temporarily ignored by setting OPTIGNOREMACROEVENTS
+ */
+static size_t MacroBufferCount = 0;
+static size_t MacroBufferLen = 0;
+static event_t *MacroEvents;
+
+/* These are used in all other "normal" situations, and are not
+ * ignored when setting OPTIGNOREMACROEVENTS
+ */
+static size_t UngetCount = 0;
+static size_t UngetLen = 0;
+static event_t *UngetKeyEvents;
 
 void mutt_refresh (void)
 {
@@ -83,8 +94,11 @@
   event_t err = {-1, OP_NULL }, ret;
   event_t timeout = {-2, OP_NULL};
 
-  if (!option(OPTUNBUFFEREDINPUT) && UngetCount)
-    return (KeyEvent[--UngetCount]);
+  if (UngetCount)
+    return (UngetKeyEvents[--UngetCount]);
+
+  if (!option(OPTIGNOREMACROEVENTS) && MacroBufferCount)
+    return (MacroEvents[--MacroBufferCount]);
 
   SigInt = 0;
 
@@ -118,7 +132,7 @@
   {
     /* send ALT-x as ESC-x */
     ch &= ~0x80;
-    mutt_ungetch (ch, 0);
+    mutt_unget_event (ch, 0);
     ret.ch = '\033';
     ret.op = 0;
     return ret;
@@ -157,9 +171,9 @@
 {
   int rc;
 
-  set_option (OPTUNBUFFEREDINPUT);
+  set_option (OPTIGNOREMACROEVENTS);
   rc = mutt_get_field (msg, buf, buflen, flags);
-  unset_option (OPTUNBUFFEREDINPUT);
+  unset_option (OPTIGNOREMACROEVENTS);
 
   return (rc);
 }
@@ -595,7 +609,7 @@
     char *pc = safe_malloc (mutt_strlen (prompt) + 3);
 
     sprintf (pc, "%s: ", prompt);      /* __SPRINTF_CHECKED__ */
-    mutt_ungetch (ch.op ? 0 : ch.ch, ch.op ? ch.op : 0);
+    mutt_unget_event (ch.op ? 0 : ch.ch, ch.op ? ch.op : 0);
     if (_mutt_get_field (pc, buf, blen, (buffy ? M_EFILE : M_FILE) | M_CLEAR, 
multiple, files, numfiles)
        != 0)
       buf[0] = 0;
@@ -606,22 +620,60 @@
   return 0;
 }
 
-void mutt_ungetch (int ch, int op)
+void mutt_unget_event (int ch, int op)
 {
   event_t tmp;
 
   tmp.ch = ch;
   tmp.op = op;
 
-  if (UngetCount >= UngetBufLen)
-    safe_realloc (&KeyEvent, (UngetBufLen += 128) * sizeof(event_t));
+  if (UngetCount >= UngetLen)
+    safe_realloc (&UngetKeyEvents, (UngetLen += 16) * sizeof(event_t));
 
-  KeyEvent[UngetCount++] = tmp;
+  UngetKeyEvents[UngetCount++] = tmp;
+}
+
+void mutt_unget_string (char *s)
+{
+  char *p = s + mutt_strlen (s) - 1;
+
+  while (p >= s)
+  {
+    mutt_unget_event ((unsigned char)*p--, 0);
+  }
+}
+
+/*
+ * Adds the ch/op to the macro buffer.
+ * This should be used for macros, push, and exec commands only.
+ */
+void mutt_push_macro_event (int ch, int op)
+{
+  event_t tmp;
+
+  tmp.ch = ch;
+  tmp.op = op;
+
+  if (MacroBufferCount >= MacroBufferLen)
+    safe_realloc (&MacroEvents, (MacroBufferLen += 128) * sizeof(event_t));
+
+  MacroEvents[MacroBufferCount++] = tmp;
+}
+
+void mutt_flush_macro_to_endcond (void)
+{
+  UngetCount = 0;
+  while (MacroBufferCount > 0)
+  {
+    if (MacroEvents[--MacroBufferCount].op == OP_END_COND)
+      return;
+  }
 }
 
 void mutt_flushinp (void)
 {
   UngetCount = 0;
+  MacroBufferCount = 0;
   flushinp ();
 }
 
diff -r 590ff6eebe1a -r 41af5a753d6f curs_main.c
--- a/curs_main.c       Wed Sep 30 11:21:06 2015 +0800
+++ b/curs_main.c       Sun Oct 18 20:05:37 2015 +0800
@@ -93,7 +93,8 @@
 #define CHECK_ACL(aclbit,action) \
                if (!mutt_bit_isset(Context->rights,aclbit)) { \
                        mutt_flushinp(); \
-                       mutt_error (_("Cannot %s: Operation not permitted by 
ACL"), action); \
+        /* L10N: %s is one of the CHECK_ACL entries below. */ \
+                       mutt_error (_("%s: Operation not permitted by ACL"), 
action); \
                        break; \
                }
 
@@ -108,8 +109,6 @@
 #define OLDHDR Context->hdrs[Context->v2r[menu->oldcurrent]]
 #define UNREAD(h) mutt_thread_contains_unread (Context, h)
 
-extern size_t UngetCount;
-
 /* de facto standard escapes for tsl/fsl */
 static char *tsl = "\033]0;";
 static char *fsl = "\007";
@@ -728,12 +727,7 @@
 
        if (!Context->tagged)
        {
-         event_t tmp;
-         while(UngetCount>0)
-         {
-           tmp=mutt_getch();
-           if(tmp.op==OP_END_COND)break;
-         }
+         mutt_flush_macro_to_endcond ();
          mutt_message  _("Nothing to do.");
          continue;
        }
@@ -818,7 +812,7 @@
 
        CHECK_MSGCOUNT;
         CHECK_VISIBLE;
-        if (isdigit (LastKey)) mutt_ungetch (LastKey, 0);
+        if (isdigit (LastKey)) mutt_unget_event (LastKey, 0);
        buf[0] = 0;
        if (mutt_get_field (_("Jump to message: "), buf, sizeof (buf), 0) != 0
            || !buf[0])
@@ -874,7 +868,8 @@
        CHECK_MSGCOUNT;
         CHECK_VISIBLE;
        CHECK_READONLY;
-       CHECK_ACL(M_ACL_DELETE, _("delete message(s)"));
+        /* L10N: CHECK_ACL */
+       CHECK_ACL(M_ACL_DELETE, _("Cannot delete message(s)"));
 
        CHECK_ATTACH;
        mutt_pattern_func (M_DELETE, _("Delete messages matching: "));
@@ -903,7 +898,7 @@
        else
        {
           char buf[STRING];
-          /* i18n: ask for a limit to apply */
+          /* L10N: ask for a limit to apply */
           snprintf (buf, sizeof(buf), _("Limit: %s"),Context->pattern);
            mutt_message ("%s", buf);
        }
@@ -1047,7 +1042,8 @@
        CHECK_MSGCOUNT;
         CHECK_VISIBLE;
        CHECK_READONLY;
-       CHECK_ACL(M_ACL_DELETE, _("undelete message(s)"));
+        /* L10N: CHECK_ACL */
+       CHECK_ACL(M_ACL_DELETE, _("Cannot undelete message(s)"));
 
        if (mutt_pattern_func (M_UNDELETE, _("Undelete messages matching: ")) 
== 0)
          menu->redraw = REDRAW_INDEX | REDRAW_STATUS;
@@ -1354,7 +1350,8 @@
        CHECK_MSGCOUNT;
         CHECK_VISIBLE;
        CHECK_READONLY;
-       CHECK_ACL(M_ACL_DELETE, _("link threads"));
+        /* L10N: CHECK_ACL */
+       CHECK_ACL(M_ACL_DELETE, _("Cannot link threads"));
 
         if ((Sort & SORT_MASK) != SORT_THREADS)
          mutt_error _("Threading is not enabled.");
@@ -1605,8 +1602,20 @@
        if (menu->current == -1)
        {
          menu->current = menu->oldcurrent;
-         mutt_error ("%s%s.", (op == OP_MAIN_NEXT_NEW || op == 
OP_MAIN_PREV_NEW) ? _("No new messages") : _("No unread messages"),
-                     Context->pattern ? _(" in this limited view") : "");
+         if (op == OP_MAIN_NEXT_NEW || op == OP_MAIN_PREV_NEW)
+          {
+            if (Context->pattern)
+              mutt_error (_("No new messages in this limited view."));
+            else
+              mutt_error (_("No new messages."));
+          }
+          else
+          {
+            if (Context->pattern)
+              mutt_error (_("No unread messages in this limited view."));
+            else
+              mutt_error (_("No unread messages."));
+          }
        }
        else if (menu->menu == MENU_PAGER)
        {
@@ -1622,7 +1631,8 @@
        CHECK_MSGCOUNT;
         CHECK_VISIBLE;
        CHECK_READONLY;
-       CHECK_ACL(M_ACL_WRITE, _("flag message"));
+        /* L10N: CHECK_ACL */
+       CHECK_ACL(M_ACL_WRITE, _("Cannot flag message"));
 
         if (tag)
         {
@@ -1659,7 +1669,8 @@
        CHECK_MSGCOUNT;
         CHECK_VISIBLE;
        CHECK_READONLY;
-       CHECK_ACL(M_ACL_SEEN, _("toggle new"));
+        /* L10N: CHECK_ACL */
+       CHECK_ACL(M_ACL_SEEN, _("Cannot toggle new"));
 
        if (tag)
        {
@@ -1913,7 +1924,8 @@
        CHECK_MSGCOUNT;
         CHECK_VISIBLE;
        CHECK_READONLY;
-       CHECK_ACL(M_ACL_DELETE, _("delete message"));
+        /* L10N: CHECK_ACL */
+       CHECK_ACL(M_ACL_DELETE, _("Cannot delete message"));
 
        if (tag)
        {
@@ -1954,7 +1966,8 @@
        CHECK_MSGCOUNT;
         CHECK_VISIBLE;
        CHECK_READONLY;
-       CHECK_ACL(M_ACL_DELETE, _("delete message(s)"));
+        /* L10N: CHECK_ACL */
+       CHECK_ACL(M_ACL_DELETE, _("Cannot delete message(s)"));
 
        rc = mutt_thread_set_flag (CURHDR, M_DELETE, 1,
                                   op == OP_DELETE_THREAD ? 0 : 1);
@@ -1995,7 +2008,8 @@
         CHECK_VISIBLE;
        CHECK_READONLY;
        CHECK_ATTACH;
-       CHECK_ACL(M_ACL_INSERT, _("edit message"));
+        /* L10N: CHECK_ACL */
+       CHECK_ACL(M_ACL_INSERT, _("Cannot edit message"));
 
        if (option (OPTPGPAUTODEC) && (tag || !(CURHDR->security & 
PGP_TRADITIONAL_CHECKED)))
          mutt_check_traditional_pgp (tag ? NULL : CURHDR, &menu->redraw);
@@ -2126,7 +2140,8 @@
        CHECK_MSGCOUNT;
        CHECK_VISIBLE;
        CHECK_READONLY;
-       CHECK_ACL(M_ACL_SEEN, _("mark message(s) as read"));
+        /* L10N: CHECK_ACL */
+       CHECK_ACL(M_ACL_SEEN, _("Cannot mark message(s) as read"));
 
        rc = mutt_thread_set_flag (CURHDR, M_READ, 1,
                                   op == OP_MAIN_READ_THREAD ? 0 : 1);
@@ -2221,7 +2236,8 @@
        CHECK_MSGCOUNT;
         CHECK_VISIBLE;
        CHECK_READONLY;
-       CHECK_ACL(M_ACL_DELETE, _("undelete message"));
+        /* L10N: CHECK_ACL */
+       CHECK_ACL(M_ACL_DELETE, _("Cannot undelete message"));
 
        if (tag)
        {
@@ -2248,7 +2264,8 @@
        CHECK_MSGCOUNT;
         CHECK_VISIBLE;
        CHECK_READONLY;
-       CHECK_ACL(M_ACL_DELETE, _("undelete message(s)"));
+        /* L10N: CHECK_ACL */
+       CHECK_ACL(M_ACL_DELETE, _("Cannot undelete message(s)"));
 
        rc = mutt_thread_set_flag (CURHDR, M_DELETE, 0,
                                   op == OP_UNDELETE_THREAD ? 0 : 1);
diff -r 590ff6eebe1a -r 41af5a753d6f doc/devel-notes.txt
--- a/doc/devel-notes.txt       Wed Sep 30 11:21:06 2015 +0800
+++ b/doc/devel-notes.txt       Sun Oct 18 20:05:37 2015 +0800
@@ -196,6 +196,10 @@
   from the times when this was an iso-8859-1 source code tree,
   please feel free to fix them.
 
+- prefix translator comments with L10N:
+  /* L10N: this is a translator comment */
+  puts(_("String to translate));
+
 Documentation
 -------------
 
diff -r 590ff6eebe1a -r 41af5a753d6f edit.c
--- a/edit.c    Wed Sep 30 11:21:06 2015 +0800
+++ b/edit.c    Sun Oct 18 20:05:37 2015 +0800
@@ -393,6 +393,11 @@
          be_print_header (msg->env);
          for (i = 0; i < buflen; i++)
            addstr (buf[i]);
+          /* L10N:
+             This entry is shown AFTER the message content,
+             not IN the middle of the content.
+             So it doesn't mean "(message will continue)"
+             but means "(press any key to continue using mutt)". */
          addstr (_("(continue)\n"));
          break;
        case 'q':
diff -r 590ff6eebe1a -r 41af5a753d6f editmsg.c
--- a/editmsg.c Wed Sep 30 11:21:06 2015 +0800
+++ b/editmsg.c Sun Oct 18 20:05:37 2015 +0800
@@ -146,6 +146,7 @@
   if (mx_open_mailbox (ctx->path, M_APPEND, &tmpctx) == NULL)
   {
     rc = -1;
+    /* L10N: %s is from strerror(errno) */
     mutt_error (_("Can't append to folder: %s"), strerror (errno));
     goto bail;
   }
diff -r 590ff6eebe1a -r 41af5a753d6f hdrline.c
--- a/hdrline.c Wed Sep 30 11:21:06 2015 +0800
+++ b/hdrline.c Sun Oct 18 20:05:37 2015 +0800
@@ -219,6 +219,8 @@
  * %N = score
  * %O = like %L, except using address instead of name
  * %P = progress indicator for builtin pager
+ * %r = comma separated list of To: recipients
+ * %R = comma separated list of Cc: recipients
  * %s = subject
  * %S = short message status (e.g., N/O/D/!/r/-)
  * %t = `to:' field (recipients)
@@ -548,6 +550,22 @@
       strfcpy(dest, NONULL(hfi->pager_progress), destlen);
       break;
 
+    case 'r':
+      buf2[0] = 0;
+      rfc822_write_address(buf2, sizeof(buf2), hdr->env->to, 1);
+      if (optional && buf2[0] == '\0')
+        optional = 0;
+      mutt_format_s (dest, destlen, prefix, buf2);
+      break;
+
+    case 'R':
+      buf2[0] = 0;
+      rfc822_write_address(buf2, sizeof(buf2), hdr->env->cc, 1);
+      if (optional && buf2[0] == '\0')
+        optional = 0;
+      mutt_format_s (dest, destlen, prefix, buf2);
+      break;
+
     case 's':
       
       if (flags & M_FORMAT_TREE && !hdr->collapsed)
diff -r 590ff6eebe1a -r 41af5a753d6f imap/browse.c
--- a/imap/browse.c     Wed Sep 30 11:21:06 2015 +0800
+++ b/imap/browse.c     Sun Oct 18 20:05:37 2015 +0800
@@ -43,8 +43,8 @@
   IMAP_DATA* idata;
   IMAP_LIST list;
   char buf[LONG_STRING];
-  char buf2[LONG_STRING];
   char mbox[LONG_STRING];
+  char munged_mbox[LONG_STRING];
   char list_cmd[5];
   int n;
   int nsup;
@@ -72,13 +72,7 @@
   if (mx.mbox && mx.mbox[0] != '\0')
   {
     int rc;
-    char *ptr;
     imap_fix_path (idata, mx.mbox, mbox, sizeof (mbox));
-    ptr = safe_strdup (mbox);
-    imap_utf7_encode (&ptr);
-    mbox[sizeof (mbox) - 1] = '\0';
-    strncpy (mbox, ptr, sizeof (mbox) - 1);
-    FREE (&ptr);
     n = mutt_strlen (mbox);
 
     dprint (3, (debugfile, "imap_browse: mbox: %s\n", mbox));
@@ -87,7 +81,8 @@
      * aren't already going to */
     if (mbox[n-1] != idata->delim)
     {
-      snprintf (buf, sizeof (buf), "%s \"\" \"%s\"", list_cmd, mbox);
+      imap_munge_mbox_name (idata, munged_mbox, sizeof (munged_mbox), mbox);
+      snprintf (buf, sizeof (buf), "%s \"\" %s", list_cmd, munged_mbox);
       imap_cmd_start (idata, buf);
       idata->cmdtype = IMAP_CT_LIST;
       idata->cmddata = &list;
@@ -180,9 +175,9 @@
 
   dprint (3, (debugfile, "imap_browse: Quoting mailbox scan: %s -> ", mbox));
   snprintf (buf, sizeof (buf), "%s%%", mbox);
-  imap_quote_string (buf2, sizeof (buf2), buf);
-  dprint (3, (debugfile, "%s\n", buf2));
-  snprintf (buf, sizeof (buf), "%s \"\" %s", list_cmd, buf2);
+  imap_munge_mbox_name (idata, munged_mbox, sizeof (munged_mbox), buf);
+  dprint (3, (debugfile, "%s\n", munged_mbox));
+  snprintf (buf, sizeof (buf), "%s \"\" %s", list_cmd, munged_mbox);
   if (browse_add_list_result (idata, buf, state, 0))
     goto fail;
 
@@ -392,8 +387,12 @@
   return rc == IMAP_CMD_OK ? 0 : -1;
 }
 
-/* imap_add_folder: add a folder name to the browser list, formatting it as
- *   necessary. */
+/* imap_add_folder:
+ * add a folder name to the browser list, formatting it as necessary.
+ *
+ * The folder parameter should already be 'unmunged' via
+ * imap_unmunge_mbox_name().
+ */
 static void imap_add_folder (char delim, char *folder, int noselect,
   int noinferiors, struct browser_state *state, short isparent)
 {
@@ -404,8 +403,6 @@
   if (imap_parse_path (state->folder, &mx))
     return;
 
-  imap_unmunge_mbox_name (folder);
-
   if (state->entrylen + 1 == state->entrymax)
   {
     safe_realloc (&state->entry,
diff -r 590ff6eebe1a -r 41af5a753d6f imap/command.c
--- a/imap/command.c    Wed Sep 30 11:21:06 2015 +0800
+++ b/imap/command.c    Sun Oct 18 20:05:37 2015 +0800
@@ -51,6 +51,7 @@
 static void cmd_parse_myrights (IMAP_DATA* idata, const char* s);
 static void cmd_parse_search (IMAP_DATA* idata, const char* s);
 static void cmd_parse_status (IMAP_DATA* idata, char* s);
+static void cmd_parse_enabled (IMAP_DATA* idata, const char* s);
 
 static const char * const Capabilities[] = {
   "IMAP4",
@@ -65,6 +66,7 @@
   "LOGINDISABLED",
   "IDLE",
   "SASL-IR",
+  "ENABLE",
 
   NULL
 };
@@ -522,6 +524,8 @@
     cmd_parse_search (idata, s);
   else if (ascii_strncasecmp ("STATUS", s, 6) == 0)
     cmd_parse_status (idata, s);
+  else if (ascii_strncasecmp ("ENABLED", s, 7) == 0)
+    cmd_parse_enabled (idata, s);
   else if (ascii_strncasecmp ("BYE", s, 3) == 0)
   {
     dprint (2, (debugfile, "Handling BYE\n"));
@@ -728,7 +732,7 @@
   }
   else
   {
-    imap_unmunge_mbox_name (s);
+    imap_unmunge_mbox_name (idata, s);
     list->name = s;
   }
 
@@ -917,7 +921,7 @@
   {
     s = imap_next_word (mailbox);
     *(s - 1) = '\0';
-    imap_unmunge_mbox_name (mailbox);
+    imap_unmunge_mbox_name (idata, mailbox);
   }
 
   status = imap_mboxcache_get (idata, mailbox, 1);
@@ -1022,3 +1026,16 @@
     FREE (&mx.mbox);
   }
 }
+
+/* cmd_parse_enabled: record what the server has enabled */
+static void cmd_parse_enabled (IMAP_DATA* idata, const char* s)
+{
+  dprint (2, (debugfile, "Handling ENABLED\n"));
+
+  while ((s = imap_next_word ((char*)s)) && *s != '\0')
+  {
+    if (ascii_strncasecmp(s, "UTF8=ACCEPT", 11) == 0 ||
+        ascii_strncasecmp(s, "UTF8=ONLY", 9) == 0)
+      idata->unicode = 1;
+  }
+}
diff -r 590ff6eebe1a -r 41af5a753d6f imap/imap.c
--- a/imap/imap.c       Wed Sep 30 11:21:06 2015 +0800
+++ b/imap/imap.c       Sun Oct 18 20:05:37 2015 +0800
@@ -92,7 +92,7 @@
     return 0;
   }
 
-  imap_munge_mbox_name (mbox, sizeof (mbox), mailbox);
+  imap_munge_mbox_name (idata, mbox, sizeof (mbox), mailbox);
 
   if (mutt_bit_isset (idata->capabilities, IMAP4REV1))
     snprintf (buf, sizeof (buf), "STATUS %s (UIDVALIDITY)", mbox);
@@ -117,7 +117,7 @@
 {
   char buf[LONG_STRING], mbox[LONG_STRING];
 
-  imap_munge_mbox_name (mbox, sizeof (mbox), mailbox);
+  imap_munge_mbox_name (idata, mbox, sizeof (mbox), mailbox);
   snprintf (buf, sizeof (buf), "CREATE %s", mbox);
 
   if (imap_exec (idata, buf, 0) != 0)
@@ -135,8 +135,8 @@
   char newmbox[LONG_STRING];
   char buf[LONG_STRING];
 
-  imap_munge_mbox_name (oldmbox, sizeof (oldmbox), mx->mbox);
-  imap_munge_mbox_name (newmbox, sizeof (newmbox), newname);
+  imap_munge_mbox_name (idata, oldmbox, sizeof (oldmbox), mx->mbox);
+  imap_munge_mbox_name (idata, newmbox, sizeof (newmbox), newname);
 
   snprintf (buf, sizeof (buf), "RENAME %s %s", oldmbox, newmbox);
 
@@ -162,7 +162,7 @@
     idata = ctx->data;
   }
 
-  imap_munge_mbox_name (mbox, sizeof (mbox), mx.mbox);
+  imap_munge_mbox_name (idata, mbox, sizeof (mbox), mx.mbox);
   snprintf (buf, sizeof (buf), "DELETE %s", mbox);
 
   if (imap_exec ((IMAP_DATA*) idata, buf, 0) != 0)
@@ -386,6 +386,9 @@
   {
     /* capabilities may have changed */
     imap_exec (idata, "CAPABILITY", IMAP_CMD_QUEUE);
+    /* enable RFC6855, if the server supports that */
+    if (mutt_bit_isset (idata->capabilities, ENABLE))
+      imap_exec (idata, "ENABLE UTF8=ACCEPT", IMAP_CMD_QUEUE);
     /* get root delimiter, '/' as default */
     idata->delim = '/';
     imap_exec (idata, "LIST \"\" \"\"", IMAP_CMD_QUEUE);
@@ -596,7 +599,7 @@
   idata->newMailCount = 0;
 
   mutt_message (_("Selecting %s..."), idata->mailbox);
-  imap_munge_mbox_name (buf, sizeof(buf), idata->mailbox);
+  imap_munge_mbox_name (idata, buf, sizeof(buf), idata->mailbox);
 
   /* pipeline ACL test */
   if (mutt_bit_isset (idata->capabilities, ACL))
@@ -1521,7 +1524,7 @@
     if (!lastdata)
       lastdata = idata;
 
-    imap_munge_mbox_name (munged, sizeof (munged), name);
+    imap_munge_mbox_name (idata, munged, sizeof (munged), name);
     snprintf (command, sizeof (command),
              "STATUS %s (UIDNEXT UIDVALIDITY UNSEEN RECENT)", munged);
 
@@ -1569,9 +1572,9 @@
   else if (mutt_bit_isset(idata->capabilities,IMAP4REV1) ||
           mutt_bit_isset(idata->capabilities,STATUS))
   {
-    imap_munge_mbox_name (mbox, sizeof(mbox), buf);
+    imap_munge_mbox_name (idata, mbox, sizeof(mbox), buf);
     snprintf (buf, sizeof (buf), "STATUS %s (%s)", mbox, "MESSAGES");
-    imap_unmunge_mbox_name (mbox);
+    imap_unmunge_mbox_name (idata, mbox);
   }
   else
     /* Server does not support STATUS, and this is not the current mailbox.
@@ -1851,14 +1854,14 @@
     mutt_message (_("Subscribing to %s..."), buf);
   else
     mutt_message (_("Unsubscribing from %s..."), buf);
-  imap_munge_mbox_name (mbox, sizeof(mbox), buf);
+  imap_munge_mbox_name (idata, mbox, sizeof(mbox), buf);
 
   snprintf (buf, sizeof (buf), "%sSUBSCRIBE %s", subscribe ? "" : "UN", mbox);
 
   if (imap_exec (idata, buf, 0) < 0)
     goto fail;
 
-  imap_unmunge_mbox_name(mx.mbox);
+  imap_unmunge_mbox_name(idata, mx.mbox);
   if (subscribe)
     mutt_message (_("Subscribed to %s"), mx.mbox);
   else
diff -r 590ff6eebe1a -r 41af5a753d6f imap/imap_private.h
--- a/imap/imap_private.h       Wed Sep 30 11:21:06 2015 +0800
+++ b/imap/imap_private.h       Sun Oct 18 20:05:37 2015 +0800

Reply via email to