NeoMutt  2020-11-20
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

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 144 of file index.c.

◆ CHECK_IN_MAILBOX

#define CHECK_IN_MAILBOX   (1 << 0)

Is there a mailbox open?

Definition at line 145 of file index.c.

◆ CHECK_MSGCOUNT

#define CHECK_MSGCOUNT   (1 << 1)

Are there any messages?

Definition at line 146 of file index.c.

◆ CHECK_VISIBLE

#define CHECK_VISIBLE   (1 << 2)

Is the selected message visible in the index?

Definition at line 147 of file index.c.

◆ CHECK_READONLY

#define CHECK_READONLY   (1 << 3)

Is the mailbox readonly?

Definition at line 148 of file index.c.

◆ CHECK_ATTACH

#define CHECK_ATTACH   (1 << 4)

Is the user in message-attach mode?

Definition at line 149 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 143 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 159 of file index.c.

160 {
161  bool result = true;
162 
163  if (checks & (CHECK_MSGCOUNT | CHECK_VISIBLE | CHECK_READONLY))
164  checks |= CHECK_IN_MAILBOX;
165 
166  if ((checks & CHECK_IN_MAILBOX) && (!ctx || !ctx->mailbox))
167  {
168  mutt_error(_("No mailbox is open"));
169  result = false;
170  }
171 
172  if (result && (checks & CHECK_MSGCOUNT) && (ctx->mailbox->msg_count == 0))
173  {
174  mutt_error(_("There are no messages"));
175  result = false;
176  }
177 
178  if (result && (checks & CHECK_VISIBLE) && (menu->current >= ctx->mailbox->vcount))
179  {
180  mutt_error(_("No visible messages"));
181  result = false;
182  }
183 
184  if (result && (checks & CHECK_READONLY) && ctx->mailbox->readonly)
185  {
186  mutt_error(_("Mailbox is read-only"));
187  result = false;
188  }
189 
190  if (result && (checks & CHECK_ATTACH) && OptAttachMsg)
191  {
192  mutt_error(_("Function not permitted in attach-message mode"));
193  result = false;
194  }
195 
196  if (!result)
197  mutt_flushinp();
198 
199  return result;
200 }
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:149
#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:147
struct Mailbox * mailbox
Definition: context.h:50
#define CHECK_IN_MAILBOX
Is there a mailbox open?
Definition: index.c:145
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:148
#define mutt_error(...)
Definition: logging.h:84
#define CHECK_MSGCOUNT
Are there any messages?
Definition: index.c:146
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 209 of file index.c.

210 {
211  if (!m)
212  return false;
213 
214  if (!(m->rights & acl))
215  {
216  /* L10N: %s is one of the CHECK_ACL entries below. */
217  mutt_error(_("%s: Operation not permitted by ACL"), msg);
218  return false;
219  }
220 
221  return true;
222 }
#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 236 of file index.c.

237 {
238  if (!ctx || !ctx->mailbox || (ctx->mailbox->msg_count == 0) || !menu)
239  return;
240 
241  struct Email *e_cur = mutt_get_virt_email(ctx->mailbox, menu->current);
242  if (!e_cur)
243  return;
244 
245  int final;
246 
247  /* Figure out what the current message would be after folding / unfolding,
248  * so that we can restore the cursor in a sane way afterwards. */
249  if (e_cur->collapsed && toggle)
250  final = mutt_uncollapse_thread(e_cur);
251  else if (mutt_thread_can_collapse(e_cur))
252  final = mutt_collapse_thread(e_cur);
253  else
254  final = e_cur->vnum;
255 
256  if (final == -1)
257  return;
258 
259  struct Email *base = mutt_get_virt_email(ctx->mailbox, final);
260  if (!base)
261  return;
262 
263  /* Iterate all threads, perform collapse/uncollapse as needed */
264  ctx->collapsed = toggle ? !ctx->collapsed : true;
266 
267  /* Restore the cursor */
268  mutt_set_vnum(ctx->mailbox);
269  for (int i = 0; i < ctx->mailbox->vcount; i++)
270  {
271  struct Email *e = mutt_get_virt_email(ctx->mailbox, i);
272  if (!e)
273  break;
274  if (e->index == base->index)
275  {
276  menu->current = i;
277  break;
278  }
279  }
280 
282 }
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:1607
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:84
#define mutt_collapse_thread(e)
Definition: mutt_thread.h:83
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:1635
+ 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 291 of file index.c.

