NeoMutt  2021-10-22-8-g9cb437
Teaching an old dog new tricks
DOXYGEN
browser.c File Reference

File/Mailbox Browser Dialog. More...

#include "config.h"
#include <dirent.h>
#include <errno.h>
#include <grp.h>
#include <limits.h>
#include <locale.h>
#include <pwd.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include "mutt/lib.h"
#include "config/lib.h"
#include "email/lib.h"
#include "core/lib.h"
#include "conn/lib.h"
#include "gui/lib.h"
#include "mutt.h"
#include "browser.h"
#include "attach/lib.h"
#include "menu/lib.h"
#include "question/lib.h"
#include "send/lib.h"
#include "format_flags.h"
#include "mutt_globals.h"
#include "mutt_mailbox.h"
#include "muttlib.h"
#include "mx.h"
#include "opcodes.h"
#include "options.h"
#include "imap/lib.h"
#include "nntp/lib.h"
#include "nntp/adata.h"
#include "nntp/mdata.h"
+ Include dependency graph for browser.c:

Go to the source code of this file.

Functions

static void init_lastdir (void)
 Initialise the browser directories. More...
 
void mutt_browser_cleanup (void)
 Clean up working Buffers. More...
 
static void destroy_state (struct BrowserState *state)
 Free the BrowserState. More...
 
static int browser_compare_subject (const void *a, const void *b)
 Compare the subject of two browser entries - Implements sort_t -. More...
 
static int browser_compare_order (const void *a, const void *b)
 Compare the order of creation of two browser entries - Implements sort_t -. More...
 
static int browser_compare_desc (const void *a, const void *b)
 Compare the descriptions of two browser entries - Implements sort_t -. More...
 
static int browser_compare_date (const void *a, const void *b)
 Compare the date of two browser entries - Implements sort_t -. More...
 
static int browser_compare_size (const void *a, const void *b)
 Compare the size of two browser entries - Implements sort_t -. More...
 
static int browser_compare_count (const void *a, const void *b)
 Compare the message count of two browser entries - Implements sort_t -. More...
 
static int browser_compare_count_new (const void *a, const void *b)
 Compare the new count of two browser entries - Implements sort_t -. More...
 
static int browser_compare (const void *a, const void *b)
 Sort the items in the browser - Implements sort_t -. More...
 
static void browser_sort (struct BrowserState *state)
 Sort the entries in the browser. More...
 
static bool link_is_dir (const char *folder, const char *path)
 Does this symlink point to a directory? More...
 
static const char * folder_format_str (char *buf, size_t buflen, size_t col, int cols, char op, const char *src, const char *prec, const char *if_str, const char *else_str, intptr_t data, MuttFormatFlags flags)
 Format a string for the folder browser - Implements format_t -. More...
 
static void add_folder (struct Menu *menu, struct BrowserState *state, const char *name, const char *desc, const struct stat *st, struct Mailbox *m, void *data)
 Add a folder to the browser list. More...
 
static void init_state (struct BrowserState *state, struct Menu *menu)
 Initialise a browser state. More...
 
static int examine_directory (struct Mailbox *m, struct Menu *menu, struct BrowserState *state, const char *d, const char *prefix)
 Get list of all files/newsgroups with mask. More...
 
static int examine_mailboxes (struct Mailbox *m, struct Menu *menu, struct BrowserState *state)
 Get list of mailboxes/subscribed newsgroups. More...
 
static int select_file_search (struct Menu *menu, regex_t *rx, int line)
 Menu search callback for matching files - Implements Menu::search() -. More...
 
static void folder_make_entry (struct Menu *menu, char *buf, size_t buflen, int line)
 Format a menu item for the folder browser - Implements Menu::make_entry() -. More...
 
static void browser_highlight_default (struct BrowserState *state, struct Menu *menu)
 Decide which browser item should be highlighted. More...
 
static void init_menu (struct BrowserState *state, struct Menu *menu, struct Mailbox *m, struct MuttWindow *sbar)
 Set up a new menu. More...
 
static int file_tag (struct Menu *menu, int sel, int act)
 Tag an entry in the menu - Implements Menu::tag() -. More...
 
static int browser_config_observer (struct NotifyCallback *nc)
 Notification that a Config Variable has changed - Implements observer_t -. More...
 
static int browser_window_observer (struct NotifyCallback *nc)
 Notification that a Window has changed - Implements observer_t -. More...
 
void mutt_browser_select_dir (const char *f)
 Remember the last directory selected. More...
 
void mutt_buffer_select_file (struct Buffer *file, SelectFileFlags flags, struct Mailbox *m, char ***files, int *numfiles)
 Let the user select a file. More...
 
void mutt_select_file (char *file, size_t filelen, SelectFileFlags flags, struct Mailbox *m, char ***files, int *numfiles)
 Let the user select a file. More...
 

Variables

static const struct Mapping FolderHelp []
 Help Bar for the File/Dir/Mailbox browser dialog. More...
 
static const struct Mapping FolderNewsHelp []
 Help Bar for the NNTP Mailbox browser dialog. More...
 
static struct Buffer LastDir = { 0 }
 
static struct Buffer LastDirBackup = { 0 }
 

Detailed Description

File/Mailbox Browser Dialog.

Authors
  • Michael R. Elkins
  • R Primus

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.

Definition in file browser.c.

Function Documentation

◆ init_lastdir()

static void init_lastdir ( void  )
static

Initialise the browser directories.

These keep track of where the browser used to be looking.

Definition at line 144 of file browser.c.

145 {
146  static bool done = false;
147  if (!done)
148  {
151  done = true;
152  }
153 }
static struct Buffer LastDir
Definition: browser.c:136
static struct Buffer LastDirBackup
Definition: browser.c:137
void mutt_buffer_alloc(struct Buffer *buf, size_t new_size)
Make sure a buffer can store at least new_size bytes.
Definition: buffer.c:265
#define PATH_MAX
Definition: mutt.h:40
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_browser_cleanup()

void mutt_browser_cleanup ( void  )

Clean up working Buffers.

Definition at line 158 of file browser.c.

159 {
162 }
void mutt_buffer_dealloc(struct Buffer *buf)
Release the memory allocated by a buffer.
Definition: buffer.c:294
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ destroy_state()

static void destroy_state ( struct BrowserState state)
static

Free the BrowserState.

Parameters
stateState to free

Frees up the memory allocated for the local-global variables.

Definition at line 170 of file browser.c.

171 {
172  struct FolderFile *ff = NULL;
173  ARRAY_FOREACH(ff, &state->entry)
174  {
175  FREE(&ff->name);
176  FREE(&ff->desc);
177  }
178  ARRAY_FREE(&state->entry);
179 
180 #ifdef USE_IMAP
181  FREE(&state->folder);
182 #endif
183 }
#define ARRAY_FOREACH(elem, head)
Iterate over all elements of the array.
Definition: array.h:208
#define ARRAY_FREE(head)
Release all memory.
Definition: array.h:200
#define FREE(x)
Definition: memory.h:40
char * folder
Folder name.
Definition: browser.h:96
struct BrowserStateEntry entry
Array of files / dirs / mailboxes.
Definition: browser.h:93
Browser entry representing a folder/dir.
Definition: browser.h:54
char * name
Name of file/dir/mailbox.
Definition: browser.h:62
char * desc
Description of mailbox.
Definition: browser.h:63
+ Here is the caller graph for this function:

◆ browser_sort()

static void browser_sort ( struct BrowserState state)
static

Sort the entries in the browser.

Parameters
stateBrowser state

Call to qsort using browser_compare function. Some specific sort methods are not used via NNTP.

Definition at line 342 of file browser.c.

343 {
344  const short c_sort_browser = cs_subset_sort(NeoMutt->sub, "sort_browser");
345  switch (c_sort_browser & SORT_MASK)
346  {
347 #ifdef USE_NNTP
348  case SORT_SIZE:
349  case SORT_DATE:
350  if (OptNews)
351  return;
352 #endif
353  default:
354  break;
355  }
356 
357  ARRAY_SORT(&state->entry, browser_compare);
358 }
#define ARRAY_SORT(head, fn)
Sort an array.
Definition: array.h:274
static int browser_compare(const void *a, const void *b)
Sort the items in the browser - Implements sort_t -.
Definition: browser.c:304
short cs_subset_sort(const struct ConfigSubset *sub, const char *name)
Get a sort config item by name.
Definition: helpers.c:292
bool OptNews
(pseudo) used to change reader mode
Definition: options.h:50
#define SORT_MASK
Mask for the sort id.
Definition: sort2.h:78
@ SORT_SIZE
Sort by the size of the email.
Definition: sort2.h:44
@ SORT_DATE
Sort by the date the email was sent.
Definition: sort2.h:43
Container for Accounts, Notifications.
Definition: neomutt.h:37
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ link_is_dir()

static bool link_is_dir ( const char *  folder,
const char *  path 
)
static

Does this symlink point to a directory?

Parameters
folderFolder
pathLink name
Return values
trueLinks to a directory
falseOtherwise

Definition at line 367 of file browser.c.

368 {
369  struct stat st = { 0 };
370  bool retval = false;
371 
372  struct Buffer *fullpath = mutt_buffer_pool_get();
373  mutt_buffer_concat_path(fullpath, folder, path);
374 
375  if (stat(mutt_buffer_string(fullpath), &st) == 0)
376  retval = S_ISDIR(st.st_mode);
377 
378  mutt_buffer_pool_release(&fullpath);
379 
380  return retval;
381 }
size_t mutt_buffer_concat_path(struct Buffer *buf, const char *dir, const char *fname)
Join a directory name and a filename.
Definition: buffer.c:374
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:77
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
String manipulation buffer.
Definition: buffer.h:34
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ add_folder()

static void add_folder ( struct Menu menu,
struct BrowserState state,
const char *  name,
const char *  desc,
const struct stat *  st,
struct Mailbox m,
void *  data 
)
static

Add a folder to the browser list.

Parameters
menuMenu to use
stateBrowser state
nameName of folder
descDescription of folder
ststat info for the folder
mMailbox
dataData to associate with the folder

Definition at line 660 of file browser.c.

