NeoMutt  2020-08-21-74-g346364
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 C_CollapseAll 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:401
#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:401
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:401
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 C_Sort is reverse and not threaded, the latest message is first.
361  * If C_Sort is threaded, the latest message is first if exactly one
362  * of C_Sort and C_SortAux 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:401
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:52
bool deleted
Email is deleted.
Definition: email.h:45
#define SORT_REVERSE
Reverse the order of the sort.
Definition: sort2.h:82
#define SORT_MASK
Mask for the sort id.
Definition: sort2.h:81
+ 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:401
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:52
#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:81
+ 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  MUTT_MATCH_FULL_ADDRESS, 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->visible = false;
493  }
494  }
495  /* Need a second sort to set virtual numbers and redraw the tree */
496  mutt_sort_headers(ctx->mailbox, ctx->threads, false, &ctx->vsize);
497  }
498 
499  /* uncollapse threads with new mail */
500  if (C_UncollapseNew)
501  {
502  if (check == MUTT_REOPENED)
503  {
504  ctx->collapsed = false;
506  mutt_set_vnum(ctx->mailbox);
507  }
508  else if (oldcount > 0)
509  {
510  for (int j = 0; j < num_new; j++)
511  {
512  if (save_new[j]->visible)
513  {
514  mutt_uncollapse_thread(save_new[j]);
515  }
516  }
517  mutt_set_vnum(ctx->mailbox);
518  }
519  }
520 
521  FREE(&save_new);
522 }
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:422
#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:694
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:92
+ 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 529 of file index.c.

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

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

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

607 {
608  if (!menu || !ctx)
609  return;
610 
611  if ((C_Sort & SORT_MASK) == SORT_THREADS)
612  update_index_threaded(ctx, check, oldcount);
613  else
614  update_index_unthreaded(ctx, check);
615 
616  const int old_current = menu->current;
617  menu->current = -1;
618  if (oldcount)
619  {
620  /* restore the current message to the message it was pointing to */
621  for (int i = 0; i < ctx->mailbox->vcount; i++)
622  {
623  struct Email *e = mutt_get_virt_email(ctx->mailbox, i);
624  if (!e)
625  continue;
626  if (is_current_email(cur, e))
627  {
628  menu->current = i;
629  break;
630  }
631  }
632  }
633 
634  if (menu->current < 0)
635  menu->current = (old_current < ctx->mailbox->vcount) ?
636  old_current :
638 }
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:401
static void update_index_unthreaded(struct Context *ctx, int check)
Update the index (if unthreaded)
Definition: index.c:529
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:52
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:581
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:81
+ 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 650 of file index.c.

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

663 {
664  if (!nc->global_data)
665  return -1;
666  if ((nc->event_type != NT_MAILBOX) || (nc->event_subtype != NT_MAILBOX_CLOSED))
667  return 0;
668 
669  struct Mailbox **ptr = nc->global_data;
670  if (!ptr || !*ptr)
671  return 0;
672 
673  *ptr = NULL;
674  return 0;
675 }
Mailbox was closed.
Definition: mailbox.h:170
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:41
+ 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 685 of file index.c.

687 {
688  if (!m)
689  return;
690 
691  /* keepalive failure in mutt_enter_fname may kill connection. */
693  ctx_free(&Context);
694 
695  if (Context && Context->mailbox)
696  {
697  char *new_last_folder = NULL;
698 #ifdef USE_INOTIFY
699  int monitor_remove_rc = mutt_monitor_remove(NULL);
700 #endif
701 #ifdef USE_COMP_MBOX
702  if (Context->mailbox->compress_info && (Context->mailbox->realpath[0] != '\0'))
703  new_last_folder = mutt_str_dup(Context->mailbox->realpath);
704  else
705 #endif
706  new_last_folder = mutt_str_dup(mailbox_path(Context->mailbox));
707  *oldcount = Context->mailbox->msg_count;
708 
709  int check = mx_mbox_close(&Context);
710  if (check != 0)
711  {
712 #ifdef USE_INOTIFY
713  if (monitor_remove_rc == 0)
714  mutt_monitor_add(NULL);
715 #endif
716  if ((check == MUTT_NEW_MAIL) || (check == MUTT_REOPENED))
717  update_index(menu, Context, check, *oldcount, cur);
718 
719  FREE(&new_last_folder);
720  OptSearchInvalid = true;
721  menu->redraw |= REDRAW_INDEX | REDRAW_STATUS;
722  return;
723  }
724  FREE(&LastFolder);
725  LastFolder = new_last_folder;
726  }
728 
729  /* If the `folder-hook` were to call `unmailboxes`, then the Mailbox (`m`)
730  * could be deleted, leaving `m` dangling. */
731  // TODO: Refactor this function to avoid the need for an observer
733  char *dup_path = mutt_str_dup(mailbox_path(m));
734 
735  mutt_folder_hook(mailbox_path(m), m ? m->name : NULL);
736  if (m)
737  {
738  /* `m` is still valid, but we won't need the observer again before the end
739  * of the function. */
741  }
742  else
743  {
744  // Recreate the Mailbox (probably because a hook has done `unmailboxes *`)
745  m = mx_path_resolve(dup_path);
746  }
747  FREE(&dup_path);
748 
749  if (!m)
750  return;
751 
752  const int flags = read_only ? MUTT_READONLY : MUTT_OPEN_NO_FLAGS;
753  Context = mx_mbox_open(m, flags);
754  if (Context)
755  {
757 #ifdef USE_INOTIFY
758  mutt_monitor_add(NULL);
759 #endif
760  }
761  else
762  {
763  menu->current = 0;
764  }
765 
766  if (((C_Sort & SORT_MASK) == SORT_THREADS) && C_CollapseAll)
767  collapse_all(Context, menu, 0);
768 
769  struct MuttWindow *dlg = dialog_find(menu->win_index);
770  struct EventMailbox em = { Context ? Context->mailbox : NULL };
772 
774  mutt_mailbox_check(Context ? Context->mailbox : NULL, MUTT_MAILBOX_CHECK_FORCE); /* force the mailbox check after we have changed the folder */
775  menu->redraw = REDRAW_FULL;
776  OptSearchInvalid = true;
777 }
#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:201
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:181
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:662
Sort by email threads.
Definition: sort2.h:52
#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:605
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:173
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:1696
Mailbox has changed, NotifyMailbox, EventMailbox.
Definition: notify_type.h:41
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:81
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 789 of file index.c.

792 {
793  if (!nm_url_from_query(NULL, buf, buflen))
794  {
795  mutt_message(_("Failed to create query, aborting"));
796  return NULL;
797  }
798 
799  struct Mailbox *m_query = mx_path_resolve(buf);
800  change_folder_mailbox(menu, m_query, oldcount, cur, read_only);
801  return m_query;
802 }
#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:1696
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:685
char * nm_url_from_query(struct Mailbox *m, char *buf, size_t buflen)
Turn a query into a URL.
Definition: notmuch.c:1767
+ 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 815 of file index.c.

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

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

933 {
934  if (!Context || !Context->mailbox || (line < 0))
935  return 0;
936 
937  struct Email *e = mutt_get_virt_email(Context->mailbox, line);
938  if (!e)
939  return 0;
940 
941  if (e->pair)
942  return e->pair;
943 
945  return e->pair;
946 }
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:401
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:3950
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 960 of file index.c.

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

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

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