292 {
293  if (!m)
294  return -1;
295 
296  for (int i = msgno + 1; i < m->vcount; i++)
297  {
298  struct Email *e = mutt_get_virt_email(m, i);
299  if (!e)
300  continue;
301  if (!e->deleted)
302  return i;
303  }
304  return -1;
305 }
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 314 of file index.c.

315 {
316  if (!m)
317  return -1;
318 
319  for (int i = msgno - 1; i >= 0; i--)
320  {
321  struct Email *e = mutt_get_virt_email(m, i);
322  if (!e)
323  continue;
324  if (!e->deleted)
325  return i;
326  }
327  return -1;
328 }
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 338 of file index.c.

339 {
340  if (!m || (m->msg_count == 0))
341  return 0;
342 
343  int old = -1;
344  for (int i = 0; i < m->vcount; i++)
345  {
346  struct Email *e = mutt_get_virt_email(m, i);
347  if (!e)
348  continue;
349  if (!e->read && !e->deleted)
350  {
351  if (!e->old)
352  return i;
353  if (old == -1)
354  old = i;
355  }
356  }
357  if (old != -1)
358  return old;
359 
360  /* If `$sort` is reverse and not threaded, the latest message is first.
361  * If `$sort` is threaded, the latest message is first if exactly one
362  * of `$sort` and `$sort_aux` are reverse. */
363  if (((C_Sort & SORT_REVERSE) && ((C_Sort & SORT_MASK) != SORT_THREADS)) ||
364  (((C_Sort & SORT_MASK) == SORT_THREADS) && ((C_Sort ^ C_SortAux) & SORT_REVERSE)))
365  {
366  return 0;
367  }
368  else
369  {
370  return m->vcount ? m->vcount - 1 : 0;
371  }
372 
373  return 0;
374 }
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 384 of file index.c.

385 {
386  if (!m)
387  return -1;
388 
389  if (m->readonly)
390  {
391  mutt_error(_("Can't toggle write on a readonly mailbox"));
392  return -1;
393  }
394 
395  if (m->dontwrite)
396  {
397  m->dontwrite = false;
398  mutt_message(_("Changes to folder will be written on folder exit"));
399  }
400  else
401  {
402  m->dontwrite = true;
403  mutt_message(_("Changes to folder will not be written"));
404  }
405 
406  return 0;
407 }
#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 414 of file index.c.

415 {
416  if (!ctx || !ctx->mailbox || !menu)
417  return;
418 
419  struct Email *e_cur = mutt_get_virt_email(ctx->mailbox, menu->current);
420 
421  menu->current = -1;
422  mutt_sort_headers(ctx->mailbox, ctx->threads, false, &ctx->vsize);
423  /* Restore the current message */
424 
425  for (int i = 0; i < ctx->mailbox->vcount; i++)
426  {
427  struct Email *e = mutt_get_virt_email(ctx->mailbox, i);
428  if (!e)
429  continue;
430  if (e == e_cur)
431  {
432  menu->current = i;
433  break;
434  }
435  }
436 
437  if (((C_Sort & SORT_MASK) == SORT_THREADS) && (menu->current < 0))
438  menu->current = mutt_parent_message(e_cur, false);
439 
440  if (menu->current < 0)
441  menu->current = ci_first_message(ctx->mailbox);
442 
443  menu->redraw |= REDRAW_INDEX | REDRAW_STATUS;
444 }
static int ci_first_message(struct Mailbox *m)
Get index of first new message.
Definition: index.c:338
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:366
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 452 of file index.c.

