changeset: 6512:590ff6eebe1a
user:      Kevin McCarthy <ke...@8t8.us>
date:      Wed Sep 30 11:21:06 2015 +0800
link:      http://dev.mutt.org/hg/mutt/rev/590ff6eebe1a

Fix oob reads when fgets returns "\0".  (closes #3776)

The ticket reported an out of bounds read in mutt_read_rfc822_line()
when a '\0' was embedded on its own line in the headers.  The function
assumed if fgets() didn't return NULL, then the string would have at
least one character.

I scanned the rest of the code and found three other places making the
same assumption for fgets.

Thanks to hanno for finding this with the "american fuzzy lop" tool.

changeset: 6513:d9142ca37afb
user:      Kevin McCarthy <ke...@8t8.us>
date:      Wed Sep 30 11:25:08 2015 +0800
link:      http://dev.mutt.org/hg/mutt/rev/d9142ca37afb

merge stable

changeset: 6514:909dfe9878ff
user:      Kevin McCarthy <ke...@8t8.us>
date:      Wed Sep 30 11:25:28 2015 +0800
link:      http://dev.mutt.org/hg/mutt/rev/909dfe9878ff

Fix chomp in smime_handle_cert_email.

During a review of the previous patch, Oswald Buddenhagen noticed two
of the fixed oob reads had another problem: they were "chomping" (the
newline) without verifying there actually was a newline at the end of
the string.

diffs (truncated from 10015 to 950 lines):

diff -r 40c47fcc9d17 -r 909dfe9878ff UPDATING
--- a/UPDATING  Sun Sep 06 07:40:06 2015 -0700
+++ b/UPDATING  Wed Sep 30 11:25:28 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 40c47fcc9d17 -r 909dfe9878ff alias.c
--- a/alias.c   Sun Sep 06 07:40:06 2015 -0700
+++ b/alias.c   Wed Sep 30 11:25:28 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 40c47fcc9d17 -r 909dfe9878ff compose.c
--- a/compose.c Sun Sep 06 07:40:06 2015 -0700
+++ b/compose.c Wed Sep 30 11:25:28 2015 +0800
@@ -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;
          }
diff -r 40c47fcc9d17 -r 909dfe9878ff crypt-gpgme.c
--- a/crypt-gpgme.c     Sun Sep 06 07:40:06 2015 -0700
+++ b/crypt-gpgme.c     Wed Sep 30 11:25:28 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 40c47fcc9d17 -r 909dfe9878ff curs_main.c
--- a/curs_main.c       Sun Sep 06 07:40:06 2015 -0700
+++ b/curs_main.c       Wed Sep 30 11:25:28 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; \
                }
 
@@ -874,7 +875,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 +905,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 +1049,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 +1357,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 +1609,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 +1638,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 +1676,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 +1931,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 +1973,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 +2015,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 +2147,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 +2243,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 +2271,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 40c47fcc9d17 -r 909dfe9878ff doc/devel-notes.txt
--- a/doc/devel-notes.txt       Sun Sep 06 07:40:06 2015 -0700
+++ b/doc/devel-notes.txt       Wed Sep 30 11:25:28 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 40c47fcc9d17 -r 909dfe9878ff edit.c
--- a/edit.c    Sun Sep 06 07:40:06 2015 -0700
+++ b/edit.c    Wed Sep 30 11:25:28 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 40c47fcc9d17 -r 909dfe9878ff editmsg.c
--- a/editmsg.c Sun Sep 06 07:40:06 2015 -0700
+++ b/editmsg.c Wed Sep 30 11:25:28 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 40c47fcc9d17 -r 909dfe9878ff hdrline.c
--- a/hdrline.c Sun Sep 06 07:40:06 2015 -0700
+++ b/hdrline.c Wed Sep 30 11:25:28 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 40c47fcc9d17 -r 909dfe9878ff imap/browse.c
--- a/imap/browse.c     Sun Sep 06 07:40:06 2015 -0700
+++ b/imap/browse.c     Wed Sep 30 11:25:28 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 40c47fcc9d17 -r 909dfe9878ff imap/command.c
--- a/imap/command.c    Sun Sep 06 07:40:06 2015 -0700
+++ b/imap/command.c    Wed Sep 30 11:25:28 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 40c47fcc9d17 -r 909dfe9878ff imap/imap.c
--- a/imap/imap.c       Sun Sep 06 07:40:06 2015 -0700
+++ b/imap/imap.c       Wed Sep 30 11:25:28 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 40c47fcc9d17 -r 909dfe9878ff imap/imap_private.h
--- a/imap/imap_private.h       Sun Sep 06 07:40:06 2015 -0700
+++ b/imap/imap_private.h       Wed Sep 30 11:25:28 2015 +0800
@@ -115,6 +115,7 @@
   LOGINDISABLED,               /*           LOGINDISABLED */
   IDLE,                         /* RFC 2177: IDLE */
   SASL_IR,                      /* SASL initial response draft */
