NeoMutt  2021-02-05
Teaching an old dog new tricks
DOXYGEN
index.c File Reference

GUI manage the main index (list of emails) More...

#include "config.h"
#include <assert.h>
#include <ctype.h>
#include <limits.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include "mutt/lib.h"
#include "config/lib.h"
#include "email/lib.h"
#include "core/lib.h"
#include "alias/lib.h"
#include "conn/lib.h"
#include "gui/lib.h"
#include "mutt.h"
#include "debug/lib.h"
#include "index.h"
#include "ncrypt/lib.h"
#include "pattern/lib.h"
#include "send/lib.h"
#include "browser.h"
#include "commands.h"
#include "context.h"
#include "format_flags.h"
#include "hdrline.h"
#include "hook.h"
#include "keymap.h"
#include "mutt_globals.h"
#include "mutt_header.h"
#include "mutt_logging.h"
#include "mutt_mailbox.h"
#include "mutt_menu.h"
#include "mutt_thread.h"
#include "muttlib.h"
#include "mx.h"
#include "opcodes.h"
#include "options.h"
#include "pager.h"
#include "progress.h"
#include "protos.h"
#include "recvattach.h"
#include "score.h"
#include "sort.h"
#include "status.h"
#include "sidebar/lib.h"
#include "pop/lib.h"
#include "imap/lib.h"
#include "notmuch/lib.h"
#include "nntp/lib.h"
#include <libintl.h>
#include "monitor.h"
#include "autocrypt/lib.h"

Go to the source code of this file.

Data Structures

struct  CurrentEmail
 Keep track of the currently selected Email. More...
 

Macros

#define CHECK_NO_FLAGS   0
 No flags are set. More...
 
#define CHECK_IN_MAILBOX   (1 << 0)
 Is there a mailbox open? More...
 
#define CHECK_MSGCOUNT   (1 << 1)
 Are there any messages? More...
 
#define CHECK_VISIBLE   (1 << 2)
 Is the selected message visible in the index? More...
 
#define CHECK_READONLY   (1 << 3)
 Is the mailbox readonly? More...
 
#define CHECK_ATTACH   (1 << 4)
 Is the user in message-attach mode? More...
 

Typedefs

typedef uint8_t CheckFlags
 Checks to perform before running a function. More...
 

Functions

static bool prereq (struct Context *ctx, struct Menu *menu, CheckFlags checks)
 Check the pre-requisites for a function. More...
 
static bool check_acl (struct Mailbox *m, AclFlags acl, const char *msg)
 Check the ACLs for a function. More...
 
static void collapse_all (struct Context *ctx, struct Menu *menu, int toggle)
 Collapse/uncollapse all threads. More...
 
static int ci_next_undeleted (struct Mailbox *m, int msgno)
 Find the next undeleted email. More...
 
static int ci_previous_undeleted (struct Mailbox *m, int msgno)
 Find the previous undeleted email. More...
 
static int ci_first_message (struct Mailbox *m)
 Get index of first new message. More...
 
static int mx_toggle_write (struct Mailbox *m)
 Toggle the mailbox's readonly flag. More...
 
static void resort_index (struct Context *ctx, struct Menu *menu)
 Resort the index. More...
 
static void update_index_threaded (struct Context *ctx, int check, int oldcount)
 Update the index (if threaded) More...
 
static void update_index_unthreaded (struct Context *ctx, int check)
 Update the index (if unthreaded) More...
 
static bool is_current_email (const struct CurrentEmail *cur, const struct Email *e)
 Check whether an email is the currently selected Email. More...
 
static void set_current_email (struct CurrentEmail *cur, struct Email *e)
 Keep track of the currently selected Email. More...
 
static void update_index (struct Menu *menu, struct Context *ctx, int check, int oldcount, const struct CurrentEmail *cur)
 Update the index. More...
 
void mutt_update_index (struct Menu *menu, struct Context *ctx, int check, int oldcount, const struct Email *cur_email)
 Update the index. More...
 
static int mailbox_index_observer (struct NotifyCallback *nc)
 Listen for Mailbox changes - Implements observer_t. More...
 
static void change_folder_mailbox (struct Menu *menu, struct Mailbox *m, int *oldcount, const struct CurrentEmail *cur, bool read_only)
 Change to a different Mailbox by pointer. More...
 
static struct Mailboxchange_folder_notmuch (struct Menu *menu, char *buf, int buflen, int *oldcount, const struct CurrentEmail *cur, bool read_only)
 Change to a different Notmuch Mailbox by string. More...
 
static void change_folder_string (struct Menu *menu, char *buf, size_t buflen, int *oldcount, const struct CurrentEmail *cur, bool *pager_return, bool read_only)
 Change to a different Mailbox by string. More...
 
void index_make_entry (char *buf, size_t buflen, struct Menu *menu, int line)
 Format a menu item for the index list - Implements Menu::make_entry() More...
 
int index_color (int line)
 Calculate the colour for a line of the index - Implements Menu::color() More...
 
void mutt_draw_statusline (int cols, const char *buf, size_t buflen)
 Draw a highlighted status bar. More...
 
static void index_custom_redraw (struct Menu *menu)
 Redraw the index - Implements Menu::custom_redraw() More...
 
int mutt_index_menu (struct MuttWindow *dlg)
 Display a list of emails. More...
 
void mutt_set_header_color (struct Mailbox *m, struct Email *e)
 Select a colour for a message. More...
 
int mutt_reply_observer (struct NotifyCallback *nc)
 Listen for config changes to "reply_regex" - Implements observer_t. More...
 
static struct MuttWindowcreate_panel_index (struct MuttWindow *parent, bool status_on_top)
 Create the Windows for the Index panel. More...
 
static struct MuttWindowcreate_panel_pager (struct MuttWindow *parent, bool status_on_top)
 Create the Windows for the Pager panel. More...
 
struct MuttWindowindex_pager_init (void)
 Allocate the Windows for the Index/Pager. More...
 
void index_pager_shutdown (struct MuttWindow *dlg)
 Clear up any non-Window parts. More...
 
int mutt_dlgindex_observer (struct NotifyCallback *nc)
 Listen for config changes affecting the Index/Pager - Implements observer_t. More...
 

Variables

bool C_ChangeFolderNext
 Config: Suggest the next folder, rather than the first when using '<change-folder>'. More...
 
bool C_CollapseAll
 Config: Collapse all threads when entering a folder. More...
 
char * C_MarkMacroPrefix
 Config: Prefix for macros using '<mark-message>'. More...
 
bool C_UncollapseJump
 Config: When opening a thread, jump to the next unread message. More...
 
bool C_UncollapseNew
 Config: Open collapsed threads when new mail arrives. More...
 
static const struct Mapping IndexHelp []
 Help Bar for the Index dialog. More...
 
static const struct Mapping IndexNewsHelp []
 Help Bar for the News Index dialog. More...
 

Detailed Description

GUI manage the main index (list of emails)

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 index.c.

Macro Definition Documentation

◆ CHECK_NO_FLAGS

#define CHECK_NO_FLAGS   0

No flags are set.

Definition at line 145 of file index.c.

◆ CHECK_IN_MAILBOX

#define CHECK_IN_MAILBOX   (1 << 0)

Is there a mailbox open?

Definition at line 146 of file index.c.

◆ CHECK_MSGCOUNT

#define CHECK_MSGCOUNT   (1 << 1)

Are there any messages?

Definition at line 147 of file index.c.

◆ CHECK_VISIBLE

#define CHECK_VISIBLE   (1 << 2)

Is the selected message visible in the index?

Definition at line 148 of file index.c.

◆ CHECK_READONLY

#define CHECK_READONLY   (1 << 3)

Is the mailbox readonly?

Definition at line 149 of file index.c.

◆ CHECK_ATTACH

#define CHECK_ATTACH   (1 << 4)

Is the user in message-attach mode?

Definition at line 150 of file index.c.

Typedef Documentation

◆ CheckFlags

typedef uint8_t CheckFlags

Checks to perform before running a function.

Flags, e.g. CHECK_IN_MAILBOX

Definition at line 144 of file index.c.

Function Documentation

◆ prereq()

static bool prereq ( struct Context ctx,
struct Menu menu,
CheckFlags  checks 
)
static

Check the pre-requisites for a function.

Parameters
ctxMailbox
menuCurrent Menu
checksChecks to perform, see CheckFlags
Return values
booltrue if the checks pass successfully

Definition at line 160 of file index.c.

161 {
162  bool result = true;
163 
164  if (checks & (CHECK_MSGCOUNT | CHECK_VISIBLE | CHECK_READONLY))
165  checks |= CHECK_IN_MAILBOX;
166 
167  if ((checks & CHECK_IN_MAILBOX) && (!ctx || !ctx->mailbox))
168  {
169  mutt_error(_("No mailbox is open"));
170  result = false;
171  }
172 
173  if (result && (checks & CHECK_MSGCOUNT) && (ctx->mailbox->msg_count == 0))
174  {
175  mutt_error(_("There are no messages"));
176  result = false;
177  }
178 
179  if (result && (checks & CHECK_VISIBLE) && (menu->current >= ctx->mailbox->vcount))
180  {
181  mutt_error(_("No visible messages"));
182  result = false;
183  }
184 
185  if (result && (checks & CHECK_READONLY) && ctx->mailbox->readonly)
186  {
187  mutt_error(_("Mailbox is read-only"));
188  result = false;
189  }
190 
191  if (result && (checks & CHECK_ATTACH) && OptAttachMsg)
192  {
193  mutt_error(_("Function not permitted in attach-message mode"));
194  result = false;
195  }
196 
197  if (!result)
198  mutt_flushinp();
199 
200  return result;
201 }
int msg_count
Total number of messages.
Definition: mailbox.h:91
void mutt_flushinp(void)
Empty all the keyboard buffers.
Definition: curs_lib.c:919
#define CHECK_ATTACH
Is the user in message-attach mode?
Definition: index.c:150
#define _(a)
Definition: message.h:28
int vcount
The number of virtual messages.
Definition: mailbox.h:102
#define CHECK_VISIBLE
Is the selected message visible in the index?
Definition: index.c:148
struct Mailbox * mailbox
Definition: context.h:50
#define CHECK_IN_MAILBOX
Is there a mailbox open?
Definition: index.c:146
bool readonly
Don&#39;t allow changes to the mailbox.
Definition: mailbox.h:119
WHERE bool OptAttachMsg
(pseudo) used by attach-message
Definition: options.h:31
#define CHECK_READONLY
Is the mailbox readonly?
Definition: index.c:149
#define mutt_error(...)
Definition: logging.h:84
#define CHECK_MSGCOUNT
Are there any messages?
Definition: index.c:147
int current
Current entry.
Definition: mutt_menu.h:56
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ check_acl()

static bool check_acl ( struct Mailbox m,
AclFlags  acl,
const char *  msg 
)
static

Check the ACLs for a function.

Parameters
mMailbox
aclACL, see AclFlags
msgError message for failure
Return values
booltrue if the function is permitted

Definition at line 210 of file index.c.

211 {
212  if (!m)
213  return false;
214 
215  if (!(m->rights & acl))
216  {
217  /* L10N: %s is one of the CHECK_ACL entries below. */
218  mutt_error(_("%s: Operation not permitted by ACL"), msg);
219  return false;
220  }
221 
222  return true;
223 }
#define _(a)
Definition: message.h:28
AclFlags rights
ACL bits, see AclFlags.
Definition: mailbox.h:121
#define mutt_error(...)
Definition: logging.h:84
+ Here is the caller graph for this function:

◆ collapse_all()

static void collapse_all ( struct Context ctx,
struct Menu menu,
int  toggle 
)
static

Collapse/uncollapse all threads.

Parameters
ctxContext
menucurrent menu
toggletoggle collapsed state

This function is called by the OP_MAIN_COLLAPSE_ALL command and on folder enter if the $collapse_all option is set. In the first case, the toggle parameter is 1 to actually toggle collapsed/uncollapsed state on all threads. In the second case, the toggle parameter is 0, actually turning this function into a one-way collapse.

Definition at line 237 of file index.c.

238 {
239  if (!ctx || !ctx->mailbox || (ctx->mailbox->msg_count == 0) || !menu)
240  return;
241 
242  struct Email *e_cur = mutt_get_virt_email(ctx->mailbox, menu->current);
243  if (!e_cur)
244  return;
245 
246  int final;
247 
248  /* Figure out what the current message would be after folding / unfolding,
249  * so that we can restore the cursor in a sane way afterwards. */
250  if (e_cur->collapsed && toggle)
251  final = mutt_uncollapse_thread(e_cur);
252  else if (mutt_thread_can_collapse(e_cur))
253  final = mutt_collapse_thread(e_cur);
254  else
255  final = e_cur->vnum;
256 
257  if (final == -1)
258  return;
259 
260  struct Email *base = mutt_get_virt_email(ctx->mailbox, final);
261  if (!base)
262  return;
263 
264  /* Iterate all threads, perform collapse/uncollapse as needed */
265  ctx->collapsed = toggle ? !ctx->collapsed : true;
267 
268  /* Restore the cursor */
269  mutt_set_vnum(ctx->mailbox);
270  for (int i = 0; i < ctx->mailbox->vcount; i++)
271  {
272  struct Email *e = mutt_get_virt_email(ctx->mailbox, i);
273  if (!e)
274  break;
275  if (e->index == base->index)
276  {
277  menu->current = i;
278  break;
279  }
280  }
281 
283 }
int msg_count
Total number of messages.
Definition: mailbox.h:91
void mutt_thread_collapse(struct ThreadsContext *tctx, bool collapse)
toggle collapse
Definition: mutt_thread.c:1604
The envelope/body of an email.
Definition: email.h:37
struct Email * mutt_get_virt_email(struct Mailbox *m, int vnum)
Get a virtual Email.
Definition: context.c:396
#define mutt_uncollapse_thread(e)
Definition: mutt_thread.h:90
#define mutt_collapse_thread(e)
Definition: mutt_thread.h:89
struct ThreadsContext * threads
Threads context.
Definition: context.h:43
int vcount
The number of virtual messages.
Definition: mailbox.h:102
struct Mailbox * mailbox
Definition: context.h:50
#define REDRAW_STATUS
Redraw the status bar.
Definition: mutt_menu.h:44
bool collapsed
Is this message part of a collapsed thread?
Definition: email.h:73
int vnum
Virtual message number.
Definition: email.h:88
MuttRedrawFlags redraw
When to redraw the screen.
Definition: mutt_menu.h:58
#define REDRAW_INDEX
Redraw the index.
Definition: mutt_menu.h:40
bool collapsed
Are all threads collapsed?
Definition: context.h:48
int index
The absolute (unsorted) message number.
Definition: email.h:86
off_t mutt_set_vnum(struct Mailbox *m)
Set the virtual index number of all the messages in a mailbox.
Definition: mutt_thread.c:1232
int current
Current entry.
Definition: mutt_menu.h:56
bool mutt_thread_can_collapse(struct Email *e)
Check whether a thread can be collapsed.
Definition: mutt_thread.c:1632
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ ci_next_undeleted()

static int ci_next_undeleted ( struct Mailbox m,
int  msgno 
)
static

Find the next undeleted email.

Parameters
mMailbox
msgnoMessage number to start at
Return values
>=0Message number of next undeleted email
-1No more undeleted messages

Definition at line 292 of file index.c.

293 {
294  if (!m)
295  return -1;
296 
297  for (int i = msgno + 1; i < m->vcount; i++)
298  {
299  struct Email *e = mutt_get_virt_email(m, i);
300  if (!e)
301  continue;
302  if (!e->deleted)
303  return i;
304  }
305  return -1;
306 }
The envelope/body of an email.
Definition: email.h:37
struct Email * mutt_get_virt_email(struct Mailbox *m, int vnum)
Get a virtual Email.
Definition: context.c:396
int vcount
The number of virtual messages.
Definition: mailbox.h:102
bool deleted
Email is deleted.
Definition: email.h:45
int msgno
Number displayed to the user.
Definition: email.h:87
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ ci_previous_undeleted()

static int ci_previous_undeleted ( struct Mailbox m,
int  msgno 
)
static

Find the previous undeleted email.

Parameters
mMailbox
msgnoMessage number to start at
Return values
>=0Message number of next undeleted email
-1No more undeleted messages

Definition at line 315 of file index.c.

316 {
317  if (!m)
318  return -1;
319 
320  for (int i = msgno - 1; i >= 0; i--)
321  {
322  struct Email *e = mutt_get_virt_email(m, i);
323  if (!e)
324  continue;
325  if (!e->deleted)
326  return i;
327  }
328  return -1;
329 }
The envelope/body of an email.
Definition: email.h:37
struct Email * mutt_get_virt_email(struct Mailbox *m, int vnum)
Get a virtual Email.
Definition: context.c:396
bool deleted
Email is deleted.
Definition: email.h:45
int msgno
Number displayed to the user.
Definition: email.h:87
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ ci_first_message()

static int ci_first_message ( struct Mailbox m)
static

Get index of first new message.

Parameters
mMailbox
Return values
numIndex of first new message

Return the index of the first new message, or failing that, the first unread message.

Definition at line 339 of file index.c.

340 {
341  if (!m || (m->msg_count == 0))
342  return 0;
343 
344  int old = -1;
345  for (int i = 0; i < m->vcount; i++)
346  {
347  struct Email *e = mutt_get_virt_email(m, i);
348  if (!e)
349  continue;
350  if (!e->read && !e->deleted)
351  {
352  if (!e->old)
353  return i;
354  if (old == -1)
355  old = i;
356  }
357  }
358  if (old != -1)
359  return old;
360 
361  /* If `$sort` is reverse and not threaded, the latest message is first.
362  * If `$sort` is threaded, the latest message is first if exactly one
363  * of `$sort` and `$sort_aux` are reverse. */
364  if (((C_Sort & SORT_REVERSE) && ((C_Sort & SORT_MASK) != SORT_THREADS)) ||
365  (((C_Sort & SORT_MASK) == SORT_THREADS) && ((C_Sort ^ C_SortAux) & SORT_REVERSE)))
366  {
367  return 0;
368  }
369  else
370  {
371  return m->vcount ? m->vcount - 1 : 0;
372  }
373 
374  return 0;
375 }
int msg_count
Total number of messages.
Definition: mailbox.h:91
The envelope/body of an email.
Definition: email.h:37
struct Email * mutt_get_virt_email(struct Mailbox *m, int vnum)
Get a virtual Email.
Definition: context.c:396
int vcount
The number of virtual messages.
Definition: mailbox.h:102
bool read
Email is read.
Definition: email.h:51
bool old
Email is seen, but unread.
Definition: email.h:50
WHERE short C_Sort
Config: Sort method for the index.
Definition: sort.h:60
WHERE short C_SortAux
Config: Secondary sort method for the index.
Definition: sort.h:61
Sort by email threads.
Definition: sort2.h:51
bool deleted
Email is deleted.
Definition: email.h:45
#define SORT_REVERSE
Reverse the order of the sort.
Definition: sort2.h:81
#define SORT_MASK
Mask for the sort id.
Definition: sort2.h:80
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mx_toggle_write()

static int mx_toggle_write ( struct Mailbox m)
static

Toggle the mailbox's readonly flag.

Parameters
mMailbox
Return values
0Success
-1Error

This should be in mx.c, but it only gets used here.

Definition at line 385 of file index.c.

386 {
387  if (!m)
388  return -1;
389 
390  if (m->readonly)
391  {
392  mutt_error(_("Can't toggle write on a readonly mailbox"));
393  return -1;
394  }
395 
396  if (m->dontwrite)
397  {
398  m->dontwrite = false;
399  mutt_message(_("Changes to folder will be written on folder exit"));
400  }
401  else
402  {
403  m->dontwrite = true;
404  mutt_message(_("Changes to folder will not be written"));
405  }
406 
407  return 0;
408 }
#define mutt_message(...)
Definition: logging.h:83
#define _(a)
Definition: message.h:28
bool readonly
Don&#39;t allow changes to the mailbox.
Definition: mailbox.h:119
bool dontwrite
Don&#39;t write the mailbox on close.
Definition: mailbox.h:115
#define mutt_error(...)
Definition: logging.h:84
+ Here is the caller graph for this function:

◆ resort_index()

static void resort_index ( struct Context ctx,
struct Menu menu 
)
static

Resort the index.

Parameters
ctxContext
menuCurrent Menu

Definition at line 415 of file index.c.

416 {
417  if (!ctx || !ctx->mailbox || !menu)
418  return;
419 
420  struct Email *e_cur = mutt_get_virt_email(ctx->mailbox, menu->current);
421 
422  menu->current = -1;
423  mutt_sort_headers(ctx->mailbox, ctx->threads, false, &ctx->vsize);
424  /* Restore the current message */
425 
426  for (int i = 0; i < ctx->mailbox->vcount; i++)
427  {
428  struct Email *e = mutt_get_virt_email(ctx->mailbox, i);
429  if (!e)
430  continue;
431  if (e == e_cur)
432  {
433  menu->current = i;
434  break;
435  }
436  }
437 
438  if (((C_Sort & SORT_MASK) == SORT_THREADS) && (menu->current < 0))
439  menu->current = mutt_parent_message(e_cur, false);
440 
441  if (menu->current < 0)
442  menu->current = ci_first_message(ctx->mailbox);
443 
444  menu->redraw |= REDRAW_INDEX | REDRAW_STATUS;
445 }
static int ci_first_message(struct Mailbox *m)
Get index of first new message.
Definition: index.c:339
The envelope/body of an email.
Definition: email.h:37
struct Email * mutt_get_virt_email(struct Mailbox *m, int vnum)
Get a virtual Email.
Definition: context.c:396
void mutt_sort_headers(struct Mailbox *m, struct ThreadsContext *threads, bool init, off_t *vsize)
Sort emails by their headers.
Definition: sort.c:367
struct ThreadsContext * threads
Threads context.
Definition: context.h:43
int vcount
The number of virtual messages.
Definition: mailbox.h:102
struct Mailbox * mailbox
Definition: context.h:50
WHERE short C_Sort
Config: Sort method for the index.
Definition: sort.h:60
off_t vsize
Size (in bytes) of the messages shown.
Definition: context.h:40
Sort by email threads.
Definition: sort2.h:51
#define REDRAW_STATUS
Redraw the status bar.
Definition: mutt_menu.h:44
int mutt_parent_message(struct Email *e, bool find_root)
Find the parent of a message.
Definition: mutt_thread.c:1182
MuttRedrawFlags redraw
When to redraw the screen.
Definition: mutt_menu.h:58
#define REDRAW_INDEX
Redraw the index.
Definition: mutt_menu.h:40
int current
Current entry.
Definition: mutt_menu.h:56
#define SORT_MASK
Mask for the sort id.
Definition: sort2.h:80
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ update_index_threaded()

static void update_index_threaded ( struct Context ctx,
int  check,
int  oldcount 
)
static