453 {
454  struct Email **save_new = NULL;
455  const bool lmt = ctx_has_limit(ctx);
456 
457  int num_new = MAX(0, ctx->mailbox->msg_count - oldcount);
458 
459  /* save the list of new messages */
460  if ((check != MUTT_REOPENED) && (oldcount > 0) && (lmt || C_UncollapseNew) && (num_new > 0))
461  {
462  save_new = mutt_mem_malloc(num_new * sizeof(struct Email *));
463  for (int i = oldcount; i < ctx->mailbox->msg_count; i++)
464  save_new[i - oldcount] = ctx->mailbox->emails[i];
465  }
466 
467  /* Sort first to thread the new messages, because some patterns
468  * require the threading information.
469  *
470  * If the mailbox was reopened, need to rethread from scratch. */
471  mutt_sort_headers(ctx->mailbox, ctx->threads, (check == MUTT_REOPENED), &ctx->vsize);
472 
473  if (lmt)
474  {
475  /* Because threading changes the order in ctx->mailbox->emails, we don't
476  * know which emails are new. Hence, we need to re-apply the limit to the
477  * whole set.
478  */
479  for (int i = 0; i < ctx->mailbox->msg_count; i++)
480  {
481  struct Email *e = ctx->mailbox->emails[i];
483  ctx->mailbox, e, NULL))
484  {
485  /* vnum will get properly set by mutt_set_vnum(), which
486  * is called by mutt_sort_headers() just below. */
487  e->vnum = 1;
488  e->visible = true;
489  }
490  else
491  {
492  e->vnum = -1;
493  e->visible = false;
494  }
495  }
496  /* Need a second sort to set virtual numbers and redraw the tree */
497  mutt_sort_headers(ctx->mailbox, ctx->threads, false, &ctx->vsize);
498  }
499 
500  /* uncollapse threads with new mail */
501  if (C_UncollapseNew)
502  {
503  if (check == MUTT_REOPENED)
504  {
505  ctx->collapsed = false;
507  mutt_set_vnum(ctx->mailbox);
508  }
509  else if (oldcount > 0)
510  {
511  for (int j = 0; j < num_new; j++)
512  {
513  if (save_new[j]->visible)
514  {
515  mutt_uncollapse_thread(save_new[j]);
516  }
517  }
518  mutt_set_vnum(ctx->mailbox);
519  }
520  }
521 
522  FREE(&save_new);
523 }
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:1607
The envelope/body of an email.
Definition: email.h:37
#define mutt_uncollapse_thread(e)
Definition: mutt_thread.h:84
void mutt_sort_headers(struct Mailbox *m, struct ThreadsContext *threads, bool init, off_t *vsize)
Sort emails by their headers.
Definition: sort.c:366
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:105
#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 530 of file index.c.

531 {
532  /* We are in a limited view. Check if the new message(s) satisfy
533  * the limit criteria. If they do, set their virtual msgno so that
534  * they will be visible in the limited view */
535  if (ctx_has_limit(ctx))
536  {
537  int padding = mx_msg_padding_size(ctx->mailbox);
538  ctx->mailbox->vcount = ctx->vsize = 0;
539  for (int i = 0; i < ctx->mailbox->msg_count; i++)
540  {
541  struct Email *e = ctx->mailbox->emails[i];
542  if (!e)
543  break;
545  MUTT_MATCH_FULL_ADDRESS, ctx->mailbox, e, NULL))
546  {
547  assert(ctx->mailbox->vcount < ctx->mailbox->msg_count);
548  e->vnum = ctx->mailbox->vcount;
549  ctx->mailbox->v2r[ctx->mailbox->vcount] = i;
550  e->visible = true;
551  ctx->mailbox->vcount++;
552  struct Body *b = e->body;
553  ctx->vsize += b->length + b->offset - b->hdr_offset + padding;
554  }
555  else
556  {
557  e->visible = false;
558  }
559  }
560  }
561 
562  /* if the mailbox was reopened, need to rethread from scratch */
563  mutt_sort_headers(ctx->mailbox, ctx->threads, (check == MUTT_REOPENED), &ctx->vsize);
564 }
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:366
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:1554
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 582 of file index.c.

583 {
584  return cur->sequence == e->sequence;
585 }
size_t sequence
Sequence number assigned on creation.
Definition: email.h:99
size_t sequence
Sequence of the current email.
Definition: index.c:572
+ 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 592 of file index.c.