+  ENABLE,                       /* RFC 5161 */
 
   CAPMAX
 };
@@ -144,7 +145,7 @@
 typedef struct
 {
   char* name;
-  
+
   char delim;
   /* if we end up storing a lot of these we could turn this into a bitfield */
   unsigned char noselect;
@@ -186,6 +187,10 @@
   char* buf;
   unsigned int blen;
   
+  /* If nonzero, we can send UTF-8, and the server will use UTF8 rather
+   * than mUTF7 */
+  int unicode;
+
   /* if set, the response parser will store results for complicated commands
    * here. */
   IMAP_COMMAND_TYPE cmdtype;
@@ -289,13 +294,13 @@
 void imap_qualify_path (char *dest, size_t len, IMAP_MBOX *mx, char* path);
 void imap_quote_string (char* dest, size_t slen, const char* src);
 void imap_unquote_string (char* s);
-void imap_munge_mbox_name (char *dest, size_t dlen, const char *src);
-void imap_unmunge_mbox_name (char *s);
+void imap_munge_mbox_name (IMAP_DATA *idata, char *dest, size_t dlen, const 
char *src);
+void imap_unmunge_mbox_name (IMAP_DATA *idata, char *s);
 int imap_wordcasecmp(const char *a, const char *b);
 
 /* utf7.c */
-void imap_utf7_encode (char **s);
-void imap_utf7_decode (char **s);
+void imap_utf_encode (IMAP_DATA *idata, char **s);
+void imap_utf_decode (IMAP_DATA *idata, char **s);
 
 #if USE_HCACHE
 /* typedef size_t (*hcache_keylen_t)(const char* fn); */
diff -r 40c47fcc9d17 -r 909dfe9878ff imap/message.c
--- a/imap/message.c    Sun Sep 06 07:40:06 2015 -0700
+++ b/imap/message.c    Wed Sep 30 11:25:28 2015 +0800
@@ -137,6 +137,8 @@
   }
   if (evalhc)
   {
+    /* L10N:
+       Comparing the cached data with the IMAP server's data */
     mutt_progress_init (&progress, _("Evaluating cache..."),
                        M_PROGRESS_MSG, ReadInc, msgend + 1);
 
@@ -642,7 +644,7 @@
   mutt_progress_init (&progressbar, _("Uploading message..."),
                      M_PROGRESS_SIZE, NetInc, len);
 
-  imap_munge_mbox_name (mbox, sizeof (mbox), mailbox);
+  imap_munge_mbox_name (idata, mbox, sizeof (mbox), mailbox);
   imap_make_date (internaldate, msg->received);
 
   imap_flags[0] = imap_flags[1] = 0;
@@ -773,7 +775,7 @@
   imap_fix_path (idata, mx.mbox, mbox, sizeof (mbox));
   if (!*mbox)
     strfcpy (mbox, "INBOX", sizeof (mbox));
-  imap_munge_mbox_name (mmbox, sizeof (mmbox), mbox);
+  imap_munge_mbox_name (idata, mmbox, sizeof (mmbox), mbox);
 
   /* loop in case of TRYCREATE */
   do
diff -r 40c47fcc9d17 -r 909dfe9878ff imap/utf7.c
--- a/imap/utf7.c       Sun Sep 06 07:40:06 2015 -0700
+++ b/imap/utf7.c       Wed Sep 30 11:25:28 2015 +0800
@@ -252,30 +252,40 @@
   return 0;
 }
 