663 {
664  if ((!menu || state->is_mailbox_list) && m && (m->flags & MB_HIDDEN))
665  {
666  return;
667  }
668 
669  struct FolderFile ff = { 0 };
670 
671  if (st)
672  {
673  ff.mode = st->st_mode;
674  ff.mtime = st->st_mtime;
675  ff.size = st->st_size;
676  ff.gid = st->st_gid;
677  ff.uid = st->st_uid;
678  ff.nlink = st->st_nlink;
679  ff.local = true;
680  }
681  else
682  ff.local = false;
683 
684  if (m)
685  {
686  ff.has_mailbox = true;
687  ff.gen = m->gen;
688  ff.has_new_mail = m->has_new;
689  ff.msg_count = m->msg_count;
690  ff.msg_unread = m->msg_unread;
691  }
692 
693  ff.name = mutt_str_dup(name);
694  ff.desc = mutt_str_dup(desc ? desc : name);
695 #ifdef USE_IMAP
696  ff.imap = false;
697 #endif
698 #ifdef USE_NNTP
699  if (OptNews)
700  ff.nd = data;
701 #endif
702 
703  ARRAY_ADD(&state->entry, ff);
704 }
#define ARRAY_ADD(head, elem)
Add an element at the end of the array.
Definition: array.h:152
#define MB_HIDDEN
Definition: mailbox.h:38
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:370
bool is_mailbox_list
Viewing mailboxes.
Definition: browser.h:98
bool imap
This is an IMAP folder.
Definition: browser.h:72
bool has_mailbox
This is a mailbox.
Definition: browser.h:76
uid_t uid
File's User ID.
Definition: browser.h:58
gid_t gid
File's Group ID.
Definition: browser.h:59
bool has_new_mail
true if mailbox has "new mail"
Definition: browser.h:65
nlink_t nlink
Number of hard links.
Definition: browser.h:60
struct NntpMboxData * nd
Extra NNTP data.
Definition: browser.h:80
off_t size
File size.
Definition: browser.h:56
int gen
Unique id, used for (un)sorting.
Definition: browser.h:83
time_t mtime
Modification time.
Definition: browser.h:57
int msg_count
total number of messages
Definition: browser.h:66
mode_t mode
File permissions.
Definition: browser.h:55
int msg_unread
number of unread messages
Definition: browser.h:67
bool has_new
Mailbox has new mail.
Definition: mailbox.h:88
int msg_count
Total number of messages.
Definition: mailbox.h:91
int msg_unread
Number of unread messages.
Definition: mailbox.h:92
uint8_t flags
e.g. MB_NORMAL
Definition: mailbox.h:134
int gen
Generation number, for sorting.
Definition: mailbox.h:150
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ init_state()

static void init_state ( struct BrowserState state,
struct Menu menu 
)
static

Initialise a browser state.

Parameters
stateBrowserState to initialise
menuCurrent menu

Definition at line 711 of file browser.c.

712 {
713  ARRAY_INIT(&state->entry);
714  ARRAY_RESERVE(&state->entry, 256);
715 #ifdef USE_IMAP
716  state->imap_browse = false;
717 #endif
718  if (menu)
719  menu->mdata = &state->entry;
720 }
#define ARRAY_RESERVE(head, num)
Reserve memory for the array.
Definition: array.h:185
#define ARRAY_INIT(head)
Initialize an array.
Definition: array.h:61
bool imap_browse
IMAP folder.
Definition: browser.h:95
void * mdata
Private data.
Definition: lib.h:153
+ Here is the caller graph for this function:

◆ examine_directory()

static int examine_directory ( struct Mailbox m,
struct Menu menu,
struct BrowserState state,
const char *  d,
const char *  prefix 
)
static

Get list of all files/newsgroups with mask.

Parameters
mMailbox
menuCurrent Menu
stateState of browser
dDirectory
prefixFiles/newsgroups must match this prefix
Return values
0Success
-1Error

Definition at line 732 of file browser.c.

734 {
735  int rc = -1;
736  struct Buffer *buf = mutt_buffer_pool_get();
737 #ifdef USE_NNTP
738  if (OptNews)
739  {
741 
742  init_state(state, menu);
743 
744  for (unsigned int i = 0; i < adata->groups_num; i++)
745  {
746  struct NntpMboxData *mdata = adata->groups_list[i];
747  if (!mdata)
748  continue;
749  if (prefix && *prefix && !mutt_str_startswith(mdata->group, prefix))
750  continue;
751  const struct Regex *c_mask = cs_subset_regex(NeoMutt->sub, "mask");
752  if (!mutt_regex_match(c_mask, mdata->group))
753  {
754  continue;
755  }
756  add_folder(menu, state, mdata->group, NULL, NULL, NULL, mdata);
757  }
758  }
759  else
760 #endif /* USE_NNTP */
761  {
762  struct stat st = { 0 };
763  DIR *dp = NULL;
764  struct dirent *de = NULL;
765 
766  while (stat(d, &st) == -1)
767  {
768  if (errno == ENOENT)
769  {
770  /* The last used directory is deleted, try to use the parent dir. */
771  char *c = strrchr(d, '/');
772 
773  if (c && (c > d))
774  {
775  *c = '\0';
776  continue;
777  }
778  }
779  mutt_perror(d);
780  goto ed_out;
781  }
782 
783  if (!S_ISDIR(st.st_mode))
784  {
785  mutt_error(_("%s is not a directory"), d);
786  goto ed_out;
787  }
788 
789  if (m)
790  mutt_mailbox_check(m, 0);
791 
792  dp = opendir(d);
793  if (!dp)
794  {
795  mutt_perror(d);
796  goto ed_out;
797  }
798 
799  init_state(state, menu);
800 
801  struct MailboxList ml = STAILQ_HEAD_INITIALIZER(ml);
803  while ((de = readdir(dp)))
804  {
805  if (mutt_str_equal(de->d_name, "."))
806  continue; /* we don't need . */
807 
808  if (prefix && *prefix && !mutt_str_startswith(de->d_name, prefix))
809  {
810  continue;
811  }
812  const struct Regex *c_mask = cs_subset_regex(NeoMutt->sub, "mask");
813  if (!mutt_regex_match(c_mask, de->d_name))
814  {
815  continue;
816  }
817 
818  mutt_buffer_concat_path(buf, d, de->d_name);
819  if (lstat(mutt_buffer_string(buf), &st) == -1)
820  continue;
821 
822  /* No size for directories or symlinks */
823  if (S_ISDIR(st.st_mode) || S_ISLNK(st.st_mode))
824  st.st_size = 0;
825  else if (!S_ISREG(st.st_mode))
826  continue;
827 
828  struct MailboxNode *np = NULL;
829  STAILQ_FOREACH(np, &ml, entries)
830  {
832  break;
833  }
834 
835  if (np && m && mutt_str_equal(np->mailbox->realpath, m->realpath))
836  {
837  np->mailbox->msg_count = m->msg_count;
838  np->mailbox->msg_unread = m->msg_unread;
839  }
840  add_folder(menu, state, de->d_name, NULL, &st, np ? np->mailbox : NULL, NULL);
841  }
843  closedir(dp);
844  }
845  browser_sort(state);
846  rc = 0;
847 ed_out:
849  return rc;
850 }
static void add_folder(struct Menu *menu, struct BrowserState *state, const char *name, const char *desc, const struct stat *st, struct Mailbox *m, void *data)
Add a folder to the browser list.
Definition: browser.c:660
static void init_state(struct BrowserState *state, struct Menu *menu)
Initialise a browser state.
Definition: browser.c:711
static void browser_sort(struct BrowserState *state)
Sort the entries in the browser.
Definition: browser.c:342
#define mutt_error(...)
Definition: logging.h:87
#define mutt_perror(...)
Definition: logging.h:88
const struct Regex * cs_subset_regex(const struct ConfigSubset *sub, const char *name)
Get a regex config item by name.
Definition: helpers.c:243
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox's path string.
Definition: mailbox.h:215
@ MUTT_MAILBOX_ANY
Match any Mailbox type.
Definition: mailbox.h:45
#define _(a)
Definition: message.h:28
bool mutt_regex_match(const struct Regex *regex, const char *str)
Shorthand to mutt_regex_capture()
Definition: regex.c:613
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:904
size_t mutt_str_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix.
Definition: string.c:160
int mutt_mailbox_check(struct Mailbox *m_cur, int force)
Check all all Mailboxes for new mail.
Definition: mutt_mailbox.c:162
void neomutt_mailboxlist_clear(struct MailboxList *ml)
Free a Mailbox List.
Definition: neomutt.c:141
size_t neomutt_mailboxlist_get_all(struct MailboxList *head, struct NeoMutt *n, enum MailboxType type)
Get a List of all Mailboxes.
Definition: neomutt.c:164
struct NntpAccountData * CurrentNewsSrv
Current NNTP news server.
Definition: nntp.c:78
#define STAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:324
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:352
void * adata
Private data (for Mailbox backends)
Definition: account.h:43
List of Mailboxes.
Definition: mailbox.h:157
struct Mailbox * mailbox
Mailbox in the list.
Definition: mailbox.h:158
char * realpath
Used for duplicate detection, context comparison, and the sidebar.
Definition: mailbox.h:84
void * mdata
Driver specific data.
Definition: mailbox.h:136
NNTP-specific Account data -.
Definition: adata.h:37
void ** groups_list
Definition: adata.h:61
NNTP-specific Mailbox data -.
Definition: mdata.h:33
char * group
Name of newsgroup.
Definition: mdata.h:34
struct NntpAccountData * adata
Definition: mdata.h:47
Cached regular expression.
Definition: regex3.h:90
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ examine_mailboxes()

static int examine_mailboxes ( struct Mailbox m,
struct Menu menu,
struct BrowserState state 
)
static

Get list of mailboxes/subscribed newsgroups.

Parameters
mMailbox
menuCurrent menu
stateState of browser
Return values
0Success
-1Error

Definition at line 860 of file browser.c.

