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>