-void imap_utf7_encode (char **s)
+void imap_utf_encode (IMAP_DATA *idata, char **s)
 {
   if (Charset)
   {
     char *t = safe_strdup (*s);
-    if (!mutt_convert_string (&t, Charset, "utf-8", 0))
+    if (t && !mutt_convert_string (&t, Charset, "utf-8", 0))
     {
-      char *u7 = utf8_to_utf7 (t, strlen (t), NULL, 0);
       FREE (s);                /* __FREE_CHECKED__ */
-      *s = u7;
+      if (idata->unicode)
+        *s = safe_strdup (t);
+      else
+        *s = utf8_to_utf7 (t, strlen (t), NULL, 0);
     }
     FREE (&t);
   }
 }
 
-void imap_utf7_decode (char **s)
+void imap_utf_decode (IMAP_DATA *idata, char **s)
 {
+  char *t;
+
   if (Charset)
   {
-    char *t = utf7_to_utf8 (*s, strlen (*s), 0, 0);
+    if (idata->unicode)
+      t = safe_strdup (*s);
+    else
+      t = utf7_to_utf8 (*s, strlen (*s), 0, 0);
+
     if (t && !mutt_convert_string (&t, "utf-8", Charset, 0))
     {
       FREE (s);                /* __FREE_CHECKED__ */
       *s = t;
     }
+    else
+      FREE (&t);
   }
 }
diff -r 40c47fcc9d17 -r 909dfe9878ff imap/util.c
--- a/imap/util.c       Sun Sep 06 07:40:06 2015 -0700
+++ b/imap/util.c       Wed Sep 30 11:25:28 2015 +0800
@@ -673,23 +673,24 @@
   *d = '\0';
 }
 
+
 /*
  * Quoting and UTF-7 conversion
  */
 
-void imap_munge_mbox_name (char *dest, size_t dlen, const char *src)
+void imap_munge_mbox_name (IMAP_DATA *idata, char *dest, size_t dlen, const 
char *src)
 {
   char *buf;
 
   buf = safe_strdup (src);
-  imap_utf7_encode (&buf);
+  imap_utf_encode (idata, &buf);
 
   imap_quote_string (dest, dlen, buf);
 
   FREE (&buf);
 }
 