593 {
594  cur->e = e;
595  cur->sequence = e ? e->sequence : 0;
596 }
struct Email * e
Current email.
Definition: index.c:571
size_t sequence
Sequence number assigned on creation.
Definition: email.h:99
size_t sequence
Sequence of the current email.
Definition: index.c:572
+ 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 606 of file index.c.

608 {
609  if (!menu || !ctx)
610  return;
611 
612  if ((C_Sort & SORT_MASK) == SORT_THREADS)
613  update_index_threaded(ctx, check, oldcount);
614  else
615  update_index_unthreaded(ctx, check);
616 
617  const int old_current = menu->current;
618  menu->current = -1;
619  if (oldcount)
620  {
621  /* restore the current message to the message it was pointing to */
622  for (int i = 0; i < ctx->mailbox->vcount; i++)
623  {
624  struct Email *e = mutt_get_virt_email(ctx->mailbox, i);
625  if (!e)
626  continue;
627  if (is_current_email(cur, e))
628  {
629  menu->current = i;
630  break;
631  }
632  }
633  }
634 
635  if (menu->current < 0)
636  menu->current = (old_current < ctx->mailbox->vcount) ?
637  old_current :
639 }
The "current" mailbox.
Definition: context.h:38
static int ci_first_message(struct Mailbox *m)
Get index of first new message.
Definition: index.c:338
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:530
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:582
static void update_index_threaded(struct Context *ctx, int check, int oldcount)
Update the index (if threaded)
Definition: index.c:452
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 651 of file index.c.

653 {
654  struct CurrentEmail se = { .e = NULL, .sequence = cur_email->sequence };
655  update_index(menu, ctx, check, oldcount, &se);
656 }
struct Email * e
Current email.
Definition: index.c:571
Keep track of the currently selected Email.
Definition: index.c:569
static void update_index(struct Menu *menu, struct Context *ctx, int check, int oldcount, const struct CurrentEmail *cur)
Update the index.
Definition: index.c:606
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 663 of file index.c.

664 {
665  if (!nc->global_data)
666  return -1;
667  if ((nc->event_type != NT_MAILBOX) || (nc->event_subtype != NT_MAILBOX_CLOSED))
668  return 0;
669 
670  struct Mailbox **ptr = nc->global_data;
671  if (!ptr || !*ptr)
672  return 0;
673 
674  *ptr = NULL;
675  return 0;
676 }
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 686 of file index.c.