861 {
862  struct stat st = { 0 };
863  struct Buffer *md = NULL;
864  struct Buffer *mailbox = NULL;
865 
866 #ifdef USE_NNTP
867  if (OptNews)
868  {
870 
871  init_state(state, menu);
872 
873  for (unsigned int i = 0; i < adata->groups_num; i++)
874  {
875  const bool c_show_only_unread =
876  cs_subset_bool(NeoMutt->sub, "show_only_unread");
877  struct NntpMboxData *mdata = adata->groups_list[i];
878  if (mdata && (mdata->has_new_mail ||
879  (mdata->subscribed && (mdata->unread || !c_show_only_unread))))
880  {
881  add_folder(menu, state, mdata->group, NULL, NULL, NULL, mdata);
882  }
883  }
884  }
885  else
886 #endif
887  {
888  init_state(state, menu);
889 
891  return -1;
892  mailbox = mutt_buffer_pool_get();
893  md = mutt_buffer_pool_get();
894 
895  mutt_mailbox_check(m, 0);
896 
897  struct MailboxList ml = STAILQ_HEAD_INITIALIZER(ml);
899  struct MailboxNode *np = NULL;
900  STAILQ_FOREACH(np, &ml, entries)
901  {
902  if (!np->mailbox)
903  continue;
904 
905  if (m && mutt_str_equal(np->mailbox->realpath, m->realpath))
906  {
907  np->mailbox->msg_count = m->msg_count;
908  np->mailbox->msg_unread = m->msg_unread;
909  }
910 
912  const bool c_browser_abbreviate_mailboxes =
913  cs_subset_bool(NeoMutt->sub, "browser_abbreviate_mailboxes");
914  if (c_browser_abbreviate_mailboxes)
916 
917  switch (np->mailbox->type)
918  {
919  case MUTT_IMAP:
920  case MUTT_POP:
921  add_folder(menu, state, mutt_buffer_string(mailbox),
922  np->mailbox->name, NULL, np->mailbox, NULL);
923  continue;
924  case MUTT_NOTMUCH:
925  case MUTT_NNTP:
926  add_folder(menu, state, mailbox_path(np->mailbox), np->mailbox->name,
927  NULL, np->mailbox, NULL);
928  continue;
929  default: /* Continue */
930  break;
931  }
932 
933  if (lstat(mailbox_path(np->mailbox), &st) == -1)
934  continue;
935 
936  if ((!S_ISREG(st.st_mode)) && (!S_ISDIR(st.st_mode)) && (!S_ISLNK(st.st_mode)))
937  continue;
938 
939  if (np->mailbox->type == MUTT_MAILDIR)
940  {
941  struct stat st2 = { 0 };
942 
943  mutt_buffer_printf(md, "%s/new", mailbox_path(np->mailbox));
944  if (stat(mutt_buffer_string(md), &st) < 0)
945  st.st_mtime = 0;
946  mutt_buffer_printf(md, "%s/cur", mailbox_path(np->mailbox));
947  if (stat(mutt_buffer_string(md), &st2) < 0)
948  st2.st_mtime = 0;
949  if (st2.st_mtime > st.st_mtime)
950  st.st_mtime = st2.st_mtime;
951  }
952 
953  add_folder(menu, state, mutt_buffer_string(mailbox), np->mailbox->name,
954  &st, np->mailbox, NULL);
955  }
957  }
958  browser_sort(state);
959 
960  mutt_buffer_pool_release(&mailbox);
962  return 0;
963 }
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:312
int mutt_buffer_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:160
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
@ MUTT_NOTMUCH
'Notmuch' (virtual) Mailbox type
Definition: mailbox.h:54
@ MUTT_POP
'POP3' Mailbox type
Definition: mailbox.h:55
@ MUTT_NNTP
'NNTP' (Usenet) Mailbox type
Definition: mailbox.h:52
@ MUTT_IMAP
'IMAP' Mailbox type
Definition: mailbox.h:53
@ MUTT_MAILDIR
'Maildir' Mailbox type
Definition: mailbox.h:51
void mutt_buffer_pretty_mailbox(struct Buffer *buf)
Shorten a mailbox path using '~' or '='.
Definition: muttlib.c:603
#define TAILQ_EMPTY(head)
Definition: queue.h:721
enum MailboxType type
Mailbox type.
Definition: mailbox.h:105
char * name
A short name for the Mailbox.
Definition: mailbox.h:85
struct AccountList accounts
List of all Accounts.
Definition: neomutt.h:40
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ browser_highlight_default()

static void browser_highlight_default ( struct BrowserState state,
struct Menu menu 
)
static

Decide which browser item should be highlighted.

Parameters
stateBrowser state
menuCurrent Menu

This function takes a menu and a state and defines the current entry that should be highlighted.

Definition at line 1019 of file browser.c.

1020 {
1021  menu->top = 0;
1022  /* Reset menu position to 1.
1023  * We do not risk overflow as the init_menu function changes
1024  * current if it is bigger than state->entrylen. */
1025  if (!ARRAY_EMPTY(&state->entry) &&
1026  (mutt_str_equal(ARRAY_FIRST(&state->entry)->desc, "..") ||
1027  mutt_str_equal(ARRAY_FIRST(&state->entry)->desc, "../")))
1028  {
1029  /* Skip the first entry, unless there's only one entry. */
1030  menu_set_index(menu, (menu->max > 1));
1031  }
1032  else
1033  {
1034  menu_set_index(menu, 0);
1035  }
1036 }
#define ARRAY_FIRST(head)
Convenience method to get the first element.
Definition: array.h:131
#define ARRAY_EMPTY(head)
Check if an array is empty.
Definition: array.h:70
MenuRedrawFlags menu_set_index(struct Menu *menu, int index)
Set the current selection in the Menu.
Definition: menu.c:622
int top
Entry that is the top of the current page.
Definition: lib.h:87
int max
Number of entries in the menu.
Definition: lib.h:69
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ init_menu()

static void init_menu ( struct BrowserState state,
struct Menu menu,
struct Mailbox m,
struct MuttWindow sbar 
)
static

Set up a new menu.

Parameters
stateBrowser state
menuCurrent menu
mMailbox
sbarStatus bar

Definition at line 1045 of file browser.c.

1047 {
1048  char title[256] = { 0 };
1049  menu->max = ARRAY_SIZE(&state->entry);
1050 
1051  int index = menu_get_index(menu);
1052  if (index >= menu->max)
1053  menu_set_index(menu, menu->max - 1);
1054  if (index < 0)
1055  menu_set_index(menu, 0);
1056  if (menu->top > index)
1057  menu->top = 0;
1058 
1059  menu->tagged = 0;
1060 
1061 #ifdef USE_NNTP
1062  if (OptNews)
1063  {
1064  if (state->is_mailbox_list)
1065  snprintf(title, sizeof(title), _("Subscribed newsgroups"));
1066  else
1067  {
1068  snprintf(title, sizeof(title), _("Newsgroups on server [%s]"),
1070  }
1071  }
1072  else
1073 #endif
1074  {
1075  if (state->is_mailbox_list)
1076  {
1077  snprintf(title, sizeof(title), _("Mailboxes [%d]"), mutt_mailbox_check(m, 0));
1078  }
1079  else
1080  {
1081  struct Buffer *path = mutt_buffer_pool_get();
1082  mutt_buffer_copy(path, &LastDir);
1084  const struct Regex *c_mask = cs_subset_regex(NeoMutt->sub, "mask");
1085 #ifdef USE_IMAP
1086  const bool c_imap_list_subscribed =
1087  cs_subset_bool(NeoMutt->sub, "imap_list_subscribed");
1088  if (state->imap_browse && c_imap_list_subscribed)
1089  {
1090  snprintf(title, sizeof(title), _("Subscribed [%s], File mask: %s"),
1091  mutt_buffer_string(path), NONULL(c_mask ? c_mask->pattern : NULL));
1092  }
1093  else
1094 #endif
1095  {
1096  snprintf(title, sizeof(title), _("Directory [%s], File mask: %s"),
1097  mutt_buffer_string(path), NONULL(c_mask ? c_mask->pattern : NULL));
1098  }
1099  mutt_buffer_pool_release(&path);
1100  }
1101  }
1102  sbar_set_title(sbar, title);
1103 
1104  /* Browser tracking feature.
1105  * The goal is to highlight the good directory if LastDir is the parent dir
1106  * of LastDirBackup (this occurs mostly when one hit "../"). It should also work
1107  * properly when the user is in examine_mailboxes-mode. */
1109  {
1110  char target_dir[PATH_MAX] = { 0 };
1111 
1112 #ifdef USE_IMAP
1113  /* Check what kind of dir LastDirBackup is. */
1115  {
1116  mutt_str_copy(target_dir, mutt_buffer_string(&LastDirBackup), sizeof(target_dir));
1117  imap_clean_path(target_dir, sizeof(target_dir));
1118  }
1119  else
1120 #endif
1121  mutt_str_copy(target_dir, strrchr(mutt_buffer_string(&LastDirBackup), '/') + 1,
1122  sizeof(target_dir));
1123 
1124  /* If we get here, it means that LastDir is the parent directory of
1125  * LastDirBackup. I.e., we're returning from a subdirectory, and we want
1126  * to position the cursor on the directory we're returning from. */
1127  bool matched = false;
1128  struct FolderFile *ff = NULL;
1129  ARRAY_FOREACH(ff, &state->entry)
1130  {
1131  if (mutt_str_equal(ff->name, target_dir))
1132  {
1133  menu_set_index(menu, ARRAY_FOREACH_IDX);
1134  matched = true;
1135  break;
1136  }
1137  }
1138  if (!matched)
1139  browser_highlight_default(state, menu);
1140  }
1141  else
1142  browser_highlight_default(state, menu);
1143 
1145 }
#define ARRAY_SIZE(head)
The number of elements stored.
Definition: array.h:83
static void browser_highlight_default(struct BrowserState *state, struct Menu *menu)
Decide which browser item should be highlighted.
Definition: browser.c:1019
size_t mutt_buffer_copy(struct Buffer *dst, const struct Buffer *src)
Copy a Buffer's contents to another Buffer.
Definition: buffer.c:445
enum MailboxType imap_path_probe(const char *path, const struct stat *st)
Is this an IMAP Mailbox? - Implements MxOps::path_probe() -.
Definition: imap.c:2402
void imap_clean_path(char *path, size_t plen)
Cleans an IMAP path using imap_fix_path.
Definition: util.c:188
#define MENU_REDRAW_FULL
Redraw everything.
Definition: lib.h:55
void menu_queue_redraw(struct Menu *menu, MenuRedrawFlags redraw)
Queue a request for a redraw.
Definition: menu.c:632
int menu_get_index(struct Menu *menu)
Get the current selection in the Menu.
Definition: menu.c:608
size_t mutt_str_copy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:749
void sbar_set_title(struct MuttWindow *win, const char *title)
Set the title for the Simple Bar.
Definition: sbar.c:219
#define NONULL(x)
Definition: string2.h:37
char host[128]
Server to login to.
Definition: connaccount.h:54
struct ConnAccount account
Account details: username, password, etc.
Definition: connection.h:50
int tagged
Number of tagged entries.
Definition: lib.h:90
struct Connection * conn
Connection to NNTP Server.
Definition: adata.h:63
char * pattern
printable version
Definition: regex3.h:91
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_browser_select_dir()

void mutt_browser_select_dir ( const char *  f)

Remember the last directory selected.

Parameters
fDirectory name to save

This function helps the browser to know which directory has been selected. It should be called anywhere a confirm hit is done to open a new directory/file which is a maildir/mbox.

We could check if the sort method is appropriate with this feature.

Definition at line 1232 of file browser.c.

1233 {
1234  init_lastdir();
1235 
1237 
1238  /* Method that will fetch the parent path depending on the type of the path. */
1239  char buf[PATH_MAX];
1241  mutt_buffer_strcpy(&LastDir, buf);
1242 }
static void init_lastdir(void)
Initialise the browser directories.
Definition: browser.c:144
void mutt_get_parent_path(const char *path, char *buf, size_t buflen)
Find the parent of a path (or mailbox)
Definition: muttlib.c:1555
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_buffer_select_file()

void mutt_buffer_select_file ( struct Buffer file,
SelectFileFlags  flags,
struct Mailbox m,
char ***  files,
int *  numfiles 
)

Let the user select a file.

Parameters
[in]fileBuffer for the result
[in]flagsFlags, see SelectFileFlags
[in]mMailbox
[out]filesArray of selected files
[out]numfilesNumber of selected files

Definition at line 1252 of file browser.c.

1254 {
1255  struct BrowserState state = { { 0 } };
1256  struct Menu *menu = NULL;
1257  struct MuttWindow *dlg = NULL;
1258  bool kill_prefix = false;
1259  bool multiple = (flags & MUTT_SEL_MULTI);
1260  bool folder = (flags & MUTT_SEL_FOLDER);
1261  state.is_mailbox_list = (flags & MUTT_SEL_MAILBOX) && folder;
1262 
1263  /* Keeps in memory the directory we were in when hitting '='
1264  * to go directly to $folder (`$folder`) */
1265  char goto_swapper[PATH_MAX] = { 0 };
1266 
1267  struct Buffer *OldLastDir = mutt_buffer_pool_get();
1268  struct Buffer *tmp = mutt_buffer_pool_get();
1269  struct Buffer *buf = mutt_buffer_pool_get();
1270  struct Buffer *prefix = mutt_buffer_pool_get();
1271 
1272  init_lastdir();
1273 
1274 #ifdef USE_NNTP
1275  if (OptNews)
1276  {
1277  if (mutt_buffer_is_empty(file))
1278  {
1280 
1281  /* default state for news reader mode is browse subscribed newsgroups */
1282  state.is_mailbox_list = false;
1283  for (size_t i = 0; i < adata->groups_num; i++)
1284  {
1285  struct NntpMboxData *mdata = adata->groups_list[i];
1286  if (mdata && mdata->subscribed)
1287  {
1288  state.is_mailbox_list = true;
1289  break;
1290  }
1291  }
1292  }
1293  else
1294  {
1295  mutt_buffer_copy(prefix, file);
1296  }
1297  }
1298  else
1299 #endif
1300  if (!mutt_buffer_is_empty(file))
1301  {
1303 #ifdef USE_IMAP
1304  if (imap_path_probe(mutt_buffer_string(file), NULL) == MUTT_IMAP)
1305  {
1306  init_state(&state, NULL);
1307  state.imap_browse = true;
1308  if (imap_browse(mutt_buffer_string(file), &state) == 0)
1309  {
1311  browser_sort(&state);
1312  }
1313  }
1314  else
1315  {
1316 #endif
1317  int i;
1318  for (i = mutt_buffer_len(file) - 1;
1319  (i > 0) && ((mutt_buffer_string(file))[i] != '/'); i--)
1320  {
1321  ; // do nothing
1322  }
1323 
1324  if (i > 0)
1325  {
1326  if ((mutt_buffer_string(file))[0] == '/')
1328  else
1329  {
1331  mutt_buffer_addch(&LastDir, '/');
1333  }
1334  }
1335  else
1336  {
1337  if ((mutt_buffer_string(file))[0] == '/')
1338  mutt_buffer_strcpy(&LastDir, "/");
1339  else
1341  }
1342 
1343  if ((i <= 0) && (mutt_buffer_string(file)[0] != '/'))
1344  mutt_buffer_copy(prefix, file);
1345  else
1346  mutt_buffer_strcpy(prefix, mutt_buffer_string(file) + i + 1);
1347  kill_prefix = true;
1348 #ifdef USE_IMAP
1349  }
1350 #endif
1351  }
1352  else
1353  {
1354  if (!folder)
1356  else
1357  {
1358  /* Whether we use the tracking feature of the browser depends
1359  * on which sort method we chose to use. This variable is defined
1360  * only to help readability of the code. */
1361  bool browser_track = false;
1362 
1363  const short c_sort_browser = cs_subset_sort(NeoMutt->sub, "sort_browser");
1364  switch (c_sort_browser & SORT_MASK)
1365  {
1366  case SORT_DESC:
1367  case SORT_SUBJECT:
1368  case SORT_ORDER:
1369  browser_track = true;
1370  break;
1371  }
1372 
1373  /* We use mutt_browser_select_dir to initialize the two
1374  * variables (LastDir, LastDirBackup) at the appropriate
1375  * values.
1376  *
1377  * We do it only when LastDir is not set (first pass there)
1378  * or when CurrentFolder and LastDirBackup are not the same.
1379  * This code is executed only when we list files, not when
1380  * we press up/down keys to navigate in a displayed list.
1381  *
1382  * We only do this when CurrentFolder has been set (ie, not
1383  * when listing folders on startup with "neomutt -y").
1384  *
1385  * This tracker is only used when browser_track is true,
1386  * meaning only with sort methods SUBJECT/DESC for now. */
1387  if (CurrentFolder)
1388  {
1390  {
1391  /* If browsing in "local"-mode, than we chose to define LastDir to
1392  * MailDir */
1393  switch (mx_path_probe(CurrentFolder))
1394  {
1395  case MUTT_IMAP:
1396  case MUTT_MAILDIR:
1397  case MUTT_MBOX:
1398  case MUTT_MH:
1399  case MUTT_MMDF:
1400  {
1401  const char *const c_folder =
1402  cs_subset_string(NeoMutt->sub, "folder");
1403  const char *const c_spool_file = cs_subset_string(NeoMutt->sub, "spool_file");
1404  if (c_folder)
1405  mutt_buffer_strcpy(&LastDir, c_folder);
1406  else if (c_spool_file)
1407  mutt_browser_select_dir(c_spool_file);
1408  break;
1409  }
1410  default:
1412  break;
1413  }
1414  }
1416  {
1418  }
1419  }
1420 
1421  /* When browser tracking feature is disabled, clear LastDirBackup */
1422  if (!browser_track)
1424  }
1425 
1426 #ifdef USE_IMAP
1427  if (!state.is_mailbox_list &&
1429  {
1430  init_state(&state, NULL);
1431  state.imap_browse = true;
1433  browser_sort(&state);
1434  }
1435  else
1436 #endif
1437  {
1438  size_t i = mutt_buffer_len(&LastDir);
1439  while ((i > 0) && (mutt_buffer_string(&LastDir)[--i] == '/'))
1440  LastDir.data[i] = '\0';
1444  }
1445  }
1446 
1447  mutt_buffer_reset(file);
1448 
1449  const struct Mapping *help_data = NULL;
1450 #ifdef USE_NNTP
1451  if (OptNews)
1452  help_data = FolderNewsHelp;
1453  else
1454 #endif
1455  help_data = FolderHelp;
1456 
1457  dlg = simple_dialog_new(MENU_FOLDER, WT_DLG_BROWSER, help_data);
1458 
1459  menu = dlg->wdata;
1460  menu->make_entry = folder_make_entry;
1461  menu->search = select_file_search;
1462  if (multiple)
1463  menu->tag = file_tag;
1464 
1465  struct MuttWindow *sbar = window_find_child(dlg, WT_STATUS_BAR);
1466 
1467  struct MuttWindow *win_menu = menu->win;
1468 
1469  // NT_COLOR is handled by the SimpleDialog
1472 
1473  if (state.is_mailbox_list)
1474  {
1475  examine_mailboxes(m, NULL, &state);
1476  }
1477  else
1478 #ifdef USE_IMAP
1479  if (!state.imap_browse)
1480 #endif
1481  {
1482  // examine_directory() calls add_folder() which needs the menu
1484  mutt_buffer_string(prefix)) == -1)
1485  {
1486  goto bail;
1487  }
1488  }
1489 
1490  init_menu(&state, menu, m, sbar);
1491  // only now do we have a valid state to attach
1492  menu->mdata = &state.entry;
1493 
1494  int last_selected_mailbox = -1;
1495 
1496  while (true)
1497  {
1498  if (state.is_mailbox_list && (last_selected_mailbox >= 0) &&
1499  (last_selected_mailbox < menu->max))
1500  {
1501  menu_set_index(menu, last_selected_mailbox);
1502  }
1503  int op = menu_loop(menu);
1504  if (op >= 0)
1505  mutt_debug(LL_DEBUG1, "Got op %s (%d)\n", OpStrings[op][0], op);
1506  int index = menu_get_index(menu);
1507  struct FolderFile *ff = ARRAY_GET(&state.entry, index);
1508  switch (op)
1509  {
1510  case OP_DESCEND_DIRECTORY:
1511  case OP_GENERIC_SELECT_ENTRY:
1512  {
1513  if (ARRAY_EMPTY(&state.entry))
1514  {
1515  mutt_error(_("No files match the file mask"));
1516  break;
1517  }
1518 
1519  if (S_ISDIR(ff->mode) ||
1520  (S_ISLNK(ff->mode) && link_is_dir(mutt_buffer_string(&LastDir), ff->name))
1521 #ifdef USE_IMAP
1522  || ff->inferiors
1523 #endif
1524  )
1525  {
1526  /* make sure this isn't a MH or maildir mailbox */
1527  if (state.is_mailbox_list)
1528  {
1529  mutt_buffer_strcpy(buf, ff->name);
1531  }
1532 #ifdef USE_IMAP
1533  else if (state.imap_browse)
1534  {
1535  mutt_buffer_strcpy(buf, ff->name);
1536  }
1537 #endif
1538  else
1539  {
1541  }
1542 
1543  enum MailboxType type = mx_path_probe(mutt_buffer_string(buf));
1544  if ((op == OP_DESCEND_DIRECTORY) || (type == MUTT_MAILBOX_ERROR) ||
1545  (type == MUTT_UNKNOWN)
1546 #ifdef USE_IMAP
1547  || ff->inferiors
1548 #endif
1549  )
1550  {
1551  /* save the old directory */
1552  mutt_buffer_copy(OldLastDir, &LastDir);
1553 
1554  if (mutt_str_equal(ff->name, ".."))
1555  {
1556  size_t lastdirlen = mutt_buffer_len(&LastDir);
1557  if ((lastdirlen > 1) &&
1558  mutt_str_equal("..", mutt_buffer_string(&LastDir) + lastdirlen - 2))
1559  {
1560  mutt_buffer_addstr(&LastDir, "/..");
1561  }
1562  else
1563  {
1564  char *p = NULL;
1565  if (lastdirlen > 1)
1566  p = strrchr(mutt_buffer_string(&LastDir) + 1, '/');
1567 
1568  if (p)
1569  {
1570  *p = '\0';
1572  }
1573  else
1574  {
1575  if (mutt_buffer_string(&LastDir)[0] == '/')
1576  mutt_buffer_strcpy(&LastDir, "/");
1577  else
1578  mutt_buffer_addstr(&LastDir, "/..");
1579  }
1580  }
1581  }
1582  else if (state.is_mailbox_list)
1583  {
1586  }
1587 #ifdef USE_IMAP
1588  else if (state.imap_browse)
1589  {
1591  /* tack on delimiter here */
1592 
1593  /* special case "" needs no delimiter */
1594  struct Url *url = url_parse(ff->name);
1595  if (url && url->path && (ff->delim != '\0'))
1596  {
1598  }
1599  url_free(&url);
1600  }
1601 #endif
1602  else
1603  {
1605  mutt_buffer_copy(&LastDir, tmp);
1606  }
1607 
1608  destroy_state(&state);
1609  if (kill_prefix)
1610  {
1611  mutt_buffer_reset(prefix);
1612  kill_prefix = false;
1613  }
1614  state.is_mailbox_list = false;
1615 #ifdef USE_IMAP
1616  if (state.imap_browse)
1617  {
1618  init_state(&state, NULL);
1619  state.imap_browse = true;
1621  browser_sort(&state);
1622  menu->mdata = &state.entry;
1623  }
1624  else
1625 #endif
1626  {
1627  if (examine_directory(m, menu, &state, mutt_buffer_string(&LastDir),
1628  mutt_buffer_string(prefix)) == -1)
1629  {
1630  /* try to restore the old values */
1631  mutt_buffer_copy(&LastDir, OldLastDir);
1632  if (examine_directory(m, menu, &state, mutt_buffer_string(&LastDir),
1633  mutt_buffer_string(prefix)) == -1)
1634  {
1636  goto bail;
1637  }
1638  }
1639  /* resolve paths navigated from GUI */
1640  if (mutt_path_realpath(LastDir.data) == 0)
1641  break;
1642  }
1643 
1644  browser_highlight_default(&state, menu);
1645  init_menu(&state, menu, m, sbar);
1646  goto_swapper[0] = '\0';
1647  break;
1648  }
1649  }
1650  else if (op == OP_DESCEND_DIRECTORY)
1651  {
1652  mutt_error(_("%s is not a directory"), ARRAY_GET(&state.entry, index)->name);
1653  break;
1654  }
1655 
1656  if (state.is_mailbox_list || OptNews) /* USE_NNTP */
1657  {
1658  mutt_buffer_strcpy(file, ff->name);
1660  }
1661 #ifdef USE_IMAP
1662  else if (state.imap_browse)
1663  mutt_buffer_strcpy(file, ff->name);
1664 #endif
1665  else
1666  {
1668  }
1669  }
1670  /* fallthrough */
1671 
1672  case OP_EXIT:
1673 
1674  if (multiple)
1675  {
1676  char **tfiles = NULL;
1677 
1678  if (menu->tagged)
1679  {
1680  *numfiles = menu->tagged;
1681  tfiles = mutt_mem_calloc(*numfiles, sizeof(char *));
1682  size_t j = 0;
1683  ARRAY_FOREACH(ff, &state.entry)
1684  {
1685  if (ff->tagged)
1686  {
1689  tfiles[j++] = mutt_buffer_strdup(tmp);
1690  }
1691  }
1692  *files = tfiles;
1693  }
1694  else if (!mutt_buffer_is_empty(file)) /* no tagged entries. return selected entry */
1695  {
1696  *numfiles = 1;
1697  tfiles = mutt_mem_calloc(*numfiles, sizeof(char *));
1699  tfiles[0] = mutt_buffer_strdup(file);
1700  *files = tfiles;
1701  }
1702  }
1703 
1704  destroy_state(&state);
1705  goto bail;
1706 
1707  case OP_BROWSER_TELL:
1708  if (!ARRAY_EMPTY(&state.entry))
1709  mutt_message("%s", ARRAY_GET(&state.entry, index)->name);
1710  break;
1711 
1712 #ifdef USE_IMAP
1713  case OP_BROWSER_TOGGLE_LSUB:
1714  bool_str_toggle(NeoMutt->sub, "imap_list_subscribed", NULL);
1715 
1716  mutt_unget_event(0, OP_CHECK_NEW);
1717  break;
1718 
1719  case OP_CREATE_MAILBOX:
1720  if (!state.imap_browse)
1721  {
1722  mutt_error(_("Create is only supported for IMAP mailboxes"));
1723  break;
1724  }
1725 
1727  {
1728  /* TODO: find a way to detect if the new folder would appear in
1729  * this window, and insert it without starting over. */
1730  destroy_state(&state);
1731  init_state(&state, NULL);
1732  state.imap_browse = true;
1734  browser_sort(&state);
1735  menu->mdata = &state.entry;
1736  browser_highlight_default(&state, menu);
1737  init_menu(&state, menu, m, sbar);
1738  }
1739  /* else leave error on screen */
1740  break;
1741 
1742  case OP_RENAME_MAILBOX:
1743  if (!ff->imap)
1744  mutt_error(_("Rename is only supported for IMAP mailboxes"));
1745  else
1746  {
1747  if (imap_mailbox_rename(ff->name) >= 0)
1748  {
1749  destroy_state(&state);
1750  init_state(&state, NULL);
1751  state.imap_browse = true;
1753  browser_sort(&state);
1754  menu->mdata = &state.entry;
1755  browser_highlight_default(&state, menu);
1756  init_menu(&state, menu, m, sbar);
1757  }
1758  }
1759  break;
1760 
1761  case OP_DELETE_MAILBOX:
1762  if (!ff->imap)
1763  mutt_error(_("Delete is only supported for IMAP mailboxes"));
1764  else
1765  {
1766  char msg[128];
1767 
1768  // TODO(sileht): It could be better to select INBOX instead. But I
1769  // don't want to manipulate Context/Mailboxes/mailbox->account here for now.
1770  // Let's just protect neomutt against crash for now. #1417
1771  if (mutt_str_equal(mailbox_path(m), ff->name))
1772  {
1773  mutt_error(_("Can't delete currently selected mailbox"));
1774  break;
1775  }
1776 
1777  snprintf(msg, sizeof(msg), _("Really delete mailbox \"%s\"?"), ff->name);
1778  if (mutt_yesorno(msg, MUTT_NO) == MUTT_YES)
1779  {
1780  if (imap_delete_mailbox(m, ff->name) == 0)
1781  {
1782  /* free the mailbox from the browser */
1783  FREE(&ff->name);
1784  FREE(&ff->desc);
1785  /* and move all other entries up */
1786  ARRAY_REMOVE(&state.entry, ff);
1787  mutt_message(_("Mailbox deleted"));
1788  init_menu(&state, menu, m, sbar);
1789  }
1790  else
1791  mutt_error(_("Mailbox deletion failed"));
1792  }
1793  else
1794  mutt_message(_("Mailbox not deleted"));
1795  }
1796  break;
1797 #endif
1798 
1799  case OP_GOTO_PARENT:
1800  case OP_CHANGE_DIRECTORY:
1801 
1802 #ifdef USE_NNTP
1803  if (OptNews)
1804  break;
1805 #endif
1806 
1807  mutt_buffer_copy(buf, &LastDir);
1808 #ifdef USE_IMAP
1809  if (!state.imap_browse)
1810 #endif
1811  {
1812  /* add '/' at the end of the directory name if not already there */
1813  size_t len = mutt_buffer_len(buf);
1814  if ((len > 0) && (mutt_buffer_string(&LastDir)[len - 1] != '/'))
1815  mutt_buffer_addch(buf, '/');
1816  }
1817 
1818  if (op == OP_CHANGE_DIRECTORY)
1819  {
1820  /* buf comes from the buffer pool, so defaults to size 1024 */
1821  int ret = mutt_buffer_get_field(_("Chdir to: "), buf, MUTT_FILE,
1822  false, NULL, NULL, NULL);
1823  if ((ret != 0) && mutt_buffer_is_empty(buf))
1824  break;
1825  }
1826  else if (op == OP_GOTO_PARENT)
1828 
1829  if (!mutt_buffer_is_empty(buf))
1830  {
1831  state.is_mailbox_list = false;
1833 #ifdef USE_IMAP
1834  if (imap_path_probe(mutt_buffer_string(buf), NULL) == MUTT_IMAP)
1835  {
1836  mutt_buffer_copy(&LastDir, buf);
1837  destroy_state(&state);
1838  init_state(&state, NULL);
1839  state.imap_browse = true;
1841  browser_sort(&state);
1842  menu->mdata = &state.entry;
1843  browser_highlight_default(&state, menu);
1844  init_menu(&state, menu, m, sbar);
1845  }
1846  else
1847 #endif
1848  {
1849  if (mutt_buffer_string(buf)[0] != '/')
1850  {
1851  /* in case dir is relative, make it relative to LastDir,
1852  * not current working dir */
1854  mutt_buffer_string(buf));
1855  mutt_buffer_copy(buf, tmp);
1856  }
1857  /* Resolve path from <chdir>
1858  * Avoids buildup such as /a/b/../../c
1859  * Symlinks are always unraveled to keep code simple */
1860  if (mutt_path_realpath(buf->data) == 0)
1861  break;
1862 
1863  struct stat st = { 0 };
1864  if (stat(mutt_buffer_string(buf), &st) == 0)
1865  {
1866  if (S_ISDIR(st.st_mode))
1867  {
1868  destroy_state(&state);
1869  if (examine_directory(m, menu, &state, mutt_buffer_string(buf),
1870  mutt_buffer_string(prefix)) == 0)
1871  {
1872  mutt_buffer_copy(&LastDir, buf);
1873  }
1874  else
1875  {
1876  mutt_error(_("Error scanning directory"));
1877  if (examine_directory(m, menu, &state, mutt_buffer_string(&LastDir),
1878  mutt_buffer_string(prefix)) == -1)
1879  {
1880  goto bail;
1881  }
1882  }
1883  browser_highlight_default(&state, menu);
1884  init_menu(&state, menu, m, sbar);
1885  }
1886  else
1887  mutt_error(_("%s is not a directory"), mutt_buffer_string(buf));
1888  }
1889  else
1891  }
1892  }
1893  break;
1894 
1895  case OP_ENTER_MASK:
1896  {
1897  const struct Regex *c_mask = cs_subset_regex(NeoMutt->sub, "mask");
1898  mutt_buffer_strcpy(buf, c_mask ? c_mask->pattern : NULL);
1899  if (mutt_get_field(_("File Mask: "), buf->data, buf->dsize,
1900  MUTT_COMP_NO_FLAGS, false, NULL, NULL) != 0)
1901  {
1902  break;
1903  }
1904 
1905  mutt_buffer_fix_dptr(buf);
1906 
1907  state.is_mailbox_list = false;
1908  /* assume that the user wants to see everything */
1909  if (mutt_buffer_is_empty(buf))
1910  mutt_buffer_strcpy(buf, ".");
1911 
1912  struct Buffer errmsg = mutt_buffer_make(256);
1913  int rc = cs_subset_str_string_set(NeoMutt->sub, "mask",
1914  mutt_buffer_string(buf), &errmsg);
1915  if (CSR_RESULT(rc) != CSR_SUCCESS)
1916  {
1917  if (!mutt_buffer_is_empty(&errmsg))
1918  {
1919  mutt_error("%s", mutt_buffer_string(&errmsg));
1920  mutt_buffer_dealloc(&errmsg);
1921  }
1922  break;
1923  }
1924  mutt_buffer_dealloc(&errmsg);
1925 
1926  destroy_state(&state);
1927 #ifdef USE_IMAP
1928  if (state.imap_browse)
1929  {
1930  init_state(&state, NULL);
1931  state.imap_browse = true;
1933  browser_sort(&state);
1934  menu->mdata = &state.entry;
1935  init_menu(&state, menu, m, sbar);
1936  }
1937  else
1938 #endif
1939  if (examine_directory(m, menu, &state, mutt_buffer_string(&LastDir), NULL) == 0)
1940  {
1941  init_menu(&state, menu, m, sbar);
1942  }
1943  else
1944  {
1945  mutt_error(_("Error scanning directory"));
1946  goto bail;
1947  }
1948  kill_prefix = false;
1949  if (ARRAY_EMPTY(&state.entry))
1950  {
1951  mutt_error(_("No files match the file mask"));
1952  break;
1953  }
1954  break;
1955  }
1956 
1957  case OP_SORT:
1958  case OP_SORT_REVERSE:
1959 
1960  {
1961  bool resort = true;
1962  int sort = -1;
1963  int reverse = (op == OP_SORT_REVERSE);
1964 
1965  switch (mutt_multi_choice(
1966  (reverse) ?
1967  /* L10N: The highlighted letters must match the "Sort" options */
1968  _("Reverse sort by (d)ate, (a)lpha, si(z)e, d(e)scription, "
1969  "(c)ount, ne(w) count, or do(n)'t sort?") :
1970  /* L10N: The highlighted letters must match the "Reverse Sort" options */
1971  _("Sort by (d)ate, (a)lpha, si(z)e, d(e)scription, (c)ount, "
1972  "ne(w) count, or do(n)'t sort?"),
1973  /* L10N: These must match the highlighted letters from "Sort" and "Reverse Sort" */
1974  _("dazecwn")))
1975  {
1976  case -1: /* abort */
1977  resort = false;
1978  break;
1979 
1980  case 1: /* (d)ate */
1981  sort = SORT_DATE;
1982  break;
1983 
1984  case 2: /* (a)lpha */
1985  sort = SORT_SUBJECT;
1986  break;
1987 
1988  case 3: /* si(z)e */
1989  sort = SORT_SIZE;
1990  break;
1991 
1992  case 4: /* d(e)scription */
1993  sort = SORT_DESC;
1994  break;
1995 
1996  case 5: /* (c)ount */
1997  sort = SORT_COUNT;
1998  break;
1999 
2000  case 6: /* ne(w) count */
2001  sort = SORT_UNREAD;
2002  break;
2003 
2004  case 7: /* do(n)'t sort */
2005  sort = SORT_ORDER;
2006  break;
2007  }
2008  if (resort)
2009  {
2010  sort |= reverse ? SORT_REVERSE : 0;
2011  cs_subset_str_native_set(NeoMutt->sub, "sort_browser", sort, NULL);
2012  browser_sort(&state);
2013  browser_highlight_default(&state, menu);
2015  }
2016  else
2017  {
2018  cs_subset_str_native_set(NeoMutt->sub, "sort_browser", sort, NULL);
2019  }
2020  break;
2021  }
2022 
2023  case OP_TOGGLE_MAILBOXES:
2024  case OP_BROWSER_GOTO_FOLDER:
2025  case OP_CHECK_NEW:
2026  if (state.is_mailbox_list)
2027  {
2028  last_selected_mailbox = menu->current;
2029  }
2030 
2031  if (op == OP_TOGGLE_MAILBOXES)
2032  {
2033  state.is_mailbox_list = !state.is_mailbox_list;
2034  }
2035 
2036  if (op == OP_BROWSER_GOTO_FOLDER)
2037  {
2038  /* When in mailboxes mode, disables this feature */
2039  const char *const c_folder = cs_subset_string(NeoMutt->sub, "folder");
2040  if (c_folder)
2041  {
2042  mutt_debug(LL_DEBUG3, "= hit! Folder: %s, LastDir: %s\n", c_folder,
2044  if (goto_swapper[0] == '\0')
2045  {
2046  if (!mutt_str_equal(mutt_buffer_string(&LastDir), c_folder))
2047  {
2048  /* Stores into goto_swapper LastDir, and swaps to `$folder` */
2049  mutt_str_copy(goto_swapper, mutt_buffer_string(&LastDir),
2050  sizeof(goto_swapper));
2052  mutt_buffer_strcpy(&LastDir, c_folder);
2053  }
2054  }
2055  else
2056  {
2058  mutt_buffer_strcpy(&LastDir, goto_swapper);
2059  goto_swapper[0] = '\0';
2060  }
2061  }
2062  }
2063  destroy_state(&state);
2064  mutt_buffer_reset(prefix);
2065  kill_prefix = false;
2066 
2067  if (state.is_mailbox_list)
2068  {
2069  examine_mailboxes(m, menu, &state);
2070  }
2071 #ifdef USE_IMAP
2072  else if (imap_path_probe(mutt_buffer_string(&LastDir), NULL) == MUTT_IMAP)
2073  {
2074  init_state(&state, NULL);
2075  state.imap_browse = true;
2077  browser_sort(&state);
2078  menu->mdata = &state.entry;
2079  }
2080 #endif
2081  else if (examine_directory(m, menu, &state, mutt_buffer_string(&LastDir),
2082  mutt_buffer_string(prefix)) == -1)
2083  {
2084  goto bail;
2085  }
2086  init_menu(&state, menu, m, sbar);
2087  break;
2088 
2089  case OP_MAILBOX_LIST:
2091  break;
2092 
2093  case OP_BROWSER_NEW_FILE:
2095  /* buf comes from the buffer pool, so defaults to size 1024 */
2096  if (mutt_buffer_get_field(_("New file name: "), buf, MUTT_FILE, false,
2097  NULL, NULL, NULL) == 0)
2098  {
2099  mutt_buffer_copy(file, buf);
2100  destroy_state(&state);
2101  goto bail;
2102  }
2103  break;
2104 
2105  case OP_BROWSER_VIEW_FILE:
2106  if (ARRAY_EMPTY(&state.entry))
2107  {
2108  mutt_error(_("No files match the file mask"));
2109  break;
2110  }
2111 
2112 #ifdef USE_IMAP
2113  if (ff->selectable)
2114  {
2115  mutt_buffer_strcpy(file, ff->name);
2116  destroy_state(&state);
2117  goto bail;
2118  }
2119  else
2120 #endif
2121  if (S_ISDIR(ff->mode) ||
2122  (S_ISLNK(ff->mode) && link_is_dir(mutt_buffer_string(&LastDir), ff->name)))
2123  {
2124  mutt_error(_("Can't view a directory"));
2125  break;
2126  }
2127  else
2128  {
2129  char buf2[PATH_MAX];
2130 
2131  mutt_path_concat(buf2, mutt_buffer_string(&LastDir), ff->name, sizeof(buf2));
2132  struct Body *b = mutt_make_file_attach(buf2, NeoMutt->sub);
2133  if (b)
2134  {
2135  mutt_view_attachment(NULL, b, MUTT_VA_REGULAR, NULL, NULL, menu->win);
2136  mutt_body_free(&b);
2138  }
2139  else
2140  mutt_error(_("Error trying to view file"));
2141  }
2142  break;
2143 
2144 #ifdef USE_NNTP
2145  case OP_CATCHUP:
2146  case OP_UNCATCHUP:
2147  {
2148  if (!OptNews)
2149  break;
2150 
2151  struct NntpMboxData *mdata = NULL;
2152 
2154  if (rc < 0)
2155  break;
2156 
2157  if (op == OP_CATCHUP)
2159  else
2161 
2162  if (mdata)
2163  {
2165  index = menu_get_index(menu) + 1;
2166  if (index < menu->max)
2167  menu_set_index(menu, index);
2168  }
2169  if (rc)
2172  break;
2173  }
2174 
2175  case OP_LOAD_ACTIVE:
2176  {
2177  if (!OptNews)
2178  break;
2179 
2181 
2182  if (nntp_newsrc_parse(adata) < 0)
2183  break;
2184 
2185  for (size_t i = 0; i < adata->groups_num; i++)
2186  {
2187  struct NntpMboxData *mdata = adata->groups_list[i];
2188  if (mdata)
2189  mdata->deleted = true;
2190  }
2191  nntp_active_fetch(adata, true);
2194 
2195  destroy_state(&state);
2196  if (state.is_mailbox_list)
2197  {
2198  examine_mailboxes(m, menu, &state);
2199  }
2200  else
2201  {
2202  if (examine_directory(m, menu, &state, NULL, NULL) == -1)
2203  break;
2204  }
2205  init_menu(&state, menu, m, sbar);
2206  break;
2207  }
2208 #endif /* USE_NNTP */
2209 
2210 #if defined(USE_IMAP) || defined(USE_NNTP)
2211  case OP_BROWSER_SUBSCRIBE:
2212  case OP_BROWSER_UNSUBSCRIBE:
2213 #endif
2214 #ifdef USE_NNTP
2215  case OP_SUBSCRIBE_PATTERN:
2216  case OP_UNSUBSCRIBE_PATTERN:
2217  {
2218  if (OptNews)
2219  {
2221  regex_t rx;
2222  memset(&rx, 0, sizeof(rx));
2223  char *s = buf->data;
2224  index = menu_get_index(menu);
2225 
2226  if ((op == OP_SUBSCRIBE_PATTERN) || (op == OP_UNSUBSCRIBE_PATTERN))
2227  {
2228  char tmp2[256];
2229 
2230  mutt_buffer_reset(buf);
2231  if (op == OP_SUBSCRIBE_PATTERN)
2232  snprintf(tmp2, sizeof(tmp2), _("Subscribe pattern: "));
2233  else
2234  snprintf(tmp2, sizeof(tmp2), _("Unsubscribe pattern: "));
2235  /* buf comes from the buffer pool, so defaults to size 1024 */
2236  if ((mutt_buffer_get_field(tmp2, buf, MUTT_PATTERN, false, NULL, NULL, NULL) != 0) ||
2237  mutt_buffer_is_empty(buf))
2238  {
2239  break;
2240  }
2241 
2242  int err = REG_COMP(&rx, s, REG_NOSUB);
2243  if (err != 0)
2244  {
2245  regerror(err, &rx, buf->data, buf->dsize);
2246  regfree(&rx);
2247  mutt_error("%s", mutt_buffer_string(buf));
2248  break;
2249  }
2251  index = 0;
2252  }
2253  else if (ARRAY_EMPTY(&state.entry))
2254  {
2255  mutt_error(_("No newsgroups match the mask"));
2256  break;
2257  }
2258 
2259  int rc = nntp_newsrc_parse(adata);
2260  if (rc < 0)
2261  break;
2262 
2263  ARRAY_FOREACH_FROM(ff, &state.entry, index)
2264  {
2265  if ((op == OP_BROWSER_SUBSCRIBE) || (op == OP_BROWSER_UNSUBSCRIBE) ||
2266  (regexec(&rx, ff->name, 0, NULL, 0) == 0))
2267  {
2268  if ((op == OP_BROWSER_SUBSCRIBE) || (op == OP_SUBSCRIBE_PATTERN))
2270  else
2272  }
2273  if ((op == OP_BROWSER_SUBSCRIBE) || (op == OP_BROWSER_UNSUBSCRIBE))
2274  {
2275  if ((index + 1) < menu->max)
2276  menu_set_index(menu, index + 1);
2277  break;
2278  }
2279  }
2280 
2281  if (op == OP_SUBSCRIBE_PATTERN)
2282  {
2283  for (size_t j = 0; adata && (j < adata->groups_num); j++)
2284  {
2285  struct NntpMboxData *mdata = adata->groups_list[j];
2286  if (mdata && mdata->group && !mdata->subscribed)
2287  {
2288  if (regexec(&rx, mdata->group, 0, NULL, 0) == 0)
2289  {
2291  add_folder(menu, &state, mdata->group, NULL, NULL, NULL, mdata);
2292  }
2293  }
2294  }
2295  init_menu(&state, menu, m, sbar);
2296  }
2297  if (rc > 0)
2302  if ((op != OP_BROWSER_SUBSCRIBE) && (op != OP_BROWSER_UNSUBSCRIBE))
2303  regfree(&rx);
2304  }
2305 #ifdef USE_IMAP
2306  else
2307 #endif /* USE_IMAP && USE_NNTP */
2308 #endif /* USE_NNTP */
2309 #ifdef USE_IMAP
2310  {
2311  char tmp2[256];
2312  mutt_str_copy(tmp2, ff->name, sizeof(tmp2));
2313  mutt_expand_path(tmp2, sizeof(tmp2));
2314  imap_subscribe(tmp2, (op == OP_BROWSER_SUBSCRIBE));
2315  }
2316 #endif /* USE_IMAP */
2317  }
2318  }
2319  }
2320 
2321 bail:
2322  mutt_buffer_pool_release(&OldLastDir);
2325  mutt_buffer_pool_release(&prefix);
2326 
2327  simple_dialog_free(&dlg);
2328 
2329  goto_swapper[0] = '\0';
2330 }
#define ARRAY_REMOVE(head, elem)
Remove an entry from the array, shifting down the subsequent entries.
Definition: array.h:263
#define ARRAY_FOREACH_FROM(elem, head, from)
Iterate from an index to the end.
Definition: array.h:219
#define ARRAY_GET(head, idx)
Return the element at index.
Definition: array.h:105
int bool_str_toggle(struct ConfigSubset *sub, const char *name, struct Buffer *err)
Toggle the value of a bool.
Definition: bool.c:214
static bool link_is_dir(const char *folder, const char *path)
Does this symlink point to a directory?
Definition: browser.c:367
static int examine_directory(struct Mailbox *m, struct Menu *menu, struct BrowserState *state, const char *d, const char *prefix)
Get list of all files/newsgroups with mask.
Definition: browser.c:732
static void init_menu(struct BrowserState *state, struct Menu *menu, struct Mailbox *m, struct MuttWindow *sbar)
Set up a new menu.
Definition: browser.c:1045
static const struct Mapping FolderNewsHelp[]
Help Bar for the NNTP Mailbox browser dialog.
Definition: browser.c:122
static int examine_mailboxes(struct Mailbox *m, struct Menu *menu, struct BrowserState *state)
Get list of mailboxes/subscribed newsgroups.
Definition: browser.c:860
static void destroy_state(struct BrowserState *state)
Free the BrowserState.
Definition: browser.c:170
void mutt_browser_select_dir(const char *f)
Remember the last directory selected.
Definition: browser.c:1232
static const struct Mapping FolderHelp[]
Help Bar for the File/Dir/Mailbox browser dialog.
Definition: browser.c:109
#define MUTT_SEL_MAILBOX
Select a mailbox.
Definition: browser.h:37
#define MUTT_SEL_FOLDER
Select a local directory.
Definition: browser.h:39
#define MUTT_SEL_MULTI
Multi-selection is enabled.
Definition: browser.h:38
struct Buffer mutt_buffer_make(size_t size)
Make a new buffer on the stack.
Definition: buffer.c:61
bool mutt_buffer_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:252
size_t mutt_buffer_addstr_n(struct Buffer *buf, const char *s, size_t len)
Add a string to a Buffer, expanding it if necessary.
Definition: buffer.c:99
size_t mutt_buffer_len(const struct Buffer *buf)
Calculate the length of a Buffer.
Definition: buffer.c:356
size_t mutt_buffer_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:240
size_t mutt_buffer_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:225
char * mutt_buffer_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition: buffer.c:432
void mutt_buffer_fix_dptr(struct Buffer *buf)
Move the dptr to end of the Buffer.
Definition: buffer.c:181
void mutt_buffer_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:79
size_t mutt_buffer_strcpy_n(struct Buffer *buf, const char *s, size_t len)
Copy a string into a Buffer.
Definition: buffer.c:327
char * HomeDir
User's home directory.
Definition: mutt_globals.h:51
int mutt_buffer_get_field(const char *field, struct Buffer *buf, CompletionFlags complete, bool multiple, struct Mailbox *m, char ***files, int *numfiles)
Ask the user for a string.
Definition: curs_lib.c:267
void mutt_unget_event(int ch, int op)
Return a keystroke to the input buffer.
Definition: curs_lib.c:588
int mutt_get_field(const char *field, char *buf, size_t buflen, CompletionFlags complete, bool multiple, char ***files, int *numfiles)
Ask the user for a string.
Definition: curs_lib.c:335
void mutt_body_free(struct Body **ptr)
Free a Body.
Definition: body.c:57
#define mutt_message(...)
Definition: logging.h:86
#define mutt_debug(LEVEL,...)
Definition: logging.h:84
static void folder_make_entry(struct Menu *menu, char *buf, size_t buflen, int line)
Format a menu item for the folder browser - Implements Menu::make_entry() -.
Definition: browser.c:984
static int select_file_search(struct Menu *menu, regex_t *rx, int line)
Menu search callback for matching files - Implements Menu::search() -.
Definition: browser.c:968
static int file_tag(struct Menu *menu, int sel, int act)
Tag an entry in the menu - Implements Menu::tag() -.
Definition: browser.c:1150
static int browser_config_observer(struct NotifyCallback *nc)
Notification that a Config Variable has changed - Implements observer_t -.
Definition: browser.c:1170
static int browser_window_observer(struct NotifyCallback *nc)
Notification that a Window has changed - Implements observer_t -.
Definition: browser.c:1200
struct MuttWindow * simple_dialog_new(enum MenuType mtype, enum WindowType wtype, const struct Mapping *help_data)
Create a simple index Dialog.
Definition: simple.c:126
void simple_dialog_free(struct MuttWindow **ptr)
Destroy a simple index Dialog.
Definition: simple.c:163
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
int imap_browse(const char *path, struct BrowserState *state)
IMAP hook into the folder browser.
Definition: browse.c:182
int imap_mailbox_create(const char *path)
Create a new IMAP mailbox.
Definition: browse.c:384
int imap_mailbox_rename(const char *path)
Rename a mailbox.
Definition: browse.c:437
int imap_subscribe(char *path, bool subscribe)
Subscribe to a mailbox.
Definition: imap.c:1286
int imap_delete_mailbox(struct Mailbox *m, char *path)
Delete a mailbox.
Definition: imap.c:516
@ LL_DEBUG3
Log at debug level 3.
Definition: logging.h:42
@ LL_DEBUG1
Log at debug level 1.
Definition: logging.h:40
MailboxType
Supported mailbox formats.
Definition: mailbox.h:44
@ MUTT_MMDF
'mmdf' Mailbox type
Definition: mailbox.h:49
@ MUTT_MAILBOX_ERROR
Error occurred examining Mailbox.
Definition: mailbox.h:46
@ MUTT_MH
'MH' Mailbox type
Definition: mailbox.h:50
@ MUTT_MBOX
'mbox' Mailbox type
Definition: mailbox.h:48
@ MUTT_UNKNOWN
Mailbox wasn't recognised.
Definition: mailbox.h:47
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:50
#define MENU_REDRAW_INDEX
Redraw the index.
Definition: lib.h:52
int menu_loop(struct Menu *menu)
Menu event loop.
Definition: menu.c:283
bool notify_observer_add(struct Notify *notify, enum NotifyType type, observer_t callback, void *global_data)
Add an observer to an object.
Definition: notify.c:189
char * mutt_path_concat(char *d, const char *dir, const char *fname, size_t l)
Join a directory name and a filename.
Definition: path.c:351
const char * mutt_path_getcwd(struct Buffer *cwd)
Get the current working directory.
Definition: path.c:561
size_t mutt_path_realpath(char *buf)
Resolve path, unraveling symlinks.
Definition: path.c:440
#define MUTT_PATTERN
Pattern mode - only used for history classes.
Definition: mutt.h:60
#define MUTT_COMP_NO_FLAGS
No flags are set.
Definition: mutt.h:52
#define MUTT_FILE
Do file completion.
Definition: mutt.h:54
int mutt_view_attachment(FILE *fp, struct Body *a, enum ViewAttachMode mode, struct Email *e, struct AttachCtx *actx, struct MuttWindow *win)
View an attachment.
Definition: mutt_attach.c:415
@ MUTT_VA_REGULAR
View using default method.
Definition: mutt_attach.h:43
char * CurrentFolder
Currently selected mailbox.
Definition: mutt_globals.h:56
bool mutt_mailbox_list(void)
List the mailboxes with new mail.
Definition: mutt_mailbox.c:249
struct MuttWindow * window_find_child(struct MuttWindow *win, enum WindowType type)
Recursively find a child Window of a given type.
Definition: mutt_window.c:520
@ WT_DLG_BROWSER
Browser Dialog, mutt_buffer_select_file()
Definition: mutt_window.h:80
@ WT_STATUS_BAR
Status Bar containing extra info about the Index/Pager/etc.
Definition: mutt_window.h:102
void mutt_buffer_expand_path(struct Buffer *buf)
Create the canonical path.
Definition: muttlib.c:322
char * mutt_expand_path(char *buf, size_t buflen)
Create the canonical path.
Definition: muttlib.c:122
enum MailboxType mx_path_probe(const char *path)
Find a mailbox that understands a path.
Definition: mx.c:1320
void nntp_clear_cache(struct NntpAccountData *adata)
Clear the NNTP cache.
Definition: newsrc.c:846
struct NntpMboxData * mutt_newsgroup_uncatchup(struct Mailbox *m, struct NntpAccountData *adata, char *group)
Uncatchup newsgroup.
Definition: newsrc.c:1347
int nntp_active_fetch(struct NntpAccountData *adata, bool mark_new)
Fetch list of all newsgroups from server.
Definition: nntp.c:1963
int nntp_newsrc_parse(struct NntpAccountData *adata)
Parse .newsrc file.
Definition: newsrc.c:162
struct NntpMboxData * mutt_newsgroup_catchup(struct Mailbox *m, struct NntpAccountData *adata, char *group)
Catchup newsgroup.
Definition: newsrc.c:1308
void nntp_newsrc_close(struct NntpAccountData *adata)
Unlock and close .newsrc file.
Definition: newsrc.c:118
int nntp_newsrc_update(struct NntpAccountData *adata)
Update .newsrc file.
Definition: newsrc.c:439
struct NntpMboxData * mutt_newsgroup_subscribe(struct NntpAccountData *adata, char *group)
Subscribe newsgroup.
Definition: newsrc.c:1256
struct NntpMboxData * mutt_newsgroup_unsubscribe(struct NntpAccountData *adata, char *group)
Unsubscribe newsgroup.
Definition: newsrc.c:1280
@ NT_WINDOW
MuttWindow has changed, NotifyWindow, EventWindow.
Definition: notify_type.h:53
@ NT_CONFIG
Config has changed, NotifyConfig, EventConfig.
Definition: notify_type.h:42
const char * OpStrings[][2]
Definition: opcodes.c:34
@ MUTT_NO
User answered 'No', or assume 'No'.
Definition: quad.h:38
@ MUTT_YES
User answered 'Yes', or assume 'Yes'.
Definition: quad.h:39
enum QuadOption mutt_yesorno(const char *msg, enum QuadOption def)
Ask the user a Yes/No question.
Definition: question.c:182
int mutt_multi_choice(const char *prompt, const char *letters)
Offer the user a multiple choice question.
Definition: question.c:50
#define REG_COMP(preg, regex, cflags)
Compile a regular expression.
Definition: regex3.h:54
struct Body * mutt_make_file_attach(const char *path, struct ConfigSubset *sub)
Create a file attachment.
Definition: sendlib.c:1093
#define CSR_RESULT(x)
Definition: set.h:52
#define CSR_SUCCESS
Action completed successfully.
Definition: set.h:35
@ SORT_SUBJECT
Sort by the email's subject.
Definition: sort2.h:46
@ SORT_ORDER
Sort by the order the messages appear in the mailbox.
Definition: sort2.h:48
@ SORT_DESC
Sort by the folder's description.
Definition: sort2.h:63
@ SORT_COUNT
Sort by number of emails in a folder.
Definition: sort2.h:58
@ SORT_UNREAD
Sort by the number of unread emails.
Definition: sort2.h:59
#define SORT_REVERSE
Reverse the order of the sort.
Definition: sort2.h:79
The body of an email.
Definition: body.h:35
State of the file/mailbox browser.
Definition: browser.h:92
size_t dsize
Length of data.
Definition: buffer.h:37
char * data
Pointer to data.
Definition: buffer.h:35
bool selectable
Folder can be selected.
Definition: browser.h:73
char delim
Path delimiter.
Definition: browser.h:70
bool tagged
Folder is tagged.
Definition: browser.h:78
bool inferiors
Folder has children.
Definition: browser.h:74
Mapping between user-readable string and a constant.
Definition: mapping.h:32
Definition: lib.h:67
struct MuttWindow * win
Window holding the Menu.
Definition: lib.h:74
void(* make_entry)(struct Menu *menu, char *buf, size_t buflen, int line)
Definition: lib.h:103
int current
Current entry.
Definition: lib.h:68
int(* search)(struct Menu *menu, regex_t *rx, int line)
Definition: lib.h:116
int(* tag)(struct Menu *menu, int sel, int act)
Definition: lib.h:128
struct WindowState state
Current state of the Window.
Definition: mutt_window.h:127
void * wdata
Private data.
Definition: mutt_window.h:145
struct Notify * notify
Notifications: NotifyWindow, EventWindow.
Definition: mutt_window.h:138
struct Notify * notify
Notifications handler.
Definition: neomutt.h:38
A parsed URL proto://user:password@host:port/path?a=1&b=2
Definition: url.h:69
char * path
Path.
Definition: url.h:75
int cs_subset_str_native_set(const struct ConfigSubset *sub, const char *name, intptr_t value, struct Buffer *err)
Natively set the value of a string config item.
Definition: subset.c:305
int cs_subset_str_string_set(const struct ConfigSubset *sub, const char *name, const char *value, struct Buffer *err)
Set a config item by string.
Definition: subset.c:408
@ MENU_FOLDER
General file/mailbox browser.
Definition: type.h:44
struct Url * url_parse(const char *src)
Fill in Url.
Definition: url.c:234
void url_free(struct Url **ptr)
Free the contents of a URL.
Definition: url.c:123
+ Here is the caller graph for this function:

◆ mutt_select_file()

void mutt_select_file ( char *  file,
size_t  filelen,
SelectFileFlags  flags,
struct Mailbox m,
char ***  files,
int *  numfiles 
)

Let the user select a file.

Parameters
[in]fileBuffer for the result
[in]filelenLength of buffer
[in]flagsFlags, see SelectFileFlags
[in]mMailbox
[out]filesArray of selected files
[out]numfilesNumber of selected files

Definition at line 2341 of file browser.c.

2343 {
2344  struct Buffer *f_buf = mutt_buffer_pool_get();
2345 
2346  mutt_buffer_strcpy(f_buf, NONULL(file));
2347  mutt_buffer_select_file(f_buf, flags, m, files, numfiles);
2348  mutt_str_copy(file, mutt_buffer_string(f_buf), filelen);
2349 
2350  mutt_buffer_pool_release(&f_buf);
2351 }
void mutt_buffer_select_file(struct Buffer *file, SelectFileFlags flags, struct Mailbox *m, char ***files, int *numfiles)
Let the user select a file.
Definition: browser.c:1252
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

Variable Documentation

◆ FolderHelp

const struct Mapping FolderHelp[]
static
Initial value:
= {
{ N_("Exit"), OP_EXIT },
{ N_("Chdir"), OP_CHANGE_DIRECTORY },
{ N_("Goto"), OP_BROWSER_GOTO_FOLDER },
{ N_("Mask"), OP_ENTER_MASK },
{ N_("Help"), OP_HELP },
{ NULL, 0 },
}
#define N_(a)
Definition: message.h:32

Help Bar for the File/Dir/Mailbox browser dialog.

Definition at line 1 of file browser.c.

◆ FolderNewsHelp

const struct Mapping FolderNewsHelp[]
static
Initial value:
= {
{ N_("Exit"), OP_EXIT },
{ N_("List"), OP_TOGGLE_MAILBOXES },
{ N_("Subscribe"), OP_BROWSER_SUBSCRIBE },
{ N_("Unsubscribe"), OP_BROWSER_UNSUBSCRIBE },
{ N_("Catchup"), OP_CATCHUP },
{ N_("Mask"), OP_ENTER_MASK },
{ N_("Help"), OP_HELP },
{ NULL, 0 },
}

Help Bar for the NNTP Mailbox browser dialog.

Definition at line 1 of file browser.c.

◆ LastDir

struct Buffer LastDir = { 0 }
static

Definition at line 1 of file browser.c.

◆ LastDirBackup

struct Buffer LastDirBackup = { 0 }
static

Definition at line 1 of file browser.c.