-void imap_unmunge_mbox_name (char *s)
+void imap_unmunge_mbox_name (IMAP_DATA *idata, char *s)
 {
   char *buf;
 
@@ -698,7 +699,7 @@
   buf = safe_strdup (s);
   if (buf)
   {
-    imap_utf7_decode (&buf);
+    imap_utf_decode (idata, &buf);
     strncpy (s, buf, strlen (s));
   }
 
diff -r 40c47fcc9d17 -r 909dfe9878ff init.h
--- a/init.h    Sun Sep 06 07:40:06 2015 -0700
+++ b/init.h    Wed Sep 30 11:25:28 2015 +0800
@@ -1311,6 +1311,8 @@
   **            stashed the message: list name or recipient name
   **            if not sent to a list
   ** .dt %P .dd progress indicator for the built-in pager (how much of the 
file has been displayed)
+  ** .dt %r .dd comma separated list of ``To:'' recipients
+  ** .dt %R .dd comma separated list of ``Cc:'' recipients
   ** .dt %s .dd subject of the message
   ** .dt %S .dd status of the message (``N''/``D''/``d''/``!''/``r''/\(as)
   ** .dt %t .dd ``To:'' field (recipients)
diff -r 40c47fcc9d17 -r 909dfe9878ff mutt_ssl.c
--- a/mutt_ssl.c        Sun Sep 06 07:40:06 2015 -0700
+++ b/mutt_ssl.c        Wed Sep 30 11:25:28 2015 +0800
@@ -432,6 +432,10 @@
   if (!ssl_check_certificate (conn, ssldata))
     return -1;
 
+  /* L10N:
+     %1$s is version (e.g. "TLSv1.2")
+     %2$s is cipher_version (e.g. "TLSv1/SSLv3")
+     %3$s is cipher_name (e.g. "ECDHE-RSA-AES128-GCM-SHA256") */
   mutt_message (_("%s connection using %s (%s)"),
     SSL_get_version(ssldata->ssl), SSL_get_cipher_version (ssldata->ssl), 
SSL_get_cipher_name (ssldata->ssl));
   mutt_sleep (0);
diff -r 40c47fcc9d17 -r 909dfe9878ff muttlib.c
--- a/muttlib.c Sun Sep 06 07:40:06 2015 -0700
+++ b/muttlib.c Wed Sep 30 11:25:28 2015 +0800
@@ -968,6 +968,9 @@
     if (directory)
     {
       switch (mutt_multi_choice
+      /* L10N:
+         Means "The path you specified as the destination file is a directory."
+         See the msgid "Save to file: " (alias.c, recvattach.c) */
              (_("File is a directory, save under it? [(y)es, (n)o, (a)ll]"), 
_("yna")))
       {
        case 3:         /* all */
@@ -984,6 +987,9 @@
          return 1;
       }
     }
+    /* L10N:
+       Means "The path you specified as the destination file is a directory."
+       See the msgid "Save to file: " (alias.c, recvattach.c) */
     else if ((rc = mutt_yesorno (_("File is a directory, save under it?"), 
M_YES)) != M_YES)
       return (rc == M_NO) ? 1 : -1;
 
diff -r 40c47fcc9d17 -r 909dfe9878ff pager.c
--- a/pager.c   Sun Sep 06 07:40:06 2015 -0700
+++ b/pager.c   Wed Sep 30 11:25:28 2015 +0800
@@ -79,7 +79,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; \
                }
 
@@ -2353,7 +2354,8 @@
       case OP_DELETE:
        CHECK_MODE(IsHeader (extra));
        CHECK_READONLY;
-       CHECK_ACL(M_ACL_DELETE, _("delete message"));
+        /* L10N: CHECK_ACL */
+       CHECK_ACL(M_ACL_DELETE, _("Cannot delete message"));
 
        mutt_set_flag (Context, extra->hdr, M_DELETE, 1);
         if (option (OPTDELETEUNTAG))
@@ -2384,7 +2386,8 @@
       case OP_DELETE_SUBTHREAD:
        CHECK_MODE(IsHeader (extra));
        CHECK_READONLY;
-       CHECK_ACL(M_ACL_DELETE, _("delete message(s)"));
+        /* L10N: CHECK_ACL */
+       CHECK_ACL(M_ACL_DELETE, _("Cannot delete message(s)"));
 
        r = mutt_thread_set_flag (extra->hdr, M_DELETE, 1,
                                  ch == OP_DELETE_THREAD ? 0 : 1);
@@ -2504,7 +2507,8 @@
       case OP_FLAG_MESSAGE:
        CHECK_MODE(IsHeader (extra));
        CHECK_READONLY;
-       CHECK_ACL(M_ACL_WRITE, "flag message");
+        /* L10N: CHECK_ACL */
+       CHECK_ACL(M_ACL_WRITE, "Cannot flag message");

Reply via email to