changeset: 6543:f99561e22a99
user:      Kevin McCarthy <ke...@8t8.us>
date:      Fri Jan 01 09:48:51 2016 -0800
link:      http://dev.mutt.org/hg/mutt/rev/f99561e22a99

Fix segfault when deleting and reusing attachment slots. (closes #3800)

When attachments are deleted, delete_attachment() slides the entries
down in the idx array, but forgets to NULL out the last vacated slot.

If more attachments are added later on via OP_COMPOSE_EDIT_HEADERS and
the Attach: pseudo-header, mutt_gen_attach_list() will attempt to
re-use the ATTACHPTR in that last slot because it wasn't set to NULL.
This will be pointing to freed memory and likely segfault (at best).

changeset: 6544:c6471322c68f
user:      Kevin McCarthy <ke...@8t8.us>
date:      Fri Jan 01 09:52:33 2016 -0800
link:      http://dev.mutt.org/hg/mutt/rev/c6471322c68f

merge stable

diffs (truncated from 15167 to 950 lines):

diff -r f542783e257d -r c6471322c68f Makefile.am
--- a/Makefile.am       Tue Dec 08 09:11:30 2015 -0800
+++ b/Makefile.am       Fri Jan 01 09:52:33 2016 -0800
@@ -33,7 +33,7 @@
        rfc822.c rfc1524.c rfc2047.c rfc2231.c rfc3676.c \
        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 mbyte.c \
+       muttlib.c editmsg.c mbyte.c mutt_idna.c \
        url.c ascii.c crypt-mod.c crypt-mod.h safe_asprintf.c
 
 nodist_mutt_SOURCES = $(BUILT_SOURCES)
@@ -53,7 +53,7 @@
 EXTRA_mutt_SOURCES = account.c bcache.c crypt-gpgme.c crypt-mod-pgp-classic.c \
        crypt-mod-pgp-gpgme.c crypt-mod-smime-classic.c \
        crypt-mod-smime-gpgme.c dotlock.c gnupgparse.c hcache.c md5.c \
-       mutt_idna.c mutt_sasl.c mutt_socket.c mutt_ssl.c mutt_ssl_gnutls.c \
+       mutt_sasl.c mutt_socket.c mutt_ssl.c mutt_ssl_gnutls.c \
        mutt_tunnel.c pgp.c pgpinvoke.c pgpkey.c pgplib.c pgpmicalg.c \
        pgppacket.c pop.c pop_auth.c pop_lib.c remailer.c resize.c sha1.c \
        smime.c smtp.c utf8.c wcwidth.c \
diff -r f542783e257d -r c6471322c68f UPDATING
--- a/UPDATING  Tue Dec 08 09:11:30 2015 -0800
+++ b/UPDATING  Fri Jan 01 09:52:33 2016 -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 f542783e257d -r c6471322c68f alias.c
--- a/alias.c   Tue Dec 08 09:11:30 2015 -0800
+++ b/alias.c   Fri Jan 01 09:52:33 2016 -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;
 
@@ -290,7 +290,7 @@
   else
     buf[0] = 0;
 
-  mutt_addrlist_to_idna (adr, NULL);
+  mutt_addrlist_to_intl (adr, NULL);
   
   do
   {
@@ -302,7 +302,7 @@
     
     if((new->addr = rfc822_parse_adrlist (new->addr, buf)) == NULL)
       BEEP ();
-    if (mutt_addrlist_to_idna (new->addr, &err))
+    if (mutt_addrlist_to_intl (new->addr, &err))
     {
       mutt_error (_("Error: '%s' is a bad IDN."), err);
       mutt_sleep (2);
diff -r f542783e257d -r c6471322c68f browser.c
--- a/browser.c Tue Dec 08 09:11:30 2015 -0800
+++ b/browser.c Fri Jan 01 09:52:33 2016 -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 f542783e257d -r c6471322c68f commands.c
--- a/commands.c        Tue Dec 08 09:11:30 2015 -0800
+++ b/commands.c        Fri Jan 01 09:52:33 2016 -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
@@ -294,7 +294,7 @@
 
   adr = mutt_expand_aliases (adr);
 
-  if (mutt_addrlist_to_idna (adr, &err) < 0)
+  if (mutt_addrlist_to_intl (adr, &err) < 0)
   {
     mutt_error (_("Bad IDN: '%s'"), err);
     FREE (&err);
diff -r f542783e257d -r c6471322c68f compose.c
--- a/compose.c Tue Dec 08 09:11:30 2015 -0800
+++ b/compose.c Fri Jan 01 09:52:33 2016 -0800
@@ -292,7 +292,7 @@
     return (REDRAW_FULL);
   }
 
-  if (mutt_addrlist_to_idna (*addr, &err) != 0)
+  if (mutt_addrlist_to_intl (*addr, &err) != 0)
   {
     mutt_error (_("Warning: '%s' is a bad IDN."), err);
     mutt_refresh();
@@ -338,6 +338,7 @@
   FREE (&idx[x]);
   for (; x < *idxlen - 1; x++)
     idx[x] = idx[x+1];
+  idx[*idxlen - 1] = NULL;
   menu->max = --(*idxlen);
   
   return (0);
@@ -606,7 +607,7 @@
          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))
+         if (mutt_env_to_intl (msg->env, &tag, &err))
          {
            mutt_error (_("Bad IDN in \"%s\": '%s'"), tag, err);
            FREE (&err);
@@ -754,7 +755,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 +1024,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 +1237,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 +1270,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 f542783e257d -r c6471322c68f configure.ac
--- a/configure.ac      Tue Dec 08 09:11:30 2015 -0800
+++ b/configure.ac      Fri Jan 01 09:52:33 2016 -0800
@@ -1196,7 +1196,6 @@
 
     AC_SEARCH_LIBS([stringprep_check_version], [idn], [
       AC_DEFINE([HAVE_LIBIDN], 1, [Define to 1 if you have the GNU idn 
library])
-      MUTT_LIB_OBJECTS="$MUTT_LIB_OBJECTS mutt_idna.o"
       MUTTLIBS="$MUTTLIBS $LIBS"
 
       LIBS="$LIBS $LIBICONV"
diff -r f542783e257d -r c6471322c68f contrib/smime.rc
--- a/contrib/smime.rc  Tue Dec 08 09:11:30 2015 -0800
+++ b/contrib/smime.rc  Fri Jan 01 09:52:33 2016 -0800
@@ -65,8 +65,12 @@
 # Encrypt a message.  Input file is a MIME entity.
 set smime_encrypt_command="openssl smime -encrypt -%a -outform DER -in %f %c"
 
+# Algorithm for the signature message digest.
+# Valid choices are md5, sha1, sha224, sha256, sha384, sha512.
+set smime_sign_digest_alg="sha256"
+
 # Sign.
-set smime_sign_command="openssl smime -sign -signer %c -inkey %k -passin stdin 
-in %f -certfile %i -outform DER"
+set smime_sign_command="openssl smime -sign -md %d -signer %c -inkey %k 
-passin stdin -in %f -certfile %i -outform DER"
 
 
 
@@ -89,7 +93,7 @@
 
 # Sign.  If you wish to NOT include the certificate your CA used in signing
 # your public key, use this command instead.
-# set smime_sign_command="openssl smime -sign -signer %c -inkey %k -passin 
stdin -in %f -outform DER"
+# set smime_sign_command="openssl smime -sign -md %d -signer %c -inkey %k 
-passin stdin -in %f -outform DER"
 #
 # In order to verify the signature only and skip checking the certificate 
chain:
 #
diff -r f542783e257d -r c6471322c68f crypt-gpgme.c
--- a/crypt-gpgme.c     Tue Dec 08 09:11:30 2015 -0800
+++ b/crypt-gpgme.c     Fri Jan 01 09:52:33 2016 -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 f542783e257d -r c6471322c68f crypt.c
--- a/crypt.c   Tue Dec 08 09:11:30 2015 -0800
+++ b/crypt.c   Fri Jan 01 09:52:33 2016 -0800
@@ -142,21 +142,34 @@
 
   if ((WithCrypto & APPLICATION_PGP) && ((msg->security & PGPINLINE) == 
PGPINLINE))
   {
-    /* they really want to send it inline... go for it */
-    if (!isendwin ()) mutt_endwin _("Invoking PGP...");
-    pbody = crypt_pgp_traditional_encryptsign (msg->content, flags, keylist);
-    if (pbody)
+    if ((msg->content->type != TYPETEXT) ||
+        ascii_strcasecmp (msg->content->subtype, "plain"))
     {
-      msg->content = pbody;
-      return 0;
+      if ((i = query_quadoption (OPT_PGPMIMEAUTO,
+              _("Inline PGP can't be used with attachments.  Revert to 
PGP/MIME?"))) != M_YES)
+      {
+        mutt_error _("Mail not sent: inline PGP can't be used with 
attachments.");
+        return -1;
+      }
     }
+    else
+    {
+      /* they really want to send it inline... go for it */
+      if (!isendwin ()) mutt_endwin _("Invoking PGP...");
+      pbody = crypt_pgp_traditional_encryptsign (msg->content, flags, keylist);
+      if (pbody)
+      {
+        msg->content = pbody;
+        return 0;
+      }
 
-    /* otherwise inline won't work...ask for revert */
-    if ((i = query_quadoption (OPT_PGPMIMEAUTO, _("Message can't be sent 
inline.  Revert to using PGP/MIME?"))) != M_YES)
+      /* otherwise inline won't work...ask for revert */
+      if ((i = query_quadoption (OPT_PGPMIMEAUTO, _("Message can't be sent 
inline.  Revert to using PGP/MIME?"))) != M_YES)
       {
-       mutt_error _("Mail not sent.");
-       return -1;
+        mutt_error _("Mail not sent.");
+        return -1;
       }
+    }
 
     /* go ahead with PGP/MIME */
   }
@@ -879,9 +892,8 @@
 int mutt_signed_handler (BODY *a, STATE *s)
 {
   char tempfile[_POSIX_PATH_MAX];
-  char *protocol;
-  int protocol_major = TYPEOTHER;
-  char *protocol_minor = NULL;
+  int signed_type;
+  int inconsistent = 0;
   
   BODY *b = a;
   BODY **signatures = NULL;
@@ -893,29 +905,44 @@
   if (!WithCrypto)
     return -1;
 
-  protocol = mutt_get_parameter ("protocol", a->parameter);
   a = a->parts;
-
-  /* extract the protocol information */
-  
-  if (protocol)
+  signed_type = mutt_is_multipart_signed (b);
+  if (!signed_type)
   {
-    char major[STRING];
-    char *t;
-
-    if ((protocol_minor = strchr (protocol, '/'))) protocol_minor++;
-    
-    strfcpy (major, protocol, sizeof(major));
-    if((t = strchr(major, '/')))
-      *t = '\0';
-    
-    protocol_major = mutt_check_mime_type (major);
+    /* A null protocol value is already checked for in mutt_body_handler() */
+    state_printf (s, _("[-- Error: "
+                       "Unknown multipart/signed protocol %s! --]\n\n"),
+                  mutt_get_parameter ("protocol", b->parameter));
+    return mutt_body_handler (a, s);
   }
 
-  /* consistency check */
-
-  if (!(a && a->next && a->next->type == protocol_major && 
-      !mutt_strcasecmp (a->next->subtype, protocol_minor)))
+  if (!(a && a->next))
+    inconsistent = 1;
+  else
+  {
+    switch (signed_type)
+    {
+      case SIGN:
+        if (a->next->type != TYPEMULTIPART ||
+            ascii_strcasecmp (a->next->subtype, "mixed"))
+          inconsistent = 1;
+        break;
+      case PGPSIGN:
+        if (a->next->type != TYPEAPPLICATION ||
+            ascii_strcasecmp (a->next->subtype, "pgp-signature"))
+          inconsistent = 1;
+        break;
+      case SMIMESIGN:
+        if (a->next->type != TYPEAPPLICATION ||
+            (ascii_strcasecmp (a->next->subtype, "x-pkcs7-signature") &&
+             ascii_strcasecmp (a->next->subtype, "pkcs7-signature")))
+          inconsistent = 1;
+        break;
+      default:
+        inconsistent = 1;
+    }
+  }
+  if (inconsistent)
   {
     state_attach_puts (_("[-- Error: "
                          "Inconsistent multipart/signed structure! --]\n\n"),
@@ -923,27 +950,6 @@
     return mutt_body_handler (a, s);
   }
 
-  
-  if ((WithCrypto & APPLICATION_PGP)
-      && protocol_major == TYPEAPPLICATION
-      && !ascii_strcasecmp (protocol_minor, "pgp-signature"))
-    ;
-  else if ((WithCrypto & APPLICATION_SMIME)
-           && protocol_major == TYPEAPPLICATION
-          && !(ascii_strcasecmp (protocol_minor, "x-pkcs7-signature")
-              && ascii_strcasecmp (protocol_minor, "pkcs7-signature")))
-    ;
-  else if (protocol_major == TYPEMULTIPART
-          && !ascii_strcasecmp (protocol_minor, "mixed"))
-    ;
-  else
-  {
-    state_printf (s, _("[-- Error: "
-                       "Unknown multipart/signed protocol %s! --]\n\n"),
-                  protocol);
-    return mutt_body_handler (a, s);
-  }
-  
   if (s->flags & M_DISPLAY)
   {
     
diff -r f542783e257d -r c6471322c68f curs_lib.c
--- a/curs_lib.c        Tue Dec 08 09:11:30 2015 -0800
+++ b/curs_lib.c        Fri Jan 01 09:52:33 2016 -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 ();
 }
 
@@ -661,7 +713,8 @@
   {
     mutt_refresh ();
     ch  = mutt_getch ();
-    if (ch.ch < 0 || CI_is_return (ch.ch))
+    /* (ch.ch == 0) is technically possible.  Treat the same as < 0 (abort) */
+    if (ch.ch <= 0 || CI_is_return (ch.ch))
     {
       choice = -1;
       break;
diff -r f542783e257d -r c6471322c68f curs_main.c
--- a/curs_main.c       Tue Dec 08 09:11:30 2015 -0800
+++ b/curs_main.c       Fri Jan 01 09:52:33 2016 -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 f542783e257d -r c6471322c68f doc/devel-notes.txt
--- a/doc/devel-notes.txt       Tue Dec 08 09:11:30 2015 -0800
+++ b/doc/devel-notes.txt       Fri Jan 01 09:52:33 2016 -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 f542783e257d -r c6471322c68f doc/manual.xml.head
--- a/doc/manual.xml.head       Tue Dec 08 09:11:30 2015 -0800
+++ b/doc/manual.xml.head       Fri Jan 01 09:52:33 2016 -0800
@@ -1612,6 +1612,44 @@
 
 </sect3>
 
+<sect3 id="ff-pager">
+<title>Reformatting</title>
+
+<para>
+  Mutt has some support for reformatting when viewing and replying to
+  <literal>format=flowed</literal> messages.  In order to take advantage of 
these,
+  <link linkend="reflow-text">$reflow_text</link> must be set.
+</para>
+
+<itemizedlist>
+  <listitem>
+  <para>
+    Paragraphs are automatically reflowed and wrapped at a width specified
+    by <link linkend="reflow-wrap">$reflow_wrap</link>.
+  </para>
+  </listitem>
+  <listitem>
+  <para>
+    In its original format, the quoting style of 
<literal>format=flowed</literal>

Reply via email to