688 {
689  if (!m)
690  return;
691 
692  /* keepalive failure in mutt_enter_fname may kill connection. */
694  ctx_free(&Context);
695 
696  if (Context && Context->mailbox)
697  {
698  char *new_last_folder = NULL;
699 #ifdef USE_INOTIFY
700  int monitor_remove_rc = mutt_monitor_remove(NULL);
701 #endif
702 #ifdef USE_COMP_MBOX
703  if (Context->mailbox->compress_info && (Context->mailbox->realpath[0] != '\0'))
704  new_last_folder = mutt_str_dup(Context->mailbox->realpath);
705  else
706 #endif
707  new_last_folder = mutt_str_dup(mailbox_path(Context->mailbox));
708  *oldcount = Context->mailbox->msg_count;
709 
710  int check = mx_mbox_close(&Context);
711  if (check != 0)
712  {
713 #ifdef USE_INOTIFY
714  if (monitor_remove_rc == 0)
715  mutt_monitor_add(NULL);
716 #endif
717  if ((check == MUTT_NEW_MAIL) || (check == MUTT_REOPENED))
718  update_index(menu, Context, check, *oldcount, cur);
719 
720  FREE(&new_last_folder);
721  OptSearchInvalid = true;
722  menu->redraw |= REDRAW_INDEX | REDRAW_STATUS;
723  return;
724  }
725  FREE(&LastFolder);
726  LastFolder = new_last_folder;
727  }
729 
730  /* If the `folder-hook` were to call `unmailboxes`, then the Mailbox (`m`)
731  * could be deleted, leaving `m` dangling. */
732  // TODO: Refactor this function to avoid the need for an observer
734  char *dup_path = mutt_str_dup(mailbox_path(m));
735  char *dup_name = mutt_str_dup(m->name);
736 
737  mutt_folder_hook(dup_path, dup_name);
738  if (m)
739  {
740  /* `m` is still valid, but we won't need the observer again before the end
741  * of the function. */
743  }
744  else
745  {
746  // Recreate the Mailbox (probably because a hook has done `unmailboxes *`)
747  m = mx_path_resolve(dup_path);
748  }
749  FREE(&dup_path);
750  FREE(&dup_name);
751 
752  if (!m)
753  return;
754 
755  const int flags = read_only ? MUTT_READONLY : MUTT_OPEN_NO_FLAGS;
756  Context = mx_mbox_open(m, flags);
757  if (Context)
758  {
760 #ifdef USE_INOTIFY
761  mutt_monitor_add(NULL);
762 #endif
763  }
764  else
765  {
766  menu->current = 0;
767  }
768 
769  if (((C_Sort & SORT_MASK) == SORT_THREADS) && C_CollapseAll)
770  collapse_all(Context, menu, 0);
771 
772  struct MuttWindow *dlg = dialog_find(menu->win_index);
773  struct EventMailbox em = { Context ? Context->mailbox : NULL };
775 
777  mutt_mailbox_check(Context ? Context->mailbox : NULL, MUTT_MAILBOX_CHECK_FORCE); /* force the mailbox check after we have changed the folder */
778  menu->redraw = REDRAW_FULL;
779  OptSearchInvalid = true;
780 }
#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:203
static int ci_first_message(struct Mailbox *m)
Get index of first new message.
Definition: index.c:338
#define REDRAW_FULL
Redraw everything.
Definition: mutt_menu.h:45
int msg_count
Total number of messages.
Definition: mailbox.h:91
int mx_mbox_close(struct Context **ptr)
Save changes and close mailbox.
Definition: mx.c:630
int mutt_monitor_remove(struct Mailbox *m)
Remove a watch for a mailbox.
Definition: monitor.c:524
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:102
#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:479
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
int flags
e.g. MB_NORMAL
Definition: mailbox.h:134
static int mailbox_index_observer(struct NotifyCallback *nc)
Listen for Mailbox changes - Implements observer_t.
Definition: index.c:663
Sort by email threads.
Definition: sort2.h:51
#define REDRAW_STATUS
Redraw the status bar.
Definition: mutt_menu.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:606
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
#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:236
#define FREE(x)
Definition: memory.h:40
struct Mailbox * mx_path_resolve(const char *path)
Get a Mailbox for a path.
Definition: mx.c:1681
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 792 of file index.c.

795 {
796  if (!nm_url_from_query(NULL, buf, buflen))
797  {
798  mutt_message(_("Failed to create query, aborting"));
799  return NULL;
800  }
801 
802  struct Mailbox *m_query = mx_path_resolve(buf);
803  change_folder_mailbox(menu, m_query, oldcount, cur, read_only);
804  return m_query;
805 }
#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:1681
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:686
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 818 of file index.c.

821 {
822 #ifdef USE_NNTP
823  if (OptNews)
824  {
825  OptNews = false;
826  nntp_expand_path(buf, buflen, &CurrentNewsSrv->conn->account);
827  }
828  else
829 #endif
830  {
831  mx_path_canon(buf, buflen, C_Folder, NULL);
832  }
833 
834  enum MailboxType type = mx_path_probe(buf);
835  if ((type == MUTT_MAILBOX_ERROR) || (type == MUTT_UNKNOWN))
836  {
837  // Look for a Mailbox by its description, before failing
838  struct Mailbox *m = mailbox_find_name(buf);
839  if (m)
840  {
841  change_folder_mailbox(menu, m, oldcount, cur, read_only);
842  *pager_return = false;
843  }
844  else
845  mutt_error(_("%s is not a mailbox"), buf);
846  return;
847  }
848 
849  /* past this point, we don't return to the pager on error */
850  *pager_return = false;
851 
852  struct Mailbox *m = mx_path_resolve(buf);
853  change_folder_mailbox(menu, m, oldcount, cur, read_only);
854 }
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:131
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:1335
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:1681
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:686
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:1381
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 859 of file index.c.

860 {
861  buf[0] = '\0';
862 
863  if (!Context || !Context->mailbox || !menu || (line < 0) ||
864  (line >= Context->mailbox->email_max))
865  return;
866 
867  struct Email *e = mutt_get_virt_email(Context->mailbox, line);
868  if (!e)
869  return;
870 
872  struct MuttThread *tmp = NULL;
873 
874  if (((C_Sort & SORT_MASK) == SORT_THREADS) && e->tree)
875  {
876  flags |= MUTT_FORMAT_TREE; /* display the thread tree */
877  if (e->display_subject)
878  flags |= MUTT_FORMAT_FORCESUBJ;
879  else
880  {
881  const int reverse = C_Sort & SORT_REVERSE;
882  int edgemsgno;
883  if (reverse)
884  {
885  if (menu->top + menu->pagelen > menu->max)
886  edgemsgno = Context->mailbox->v2r[menu->max - 1];
887  else
888  edgemsgno = Context->mailbox->v2r[menu->top + menu->pagelen - 1];
889  }
890  else
891  edgemsgno = Context->mailbox->v2r[menu->top];
892 
893  for (tmp = e->thread->parent; tmp; tmp = tmp->parent)
894  {
895  if (!tmp->message)
896  continue;
897 
898  /* if no ancestor is visible on current screen, provisionally force
899  * subject... */
900  if (reverse ? (tmp->message->msgno > edgemsgno) : (tmp->message->msgno < edgemsgno))
901  {
902  flags |= MUTT_FORMAT_FORCESUBJ;
903  break;
904  }
905  else if (tmp->message->vnum >= 0)
906  break;
907  }
908  if (flags & MUTT_FORMAT_FORCESUBJ)
909  {
910  for (tmp = e->thread->prev; tmp; tmp = tmp->prev)
911  {
912  if (!tmp->message)
913  continue;
914 
915  /* ...but if a previous sibling is available, don't force it */
916  if (reverse ? (tmp->message->msgno > edgemsgno) : (tmp->message->msgno < edgemsgno))
917  break;
918  else if (tmp->message->vnum >= 0)
919  {
920  flags &= ~MUTT_FORMAT_FORCESUBJ;
921  break;
922  }
923  }
924  }
925  }
926  }
927 
929  Context->mailbox, Context->msg_in_pager, e, flags);
930 }
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
#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
struct Mailbox * mailbox
Definition: context.h:50
#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
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 935 of file index.c.

936 {
937  if (!Context || !Context->mailbox || (line < 0))
938  return 0;
939 
940  struct Email *e = mutt_get_virt_email(Context->mailbox, line);
941  if (!e)
942  return 0;
943 
944  if (e->pair)
945  return e->pair;
946 
948  return e->pair;
949 }
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 * mailbox
Definition: context.h:50
void mutt_set_header_color(struct Mailbox *m, struct Email *e)
Select a colour for a message.
Definition: index.c:3956
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 963 of file index.c.

