--- /dev/null
+From 1600dd189b064341b6579d8b07d0bf5f6ad80f8d Mon Sep 17 00:00:00 2001
+From: Kevin McCarthy <kevin@8t8.us>
+Date: Sun, 8 Sep 2019 12:09:51 -0700
+Subject: Rename browser fields to display_name and full_path
+
+Mailbox and Folder view don't make use of the desc field. They store
+an abbreviated version in the name field and expand it when selecting
+or testing it.
+
+IMAP stores the full URL in name, and stores an abbreviated
+version(possibly with a trailing slash) in the desc field.
+
+The asymetricity makes it awkward, and interferes with a smart-cursor
+option in the next commit. So instead rename the fields to
+"display_name" and "full_path".
+
+In Mailfox and Folder view, store the fully expanded path, which we
+have while iterating, in "full_path", and the shortened version in
+"display_name".
+
+Likewise in IMAP, store the full URL in "full_path" and the shortened
+version in "display_name".
+
+Simplify the code in browser.c to use the full_path instead of
+concatenating and expanding.
+
+Upstream-commit: https://gitlab.com/muttmua/mutt/commit/1600dd189b064341b6579d8b07d0bf5f6ad80f8d
+Co-authored-by:
+---
+ browser.c | 135 ++++++++++++++++----------------------------------
+ browser.h | 4 +-
+ imap/browse.c | 6 +--
+ 3 files changed, 49 insertions(+), 96 deletions(-)
+
+diff --git a/browser.c b/browser.c
+index 973e17ae..56ce75d2 100644
+--- a/browser.c
++++ b/browser.c
+@@ -72,8 +72,8 @@ static void destroy_state(struct browser_state *state)
+
+ for (c = 0; c < state->entrylen; c++)
+ {
+- FREE(& ((state->entry)[c].name));
+- FREE(& ((state->entry)[c].desc));
++ FREE(& ((state->entry)[c].display_name));
++ FREE(& ((state->entry)[c].full_path));
+ }
+ #ifdef USE_IMAP
+ FREE(&state->folder);
+@@ -86,7 +86,7 @@ static int browser_compare_subject(const void *a, const void *b)
+ struct folder_file *pa =(struct folder_file *) a;
+ struct folder_file *pb =(struct folder_file *) b;
+
+- int r = mutt_str_strcoll(pa->name, pb->name);
++ int r = mutt_str_strcoll(pa->display_name, pb->display_name);
+
+ return ((SortBrowser & SORT_REVERSE) ? -r : r);
+ }
+@@ -159,21 +159,14 @@ static void browser_sort(struct browser_state *state)
+ qsort(state->entry, state->entrylen, sizeof(struct folder_file), f);
+ }
+
+-static int link_is_dir(const char *folder, const char *path)
++static int link_is_dir(const char *full_path)
+ {
+ struct stat st;
+- struct Buffer *fullpath = NULL;
+ int retval = 0;
+
+- fullpath = mutt_buffer_pool_get();
+-
+- mutt_buffer_concat_path(fullpath, folder, path);
+-
+- if (stat(mutt_b2s(fullpath), &st) == 0)
++ if (stat(full_path, &st) == 0)
+ retval = S_ISDIR(st.st_mode);
+
+- mutt_buffer_pool_release(&fullpath);
+-
+ return retval;
+ }
+
+@@ -232,13 +225,7 @@ folder_format_str(char *dest, size_t destlen, size_t col, int cols, char op, co
+
+ case 'f':
+ {
+- char *s;
+-#ifdef USE_IMAP
+- if (folder->ff->imap)
+- s = NONULL(folder->ff->desc);
+- else
+-#endif
+- s = NONULL(folder->ff->name);
++ char *s = NONULL(folder->ff->display_name);
+
+ snprintf(fn, sizeof(fn), "%s%s", s,
+ folder->ff->local ?
+@@ -389,7 +376,8 @@ folder_format_str(char *dest, size_t destlen, size_t col, int cols, char op, co
+ }
+
+ static void add_folder(struct Menu *m, struct browser_state *state,
+- const char *name, const struct stat *s, struct Mailbox *b)
++ const char *display_name, const char *full_path,
++ const struct stat *s, struct Mailbox *b)
+ {
+ if (state->entrylen == state->entrymax)
+ {
+@@ -422,8 +410,8 @@ static void add_folder(struct Menu *m, struct browser_state *state,
+ (state->entry)[state->entrylen].msg_unread = b->msg_unread;
+ }
+
+-(state->entry)[state->entrylen].name = mutt_str_strdup(name);
+-(state->entry)[state->entrylen].desc = mutt_str_strdup(name);
++(state->entry)[state->entrylen].display_name = mutt_str_strdup(display_name);
++(state->entry)[state->entrylen].full_path = mutt_str_strdup(full_path);
+ #ifdef USE_IMAP
+ (state->entry)[state->entrylen].imap = 0;
+ #endif
+@@ -448,7 +436,7 @@ static int examine_directory(struct Menu *menu, struct browser_state *state,
+ struct stat s;
+ DIR *dp;
+ struct dirent *de;
+- struct Buffer *buffer = NULL;
++ struct Buffer *full_path = NULL;
+ struct Mailbox *tmp;
+
+ while (stat(d, &s) == -1)
+@@ -482,7 +470,7 @@ static int examine_directory(struct Menu *menu, struct browser_state *state,
+ return (-1);
+ }
+
+- buffer = mutt_buffer_pool_get();
++ full_path = mutt_buffer_pool_get();
+ init_state(state, menu);
+
+ while ((de = readdir(dp)) != NULL)
+@@ -495,8 +483,8 @@ static int examine_directory(struct Menu *menu, struct browser_state *state,
+ if (!((mutt/regex.c(C_Mask.regex, de->d_name, 0, NULL, 0) == 0) ^ C_Mask.not))
+ continue;
+
+- mutt_buffer_concat_path(buffer, d, de->d_name);
+- if (lstat(mutt_b2s(buffer), &s) == -1)
++ mutt_buffer_concat_path(full_path, d, de->d_name);
++ if (lstat(mutt_b2s(full_path), &s) == -1)
+ continue;
+
+ /* No size for directories or symlinks */
+@@ -506,7 +494,7 @@ static int examine_directory(struct Menu *menu, struct browser_state *state,
+ continue;
+
+ tmp = AllMailboxes;
+- while (tmp && mutt_str_strcmp(mutt_b2s(buffer), mutt_b2s(tmp->pathbuf)))
++ while (tmp && mutt_str_strcmp(mutt_b2s(full_path), mutt_b2s(tmp->pathbuf)))
+ tmp = tmp->next;
+ if (tmp && Context &&
+ !mutt_str_strcmp(tmp->realpath, Context->realpath))
+@@ -514,12 +502,12 @@ static int examine_directory(struct Menu *menu, struct browser_state *state,
+ tmp->msg_count = Context->msgcount;
+ tmp->msg_unread = Context->unread;
+ }
+- add_folder(menu, state, de->d_name, &s, tmp);
++ add_folder(menu, state, de->d_name, mutt_b2s(full_path), &s, tmp);
+ }
+ closedir(dp);
+ browser_sort(state);
+
+- mutt_buffer_pool_release(&buffer);
++ mutt_buffer_pool_release(&full_path);
+ return 0;
+ }
+
+@@ -554,14 +542,14 @@ static int examine_mailboxes(struct Menu *menu, struct browser_state *state)
+ #ifdef USE_IMAP
+ if (mx_is_imap(mutt_b2s(tmp->pathbuf)))
+ {
+- add_folder(menu, state, mutt_b2s(mailbox), NULL, tmp);
++ add_folder(menu, state, mutt_b2s(mailbox), mutt_b2s(tmp->pathbuf), NULL, tmp);
+ continue;
+ }
+ #endif
+ #ifdef USE_POP
+ if (mx_is_pop(mutt_b2s(tmp->pathbuf)))
+ {
+- add_folder(menu, state, mutt_b2s(mailbox), NULL, tmp);
++ add_folder(menu, state, mutt_b2s(mailbox), mutt_b2s(tmp->pathbuf), NULL, tmp);
+ continue;
+ }
+ #endif
+@@ -586,7 +574,7 @@ static int examine_mailboxes(struct Menu *menu, struct browser_state *state)
+ s.st_mtime = st2.st_mtime;
+ }
+
+- add_folder(menu, state, mutt_b2s(mailbox), &s, tmp);
++ add_folder(menu, state, mutt_b2s(mailbox), mutt_b2s(tmp->pathbuf), &s, tmp);
+ }
+ while ((tmp = tmp->next));
+ browser_sort(state);
+@@ -598,7 +586,7 @@ static int examine_mailboxes(struct Menu *menu, struct browser_state *state)
+
+ static int select_file_search(struct Menu *menu, regex_t *re, int n)
+ {
+- return (mutt/regex.c(re, ((struct folder_file *) menu->data)[n].name, 0, NULL, 0));
++ return (mutt/regex.c(re, ((struct folder_file *) menu->data)[n].display_name, 0, NULL, 0));
+ }
+
+ static void folder_entry(char *s, size_t slen, struct Menu *menu, int num)
+@@ -655,7 +643,7 @@ static int file_tag(struct Menu *menu, int n, int m)
+ struct folder_file *ff = & (((struct folder_file *)menu->data)[n]);
+ int ot;
+ if (S_ISDIR(ff->mode) ||
+- (S_ISLNK(ff->mode) && link_is_dir(mutt_b2s(LastDir), ff->name)))
++ (S_ISLNK(ff->mode) && link_is_dir(ff->full_path)))
+ {
+ mutt_error _("Can't attach a directory!");
+ return 0;
+@@ -832,28 +820,14 @@ void _mutt_buffer_select_file(struct Buffer *f, int flags, char ***files, int *numfile
+
+ if (S_ISDIR(state.entry[menu->current].mode) ||
+ (S_ISLNK(state.entry[menu->current].mode) &&
+- link_is_dir(mutt_b2s(LastDir), state.entry[menu->current].name))
++ link_is_dir(state.entry[menu->current].full_path))
+ #ifdef USE_IMAP
+ || state.entry[menu->current].inferiors
+ #endif
+ )
+ {
+- /* make sure this isn't a MH or maildir mailbox */
+- if (mailbox)
+- {
+- mutt_buffer_strcpy(buf, state.entry[menu->current].name);
+- mutt_buffer_expand_path(buf);
+- }
+-#ifdef USE_IMAP
+- else if (state.imap_browse)
+- {
+- mutt_buffer_strcpy(buf, state.entry[menu->current].name);
+- }
+-#endif
+- else
+- mutt_buffer_concat_path(buf, mutt_b2s(LastDir), state.entry[menu->current].name);
+-
+- if (op == OP_DESCEND_DIRECTORY || (mx_get_magic(mutt_b2s(buf)) <= 0)
++ if (op == OP_DESCEND_DIRECTORY
++ || (mx_get_magic(state.entry[menu->current].full_path) <= 0)
+ #ifdef USE_IMAP
+ || state.entry[menu->current].inferiors
+ #endif
+@@ -862,7 +836,7 @@ void _mutt_buffer_select_file(struct Buffer *f, int flags, char ***files, int *numfile
+ /* save the old directory */
+ mutt_buffer_strcpy(OldLastDir, mutt_b2s(LastDir));
+
+- if (mutt_str_strcmp(state.entry[menu->current].name, "..") == 0)
++ if (mutt_str_strcmp(state.entry[menu->current].display_name, "..") == 0)
+ {
+ size_t lastdirlen = mutt_buffer_len(LastDir);
+
+@@ -893,19 +867,18 @@ void _mutt_buffer_select_file(struct Buffer *f, int flags, char ***files, int *numfile
+ }
+ else if (mailbox)
+ {
+- mutt_buffer_strcpy(LastDir, state.entry[menu->current].name);
+- mutt_buffer_expand_path(LastDir);
++ mutt_buffer_strcpy(LastDir, state.entry[menu->current].full_path);
+ }
+ #ifdef USE_IMAP
+ else if (state.imap_browse)
+ {
+ struct Url url;
+
+- mutt_buffer_strcpy(LastDir, state.entry[menu->current].name);
++ mutt_buffer_strcpy(LastDir, state.entry[menu->current].full_path);
+ /* tack on delimiter here */
+
+ /* special case "" needs no delimiter */
+- url_parse(&url, state.entry[menu->current].name);
++ url_parse(&url, state.entry[menu->current].full_path);
+ if (url.path &&
+ (state.entry[menu->current].delim != '\0'))
+ {
+@@ -915,8 +888,7 @@ void _mutt_buffer_select_file(struct Buffer *f, int flags, char ***files, int *numfile
+ #endif
+ else
+ {
+- mutt_buffer_concat_path(tmp, mutt_b2s(LastDir), state.entry[menu->current].name);
+- mutt_buffer_strcpy(LastDir, mutt_b2s(tmp));
++ mutt_buffer_strcpy(LastDir, state.entry[menu->current].full_path);
+ }
+
+ destroy_state(&state);
+@@ -955,21 +927,11 @@ void _mutt_buffer_select_file(struct Buffer *f, int flags, char ***files, int *numfile
+ }
+ else if (op == OP_DESCEND_DIRECTORY)
+ {
+- mutt_error(_("%s is not a directory."), state.entry[menu->current].name);
++ mutt_error(_("%s is not a directory."), state.entry[menu->current].display_name);
+ break;
+ }
+
+- if (mailbox)
+- {
+- mutt_buffer_strcpy(f, state.entry[menu->current].name);
+- mutt_buffer_expand_path(f);
+- }
+-#ifdef USE_IMAP
+- else if (state.imap_browse)
+- mutt_buffer_strcpy(f, state.entry[menu->current].name);
+-#endif
+- else
+- mutt_buffer_concat_path(f, mutt_b2s(LastDir), state.entry[menu->current].name);
++ mutt_buffer_strcpy(f, state.entry[menu->current].full_path);
+
+ /* Fall through to OP_EXIT */
+
+@@ -984,22 +946,14 @@ void _mutt_buffer_select_file(struct Buffer *f, int flags, char ***files, int *numfile
+ *numfiles = menu->tagged;
+ tfiles = mutt_mem_calloc(*numfiles, sizeof(char *));
+ for (i = 0, j = 0; i < state.entrylen; i++)
+- {
+- struct folder_file ff = state.entry[i];
+- if (ff.tagged)
+- {
+- mutt_buffer_concat_path(tmp, mutt_b2s(LastDir), ff.name);
+- mutt_buffer_expand_path(tmp);
+- tfiles[j++] = mutt_str_strdup(mutt_b2s(tmp));
+- }
+- }
++ if (state.entry[i].tagged)
++ tfiles[j++] = mutt_str_strdup(state.entry[i].full_path);
+ *files = tfiles;
+ }
+ else if ((mutt_b2s(f))[0]) /* no tagged entries. return selected entry */
+ {
+ *numfiles = 1;
+ tfiles = mutt_mem_calloc(*numfiles, sizeof(char *));
+- mutt_buffer_expand_path(f);
+ tfiles[0] = mutt_str_strdup(mutt_b2s(f));
+ *files = tfiles;
+ }
+@@ -1010,16 +964,16 @@ void _mutt_buffer_select_file(struct Buffer *f, int flags, char ***files, int *numfile
+
+ case OP_BROWSER_TELL:
+ if (state.entrylen)
+- mutt_message("%s", state.entry[menu->current].name);
++ mutt_message("%s", state.entry[menu->current].display_name);
+ break;
+
+ #ifdef USE_IMAP
+ case OP_BROWSER_SUBSCRIBE:
+- imap_subscribe(state.entry[menu->current].name, 1);
++ imap_subscribe(state.entry[menu->current].full_path, 1);
+ break;
+
+ case OP_BROWSER_UNSUBSCRIBE:
+- imap_subscribe(state.entry[menu->current].name, 0);
++ imap_subscribe(state.entry[menu->current].full_path, 0);
+ break;
+
+ case OP_BROWSER_TOGGLE_LSUB:
+@@ -1062,7 +1016,7 @@ void _mutt_buffer_select_file(struct Buffer *f, int flags, char ***files, int *numfile
+ {
+ int nentry = menu->current;
+
+- if (imap_mailbox_rename(state.entry[nentry].name) >= 0)
++ if (imap_mailbox_rename(state.entry[nentry].full_path) >= 0)
+ {
+ destroy_state(&state);
+ init_state(&state, NULL);
+@@ -1086,7 +1040,7 @@ void _mutt_buffer_select_file(struct Buffer *f, int flags, char ***files, int *numfile
+ IMAP_MBOX mx;
+ int nentry = menu->current;
+
+- imap_parse_path(state.entry[nentry].name, &mx);
++ imap_parse_path(state.entry[nentry].full_path, &mx);
+ if (!mx.mbox)
+ {
+ mutt_error _("Cannot delete root folder");
+@@ -1099,8 +1053,8 @@ void _mutt_buffer_select_file(struct Buffer *f, int flags, char ***files, int *numfile
+ if (!imap_delete_mailbox(Context, mx))
+ {
+ /* free the mailbox from the browser */
+- FREE(& ((state.entry)[nentry].name));
+- FREE(& ((state.entry)[nentry].desc));
++ FREE(& ((state.entry)[nentry].display_name));
++ FREE(& ((state.entry)[nentry].full_path));
+ /* and move all other entries up */
+ if (nentry+1 < state.entrylen)
+ memmove(state.entry + nentry, state.entry + nentry + 1,
+@@ -1367,7 +1321,7 @@ void _mutt_buffer_select_file(struct Buffer *f, int flags, char ***files, int *numfile
+ #ifdef USE_IMAP
+ if (state.entry[menu->current].selectable)
+ {
+- mutt_buffer_strcpy(f, state.entry[menu->current].name);
++ mutt_buffer_strcpy(f, state.entry[menu->current].full_path);
+ destroy_state(&state);
+ goto bail;
+ }
+@@ -1375,7 +1329,7 @@ void _mutt_buffer_select_file(struct Buffer *f, int flags, char ***files, int *numfile
+ #endif
+ if (S_ISDIR(state.entry[menu->current].mode) ||
+ (S_ISLNK(state.entry[menu->current].mode) &&
+- link_is_dir(mutt_b2s(LastDir), state.entry[menu->current].name)))
++ link_is_dir(state.entry[menu->current].full_path)))
+ {
+ mutt_error _("Can't view a directory");
+ break;
+@@ -1384,8 +1338,7 @@ void _mutt_buffer_select_file(struct Buffer *f, int flags, char ***files, int *numfile
+ {
+ struct Body *b;
+
+- mutt_buffer_concat_path(buf, mutt_b2s(LastDir), state.entry[menu->current].name);
+- b = mutt_make_file_attach(mutt_b2s(buf));
++ b = mutt_make_file_attach(state.entry[menu->current].full_path);
+ if (b != NULL)
+ {
+ mutt_view_attachment(NULL, b, MUTT_REGULAR, NULL, NULL);
+diff --git a/browser.h b/browser.h
+index a7103743..39c257b6 100644
+--- a/browser.h
++++ b/browser.h
+@@ -28,8 +28,8 @@ struct folder_file
+ gid_t gid;
+ nlink_t nlink;
+
+- char *name;
+- char *desc;
++ char *display_name;
++ char *full_path;
+
+ short new; /* true if mailbox has "new mail" */
+ int msg_count; /* total number of messages */
+diff --git a/imap/browse.c b/imap/browse.c
+index ab965803..277444aa 100644
+--- a/imap/browse.c
++++ b/imap/browse.c
+@@ -426,7 +426,7 @@ static void imap_add_folder(char delim, char *folder, int noselect,
+ }
+
+ imap_qualify_path(tmp, sizeof(tmp), &mx, folder);
+-(state->entry)[state->entrylen].name = mutt_str_strdup(tmp);
++(state->entry)[state->entrylen].full_path = mutt_str_strdup(tmp);
+
+ /* mark desc with delim in browser if it can have subfolders */
+ if (!isparent && !noinferiors && strlen(relpath) < sizeof(relpath) - 1)
+@@ -435,7 +435,7 @@ static void imap_add_folder(char delim, char *folder, int noselect,
+ relpath[strlen(relpath)] = delim;
+ }
+
+-(state->entry)[state->entrylen].desc = mutt_str_strdup(relpath);
++(state->entry)[state->entrylen].display_name = mutt_str_strdup(relpath);
+
+ (state->entry)[state->entrylen].imap = 1;
+ /* delimiter at the root is useless. */
+@@ -469,5 +469,5 @@ static void imap_add_folder(char delim, char *folder, int noselect,
+
+ static int compare_names(struct folder_file *a, struct folder_file *b)
+ {
+- return mutt_str_strcmp(a->name, b->name);
++ return mutt_str_strcmp(a->full_path, b->full_path);
+ }
--- /dev/null
+From 0fa710308f8ad337376bee1af6bd73595a71cadb Mon Sep 17 00:00:00 2001
+From: Kevin McCarthy <kevin@8t8.us>
+Date: Sun, 8 Sep 2019 10:49:37 -0700
+Subject: Add $browser_sticky_cursor default set
+
+This option attempts to keep the browser cursor on the same mailbox.
+
+It does this by keeping track of the current selected mailbox and
+comparing that when regenerating the menu.
+
+Modify imap_mailbox_create() and imap_mailbox_rename() to return the
+new mailbox name so it can be automatically selected.
+
+Upstream-commit: https://gitlab.com/muttmua/mutt/commit/0fa710308f8ad337376bee1af6bd73595a71cadb
+Co-authored-by:
+---
+ browser.c | 63 +++++++++++++++++++++++++++++++++++----------
+ imap/browse.c | 8 ++++--
+ imap/imap.h | 4 +--
+ imap/imap_private.h | 1 +
+ imap/util.c | 10 +++++++
+ init.h | 9 +++++++
+ mutt.h | 1 +
+ 7 files changed, 78 insertions(+), 18 deletions(-)
+
+diff --git a/browser.c b/browser.c
+index 56ce75d2..c75406ca 100644
+--- a/browser.c
++++ b/browser.c
+@@ -601,9 +601,10 @@ static void folder_entry(char *s, size_t slen, struct Menu *menu, int num)
+ }
+
+ static void init_menu(struct browser_state *state, struct Menu *menu, char *title,
+- size_t titlelen, int mailbox)
++ size_t titlelen, int mailbox, const char *defaultsel)
+ {
+ struct Buffer *path = NULL;
++ int i;
+
+ path = mutt_buffer_pool_get();
+
+@@ -635,6 +636,18 @@ static void init_menu(struct browser_state *state, struct Menu *menu, char *title,
+ }
+ menu->redraw = REDRAW_FULL;
+
++ if (option(OPTBROWSERSTICKYCURSOR) && defaultsel && *defaultsel)
++ {
++ for (i = 0; i < menu->max; i++)
++ {
++ if (!mutt_str_strcmp(defaultsel, state->entry[i].full_path))
++ {
++ menu->current = i;
++ break;
++ }
++ }
++ }
++
+ mutt_buffer_pool_release(&path);
+ }
+
+@@ -674,6 +687,7 @@ void _mutt_buffer_select_file(struct Buffer *f, int flags, char ***files, int *numfile
+ struct Buffer *prefix = NULL;
+ struct Buffer *tmp = NULL;
+ struct Buffer *OldLastDir = NULL;
++ struct Buffer *defaultsel = NULL;
+ char helpstr[1024];
+ char title[256];
+ struct browser_state state;
+@@ -691,6 +705,7 @@ void _mutt_buffer_select_file(struct Buffer *f, int flags, char ***files, int *numfile
+ prefix = mutt_buffer_pool_get();
+ tmp = mutt_buffer_pool_get();
+ OldLastDir = mutt_buffer_pool_get();
++ defaultsel = mutt_buffer_pool_get();
+
+ memset(&state, 0, sizeof(struct browser_state));
+
+@@ -757,6 +772,9 @@ void _mutt_buffer_select_file(struct Buffer *f, int flags, char ***files, int *numfile
+ else if (!*(mutt_b2s(LastDir)))
+ mutt_buffer_strcpy(LastDir, NONULL(Folder));
+
++ if (Context)
++ mutt_buffer_strcpy(defaultsel, NONULL(Context->path));
++
+ #ifdef USE_IMAP
+ if (!mailbox && mx_is_imap(mutt_b2s(LastDir)))
+ {
+@@ -803,11 +821,16 @@ void _mutt_buffer_select_file(struct Buffer *f, int flags, char ***files, int *numfile
+ FolderHelp);
+ mutt_menu_push_current(menu);
+
+- init_menu(&state, menu, title, sizeof(title), mailbox);
++ init_menu(&state, menu, title, sizeof(title), mailbox, mutt_b2s(defaultsel));
+
+ FOREVER
+ {
+- switch(op = mutt_menu_loop(menu))
++ op = mutt_menu_loop(menu);
++
++ if (state.entrylen)
++ mutt_buffer_strcpy(defaultsel, state.entry[menu->current].full_path);
++
++ switch(op)
+ {
+ case OP_DESCEND_DIRECTORY:
+ case OP_GENERIC_SELECT_ENTRY:
+@@ -836,6 +859,13 @@ void _mutt_buffer_select_file(struct Buffer *f, int flags, char ***files, int *numfile
+ /* save the old directory */
+ mutt_buffer_strcpy(OldLastDir, mutt_b2s(LastDir));
+
++ mutt_buffer_strcpy(defaultsel, mutt_b2s(OldLastDir));
++ if (mutt_buffer_len(defaultsel) && (*(defaultsel->dptr - 1) == '/'))
++ {
++ defaultsel->dptr--;
++ *(defaultsel->dptr) = '\0';
++ }
++
+ if (mutt_str_strcmp(state.entry[menu->current].display_name, "..") == 0)
+ {
+ size_t lastdirlen = mutt_buffer_len(LastDir);
+@@ -921,7 +951,7 @@ void _mutt_buffer_select_file(struct Buffer *f, int flags, char ***files, int *numfile
+ }
+ menu->current = 0;
+ menu->top = 0;
+- init_menu(&state, menu, title, sizeof(title), mailbox);
++ init_menu(&state, menu, title, sizeof(title), mailbox, mutt_b2s(defaultsel));
+ break;
+ }
+ }
+@@ -992,7 +1022,7 @@ void _mutt_buffer_select_file(struct Buffer *f, int flags, char ***files, int *numfile
+ break;
+ }
+
+- if (!imap_mailbox_create(mutt_b2s(LastDir)))
++ if (!imap_mailbox_create(mutt_b2s(LastDir), defaultsel))
+ {
+ /* TODO: find a way to detect if the new folder would appear in
+ * this window, and insert it without starting over. */
+@@ -1004,7 +1034,7 @@ void _mutt_buffer_select_file(struct Buffer *f, int flags, char ***files, int *numfile
+ menu->data = state.entry;
+ menu->current = 0;
+ menu->top = 0;
+- init_menu(&state, menu, title, sizeof(title), mailbox);
++ init_menu(&state, menu, title, sizeof(title), mailbox, mutt_b2s(defaultsel));
+ }
+ /* else leave error on screen */
+ break;
+@@ -1016,7 +1046,7 @@ void _mutt_buffer_select_file(struct Buffer *f, int flags, char ***files, int *numfile
+ {
+ int nentry = menu->current;
+
+- if (imap_mailbox_rename(state.entry[nentry].full_path) >= 0)
++ if (imap_mailbox_rename(state.entry[nentry].full_path, defaultsel) >= 0)
+ {
+ destroy_state(&state);
+ init_state(&state, NULL);
+@@ -1026,7 +1056,7 @@ void _mutt_buffer_select_file(struct Buffer *f, int flags, char ***files, int *numfile
+ menu->data = state.entry;
+ menu->current = 0;
+ menu->top = 0;
+- init_menu(&state, menu, title, sizeof(title), mailbox);
++ init_menu(&state, menu, title, sizeof(title), mailbox, mutt_b2s(defaultsel));
+ }
+ }
+ break;
+@@ -1063,7 +1093,8 @@ void _mutt_buffer_select_file(struct Buffer *f, int flags, char ***files, int *numfile
+ sizeof(struct folder_file));
+ state.entrylen--;
+ mutt_message _("Mailbox deleted.");
+- init_menu(&state, menu, title, sizeof(title), mailbox);
++ mutt_buffer_clear(defaultsel);
++ init_menu(&state, menu, title, sizeof(title), mailbox, mutt_b2s(defaultsel));
+ }
+ else
+ mutt_error _("Mailbox deletion failed.");
+@@ -1078,6 +1109,7 @@ void _mutt_buffer_select_file(struct Buffer *f, int flags, char ***files, int *numfile
+ case OP_CHANGE_DIRECTORY:
+
+ mutt_buffer_strcpy(buf, mutt_b2s(LastDir));
++ mutt_buffer_clear(defaultsel);
+ #ifdef USE_IMAP
+ if (!state.imap_browse)
+ #endif
+@@ -1107,7 +1139,7 @@ void _mutt_buffer_select_file(struct Buffer *f, int flags, char ***files, int *numfile
+ menu->data = state.entry;
+ menu->current = 0;
+ menu->top = 0;
+- init_menu(&state, menu, title, sizeof(title), mailbox);
++ init_menu(&state, menu, title, sizeof(title), mailbox, mutt_b2s(defaultsel));
+ }
+ else
+ #endif
+@@ -1136,7 +1168,7 @@ void _mutt_buffer_select_file(struct Buffer *f, int flags, char ***files, int *numfile
+ }
+ menu->current = 0;
+ menu->top = 0;
+- init_menu(&state, menu, title, sizeof(title), mailbox);
++ init_menu(&state, menu, title, sizeof(title), mailbox, mutt_b2s(defaultsel));
+ }
+ else
+ mutt_error(_("%s is not a directory."), mutt_b2s(buf));
+@@ -1195,12 +1227,12 @@ void _mutt_buffer_select_file(struct Buffer *f, int flags, char ***files, int *numfile
+ imap_browse(mutt_b2s(LastDir), &state);
+ browser_sort(&state);
+ menu->data = state.entry;
+- init_menu(&state, menu, title, sizeof(title), mailbox);
++ init_menu(&state, menu, title, sizeof(title), mailbox, mutt_b2s(defaultsel));
+ }
+ else
+ #endif
+ if (examine_directory(menu, &state, mutt_b2s(LastDir), NULL) == 0)
+- init_menu(&state, menu, title, sizeof(title), mailbox);
++ init_menu(&state, menu, title, sizeof(title), mailbox, mutt_b2s(defaultsel));
+ else
+ {
+ mutt_error _("Error scanning directory.");
+@@ -1268,6 +1300,8 @@ void _mutt_buffer_select_file(struct Buffer *f, int flags, char ***files, int *numfile
+
+ case OP_TOGGLE_MAILBOXES:
+ mailbox = 1 - mailbox;
++ menu->current = 0;
++ /* fall through */
+
+ case OP_CHECK_NEW:
+ destroy_state(&state);
+@@ -1291,7 +1325,7 @@ void _mutt_buffer_select_file(struct Buffer *f, int flags, char ***files, int *numfile
+ #endif
+ else if (examine_directory(menu, &state, mutt_b2s(LastDir), mutt_b2s(prefix)) == -1)
+ goto bail;
+- init_menu(&state, menu, title, sizeof(title), mailbox);
++ init_menu(&state, menu, title, sizeof(title), mailbox, mutt_b2s(defaultsel));
+ break;
+
+ case OP_MAILBOX_LIST:
+@@ -1356,6 +1390,7 @@ bail:
+ mutt_buffer_pool_release(&prefix);
+ mutt_buffer_pool_release(&tmp);
+ mutt_buffer_pool_release(&OldLastDir);
++ mutt_buffer_pool_release(&defaultsel);
+
+ if (menu)
+ {
+diff --git a/imap/browse.c b/imap/browse.c
+index 277444aa..fee412d6 100644
+--- a/imap/browse.c
++++ b/imap/browse.c
+@@ -229,7 +229,7 @@ fail:
+ }
+
+ /* imap_mailbox_create: Prompt for a new mailbox name, and try to create it */
+-int imap_mailbox_create(const char* folder)
++int imap_mailbox_create(const char* folder, struct Buffer *result)
+ {
+ IMAP_DATA* idata;
+ IMAP_MBOX mx;
+@@ -272,6 +272,8 @@ int imap_mailbox_create(const char* folder)
+ if (imap_create_mailbox(idata, buf) < 0)
+ goto fail;
+
++ imap_buffer_qualify_path(result, &mx, buf);
++
+ mutt_message _("Mailbox created.");
+ mutt_sleep(0);
+
+@@ -283,7 +285,7 @@ fail:
+ return -1;
+ }
+
+-int imap_mailbox_rename(const char* mailbox)
++int imap_mailbox_rename(const char* mailbox, struct Buffer *result)
+ {
+ IMAP_DATA* idata;
+ IMAP_MBOX mx;
+@@ -331,6 +333,8 @@ int imap_mailbox_rename(const char* mailbox)
+ goto fail;
+ }
+
++ imap_buffer_qualify_path(result, &mx, buf);
++
+ mutt_message(_("Mailbox renamed."));
+ mutt_sleep(0);
+
+diff --git a/imap/imap.h b/imap/imap.h
+index fe99472b..24001c5e 100644
+--- a/imap/imap.h
++++ b/imap/imap.h
+@@ -51,8 +51,8 @@ extern struct mx_ops mx_imap_ops;
+
+ /* imap/browse.c */
+ int imap_browse(const char* path, struct browser_state* state);
+-int imap_mailbox_create(const char* folder);
+-int imap_mailbox_rename(const char* mailbox);
++int imap_mailbox_create(const char* folder, struct Buffer *result);
++int imap_mailbox_rename(const char* mailbox, struct Buffer *result);
+
+ /* imap/message.c */
+ int imap_append_message(struct Context* ctx, struct Message* msg);
+diff --git a/imap/imap_private.h b/imap/imap_private.h
+index 7d12ec25..67376d2b 100644
+--- a/imap/imap_private.h
++++ b/imap/imap_private.h
+@@ -323,6 +323,7 @@ char* imap_next_word(char* s);
+ time_t mutt_date_parse_imap(char* s);
+ void mutt_date_make_imap(char* buf, time_t timestamp);
+ void imap_qualify_path(char *dest, size_t len, IMAP_MBOX *mx, char* path);
++void imap_buffer_qualify_path(struct Buffer *dest, IMAP_MBOX *mx, char* path);
+ void imap_quote_string(char* dest, size_t dlen, const char* src);
+ void imap_quote_string_and_backquotes(char *dest, size_t dlen, const char *src);
+ void imap_unquote_string(char* s);
+diff --git a/imap/util.c b/imap/util.c
+index 01b57d08..315e77d8 100644
+--- a/imap/util.c
++++ b/imap/util.c
+@@ -707,6 +707,16 @@ void imap_qualify_path(char *dest, size_t len, IMAP_MBOX *mx, char* path)
+ url_tostring(&url, dest, len, 0);
+ }
+
++void imap_buffer_qualify_path(struct Buffer *dest, IMAP_MBOX *mx, char* path)
++{
++ struct Url url;
++
++ mutt_account_tourl(&mx->account, &url);
++ url.path = path;
++
++ url_ciss_tobuffer(&url, dest, 0);
++}
++
+
+ static void _imap_quote_string(char *dest, size_t dlen, const char *src,
+ const char *to_quote)
+diff --git a/init.h b/init.h
+index 2f450a43..39e5d8cd 100644
+--- a/init.h
++++ b/init.h
+@@ -422,6 +422,15 @@ struct option_t MuttVars[] = {
+ ** doesn't make intuitive sense. In those cases, it may be
+ ** desirable to \fIunset\fP this variable.
+ */
++ { "browser_sticky_cursor", DT_BOOL, R_NONE, {.l=OPTBROWSERSTICKYCURSOR}, {.l=1} },
++ /*
++ ** .pp
++ ** When this variable is \fIset\fP, the browser will attempt to keep
++ ** the cursor on the same mailbox when performing various functions.
++ ** These include moving up a directory, toggling between mailboxes
++ ** and directory listing, creating/renaming a mailbox, toggling
++ ** subscribed mailboxes, and entering a new mask.
++ */
+ #if defined(USE_SSL)
+ { "certificate_file", DT_STRING|DT_PATH, R_NONE, {.p=&CertificateFile}, {.p="~/.mutt_certificates"} },
+ /*
+diff --git a/mutt.h b/mutt.h
+index ce9056d7..549a4dde 100644
+--- a/mutt.h
++++ b/mutt.h
+@@ -392,6 +392,7 @@ enum
+ C_ChangeFolderNext,
+ C_BrailleFriendly,
+ C_BrowserAbbreviateMailboxes,
++ OPTBROWSERSTICKYCURSOR,
+ C_CheckMboxSize,
+ C_CheckNew,
+ C_CollapseUnread,
--- /dev/null
+From 2e6d4903a1e81f673ba2b66ab372dd09f95d6d5a Mon Sep 17 00:00:00 2001
+From: Kevin McCarthy <kevin@8t8.us>
+Date: Mon, 9 Sep 2019 14:06:31 -0700
+Subject: Convert remaining mutt_encode_path() call to use struct Buffer
+
+Then rename the other uses of mutt_buffer_encode_path() to
+mutt_encode_path().
+
+Upstream-commit: https://gitlab.com/muttmua/mutt/commit/2e6d4903a1e81f673ba2b66ab372dd09f95d6d5a
+Co-authored-by:
+---
+ bcache.c | 2 +-
+ hcache/hcache.c | 16 +++++++++-------
+ muttlib.c | 11 +----------
+ protos.h | 3 +--
+ 4 files changed, 12 insertions(+), 20 deletions(-)
+
+diff --git a/bcache.c b/bcache.c
+index 0fef6c32..b6925d4a 100644
+--- a/bcache.c
++++ b/bcache.c
+@@ -62,7 +62,7 @@ static int bcache_path(struct Account *account, const char *mailbox, struct BodyCache *bcac
+
+ path = mutt_buffer_pool_get();
+ dst = mutt_buffer_pool_get();
+- mutt_buffer_encode_path(path, NONULL(mailbox));
++ mutt_encode_path(path, NONULL(mailbox));
+
+ mutt_buffer_printf(dst, "%s/%s%s", C_MessageCachedir, host, mutt_b2s(path));
+ if (*(dst->dptr - 1) != '/')
+diff --git a/hcache/hcache.c b/hcache/hcache.c
+index 07f3fbd3..b8d7a9da 100644
+--- a/hcache/hcache.c
++++ b/hcache/hcache.c
+@@ -995,25 +995,27 @@ mutt_hcache_store_raw(header_cache_t* h, const char* filename, void* data,
+ #endif
+ }
+
+-static char* get_foldername(const char *folder)
++static char* get_foldername(const char *folder)
+ {
+ char *p = NULL;
+- char path[PATH_MAX];
++ struct Buffer *path;
+ struct stat st;
+
+- mutt_encode_path(path, sizeof(path), folder);
++ path = mutt_buffer_pool_get();
++ mutt_encode_path(path, folder);
+
+ /* if the folder is local, canonify the path to avoid
+ * to ensure equivalent paths share the hcache */
+- if (stat(path, &st) == 0)
++ if (stat(mutt_b2s(path), &st) == 0)
+ {
+ p = mutt_mem_malloc(PATH_MAX+1);
+- if (!realpath(path, p))
+- mutt_str_replace(&p, path);
++ if (!realpath(mutt_b2s(path), p))
++ mutt_str_replace(&p, mutt_b2s(path));
+ }
+ else
+- p = mutt_str_strdup(path);
++ p = mutt_str_strdup(mutt_b2s(path));
+
++ mutt_buffer_pool_release(&path);
+ return p;
+ }
+
+diff --git a/muttlib.c b/muttlib.c
+index 82f90faf..69641230 100644
+--- a/muttlib.c
++++ b/muttlib.c
+@@ -2247,16 +2247,7 @@ int mutt_replacelist_match(const char *s, struct ReplaceList *l, char *text, int textsi
+ return 0;
+ }
+
+-void mutt_encode_path(char *dest, size_t dlen, const char *src)
+-{
+- char *p = mutt_str_strdup(src);
+- int rc = mutt_cs_convert_string(&p, C_Charset, "utf-8", 0);
+- /* `src' may be NULL, such as when called from the pop3 driver. */
+- mutt_str_strfcpy(dest, (rc == 0) ? NONULL(p) : NONULL(src), dlen);
+- FREE(&p);
+-}
+-
+-void mutt_buffer_encode_path(struct Buffer *dest, const char *src)
++void mutt_encode_path(struct Buffer *dest, const char *src)
+ {
+ char *p;
+ int rc;
+diff --git a/protos.h b/protos.h
+index 66348bc3..f747bcb9 100644
+--- a/protos.h
++++ b/protos.h
+@@ -204,8 +204,7 @@ int mutt_label_complete(char *, size_t, int);
+ void mutt_curses_error(const char *, ...);
+ void mutt_curses_message(const char *, ...);
+ void mutt_encode_descriptions(struct Body *, short);
+-void mutt_encode_path(char *, size_t, const char *);
+-void mutt_buffer_encode_path(struct Buffer *, const char *);
++void mutt_encode_path(struct Buffer *, const char *);
+ void mutt_enter_command(void);
+ void mutt_error_history_display(void);
+ void mutt_error_history_init(void);
--- /dev/null
+From 773166e9ef0a2bc3eca93a8e16560fa4571673ad Mon Sep 17 00:00:00 2001
+From: Kevin McCarthy <kevin@8t8.us>
+Date: Mon, 9 Sep 2019 18:19:03 -0700
+Subject: Change browser <display-filename> to show full_path
+
+Prior to the introduction of display_name/full_path, it showed "name",
+which was the full IMAP URL but the shortname for folder/mailbox view.
+
+Now that the full_path is available, it makes sense to show that for
+all cases.
+
+Upstream-commit: https://gitlab.com/muttmua/mutt/commit/773166e9ef0a2bc3eca93a8e16560fa4571673ad
+Co-authored-by:
+---
+ browser.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/browser.c b/browser.c
+index c75406ca..4e45013d 100644
+--- a/browser.c
++++ b/browser.c
+@@ -994,7 +994,7 @@ void _mutt_buffer_select_file(struct Buffer *f, int flags, char ***files, int *numfile
+
+ case OP_BROWSER_TELL:
+ if (state.entrylen)
+- mutt_message("%s", state.entry[menu->current].display_name);
++ mutt_message("%s", state.entry[menu->current].full_path);
+ break;
+
+ #ifdef USE_IMAP
--- /dev/null
+From a4b53e19ef471efc1938348d1623b811354f1c93 Mon Sep 17 00:00:00 2001
+From: Kevin McCarthy <kevin@8t8.us>
+Date: Sun, 15 Sep 2019 15:41:42 -0700
+Subject: Improve sidebar indentation and shortpath behavior
+
+The previous implementation only enabled $sidebar_folder_indent for
+mailboxes underneath $folder. Change indentation to be based upon the
+previous common-path mailbox in the list. Indent one more than the
+common-path mailbox, rather than the number of delimiters after
+$folder.
+
+Change $sidebar_short_path to shorten based on the previous mailbox in
+the list too.
+
+Invoke mutt_buffer_pretty_mailbox() to prefix the mailbox with '~' or
+'=' characters. This changes the output for the case where mailbox
+equals $folder, but provides uniform display behavior across mutt.
+
+Thanks to Christopher Zimmermann(@madroach) for the original patch,
+which this commit is based upon.
+
+Upstream-commit: https://gitlab.com/muttmua/mutt/commit/a4b53e19ef471efc1938348d1623b811354f1c93
+Co-authored-by:
+---
+ sidebar.c | 194 +++++++++++++++++++++++++++++++++++++++---------------
+ 1 file changed, 140 insertions(+), 54 deletions(-)
+
+diff --git a/sidebar.c b/sidebar.c
+index 9df19872..364b2285 100644
+--- a/sidebar.c
++++ b/sidebar.c
+@@ -520,6 +520,79 @@ static void fill_empty_space(int first_row, int num_rows, int width)
+ }
+ }
+
++/**
++ * calculate_depth - Calculate depth of path based on C_SidebarDelimChars.
++ *
++ * If lastpath is not NULL, common_depth is also calculated. These
++ * are used for indentation and short_path calculation.
++ */
++static void calculate_depth(const char *path, const char *lastpath,
++ int *depth, int *common_depth)
++{
++ int i, has_trailing_delim = 0;
++
++ *depth = *common_depth = 0;
++ if (!C_SidebarDelimChars || !path)
++ return;
++
++ for (i = 0; path[i]; i++)
++ {
++ if (strchr(C_SidebarDelimChars, path[i]))
++ {
++ (*depth)++;
++
++ /* /a/b/c and /a/b/c/ both are a depth of 3.
++ * Only count the final '\0' if the last character wasn't a separator.
++ */
++ if (!path[i+1])
++ has_trailing_delim = 1;
++ }
++
++ if (lastpath)
++ {
++ /* path /a/b/c/d
++ * lastpath /a/b
++ * lastpath /a/
++ * lastpath /a
++ * ^
++ */
++ if (strchr(C_SidebarDelimChars, path[i]) &&
++ (strchr(C_SidebarDelimChars, lastpath[i]) || !lastpath[i]))
++ {
++ (*common_depth)++;
++ if (!lastpath[i])
++ lastpath = NULL;
++ }
++
++ /* path /abc
++ * lastpath /ad
++ * lastpath /a/
++ * lastpath /a
++ * ^
++ */
++ else if (!lastpath[i] || path[i] != lastpath[i])
++ lastpath = NULL;
++ }
++ }
++
++ if (!has_trailing_delim)
++ {
++ (*depth)++;
++
++ /* path /a
++ * lastpath /a/b/c
++ * lastpath /a/
++ * lastpath /a
++ * ^
++ */
++ if (lastpath &&
++ (strchr(C_SidebarDelimChars, lastpath[i]) || !lastpath[i]))
++ (*common_depth)++;
++ }
++}
++
++#define SIDEBAR_MAX_INDENT 32
++
+ /**
+ * draw_sidebar - Write out a list of mailboxes, on the left
+ * @num_rows: Height of the Sidebar
+@@ -546,9 +619,18 @@ static void draw_sidebar(int num_rows, int num_cols, int div_width)
+ int entryidx;
+ struct SbEntry *entry;
+ struct Mailbox *b;
++ int indent_width = -1;
++ int indent_depths[SIDEBAR_MAX_INDENT];
++ const char *sidebar_folder_name;
++ struct Buffer *pretty_folder_name, *last_folder_name, *indent_folder_name;
++
+ if (TopIndex < 0)
+ return;
+
++ pretty_folder_name = mutt_buffer_pool_get();
++ last_folder_name = mutt_buffer_pool_get();
++ indent_folder_name = mutt_buffer_pool_get();
++
+ int w = MIN(num_cols, (C_SidebarWidth - div_width));
+ int row = 0;
+ for (entryidx = TopIndex;(entryidx < EntryCount) && (row < num_rows); entryidx++)
+@@ -586,75 +668,79 @@ static void draw_sidebar(int num_rows, int num_cols, int div_width)
+ b->msg_flagged = Context->flagged;
+ }
+
+- /* compute length of Folder without trailing separator */
+- size_t maildirlen = mutt_str_strlen(Folder);
+- if (maildirlen &&
+- C_SidebarDelimChars &&
+- strchr(C_SidebarDelimChars, Folder[maildirlen - 1]))
+- maildirlen--;
+-
+- /* check whether Folder is a prefix of the current folder's path */
+- short maildir_is_prefix = 0;
+- if ((mutt_buffer_len(b->pathbuf) > maildirlen) &&
+- (mutt_str_strncmp(Folder, mutt_b2s(b->pathbuf), maildirlen) == 0) &&
+- C_SidebarDelimChars &&
+- strchr(C_SidebarDelimChars, mutt_b2s(b->pathbuf)[maildirlen]))
+- maildir_is_prefix = 1;
+-
+- /* calculate depth of current folder and generate its display name with indented spaces */
+- int sidebar_folder_depth = 0;
+- const char *sidebar_folder_name;
+- struct Buffer *short_folder_name = NULL;
+- int i;
+- if (option(C_SidebarShortPath))
++ mutt_buffer_strcpy(pretty_folder_name, mutt_b2s(b->pathbuf));
++ mutt_buffer_pretty_mailbox(pretty_folder_name);
++ sidebar_folder_name = mutt_b2s(pretty_folder_name);
++
++ if (C_SidebarDelimChars)
+ {
+- /* disregard a trailing separator, so strlen() - 2 */
+- sidebar_folder_name = mutt_b2s(b->pathbuf);
+- for (i = mutt_str_strlen(sidebar_folder_name) - 2; i >= 0; i--)
++ int parent_depth = 0;
++ int i;
++
++ if (option(C_SidebarShortPath) || option(C_SidebarFolderIndent))
+ {
+- if (C_SidebarDelimChars &&
+- strchr(C_SidebarDelimChars, sidebar_folder_name[i]))
+- {
+- sidebar_folder_name +=(i + 1);
+- break;
+- }
++ int depth = 0, common_depth = 0;
++
++ calculate_depth(sidebar_folder_name, mutt_b2s(last_folder_name),
++ &depth, &common_depth);
++ mutt_buffer_strcpy(last_folder_name, sidebar_folder_name);
++
++ if (indent_width < SIDEBAR_MAX_INDENT)
++ indent_width++;
++
++ /* indent_depths[] hold the path depths at each level of indentation.
++ * Indent based off the longest path that we share in common.
++ *
++ * The 'indent_depths[] >= depth' test below is for a corner case:
++ *
++ * path depth common_depth indent_width
++ * /a 2 0 0
++ * /a/b 3 2 1
++ * /a/b/ 3 3 1
++ *
++ * Because the common_depth of /a/b/ matches the depth of
++ * /a/b, we need the additional test to continue popping the
++ * indent_depths[] stack.
++ */
++ while (indent_width &&
++ ((indent_depths[indent_width - 1] > common_depth) ||
++ (indent_depths[indent_width - 1] >= depth)))
++ indent_width--;
++
++ if (indent_width < SIDEBAR_MAX_INDENT)
++ indent_depths[indent_width] = depth;
++ if (indent_width)
++ parent_depth = indent_depths[indent_width - 1];
+ }
+- }
+- else
+- sidebar_folder_name = mutt_b2s(b->pathbuf) + maildir_is_prefix *(maildirlen + 1);
+
+- if (maildir_is_prefix && option(C_SidebarFolderIndent))
+- {
+- const char *tmp_folder_name;
+- int lastsep = 0;
+- tmp_folder_name = mutt_b2s(b->pathbuf) + maildirlen + 1;
+- int tmplen =(int) mutt_str_strlen(tmp_folder_name) - 1;
+- for (i = 0; i < tmplen; i++)
++ if (option(C_SidebarShortPath) && parent_depth)
+ {
+- if (C_SidebarDelimChars && strchr(C_SidebarDelimChars, tmp_folder_name[i]))
+- {
+- sidebar_folder_depth++;
+- lastsep = i + 1;
+- }
++ for (i = 0; parent_depth && sidebar_folder_name[i]; i++)
++ if (strchr(C_SidebarDelimChars, sidebar_folder_name[i]))
++ parent_depth--;
++ sidebar_folder_name += i;
+ }
+- if (sidebar_folder_depth > 0)
++
++ if (option(C_SidebarFolderIndent) && indent_width)
+ {
+- if (option(C_SidebarShortPath))
+- tmp_folder_name += lastsep; /* basename */
+- short_folder_name = mutt_buffer_pool_get();
+- for (i=0; i < sidebar_folder_depth; i++)
+- mutt_buffer_addstr(short_folder_name, NONULL(C_SidebarIndentString));
+- mutt_buffer_addstr(short_folder_name, tmp_folder_name);
+- sidebar_folder_name = mutt_b2s(short_folder_name);
++ mutt_buffer_clear(indent_folder_name);
++ for (i = 0; i < indent_width; i++)
++ mutt_buffer_addstr(indent_folder_name, NONULL(C_SidebarIndentString));
++ mutt_buffer_addstr(indent_folder_name, sidebar_folder_name);
++ sidebar_folder_name = mutt_b2s(indent_folder_name);
+ }
+ }
++
+ char str[256];
+ make_sidebar_entry(str, sizeof(str), w, sidebar_folder_name, entry);
+ printw("%s", str);
+- mutt_buffer_pool_release(&short_folder_name);
+ row++;
+ }
+
++ mutt_buffer_pool_release(&pretty_folder_name);
++ mutt_buffer_pool_release(&last_folder_name);
++ mutt_buffer_pool_release(&indent_folder_name);
++
+ fill_empty_space(row, num_rows - row, w);
+ }
+
--- /dev/null
+From a6bccbe1d1b731e69b2b609278ef0811d547a6e7 Mon Sep 17 00:00:00 2001
+From: Kevin McCarthy <kevin@8t8.us>
+Date: Mon, 30 Sep 2019 18:50:27 -0700
+Subject: Memcpy header cache fetch values to ensure alignment
+
+While testing the hcache buffer pool changes, I noticed a misaligned
+pointer warning when using LMDB.
+
+The other header cache backends must ensure alignment of the pointer
+they return, but LMDB apparently does not.
+
+Instead of directly assigning and dereferencing the pointer fetched,
+use memcpy to the appropriate type, just as the header cache restore
+operation does.
+
+Upstream-commit: https://gitlab.com/muttmua/mutt/commit/a6bccbe1d1b731e69b2b609278ef0811d547a6e7
+Co-authored-by:
+---
+ imap/imap.c | 40 ++++++++++++++++++++++++----------------
+ imap/message.c | 19 +++++++++++--------
+ imap/util.c | 18 ++++++++++--------
+ maildir/mh.c | 7 ++++---
+ 4 files changed, 49 insertions(+), 35 deletions(-)
+
+diff --git a/imap/imap.c b/imap/imap.c
+index ccba3a38..33469f5f 100644
+--- a/imap/imap.c
++++ b/imap/imap.c
+@@ -1800,9 +1800,9 @@ IMAP_STATUS* imap_mboxcache_get(IMAP_DATA* idata, const char* mbox, int create)
+ IMAP_STATUS scache;
+ #ifdef USE_HCACHE
+ header_cache_t *hc = NULL;
+- unsigned int *uidvalidity = NULL;
+- unsigned int *uidnext = NULL;
+- unsigned long long *modseq = NULL;
++ void *puidvalidity = NULL;
++ void *puidnext = NULL;
++ void *pmodseq = NULL;
+ #endif
+
+ for (cur = idata->mboxcache; cur; cur = cur->next)
+@@ -1829,28 +1829,36 @@ IMAP_STATUS* imap_mboxcache_get(IMAP_DATA* idata, const char* mbox, int create)
+ hc = imap_hcache_open(idata, mbox);
+ if (hc)
+ {
+- uidvalidity = mutt_hcache_fetch_raw(hc, "/UIDVALIDITY", imap_hcache_keylen);
+- uidnext = mutt_hcache_fetch_raw(hc, "/UIDNEXT", imap_hcache_keylen);
+- modseq = mutt_hcache_fetch_raw(hc, "/MODSEQ", imap_hcache_keylen);
+- if (uidvalidity)
++ puidvalidity = mutt_hcache_fetch_raw(hc, "/UIDVALIDITY", imap_hcache_keylen);
++ puidnext = mutt_hcache_fetch_raw(hc, "/UIDNEXT", imap_hcache_keylen);
++ pmodseq = mutt_hcache_fetch_raw(hc, "/MODSEQ", imap_hcache_keylen);
++ if (puidvalidity)
+ {
+ if (!status)
+ {
+- mutt_hcache_free((void **)&uidvalidity);
+- mutt_hcache_free((void **)&uidnext);
+- mutt_hcache_free((void **)&modseq);
++ mutt_hcache_free((void **)&puidvalidity);
++ mutt_hcache_free((void **)&puidnext);
++ mutt_hcache_free((void **)&pmodseq);
+ mutt_hcache_close(hc);
+ return imap_mboxcache_get(idata, mbox, 1);
+ }
+- status->uidvalidity = *uidvalidity;
+- status->uidnext = uidnext ? *uidnext: 0;
+- status->modseq = modseq ? *modseq: 0;
++ memcpy(&status->uidvalidity, puidvalidity, sizeof(unsigned int));
++
++ if (puidnext)
++ memcpy(&status->uidnext, puidnext, sizeof(unsigned int));
++ else
++ status->uidnext = 0;
++
++ if (pmodseq)
++ memcpy(&status->modseq, pmodseq, sizeof(unsigned long long));
++ else
++ status->modseq = 0;
+ mutt_debug(LL_DEBUG3, "mboxcache: hcache uidvalidity %u, uidnext %u, modseq %llu\n",
+ status->uidvalidity, status->uidnext, status->modseq);
+ }
+- mutt_hcache_free((void **)&uidvalidity);
+- mutt_hcache_free((void **)&uidnext);
+- mutt_hcache_free((void **)&modseq);
++ mutt_hcache_free((void **)&puidvalidity);
++ mutt_hcache_free((void **)&puidnext);
++ mutt_hcache_free((void **)&pmodseq);
+ mutt_hcache_close(hc);
+ }
+ #endif
+diff --git a/imap/message.c b/imap/message.c
+index f32f5db6..48dc0437 100644
+--- a/imap/message.c
++++ b/imap/message.c
+@@ -228,14 +228,15 @@ int imap_read_headers(IMAP_DATA* idata, unsigned int msn_begin, unsigned int ms
+ int evalhc = 0;
+
+ #if USE_HCACHE
+- unsigned int *uid_validity = NULL;
+- unsigned int *puidnext = NULL;
++ void *puid_validity = NULL;
++ unsigned int uid_validity = 0;
++ void *puidnext = NULL;
+ unsigned int uidnext = 0;
+ int has_condstore = 0;
+ int has_qresync = 0;
+ int eval_condstore = 0;
+ int eval_qresync = 0;
+- unsigned long long *pmodseq = NULL;
++ void *pmodseq = NULL;
+ unsigned long long hc_modseq = 0;
+ char *uid_seqset = NULL;
+ #endif /* USE_HCACHE */
+@@ -257,11 +258,13 @@ int imap_read_headers(IMAP_DATA* idata, unsigned int msn_begin, unsigned int ms
+
+ if (idata->hcache && initial_download)
+ {
+- uid_validity = mutt_hcache_fetch_raw(idata->hcache, "/UIDVALIDITY", imap_hcache_keylen);
++ puid_validity = mutt_hcache_fetch_raw(idata->hcache, "/UIDVALIDITY", imap_hcache_keylen);
++ if (puid_validity)
++ memcpy(&uid_validity, puid_validity, sizeof(unsigned int));
+ puidnext = mutt_hcache_fetch_raw(idata->hcache, "/UIDNEXT", imap_hcache_keylen);
+ if (puidnext)
+ {
+- uidnext = *puidnext;
++ memcpy(&uidnext, puidnext, sizeof(unsigned int));;
+ mutt_hcache_free((void **)&puidnext);
+ }
+
+@@ -278,13 +281,13 @@ int imap_read_headers(IMAP_DATA* idata, unsigned int msn_begin, unsigned int ms
+ has_qresync = 1;
+ }
+
+- if (uid_validity && uidnext && *uid_validity == idata->uid_validity)
++ if (puid_validity && uidnext && (uid_validity == idata->uid_validity))
+ {
+ evalhc = 1;
+ pmodseq = mutt_hcache_fetch_raw(idata->hcache, "/MODSEQ", imap_hcache_keylen);
+ if (pmodseq)
+ {
+- hc_modseq = *pmodseq;
++ memcpy(&hc_modseq, pmodseq, sizeof(unsigned long long));;
+ mutt_hcache_free((void **)&pmodseq);
+ }
+ if (hc_modseq)
+@@ -300,7 +303,7 @@ int imap_read_headers(IMAP_DATA* idata, unsigned int msn_begin, unsigned int ms
+ eval_condstore = 1;
+ }
+ }
+- mutt_hcache_free((void **)&uid_validity);
++ mutt_hcache_free((void **)&puid_validity);
+ }
+ if (evalhc)
+ {
+diff --git a/imap/util.c b/imap/util.c
+index 0812bac3..42f07cc2 100644
+--- a/imap/util.c
++++ b/imap/util.c
+@@ -179,22 +179,24 @@ void imap_hcache_close(IMAP_DATA* idata)
+ struct Email* imap_hcache_get(IMAP_DATA* idata, unsigned int uid)
+ {
+ char key[16];
+- unsigned int* uv;
++ void *data;
++ unsigned int uv;
+ struct Email* h = NULL;
+
+ if (!idata->hcache)
+ return NULL;
+
+ sprintf(key, "/%u", uid);
+- uv =(unsigned int*)mutt_hcache_fetch(idata->hcache, key,
+- imap_hcache_keylen);
+- if (uv)
++ data = mutt_hcache_fetch(idata->hcache, key,
++ imap_hcache_keylen);
++ if (data)
+ {
+- if (*uv == idata->uid_validity)
+- h = mutt_hcache_restore((unsigned char*)uv, NULL);
++ memcpy(&uv, data, sizeof(unsigned int));
++ if (uv == idata->uid_validity)
++ h = mutt_hcache_restore((unsigned char *)data, NULL);
+ else
+- mutt_debug(LL_DEBUG3, "hcache uidvalidity mismatch: %u", *uv);
+- mutt_hcache_free((void **)&uv);
++ mutt_debug(LL_DEBUG3, "hcache uidvalidity mismatch: %u", uv);
++ mutt_hcache_free((void **)&data);
+ }
+
+ return h;
+diff --git a/maildir/mh.c b/maildir/mh.c
+index 37cef860..ad3c8253 100644
+--- a/maildir/mh.c
++++ b/maildir/mh.c
+@@ -1145,7 +1145,7 @@ static void maildir_delayed_parsing(struct Context * ctx, struct maildir **md,
+ #if USE_HCACHE
+ header_cache_t *hc = NULL;
+ void *data;
+- struct timeval *when = NULL;
++ struct timeval when;
+ struct stat lastchanged;
+ int ret;
+ #endif
+@@ -1207,9 +1207,10 @@ static void maildir_delayed_parsing(struct Context * ctx, struct maildir **md,
+ data = mutt_hcache_fetch(hc, p->h->path, strlen);
+ else
+ data = mutt_hcache_fetch(hc, p->h->path + 3, &maildir_hcache_keylen);
+- when =(struct timeval *) data;
++ if (data)
++ memcpy(&when, data, sizeof(struct timeval));
+
+- if (data != NULL && !ret && lastchanged.st_mtime <= when->tv_sec)
++ if (data != NULL && !ret && lastchanged.st_mtime <= when.tv_sec)
+ {
+ p->h = mutt_hcache_restore((unsigned char *)data, &p->h);
+ if (ctx->magic == MUTT_MAILDIR)
--- /dev/null
+From fe69e4d1a30aabb70dc4a5890bb7188841b61421 Mon Sep 17 00:00:00 2001
+From: Kevin McCarthy <kevin@8t8.us>
+Date: Wed, 9 Oct 2019 08:36:59 +0800
+Subject: Add sticky browser behavior for sorting
+
+The menu isn't rebuilt after sorting, so the selected mailbox was not
+sticky for that operation.
+
+Refactor the sticky cursor setting out so it can be explicitly called
+after sorting too.
+
+Upstream-commit: https://gitlab.com/muttmua/mutt/commit/fe69e4d1a30aabb70dc4a5890bb7188841b61421
+Co-authored-by:
+---
+ browser.c | 31 +++++++++++++++++++------------
+ 1 file changed, 19 insertions(+), 12 deletions(-)
+
+diff --git a/browser.c b/browser.c
+index eb212d3e..b560c54d 100644
+--- a/browser.c
++++ b/browser.c
+@@ -600,11 +600,27 @@ static void folder_entry(char *s, size_t slen, struct Menu *menu, int num)
+ (unsigned long) &folder, MUTT_FORMAT_ARROWCURSOR);
+ }
+
++static void set_sticky_cursor(struct browser_state *state, struct Menu *menu, const char *defaultsel)
++{
++ int i;
++
++ if (option(OPTBROWSERSTICKYCURSOR) && defaultsel && *defaultsel)
++ {
++ for (i = 0; i < menu->max; i++)
++ {
++ if (!mutt_str_strcmp(defaultsel, state->entry[i].full_path))
++ {
++ menu->current = i;
++ break;
++ }
++ }
++ }
++}
++
+ static void init_menu(struct browser_state *state, struct Menu *menu, char *title,
+ size_t titlelen, int mailbox, const char *defaultsel)
+ {
+ struct Buffer *path = NULL;
+- int i;
+
+ path = mutt_buffer_pool_get();
+
+@@ -636,17 +652,7 @@ static void init_menu(struct browser_state *state, struct Menu *menu, char *title,
+ }
+ menu->redraw = REDRAW_FULL;
+
+- if (option(OPTBROWSERSTICKYCURSOR) && defaultsel && *defaultsel)
+- {
+- for (i = 0; i < menu->max; i++)
+- {
+- if (!mutt_str_strcmp(defaultsel, state->entry[i].full_path))
+- {
+- menu->current = i;
+- break;
+- }
+- }
+- }
++ set_sticky_cursor(state, menu, defaultsel);
+
+ mutt_buffer_pool_release(&path);
+ }
+@@ -1290,6 +1296,7 @@ void _mutt_buffer_select_file(struct Buffer *f, int flags, char ***files, int *numfile
+ {
+ SortBrowser |= reverse ? SORT_REVERSE : 0;
+ browser_sort(&state);
++ set_sticky_cursor(&state, menu, mutt_b2s(defaultsel));
+ menu->redraw = REDRAW_FULL;
+ }
+ break;
--- /dev/null
+From 0e32b977454de79899c497debcd460470e720e7a Mon Sep 17 00:00:00 2001
+From: Kevin McCarthy <kevin@8t8.us>
+Date: Thu, 10 Oct 2019 15:03:05 +0800
+Subject: Add new browse-mailboxes function in index and pager
+
+This allows direct access to the mailboxes list in the folder menu.
+This is useful, for instance, if $browser_sticky_cursor is set and the
+current directory does not contain the open mailbox. The macro
+version will lose the current mailbox while toggling to the mailboxes
+list.
+
+Upstream-commit: https://gitlab.com/muttmua/mutt/commit/0e32b977454de79899c497debcd460470e720e7a
+Co-authored-by:
+---
+ opcodes.h | 2 ++
+ index.c | 31 +++++++++++++++++++------------
+ doc/neomuttrc.head | 5 +++--
+ functions.h | 4 ++++
+ 4 files changed, 28 insertions(+), 14 deletions(-)
+
+diff --git a/opcodes.h b/opcodes.h
+index a91a14ab..4e3bd1d0 100644
+--- a/opcodes.h
++++ b/opcodes.h
+@@ -109,6 +109,8 @@ OP_LIST_REPLY "reply to specified mailing list"
+ OP_MACRO "execute a macro"
+ OP_MAIL "compose a new mail message"
+ OP_MAIN_BREAK_THREAD "break the thread in two"
++OP_MAIN_BROWSE_MAILBOXES "select a new mailbox from the browser"
++OP_MAIN_BROWSE_MAILBOXES_READONLY "select a new mailbox from the browser in read only mode"
+ OP_MAIN_CHANGE_FOLDER "open a different folder"
+ OP_MAIN_CHANGE_FOLDER_READONLY "open a different folder in read only mode"
+ OP_MAIN_CLEAR_FLAG "clear a status flag from a message"
+diff --git a/index.c b/index.c
+index 919cf154..4e0f6e86 100644
+--- a/index.c
++++ b/index.c
+@@ -1266,8 +1266,13 @@ int mutt_index_menu(void)
+ if (attach_msg)
+ op = OP_MAIN_CHANGE_FOLDER_READONLY;
+
++ case OP_MAIN_BROWSE_MAILBOXES:
++ if (attach_msg && (op != OP_MAIN_CHANGE_FOLDER_READONLY))
++ op = OP_MAIN_BROWSE_MAILBOXES_READONLY;
++
+ /* fallback to the readonly case */
+
++ case OP_MAIN_BROWSE_MAILBOXES_READONLY:
+ case OP_MAIN_CHANGE_FOLDER_READONLY:
+ {
+ struct Buffer *folderbuf;
+@@ -1293,13 +1298,13 @@ int mutt_index_menu(void)
+ }
+ #ifdef USE_SIDEBAR
+ else if (op == OP_SIDEBAR_OPEN)
+- {
+- const char *path = mutt_sb_get_highlight();
+- if (!path || !*path)
+- goto changefoldercleanup;
+- mutt_buffer_strcpy(folderbuf, path);
+- }
++ mutt_buffer_strcpy(folderbuf, NONULL(mutt_sb_get_highlight()));
+ #endif
++
++ else if ((op == OP_MAIN_BROWSE_MAILBOXES) ||
++ (op == OP_MAIN_BROWSE_MAILBOXES_READONLY))
++ mutt_buffer_select_file(folderbuf, MUTT_SEL_FOLDER | MUTT_SEL_MAILBOX);
++
+ else
+ {
+ if (option(C_ChangeFolderNext) && Context && Context->path)
+@@ -1318,13 +1323,13 @@ int mutt_index_menu(void)
+ }
+ goto changefoldercleanup;
+ }
+- if (!mutt_buffer_len(folderbuf))
+- {
+- mutt_window_clearline(MuttMessageWindow, 0);
+- goto changefoldercleanup;
+- }
+ }
+
++ if (!mutt_buffer_len(folderbuf))
++ {
++ mutt_window_clearline(MuttMessageWindow, 0);
++ goto changefoldercleanup;
++ }
+ mutt_buffer_expand_path(folderbuf);
+ if (mx_get_magic(mutt_b2s(folderbuf)) <= 0)
+ {
+@@ -1386,7 +1391,9 @@ int mutt_index_menu(void)
+ mutt_folder_hook(mutt_b2s(folderbuf));
+
+ if ((Context = mx_open_mailbox(mutt_b2s(folderbuf),
+- (option(C_ReadOnly) || op == OP_MAIN_CHANGE_FOLDER_READONLY) ?
++ (option(C_ReadOnly) ||
++ op == OP_MAIN_CHANGE_FOLDER_READONLY ||
++ op == OP_MAIN_BROWSE_MAILBOXES_READONLY) ?
+ MUTT_READONLY : 0, NULL)) != NULL)
+ {
+ menu->current = ci_first_message();
+diff --git a/doc/neomuttrc.head b/doc/neomuttrc.head
+index 2b0020f7..0d2b2f52 100644
+--- a/doc/neomuttrc.head
++++ b/doc/neomuttrc.head
+@@ -26,8 +26,9 @@ macro index,pager,attach,compose \cb "\
+ macro generic,pager <F1> "<shell-escape> less @docdir@/manual.txt<Enter>" "show Mutt documentation"
+
+ # show the incoming mailboxes list(just like "mutt -y") and back when pressing "y"
+-macro index y "<change-folder>?<toggle-mailboxes>" "show incoming mailboxes list"
+-macro pager y "<exit><change-folder>?<toggle-mailboxes>" "show incoming mailboxes list"
++# note: these macros have been subsumed by the <browse-mailboxes> function.
++# macro index y "<change-folder>?<toggle-mailboxes>" "show incoming mailboxes list"
++# macro pager y "<exit><change-folder>?<toggle-mailboxes>" "show incoming mailboxes list"
+ bind browser y exit
+
+ # Handler for gzip compressed mailboxes
+diff --git a/functions.h b/functions.h
+index 419dfc50..ba8340b8 100644
+--- a/functions.h
++++ b/functions.h
+@@ -91,6 +91,8 @@ const struct binding_t OpMain[] = { /* map: index */
+ #endif
+ { "bounce-message", OP_BOUNCE_MESSAGE, "b" },
+ { "break-thread", OP_MAIN_BREAK_THREAD, "#" },
++ { "browse-mailboxes", OP_MAIN_BROWSE_MAILBOXES, "y" },
++ { "browse-mailboxes-readonly", OP_MAIN_BROWSE_MAILBOXES_READONLY, NULL },
+ { "change-folder", OP_MAIN_CHANGE_FOLDER, "c" },
+ { "change-folder-readonly", OP_MAIN_CHANGE_FOLDER_READONLY, "\033c" },
+ { "next-unread-mailbox", OP_MAIN_NEXT_UNREAD_MAILBOX, NULL },
+@@ -195,6 +197,8 @@ const struct binding_t OpMain[] = { /* map: index */
+
+ const struct binding_t OpPager[] = { /* map: pager */
+ { "break-thread", OP_MAIN_BREAK_THREAD, "#" },
++ { "browse-mailboxes", OP_MAIN_BROWSE_MAILBOXES, "y" },
++ { "browse-mailboxes-readonly", OP_MAIN_BROWSE_MAILBOXES_READONLY, NULL },
+ { "create-alias", OP_CREATE_ALIAS, "a" },
+ { "bounce-message", OP_BOUNCE_MESSAGE, "b" },
+ { "change-folder", OP_MAIN_CHANGE_FOLDER, "c" },
--- /dev/null
+From 71d6dbea64b3f6d9676867030214236878693bcb Mon Sep 17 00:00:00 2001
+From: Kevin McCarthy <kevin@8t8.us>
+Date: Sun, 13 Oct 2019 16:25:54 +0800
+Subject: Update mime fields when piping a message with $pipe_decode set
+
+Programs that process the message may get confused if the original
+mime fields are in the output. Add the CH_MIME flag to strip mime
+headers and CH_TXTPLAIN to add decoded text mime headers in their
+place, just as <decode-copy> does.
+
+However, make sure not to add the flags when printing, as printers
+highly likely won't care and users probably don't want to see those
+headers in their printout.
+
+Upstream-commit: https://gitlab.com/muttmua/mutt/commit/71d6dbea64b3f6d9676867030214236878693bcb
+Co-authored-by:
+---
+ commands.c | 9 ++++++++-
+ 1 file changed, 8 insertions(+), 1 deletion(-)
+
+diff --git a/commands.c b/commands.c
+index b88335d1..9a27614f 100644
+--- a/commands.c
++++ b/commands.c
+@@ -440,14 +440,21 @@ static void pipe_set_flags(int decode, int print, int *cmflags, int *chflags)
+ {
+ if (decode)
+ {
+- *cmflags |= MUTT_CM_DECODE | MUTT_CM_CHARCONV;
+ *chflags |= CH_DECODE | CH_REORDER;
++ *cmflags |= MUTT_CM_DECODE | MUTT_CM_CHARCONV;
+
+ if (option(C_Weed))
+ {
+ *chflags |= CH_WEED;
+ *cmflags |= MUTT_CM_WEED;
+ }
++
++ /* Just as with copy-decode, we need to update the
++ * mime fields to avoid confusing programs that may
++ * process the email. However, we don't want to force
++ * those fields to appear in printouts. */
++ if (!print)
++ *chflags |= CH_MIME | CH_TXTPLAIN;
+ }
+
+ if (print)
--- /dev/null
+From 9506db1e4a01fadf503b63381ab2b60dee32b836 Mon Sep 17 00:00:00 2001
+From: Kevin McCarthy <kevin@8t8.us>
+Date: Tue, 15 Oct 2019 15:26:20 +0800
+Subject: Reduce line buffer size in mx_get_magic()
+
+tmp is only used for mbox and mmdf iniital line examination. That
+only needs to look at 6 characters from the first line.
+
+Upstream-commit: https://gitlab.com/muttmua/mutt/commit/9506db1e4a01fadf503b63381ab2b60dee32b836
+Co-authored-by:
+---
+ mx.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/mx.c b/mx.c
+index 472e8ee3..f693f0e0 100644
+--- a/mx.c
++++ b/mx.c
+@@ -391,7 +391,6 @@ int mx_get_magic(const char *path)
+ {
+ struct stat st;
+ int magic = 0;
+- char tmp[PATH_MAX];
+ FILE *f;
+
+ #ifdef USE_IMAP
+@@ -437,6 +436,7 @@ int mx_get_magic(const char *path)
+ struct utimbuf times;
+ #endif /* HAVE_UTIMENSAT */
+ int ch;
++ char tmp[10];
+
+ /* Some mailbox creation tools erroneously append a blank line to
+ * a file before appending a mail message. This allows mutt to
--- /dev/null
+From a327386c5bf676a8321335fca849159ddd664ab9 Mon Sep 17 00:00:00 2001
+From: Kevin McCarthy <kevin@8t8.us>
+Date: Thu, 17 Oct 2019 15:48:31 +0800
+Subject: Stable branch quick fix for pager change-mailbox push/exec bug
+
+The menu functions mutt_push/pop_current_menu() keep track of the menu
+stack, automatically setting CurrentMenu when exiting menus.
+
+The only gotcha was the function sharing between the index and pager
+menus. The index uses a hack, setting menu->menu to MENU_PAGER for
+operations redirecting through the index and back to the pager
+afterwards.
+
+I thought this was covered by the restoration of the menu before
+returning to the pager, or when exiting the index switch. However it
+is not: invoking other menus, such as the browser, will result in
+CurrentMenu being set to the C_Pager when exiting those(by
+mutt_menu_pop_current()). This can result in folder hooks failing for
+unshared functions.
+
+A better fix is to remove the hack of using menu->menu, because this
+can easily cause a problem in the future in other situations.(I will
+make this fix in master next.) For the stable branch, I am explicitly
+setting/restoring CurrentMenu before invoking the folder hooks.
+
+Upstream-commit: https://gitlab.com/muttmua/mutt/commit/a327386c5bf676a8321335fca849159ddd664ab9
+Co-authored-by:
+---
+ index.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/index.c b/index.c
+index 32925f29..d57ce985 100644
+--- a/index.c
++++ b/index.c
+@@ -1371,6 +1371,9 @@ int mutt_index_menu(void)
+
+ mutt_sleep(0);
+
++ /* XXX: quick fix in stable branch. Better fix will be in master */
++ CurrentMenu = MENU_MAIN;
++
+ /* Note that menu->menu may be MENU_PAGER if the change folder
+ * operation originated from the pager.
+ *
--- /dev/null
+From b15e8659514362e85114a6db4a89f799a9593787 Mon Sep 17 00:00:00 2001
+From: Kevin McCarthy <kevin@8t8.us>
+Date: Thu, 17 Oct 2019 17:30:03 +0800
+Subject: Remove menu->menu hack when redirecting pager ops through index
+
+As noted in commit a327386c, this causes problems when redirecting ops
+that open new menus. There is no need to change the menu->menu type,
+as a flag works perfectly well with no such side effects.
+
+This also removes the need for comments explaning the hack before
+mutt_folder_hooks() when changing folders, or before displaying a
+message in the pager.
+
+Upstream-commit: https://gitlab.com/muttmua/mutt/commit/b15e8659514362e85114a6db4a89f799a9593787
+Co-authored-by:
+---
+ index.c | 81 ++++++++++++++++++++++-------------------------------
+ 1 file changed, 33 insertions(+), 48 deletions(-)
+
+diff --git a/index.c b/index.c
+index 9a0df384..35f106b0 100644
+--- a/index.c
++++ b/index.c
+@@ -622,6 +622,7 @@ int mutt_index_menu(void)
+ int do_buffy_notify = 1;
+ int close = 0; /* did we OP_QUIT or OP_EXIT out of this menu? */
+ int attach_msg = option(OptAttachMsg);
++ int in_pager = 0; /* set when pager redirects a function through the index */
+
+ menu = mutt_menu_new(MENU_MAIN);
+ menu->make_entry = index_make_entry;
+@@ -746,7 +747,7 @@ int mutt_index_menu(void)
+ if (op >= 0)
+ mutt_curs_set(0);
+
+- if (menu->menu == MENU_MAIN)
++ if (!in_pager)
+ {
+ index_menu_redraw(menu);
+
+@@ -908,7 +909,7 @@ int mutt_index_menu(void)
+ if (mutt_get_field(_("Jump to message: "), buf, sizeof(buf), 0) != 0
+ || !buf[0])
+ {
+- if (menu->menu == MENU_PAGER)
++ if (in_pager)
+ {
+ op = OP_DISPLAY_MESSAGE;
+ continue;
+@@ -941,7 +942,7 @@ int mutt_index_menu(void)
+ if (j >= 0)
+ {
+ menu->current = Context->hdrs[j]->virtual;
+- if (menu->menu == MENU_PAGER)
++ if (in_pager)
+ {
+ op = OP_DISPLAY_MESSAGE;
+ continue;
+@@ -1094,7 +1095,7 @@ int mutt_index_menu(void)
+ resort_index(menu);
+ set_option(OptSearchInvalid);
+ }
+- if (menu->menu == MENU_PAGER)
++ if (in_pager)
+ {
+ op = OP_DISPLAY_MESSAGE;
+ continue;
+@@ -1248,7 +1249,7 @@ int mutt_index_menu(void)
+ FREE(&Context);
+
+ /* if we were in the pager, redisplay the message */
+- if (menu->menu == MENU_PAGER)
++ if (in_pager)
+ {
+ op = OP_DISPLAY_MESSAGE;
+ continue;
+@@ -1316,7 +1317,7 @@ int mutt_index_menu(void)
+
+ if (mutt_buffer_enter_fname(cp, folderbuf, 1) == -1)
+ {
+- if (menu->menu == MENU_PAGER)
++ if (in_pager)
+ {
+ op = OP_DISPLAY_MESSAGE;
+ cont = 1;
+@@ -1380,17 +1381,6 @@ int mutt_index_menu(void)
+
+ mutt_sleep(0);
+
+- /* XXX: quick fix in stable branch. Better fix will be in master */
+- CurrentMenu = MENU_MAIN;
+-
+- /* Note that menu->menu may be MENU_PAGER if the change folder
+- * operation originated from the pager.
+- *
+- * However, exec commands currently use CurrentMenu to determine what
+- * functions are available, which is automatically set by the
+- * mutt_push/pop_current_menu() functions. If that changes, the menu
+- * would need to be reset here, and the pager cleanup code after the
+- * switch statement would need to be run. */
+ mutt_folder_hook(mutt_b2s(folderbuf));
+
+ if ((Context = mx_open_mailbox(mutt_b2s(folderbuf),
+@@ -1451,11 +1441,6 @@ int mutt_index_menu(void)
+ if (option(C_PgpAutoDecode) && (tag || !(CURHDR->security & PGP_TRADITIONAL_CHECKED)))
+ mutt_check_traditional_pgp(tag ? NULL : CURHDR, &menu->redraw);
+
+- /* If we are returning to the pager via an index menu redirection, we
+- * need to reset the menu->menu. Otherwise mutt_menu_pop_current() will
+- * set CurrentMenu incorrectly when we return back to the index menu. */
+- menu->menu = MENU_MAIN;
+-
+ if ((op = mutt_display_message(CURHDR)) < 0)
+ {
+ unset_option(OptNeedResort);
+@@ -1463,22 +1448,22 @@ int mutt_index_menu(void)
+ }
+
+ /* This is used to redirect a single operation back here afterwards. If
+- * mutt_display_message() returns 0, then the menu and pager state will
++ * mutt_display_message() returns 0, then this flag and pager state will
+ * be cleaned up after this switch statement. */
+- menu->menu = MENU_PAGER;
++ in_pager = 1;
+ menu->oldcurrent = menu->current;
+ continue;
+
+ case OP_EXIT:
+
+ close = op;
+- if (menu->menu == MENU_MAIN && attach_msg)
++ if (!in_pager && attach_msg)
+ {
+ done = 1;
+ break;
+ }
+
+- if ((menu->menu == MENU_MAIN)
++ if ((!in_pager)
+ && (query_quadoption(C_Quit,
+ _("Exit Mutt without saving?")) == MUTT_YES))
+ {
+@@ -1512,7 +1497,7 @@ int mutt_index_menu(void)
+ Context->changed = 1;
+ mutt_message _("Thread broken");
+
+- if (menu->menu == MENU_PAGER)
++ if (in_pager)
+ {
+ op = OP_DISPLAY_MESSAGE;
+ continue;
+@@ -1556,7 +1541,7 @@ int mutt_index_menu(void)
+ mutt_error _("No thread linked");
+ }
+
+- if (menu->menu == MENU_PAGER)
++ if (in_pager)
+ {
+ op = OP_DISPLAY_MESSAGE;
+ continue;
+@@ -1573,7 +1558,7 @@ int mutt_index_menu(void)
+ CHECK_ATTACH;
+ mutt_edit_content_type(CURHDR, CURHDR->content, NULL);
+ /* if we were in the pager, redisplay the message */
+- if (menu->menu == MENU_PAGER)
++ if (in_pager)
+ {
+ op = OP_DISPLAY_MESSAGE;
+ continue;
+@@ -1588,17 +1573,17 @@ int mutt_index_menu(void)
+ CHECK_VISIBLE;
+ if (menu->current >= Context->vcount - 1)
+ {
+- if (menu->menu == MENU_MAIN)
++ if (!in_pager)
+ mutt_error _("You are on the last message.");
+ break;
+ }
+ if ((menu->current = ci_next_undeleted(menu->current)) == -1)
+ {
+ menu->current = menu->oldcurrent;
+- if (menu->menu == MENU_MAIN)
++ if (!in_pager)
+ mutt_error _("No undeleted messages.");
+ }
+- else if (menu->menu == MENU_PAGER)
++ else if (in_pager)
+ {
+ op = OP_DISPLAY_MESSAGE;
+ continue;
+@@ -1613,12 +1598,12 @@ int mutt_index_menu(void)
+ CHECK_VISIBLE;
+ if (menu->current >= Context->vcount - 1)
+ {
+- if (menu->menu == MENU_MAIN)
++ if (!in_pager)
+ mutt_error _("You are on the last message.");
+ break;
+ }
+ menu->current++;
+- if (menu->menu == MENU_PAGER)
++ if (in_pager)
+ {
+ op = OP_DISPLAY_MESSAGE;
+ continue;
+@@ -1639,10 +1624,10 @@ int mutt_index_menu(void)
+ if ((menu->current = ci_previous_undeleted(menu->current)) == -1)
+ {
+ menu->current = menu->oldcurrent;
+- if (menu->menu == MENU_MAIN)
++ if (!in_pager)
+ mutt_error _("No undeleted messages.");
+ }
+- else if (menu->menu == MENU_PAGER)
++ else if (in_pager)
+ {
+ op = OP_DISPLAY_MESSAGE;
+ continue;
+@@ -1657,11 +1642,11 @@ int mutt_index_menu(void)
+ CHECK_VISIBLE;
+ if (menu->current < 1)
+ {
+- if (menu->menu == MENU_MAIN) mutt_error _("You are on the first message.");
++ if (!in_pager) mutt_error _("You are on the first message.");
+ break;
+ }
+ menu->current--;
+- if (menu->menu == MENU_PAGER)
++ if (in_pager)
+ {
+ op = OP_DISPLAY_MESSAGE;
+ continue;
+@@ -1797,7 +1782,7 @@ int mutt_index_menu(void)
+ mutt_error(_("No unread messages."));
+ }
+ }
+- else if (menu->menu == MENU_PAGER)
++ else if (in_pager)
+ {
+ op = OP_DISPLAY_MESSAGE;
+ continue;
+@@ -1895,7 +1880,7 @@ int mutt_index_menu(void)
+ CHECK_IN_MAILBOX;
+ if (mx_toggle_write(Context) == 0)
+ {
+- if (menu->menu == MENU_PAGER)
++ if (in_pager)
+ {
+ op = OP_DISPLAY_MESSAGE;
+ continue;
+@@ -1939,7 +1924,7 @@ int mutt_index_menu(void)
+ else
+ mutt_error _("You are on the first thread.");
+ }
+- else if (menu->menu == MENU_PAGER)
++ else if (in_pager)
+ {
+ op = OP_DISPLAY_MESSAGE;
+ continue;
+@@ -1959,7 +1944,7 @@ int mutt_index_menu(void)
+ {
+ menu->current = menu->oldcurrent;
+ }
+- else if (menu->menu == MENU_PAGER)
++ else if (in_pager)
+ {
+ op = OP_DISPLAY_MESSAGE;
+ continue;
+@@ -2146,7 +2131,7 @@ int mutt_index_menu(void)
+ menu->current = menu->oldcurrent;
+ menu->redraw |= REDRAW_CURRENT;
+ }
+- else if (menu->menu == MENU_PAGER)
++ else if (in_pager)
+ {
+ op = OP_DISPLAY_MESSAGE;
+ continue;
+@@ -2285,7 +2270,7 @@ int mutt_index_menu(void)
+ if (tag || !(CURHDR->security & PGP_TRADITIONAL_CHECKED))
+ mutt_check_traditional_pgp(tag ? NULL : CURHDR, &menu->redraw);
+
+- if (menu->menu == MENU_PAGER)
++ if (in_pager)
+ {
+ op = OP_DISPLAY_MESSAGE;
+ continue;
+@@ -2347,7 +2332,7 @@ int mutt_index_menu(void)
+ if ((menu->current =(op == OP_MAIN_READ_THREAD ?
+ mutt_next_thread(CURHDR) : mutt_next_subthread(CURHDR))) == -1)
+ menu->current = menu->oldcurrent;
+- else if (menu->menu == MENU_PAGER)
++ else if (in_pager)
+ {
+ op = OP_DISPLAY_MESSAGE;
+ continue;
+@@ -2584,14 +2569,14 @@ int mutt_index_menu(void)
+ #endif
+
+ default:
+- if (menu->menu == MENU_MAIN)
++ if (!in_pager)
+ km_error_key(MENU_MAIN);
+ }
+
+- if (menu->menu == MENU_PAGER)
++ if (in_pager)
+ {
+ mutt_clear_pager_position();
+- menu->menu = MENU_MAIN;
++ in_pager = 0;
+ menu->redraw = REDRAW_FULL;
+ }
+
--- /dev/null
+From e750e39c4a80bb98e98c5fc38500e0897a3e0279 Mon Sep 17 00:00:00 2001
+From: Kevin McCarthy <kevin@8t8.us>
+Date: Thu, 17 Oct 2019 18:34:55 +0800
+Subject: Clean up pager change folder aborts to return to pager
+
+Changing folder from within the pager behaved inconsistently when
+aborting, or upon a normal error. It would sometimes return the pager
+and other times return to the index.
+
+Ensure it returns to the pager, except in the case where
+mx_close_mailbox() fails due to a new mail or reopen event. In that
+case we likely want to be in the index - the message we were viewing
+could have disappeared or relocated.
+
+Upstream-commit: https://gitlab.com/muttmua/mutt/commit/e750e39c4a80bb98e98c5fc38500e0897a3e0279
+Co-authored-by:
+---
+ index.c | 20 +++++++++-----------
+ 1 file changed, 9 insertions(+), 11 deletions(-)
+
+diff --git a/index.c b/index.c
+index 35f106b0..0f93df3f 100644
+--- a/index.c
++++ b/index.c
+@@ -1277,7 +1277,7 @@ int mutt_index_menu(void)
+ case OP_MAIN_CHANGE_FOLDER_READONLY:
+ {
+ struct Buffer *folderbuf;
+- int cont = 0; /* Set if we want to continue instead of break */
++ int pager_return = 1; /* return to display message in pager */
+
+ folderbuf = mutt_buffer_pool_get();
+
+@@ -1316,14 +1316,7 @@ int mutt_index_menu(void)
+ mutt_buffer_buffy(folderbuf);
+
+ if (mutt_buffer_enter_fname(cp, folderbuf, 1) == -1)
+- {
+- if (in_pager)
+- {
+- op = OP_DISPLAY_MESSAGE;
+- cont = 1;
+- }
+ goto changefoldercleanup;
+- }
+ }
+
+ if (!mutt_buffer_len(folderbuf))
+@@ -1338,6 +1331,9 @@ int mutt_index_menu(void)
+ goto changefoldercleanup;
+ }
+
++ /* past this point, we don't return to the pager on error */
++ pager_return = 0;
++
+ /* keepalive failure in mutt_enter_fname may kill connection. #3028 */
+ if (Context && !Context->path)
+ FREE(&Context);
+@@ -1410,10 +1406,12 @@ int mutt_index_menu(void)
+
+ changefoldercleanup:
+ mutt_buffer_pool_release(&folderbuf);
+- if (cont)
++ if (in_pager && pager_return)
++ {
++ op = OP_DISPLAY_MESSAGE;
+ continue;
+- else
+- break;
++ }
++ break;
+ }
+
+ case OP_DISPLAY_MESSAGE:
--- /dev/null
+From 12cd2d529c8462268c3958e4ae2bab25cee92ae7 Mon Sep 17 00:00:00 2001
+From: Kevin McCarthy <kevin@8t8.us>
+Date: Wed, 23 Oct 2019 19:17:09 +0800
+Subject: Add typelen parameter to rfc1524_mailcap_lookup()
+
+Because of mime_lookup commands, the call to mutt_check_lookup_list()
+inside the function can modify the passed in type. Add an explicit
+length parameter to the function, rather than assume the parameter
+size. This also makes it more evident the type parameter can be
+modified to callers.
+
+Change the len parameter to mutt_check_lookup_list() to type size_t,
+just to be correct about it.
+
+Upstream-commit: https://gitlab.com/muttmua/mutt/commit/12cd2d529c8462268c3958e4ae2bab25cee92ae7
+Co-authored-by:
+---
+ email/attach.c | 14 +++++++-------
+ handler.c | 6 +++---
+ protos.h | 2 +-
+ recvattach.c | 5 +++--
+ mailcap.c | 5 ++---
+ mailcap.h | 2 +-
+ 6 files changed, 17 insertions(+), 17 deletions(-)
+
+diff --git a/email/attach.c b/email/attach.c
+index de32d1fb..5e9906f5 100644
+--- a/email/attach.c
++++ b/email/attach.c
+@@ -58,7 +58,7 @@ int mutt_get_tmp_attachment(struct Body *a)
+ entry = rfc1524_new_entry();
+
+ snprintf(type, sizeof(type), "%s/%s", TYPE(a), a->subtype);
+- rfc1524_mailcap_lookup(a, type, entry, 0);
++ rfc1524_mailcap_lookup(a, type, sizeof(type), entry, 0);
+ mutt_rfc1524_expand_filename(entry->nametemplate, a->filename, tempfile);
+
+ rfc1524_free_entry(&entry);
+@@ -103,7 +103,7 @@ int mutt_compose_attachment(struct Body *a)
+ int rc = 0;
+
+ snprintf(type, sizeof(type), "%s/%s", TYPE(a), a->subtype);
+- if (rfc1524_mailcap_lookup(a, type, entry, MUTT_COMPOSE))
++ if (rfc1524_mailcap_lookup(a, type, sizeof(type), entry, MUTT_COMPOSE))
+ {
+ if (entry->composecommand || entry->composetypecommand)
+ {
+@@ -239,7 +239,7 @@ int mutt_edit_attachment(struct Body *a)
+ int rc = 0;
+
+ snprintf(type, sizeof(type), "%s/%s", TYPE(a), a->subtype);
+- if (rfc1524_mailcap_lookup(a, type, entry, MUTT_EDIT))
++ if (rfc1524_mailcap_lookup(a, type, sizeof(type), entry, MUTT_EDIT))
+ {
+ if (entry->editcommand)
+ {
+@@ -303,7 +303,7 @@ bailout:
+ }
+
+
+-void mutt_check_lookup_list(struct Body *b, char *type, int len)
++void mutt_check_lookup_list(struct Body *b, char *type, size_t len)
+ {
+ struct ListHead *t = MimeLookupList;
+ int i;
+@@ -374,7 +374,7 @@ int mutt_view_attachment(FILE *fp, struct Body *a, int flag, struct Email *hdr,
+ if (use_mailcap)
+ {
+ entry = rfc1524_new_entry();
+- if (!rfc1524_mailcap_lookup(a, type, entry, 0))
++ if (!rfc1524_mailcap_lookup(a, type, sizeof(type), entry, 0))
+ {
+ if (flag == MUTT_REGULAR)
+ {
+@@ -929,7 +929,7 @@ int mutt_print_attachment(FILE *fp, struct Body *a)
+
+ snprintf(type, sizeof(type), "%s/%s", TYPE(a), a->subtype);
+
+- if (rfc1524_mailcap_lookup(a, type, NULL, MUTT_PRINT))
++ if (rfc1524_mailcap_lookup(a, type, sizeof(type), NULL, MUTT_PRINT))
+ {
+ struct MailcapEntry *entry = NULL;
+ int piped = FALSE;
+@@ -937,7 +937,7 @@ int mutt_print_attachment(FILE *fp, struct Body *a)
+ mutt_debug(LL_DEBUG2, "Using mailcap...\n"));
+
+ entry = rfc1524_new_entry();
+- rfc1524_mailcap_lookup(a, type, entry, MUTT_PRINT);
++ rfc1524_mailcap_lookup(a, type, sizeof(type), entry, MUTT_PRINT);
+ mutt_rfc1524_expand_filename(entry->nametemplate, a->filename,
+ newfile);
+
+diff --git a/handler.c b/handler.c
+index 5a0766a8..5e613d41 100644
+--- a/handler.c
++++ b/handler.c
+@@ -955,7 +955,7 @@ static int is_mmnoask(const char *buf)
+ */
+ static int is_autoview(struct Body *b)
+ {
+- char type[128];
++ char type[256];
+ int is_autoview = 0;
+
+ snprintf(type, sizeof(type), "%s/%s", TYPE(b), b->subtype);
+@@ -988,7 +988,7 @@ static int is_autoview(struct Body *b)
+ *
+ * WARNING: type is altered by this call as a result of `mime_lookup' support */
+ if (is_autoview)
+- return rfc1524_mailcap_lookup(b, type, NULL, MUTT_AUTOVIEW);
++ return rfc1524_mailcap_lookup(b, type, sizeof(type), NULL, MUTT_AUTOVIEW);
+
+ return 0;
+ }
+@@ -1320,7 +1320,7 @@ static int autoview_handler(struct Body *a, struct State *s)
+ tempfile = mutt_buffer_pool_get();
+
+ snprintf(type, sizeof(type), "%s/%s", TYPE(a), a->subtype);
+- rfc1524_mailcap_lookup(a, type, entry, MUTT_AUTOVIEW);
++ rfc1524_mailcap_lookup(a, type, sizeof(type), entry, MUTT_AUTOVIEW);
+
+ fname = mutt_str_strdup(a->filename);
+ mutt_file_sanitize_filename(fname, 1);
+diff --git a/protos.h b/protos.h
+index 8ee932c8..759acc4f 100644
+--- a/protos.h
++++ b/protos.h
+@@ -236,7 +236,7 @@ const char *mutt_getcwd(struct Buffer *);
+ void mutt_help(int);
+ const char *mutt_idxfmt_hook(const char *, struct Context *, struct Email *);
+ void mutt_draw_tree(struct Context *);
+-void mutt_check_lookup_list(struct Body *, char *, int);
++void mutt_check_lookup_list(struct Body *, char *, size_t);
+ void mutt_make_attribution(struct Context *ctx, struct Email *cur, FILE *out);
+ void mutt_make_forward_subject(struct Envelope *env, struct Context *ctx, struct Email *cur);
+ void mutt_make_help(char *, size_t, const char *, int, int);
+diff --git a/recvattach.c b/recvattach.c
+index 087858c9..c2da1785 100644
+--- a/recvattach.c
++++ b/recvattach.c
+@@ -741,7 +741,7 @@ static int can_print(ATTACH_CONTEXT *actx, struct Body *top, int tag)
+ snprintf(type, sizeof(type), "%s/%s", TYPE(top), top->subtype);
+ if (!tag || top->tagged)
+ {
+- if (!rfc1524_mailcap_lookup(top, type, NULL, MUTT_PRINT))
++ if (!rfc1524_mailcap_lookup(top, type, sizeof(type), NULL, MUTT_PRINT))
+ {
+ if (mutt_str_strcasecmp("text/plain", top->subtype) &&
+ mutt_str_strcasecmp("application/postscript", top->subtype))
+@@ -775,7 +775,8 @@ static void print_attachment_list(ATTACH_CONTEXT *actx, FILE *fp, int tag, struct Body
+ if (!tag || top->tagged)
+ {
+ snprintf(type, sizeof(type), "%s/%s", TYPE(top), top->subtype);
+- if (!option(C_AttachSplit) && !rfc1524_mailcap_lookup(top, type, NULL, MUTT_PRINT))
++ if (!option(C_AttachSplit) &&
++ !rfc1524_mailcap_lookup(top, type, sizeof(type), NULL, MUTT_PRINT))
+ {
+ if (!mutt_str_strcasecmp("text/plain", top->subtype) ||
+ !mutt_str_strcasecmp("application/postscript", top->subtype))
+diff --git a/mailcap.c b/mailcap.c
+index 6597df2b..2fc9f175 100644
+--- a/mailcap.c
++++ b/mailcap.c
+@@ -420,7 +420,7 @@ void rfc1524_free_entry(struct MailcapEntry **entry)
+ * in *entry, and returns 1. On failure(not found), returns 0.
+ * If entry == NULL just return 1 if the given type is found.
+ */
+-int rfc1524_mailcap_lookup(struct Body *a, char *type, struct MailcapEntry *entry, int opt)
++int rfc1524_mailcap_lookup(struct Body *a, char *type, size_t typelen, struct MailcapEntry *entry, int opt)
+ {
+ struct Buffer *path = NULL;
+ int found = FALSE;
+@@ -438,8 +438,7 @@ int rfc1524_mailcap_lookup(struct Body *a, char *type, struct MailcapEntry *entry, int opt)
+ return 0;
+ }
+
+- /* FIXME: sizeof type should be passed to rfc1524_mailcap_lookup() */
+- mutt_check_lookup_list(a, type, 128);
++ mutt_check_lookup_list(a, type, typelen);
+
+ path = mutt_buffer_pool_get();
+
+diff --git a/mailcap.h b/mailcap.h
+index 87b06d6d..bdf0468e 100644
+--- a/mailcap.h
++++ b/mailcap.h
+@@ -38,7 +38,7 @@ struct MailcapEntry *rfc1524_new_entry(void);
+ void rfc1524_free_entry(struct MailcapEntry **);
+ int mutt_rfc1524_expand_command(struct Body *, const char *, const char *, struct Buffer *);
+ void mutt_rfc1524_expand_filename(const char *, const char *, struct Buffer *);
+-int rfc1524_mailcap_lookup(struct Body *, char *, struct MailcapEntry *, int);
++int rfc1524_mailcap_lookup(struct Body *, char *, size_t, struct MailcapEntry *, int);
+ int mutt_file_rename(const char *, const char *);
+
+ #endif /* _RFC1524_H */
--- /dev/null
+From 671e653c6b5d70adeb644a36961bdc2c8d2f2e9f Mon Sep 17 00:00:00 2001
+From: Kevin McCarthy <kevin@8t8.us>
+Date: Fri, 25 Oct 2019 15:28:25 +0800
+Subject: Convert mutt_message_to_7bit() to use buffer
+
+Clean up the error handling a bit.
+
+Because of the recursive invocation, avoid the buffer pool in this
+case.
+
+Upstream-commit: https://gitlab.com/muttmua/mutt/commit/671e653c6b5d70adeb644a36961bdc2c8d2f2e9f
+Co-authored-by:
+---
+ sendlib.c | 36 ++++++++++++++++++++++--------------
+ 1 file changed, 22 insertions(+), 14 deletions(-)
+
+diff --git a/sendlib.c b/sendlib.c
+index 72ac3a93..de2cf78f 100644
+--- a/sendlib.c
++++ b/sendlib.c
+@@ -1072,8 +1072,7 @@ bye:
+
+ void mutt_message_to_7bit(struct Body *a, FILE *fp)
+ {
+- char temp[PATH_MAX];
+- char *line = NULL;
++ struct Buffer *temp = NULL;
+ FILE *fpin = NULL;
+ FILE *fpout = NULL;
+ struct stat sb;
+@@ -1092,12 +1091,15 @@ void mutt_message_to_7bit(struct Body *a, FILE *fp)
+ {
+ mutt_perror("stat");
+ mutt_file_fclose(&fpin);
++ goto cleanup;
+ }
+ a->length = sb.st_size;
+ }
+
+- mutt_mktemp(temp, sizeof(temp));
+- if (!(fpout = mutt_file_fopen(temp, "w+")))
++ /* Avoid buffer pool due to recursion */
++ temp = mutt_buffer_new();
++ mutt_buffer_mktemp(temp);
++ if (!(fpout = mutt_file_fopen(mutt_b2s(temp), "w+")))
+ {
+ mutt_perror("fopen");
+ goto cleanup;
+@@ -1116,31 +1118,37 @@ void mutt_message_to_7bit(struct Body *a, FILE *fp)
+ fputc('\n', fpout);
+ mutt_write_mime_body(a->parts, fpout);
+
+-cleanup:
+- FREE(&line);
+-
+- if (fpin && fpin != fp)
++ if (fpin != fp)
+ mutt_file_fclose(&fpin);
+- if (fpout)
+- mutt_file_fclose(&fpout);
+- else
+- return;
++ mutt_file_fclose(&fpout);
+
+ a->encoding = ENC_7BIT;
+ FREE(&a->d_filename);
+ a->d_filename = a->filename;
+ if (a->filename && a->unlink)
+ unlink(a->filename);
+- a->filename = mutt_str_strdup(temp);
++ a->filename = mutt_str_strdup(mutt_b2s(temp));
+ a->unlink = 1;
+ if (stat(a->filename, &sb) == -1)
+ {
+ mutt_perror("stat");
+- return;
++ goto cleanup;
+ }
+ a->length = sb.st_size;
+ mutt_body_free(&a->parts);
+ a->hdr->content = NULL;
++
++cleanup:
++ if (fpin && fpin != fp)
++ mutt_file_fclose(&fpin);
++
++ if (fpout)
++ {
++ mutt_file_fclose(&fpout);
++ mutt_file_unlink(mutt_b2s(temp));
++ }
++
++ mutt_buffer_free(&temp);
+ }
+
+ static void transform_to_7bit(struct Body *a, FILE *fpin)
--- /dev/null
+From 3565f686bf929fe91ca07d683d99125b5a8b2c21 Mon Sep 17 00:00:00 2001
+From: Kevin McCarthy <kevin@8t8.us>
+Date: Fri, 25 Oct 2019 15:55:49 +0800
+Subject: Convert transform_to_7bit() to use buffer pool
+
+Upstream-commit: https://gitlab.com/muttmua/mutt/commit/3565f686bf929fe91ca07d683d99125b5a8b2c21
+Co-authored-by:
+---
+ sendlib.c | 13 +++++++++----
+ 1 file changed, 9 insertions(+), 4 deletions(-)
+
+diff --git a/sendlib.c b/sendlib.c
+index de2cf78f..5850da3e 100644
+--- a/sendlib.c
++++ b/sendlib.c
+@@ -1153,7 +1153,7 @@ cleanup:
+
+ static void transform_to_7bit(struct Body *a, FILE *fpin)
+ {
+- char buff[PATH_MAX];
++ struct Buffer *buff;
+ struct State s;
+ struct stat sb;
+
+@@ -1176,10 +1176,14 @@ static void transform_to_7bit(struct Body *a, FILE *fpin)
+ a->noconv = 1;
+ a->force_charset = 1;
+
+- mutt_mktemp(buff, sizeof(buff));
+- if ((s.fpout = mutt_file_fopen(buff, "w")) == NULL)
++ /* Because of the potential recursion in message types, we
++ * restrict the lifetime of the buffer tightly */
++ buff = mutt_buffer_pool_get();
++ mutt_buffer_mktemp(buff);
++ if ((s.fpout = mutt_file_fopen(mutt_b2s(buff), "w")) == NULL)
+ {
+ mutt_perror("fopen");
++ mutt_buffer_pool_release(&buff);
+ return;
+ }
+ s.fpin = fpin;
+@@ -1187,7 +1191,8 @@ static void transform_to_7bit(struct Body *a, FILE *fpin)
+ mutt_file_fclose(&s.fpout);
+ FREE(&a->d_filename);
+ a->d_filename = a->filename;
+- a->filename = mutt_str_strdup(buff);
++ a->filename = mutt_str_strdup(mutt_b2s(buff));
++ mutt_buffer_pool_release(&buff);
+ a->unlink = 1;
+ if (stat(a->filename, &sb) == -1)
+ {
--- /dev/null
+From 8de05d5ffc86c1a9dad61e83189a74331c2869b9 Mon Sep 17 00:00:00 2001
+From: Kevin McCarthy <kevin@8t8.us>
+Date: Fri, 25 Oct 2019 19:13:50 +0800
+Subject: Convert send_msg() $sendmail_wait to use buffer pool
+
+Upstream-commit: https://gitlab.com/muttmua/mutt/commit/8de05d5ffc86c1a9dad61e83189a74331c2869b9
+Co-authored-by:
+---
+ sendlib.c | 8 +++++---
+ 1 file changed, 5 insertions(+), 3 deletions(-)
+
+diff --git a/sendlib.c b/sendlib.c
+index 5850da3e..0b1766ce 100644
+--- a/sendlib.c
++++ b/sendlib.c
+@@ -2268,10 +2268,12 @@ send_msg(const char *path, char **args, const char *msg, char **tempfile)
+
+ if (C_SendmailWait >= 0 && tempfile)
+ {
+- char tmp[PATH_MAX];
++ struct Buffer *tmp;
+
+- mutt_mktemp(tmp, sizeof(tmp));
+- *tempfile = mutt_str_strdup(tmp);
++ tmp = mutt_buffer_pool_get();
++ mutt_buffer_mktemp(tmp);
++ *tempfile = mutt_str_strdup(mutt_b2s(tmp));
++ mutt_buffer_pool_release(&tmp);
+ }
+
+ if ((pid = fork()) == 0)
--- /dev/null
+From 58a8189770149329507f4d64224a8c6cc26b09f2 Mon Sep 17 00:00:00 2001
+From: Kevin McCarthy <kevin@8t8.us>
+Date: Fri, 25 Oct 2019 19:29:56 +0800
+Subject: Convert _mutt_bounce_message to use buffer pool
+
+Upstream-commit: https://gitlab.com/muttmua/mutt/commit/58a8189770149329507f4d64224a8c6cc26b09f2
+Co-authored-by:
+---
+ sendlib.c | 14 +++++++++-----
+ 1 file changed, 9 insertions(+), 5 deletions(-)
+
+diff --git a/sendlib.c b/sendlib.c
+index 0b1766ce..2d5d221a 100644
+--- a/sendlib.c
++++ b/sendlib.c
+@@ -2633,7 +2633,8 @@ static int _mutt_bounce_message(FILE *fp, struct Email *h, struct Address *to, const char *r
+ {
+ int i, ret = 0;
+ FILE *f;
+- char date[128], tempfile[PATH_MAX];
++ char date[128];
++ struct Buffer *tempfile;
+ struct Message *msg = NULL;
+
+ if (!h)
+@@ -2651,8 +2652,9 @@ static int _mutt_bounce_message(FILE *fp, struct Email *h, struct Address *to, const char *r
+
+ if (!fp) fp = msg->fp;
+
+- mutt_mktemp(tempfile, sizeof(tempfile));
+- if ((f = mutt_file_fopen(tempfile, "w")) != NULL)
++ tempfile = mutt_buffer_pool_get();
++ mutt_buffer_mktemp(tempfile);
++ if ((f = mutt_file_fopen(mutt_b2s(tempfile), "w")) != NULL)
+ {
+ int ch_flags = CH_XMIT | CH_NONEWLINE | CH_NOQFROM;
+ char* msgid_str;
+@@ -2675,14 +2677,16 @@ static int _mutt_bounce_message(FILE *fp, struct Email *h, struct Address *to, const char *r
+
+ #if USE_SMTP
+ if (C_SmtpUrl)
+- ret = mutt_smtp_send(env_from, to, NULL, NULL, tempfile,
++ ret = mutt_smtp_send(env_from, to, NULL, NULL, mutt_b2s(tempfile),
+ h->content->encoding == ENC_8BIT);
+ else
+ #endif /* USE_SMTP */
+- ret = mutt_invoke_sendmail(env_from, to, NULL, NULL, tempfile,
++ ret = mutt_invoke_sendmail(env_from, to, NULL, NULL, mutt_b2s(tempfile),
+ h->content->encoding == ENC_8BIT);
+ }
+
++ mutt_buffer_pool_release(&tempfile);
++
+ if (msg)
+ mx_close_message(Context, &msg);
+
--- /dev/null
+From 7e29eb237f17bd573a93c6e5f71bfe87f92909c7 Mon Sep 17 00:00:00 2001
+From: Kevin McCarthy <kevin@8t8.us>
+Date: Sat, 26 Oct 2019 19:36:33 +0800
+Subject: Convert mutt_write_fcc() to use buffer pool
+
+Upstream-commit: https://gitlab.com/muttmua/mutt/commit/7e29eb237f17bd573a93c6e5f71bfe87f92909c7
+Co-authored-by:
+---
+ sendlib.c | 35 ++++++++++++++++++++++-------------
+ 1 file changed, 22 insertions(+), 13 deletions(-)
+
+diff --git a/sendlib.c b/sendlib.c
+index 2d5d221a..cc7a8145 100644
+--- a/sendlib.c
++++ b/sendlib.c
+@@ -2807,9 +2807,9 @@ int mutt_write_fcc(const char *path, struct Email *hdr, const char *msgid, int post,
+ {
+ struct Context f;
+ struct Message *msg;
+- char tempfile[PATH_MAX];
++ struct Buffer *tempfile = NULL;
+ FILE *tempfp = NULL;
+- int r, need_buffy_cleanup = 0;
++ int r = -1, need_buffy_cleanup = 0;
+ struct stat st;
+ char buf[128];
+ int onm_flags;
+@@ -2821,7 +2821,7 @@ int mutt_write_fcc(const char *path, struct Email *hdr, const char *msgid, int post,
+ {
+ mutt_debug(LL_DEBUG1, "mutt_write_fcc(): unable to open mailbox %s in append-mode, aborting.\n",
+ path));
+- return (-1);
++ goto cleanup;
+ }
+
+ /* We need to add a Content-Length field to avoid problems where a line in
+@@ -2829,12 +2829,13 @@ int mutt_write_fcc(const char *path, struct Email *hdr, const char *msgid, int post,
+ */
+ if (f.magic == MUTT_MMDF || f.magic == MUTT_MBOX)
+ {
+- mutt_mktemp(tempfile, sizeof(tempfile));
+- if ((tempfp = mutt_file_fopen(tempfile, "w+")) == NULL)
++ tempfile = mutt_buffer_pool_get();
++ mutt_buffer_mktemp(tempfile);
++ if ((tempfp = mutt_file_fopen(mutt_b2s(tempfile), "w+")) == NULL)
+ {
+- mutt_perror(tempfile);
++ mutt_perror(mutt_b2s(tempfile));
+ mx_close_mailbox(&f, NULL);
+- return (-1);
++ goto cleanup;
+ }
+ /* remember new mail status before appending message */
+ need_buffy_cleanup = 1;
+@@ -2848,7 +2849,7 @@ int mutt_write_fcc(const char *path, struct Email *hdr, const char *msgid, int post,
+ if ((msg = mx_open_new_message(&f, hdr, onm_flags)) == NULL)
+ {
+ mx_close_mailbox(&f, NULL);
+- return (-1);
++ goto cleanup;
+ }
+
+ /* post == 1 => postpone message.
+@@ -2971,13 +2972,13 @@ int mutt_write_fcc(const char *path, struct Email *hdr, const char *msgid, int post,
+ fflush(tempfp);
+ if (ferror(tempfp))
+ {
+- mutt_debug(LL_DEBUG1, "mutt_write_fcc(): %s: write failed.\n", tempfile));
++ mutt_debug(LL_DEBUG1, "mutt_write_fcc(): %s: write failed.\n", mutt_b2s(tempfile)));
+ mutt_file_fclose(&tempfp);
+- unlink(tempfile);
++ unlink(mutt_b2s(tempfile));
+ mx_commit_message(msg, &f); /* XXX - really? */
+ mx_close_message(&f, &msg);
+ mx_close_mailbox(&f, NULL);
+- return -1;
++ goto cleanup;
+ }
+
+ /* count the number of lines */
+@@ -2990,11 +2991,11 @@ int mutt_write_fcc(const char *path, struct Email *hdr, const char *msgid, int post,
+ /* copy the body and clean up */
+ rewind(tempfp);
+ r = mutt_file_copy_stream(tempfp, msg->fp);
+- if (fclose(tempfp) != 0)
++ if (mutt_file_fclose(&tempfp) != 0)
+ r = -1;
+ /* if there was an error, leave the temp version */
+ if (!r)
+- unlink(tempfile);
++ unlink(mutt_b2s(tempfile));
+ }
+ else
+ {
+@@ -3013,5 +3014,13 @@ int mutt_write_fcc(const char *path, struct Email *hdr, const char *msgid, int post,
+ if (post)
+ set_noconv_flags(hdr->content, 0);
+
++cleanup:
++ if (tempfp)
++ {
++ mutt_file_fclose(&tempfp);
++ unlink(mutt_b2s(tempfile));
++ }
++ mutt_buffer_pool_release(&tempfile);
++
+ return r;
+ }