Update the index (if threaded)

Parameters
ctxMailbox
checkFlags, e.g. MUTT_REOPENED
oldcountHow many items are currently in the index

Definition at line 453 of file index.c.

454 {
455  struct Email **save_new = NULL;
456  const bool lmt = ctx_has_limit(ctx);
457 
458  int num_new = MAX(0, ctx->mailbox->msg_count - oldcount);
459 
460  /* save the list of new messages */
461  if ((check != MUTT_REOPENED) && (oldcount > 0) && (lmt || C_UncollapseNew) && (num_new > 0))
462  {
463  save_new = mutt_mem_malloc(num_new * sizeof(struct Email *));
464  for (int i = oldcount; i < ctx->mailbox->msg_count; i++)
465  save_new[i - oldcount] = ctx->mailbox->emails[i];
466  }
467 
468  /* Sort first to thread the new messages, because some patterns
469  * require the threading information.
470  *
471  * If the mailbox was reopened, need to rethread from scratch. */
472  mutt_sort_headers(ctx->mailbox, ctx->threads, (check == MUTT_REOPENED), &ctx->vsize);
473 
474  if (lmt)
475  {
476  /* Because threading changes the order in ctx->mailbox->emails, we don't
477  * know which emails are new. Hence, we need to re-apply the limit to the
478  * whole set.
479  */
480  for (int i = 0; i < ctx->mailbox->msg_count; i++)
481  {
482  struct Email *e = ctx->mailbox->emails[i];
484  ctx->mailbox, e, NULL))
485  {
486  /* vnum will get properly set by mutt_set_vnum(), which
487  * is called by mutt_sort_headers() just below. */
488  e->vnum = 1;
489  e->visible = true;
490  }
491  else
492  {
493  e->vnum = -1;
494  e->visible = false;
495  }
496  }
497  /* Need a second sort to set virtual numbers and redraw the tree */
498  mutt_sort_headers(ctx->mailbox, ctx->threads, false, &ctx->vsize);
499  }
500 
501  /* uncollapse threads with new mail */
502  if (C_UncollapseNew)
503  {
504  if (check == MUTT_REOPENED)
505  {
506  ctx->collapsed = false;
508  mutt_set_vnum(ctx->mailbox);
509  }
510  else if (oldcount > 0)
511  {
512  for (int j = 0; j < num_new; j++)
513  {
514  if (save_new[j]->visible)
515  {
516  mutt_uncollapse_thread(save_new[j]);
517  }
518  }
519  mutt_set_vnum(ctx->mailbox);
520  }
521  }
522 
523  FREE(&save_new);
524 }
struct Email ** emails
Array of Emails.
Definition: mailbox.h:99
int msg_count
Total number of messages.
Definition: mailbox.h:91
void mutt_thread_collapse(struct ThreadsContext *tctx, bool collapse)
toggle collapse
Definition: mutt_thread.c:1604
The envelope/body of an email.
Definition: email.h:37
#define mutt_uncollapse_thread(e)
Definition: mutt_thread.h:90
void mutt_sort_headers(struct Mailbox *m, struct ThreadsContext *threads, bool init, off_t *vsize)
Sort emails by their headers.
Definition: sort.c:367
struct ThreadsContext * threads
Threads context.
Definition: context.h:43
bool ctx_has_limit(const struct Context *ctx)
Is a limit active?
Definition: context.c:417
#define MAX(a, b)
Definition: memory.h:30
struct Mailbox * mailbox
Definition: context.h:50
off_t vsize
Size (in bytes) of the messages shown.
Definition: context.h:40
bool visible
Is this message part of the view?
Definition: email.h:74
#define SLIST_FIRST(head)
Definition: queue.h:228
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:90
struct PatternList * limit_pattern
Compiled limit pattern.
Definition: context.h:42
int vnum
Virtual message number.
Definition: email.h:88
int mutt_pattern_exec(struct Pattern *pat, PatternExecFlags flags, struct Mailbox *m, struct Email *e, struct PatternCache *cache)
Match a pattern against an email header.
Definition: exec.c:738
bool collapsed
Are all threads collapsed?
Definition: context.h:48
#define FREE(x)
Definition: memory.h:40
off_t mutt_set_vnum(struct Mailbox *m)
Set the virtual index number of all the messages in a mailbox.
Definition: mutt_thread.c:1232
Mailbox was reopened.
Definition: mx.h:75
bool C_UncollapseNew
Config: Open collapsed threads when new mail arrives.
Definition: index.c:106
#define MUTT_MATCH_FULL_ADDRESS
Match the full address.
Definition: lib.h:98
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ update_index_unthreaded()

static void update_index_unthreaded ( struct Context ctx,
int  check 
)
static

Update the index (if unthreaded)

Parameters
ctxMailbox
checkFlags, e.g. MUTT_REOPENED

Definition at line 531 of file index.c.

532 {
533  /* We are in a limited view. Check if the new message(s) satisfy
534  * the limit criteria. If they do, set their virtual msgno so that
535  * they will be visible in the limited view */
536  if (ctx_has_limit(ctx))
537  {
538  int padding = mx_msg_padding_size(ctx->mailbox);
539  ctx->mailbox->vcount = ctx->vsize = 0;
540  for (int i = 0; i < ctx->mailbox->msg_count; i++)
541  {
542  struct Email *e = ctx->mailbox->emails[i];
543  if (!e)
544  break;
546  MUTT_MATCH_FULL_ADDRESS, ctx->mailbox, e, NULL))
547  {
548  assert(ctx->mailbox->vcount < ctx->mailbox->msg_count);
549  e->vnum = ctx->mailbox->vcount;
550  ctx->mailbox->v2r[ctx->mailbox->vcount] = i;
551  e->visible = true;
552  ctx->mailbox->vcount++;
553  struct Body *b = e->body;
554  ctx->vsize += b->length + b->offset - b->hdr_offset + padding;
555  }
556  else
557  {
558  e->visible = false;
559  }
560  }
561  }
562 
563  /* if the mailbox was reopened, need to rethread from scratch */
564  mutt_sort_headers(ctx->mailbox, ctx->threads, (check == MUTT_REOPENED), &ctx->vsize);
565 }
struct Email ** emails
Array of Emails.
Definition: mailbox.h:99
int msg_count
Total number of messages.
Definition: mailbox.h:91
The envelope/body of an email.
Definition: email.h:37
struct Body * body
List of MIME parts.
Definition: email.h:91
void mutt_sort_headers(struct Mailbox *m, struct ThreadsContext *threads, bool init, off_t *vsize)
Sort emails by their headers.
Definition: sort.c:367
struct ThreadsContext * threads
Threads context.
Definition: context.h:43
bool ctx_has_limit(const struct Context *ctx)
Is a limit active?
Definition: context.c:417
LOFF_T offset
offset where the actual data begins
Definition: body.h:44
int vcount
The number of virtual messages.
Definition: mailbox.h:102
The body of an email.
Definition: body.h:34
struct Mailbox * mailbox
Definition: context.h:50
off_t vsize
Size (in bytes) of the messages shown.
Definition: context.h:40
bool visible
Is this message part of the view?
Definition: email.h:74
#define SLIST_FIRST(head)
Definition: queue.h:228
LOFF_T length
length (in bytes) of attachment
Definition: body.h:45
struct PatternList * limit_pattern
Compiled limit pattern.
Definition: context.h:42
int vnum
Virtual message number.
Definition: email.h:88
int mutt_pattern_exec(struct Pattern *pat, PatternExecFlags flags, struct Mailbox *m, struct Email *e, struct PatternCache *cache)
Match a pattern against an email header.
Definition: exec.c:738
int * v2r
Mapping from virtual to real msgno.
Definition: mailbox.h:101
int mx_msg_padding_size(struct Mailbox *m)
Bytes of padding between messages - Wrapper for MxOps::msg_padding_size()
Definition: mx.c:1555
long hdr_offset
Offset in stream where the headers begin.
Definition: body.h:42
Mailbox was reopened.
Definition: mx.h:75
#define MUTT_MATCH_FULL_ADDRESS
Match the full address.
Definition: lib.h:98
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ is_current_email()

static bool is_current_email ( const struct CurrentEmail cur,
const struct Email e 
)
static

Check whether an email is the currently selected Email.

Parameters
curCurrently selected Email
eEmail to check
Return values
truee is current
falsee is not current

Definition at line 583 of file index.c.

584 {
585  return cur->sequence == e->sequence;
586 }
size_t sequence
Sequence number assigned on creation.
Definition: email.h:99
size_t sequence
Sequence of the current email.
Definition: index.c:573
+ Here is the caller graph for this function:

◆ set_current_email()

static void set_current_email ( struct CurrentEmail cur,
struct Email e 
)
static

Keep track of the currently selected Email.

Parameters
curCurrently selected Email
eEmail to set as current

Definition at line 593 of file index.c.

594 {
595  cur->e = e;
596  cur->sequence = e ? e->sequence : 0;
597 }
struct Email * e
Current email.
Definition: index.c:572
size_t sequence
Sequence number assigned on creation.
Definition: email.h:99
size_t sequence
Sequence of the current email.
Definition: index.c:573
+ Here is the caller graph for this function:

◆ update_index()

static void update_index ( struct Menu menu,
struct Context ctx,
int  check,
int  oldcount,
const struct CurrentEmail cur 
)
static

Update the index.

Parameters
menuCurrent Menu
ctxMailbox
checkFlags, e.g. MUTT_REOPENED
oldcountHow many items are currently in the index
curRemember our place in the index

Definition at line 607 of file index.c.

609 {
610  if (!menu || !ctx)
611  return;
612 
613  if ((C_Sort & SORT_MASK) == SORT_THREADS)
614  update_index_threaded(ctx, check, oldcount);
615  else
616  update_index_unthreaded(ctx, check);
617 
618  const int old_current = menu->current;
619  menu->current = -1;
620  if (oldcount)
621  {
622  /* restore the current message to the message it was pointing to */
623  for (int i = 0; i < ctx->mailbox->vcount; i++)
624  {
625  struct Email *e = mutt_get_virt_email(ctx->mailbox, i);
626  if (!e)
627  continue;
628  if (is_current_email(cur, e))
629  {
630  menu->current = i;
631  break;
632  }
633  }
634  }
635 
636  if (menu->current < 0)
637  menu->current = (old_current < ctx->mailbox->vcount) ?
638  old_current :
640 }
The "current" mailbox.
Definition: context.h:38
static int ci_first_message(struct Mailbox *m)
Get index of first new message.
Definition: index.c:339
The envelope/body of an email.
Definition: email.h:37
struct Email * mutt_get_virt_email(struct Mailbox *m, int vnum)
Get a virtual Email.
Definition: context.c:396
static void update_index_unthreaded(struct Context *ctx, int check)
Update the index (if unthreaded)
Definition: index.c:531
int vcount
The number of virtual messages.
Definition: mailbox.h:102
struct Mailbox * mailbox
Definition: context.h:50
WHERE short C_Sort
Config: Sort method for the index.
Definition: sort.h:60
Sort by email threads.
Definition: sort2.h:51
static bool is_current_email(const struct CurrentEmail *cur, const struct Email *e)
Check whether an email is the currently selected Email.
Definition: index.c:583
static void update_index_threaded(struct Context *ctx, int check, int oldcount)
Update the index (if threaded)
Definition: index.c:453
int current
Current entry.
Definition: mutt_menu.h:56
#define SORT_MASK
Mask for the sort id.
Definition: sort2.h:80
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_update_index()

void mutt_update_index ( struct Menu menu,
struct Context ctx,
int  check,
int  oldcount,
const struct Email cur_email 
)

Update the index.

Parameters
menuCurrent Menu
ctxMailbox
checkFlags, e.g. MUTT_REOPENED
oldcountHow many items are currently in the index
cur_emailCurrently selected email
Note
cur_email cannot be NULL

Definition at line 652 of file index.c.

654 {
655  struct CurrentEmail se = { .e = NULL, .sequence = cur_email->sequence };
656  update_index(menu, ctx, check, oldcount, &se);
657 }
struct Email * e
Current email.
Definition: index.c:572
Keep track of the currently selected Email.
Definition: index.c:570
static void update_index(struct Menu *menu, struct Context *ctx, int check, int oldcount, const struct CurrentEmail *cur)
Update the index.
Definition: index.c:607
size_t sequence
Sequence number assigned on creation.
Definition: email.h:99
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mailbox_index_observer()

static int mailbox_index_observer ( struct NotifyCallback nc)
static

Listen for Mailbox changes - Implements observer_t.

If a Mailbox is closed, then set a pointer to NULL.

Definition at line 664 of file index.c.

665 {
666  if (!nc->global_data)
667  return -1;
668  if ((nc->event_type != NT_MAILBOX) || (nc->event_subtype != NT_MAILBOX_CLOSED))
669  return 0;
670 
671  struct Mailbox **ptr = nc->global_data;
672  if (!ptr || !*ptr)
673  return 0;
674 
675  *ptr = NULL;
676  return 0;
677 }
Mailbox was closed.
Definition: mailbox.h:172
int event_subtype
Send: Event subtype, e.g. NT_ACCOUNT_ADD.
Definition: observer.h:43
enum NotifyType event_type
Send: Event type, e.g. NT_ACCOUNT.
Definition: observer.h:42
void * global_data
Data from notify_observer_add()
Definition: observer.h:45
A mailbox.
Definition: mailbox.h:81
Mailbox has changed, NotifyMailbox, EventMailbox.
Definition: notify_type.h:42
+ Here is the caller graph for this function:

◆ change_folder_mailbox()

static void change_folder_mailbox ( struct Menu menu,
struct Mailbox m,
int *  oldcount,
const struct CurrentEmail cur,
bool  read_only 
)
static

Change to a different Mailbox by pointer.

Parameters
menuCurrent Menu
mMailbox
oldcountHow many items are currently in the index
curRemember our place in the index
read_onlyOpen Mailbox in read-only mode

Definition at line 687 of file index.c.

689 {
690  if (!m)
691  return;
692 
693  struct Mailbox *m_ctx = ctx_mailbox(Context);
694  /* keepalive failure in mutt_enter_fname may kill connection. */
695  if (m_ctx && (mutt_buffer_is_empty(&m_ctx->pathbuf)))
696  ctx_free(&Context);
697 
698  if (m_ctx)
699  {
700  char *new_last_folder = NULL;
701 #ifdef USE_INOTIFY
702  int monitor_remove_rc = mutt_monitor_remove(NULL);
703 #endif
704 #ifdef USE_COMP_MBOX
705  if (m_ctx->compress_info && (m_ctx->realpath[0] != '\0'))
706  new_last_folder = mutt_str_dup(m_ctx->realpath);
707  else
708 #endif
709  new_last_folder = mutt_str_dup(mailbox_path(m_ctx));
710  *oldcount = m_ctx->msg_count;
711 
712  int check = mx_mbox_close(&Context);
713  if (check != 0)
714  {
715 #ifdef USE_INOTIFY
716  if (monitor_remove_rc == 0)
717  mutt_monitor_add(NULL);
718 #endif
719  if ((check == MUTT_NEW_MAIL) || (check == MUTT_REOPENED))
720  update_index(menu, Context, check, *oldcount, cur);
721 
722  FREE(&new_last_folder);
723  OptSearchInvalid = true;
724  menu->redraw |= REDRAW_INDEX | REDRAW_STATUS;
725  return;
726  }
727  FREE(&LastFolder);
728  LastFolder = new_last_folder;
729  }
731 
732  /* If the `folder-hook` were to call `unmailboxes`, then the Mailbox (`m`)
733  * could be deleted, leaving `m` dangling. */
734  // TODO: Refactor this function to avoid the need for an observer
736  char *dup_path = mutt_str_dup(mailbox_path(m));
737  char *dup_name = mutt_str_dup(m->name);
738 
739  mutt_folder_hook(dup_path, dup_name);
740  if (m)
741  {
742  /* `m` is still valid, but we won't need the observer again before the end
743  * of the function. */
745  }
746 
747  // Recreate the Mailbox as the folder-hook might have invoked `mailboxes`
748  // and/or `unmailboxes`.
749  m = mx_path_resolve(dup_path);
750  FREE(&dup_path);
751  FREE(&dup_name);
752 
753  if (!m)
754  return;
755 
757  Context = mx_mbox_open(m, flags);
758  if (Context)
759  {
761 #ifdef USE_INOTIFY
762  mutt_monitor_add(NULL);
763 #endif
764  }
765  else
766  {
767  menu->current = 0;
768  }
769 
770  if (((C_Sort & SORT_MASK) == SORT_THREADS) && C_CollapseAll)
771  collapse_all(Context, menu, 0);
772 
773  struct MuttWindow *dlg = dialog_find(menu->win_index);
774  struct EventMailbox em = { Context ? Context->mailbox : NULL };
776 
778  /* force the mailbox check after we have changed the folder */
780  menu->redraw = REDRAW_FULL;
781  OptSearchInvalid = true;
782 }
#define MUTT_OPEN_NO_FLAGS
No flags are set.
Definition: mx.h:51
The "current" mailbox.
Definition: context.h:38
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox&#39;s path string.
Definition: mailbox.h:204
static int ci_first_message(struct Mailbox *m)
Get index of first new message.
Definition: index.c:339
#define REDRAW_FULL
Redraw everything.
Definition: mutt_menu.h:45
int msg_count
Total number of messages.
Definition: mailbox.h:91
struct Mailbox * ctx_mailbox(struct Context *ctx)
wrapper to get the mailbox in a Context, or NULL
Definition: context.c:428
int mx_mbox_close(struct Context **ptr)
Save changes and close mailbox.
Definition: mx.c:630
struct Mailbox * mailbox
The Mailbox this Event relates to.
Definition: mailbox.h:185
int mutt_monitor_remove(struct Mailbox *m)
Remove a watch for a mailbox.
Definition: monitor.c:526
char * realpath
Used for duplicate detection, context comparison, and the sidebar.
Definition: mailbox.h:84
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:370
struct Context * mx_mbox_open(struct Mailbox *m, OpenMailboxFlags flags)
Open a mailbox and parse it.
Definition: mx.c:303
A division of the screen.
Definition: mutt_window.h:115
bool C_CollapseAll
Config: Collapse all threads when entering a folder.
Definition: index.c:103
uint8_t OpenMailboxFlags
Flags for mutt_open_mailbox(), e.g. MUTT_NOSORT.
Definition: mx.h:50
#define MUTT_READONLY
Open in read-only mode.
Definition: mx.h:54
An Event that happened to a Mailbox.
Definition: mailbox.h:183
int mutt_monitor_add(struct Mailbox *m)
Add a watch for a mailbox.
Definition: monitor.c:481
void mutt_folder_hook(const char *path, const char *desc)
Perform a folder hook.
Definition: hook.c:504
char * name
A short name for the Mailbox.
Definition: mailbox.h:85
struct Notify * notify
Notifications system.
Definition: mutt_window.h:131
struct Mailbox * mailbox
Definition: context.h:50
WHERE short C_Sort
Config: Sort method for the index.
Definition: sort.h:60
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:113
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:169
static int mailbox_index_observer(struct NotifyCallback *nc)
Listen for Mailbox changes - Implements observer_t.
Definition: index.c:664
Sort by email threads.
Definition: sort2.h:51
#define REDRAW_STATUS
Redraw the status bar.
Definition: mutt_menu.h:44
A mailbox.
Definition: mailbox.h:81
int mutt_mailbox_check(struct Mailbox *m_cur, int force)
Check all all Mailboxes for new mail.
Definition: mutt_mailbox.c:138
static void update_index(struct Menu *menu, struct Context *ctx, int check, int oldcount, const struct CurrentEmail *cur)
Update the index.
Definition: index.c:607
WHERE bool OptSearchInvalid
(pseudo) used to invalidate the search pattern
Definition: options.h:52
WHERE char * LastFolder
Previously selected mailbox.
Definition: mutt_globals.h:55
#define MUTT_MAILBOX_CHECK_FORCE
Definition: mutt_mailbox.h:16
MuttRedrawFlags redraw
When to redraw the screen.
Definition: mutt_menu.h:58
uint8_t flags
e.g. MB_NORMAL
Definition: mailbox.h:134
#define REDRAW_INDEX
Redraw the index.
Definition: mutt_menu.h:40
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:446
Current Mailbox has changed.
Definition: mailbox.h:175
void * compress_info
Compressed mbox module private data.
Definition: mailbox.h:124
WHERE char * CurrentFolder
Currently selected mailbox.
Definition: mutt_globals.h:54
static void collapse_all(struct Context *ctx, struct Menu *menu, int toggle)
Collapse/uncollapse all threads.
Definition: index.c:237
#define FREE(x)
Definition: memory.h:40
struct Mailbox * mx_path_resolve(const char *path)
Get a Mailbox for a path.
Definition: mx.c:1682
Mailbox has changed, NotifyMailbox, EventMailbox.
Definition: notify_type.h:42
bool notify_observer_remove(struct Notify *notify, observer_t callback, void *global_data)
Remove an observer from an object.
Definition: notify.c:207
void ctx_free(struct Context **ptr)
Free a Context.
Definition: context.c:50
New mail received in Mailbox.
Definition: mx.h:73
struct Notify * notify
Notifications handler.
Definition: mailbox.h:144
int current
Current entry.
Definition: mutt_menu.h:56
struct Buffer pathbuf
Definition: mailbox.h:83
struct MuttWindow * win_index
Definition: mutt_menu.h:63
bool mutt_buffer_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:252
Mailbox was reopened.
Definition: mx.h:75
struct MuttWindow * dialog_find(struct MuttWindow *win)
Find the parent Dialog of a Window.
Definition: dialog.c:46
#define SORT_MASK
Mask for the sort id.
Definition: sort2.h:80
bool notify_send(struct Notify *notify, enum NotifyType event_type, int event_subtype, void *event_data)
Send out a notification message.
Definition: notify.c:152
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ change_folder_notmuch()

static struct Mailbox* change_folder_notmuch ( struct Menu menu,
char *  buf,
int  buflen,
int *  oldcount,
const struct CurrentEmail cur,
bool  read_only 
)
static

Change to a different Notmuch Mailbox by string.

Parameters
menuCurrent Menu
bufFolder to change to
buflenLength of buffer
oldcountHow many items are currently in the index
curRemember our place in the index
read_onlyOpen Mailbox in read-only mode

Definition at line 794 of file index.c.

