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