964 {
965  if (!buf || !stdscr)
966  return;
967 
968  size_t i = 0;
969  size_t offset = 0;
970  bool found = false;
971  size_t chunks = 0;
972  size_t len = 0;
973 
974  struct StatusSyntax
975  {
976  int color;
977  int first;
978  int last;
979  } *syntax = NULL;
980 
981  do
982  {
983  struct ColorLine *cl = NULL;
984  found = false;
985 
986  if (!buf[offset])
987  break;
988 
989  /* loop through each "color status regex" */
990  STAILQ_FOREACH(cl, &Colors->status_list, entries)
991  {
992  regmatch_t pmatch[cl->match + 1];
993 
994  if (regexec(&cl->regex, buf + offset, cl->match + 1, pmatch, 0) != 0)
995  continue; /* regex doesn't match the status bar */
996 
997  int first = pmatch[cl->match].rm_so + offset;
998  int last = pmatch[cl->match].rm_eo + offset;
999 
1000  if (first == last)
1001  continue; /* ignore an empty regex */
1002 
1003  if (!found)
1004  {
1005  chunks++;
1006  mutt_mem_realloc(&syntax, chunks * sizeof(struct StatusSyntax));
1007  }
1008 
1009  i = chunks - 1;
1010  if (!found || (first < syntax[i].first) ||
1011  ((first == syntax[i].first) && (last > syntax[i].last)))
1012  {
1013  syntax[i].color = cl->pair;
1014  syntax[i].first = first;
1015  syntax[i].last = last;
1016  }
1017  found = true;
1018  }
1019 
1020  if (syntax)
1021  {
1022  offset = syntax[i].last;
1023  }
1024  } while (found);
1025 
1026  /* Only 'len' bytes will fit into 'cols' screen columns */
1027  len = mutt_wstr_trunc(buf, buflen, cols, NULL);
1028 
1029  offset = 0;
1030 
1031  if ((chunks > 0) && (syntax[0].first > 0))
1032  {
1033  /* Text before the first highlight */
1034  mutt_window_addnstr(buf, MIN(len, syntax[0].first));
1035  attrset(Colors->defs[MT_COLOR_STATUS]);
1036  if (len <= syntax[0].first)
1037  goto dsl_finish; /* no more room */
1038 
1039  offset = syntax[0].first;
1040  }
1041 
1042  for (i = 0; i < chunks; i++)
1043  {
1044  /* Highlighted text */
1045  attrset(syntax[i].color);
1046  mutt_window_addnstr(buf + offset, MIN(len, syntax[i].last) - offset);
1047  if (len <= syntax[i].last)
1048  goto dsl_finish; /* no more room */
1049 
1050  size_t next;
1051  if ((i + 1) == chunks)
1052  {
1053  next = len;
1054  }
1055  else
1056  {
1057  next = MIN(len, syntax[i + 1].first);
1058  }
1059 
1060  attrset(Colors->defs[MT_COLOR_STATUS]);
1061  offset = syntax[i].last;
1062  mutt_window_addnstr(buf + offset, next - offset);
1063 
1064  offset = next;
1065  if (offset >= len)
1066  goto dsl_finish; /* no more room */
1067  }
1068 
1069  attrset(Colors->defs[MT_COLOR_STATUS]);
1070  if (offset < len)
1071  {
1072  /* Text after the last highlight */
1073  mutt_window_addnstr(buf + offset, len - offset);
1074  }
1075 
1076  int width = mutt_strwidth(buf);
1077  if (width < cols)
1078  {
1079  /* Pad the rest of the line with whitespace */
1080  mutt_paddstr(cols - width, "");
1081  }
1082 dsl_finish:
1083  FREE(&syntax);
1084 }
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 1089 of file index.c.

1090 {
1091  if (menu->redraw & REDRAW_FULL)
1092  {
1093  menu_redraw_full(menu);
1094  mutt_show_error();
1095  }
1096 
1097  struct Mailbox *m = Context ? Context->mailbox : NULL;
1098  if (m && m->emails && !(menu->current >= m->vcount))
1099  {
1100  menu_check_recenter(menu);
1101 
1102  if (menu->redraw & REDRAW_INDEX)
1103  {
1104  menu_redraw_index(menu);
1105  menu->redraw |= REDRAW_STATUS;
1106  }
1107  else if (menu->redraw & (REDRAW_MOTION_RESYNC | REDRAW_MOTION))
1108  menu_redraw_motion(menu);
1109  else if (menu->redraw & REDRAW_CURRENT)
1110  menu_redraw_current(menu);
1111  }
1112 
1113  if (menu->redraw & REDRAW_STATUS)
1114  {
1115  char buf[1024];
1116  menu_status_line(buf, sizeof(buf), menu, m, NONULL(C_StatusFormat));
1117  mutt_window_move(menu->win_ibar, 0, 0);
1119  mutt_draw_statusline(menu->win_ibar->state.cols, buf, sizeof(buf));
1121  menu->redraw &= ~REDRAW_STATUS;
1122  if (C_TsEnabled && TsSupported)
1123  {
1124  menu_status_line(buf, sizeof(buf), menu, m, NONULL(C_TsStatusFormat));
1125  mutt_ts_status(buf);
1126  menu_status_line(buf, sizeof(buf), menu, m, NONULL(C_TsIconFormat));
1127  mutt_ts_icon(buf);
1128  }
1129  }
1130 
1131  menu->redraw = REDRAW_NO_FLAGS;
1132 }
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
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 Mailbox * mailbox
Definition: context.h:50
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:421
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:963
#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 1142 of file index.c.

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