797 {
798  if (!nm_url_from_query(NULL, buf, buflen))
799  {
800  mutt_message(_("Failed to create query, aborting"));
801  return NULL;
802  }
803 
804  struct Mailbox *m_query = mx_path_resolve(buf);
805  change_folder_mailbox(menu, m_query, oldcount, cur, read_only);
806  return m_query;
807 }
#define mutt_message(...)
Definition: logging.h:83
#define _(a)
Definition: message.h:28
A mailbox.
Definition: mailbox.h:81
struct Mailbox * mx_path_resolve(const char *path)
Get a Mailbox for a path.
Definition: mx.c:1682
static void change_folder_mailbox(struct Menu *menu, struct Mailbox *m, int *oldcount, const struct CurrentEmail *cur, bool read_only)
Change to a different Mailbox by pointer.
Definition: index.c:687
char * nm_url_from_query(struct Mailbox *m, char *buf, size_t buflen)
Turn a query into a URL.
Definition: notmuch.c:1807
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ change_folder_string()

static void change_folder_string ( struct Menu menu,
char *  buf,
size_t  buflen,
int *  oldcount,
const struct CurrentEmail cur,
bool *  pager_return,
bool  read_only 
)
static

Change to a different Mailbox by string.

Parameters
menuCurrent Menu
bufFolder to change to
buflenLength of buffer
oldcountHow many items are currently in the index
curRemember our place in the index
pager_returnReturn to the pager afterwards
read_onlyOpen Mailbox in read-only mode

Definition at line 820 of file index.c.

823 {
824 #ifdef USE_NNTP
825  if (OptNews)
826  {
827  OptNews = false;
828  nntp_expand_path(buf, buflen, &CurrentNewsSrv->conn->account);
829  }
830  else
831 #endif
832  {
833  mx_path_canon(buf, buflen, C_Folder, NULL);
834  }
835 
836  enum MailboxType type = mx_path_probe(buf);
837  if ((type == MUTT_MAILBOX_ERROR) || (type == MUTT_UNKNOWN))
838  {
839  // Look for a Mailbox by its description, before failing
840  struct Mailbox *m = mailbox_find_name(buf);
841  if (m)
842  {
843  change_folder_mailbox(menu, m, oldcount, cur, read_only);
844  *pager_return = false;
845  }
846  else
847  mutt_error(_("%s is not a mailbox"), buf);
848  return;
849  }
850 
851  /* past this point, we don't return to the pager on error */
852  *pager_return = false;
853 
854  struct Mailbox *m = mx_path_resolve(buf);
855  change_folder_mailbox(menu, m, oldcount, cur, read_only);
856 }
enum MailboxType type
Mailbox type.
Definition: mailbox.h:105
struct ConnAccount account
Account details: username, password, etc.
Definition: connection.h:36
#define _(a)
Definition: message.h:28
Mailbox wasn&#39;t recognised.
Definition: mailbox.h:47
Error occurred examining Mailbox.
Definition: mailbox.h:46
struct Mailbox * mailbox_find_name(const char *name)
Find the mailbox with a given name.
Definition: mailbox.c:138
A mailbox.
Definition: mailbox.h:81
WHERE char * C_Folder
Config: Base folder for a set of mailboxes.
Definition: mutt_globals.h:96
struct Connection * conn
Definition: lib.h:102
enum MailboxType mx_path_probe(const char *path)
Find a mailbox that understands a path.
Definition: mx.c:1336
MailboxType
Supported mailbox formats.
Definition: mailbox.h:43
#define mutt_error(...)
Definition: logging.h:84
struct Mailbox * mx_path_resolve(const char *path)
Get a Mailbox for a path.
Definition: mx.c:1682
struct NntpAccountData * CurrentNewsSrv
Current NNTP news server.
Definition: nntp.c:76
static void change_folder_mailbox(struct Menu *menu, struct Mailbox *m, int *oldcount, const struct CurrentEmail *cur, bool read_only)
Change to a different Mailbox by pointer.
Definition: index.c:687
void nntp_expand_path(char *buf, size_t buflen, struct ConnAccount *acct)
Make fully qualified url from newsgroup name.
Definition: newsrc.c:557
int mx_path_canon(char *buf, size_t buflen, const char *folder, enum MailboxType *type)
Canonicalise a mailbox path - Wrapper for MxOps::path_canon()
Definition: mx.c:1382
WHERE bool OptNews
(pseudo) used to change reader mode
Definition: options.h:45
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ index_make_entry()

void index_make_entry ( char *  buf,
size_t  buflen,
struct Menu menu,
int  line 
)

Format a menu item for the index list - Implements Menu::make_entry()

Definition at line 861 of file index.c.

862 {
863  buf[0] = '\0';
864 
865  struct Mailbox *m = ctx_mailbox(Context);
866 
867  if (!m || !menu || (line < 0) || (line >= m->email_max))
868  return;
869 
870  struct Email *e = mutt_get_virt_email(m, line);
871  if (!e)
872  return;
873 
875  struct MuttThread *tmp = NULL;
876 
877  if (((C_Sort & SORT_MASK) == SORT_THREADS) && e->tree)
878  {
879  flags |= MUTT_FORMAT_TREE; /* display the thread tree */
880  if (e->display_subject)
881  flags |= MUTT_FORMAT_FORCESUBJ;
882  else
883  {
884  const int reverse = C_Sort & SORT_REVERSE;
885  int edgemsgno;
886  if (reverse)
887  {
888  if (menu->top + menu->pagelen > menu->max)
889  edgemsgno = m->v2r[menu->max - 1];
890  else
891  edgemsgno = m->v2r[menu->top + menu->pagelen - 1];
892  }
893  else
894  edgemsgno = m->v2r[menu->top];
895 
896  for (tmp = e->thread->parent; tmp; tmp = tmp->parent)
897  {
898  if (!tmp->message)
899  continue;
900 
901  /* if no ancestor is visible on current screen, provisionally force
902  * subject... */
903  if (reverse ? (tmp->message->msgno > edgemsgno) : (tmp->message->msgno < edgemsgno))
904  {
905  flags |= MUTT_FORMAT_FORCESUBJ;
906  break;
907  }
908  else if (tmp->message->vnum >= 0)
909  break;
910  }
911  if (flags & MUTT_FORMAT_FORCESUBJ)
912  {
913  for (tmp = e->thread->prev; tmp; tmp = tmp->prev)
914  {
915  if (!tmp->message)
916  continue;
917 
918  /* ...but if a previous sibling is available, don't force it */
919  if (reverse ? (tmp->message->msgno > edgemsgno) : (tmp->message->msgno < edgemsgno))
920  break;
921  else if (tmp->message->vnum >= 0)
922  {
923  flags &= ~MUTT_FORMAT_FORCESUBJ;
924  break;
925  }
926  }
927  }
928  }
929  }
930 
931  mutt_make_string_flags(buf, buflen, menu->win_index->state.cols,
932  NONULL(C_IndexFormat), m, Context->msg_in_pager, e, flags);
933 }
The "current" mailbox.
Definition: context.h:38
uint8_t MuttFormatFlags
Flags for mutt_expando_format(), e.g. MUTT_FORMAT_FORCESUBJ.
Definition: format_flags.h:29
#define NONULL(x)
Definition: string2.h:37
void mutt_make_string_flags(char *buf, size_t buflen, int cols, const char *s, struct Mailbox *m, int inpgr, struct Email *e, MuttFormatFlags flags)
Create formatted strings using mailbox expandos.
Definition: hdrline.c:1415
int msg_in_pager
Message currently shown in the pager.
Definition: context.h:44
The envelope/body of an email.
Definition: email.h:37
struct Email * mutt_get_virt_email(struct Mailbox *m, int vnum)
Get a virtual Email.
Definition: context.c:396
struct Mailbox * ctx_mailbox(struct Context *ctx)
wrapper to get the mailbox in a Context, or NULL
Definition: context.c:428
#define MUTT_FORMAT_FORCESUBJ
Print the subject even if unchanged.
Definition: format_flags.h:31
struct MuttThread * thread
Thread of Emails.
Definition: email.h:95
#define MUTT_FORMAT_ARROWCURSOR
Reserve space for arrow_cursor.
Definition: format_flags.h:35
bool display_subject
Used for threading.
Definition: email.h:57
struct MuttThread * parent
Parent of this Thread.
Definition: thread.h:45
struct MuttThread * prev
Previous sibling Thread.
Definition: thread.h:48
#define MUTT_FORMAT_TREE
Draw the thread tree.
Definition: format_flags.h:32
WHERE char * C_IndexFormat
Config: printf-like format string for the index menu (emails)
Definition: mutt_globals.h:92
WHERE short C_Sort
Config: Sort method for the index.
Definition: sort.h:60
short cols
Number of columns, can be MUTT_WIN_SIZE_UNLIMITED.
Definition: mutt_window.h:57
Sort by email threads.
Definition: sort2.h:51
struct WindowState state
Current state of the Window.
Definition: mutt_window.h:120
int email_max
Number of pointers in emails.
Definition: mailbox.h:100
A mailbox.
Definition: mailbox.h:81
int top
Entry that is the top of the current page.
Definition: mutt_menu.h:75
int vnum
Virtual message number.
Definition: email.h:88
int pagelen
Number of entries per screen.
Definition: mutt_menu.h:60
char * tree
Character string to print thread tree.
Definition: email.h:94
struct Email * message
Email this Thread refers to.
Definition: thread.h:49
int max
Number of entries in the menu.
Definition: mutt_menu.h:57
An Email conversation.
Definition: thread.h:34
int * v2r
Mapping from virtual to real msgno.
Definition: mailbox.h:101
#define MUTT_FORMAT_INDEX
This is a main index entry.
Definition: format_flags.h:36
struct MuttWindow * win_index
Definition: mutt_menu.h:63
#define SORT_REVERSE
Reverse the order of the sort.
Definition: sort2.h:81
#define SORT_MASK
Mask for the sort id.
Definition: sort2.h:80
int msgno
Number displayed to the user.
Definition: email.h:87
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ index_color()

int index_color ( int  line)

Calculate the colour for a line of the index - Implements Menu::color()

Definition at line 938 of file index.c.

939 {
940  struct Mailbox *m = ctx_mailbox(Context);
941  if (!m || (line < 0))
942  return 0;
943 
944  struct Email *e = mutt_get_virt_email(m, line);
945  if (!e)
946  return 0;
947 
948  if (e->pair)
949  return e->pair;
950 
951  mutt_set_header_color(m, e);
952  return e->pair;
953 }
The "current" mailbox.
Definition: context.h:38
The envelope/body of an email.
Definition: email.h:37
struct Email * mutt_get_virt_email(struct Mailbox *m, int vnum)
Get a virtual Email.
Definition: context.c:396
struct Mailbox * ctx_mailbox(struct Context *ctx)
wrapper to get the mailbox in a Context, or NULL
Definition: context.c:428
A mailbox.
Definition: mailbox.h:81
void mutt_set_header_color(struct Mailbox *m, struct Email *e)
Select a colour for a message.
Definition: index.c:3962
int pair
Color-pair to use when displaying in the index.
Definition: email.h:80
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_draw_statusline()

void mutt_draw_statusline ( int  cols,
const char *  buf,
size_t  buflen 
)

Draw a highlighted status bar.

Parameters
colsMaximum number of screen columns
bufMessage to be displayed
buflenLength of the buffer

Users configure the highlighting of the status bar, e.g. color status red default "[0-9][0-9]:[0-9][0-9]"

Where regexes overlap, the one nearest the start will be used. If two regexes start at the same place, the longer match will be used.

Definition at line 967 of file index.c.

968 {
969  if (!buf || !stdscr)
970  return;
971 
972  size_t i = 0;
973  size_t offset = 0;
974  bool found = false;
975  size_t chunks = 0;
976  size_t len = 0;
977 
978  struct StatusSyntax
979  {
980  int color;
981  int first;
982  int last;
983  } *syntax = NULL;
984 
985  do
986  {
987  struct ColorLine *cl = NULL;
988  found = false;
989 
990  if (!buf[offset])
991  break;
992 
993  /* loop through each "color status regex" */
994  STAILQ_FOREACH(cl, &Colors->status_list, entries)
995  {
996  regmatch_t pmatch[cl->match + 1];
997 
998  if (regexec(&cl->regex, buf + offset, cl->match + 1, pmatch, 0) != 0)
999  continue; /* regex doesn't match the status bar */
1000 
1001  int first = pmatch[cl->match].rm_so + offset;
1002  int last = pmatch[cl->match].rm_eo + offset;
1003 
1004  if (first == last)
1005  continue; /* ignore an empty regex */
1006 
1007  if (!found)
1008  {
1009  chunks++;
1010  mutt_mem_realloc(&syntax, chunks * sizeof(struct StatusSyntax));
1011  }
1012 
1013  i = chunks - 1;
1014  if (!found || (first < syntax[i].first) ||
1015  ((first == syntax[i].first) && (last > syntax[i].last)))
1016  {
1017  syntax[i].color = cl->pair;
1018  syntax[i].first = first;
1019  syntax[i].last = last;
1020  }
1021  found = true;
1022  }
1023 
1024  if (syntax)
1025  {
1026  offset = syntax[i].last;
1027  }
1028  } while (found);
1029 
1030  /* Only 'len' bytes will fit into 'cols' screen columns */
1031  len = mutt_wstr_trunc(buf, buflen, cols, NULL);
1032 
1033  offset = 0;
1034 
1035  if ((chunks > 0) && (syntax[0].first > 0))
1036  {
1037  /* Text before the first highlight */
1038  mutt_window_addnstr(buf, MIN(len, syntax[0].first));
1039  attrset(Colors->defs[MT_COLOR_STATUS]);
1040  if (len <= syntax[0].first)
1041  goto dsl_finish; /* no more room */
1042 
1043  offset = syntax[0].first;
1044  }
1045 
1046  for (i = 0; i < chunks; i++)
1047  {
1048  /* Highlighted text */
1049  attrset(syntax[i].color);
1050  mutt_window_addnstr(buf + offset, MIN(len, syntax[i].last) - offset);
1051  if (len <= syntax[i].last)
1052  goto dsl_finish; /* no more room */
1053 
1054  size_t next;
1055  if ((i + 1) == chunks)
1056  {
1057  next = len;
1058  }
1059  else
1060  {
1061  next = MIN(len, syntax[i + 1].first);
1062  }
1063 
1064  attrset(Colors->defs[MT_COLOR_STATUS]);
1065  offset = syntax[i].last;
1066  mutt_window_addnstr(buf + offset, next - offset);
1067 
1068  offset = next;
1069  if (offset >= len)
1070  goto dsl_finish; /* no more room */
1071  }
1072 
1073  attrset(Colors->defs[MT_COLOR_STATUS]);
1074  if (offset < len)
1075  {
1076  /* Text after the last highlight */
1077  mutt_window_addnstr(buf + offset, len - offset);
1078  }
1079 
1080  int width = mutt_strwidth(buf);
1081  if (width < cols)
1082  {
1083  /* Pad the rest of the line with whitespace */
1084  mutt_paddstr(cols - width, "");
1085  }
1086 dsl_finish:
1087  FREE(&syntax);
1088 }
struct ColorLineList status_list
List of colours applied to the status bar.
Definition: color.h:141
#define MIN(a, b)
Definition: memory.h:31
int * defs
Array of all fixed colours, see enum ColorId.
Definition: color.h:131
int pair
Colour pair index.
Definition: color.h:43
void mutt_paddstr(int n, const char *s)
Display a string on screen, padded if necessary.
Definition: curs_lib.c:1266
int match
Substring to match, 0 for old behaviour.
Definition: color.h:38
int mutt_window_addnstr(const char *str, int num)
Write a partial string to a Window.
Definition: mutt_window.c:504
void mutt_mem_realloc(void *ptr, size_t size)
Resize a block of memory on the heap.
Definition: memory.c:114
Status bar (takes a pattern)
Definition: color.h:94
int mutt_strwidth(const char *s)
Measure a string&#39;s width in screen cells.
Definition: curs_lib.c:1359
size_t mutt_wstr_trunc(const char *src, size_t maxlen, size_t maxwid, size_t *width)
Work out how to truncate a widechar string.
Definition: curs_lib.c:1309
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:349
Definition: color.h:129
LOFF_T offset
Where in the stream does this message begin?
Definition: email.h:84
regex_t regex
Compiled regex.
Definition: color.h:37
#define FREE(x)
Definition: memory.h:40
A regular expression and a color to highlight a line.
Definition: color.h:35
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ index_custom_redraw()

static void index_custom_redraw ( struct Menu menu)
static

Redraw the index - Implements Menu::custom_redraw()

Definition at line 1093 of file index.c.

1094 {
1095  if (menu->redraw & REDRAW_FULL)
1096  {
1097  menu_redraw_full(menu);
1098  mutt_show_error();
1099  }
1100 
1101  struct Mailbox *m = ctx_mailbox(Context);
1102  if (m && m->emails && !(menu->current >= m->vcount))
1103  {
1104  menu_check_recenter(menu);
1105 
1106  if (menu->redraw & REDRAW_INDEX)
1107  {
1108  menu_redraw_index(menu);
1109  menu->redraw |= REDRAW_STATUS;
1110  }
1111  else if (menu->redraw & (REDRAW_MOTION_RESYNC | REDRAW_MOTION))
1112  menu_redraw_motion(menu);
1113  else if (menu->redraw & REDRAW_CURRENT)
1114  menu_redraw_current(menu);
1115  }
1116 
1117  if (menu->redraw & REDRAW_STATUS)
1118  {
1119  char buf[1024];
1120  menu_status_line(buf, sizeof(buf), menu, m, NONULL(C_StatusFormat));
1121  mutt_window_move(menu->win_ibar, 0, 0);
1123  mutt_draw_statusline(menu->win_ibar->state.cols, buf, sizeof(buf));
1125  menu->redraw &= ~REDRAW_STATUS;
1126  if (C_TsEnabled && TsSupported)
1127  {
1128  menu_status_line(buf, sizeof(buf), menu, m, NONULL(C_TsStatusFormat));
1129  mutt_ts_status(buf);
1130  menu_status_line(buf, sizeof(buf), menu, m, NONULL(C_TsIconFormat));
1131  mutt_ts_icon(buf);
1132  }
1133  }
1134 
1135  menu->redraw = REDRAW_NO_FLAGS;
1136 }
struct Email ** emails
Array of Emails.
Definition: mailbox.h:99
The "current" mailbox.
Definition: context.h:38
#define REDRAW_FULL
Redraw everything.
Definition: mutt_menu.h:45
#define NONULL(x)
Definition: string2.h:37
struct Mailbox * ctx_mailbox(struct Context *ctx)
wrapper to get the mailbox in a Context, or NULL
Definition: context.c:428
WHERE char * C_TsIconFormat
Config: printf-like format string for the terminal&#39;s icon title.
Definition: mutt_globals.h:111
void mutt_curses_set_color(enum ColorId color)
Set the current colour for text.
Definition: mutt_curses.c:57
int vcount
The number of virtual messages.
Definition: mailbox.h:102
int mutt_window_move(struct MuttWindow *win, int col, int row)
Move the cursor in a Window.
Definition: mutt_window.c:382
struct MuttWindow * win_ibar
Definition: mutt_menu.h:64
WHERE char * C_StatusFormat
Config: printf-like format string for the index&#39;s status line.
Definition: mutt_globals.h:109
#define REDRAW_MOTION
Redraw after moving the menu list.
Definition: mutt_menu.h:41
Plain text.
Definition: color.h:77
#define REDRAW_MOTION_RESYNC
Redraw any changing the menu selection.
Definition: mutt_menu.h:42
void menu_status_line(char *buf, size_t buflen, struct Menu *menu, struct Mailbox *m, const char *p)
Create the status line.
Definition: status.c:420
short cols
Number of columns, can be MUTT_WIN_SIZE_UNLIMITED.
Definition: mutt_window.h:57
struct WindowState state
Current state of the Window.
Definition: mutt_window.h:120
#define REDRAW_STATUS
Redraw the status bar.
Definition: mutt_menu.h:44
Status bar (takes a pattern)
Definition: color.h:94
A mailbox.
Definition: mailbox.h:81
WHERE bool C_TsEnabled
Config: Allow NeoMutt to set the terminal status line and icon.
Definition: mutt_globals.h:167
bool TsSupported
Terminal Setting is supported.
Definition: terminal.c:43
WHERE char * C_TsStatusFormat
Config: printf-like format string for the terminal&#39;s status (window title)
Definition: mutt_globals.h:110
MuttRedrawFlags redraw
When to redraw the screen.
Definition: mutt_menu.h:58
#define REDRAW_INDEX
Redraw the index.
Definition: mutt_menu.h:40
void mutt_ts_icon(char *str)
Set the icon in the terminal title bar.
Definition: terminal.c:118
void mutt_show_error(void)
Show the user an error message.
Definition: curs_lib.c:557
void mutt_ts_status(char *str)
Set the text of the terminal title bar.
Definition: terminal.c:104
int current
Current entry.
Definition: mutt_menu.h:56
#define REDRAW_NO_FLAGS
No flags are set.
Definition: mutt_menu.h:39
void mutt_draw_statusline(int cols, const char *buf, size_t buflen)
Draw a highlighted status bar.
Definition: index.c:967
#define REDRAW_CURRENT
Redraw the current line of the menu.
Definition: mutt_menu.h:43
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_index_menu()

int mutt_index_menu ( struct MuttWindow dlg)

Display a list of emails.

Parameters
dlgDialog containing Windows to draw on
Return values
numHow the menu was finished, e.g. OP_QUIT, OP_EXIT

This function handles the message index window as well as commands returned from the pager (MENU_PAGER).

Definition at line 1146 of file index.c.

