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");