1147 {
1148  char buf[PATH_MAX];
1149  int op = OP_NULL;
1150  bool done = false; /* controls when to exit the "event" loop */
1151  bool tag = false; /* has the tag-prefix command been pressed? */
1152  int newcount = -1;
1153  int oldcount = -1;
1154  struct CurrentEmail cur = { 0 };
1155  bool do_mailbox_notify = true;
1156  int close = 0; /* did we OP_QUIT or OP_EXIT out of this menu? */
1157  int attach_msg = OptAttachMsg;
1158  bool in_pager = false; /* set when pager redirects a function through the index */
1159 
1160  struct MuttWindow *win_index = mutt_window_find(dlg, WT_INDEX);
1161  struct MuttWindow *win_ibar = mutt_window_find(dlg, WT_INDEX_BAR);
1162  struct MuttWindow *win_pager = mutt_window_find(dlg, WT_PAGER);
1163  struct MuttWindow *win_pbar = mutt_window_find(dlg, WT_PAGER_BAR);
1164 
1165 #ifdef USE_NNTP
1167  dlg->help_data = IndexNewsHelp;
1168  else
1169 #endif
1170  dlg->help_data = IndexHelp;
1171  dlg->help_menu = MENU_MAIN;
1172 
1173  struct Menu *menu = mutt_menu_new(MENU_MAIN);
1174  menu->pagelen = win_index->state.rows;
1175  menu->win_index = win_index;
1176  menu->win_ibar = win_ibar;
1177 
1178  menu->make_entry = index_make_entry;
1179  menu->color = index_color;
1182  mutt_menu_push_current(menu);
1183  mutt_window_reflow(NULL);
1184 
1185  if (!attach_msg)
1186  {
1187  /* force the mailbox check after we enter the folder */
1189  }
1190 #ifdef USE_INOTIFY
1191  mutt_monitor_add(NULL);
1192 #endif
1193 
1194  if (((C_Sort & SORT_MASK) == SORT_THREADS) && C_CollapseAll)
1195  {
1196  collapse_all(Context, menu, 0);
1197  menu->redraw = REDRAW_FULL;
1198  }
1199 
1200  while (true)
1201  {
1202  /* Clear the tag prefix unless we just started it. Don't clear
1203  * the prefix on a timeout (op==-2), but do clear on an abort (op==-1) */
1204  if (tag && (op != OP_TAG_PREFIX) && (op != OP_TAG_PREFIX_COND) && (op != -2))
1205  tag = false;
1206 
1207  /* check if we need to resort the index because just about
1208  * any 'op' below could do mutt_enter_command(), either here or
1209  * from any new menu launched, and change $sort/$sort_aux */
1210  if (OptNeedResort && ctx_mailbox(Context) &&
1211  (Context->mailbox->msg_count != 0) && (menu->current >= 0))
1212  {
1213  resort_index(Context, menu);
1214  }
1215 
1216  menu->max = ctx_mailbox(Context) ? Context->mailbox->vcount : 0;
1217  oldcount = ctx_mailbox(Context) ? Context->mailbox->msg_count : 0;
1218 
1219  if (OptRedrawTree && ctx_mailbox(Context) && (Context->mailbox->msg_count != 0) &&
1220  ((C_Sort & SORT_MASK) == SORT_THREADS))
1221  {
1223  menu->redraw |= REDRAW_STATUS;
1224  OptRedrawTree = false;
1225  }
1226 
1227  if (ctx_mailbox(Context))
1228  {
1229  Context->menu = menu;
1230  /* check for new mail in the mailbox. If nonzero, then something has
1231  * changed about the file (either we got new mail or the file was
1232  * modified underneath us.) */
1233  int check = mx_mbox_check(Context->mailbox);
1234 
1235  if (check < 0)
1236  {
1238  {
1239  /* fatal error occurred */
1240  ctx_free(&Context);
1241  menu->redraw = REDRAW_FULL;
1242  }
1243 
1244  OptSearchInvalid = true;
1245  }
1246  else if ((check == MUTT_NEW_MAIL) || (check == MUTT_REOPENED) || (check == MUTT_FLAGS))
1247  {
1248  /* notify the user of new mail */
1249  if (check == MUTT_REOPENED)
1250  {
1251  mutt_error(
1252  _("Mailbox was externally modified. Flags may be wrong."));
1253  }
1254  else if (check == MUTT_NEW_MAIL)
1255  {
1256  for (size_t i = 0; i < Context->mailbox->msg_count; i++)
1257  {
1258  const struct Email *e = Context->mailbox->emails[i];
1259  if (e && !e->read && !e->old)
1260  {
1261  mutt_message(_("New mail in this mailbox"));
1262  if (C_BeepNew)
1263  mutt_beep(true);
1264  if (C_NewMailCommand)
1265  {
1266  char cmd[1024];
1267  menu_status_line(cmd, sizeof(cmd), menu, Context->mailbox,
1269  if (mutt_system(cmd) != 0)
1270  mutt_error(_("Error running \"%s\""), cmd);
1271  }
1272  break;
1273  }
1274  }
1275  }
1276  else if (check == MUTT_FLAGS)
1277  {
1278  mutt_message(_("Mailbox was externally modified"));
1279  }
1280 
1281  /* avoid the message being overwritten by mailbox */
1282  do_mailbox_notify = false;
1283 
1284  bool verbose = Context->mailbox->verbose;
1285  Context->mailbox->verbose = false;
1286  update_index(menu, Context, check, oldcount, &cur);
1287  Context->mailbox->verbose = verbose;
1288  menu->max = Context->mailbox->vcount;
1289  menu->redraw = REDRAW_FULL;
1290  OptSearchInvalid = true;
1291  }
1292 
1293  if (Context)
1294  {
1296  }
1297  }
1298 
1299  if (!attach_msg)
1300  {
1301  struct Mailbox *m = Context ? Context->mailbox : NULL;
1302  /* check for new mail in the incoming folders */
1303  oldcount = newcount;
1304  newcount = mutt_mailbox_check(m, 0);
1305  if (newcount != oldcount)
1306  menu->redraw |= REDRAW_STATUS;
1307  if (do_mailbox_notify)
1308  {
1309  if (mutt_mailbox_notify(m))
1310  {
1311  menu->redraw |= REDRAW_STATUS;
1312  if (C_BeepNew)
1313  mutt_beep(true);
1314  if (C_NewMailCommand)
1315  {
1316  char cmd[1024];
1317  menu_status_line(cmd, sizeof(cmd), menu, m, NONULL(C_NewMailCommand));
1318  if (mutt_system(cmd) != 0)
1319  mutt_error(_("Error running \"%s\""), cmd);
1320  }
1321  }
1322  }
1323  else
1324  do_mailbox_notify = true;
1325  }
1326 
1327  if (op >= 0)
1329 
1330  if (in_pager)
1331  {
1332  if (menu->current < menu->max)
1333  menu->oldcurrent = menu->current;
1334  else
1335  menu->oldcurrent = -1;
1336 
1337  mutt_curses_set_cursor(MUTT_CURSOR_VISIBLE); /* fallback from the pager */
1338  }
1339  else
1340  {
1341  index_custom_redraw(menu);
1342  window_redraw(RootWindow, false);
1343 
1344  /* give visual indication that the next command is a tag- command */
1345  if (tag)
1346  {
1347  mutt_window_mvaddstr(MessageWindow, 0, 0, "tag-");
1349  }
1350 
1351  if (menu->current < menu->max)
1352  menu->oldcurrent = menu->current;
1353  else
1354  menu->oldcurrent = -1;
1355 
1356  if (C_ArrowCursor)
1357  mutt_window_move(menu->win_index, 2, menu->current - menu->top);
1358  else if (C_BrailleFriendly)
1359  mutt_window_move(menu->win_index, 0, menu->current - menu->top);
1360  else
1361  {
1362  mutt_window_move(menu->win_index, menu->win_index->state.cols - 1,
1363  menu->current - menu->top);
1364  }
1365  mutt_refresh();
1366 
1367  if (SigWinch)
1368  {
1369  SigWinch = 0;
1371  menu->top = 0; /* so we scroll the right amount */
1372  /* force a real complete redraw. clrtobot() doesn't seem to be able
1373  * to handle every case without this. */
1374  clearok(stdscr, true);
1376  continue;
1377  }
1378 
1379  op = km_dokey(MENU_MAIN);
1380 
1381  /* either user abort or timeout */
1382  if (op < 0)
1383  {
1385  if (tag)
1387  continue;
1388  }
1389 
1390  mutt_debug(LL_DEBUG1, "Got op %s (%d)\n", OpStrings[op][0], op);
1391 
1393 
1394  /* special handling for the tag-prefix function */
1395  if ((op == OP_TAG_PREFIX) || (op == OP_TAG_PREFIX_COND))
1396  {
1397  /* A second tag-prefix command aborts */
1398  if (tag)
1399  {
1400  tag = false;
1402  continue;
1403  }
1404 
1405  if (!ctx_mailbox(Context))
1406  {
1407  mutt_error(_("No mailbox is open"));
1408  continue;
1409  }
1410 
1411  if (Context->mailbox->msg_tagged == 0)
1412  {
1413  if (op == OP_TAG_PREFIX)
1414  mutt_error(_("No tagged messages"));
1415  else if (op == OP_TAG_PREFIX_COND)
1416  {
1418  mutt_message(_("Nothing to do"));
1419  }
1420  continue;
1421  }
1422 
1423  /* get the real command */
1424  tag = true;
1425  continue;
1426  }
1427  else if (C_AutoTag && ctx_mailbox(Context) && (Context->mailbox->msg_tagged != 0))
1428  {
1429  tag = true;
1430  }
1431 
1432  mutt_clear_error();
1433  }
1434 
1435 #ifdef USE_NNTP
1436  OptNews = false; /* for any case */
1437 #endif
1438 
1439 #ifdef USE_NOTMUCH
1440  if (Context)
1442 #endif
1443 
1444  switch (op)
1445  {
1446  /* ----------------------------------------------------------------------
1447  * movement commands
1448  */
1449 
1450  case OP_BOTTOM_PAGE:
1451  menu_bottom_page(menu);
1452  break;
1453  case OP_CURRENT_BOTTOM:
1454  menu_current_bottom(menu);
1455  break;
1456  case OP_CURRENT_MIDDLE:
1457  menu_current_middle(menu);
1458  break;
1459  case OP_CURRENT_TOP:
1460  menu_current_top(menu);
1461  break;
1462  case OP_FIRST_ENTRY:
1463  menu_first_entry(menu);
1464  break;
1465  case OP_HALF_DOWN:
1466  menu_half_down(menu);
1467  break;
1468  case OP_HALF_UP:
1469  menu_half_up(menu);
1470  break;
1471  case OP_LAST_ENTRY:
1472  menu_last_entry(menu);
1473  break;
1474  case OP_MIDDLE_PAGE:
1475  menu_middle_page(menu);
1476  break;
1477  case OP_NEXT_LINE:
1478  menu_next_line(menu);
1479  break;
1480  case OP_NEXT_PAGE:
1481  menu_next_page(menu);
1482  break;
1483  case OP_PREV_LINE:
1484  menu_prev_line(menu);
1485  break;
1486  case OP_PREV_PAGE:
1487  menu_prev_page(menu);
1488  break;
1489  case OP_TOP_PAGE:
1490  menu_top_page(menu);
1491  break;
1492 
1493 #ifdef USE_NNTP
1494  case OP_GET_PARENT:
1496  break;
1497  /* fallthrough */
1498 
1499  case OP_GET_MESSAGE:
1501  break;
1502  if (Context->mailbox->type == MUTT_NNTP)
1503  {
1504  if (op == OP_GET_MESSAGE)
1505  {
1506  buf[0] = '\0';
1507  if ((mutt_get_field(_("Enter Message-Id: "), buf, sizeof(buf),
1508  MUTT_COMP_NO_FLAGS) != 0) ||
1509  (buf[0] == '\0'))
1510  {
1511  break;
1512  }
1513  }
1514  else
1515  {
1516  if (!cur.e || STAILQ_EMPTY(&cur.e->env->references))
1517  {
1518  mutt_error(_("Article has no parent reference"));
1519  break;
1520  }
1521  mutt_str_copy(buf, STAILQ_FIRST(&cur.e->env->references)->data, sizeof(buf));
1522  }
1523  if (!Context->mailbox->id_hash)
1525  struct Email *e = mutt_hash_find(Context->mailbox->id_hash, buf);
1526  if (e)
1527  {
1528  if (e->vnum != -1)
1529  {
1530  menu->current = e->vnum;
1531  menu->redraw = REDRAW_MOTION_RESYNC;
1532  }
1533  else if (e->collapsed)
1534  {
1537  menu->current = e->vnum;
1538  menu->redraw = REDRAW_MOTION_RESYNC;
1539  }
1540  else
1541  mutt_error(_("Message is not visible in limited view"));
1542  }
1543  else
1544  {
1545  mutt_message(_("Fetching %s from server..."), buf);
1546  int rc = nntp_check_msgid(Context->mailbox, buf);
1547  if (rc == 0)
1548  {
1551  &Context->vsize);
1552  menu->current = e->vnum;
1553  menu->redraw = REDRAW_FULL;
1554  }
1555  else if (rc > 0)
1556  mutt_error(_("Article %s not found on the server"), buf);
1557  }
1558  }
1559  break;
1560 
1561  case OP_GET_CHILDREN:
1562  case OP_RECONSTRUCT_THREAD:
1563  {
1564  if (!prereq(Context, menu,
1566  {
1567  break;
1568  }
1569  if (Context->mailbox->type != MUTT_NNTP)
1570  break;
1571 
1572  if (!cur.e)
1573  break;
1574 
1575  int oldmsgcount = Context->mailbox->msg_count;
1576  int oldindex = cur.e->index;
1577  int rc = 0;
1578 
1579  if (!cur.e->env->message_id)
1580  {
1581  mutt_error(_("No Message-Id. Unable to perform operation."));
1582  break;
1583  }
1584 
1585  mutt_message(_("Fetching message headers..."));
1586  if (!Context->mailbox->id_hash)
1588  mutt_str_copy(buf, cur.e->env->message_id, sizeof(buf));
1589 
1590  /* trying to find msgid of the root message */
1591  if (op == OP_RECONSTRUCT_THREAD)
1592  {
1593  struct ListNode *ref = NULL;
1594  STAILQ_FOREACH(ref, &cur.e->env->references, entries)
1595  {
1596  if (!mutt_hash_find(Context->mailbox->id_hash, ref->data))
1597  {
1598  rc = nntp_check_msgid(Context->mailbox, ref->data);
1599  if (rc < 0)
1600  break;
1601  }
1602 
1603  /* the last msgid in References is the root message */
1604  if (!STAILQ_NEXT(ref, entries))
1605  mutt_str_copy(buf, ref->data, sizeof(buf));
1606  }
1607  }
1608 
1609  /* fetching all child messages */
1610  if (rc >= 0)
1611  rc = nntp_check_children(Context->mailbox, buf);
1612 
1613  /* at least one message has been loaded */
1614  if (Context->mailbox->msg_count > oldmsgcount)
1615  {
1616  struct Email *e_oldcur = mutt_get_virt_email(Context->mailbox, menu->current);
1617  bool verbose = Context->mailbox->verbose;
1618 
1619  if (rc < 0)
1620  Context->mailbox->verbose = false;
1622  (op == OP_RECONSTRUCT_THREAD), &Context->vsize);
1623  Context->mailbox->verbose = verbose;
1624 
1625  /* Similar to OP_MAIN_ENTIRE_THREAD, keep displaying the old message, but
1626  * update the index */
1627  if (in_pager)
1628  {
1629  menu->current = e_oldcur->vnum;
1630  menu->redraw = REDRAW_STATUS | REDRAW_INDEX;
1631  op = OP_DISPLAY_MESSAGE;
1632  continue;
1633  }
1634 
1635  /* if the root message was retrieved, move to it */
1636  struct Email *e = mutt_hash_find(Context->mailbox->id_hash, buf);
1637  if (e)
1638  menu->current = e->vnum;
1639  else
1640  {
1641  /* try to restore old position */
1642  for (int i = 0; i < Context->mailbox->msg_count; i++)
1643  {
1644  e = Context->mailbox->emails[i];
1645  if (!e)
1646  break;
1647  if (e->index == oldindex)
1648  {
1649  menu->current = e->vnum;
1650  /* as an added courtesy, recenter the menu
1651  * with the current entry at the middle of the screen */
1652  menu_check_recenter(menu);
1653  menu_current_middle(menu);
1654  }
1655  }
1656  }
1657  menu->redraw = REDRAW_FULL;
1658  }
1659  else if (rc >= 0)
1660  {
1661  mutt_error(_("No deleted messages found in the thread"));
1662  /* Similar to OP_MAIN_ENTIRE_THREAD, keep displaying the old message, but
1663  * update the index */
1664  if (in_pager)
1665  {
1666  op = OP_DISPLAY_MESSAGE;
1667  continue;
1668  }
1669  }
1670  break;
1671  }
1672 #endif
1673 
1674  case OP_JUMP:
1675  {
1676  int msg_num = 0;
1677  if (!prereq(Context, menu, CHECK_IN_MAILBOX))
1678  break;
1679  if (isdigit(LastKey))
1681  buf[0] = '\0';
1682  if ((mutt_get_field(_("Jump to message: "), buf, sizeof(buf), MUTT_COMP_NO_FLAGS) != 0) ||
1683  (buf[0] == '\0'))
1684  {
1685  mutt_error(_("Nothing to do"));
1686  }
1687  else if (mutt_str_atoi(buf, &msg_num) < 0)
1688  mutt_error(_("Argument must be a message number"));
1689  else if ((msg_num < 1) || (msg_num > Context->mailbox->msg_count))
1690  mutt_error(_("Invalid message number"));
1691  else if (!Context->mailbox->emails[msg_num - 1]->visible)
1692  mutt_error(_("That message is not visible"));
1693  else
1694  {
1695  struct Email *e = Context->mailbox->emails[msg_num - 1];
1696 
1698  {
1701  }
1702  menu->current = e->vnum;
1703  }
1704 
1705  if (in_pager)
1706  {
1707  op = OP_DISPLAY_MESSAGE;
1708  continue;
1709  }
1710  else
1711  menu->redraw = REDRAW_FULL;
1712 
1713  break;
1714  }
1715 
1716  /* --------------------------------------------------------------------
1717  * 'index' specific commands
1718  */
1719 
1720  case OP_MAIN_DELETE_PATTERN:
1722  {
1723  break;
1724  }
1725  /* L10N: CHECK_ACL */
1726  /* L10N: Due to the implementation details we do not know whether we
1727  delete zero, 1, 12, ... messages. So in English we use
1728  "messages". Your language might have other means to express this. */
1729  if (!check_acl(Context->mailbox, MUTT_ACL_DELETE, _("Can't delete messages")))
1730  break;
1731 
1732  mutt_pattern_func(MUTT_DELETE, _("Delete messages matching: "));
1733  menu->redraw |= REDRAW_INDEX | REDRAW_STATUS;
1734  break;
1735 
1736 #ifdef USE_POP
1737  case OP_MAIN_FETCH_MAIL:
1738  if (!prereq(Context, menu, CHECK_ATTACH))
1739  break;
1740  pop_fetch_mail();
1741  menu->redraw = REDRAW_FULL;
1742  break;
1743 #endif /* USE_POP */
1744 
1745  case OP_SHOW_LOG_MESSAGES:
1746  {
1747 #ifdef USE_DEBUG_GRAPHVIZ
1748  dump_graphviz("index");
1749 #endif
1750  char tempfile[PATH_MAX];
1751  mutt_mktemp(tempfile, sizeof(tempfile));
1752 
1753  FILE *fp = mutt_file_fopen(tempfile, "a+");
1754  if (!fp)
1755  {
1756  mutt_perror("fopen");
1757  break;
1758  }
1759 
1760  log_queue_save(fp);
1761  mutt_file_fclose(&fp);
1762 
1763  mutt_do_pager("messages", tempfile, MUTT_PAGER_LOGS, NULL);
1764  break;
1765  }
1766 
1767  case OP_HELP:
1768  mutt_help(MENU_MAIN, dlg->state.cols);
1769  menu->redraw = REDRAW_FULL;
1770  break;
1771 
1772  case OP_MAIN_SHOW_LIMIT:
1773  if (!prereq(Context, menu, CHECK_IN_MAILBOX))
1774  break;
1775  if (!ctx_has_limit(Context))
1776  mutt_message(_("No limit pattern is in effect"));
1777  else
1778  {
1779  char buf2[256];
1780  /* L10N: ask for a limit to apply */
1781  snprintf(buf2, sizeof(buf2), _("Limit: %s"), Context->pattern);
1782  mutt_message("%s", buf2);
1783  }
1784  break;
1785 
1786  case OP_LIMIT_CURRENT_THREAD:
1787  case OP_MAIN_LIMIT:
1788  case OP_TOGGLE_READ:
1789  {
1790  if (!prereq(Context, menu, CHECK_IN_MAILBOX))
1791  break;
1792  const bool lmt = ctx_has_limit(Context);
1793  menu->oldcurrent = cur.e ? cur.e->index : -1;
1794  if (op == OP_TOGGLE_READ)
1795  {
1796  char buf2[1024];
1797 
1798  if (!lmt || !mutt_strn_equal(Context->pattern, "!~R!~D~s", 8))
1799  {
1800  snprintf(buf2, sizeof(buf2), "!~R!~D~s%s", lmt ? Context->pattern : ".*");
1801  }
1802  else
1803  {
1804  mutt_str_copy(buf2, Context->pattern + 8, sizeof(buf2));
1805  if ((*buf2 == '\0') || mutt_strn_equal(buf2, ".*", 2))
1806  snprintf(buf2, sizeof(buf2), "~A");
1807  }
1808  mutt_str_replace(&Context->pattern, buf2);
1810  }
1811 
1812  if (((op == OP_LIMIT_CURRENT_THREAD) && mutt_limit_current_thread(cur.e)) ||
1813  (op == OP_TOGGLE_READ) ||
1814  ((op == OP_MAIN_LIMIT) &&
1816  _("Limit to messages matching: ")) == 0)))
1817  {
1818  if (menu->oldcurrent >= 0)
1819  {
1820  /* try to find what used to be the current message */
1821  menu->current = -1;
1822  for (size_t i = 0; i < Context->mailbox->vcount; i++)
1823  {
1824  struct Email *e = mutt_get_virt_email(Context->mailbox, i);
1825  if (!e)
1826  continue;
1827  if (e->index == menu->oldcurrent)
1828  {
1829  menu->current = i;
1830  break;
1831  }
1832  }
1833  if (menu->current < 0)
1834  menu->current = 0;
1835  }
1836  else
1837  menu->current = 0;
1838  if ((Context->mailbox->msg_count != 0) && ((C_Sort & SORT_MASK) == SORT_THREADS))
1839  {
1840  if (C_CollapseAll)
1841  collapse_all(Context, menu, 0);
1843  }
1844  menu->redraw = REDRAW_FULL;
1845  }
1846  if (lmt)
1847  mutt_message(_("To view all messages, limit to \"all\""));
1848  break;
1849  }
1850 
1851  case OP_QUIT:
1852  close = op;
1853  if (attach_msg)
1854  {
1855  done = true;
1856  break;
1857  }
1858 
1859  if (query_quadoption(C_Quit, _("Quit NeoMutt?")) == MUTT_YES)
1860  {
1861  int check;
1862 
1863  oldcount = ctx_mailbox(Context) ? Context->mailbox->msg_count : 0;
1864 
1867 
1868  if (!Context || ((check = mx_mbox_close(&Context)) == 0))
1869  {
1870  done = true;
1871  }
1872  else
1873  {
1874  if ((check == MUTT_NEW_MAIL) || (check == MUTT_REOPENED))
1875  update_index(menu, Context, check, oldcount, &cur);
1876 
1877  menu->redraw = REDRAW_FULL; /* new mail arrived? */
1878  OptSearchInvalid = true;
1879  }
1880  }
1881  break;
1882 
1883  case OP_REDRAW:
1884  mutt_window_reflow(NULL);
1885  clearok(stdscr, true);
1886  menu->redraw = REDRAW_FULL;
1887  break;
1888 
1889  // Initiating a search can happen on an empty mailbox, but
1890  // searching for next/previous/... needs to be on a message and
1891  // thus a non-empty mailbox
1892  case OP_SEARCH_REVERSE:
1893  case OP_SEARCH_NEXT:
1894  case OP_SEARCH_OPPOSITE:
1896  break;
1897  /* fallthrough */
1898  case OP_SEARCH:
1899  if (!prereq(Context, menu, CHECK_IN_MAILBOX))
1900  break;
1901  menu->current = mutt_search_command(Context->mailbox, menu->current, op);
1902  if (menu->current == -1)
1903  menu->current = menu->oldcurrent;
1904  else
1905  menu->redraw |= REDRAW_MOTION;
1906  break;
1907 
1908  case OP_SORT:
1909  case OP_SORT_REVERSE:
1910  if (mutt_select_sort((op == OP_SORT_REVERSE)) != 0)
1911  break;
1912 
1913  if (ctx_mailbox(Context) && (Context->mailbox->msg_count != 0))
1914  {
1915  resort_index(Context, menu);
1916  OptSearchInvalid = true;
1917  }
1918  if (in_pager)
1919  {
1920  op = OP_DISPLAY_MESSAGE;
1921  continue;
1922  }
1923  menu->redraw |= REDRAW_STATUS;
1924  break;
1925 
1926  case OP_TAG:
1927  {
1929  break;
1930  if (tag && !C_AutoTag)
1931  {
1932  struct Mailbox *m = Context->mailbox;
1933  for (size_t i = 0; i < m->msg_count; i++)
1934  {
1935  struct Email *e = m->emails[i];
1936  if (!e)
1937  break;
1938  if (e->visible)
1939  mutt_set_flag(m, e, MUTT_TAG, false);
1940  }
1941  menu->redraw |= REDRAW_STATUS | REDRAW_INDEX;
1942  }
1943  else
1944  {
1945  if (!cur.e)
1946  break;
1947  mutt_set_flag(Context->mailbox, cur.e, MUTT_TAG, !cur.e->tagged);
1948 
1949  menu->redraw |= REDRAW_STATUS;
1950  if (C_Resolve && (menu->current < Context->mailbox->vcount - 1))
1951  {
1952  menu->current++;
1953  menu->redraw |= REDRAW_MOTION_RESYNC;
1954  }
1955  else
1956  menu->redraw |= REDRAW_CURRENT;
1957  }
1958  break;
1959  }
1960 
1961  case OP_MAIN_TAG_PATTERN:
1962  if (!prereq(Context, menu, CHECK_IN_MAILBOX))
1963  break;
1964  mutt_pattern_func(MUTT_TAG, _("Tag messages matching: "));
1965  menu->redraw |= REDRAW_INDEX | REDRAW_STATUS;
1966  break;
1967 
1968  case OP_MAIN_UNDELETE_PATTERN:
1970  break;
1971  /* L10N: CHECK_ACL */
1972  /* L10N: Due to the implementation details we do not know whether we
1973  undelete zero, 1, 12, ... messages. So in English we use
1974  "messages". Your language might have other means to express this. */
1975  if (!check_acl(Context->mailbox, MUTT_ACL_DELETE, _("Can't undelete messages")))
1976  break;
1977 
1979  _("Undelete messages matching: ")) == 0)
1980  {
1981  menu->redraw |= REDRAW_INDEX | REDRAW_STATUS;
1982  }
1983  break;
1984 
1985  case OP_MAIN_UNTAG_PATTERN:
1986  if (!prereq(Context, menu, CHECK_IN_MAILBOX))
1987  break;
1988  if (mutt_pattern_func(MUTT_UNTAG, _("Untag messages matching: ")) == 0)
1989  menu->redraw |= REDRAW_INDEX | REDRAW_STATUS;
1990  break;
1991 
1992  case OP_COMPOSE_TO_SENDER:
1993  {
1995  break;
1996  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
1997  el_add_tagged(&el, Context, cur.e, tag);
1998  mutt_send_message(SEND_TO_SENDER, NULL, NULL, Context, &el, NeoMutt->sub);
1999  emaillist_clear(&el);
2000  menu->redraw = REDRAW_FULL;
2001  break;
2002  }
2003 
2004  /* --------------------------------------------------------------------
2005  * The following operations can be performed inside of the pager.
2006  */
2007 
2008 #ifdef USE_IMAP
2009  case OP_MAIN_IMAP_FETCH:
2012  break;
2013 
2014  case OP_MAIN_IMAP_LOGOUT_ALL:
2016  {
2017  int check = mx_mbox_close(&Context);
2018  if (check != 0)
2019  {
2020  if ((check == MUTT_NEW_MAIL) || (check == MUTT_REOPENED))
2021  update_index(menu, Context, check, oldcount, &cur);
2022  OptSearchInvalid = true;
2023  menu->redraw = REDRAW_FULL;
2024  break;
2025  }
2026  }
2027  imap_logout_all();
2028  mutt_message(_("Logged out of IMAP servers"));
2029  OptSearchInvalid = true;
2030  menu->redraw = REDRAW_FULL;
2031  break;
2032 #endif
2033 
2034  case OP_MAIN_SYNC_FOLDER:
2035  if (!ctx_mailbox(Context) || (Context->mailbox->msg_count == 0))
2036  break;
2037 
2039  break;
2040  {
2041  int ovc = Context->mailbox->vcount;
2042  int oc = Context->mailbox->msg_count;
2043  struct Email *e = NULL;
2044 
2045  /* don't attempt to move the cursor if there are no visible messages in the current limit */
2046  if (menu->current < Context->mailbox->vcount)
2047  {
2048  /* threads may be reordered, so figure out what header the cursor
2049  * should be on. */
2050  int newidx = menu->current;
2051  if (!cur.e)
2052  break;
2053  if (cur.e->deleted)
2054  newidx = ci_next_undeleted(Context->mailbox, menu->current);
2055  if (newidx < 0)
2056  newidx = ci_previous_undeleted(Context->mailbox, menu->current);
2057  if (newidx >= 0)
2058  e = mutt_get_virt_email(Context->mailbox, newidx);
2059  }
2060 
2061  int check = mx_mbox_sync(Context->mailbox);
2062  if (check == 0)
2063  {
2064  if (e && (Context->mailbox->vcount != ovc))
2065  {
2066  for (size_t i = 0; i < Context->mailbox->vcount; i++)
2067  {
2068  struct Email *e2 = mutt_get_virt_email(Context->mailbox, i);
2069  if (e2 == e)
2070  {
2071  menu->current = i;
2072  break;
2073  }
2074  }
2075  }
2076  OptSearchInvalid = true;
2077  }
2078  else if ((check == MUTT_NEW_MAIL) || (check == MUTT_REOPENED))
2079  update_index(menu, Context, check, oc, &cur);
2080 
2081  /* do a sanity check even if mx_mbox_sync failed. */
2082 
2083  if ((menu->current < 0) ||
2084  (ctx_mailbox(Context) && (menu->current >= Context->mailbox->vcount)))
2085  {
2087  }
2088  }
2089 
2090  /* check for a fatal error, or all messages deleted */
2092  ctx_free(&Context);
2093 
2094  /* if we were in the pager, redisplay the message */
2095  if (in_pager)
2096  {
2097  op = OP_DISPLAY_MESSAGE;
2098  continue;
2099  }
2100  else
2101  menu->redraw = REDRAW_FULL;
2102  break;
2103 
2104  case OP_MAIN_QUASI_DELETE:
2106  break;
2107  if (tag)
2108  {
2109  struct Mailbox *m = Context->mailbox;
2110  for (size_t i = 0; i < m->msg_count; i++)
2111  {
2112  struct Email *e = m->emails[i];
2113  if (!e)
2114  break;
2115  if (message_is_tagged(Context, e))
2116  {
2117  e->quasi_deleted = true;
2118  m->changed = true;
2119  }
2120  }
2121  }
2122  else
2123  {
2124  if (!cur.e)
2125  break;
2126  cur.e->quasi_deleted = true;
2127  Context->mailbox->changed = true;
2128  }
2129  break;
2130 
2131 #ifdef USE_NOTMUCH
2132  case OP_MAIN_ENTIRE_THREAD:
2133  {
2135  break;
2136  if (Context->mailbox->type != MUTT_NOTMUCH)
2137  {
2138  if (((Context->mailbox->type != MUTT_MH) && (Context->mailbox->type != MUTT_MAILDIR)) ||
2139  (!cur.e || !cur.e->env || !cur.e->env->message_id))
2140  {
2141  mutt_message(_("No virtual folder and no Message-Id, aborting"));
2142  break;
2143  } // no virtual folder, but we have message-id, reconstruct thread on-the-fly
2144  strncpy(buf, "id:", sizeof(buf));
2145  int msg_id_offset = 0;
2146  if ((cur.e->env->message_id)[0] == '<')
2147  msg_id_offset = 1;
2148  mutt_str_cat(buf, sizeof(buf), (cur.e->env->message_id) + msg_id_offset);
2149  if (buf[strlen(buf) - 1] == '>')
2150  buf[strlen(buf) - 1] = '\0';
2151 
2152  change_folder_notmuch(menu, buf, sizeof(buf), &oldcount, &cur, false);
2153 
2154  // If notmuch doesn't contain the message, we're left in an empty
2155  // vfolder. No messages are found, but nm_read_entire_thread assumes
2156  // a valid message-id and will throw a segfault.
2157  //
2158  // To prevent that, stay in the empty vfolder and print an error.
2159  if (Context->mailbox->msg_count == 0)
2160  {
2161  mutt_error(_("failed to find message in notmuch database. try "
2162  "running 'notmuch new'."));
2163  break;
2164  }
2165  }
2166  oldcount = Context->mailbox->msg_count;
2167  struct Email *e_oldcur = mutt_get_virt_email(Context->mailbox, menu->current);
2168  if (nm_read_entire_thread(Context->mailbox, e_oldcur) < 0)
2169  {
2170  mutt_message(_("Failed to read thread, aborting"));
2171  break;
2172  }
2173  if (oldcount < Context->mailbox->msg_count)
2174  {
2175  /* nm_read_entire_thread() triggers mutt_sort_headers() if necessary */
2176  menu->current = e_oldcur->vnum;
2177  menu->redraw = REDRAW_STATUS | REDRAW_INDEX;
2178 
2179  if (e_oldcur->collapsed || Context->collapsed)
2180  {
2181  menu->current = mutt_uncollapse_thread(e_oldcur);
2183  }
2184  }
2185  if (in_pager)
2186  {
2187  op = OP_DISPLAY_MESSAGE;
2188  continue;
2189  }
2190  break;
2191  }
2192 #endif
2193 
2194  case OP_MAIN_MODIFY_TAGS:
2195  case OP_MAIN_MODIFY_TAGS_THEN_HIDE:
2196  {
2197  if (!ctx_mailbox(Context))
2198  break;
2199  struct Mailbox *m = Context->mailbox;
2200  if (!mx_tags_is_supported(m))
2201  {
2202  mutt_message(_("Folder doesn't support tagging, aborting"));
2203  break;
2204  }
2206  break;
2207  if (!cur.e)
2208  break;
2209  char *tags = NULL;
2210  if (!tag)
2211  tags = driver_tags_get_with_hidden(&cur.e->tags);
2212  int rc = mx_tags_edit(m, tags, buf, sizeof(buf));
2213  FREE(&tags);
2214  if (rc < 0)
2215  break;
2216  else if (rc == 0)
2217  {
2218  mutt_message(_("No tag specified, aborting"));
2219  break;
2220  }
2221 
2222  if (tag)
2223  {
2224  struct Progress progress;
2225 
2226  if (m->verbose)
2227  {
2228  mutt_progress_init(&progress, _("Update tags..."),
2230  }
2231 
2232 #ifdef USE_NOTMUCH
2233  if (m->type == MUTT_NOTMUCH)
2234  nm_db_longrun_init(m, true);
2235 #endif
2236  for (int px = 0, i = 0; i < m->msg_count; i++)
2237  {
2238  struct Email *e = m->emails[i];
2239  if (!e)
2240  break;
2241  if (!message_is_tagged(Context, e))
2242  continue;
2243 
2244  if (m->verbose)
2245  mutt_progress_update(&progress, ++px, -1);
2246  mx_tags_commit(m, e, buf);
2247  if (op == OP_MAIN_MODIFY_TAGS_THEN_HIDE)
2248  {
2249  bool still_queried = false;
2250 #ifdef USE_NOTMUCH
2251  if (m->type == MUTT_NOTMUCH)
2252  still_queried = nm_message_is_still_queried(m, e);
2253 #endif
2254  e->quasi_deleted = !still_queried;
2255  m->changed = true;
2256  }
2257  }
2258 #ifdef USE_NOTMUCH
2259  if (m->type == MUTT_NOTMUCH)
2260  nm_db_longrun_done(m);
2261 #endif
2262  menu->redraw = REDRAW_STATUS | REDRAW_INDEX;
2263  }
2264  else
2265  {
2266  if (mx_tags_commit(m, cur.e, buf))
2267  {
2268  mutt_message(_("Failed to modify tags, aborting"));
2269  break;
2270  }
2271  if (op == OP_MAIN_MODIFY_TAGS_THEN_HIDE)
2272  {
2273  bool still_queried = false;
2274 #ifdef USE_NOTMUCH
2275  if (m->type == MUTT_NOTMUCH)
2276  still_queried = nm_message_is_still_queried(m, cur.e);
2277 #endif
2278  cur.e->quasi_deleted = !still_queried;
2279  m->changed = true;
2280  }
2281  if (in_pager)
2282  {
2283  op = OP_DISPLAY_MESSAGE;
2284  continue;
2285  }
2286  if (C_Resolve)
2287  {
2288  menu->current = ci_next_undeleted(Context->mailbox, menu->current);
2289  if (menu->current == -1)
2290  {
2291  menu->current = menu->oldcurrent;
2292  menu->redraw = REDRAW_CURRENT;
2293  }
2294  else
2295  menu->redraw = REDRAW_MOTION_RESYNC;
2296  }
2297  else
2298  menu->redraw = REDRAW_CURRENT;
2299  }
2300  menu->redraw |= REDRAW_STATUS;
2301  break;
2302  }
2303 
2304  case OP_CHECK_STATS:
2305  mutt_check_stats();
2306  break;
2307 
2308 #ifdef USE_NOTMUCH
2309  case OP_MAIN_VFOLDER_FROM_QUERY:
2310  case OP_MAIN_VFOLDER_FROM_QUERY_READONLY:
2311  {
2312  buf[0] = '\0';
2313  if ((mutt_get_field("Query: ", buf, sizeof(buf), MUTT_NM_QUERY) != 0) ||
2314  (buf[0] == '\0'))
2315  {
2316  mutt_message(_("No query, aborting"));
2317  break;
2318  }
2319 
2320  // Keep copy of user's query to name the mailbox
2321  char *query_unencoded = mutt_str_dup(buf);
2322 
2323  struct Mailbox *m_query =
2324  change_folder_notmuch(menu, buf, sizeof(buf), &oldcount, &cur,
2325  (op == OP_MAIN_VFOLDER_FROM_QUERY_READONLY));
2326  if (m_query)
2327  {
2328  m_query->name = query_unencoded;
2329  query_unencoded = NULL;
2330  }
2331  else
2332  {
2333  FREE(&query_unencoded);
2334  }
2335 
2336  break;
2337  }
2338 
2339  case OP_MAIN_WINDOWED_VFOLDER_BACKWARD:
2340  {
2341  if (!prereq(Context, menu, CHECK_IN_MAILBOX))
2342  break;
2343  if (C_NmQueryWindowDuration <= 0)
2344  {
2345  mutt_message(_("Windowed queries disabled"));
2346  break;
2347  }
2349  {
2350  mutt_message(_("No notmuch vfolder currently loaded"));
2351  break;
2352  }
2354  mutt_str_copy(buf, C_NmQueryWindowCurrentSearch, sizeof(buf));
2355  change_folder_notmuch(menu, buf, sizeof(buf), &oldcount, &cur, false);
2356  break;
2357  }
2358 
2359  case OP_MAIN_WINDOWED_VFOLDER_FORWARD:
2360  {
2361  if (!prereq(Context, menu, CHECK_IN_MAILBOX))
2362  break;
2363  if (C_NmQueryWindowDuration <= 0)
2364  {
2365  mutt_message(_("Windowed queries disabled"));
2366  break;
2367  }
2369  {
2370  mutt_message(_("No notmuch vfolder currently loaded"));
2371  break;
2372  }
2374  mutt_str_copy(buf, C_NmQueryWindowCurrentSearch, sizeof(buf));
2375  change_folder_notmuch(menu, buf, sizeof(buf), &oldcount, &cur, false);
2376  break;
2377  }
2378 #endif
2379 
2380 #ifdef USE_SIDEBAR
2381  case OP_SIDEBAR_OPEN:
2382  {
2383  struct MuttWindow *win_sidebar = mutt_window_find(dlg, WT_SIDEBAR);
2384  change_folder_mailbox(menu, sb_get_highlight(win_sidebar), &oldcount, &cur, false);
2385  break;
2386  }
2387 #endif
2388 
2389  case OP_MAIN_NEXT_UNREAD_MAILBOX:
2390  {
2391  if (!prereq(Context, menu, CHECK_IN_MAILBOX))
2392  break;
2393 
2394  struct Mailbox *m = Context->mailbox;
2395 
2396  struct Buffer *folderbuf = mutt_buffer_pool_get();
2397  mutt_buffer_strcpy(folderbuf, mailbox_path(m));
2398  m = mutt_mailbox_next(m, folderbuf);
2399  mutt_buffer_pool_release(&folderbuf);
2400 
2401  if (!m)
2402  {
2403  mutt_error(_("No mailboxes have new mail"));
2404  break;
2405  }
2406 
2407  change_folder_mailbox(menu, m, &oldcount, &cur, false);
2408  break;
2409  }
2410 
2411  case OP_MAIN_CHANGE_FOLDER:
2412  case OP_MAIN_CHANGE_FOLDER_READONLY:
2413 #ifdef USE_NOTMUCH
2414  case OP_MAIN_CHANGE_VFOLDER: // now an alias for OP_MAIN_CHANGE_FOLDER
2415 #endif
2416  {
2417  bool pager_return = true; /* return to display message in pager */
2418  struct Buffer *folderbuf = mutt_buffer_pool_get();
2419  mutt_buffer_alloc(folderbuf, PATH_MAX);
2420 
2421  char *cp = NULL;
2422  bool read_only;
2423  if (attach_msg || C_ReadOnly || (op == OP_MAIN_CHANGE_FOLDER_READONLY))
2424  {
2425  cp = _("Open mailbox in read-only mode");
2426  read_only = true;
2427  }
2428  else
2429  {
2430  cp = _("Open mailbox");
2431  read_only = false;
2432  }
2433 
2436  {
2438  mutt_buffer_pretty_mailbox(folderbuf);
2439  }
2440  /* By default, fill buf with the next mailbox that contains unread mail */
2441  mutt_mailbox_next(Context ? Context->mailbox : NULL, folderbuf);
2442 
2443  if (mutt_buffer_enter_fname(cp, folderbuf, true) == -1)
2444  goto changefoldercleanup;
2445 
2446  /* Selected directory is okay, let's save it. */
2448 
2449  if (mutt_buffer_is_empty(folderbuf))
2450  {
2452  goto changefoldercleanup;
2453  }
2454 
2455  struct Mailbox *m = mx_mbox_find2(mutt_buffer_string(folderbuf));
2456  if (m)
2457  {
2458  change_folder_mailbox(menu, m, &oldcount, &cur, read_only);
2459  pager_return = false;
2460  }
2461  else
2462  {
2463  change_folder_string(menu, folderbuf->data, folderbuf->dsize,
2464  &oldcount, &cur, &pager_return, read_only);
2465  }
2466 
2467  changefoldercleanup:
2468  mutt_buffer_pool_release(&folderbuf);
2469  if (in_pager && pager_return)
2470  {
2471  op = OP_DISPLAY_MESSAGE;
2472  continue;
2473  }
2474  break;
2475  }
2476 
2477 #ifdef USE_NNTP
2478  case OP_MAIN_CHANGE_GROUP:
2479  case OP_MAIN_CHANGE_GROUP_READONLY:
2480  {
2481  bool pager_return = true; /* return to display message in pager */
2482  struct Buffer *folderbuf = mutt_buffer_pool_get();
2483  mutt_buffer_alloc(folderbuf, PATH_MAX);
2484 
2485  OptNews = false;
2486  bool read_only;
2487  char *cp = NULL;
2488  if (attach_msg || C_ReadOnly || (op == OP_MAIN_CHANGE_GROUP_READONLY))
2489  {
2490  cp = _("Open newsgroup in read-only mode");
2491  read_only = true;
2492  }
2493  else
2494  {
2495  cp = _("Open newsgroup");
2496  read_only = false;
2497  }
2498 
2501  {
2503  mutt_buffer_pretty_mailbox(folderbuf);
2504  }
2505 
2506  OptNews = true;
2507  CurrentNewsSrv =
2509  if (!CurrentNewsSrv)
2510  goto changefoldercleanup2;
2511 
2512  nntp_mailbox(Context ? Context->mailbox : NULL, folderbuf->data,
2513  folderbuf->dsize);
2514 
2515  if (mutt_buffer_enter_fname(cp, folderbuf, true) == -1)
2516  goto changefoldercleanup2;
2517 
2518  /* Selected directory is okay, let's save it. */
2520 
2521  if (mutt_buffer_is_empty(folderbuf))
2522  {
2524  goto changefoldercleanup2;
2525  }
2526 
2527  struct Mailbox *m = mx_mbox_find2(mutt_buffer_string(folderbuf));
2528  if (m)
2529  {
2530  change_folder_mailbox(menu, m, &oldcount, &cur, read_only);
2531  pager_return = false;
2532  }
2533  else
2534  {
2535  change_folder_string(menu, folderbuf->data, folderbuf->dsize,
2536  &oldcount, &cur, &pager_return, read_only);
2537  }
2538  dlg->help_data = IndexNewsHelp;
2539 
2540  changefoldercleanup2:
2541  mutt_buffer_pool_release(&folderbuf);
2542  if (in_pager && pager_return)
2543  {
2544  op = OP_DISPLAY_MESSAGE;
2545  continue;
2546  }
2547  break;
2548  }
2549 #endif
2550 
2551  case OP_DISPLAY_MESSAGE:
2552  case OP_DISPLAY_HEADERS: /* don't weed the headers */
2553  {
2555  break;
2556  if (!cur.e)
2557  break;
2558  /* toggle the weeding of headers so that a user can press the key
2559  * again while reading the message. */
2560  if (op == OP_DISPLAY_HEADERS)
2561  bool_str_toggle(NeoMutt->sub, "weed", NULL);
2562 
2563  OptNeedResort = false;
2564 
2565  if (((C_Sort & SORT_MASK) == SORT_THREADS) && cur.e->collapsed)
2566  {
2569  if (C_UncollapseJump)
2570  menu->current = mutt_thread_next_unread(cur.e);
2571  }
2572 
2573  if (C_PgpAutoDecode && (tag || !(cur.e->security & PGP_TRADITIONAL_CHECKED)))
2574  {
2575  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
2576  el_add_tagged(&el, Context, cur.e, tag);
2577  mutt_check_traditional_pgp(&el, &menu->redraw);
2578  emaillist_clear(&el);
2579  }
2581 
2582  op = mutt_display_message(win_index, win_ibar, win_pager, win_pbar,
2583  Context->mailbox, cur.e);
2584  window_set_focus(win_index);
2585  if (op < 0)
2586  {
2587  OptNeedResort = false;
2588  break;
2589  }
2590 
2591  /* This is used to redirect a single operation back here afterwards. If
2592  * mutt_display_message() returns 0, then this flag and pager state will
2593  * be cleaned up after this switch statement. */
2594  in_pager = true;
2595  menu->oldcurrent = menu->current;
2596  if (ctx_mailbox(Context))
2598  continue;
2599  }
2600 
2601  case OP_EXIT:
2602  close = op;
2603  if ((!in_pager) && attach_msg)
2604  {
2605  done = true;
2606  break;
2607  }
2608 
2609  if ((!in_pager) &&
2610  (query_quadoption(C_Quit, _("Exit NeoMutt without saving?")) == MUTT_YES))
2611  {
2612  if (Context)
2613  {
2615  ctx_free(&Context);
2616  }
2617  done = true;
2618  }
2619  break;
2620 
2621  case OP_MAIN_BREAK_THREAD:
2622  {
2624  break;
2625  /* L10N: CHECK_ACL */
2626  if (!check_acl(Context->mailbox, MUTT_ACL_WRITE, _("Can't break thread")))
2627  break;
2628  if (!cur.e)
2629  break;
2630 
2631  if ((C_Sort & SORT_MASK) != SORT_THREADS)
2632  mutt_error(_("Threading is not enabled"));
2633  else if (!STAILQ_EMPTY(&cur.e->env->in_reply_to) ||
2634  !STAILQ_EMPTY(&cur.e->env->references))
2635  {
2636  {
2637  mutt_break_thread(cur.e);
2639  menu->current = cur.e->vnum;
2640  }
2641 
2642  Context->mailbox->changed = true;
2643  mutt_message(_("Thread broken"));
2644 
2645  if (in_pager)
2646  {
2647  op = OP_DISPLAY_MESSAGE;
2648  continue;
2649  }
2650  else
2651  menu->redraw |= REDRAW_INDEX;
2652  }
2653  else
2654  {
2655  mutt_error(
2656  _("Thread can't be broken, message is not part of a thread"));
2657  }
2658  break;
2659  }
2660 
2661  case OP_MAIN_LINK_THREADS:
2662  {
2664  break;
2665  /* L10N: CHECK_ACL */
2666  if (!check_acl(Context->mailbox, MUTT_ACL_WRITE, _("Can't link threads")))
2667  break;
2668  if (!cur.e)
2669  break;
2670 
2671  if ((C_Sort & SORT_MASK) != SORT_THREADS)
2672  mutt_error(_("Threading is not enabled"));
2673  else if (!cur.e->env->message_id)
2674  mutt_error(_("No Message-ID: header available to link thread"));
2675  else
2676  {
2677  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
2678  el_add_tagged(&el, Context, NULL, true);
2679 
2680  if (mutt_link_threads(cur.e, &el, Context->mailbox))
2681  {
2683  menu->current = cur.e->vnum;
2684 
2685  Context->mailbox->changed = true;
2686  mutt_message(_("Threads linked"));
2687  }
2688  else
2689  mutt_error(_("No thread linked"));
2690 
2691  emaillist_clear(&el);
2692  }
2693 
2694  if (in_pager)
2695  {
2696  op = OP_DISPLAY_MESSAGE;
2697  continue;
2698  }
2699  else
2700  menu->redraw |= REDRAW_STATUS | REDRAW_INDEX;
2701 
2702  break;
2703  }
2704 
2705  case OP_EDIT_TYPE:
2706  {
2708  break;
2709  if (!cur.e)
2710  break;
2711  mutt_edit_content_type(cur.e, cur.e->body, NULL);
2712  /* if we were in the pager, redisplay the message */
2713  if (in_pager)
2714  {
2715  op = OP_DISPLAY_MESSAGE;
2716  continue;
2717  }
2718  else
2719  menu->redraw = REDRAW_CURRENT;
2720  break;
2721  }
2722 
2723  case OP_MAIN_NEXT_UNDELETED:
2725  break;
2726  if (menu->current >= (Context->mailbox->vcount - 1))
2727  {
2728  if (!in_pager)
2729  mutt_message(_("You are on the last message"));
2730  break;
2731  }
2732  menu->current = ci_next_undeleted(Context->mailbox, menu->current);
2733  if (menu->current == -1)
2734  {
2735  menu->current = menu->oldcurrent;
2736  if (!in_pager)
2737  mutt_error(_("No undeleted messages"));
2738  }
2739  else if (in_pager)
2740  {
2741  op = OP_DISPLAY_MESSAGE;
2742  continue;
2743  }
2744  else
2745  menu->redraw = REDRAW_MOTION;
2746  break;
2747 
2748  case OP_NEXT_ENTRY:
2750  break;
2751  if (menu->current >= (Context->mailbox->vcount - 1))
2752  {
2753  if (!in_pager)
2754  mutt_message(_("You are on the last message"));
2755  break;
2756  }
2757  menu->current++;
2758  if (in_pager)
2759  {
2760  op = OP_DISPLAY_MESSAGE;
2761  continue;
2762  }
2763  else
2764  menu->redraw = REDRAW_MOTION;
2765  break;
2766 
2767  case OP_MAIN_PREV_UNDELETED:
2769  break;
2770  if (menu->current < 1)
2771  {
2772  mutt_message(_("You are on the first message"));
2773  break;
2774  }
2776  if (menu->current == -1)
2777  {
2778  menu->current = menu->oldcurrent;
2779  if (!in_pager)
2780  mutt_error(_("No undeleted messages"));
2781  }
2782  else if (in_pager)
2783  {
2784  op = OP_DISPLAY_MESSAGE;
2785  continue;
2786  }
2787  else
2788  menu->redraw = REDRAW_MOTION;
2789  break;
2790 
2791  case OP_PREV_ENTRY:
2793  break;
2794  if (menu->current < 1)
2795  {
2796  if (!in_pager)
2797  mutt_message(_("You are on the first message"));
2798  break;
2799  }
2800  menu->current--;
2801  if (in_pager)
2802  {
2803  op = OP_DISPLAY_MESSAGE;
2804  continue;
2805  }
2806  else
2807  menu->redraw = REDRAW_MOTION;
2808  break;
2809 
2810  case OP_DECRYPT_COPY:
2811  case OP_DECRYPT_SAVE:
2812  if (!WithCrypto)
2813  break;
2814  /* fallthrough */
2815  case OP_COPY_MESSAGE:
2816  case OP_SAVE:
2817  case OP_DECODE_COPY:
2818  case OP_DECODE_SAVE:
2819  {
2821  break;
2822  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
2823  el_add_tagged(&el, Context, cur.e, tag);
2824 
2825  const bool delete_original =
2826  (op == OP_SAVE) || (op == OP_DECODE_SAVE) || (op == OP_DECRYPT_SAVE);
2827  const bool decode = (op == OP_DECODE_SAVE) || (op == OP_DECODE_COPY);
2828  const bool decrypt = (op == OP_DECRYPT_SAVE) || (op == OP_DECRYPT_COPY);
2829 
2830  if ((mutt_save_message(Context->mailbox, &el, delete_original, decode, decrypt) == 0) &&
2831  delete_original)
2832  {
2833  menu->redraw |= REDRAW_STATUS;
2834  if (tag)
2835  menu->redraw |= REDRAW_INDEX;
2836  else if (C_Resolve)
2837  {
2838  menu->current = ci_next_undeleted(Context->mailbox, menu->current);
2839  if (menu->current == -1)
2840  {
2841  menu->current = menu->oldcurrent;
2842  menu->redraw |= REDRAW_CURRENT;
2843  }
2844  else
2845  menu->redraw |= REDRAW_MOTION_RESYNC;
2846  }
2847  else
2848  menu->redraw |= REDRAW_CURRENT;
2849  }
2850  emaillist_clear(&el);
2851  break;
2852  }
2853 
2854  case OP_MAIN_NEXT_NEW:
2855  case OP_MAIN_NEXT_UNREAD:
2856  case OP_MAIN_PREV_NEW:
2857  case OP_MAIN_PREV_UNREAD:
2858  case OP_MAIN_NEXT_NEW_THEN_UNREAD:
2859  case OP_MAIN_PREV_NEW_THEN_UNREAD:
2860  {
2862  break;
2863 
2864  int first_unread = -1;
2865  int first_new = -1;
2866 
2867  const int saved_current = menu->current;
2868  int mcur = menu->current;
2869  menu->current = -1;
2870  for (size_t i = 0; i != Context->mailbox->vcount; i++)
2871  {
2872  if ((op == OP_MAIN_NEXT_NEW) || (op == OP_MAIN_NEXT_UNREAD) ||
2873  (op == OP_MAIN_NEXT_NEW_THEN_UNREAD))
2874  {
2875  mcur++;
2876  if (mcur > (Context->mailbox->vcount - 1))
2877  {
2878  mcur = 0;
2879  }
2880  }
2881  else
2882  {
2883  mcur--;
2884  if (mcur < 0)
2885  {
2886  mcur = Context->mailbox->vcount - 1;
2887  }
2888  }
2889 
2890  struct Email *e = mutt_get_virt_email(Context->mailbox, mcur);
2891  if (!e)
2892  break;
2893  if (e->collapsed && ((C_Sort & SORT_MASK) == SORT_THREADS))
2894  {
2895  int unread = mutt_thread_contains_unread(e);
2896  if ((unread != 0) && (first_unread == -1))
2897  first_unread = mcur;
2898  if ((unread == 1) && (first_new == -1))
2899  first_new = mcur;
2900  }
2901  else if (!e->deleted && !e->read)
2902  {
2903  if (first_unread == -1)
2904  first_unread = mcur;
2905  if (!e->old && (first_new == -1))
2906  first_new = mcur;
2907  }
2908 
2909  if (((op == OP_MAIN_NEXT_UNREAD) || (op == OP_MAIN_PREV_UNREAD)) &&
2910  (first_unread != -1))
2911  break;
2912  if (((op == OP_MAIN_NEXT_NEW) || (op == OP_MAIN_PREV_NEW) ||
2913  (op == OP_MAIN_NEXT_NEW_THEN_UNREAD) || (op == OP_MAIN_PREV_NEW_THEN_UNREAD)) &&
2914  (first_new != -1))
2915  {
2916  break;
2917  }
2918  }
2919  if (((op == OP_MAIN_NEXT_NEW) || (op == OP_MAIN_PREV_NEW) ||
2920  (op == OP_MAIN_NEXT_NEW_THEN_UNREAD) || (op == OP_MAIN_PREV_NEW_THEN_UNREAD)) &&
2921  (first_new != -1))
2922  {
2923  menu->current = first_new;
2924  }
2925  else if (((op == OP_MAIN_NEXT_UNREAD) || (op == OP_MAIN_PREV_UNREAD) ||
2926  (op == OP_MAIN_NEXT_NEW_THEN_UNREAD) || (op == OP_MAIN_PREV_NEW_THEN_UNREAD)) &&
2927  (first_unread != -1))
2928  {
2929  menu->current = first_unread;
2930  }
2931 
2932  if (menu->current == -1)
2933  {
2934  menu->current = menu->oldcurrent;
2935  if ((op == OP_MAIN_NEXT_NEW) || (op == OP_MAIN_PREV_NEW))
2936  {
2937  if (ctx_has_limit(Context))
2938  mutt_error(_("No new messages in this limited view"));
2939  else
2940  mutt_error(_("No new messages"));
2941  }
2942  else
2943  {
2944  if (ctx_has_limit(Context))
2945  mutt_error(_("No unread messages in this limited view"));
2946  else
2947  mutt_error(_("No unread messages"));
2948  }
2949  break;
2950  }
2951 
2952  if ((op == OP_MAIN_NEXT_NEW) || (op == OP_MAIN_NEXT_UNREAD) ||
2953  (op == OP_MAIN_NEXT_NEW_THEN_UNREAD))
2954  {
2955  if (saved_current > menu->current)
2956  {
2957  mutt_message(_("Search wrapped to top"));
2958  }
2959  }
2960  else if (saved_current < menu->current)
2961  {
2962  mutt_message(_("Search wrapped to bottom"));
2963  }
2964 
2965  if (in_pager)
2966  {
2967  op = OP_DISPLAY_MESSAGE;
2968  continue;
2969  }
2970  else
2971  menu->redraw = REDRAW_MOTION;
2972  break;
2973  }
2974  case OP_FLAG_MESSAGE:
2975  {
2977  break;
2978  /* L10N: CHECK_ACL */
2979  if (!check_acl(Context->mailbox, MUTT_ACL_WRITE, _("Can't flag message")))
2980  break;
2981 
2982  struct Mailbox *m = Context->mailbox;
2983  if (tag)
2984  {
2985  for (size_t i = 0; i < m->msg_count; i++)
2986  {
2987  struct Email *e = m->emails[i];
2988  if (!e)
2989  break;
2990  if (message_is_tagged(Context, e))
2991  mutt_set_flag(m, e, MUTT_FLAG, !e->flagged);
2992  }
2993 
2994  menu->redraw |= REDRAW_INDEX;
2995  }
2996  else
2997  {
2998  if (!cur.e)
2999  break;
3000  mutt_set_flag(m, cur.e, MUTT_FLAG, !cur.e->flagged);
3001  if (C_Resolve)
3002  {
3003  menu->current = ci_next_undeleted(Context->mailbox, menu->current);
3004  if (menu->current == -1)
3005  {
3006  menu->current = menu->oldcurrent;
3007  menu->redraw |= REDRAW_CURRENT;
3008  }
3009  else
3010  menu->redraw |= REDRAW_MOTION_RESYNC;
3011  }
3012  else
3013  menu->redraw |= REDRAW_CURRENT;
3014  }
3015  menu->redraw |= REDRAW_STATUS;
3016  break;
3017  }
3018 
3019  case OP_TOGGLE_NEW:
3020  {
3022  break;
3023  /* L10N: CHECK_ACL */
3024  if (!check_acl(Context->mailbox, MUTT_ACL_SEEN, _("Can't toggle new")))
3025  break;
3026 
3027  struct Mailbox *m = Context->mailbox;
3028  if (tag)
3029  {
3030  for (size_t i = 0; i < m->msg_count; i++)
3031  {
3032  struct Email *e = m->emails[i];
3033  if (!e)
3034  break;
3035  if (!message_is_tagged(Context, e))
3036  continue;
3037 
3038  if (e->read || e->old)
3039  mutt_set_flag(m, e, MUTT_NEW, true);
3040  else
3041  mutt_set_flag(m, e, MUTT_READ, true);
3042  }
3043  menu->redraw |= REDRAW_STATUS | REDRAW_INDEX;
3044  }
3045  else
3046  {
3047  if (!cur.e)
3048  break;
3049  if (cur.e->read || cur.e->old)
3050  mutt_set_flag(m, cur.e, MUTT_NEW, true);
3051  else
3052  mutt_set_flag(m, cur.e, MUTT_READ, true);
3053 
3054  if (C_Resolve)
3055  {
3056  menu->current = ci_next_undeleted(Context->mailbox, menu->current);
3057  if (menu->current == -1)
3058  {
3059  menu->current = menu->oldcurrent;
3060  menu->redraw |= REDRAW_CURRENT;
3061  }
3062  else
3063  menu->redraw |= REDRAW_MOTION_RESYNC;
3064  }
3065  else
3066  menu->redraw |= REDRAW_CURRENT;
3067  menu->redraw |= REDRAW_STATUS;
3068  }
3069  break;
3070  }
3071 
3072  case OP_TOGGLE_WRITE:
3073  if (!prereq(Context, menu, CHECK_IN_MAILBOX))
3074  break;
3075  if (mx_toggle_write(Context->mailbox) == 0)
3076  {
3077  if (in_pager)
3078  {
3079  op = OP_DISPLAY_MESSAGE;
3080  continue;
3081  }
3082  else
3083  menu->redraw |= REDRAW_STATUS;
3084  }
3085  break;
3086 
3087  case OP_MAIN_NEXT_THREAD:
3088  case OP_MAIN_NEXT_SUBTHREAD:
3089  case OP_MAIN_PREV_THREAD:
3090  case OP_MAIN_PREV_SUBTHREAD:
3091  {
3093  break;
3094 
3095  switch (op)
3096  {
3097  case OP_MAIN_NEXT_THREAD:
3098  menu->current = mutt_next_thread(cur.e);
3099  break;
3100 
3101  case OP_MAIN_NEXT_SUBTHREAD:
3102  menu->current = mutt_next_subthread(cur.e);
3103  break;
3104 
3105  case OP_MAIN_PREV_THREAD:
3106  menu->current = mutt_previous_thread(cur.e);
3107  break;
3108 
3109  case OP_MAIN_PREV_SUBTHREAD:
3110  menu->current = mutt_previous_subthread(cur.e);
3111  break;
3112  }
3113 
3114  if (menu->current < 0)
3115  {
3116  menu->current = menu->oldcurrent;
3117  if ((op == OP_MAIN_NEXT_THREAD) || (op == OP_MAIN_NEXT_SUBTHREAD))
3118  mutt_error(_("No more threads"));
3119  else
3120  mutt_error(_("You are on the first thread"));
3121  }
3122  else if (in_pager)
3123  {
3124  op = OP_DISPLAY_MESSAGE;
3125  continue;
3126  }
3127  else
3128  menu->redraw = REDRAW_MOTION;
3129  break;
3130  }
3131 
3132  case OP_MAIN_ROOT_MESSAGE:
3133  case OP_MAIN_PARENT_MESSAGE:
3134  {
3136  break;
3137 
3138  menu->current = mutt_parent_message(cur.e, op == OP_MAIN_ROOT_MESSAGE);
3139  if (menu->current < 0)
3140  {
3141  menu->current = menu->oldcurrent;
3142  }
3143  else if (in_pager)
3144  {
3145  op = OP_DISPLAY_MESSAGE;
3146  continue;
3147  }
3148  else
3149  menu->redraw = REDRAW_MOTION;
3150  break;
3151  }
3152 
3153  case OP_MAIN_SET_FLAG:
3154  case OP_MAIN_CLEAR_FLAG:
3155  {
3157  break;
3158  /* check_acl(MUTT_ACL_WRITE); */
3159 
3160  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3161  el_add_tagged(&el, Context, cur.e, tag);
3162 
3163  if (mutt_change_flag(Context->mailbox, &el, (op == OP_MAIN_SET_FLAG)) == 0)
3164  {
3165  menu->redraw |= REDRAW_STATUS;
3166  if (tag)
3167  menu->redraw |= REDRAW_INDEX;
3168  else if (C_Resolve)
3169  {
3170  menu->current = ci_next_undeleted(Context->mailbox, menu->current);
3171  if (menu->current == -1)
3172  {
3173  menu->current = menu->oldcurrent;
3174  menu->redraw |= REDRAW_CURRENT;
3175  }
3176  else
3177  menu->redraw |= REDRAW_MOTION_RESYNC;
3178  }
3179  else
3180  menu->redraw |= REDRAW_CURRENT;
3181  }
3182  emaillist_clear(&el);
3183  break;
3184  }
3185 
3186  case OP_MAIN_COLLAPSE_THREAD:
3187  {
3189  break;
3190 
3191  if ((C_Sort & SORT_MASK) != SORT_THREADS)
3192  {
3193  mutt_error(_("Threading is not enabled"));
3194  break;
3195  }
3196 
3197  if (!cur.e)
3198  break;
3199 
3200  if (cur.e->collapsed)
3201  {
3202  menu->current = mutt_uncollapse_thread(cur.e);
3204  if (C_UncollapseJump)
3205  menu->current = mutt_thread_next_unread(cur.e);
3206  }
3207  else if (mutt_thread_can_collapse(cur.e))
3208  {
3209  menu->current = mutt_collapse_thread(cur.e);
3211  }
3212  else
3213  {
3214  mutt_error(_("Thread contains unread or flagged messages"));
3215  break;
3216  }
3217 
3218  menu->redraw = REDRAW_INDEX | REDRAW_STATUS;
3219 
3220  break;
3221  }
3222 
3223  case OP_MAIN_COLLAPSE_ALL:
3224  if (!prereq(Context, menu, CHECK_IN_MAILBOX))
3225  break;
3226 
3227  if ((C_Sort & SORT_MASK) != SORT_THREADS)
3228  {
3229  mutt_error(_("Threading is not enabled"));
3230  break;
3231  }
3232  collapse_all(Context, menu, 1);
3233  break;
3234 
3235  /* --------------------------------------------------------------------
3236  * These functions are invoked directly from the internal-pager
3237  */
3238 
3239  case OP_BOUNCE_MESSAGE:
3240  {
3242  break;
3243  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3244  el_add_tagged(&el, Context, cur.e, tag);
3246  emaillist_clear(&el);
3247  break;
3248  }
3249 
3250  case OP_CREATE_ALIAS:
3251  {
3252  struct AddressList *al = NULL;
3253  if (cur.e && cur.e->env)
3254  al = mutt_get_address(cur.e->env, NULL);
3255  alias_create(al, NeoMutt->sub);
3256  menu->redraw |= REDRAW_CURRENT;
3257  break;
3258  }
3259 
3260  case OP_QUERY:
3261  if (!prereq(Context, menu, CHECK_ATTACH))
3262  break;
3264  break;
3265 
3266  case OP_PURGE_MESSAGE:
3267  case OP_DELETE:
3268  {
3270  break;
3271  /* L10N: CHECK_ACL */
3272  if (!check_acl(Context->mailbox, MUTT_ACL_DELETE, _("Can't delete message")))
3273  break;
3274 
3275  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3276  el_add_tagged(&el, Context, cur.e, tag);
3277 
3279  mutt_emails_set_flag(Context->mailbox, &el, MUTT_PURGE, (op == OP_PURGE_MESSAGE));
3280  if (C_DeleteUntag)
3282  emaillist_clear(&el);
3283 
3284  if (tag)
3285  {
3286  menu->redraw |= REDRAW_INDEX;
3287  }
3288  else
3289  {
3290  if (C_Resolve)
3291  {
3292  menu->current = ci_next_undeleted(Context->mailbox, menu->current);
3293  if (menu->current == -1)
3294  {
3295  menu->current = menu->oldcurrent;
3296  menu->redraw |= REDRAW_CURRENT;
3297  }
3298  else if (in_pager)
3299  {
3300  op = OP_DISPLAY_MESSAGE;
3301  continue;
3302  }
3303  else
3304  menu->redraw |= REDRAW_MOTION_RESYNC;
3305  }
3306  else
3307  menu->redraw |= REDRAW_CURRENT;
3308  }
3309  menu->redraw |= REDRAW_STATUS;
3310  break;
3311  }
3312 
3313  case OP_DELETE_THREAD:
3314  case OP_DELETE_SUBTHREAD:
3315  case OP_PURGE_THREAD:
3316  {
3318  break;
3319  /* L10N: CHECK_ACL */
3320  /* L10N: Due to the implementation details we do not know whether we
3321  delete zero, 1, 12, ... messages. So in English we use
3322  "messages". Your language might have other means to express this. */
3323  if (!check_acl(Context->mailbox, MUTT_ACL_DELETE, _("Can't delete messages")))
3324  break;
3325  if (!cur.e)
3326  break;
3327 
3328  int subthread = (op == OP_DELETE_SUBTHREAD);
3329  int rc = mutt_thread_set_flag(cur.e, MUTT_DELETE, true, subthread);
3330  if (rc == -1)
3331  break;
3332  if (op == OP_PURGE_THREAD)
3333  {
3334  rc = mutt_thread_set_flag(cur.e, MUTT_PURGE, true, subthread);
3335  if (rc == -1)
3336  break;
3337  }
3338 
3339  if (C_DeleteUntag)
3340  mutt_thread_set_flag(cur.e, MUTT_TAG, false, subthread);
3341  if (C_Resolve)
3342  {
3343  menu->current = ci_next_undeleted(Context->mailbox, menu->current);
3344  if (menu->current == -1)
3345  menu->current = menu->oldcurrent;
3346  }
3347  menu->redraw |= REDRAW_INDEX | REDRAW_STATUS;
3348  break;
3349  }
3350 
3351 #ifdef USE_NNTP
3352  case OP_CATCHUP:
3354  break;
3355  if (Context && (Context->mailbox->type == MUTT_NNTP))
3356  {
3357  struct NntpMboxData *mdata = Context->mailbox->mdata;
3358  if (mutt_newsgroup_catchup(Context->mailbox, mdata->adata, mdata->group))
3359  menu->redraw = REDRAW_INDEX | REDRAW_STATUS;
3360  }
3361  break;
3362 #endif
3363 
3364  case OP_DISPLAY_ADDRESS:
3365  {
3367  break;
3368  if (!cur.e)
3369  break;
3370  mutt_display_address(cur.e->env);
3371  break;
3372  }
3373 
3374  case OP_ENTER_COMMAND:
3376  window_set_focus(win_index);
3377  if (Context)
3379  menu->redraw = REDRAW_FULL;
3380  break;
3381 
3382  case OP_EDIT_OR_VIEW_RAW_MESSAGE:
3383  case OP_EDIT_RAW_MESSAGE:
3384  case OP_VIEW_RAW_MESSAGE:
3385  {
3386  /* TODO split this into 3 cases? */
3388  break;
3389  bool edit;
3390  if (op == OP_EDIT_RAW_MESSAGE)
3391  {
3392  if (!prereq(Context, menu, CHECK_READONLY))
3393  break;
3394  /* L10N: CHECK_ACL */
3395  if (!check_acl(Context->mailbox, MUTT_ACL_INSERT, _("Can't edit message")))
3396  break;
3397  edit = true;
3398  }
3399  else if (op == OP_EDIT_OR_VIEW_RAW_MESSAGE)
3401  else
3402  edit = false;
3403 
3404  if (!cur.e)
3405  break;
3406  if (C_PgpAutoDecode && (tag || !(cur.e->security & PGP_TRADITIONAL_CHECKED)))
3407  {
3408  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3409  el_add_tagged(&el, Context, cur.e, tag);
3410  mutt_check_traditional_pgp(&el, &menu->redraw);
3411  emaillist_clear(&el);
3412  }
3413  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3414  el_add_tagged(&el, Context, cur.e, tag);
3415  mutt_ev_message(Context->mailbox, &el, edit ? EVM_EDIT : EVM_VIEW);
3416  emaillist_clear(&el);
3417  menu->redraw = REDRAW_FULL;
3418 
3419  break;
3420  }
3421 
3422  case OP_FORWARD_MESSAGE:
3423  {
3425  break;
3426  if (!cur.e)
3427  break;
3428  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3429  el_add_tagged(&el, Context, cur.e, tag);
3430  if (C_PgpAutoDecode && (tag || !(cur.e->security & PGP_TRADITIONAL_CHECKED)))
3431  {
3432  mutt_check_traditional_pgp(&el, &menu->redraw);
3433  }
3434  mutt_send_message(SEND_FORWARD, NULL, NULL, Context, &el, NeoMutt->sub);
3435  emaillist_clear(&el);
3436  menu->redraw = REDRAW_FULL;
3437  break;
3438  }
3439 
3440  case OP_FORGET_PASSPHRASE:
3442  break;
3443 
3444  case OP_GROUP_REPLY:
3445  case OP_GROUP_CHAT_REPLY:
3446  {
3447  SendFlags replyflags = SEND_REPLY;
3448  if (op == OP_GROUP_REPLY)
3449  replyflags |= SEND_GROUP_REPLY;
3450  else
3451  replyflags |= SEND_GROUP_CHAT_REPLY;
3453  break;
3454  if (!cur.e)
3455  break;
3456  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3457  el_add_tagged(&el, Context, cur.e, tag);
3458  if (C_PgpAutoDecode && (tag || !(cur.e->security & PGP_TRADITIONAL_CHECKED)))
3459  {
3460  mutt_check_traditional_pgp(&el, &menu->redraw);
3461  }
3462  mutt_send_message(replyflags, NULL, NULL, Context, &el, NeoMutt->sub);
3463  emaillist_clear(&el);
3464  menu->redraw = REDRAW_FULL;
3465  break;
3466  }
3467 
3468  case OP_EDIT_LABEL:
3469  {
3471  break;
3472 
3473  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3474  el_add_tagged(&el, Context, cur.e, tag);
3475  int num_changed = mutt_label_message(Context->mailbox, &el);
3476  emaillist_clear(&el);
3477 
3478  if (num_changed > 0)
3479  {
3480  Context->mailbox->changed = true;
3481  menu->redraw = REDRAW_FULL;
3482  /* L10N: This is displayed when the x-label on one or more
3483  messages is edited. */
3484  mutt_message(ngettext("%d label changed", "%d labels changed", num_changed),
3485  num_changed);
3486  }
3487  else
3488  {
3489  /* L10N: This is displayed when editing an x-label, but no messages
3490  were updated. Possibly due to canceling at the prompt or if the new
3491  label is the same as the old label. */
3492  mutt_message(_("No labels changed"));
3493  }
3494  break;
3495  }
3496 
3497  case OP_LIST_REPLY:
3498  {
3500  break;
3501  if (!cur.e)
3502  break;
3503  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3504  el_add_tagged(&el, Context, cur.e, tag);
3505  if (C_PgpAutoDecode && (tag || !(cur.e->security & PGP_TRADITIONAL_CHECKED)))
3506  {
3507  mutt_check_traditional_pgp(&el, &menu->redraw);
3508  }
3510  &el, NeoMutt->sub);
3511  emaillist_clear(&el);
3512  menu->redraw = REDRAW_FULL;
3513  break;
3514  }
3515 
3516  case OP_MAIL:
3517  if (!prereq(Context, menu, CHECK_ATTACH))
3518  break;
3519  mutt_send_message(SEND_NO_FLAGS, NULL, NULL, Context, NULL, NeoMutt->sub);
3520  menu->redraw = REDRAW_FULL;
3521  break;
3522 
3523  case OP_MAIL_KEY:
3524  if (!(WithCrypto & APPLICATION_PGP))
3525  break;
3526  if (!prereq(Context, menu, CHECK_ATTACH))
3527  break;
3528  mutt_send_message(SEND_KEY, NULL, NULL, NULL, NULL, NeoMutt->sub);
3529  menu->redraw = REDRAW_FULL;
3530  break;
3531 
3532  case OP_EXTRACT_KEYS:
3533  {
3534  if (!WithCrypto)
3535  break;
3537  break;
3538  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3539  el_add_tagged(&el, Context, cur.e, tag);
3541  emaillist_clear(&el);
3542  menu->redraw = REDRAW_FULL;
3543  break;
3544  }
3545 
3546  case OP_CHECK_TRADITIONAL:
3547  {
3548  if (!(WithCrypto & APPLICATION_PGP))
3549  break;
3551  break;
3552  if (!cur.e)
3553  break;
3554  if (tag || !(cur.e->security & PGP_TRADITIONAL_CHECKED))
3555  {
3556  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3557  el_add_tagged(&el, Context, cur.e, tag);
3558  mutt_check_traditional_pgp(&el, &menu->redraw);
3559  emaillist_clear(&el);
3560  }
3561 
3562  if (in_pager)
3563  {
3564  op = OP_DISPLAY_MESSAGE;
3565  continue;
3566  }
3567  break;
3568  }
3569 
3570  case OP_PIPE:
3571  {
3573  break;
3574  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3575  el_add_tagged(&el, Context, cur.e, tag);
3577  emaillist_clear(&el);
3578 
3579 #ifdef USE_IMAP
3580  /* in an IMAP folder index with imap_peek=no, piping could change
3581  * new or old messages status to read. Redraw what's needed. */
3582  if ((Context->mailbox->type == MUTT_IMAP) && !C_ImapPeek)
3583  {
3584  menu->redraw |= (tag ? REDRAW_INDEX : REDRAW_CURRENT) | REDRAW_STATUS;
3585  }
3586 #endif
3587  break;
3588  }
3589 
3590  case OP_PRINT:
3591  {
3593  break;
3594  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3595  el_add_tagged(&el, Context, cur.e, tag);
3597  emaillist_clear(&el);
3598 
3599 #ifdef USE_IMAP
3600  /* in an IMAP folder index with imap_peek=no, printing could change
3601  * new or old messages status to read. Redraw what's needed. */
3602  if ((Context->mailbox->type == MUTT_IMAP) && !C_ImapPeek)
3603  {
3604  menu->redraw |= (tag ? REDRAW_INDEX : REDRAW_CURRENT) | REDRAW_STATUS;
3605  }
3606 #endif
3607  break;
3608  }
3609 
3610  case OP_MAIN_READ_THREAD:
3611  case OP_MAIN_READ_SUBTHREAD:
3612  {
3614  break;
3615  /* L10N: CHECK_ACL */
3616  /* L10N: Due to the implementation details we do not know whether we
3617  mark zero, 1, 12, ... messages as read. So in English we use
3618  "messages". Your language might have other means to express this. */
3619  if (!check_acl(Context->mailbox, MUTT_ACL_SEEN, _("Can't mark messages as read")))
3620  break;
3621 
3622  int rc = mutt_thread_set_flag(cur.e, MUTT_READ, true, (op != OP_MAIN_READ_THREAD));
3623  if (rc != -1)
3624  {
3625  if (C_Resolve)
3626  {
3627  menu->current = ((op == OP_MAIN_READ_THREAD) ? mutt_next_thread(cur.e) :
3628  mutt_next_subthread(cur.e));
3629  if (menu->current == -1)
3630  {
3631  menu->current = menu->oldcurrent;
3632  }
3633  else if (in_pager)
3634  {
3635  op = OP_DISPLAY_MESSAGE;
3636  continue;
3637  }
3638  }
3639  menu->redraw |= REDRAW_INDEX | REDRAW_STATUS;
3640  }
3641  break;
3642  }
3643 
3644  case OP_MARK_MSG:
3645  {
3647  break;
3648  if (!cur.e)
3649  break;
3650  if (cur.e->env->message_id)
3651  {
3652  char buf2[128];
3653 
3654  buf2[0] = '\0';
3655  /* L10N: This is the prompt for <mark-message>. Whatever they
3656  enter will be prefixed by $mark_macro_prefix and will become
3657  a macro hotkey to jump to the currently selected message. */
3658  if (!mutt_get_field(_("Enter macro stroke: "), buf2, sizeof(buf2), MUTT_COMP_NO_FLAGS) &&
3659  buf2[0])
3660  {
3661  char str[256], macro[256];
3662  snprintf(str, sizeof(str), "%s%s", C_MarkMacroPrefix, buf2);
3663  snprintf(macro, sizeof(macro), "<search>~i \"%s\"\n", cur.e->env->message_id);
3664  /* L10N: "message hotkey" is the key bindings menu description of a
3665  macro created by <mark-message>. */
3666  km_bind(str, MENU_MAIN, OP_MACRO, macro, _("message hotkey"));
3667 
3668  /* L10N: This is echoed after <mark-message> creates a new hotkey
3669  macro. %s is the hotkey string ($mark_macro_prefix followed
3670  by whatever they typed at the prompt.) */
3671  snprintf(buf2, sizeof(buf2), _("Message bound to %s"), str);
3672  mutt_message(buf2);
3673  mutt_debug(LL_DEBUG1, "Mark: %s => %s\n", str, macro);
3674  }
3675  }
3676  else
3677  {
3678  /* L10N: This error is printed if <mark-message> can't find a
3679  Message-ID for the currently selected message in the index. */
3680  mutt_error(_("No message ID to macro"));
3681  }
3682  break;
3683  }
3684 
3685  case OP_RECALL_MESSAGE:
3686  if (!prereq(Context, menu, CHECK_ATTACH))
3687  break;
3688  mutt_send_message(SEND_POSTPONED, NULL, NULL, Context, NULL, NeoMutt->sub);
3689  menu->redraw = REDRAW_FULL;
3690  break;
3691 
3692  case OP_RESEND:
3694  break;
3695 
3696  if (tag)
3697  {
3698  struct Mailbox *m = Context->mailbox;
3699  for (size_t i = 0; i < m->msg_count; i++)
3700  {
3701  struct Email *e = m->emails[i];
3702  if (!e)
3703  break;
3704  if (message_is_tagged(Context, e))
3705  mutt_resend_message(NULL, Context, e, NeoMutt->sub);
3706  }
3707  }
3708  else
3709  {
3710  mutt_resend_message(NULL, Context, cur.e, NeoMutt->sub);
3711  }
3712 
3713  menu->redraw = REDRAW_FULL;
3714  break;
3715 
3716 #ifdef USE_NNTP
3717  case OP_FOLLOWUP:
3718  case OP_FORWARD_TO_GROUP:
3720  break;
3721  /* fallthrough */
3722 
3723  case OP_POST:
3724  {
3726  break;
3727  if (!cur.e)
3728  break;
3729  if ((op != OP_FOLLOWUP) || !cur.e->env->followup_to ||
3730  !mutt_istr_equal(cur.e->env->followup_to, "poster") ||
3732  _("Reply by mail as poster prefers?")) != MUTT_YES))
3733  {
3734  if (Context && (Context->mailbox->type == MUTT_NNTP) &&
3735  !((struct NntpMboxData *) Context->mailbox->mdata)->allowed && (query_quadoption(C_PostModerated, _("Posting to this group not allowed, may be moderated. Continue?")) != MUTT_YES))
3736  {
3737  break;
3738  }
3739  if (op == OP_POST)
3740  mutt_send_message(SEND_NEWS, NULL, NULL, Context, NULL, NeoMutt->sub);
3741  else
3742  {
3744  break;
3745  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3746  el_add_tagged(&el, Context, cur.e, tag);
3747  mutt_send_message(((op == OP_FOLLOWUP) ? SEND_REPLY : SEND_FORWARD) | SEND_NEWS,
3748  NULL, NULL, Context, &el, NeoMutt->sub);
3749  emaillist_clear(&el);
3750  }
3751  menu->redraw = REDRAW_FULL;
3752  break;
3753  }
3754  }
3755 #endif
3756  /* fallthrough */
3757  case OP_REPLY:
3758  {
3760  break;
3761  if (!cur.e)
3762  break;
3763  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3764  el_add_tagged(&el, Context, cur.e, tag);
3765  if (C_PgpAutoDecode && (tag || !(cur.e->security & PGP_TRADITIONAL_CHECKED)))
3766  {
3767  mutt_check_traditional_pgp(&el, &menu->redraw);
3768  }
3769  mutt_send_message(SEND_REPLY, NULL, NULL, Context, &el, NeoMutt->sub);
3770  emaillist_clear(&el);
3771  menu->redraw = REDRAW_FULL;
3772  break;
3773  }
3774 
3775  case OP_SHELL_ESCAPE:
3776  if (mutt_shell_escape())
3777  {
3779  }
3780  break;
3781 
3782  case OP_TAG_THREAD:
3783  case OP_TAG_SUBTHREAD:
3784  {
3786  break;
3787  if (!cur.e)
3788  break;
3789 
3790  int rc = mutt_thread_set_flag(cur.e, MUTT_TAG, !cur.e->tagged, (op != OP_TAG_THREAD));
3791  if (rc != -1)
3792  {
3793  if (C_Resolve)
3794  {
3795  if (op == OP_TAG_THREAD)
3796  menu->current = mutt_next_thread(cur.e);
3797  else
3798  menu->current = mutt_next_subthread(cur.e);
3799 
3800  if (menu->current == -1)
3801  menu->current = menu->oldcurrent;
3802  }
3803  menu->redraw |= REDRAW_INDEX | REDRAW_STATUS;
3804  }
3805  break;
3806  }
3807 
3808  case OP_UNDELETE:
3809  {
3811  break;
3812  /* L10N: CHECK_ACL */
3813  if (!check_acl(Context->mailbox, MUTT_ACL_DELETE, _("Can't undelete message")))
3814  break;
3815 
3816  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3817  el_add_tagged(&el, Context, cur.e, tag);
3818 
3821  emaillist_clear(&el);
3822 
3823  if (tag)
3824  {
3825  menu->redraw |= REDRAW_INDEX;
3826  }
3827  else
3828  {
3829  if (C_Resolve && (menu->current < (Context->mailbox->vcount - 1)))
3830  {
3831  menu->current++;
3832  menu->redraw |= REDRAW_MOTION_RESYNC;
3833  }
3834  else
3835  menu->redraw |= REDRAW_CURRENT;
3836  }
3837 
3838  menu->redraw |= REDRAW_STATUS;
3839  break;
3840  }
3841 
3842  case OP_UNDELETE_THREAD:
3843  case OP_UNDELETE_SUBTHREAD:
3844  {
3846  break;
3847  /* L10N: CHECK_ACL */
3848  /* L10N: Due to the implementation details we do not know whether we
3849  undelete zero, 1, 12, ... messages. So in English we use
3850  "messages". Your language might have other means to express this. */
3851  if (!check_acl(Context->mailbox, MUTT_ACL_DELETE, _("Can't undelete messages")))
3852  break;
3853 
3854  int rc = mutt_thread_set_flag(cur.e, MUTT_DELETE, false, (op != OP_UNDELETE_THREAD));
3855  if (rc != -1)
3856  {
3857  rc = mutt_thread_set_flag(cur.e, MUTT_PURGE, false, (op != OP_UNDELETE_THREAD));
3858  }
3859  if (rc != -1)
3860  {
3861  if (C_Resolve)
3862  {
3863  if (op == OP_UNDELETE_THREAD)
3864  menu->current = mutt_next_thread(cur.e);
3865  else
3866  menu->current = mutt_next_subthread(cur.e);
3867 
3868  if (menu->current == -1)
3869  menu->current = menu->oldcurrent;
3870  }
3871  menu->redraw |= REDRAW_INDEX | REDRAW_STATUS;
3872  }
3873  break;
3874  }
3875 
3876  case OP_VERSION:
3878  break;
3879 
3880  case OP_MAILBOX_LIST:
3882  break;
3883 
3884  case OP_VIEW_ATTACHMENTS:
3886  break;
3887  if (!cur.e)
3888  break;
3889  dlg_select_attachment(cur.e);
3890  if (cur.e->attach_del)
3891  Context->mailbox->changed = true;
3892  menu->redraw = REDRAW_FULL;
3893  break;
3894 
3895  case OP_END_COND:
3896  break;
3897 
3898  case OP_WHAT_KEY:
3899  mutt_what_key();
3900  break;
3901 
3902 #ifdef USE_SIDEBAR
3903  case OP_SIDEBAR_FIRST:
3904  case OP_SIDEBAR_LAST:
3905  case OP_SIDEBAR_NEXT:
3906  case OP_SIDEBAR_NEXT_NEW:
3907  case OP_SIDEBAR_PAGE_DOWN:
3908  case OP_SIDEBAR_PAGE_UP:
3909  case OP_SIDEBAR_PREV:
3910  case OP_SIDEBAR_PREV_NEW:
3911  {
3912  struct MuttWindow *win_sidebar = mutt_window_find(dlg, WT_SIDEBAR);
3913  if (!win_sidebar)
3914  break;
3915  sb_change_mailbox(win_sidebar, op);
3916  break;
3917  }
3918 
3919  case OP_SIDEBAR_TOGGLE_VISIBLE:
3920  bool_str_toggle(NeoMutt->sub, "sidebar_visible", NULL);
3921  mutt_window_reflow(NULL);
3922  break;
3923 #endif
3924 
3925 #ifdef USE_AUTOCRYPT
3926  case OP_AUTOCRYPT_ACCT_MENU:
3928  break;
3929 #endif
3930 
3931  default:
3932  if (!in_pager)
3934  }
3935 
3936 #ifdef USE_NOTMUCH
3937  if (Context)
3939 #endif
3940 
3941  if (in_pager)
3942  {
3944  in_pager = false;
3945  menu->redraw = REDRAW_FULL;
3946  }
3947 
3948  if (done)
3949  break;
3950  }
3951 
3952  mutt_menu_pop_current(menu);
3953  mutt_menu_free(&menu);
3954  return close;
3955 }
int km_dokey(enum MenuType menu)
Determine what a keypress should do.
Definition: keymap.c:658
void * mutt_hash_find(const struct HashTable *table, const char *strkey)
Find the HashElem data in a Hash Table element using a key.
Definition: hash.c:354
struct Email ** emails
Array of Emails.
Definition: mailbox.h:99
int mutt_save_message(struct Mailbox *m, struct EmailList *el, bool delete_original, bool decode, bool decrypt)
Save an email.
Definition: commands.c:1042
The "current" mailbox.
Definition: context.h:38
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox&#39;s path string.
Definition: mailbox.h:204
void nm_query_window_forward(void)
Function to move the current search window forward in time.
Definition: notmuch.c:1868
static int ci_first_message(struct Mailbox *m)
Get index of first new message.
Definition: index.c:339
#define REDRAW_FULL
Redraw everything.
Definition: mutt_menu.h:45
static struct Mailbox * change_folder_notmuch(struct Menu *menu, char *buf, int buflen, int *oldcount, const struct CurrentEmail *cur, bool read_only)
Change to a different Notmuch Mailbox by string.
Definition: index.c:794
bool message_is_tagged(struct Context *ctx, struct Email *e)
Is a message in the index tagged (and within limit)
Definition: context.c:334
enum MailboxType type
Mailbox type.
Definition: mailbox.h:105
bool mutt_mailbox_list(void)
List the mailboxes with new mail.
Definition: mutt_mailbox.c:217
#define NONULL(x)
Definition: string2.h:37
int msg_count
Total number of messages.
Definition: mailbox.h:91
#define mutt_set_flag(m, e, flag, bf)
Definition: protos.h:67
#define WithCrypto
Definition: lib.h:123
int mutt_str_atoi(const char *str, int *dst)
Convert ASCII string to an integer.
Definition: string.c:252
#define SEND_TO_SENDER
Compose new email to sender.
Definition: send.h:52
void mutt_pipe_message(struct Mailbox *m, struct EmailList *el)
Pipe a message.
Definition: commands.c:706
The envelope/body of an email.
Definition: email.h:37
WHERE bool C_DeleteUntag
Config: Untag messages when they are marked for deletion.
Definition: mutt_globals.h:145
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
struct Email * mutt_get_virt_email(struct Mailbox *m, int vnum)
Get a virtual Email.
Definition: context.c:396
#define mutt_perror(...)
Definition: logging.h:85
#define MUTT_SHUTDOWN_HOOK
shutdown-hook: run when leaving NeoMutt
Definition: hook.h:65
GUI selectable list of items.
Definition: mutt_menu.h:52
struct Body * body
List of MIME parts.
Definition: email.h:91
void nm_query_window_backward(void)
Function to move the current search window backward in time.
Definition: notmuch.c:1884
struct Mailbox * ctx_mailbox(struct Context *ctx)
wrapper to get the mailbox in a Context, or NULL
Definition: context.c:428
void window_set_focus(struct MuttWindow *win)
Set the Window focus.
Definition: mutt_window.c:763
&#39;NNTP&#39; (Usenet) Mailbox type
Definition: mailbox.h:52
int mx_mbox_close(struct Context **ptr)
Save changes and close mailbox.
Definition: mx.c:630
#define mutt_uncollapse_thread(e)
Definition: mutt_thread.h:90
bool C_UncollapseJump
Config: When opening a thread, jump to the next unread message.
Definition: index.c:105
#define mutt_collapse_thread(e)
Definition: mutt_thread.h:89
Pager Bar containing status info about the Pager.
Definition: mutt_window.h:98
int mutt_search_command(struct Mailbox *m, int cur, int op)
Perform a search.
Definition: pattern.c:484
#define mutt_message(...)
Definition: logging.h:83
void mutt_emails_set_flag(struct Mailbox *m, struct EmailList *el, enum MessageType flag, bool bf)
Set flag on messages.
Definition: flags.c:354
int help_menu
Menu for key bindings, e.g. MENU_PAGER.
Definition: mutt_window.h:134
void mutt_check_rescore(struct Mailbox *m)
Do the emails need to have their scores recalculated?
Definition: score.c:71
void mutt_sort_headers(struct Mailbox *m, struct ThreadsContext *threads, bool init, off_t *vsize)
Sort emails by their headers.
Definition: sort.c:367
int oldcurrent
For driver use only.
Definition: mutt_menu.h:76
void mutt_display_address(struct Envelope *env)
Display the address of a message.
Definition: commands.c:925
struct NntpAccountData * adata
Definition: lib.h:153
bool mutt_shell_escape(void)
invoke a command in a subshell
Definition: commands.c:846
static void index_custom_redraw(struct Menu *menu)
Redraw the index - Implements Menu::custom_redraw()
Definition: index.c:1093
Progress tracks elements, according to $write_inc
Definition: progress.h:43
Messages in limited view.
Definition: mutt.h:105
struct HashTable * mutt_make_id_hash(struct Mailbox *m)
Create a Hash Table for message-ids.
Definition: mutt_thread.c:1518
bool attach_del
Has an attachment marked for deletion.
Definition: email.h:49
#define SEND_FORWARD
Forward email.
Definition: send.h:44
struct MuttWindow * mutt_window_find(struct MuttWindow *root, enum WindowType type)
Find a Window of a given type.
Definition: mutt_window.c:678
void mutt_window_clrtoeol(struct MuttWindow *win)
Clear to the end of the line.
Definition: mutt_window.c:244
void mutt_resize_screen(void)
Update NeoMutt&#39;s opinion about the window size (CURSES)
Definition: resize.c:101
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
#define CHECK_ATTACH
Is the user in message-attach mode?
Definition: index.c:150
WHERE bool OptNeedResort
(pseudo) used to force a re-sort
Definition: options.h:43
void index_make_entry(char *buf, size_t buflen, struct Menu *menu, int line)
Format a menu item for the index list - Implements Menu::make_entry()
Definition: index.c:861
void mutt_check_stats(void)
Forcibly update mailbox stats.
Definition: commands.c:1435
struct ThreadsContext * threads
Threads context.
Definition: context.h:43
#define mutt_next_subthread(e)
Definition: mutt_thread.h:98
void crypt_forget_passphrase(void)
Forget a passphrase and display a message.
Definition: crypt.c:92
bool mutt_link_threads(struct Email *parent, struct EmailList *children, struct Mailbox *m)
Forcibly link threads together.
Definition: mutt_thread.c:1563
#define MUTT_NM_QUERY
Notmuch query mode.
Definition: mutt.h:66
void mutt_enter_command(void)
enter a neomutt command
Definition: commands.c:879
String manipulation buffer.
Definition: buffer.h:33
#define MUTT_ACL_INSERT
Add/copy into the mailbox (used when editing a message)
Definition: mailbox.h:69
int nntp_check_msgid(struct Mailbox *m, const char *msgid)
Fetch article by Message-ID.
Definition: nntp.c:2222
bool ctx_has_limit(const struct Context *ctx)
Is a limit active?
Definition: context.c:417
Messages to be un-deleted.
Definition: mutt.h:99
Flagged messages.
Definition: mutt.h:102
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:370
void mutt_unget_event(int ch, int op)
Return a keystroke to the input buffer.
Definition: curs_lib.c:834
#define _(a)
Definition: message.h:28
WHERE bool C_BeepNew
Config: Make a noise when new mail arrives.
Definition: mutt_globals.h:139
int index_color(int line)
Calculate the colour for a line of the index - Implements Menu::color()
Definition: index.c:938
static bool check_acl(struct Mailbox *m, AclFlags acl, const char *msg)
Check the ACLs for a function.
Definition: index.c:210
bool mutt_check_traditional_pgp(struct EmailList *el, MuttRedrawFlags *redraw)
Check if a message has inline PGP content.
Definition: commands.c:1419
static const struct Mapping IndexNewsHelp[]
Help Bar for the News Index dialog.
Definition: index.c:125
Messages to be purged (bypass trash)
Definition: mutt.h:100
A division of the screen.
Definition: mutt_window.h:115
void nm_db_longrun_init(struct Mailbox *m, bool writable)
Start a long transaction.
Definition: db.c:289
char * C_NewsServer
Config: (nntp) Url of the news server.
Definition: config.c:41
WHERE bool C_BrailleFriendly
Config: Move the cursor to the beginning of the line.
Definition: mutt_globals.h:140
char * C_MarkMacroPrefix
Config: Prefix for macros using &#39;<mark-message>&#39;.
Definition: index.c:104
bool C_CollapseAll
Config: Collapse all threads when entering a folder.
Definition: index.c:103
void emaillist_clear(struct EmailList *el)
Drop a private list of Emails.
Definition: email.c:130
Index panel (list of emails)
Definition: keymap.h:80
int mutt_pattern_func(int op, char *prompt)
Perform some Pattern matching.
Definition: pattern.c:338
struct Mailbox * mutt_mailbox_next(struct Mailbox *m_cur, struct Buffer *s)
incoming folders completion routine
Definition: mutt_mailbox.c:309
uint16_t SendFlags
Flags for mutt_send_message(), e.g. SEND_REPLY.
Definition: send.h:37
int mutt_window_mvaddstr(struct MuttWindow *win, int col, int row, const char *str)
Move the cursor and write a fixed string to a Window.
Definition: mutt_window.c:396
static int ci_next_undeleted(struct Mailbox *m, int msgno)
Find the next undeleted email.
Definition: index.c:292
int mutt_monitor_add(struct Mailbox *m)
Add a watch for a mailbox.
Definition: monitor.c:481
struct Mailbox * mx_mbox_find2(const char *path)
Find a Mailbox on an Account.
Definition: mx.c:1655
WHERE bool C_AutoTag
Config: Automatically apply actions to all tagged messages.
Definition: mutt_globals.h:137
struct Email * e
Current email.
Definition: index.c:572
int C_NmQueryWindowDuration
Config: (notmuch) Time duration of the current search window.
Definition: config.c:45
#define SEND_POSTPONED
Recall a postponed email.
Definition: send.h:45
Container for Accounts, Notifications.
Definition: neomutt.h:36
A progress bar.
Definition: progress.h:50
void mutt_buffer_pretty_mailbox(struct Buffer *buf)
Shorten a mailbox path using &#39;~&#39; or &#39;=&#39;.
Definition: muttlib.c:599
Keep track of the currently selected Email.
Definition: index.c:570
#define MUTT_ACL_DELETE
Delete a message.
Definition: mailbox.h:66
#define mutt_get_field(field, buf, buflen, complete)
Definition: curs_lib.h:91
int vcount
The number of virtual messages.
Definition: mailbox.h:102
int mutt_window_move(struct MuttWindow *win, int col, int row)
Move the cursor in a Window.
Definition: mutt_window.c:382
An Index Window containing a selection list.
Definition: mutt_window.h:94
int mx_mbox_sync(struct Mailbox *m)
Save changes to mailbox.
Definition: mx.c:938
void imap_logout_all(void)
close all open connections
Definition: imap.c:557
void mutt_print_message(struct Mailbox *m, struct EmailList *el)
Print a message.
Definition: commands.c:731
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:77
#define SEND_NO_FLAGS
No flags are set.
Definition: send.h:40
void mutt_beep(bool force)
Irritate the user.
Definition: curs_lib.c:99
#define mutt_previous_thread(e)
Definition: mutt_thread.h:97
size_t dsize
Length of data.
Definition: buffer.h:37
bool tagged
Email is tagged.
Definition: email.h:44
#define CHECK_VISIBLE
Is the selected message visible in the index?
Definition: index.c:148
bool read
Email is read.
Definition: email.h:51
void mutt_progress_update(struct Progress *progress, size_t pos, int percent)
Update the state of the progress bar.
Definition: progress.c:212
char * name
A short name for the Mailbox.
Definition: mailbox.h:85
void mutt_startup_shutdown_hook(HookFlags type)
Execute any startup/shutdown hooks.
Definition: hook.c:836
void mutt_curses_set_cursor(enum MuttCursorState state)
Set the cursor state.
Definition: mutt_curses.c:78
struct ListHead in_reply_to
in-reply-to header content
Definition: envelope.h:82
char * message_id
Message ID.
Definition: envelope.h:69
struct Mailbox * mailbox
Definition: context.h:50
struct HashTable * id_hash
Hash Table by msg id.
Definition: mailbox.h:127
#define CHECK_IN_MAILBOX
Is there a mailbox open?
Definition: index.c:146
bool old
Email is seen, but unread.
Definition: email.h:50
static bool prereq(struct Context *ctx, struct Menu *menu, CheckFlags checks)
Check the pre-requisites for a function.
Definition: index.c:160
void mutt_flush_macro_to_endcond(void)
Drop a macro from the input buffer.
Definition: curs_lib.c:890
#define MUTT_COMP_NO_FLAGS
No flags are set.
Definition: mutt.h:56
struct MuttWindow * win_ibar
Definition: mutt_menu.h:64
bool readonly
Don&#39;t allow changes to the mailbox.
Definition: mailbox.h:119
bool nm_message_is_still_queried(struct Mailbox *m, struct Email *e)
Is a message still visible in the query?
Definition: notmuch.c:1896
void mutt_window_clearline(struct MuttWindow *win, int row)
Clear a row of a Window.
Definition: mutt_window.c:232
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:153
#define mutt_thread_next_unread(e)
Definition: mutt_thread.h:93
void mutt_what_key(void)
Ask the user to press a key.
Definition: keymap.c:1676
struct Envelope * env
Envelope information.
Definition: email.h:90
Display a normal cursor.
Definition: mutt_curses.h:81
int LastKey
contains the last key the user pressed
Definition: keymap.c:146
int mx_tags_commit(struct Mailbox *m, struct Email *e, char *tags)
Save tags to the Mailbox - Wrapper for MxOps::tags_commit()
Definition: mx.c:1309
void alias_create(struct AddressList *al, const struct ConfigSubset *sub)
Create a new Alias from an Address.
Definition: alias.c:366
bool mutt_mailbox_notify(struct Mailbox *m_cur)
Notify the user if there&#39;s new mail.
Definition: mutt_mailbox.c:204
void mx_fastclose_mailbox(struct Mailbox *m)
free up memory associated with the Mailbox
Definition: mx.c:445
char * group
Definition: lib.h:140
#define mutt_thread_contains_unread(e)
Definition: mutt_thread.h:91
int mutt_display_message(struct MuttWindow *win_index, struct MuttWindow *win_ibar, struct MuttWindow *win_pager, struct MuttWindow *win_pbar, struct Mailbox *m, struct Email *e)
Display a message in the pager.
Definition: commands.c:205
struct Menu * menu
Needed for pattern compilation.
Definition: context.h:46
WHERE bool C_ReadOnly
Config: Open folders in read-only mode.
Definition: mutt_globals.h:154
void mutt_break_thread(struct Email *e)
Break the email Thread.
Definition: thread.c:225
int bool_str_toggle(struct ConfigSubset *sub, const char *name, struct Buffer *err)
Toggle the value of a bool.
Definition: bool.c:213
#define SEND_LIST_REPLY
Reply to mailing list.
Definition: send.h:43
bool C_PgpAutoDecode
Config: Automatically decrypt PGP messages.
Definition: config.c:122
WHERE short C_Sort
Config: Sort method for the index.
Definition: sort.h:60
int mutt_thread_set_flag(struct Email *e, enum MessageType flag, bool bf, bool subthread)
Set a flag on an entire thread.
Definition: flags.c:376
int nntp_check_children(struct Mailbox *m, const char *msgid)
Fetch children of article with the Message-ID.
Definition: nntp.c:2292
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:113
static int mx_toggle_write(struct Mailbox *m)
Toggle the mailbox&#39;s readonly flag.
Definition: index.c:385
const char * OpStrings[][2]
Definition: opcodes.c:28
void * mdata
Driver specific data.
Definition: mailbox.h:136
static int ci_previous_undeleted(struct Mailbox *m, int msgno)
Find the previous undeleted email.
Definition: index.c:315
struct NntpAccountData * nntp_select_server(struct Mailbox *m, const char *server, bool leave_lock)
Open a connection to an NNTP server.
Definition: newsrc.c:1009
#define MUTT_ACL_WRITE
Write to a message (for flagging or linking threads)
Definition: mailbox.h:74
struct TagList tags
For drivers that support server tagging.
Definition: email.h:109
#define REDRAW_MOTION
Redraw after moving the menu list.
Definition: mutt_menu.h:41
&#39;Maildir&#39; Mailbox type
Definition: mailbox.h:51
void nm_db_debug_check(struct Mailbox *m)
Check if the database is open.
Definition: db.c:322
bool quasi_deleted
Deleted from neomutt, but not modified on disk.
Definition: email.h:47
#define SEND_KEY
Mail a PGP public key.
Definition: send.h:47
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:883
#define REDRAW_MOTION_RESYNC
Redraw any changing the menu selection.
Definition: mutt_menu.h:42
void menu_status_line(char *buf, size_t buflen, struct Menu *menu, struct Mailbox *m, const char *p)
Create the status line.
Definition: status.c:420
short cols
Number of columns, can be MUTT_WIN_SIZE_UNLIMITED.
Definition: mutt_window.h:57
off_t vsize
Size (in bytes) of the messages shown.
Definition: context.h:40
View the message.
Definition: protos.h:56
void mutt_refresh(void)
Force a refresh of the screen.
Definition: curs_lib.c:108
Side panel containing Accounts or groups of data.
Definition: mutt_window.h:99
Edit the message.
Definition: protos.h:57
bool visible
Is this message part of the view?
Definition: email.h:74
bool mutt_limit_current_thread(struct Email *e)
Limit the email view to the current thread.
Definition: pattern.c:189
bool C_ImapPeek
Config: (imap) Don&#39;t mark messages as read when fetching them from the server.
Definition: config.c:55
#define mutt_mktemp(buf, buflen)
Definition: muttlib.h:74
Sort by email threads.
Definition: sort2.h:51
struct WindowState state
Current state of the Window.
Definition: mutt_window.h:120
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: lib.h:97
WHERE bool OptAttachMsg
(pseudo) used by attach-message
Definition: options.h:31
#define REDRAW_STATUS
Redraw the status bar.
Definition: mutt_menu.h:44
struct AddressList * mutt_get_address(struct Envelope *env, const char **prefix)
Get an Address from an Envelope.
Definition: alias.c:326
struct MuttWindow * MessageWindow
Message Window, ":set", etc.
Definition: mutt_window.c:47
struct MuttWindow * RootWindow
Parent of all Windows.
Definition: mutt_window.c:45
void km_error_key(enum MenuType menu)
Handle an unbound key sequence.
Definition: keymap.c:1137
int(* color)(int line)
Calculate the colour for a line of the menu.
Definition: mutt_menu.h:115
Messages to be deleted.
Definition: mutt.h:98
A mailbox.
Definition: mailbox.h:81
#define PATH_MAX
Definition: mutt.h:44
int mutt_mailbox_check(struct Mailbox *m_cur, int force)
Check all all Mailboxes for new mail.
Definition: mutt_mailbox.c:138
static void update_index(struct Menu *menu, struct Context *ctx, int check, int oldcount, const struct CurrentEmail *cur)
Update the index.
Definition: index.c:607
short rows
Number of rows, can be MUTT_WIN_SIZE_UNLIMITED.
Definition: mutt_window.h:58
int top
Entry that is the top of the current page.
Definition: mutt_menu.h:75
Nondestructive flags change (IMAP)
Definition: mx.h:76
int log_queue_save(FILE *fp)
Save the contents of the queue to a temporary file.
Definition: logging.c:369
void pop_fetch_mail(void)
Fetch messages and save them in $spoolfile.
Definition: pop.c:561
int nm_read_entire_thread(struct Mailbox *m, struct Email *e)
Get the entire thread of an email.
Definition: notmuch.c:1708
const struct Mapping * help_data
Data for the Help Bar.
Definition: mutt_window.h:135
Tagged messages.
Definition: mutt.h:103
char * data
Pointer to data.
Definition: buffer.h:35
int mutt_parent_message(struct Email *e, bool find_root)
Find the parent of a message.
Definition: mutt_thread.c:1182
#define mutt_next_thread(e)
Definition: mutt_thread.h:96
void nm_db_longrun_done(struct Mailbox *m)
Finish a long transaction.
Definition: db.c:304
New messages.
Definition: mutt.h:93
Messages that have been read.
Definition: mutt.h:96
Not object-related, NotifyGlobal.
Definition: notify_type.h:40
&#39;MH&#39; Mailbox type
Definition: mailbox.h:50
bool collapsed
Is this message part of a collapsed thread?
Definition: email.h:73
bool verbose
Display status messages?
Definition: mailbox.h:118
int mx_tags_edit(struct Mailbox *m, const char *tags, char *buf, size_t buflen)
start the tag editor of the mailbox
Definition: mx.c:1289
int msg_tagged
How many messages are tagged?
Definition: mailbox.h:97
#define CHECK_READONLY
Is the mailbox readonly?
Definition: index.c:149
int vnum
Virtual message number.
Definition: email.h:88
WHERE char * C_NewMailCommand
Config: External command to run when new mail arrives.
Definition: mutt_globals.h:104
void(* custom_redraw)(struct Menu *menu)
Redraw the menu.
Definition: mutt_menu.h:121
#define SEND_NEWS
Reply to a news article.
Definition: send.h:54
void dlg_select_attachment(struct Email *e)
Show the attachments in a Menu.
Definition: recvattach.c:1547
WHERE bool OptSearchInvalid
(pseudo) used to invalidate the search pattern
Definition: options.h:52
AclFlags rights
ACL bits, see AclFlags.
Definition: mailbox.h:121
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:349
void mutt_progress_init(struct Progress *progress, const char *msg, enum ProgressType type, size_t size)
Set up a progress bar.
Definition: progress.c:153
int pagelen
Number of entries per screen.
Definition: mutt_menu.h:60
struct Notify * notify
Notifications handler.
Definition: neomutt.h:38
WHERE bool OptRedrawTree
(pseudo) redraw the thread tree
Definition: options.h:50
int mx_mbox_check(struct Mailbox *m)
Check for new mail - Wrapper for MxOps::mbox_check()
Definition: mx.c:1140
#define STAILQ_NEXT(elm, field)
Definition: queue.h:397
SecurityFlags security
bit 0-10: flags, bit 11,12: application, bit 13: traditional pgp See: ncrypt/lib.h pgplib...
Definition: email.h:39
#define SEND_REPLY
Reply to sender.
Definition: send.h:41
#define MUTT_PAGER_LOGS
Logview mode.
Definition: pager.h:57
NNTP-specific Mailbox data -.
Definition: lib.h:138
int mutt_messages_in_thread(struct Mailbox *m, struct Email *e, enum MessageInThread mit)
Count the messages in a thread.
Definition: mutt_thread.c:1476
void mutt_clear_pager_position(void)
Reset the pager&#39;s viewing position.
Definition: pager.c:1976
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:312
#define MUTT_MAILBOX_CHECK_FORCE
Definition: mutt_mailbox.h:16
int max
Number of entries in the menu.
Definition: mutt_menu.h:57
&#39;Notmuch&#39; (virtual) Mailbox type
Definition: mailbox.h:54
WHERE bool C_ArrowCursor
Config: Use an arrow &#39;->&#39; instead of highlighting in the index.
Definition: mutt_globals.h:131
int mutt_resend_message(FILE *fp, struct Context *ctx, struct Email *e_cur, struct ConfigSubset *sub)
Resend an email.
Definition: send.c:1510
bool mutt_strn_equal(const char *a, const char *b, size_t l)
Check for equality of two strings (to a maximum), safely.
Definition: string.c:593
static void set_current_email(struct CurrentEmail *cur, struct Email *e)
Keep track of the currently selected Email.
Definition: index.c:593
MuttRedrawFlags redraw
When to redraw the screen.
Definition: