NeoMutt  2020-03-20-65-g141838
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 <regex.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "mutt/lib.h"
#include "config/lib.h"
#include "email/lib.h"
#include "core/lib.h"
#include "conn/lib.h"
#include "gui/lib.h"
#include "mutt.h"
#include "debug/lib.h"
#include "index.h"
#include "alias.h"
#include "browser.h"
#include "commands.h"
#include "context.h"
#include "format_flags.h"
#include "globals.h"
#include "hdrline.h"
#include "hook.h"
#include "init.h"
#include "keymap.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 "pattern.h"
#include "progress.h"
#include "protos.h"
#include "query.h"
#include "recvattach.h"
#include "score.h"
#include "send.h"
#include "sort.h"
#include "status.h"
#include "ncrypt/lib.h"
#include "sidebar.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.

Macros

#define UNREAD(email)   mutt_thread_contains_unread(Context, email)
 
#define FLAGGED(email)   mutt_thread_contains_flagged(Context, email)
 
#define CAN_COLLAPSE(email)   ((C_CollapseUnread || !UNREAD(email)) && (C_CollapseFlagged || !FLAGGED(email)))
 
#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 struct Emailget_cur_email (struct Context *ctx, struct Menu *menu)
 Get the currently-selected Email. More...
 
static bool prereq (struct Context *ctx, struct Menu *menu, CheckFlags checks)
 Check the pre-requisites for a function. More...
 
static bool check_acl (struct Context *ctx, 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 Context *ctx, int msgno)
 Find the next undeleted email. More...
 
static int ci_previous_undeleted (struct Context *ctx, int msgno)
 Find the previous undeleted email. More...
 
static int ci_first_message (struct Context *ctx)
 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, int oldcount)
 Update the index (if unthreaded) More...
 
void update_index (struct Menu *menu, struct Context *ctx, int check, int oldcount, int index_hint)
 Update the index. More...
 
static int mailbox_index_observer (struct NotifyCallback *nc)
 Listen for Mailbox changes - Implements observer_t. More...
 
static int main_change_folder (struct Menu *menu, int op, struct Mailbox *m, char *buf, size_t buflen, int *oldcount, int *index_hint, bool *pager_return)
 Change to a different mailbox. 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...
 
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_dlg_index_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...
 
bool C_CollapseFlagged
 Config: Prevent the collapse of threads with flagged emails. More...
 
bool C_CollapseUnread
 Config: Prevent the collapse of threads with unread emails. More...
 
char * C_MarkMacroPrefix
 Config: Prefix for macros using '<mark-message>'. More...
 
bool C_PgpAutoDecode
 Config: Automatically decrypt PGP messages. 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 []
 
struct Mapping IndexNewsHelp []
 

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

◆ UNREAD

#define UNREAD (   email)    mutt_thread_contains_unread(Context, email)

Definition at line 138 of file index.c.

◆ FLAGGED

#define FLAGGED (   email)    mutt_thread_contains_flagged(Context, email)

Definition at line 139 of file index.c.

◆ CAN_COLLAPSE

#define CAN_COLLAPSE (   email)    ((C_CollapseUnread || !UNREAD(email)) && (C_CollapseFlagged || !FLAGGED(email)))

Definition at line 141 of file index.c.

◆ CHECK_NO_FLAGS

#define CHECK_NO_FLAGS   0

No flags are set.

Definition at line 149 of file index.c.

◆ CHECK_IN_MAILBOX

#define CHECK_IN_MAILBOX   (1 << 0)

Is there a mailbox open?

Definition at line 150 of file index.c.

◆ CHECK_MSGCOUNT

#define CHECK_MSGCOUNT   (1 << 1)

Are there any messages?

Definition at line 151 of file index.c.

◆ CHECK_VISIBLE

#define CHECK_VISIBLE   (1 << 2)

Is the selected message visible in the index?

Definition at line 152 of file index.c.

◆ CHECK_READONLY

#define CHECK_READONLY   (1 << 3)

Is the mailbox readonly?

Definition at line 153 of file index.c.

◆ CHECK_ATTACH

#define CHECK_ATTACH   (1 << 4)

Is the user in message-attach mode?

Definition at line 154 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 148 of file index.c.

Function Documentation

◆ get_cur_email()

static struct Email* get_cur_email ( struct Context ctx,
struct Menu menu 
)
static

Get the currently-selected Email.

Parameters
ctxContext
menuMenu
Return values
ptrEmail
NULLNo Email selected, or bad index values

Definition at line 164 of file index.c.

165 {
166  if (!ctx || !ctx->mailbox || !menu)
167  return NULL;
168 
169  return mutt_get_virt_email(ctx->mailbox, menu->current);
170 }
struct Email * mutt_get_virt_email(struct Mailbox *m, int vnum)
Get a virtual Email.
Definition: context.c:413
struct Mailbox * mailbox
Definition: context.h:51
int current
Current entry.
Definition: mutt_menu.h:87
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

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

180 {
181  bool result = true;
182 
183  if (checks & (CHECK_MSGCOUNT | CHECK_VISIBLE | CHECK_READONLY))
184  checks |= CHECK_IN_MAILBOX;
185 
186  if ((checks & CHECK_IN_MAILBOX) && (!ctx || !ctx->mailbox))
187  {
188  mutt_error(_("No mailbox is open"));
189  result = false;
190  }
191 
192  if (result && (checks & CHECK_MSGCOUNT) && (ctx->mailbox->msg_count == 0))
193  {
194  mutt_error(_("There are no messages"));
195  result = false;
196  }
197 
198  if (result && (checks & CHECK_VISIBLE) && (menu->current >= ctx->mailbox->vcount))
199  {
200  mutt_error(_("No visible messages"));
201  result = false;
202  }
203 
204  if (result && (checks & CHECK_READONLY) && ctx->mailbox->readonly)
205  {
206  mutt_error(_("Mailbox is read-only"));
207  result = false;
208  }
209 
210  if (result && (checks & CHECK_ATTACH) && OptAttachMsg)
211  {
212  mutt_error(_("Function not permitted in attach-message mode"));
213  result = false;
214  }
215 
216  if (!result)
217  mutt_flushinp();
218 
219  return result;
220 }
int msg_count
Total number of messages.
Definition: mailbox.h:91
void mutt_flushinp(void)
Empty all the keyboard buffers.
Definition: curs_lib.c:897
#define CHECK_ATTACH
Is the user in message-attach mode?
Definition: index.c:154
#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:152
struct Mailbox * mailbox
Definition: context.h:51
#define CHECK_IN_MAILBOX
Is there a mailbox open?
Definition: index.c:150
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:153
#define mutt_error(...)
Definition: logging.h:84
#define CHECK_MSGCOUNT
Are there any messages?
Definition: index.c:151
int current
Current entry.
Definition: mutt_menu.h:87
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ check_acl()

static bool check_acl ( struct Context ctx,
AclFlags  acl,
const char *  msg 
)
static

Check the ACLs for a function.

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

Definition at line 229 of file index.c.

230 {
231  if (!ctx || !ctx->mailbox)
232  return false;
233 
234  if (!(ctx->mailbox->rights & acl))
235  {
236  /* L10N: %s is one of the CHECK_ACL entries below. */
237  mutt_error(_("%s: Operation not permitted by ACL"), msg);
238  return false;
239  }
240 
241  return true;
242 }
#define _(a)
Definition: message.h:28
struct Mailbox * mailbox
Definition: context.h:51
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 256 of file index.c.

257 {
258  if (!ctx || !ctx->mailbox || (ctx->mailbox->msg_count == 0) || !menu)
259  return;
260 
261  struct Email *e_cur = get_cur_email(ctx, menu);
262  if (!e_cur)
263  return;
264 
265  struct MuttThread *thread = NULL, *top = NULL;
266  int final;
267 
268  /* Figure out what the current message would be after folding / unfolding,
269  * so that we can restore the cursor in a sane way afterwards. */
270  if (e_cur->collapsed && toggle)
271  final = mutt_uncollapse_thread(ctx, e_cur);
272  else if (CAN_COLLAPSE(e_cur))
273  final = mutt_collapse_thread(ctx, e_cur);
274  else
275  final = e_cur->vnum;
276 
277  if (final == -1)
278  return;
279 
280  struct Email *base = mutt_get_virt_email(ctx->mailbox, final);
281  if (!base)
282  return;
283 
284  /* Iterate all threads, perform collapse/uncollapse as needed */
285  top = ctx->tree;
286  ctx->collapsed = toggle ? !ctx->collapsed : true;
287  struct Email *e = NULL;
288  while ((thread = top))
289  {
290  while (!thread->message)
291  thread = thread->child;
292  e = thread->message;
293 
294  if (e->collapsed != ctx->collapsed)
295  {
296  if (e->collapsed)
297  mutt_uncollapse_thread(ctx, e);
298  else if (CAN_COLLAPSE(e))
299  mutt_collapse_thread(ctx, e);
300  }
301  top = top->next;
302  }
303 
304  /* Restore the cursor */
305  mutt_set_vnum(ctx);
306  for (int i = 0; i < ctx->mailbox->vcount; i++)
307  {
308  e = mutt_get_virt_email(ctx->mailbox, i);
309  if (!e)
310  break;
311  if (e->index == base->index)
312  {
313  menu->current = i;
314  break;
315  }
316  }
317 
319 }
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:413
void mutt_set_vnum(struct Context *ctx)
Set the virtual index number of all the messages in a mailbox.
Definition: mutt_thread.c:1197
struct MuttThread * tree
Top of thread tree.
Definition: context.h:43
#define mutt_collapse_thread(ctx, e)
Definition: mutt_thread.h:57
int vcount
The number of virtual messages.
Definition: mailbox.h:102
struct Mailbox * mailbox
Definition: context.h:51
struct MuttThread * child
Child of this Thread.
Definition: thread.h:46
#define CAN_COLLAPSE(email)
Definition: index.c:141
#define REDRAW_STATUS
Redraw the status bar.
Definition: mutt_menu.h:46
static struct Email * get_cur_email(struct Context *ctx, struct Menu *menu)
Get the currently-selected Email.
Definition: index.c:164
bool collapsed
Is this message part of a collapsed thread?
Definition: email.h:73
int vnum
Virtual message number.
Definition: email.h:87
struct Email * message
Email this Thread refers to.
Definition: thread.h:49
MuttRedrawFlags redraw
When to redraw the screen.
Definition: mutt_menu.h:89
An Email conversation.
Definition: thread.h:34
#define REDRAW_INDEX
Redraw the index.
Definition: mutt_menu.h:42
bool collapsed
Are all threads collapsed?
Definition: context.h:49
int index
The absolute (unsorted) message number.
Definition: email.h:85
int current
Current entry.
Definition: mutt_menu.h:87
#define mutt_uncollapse_thread(ctx, e)
Definition: mutt_thread.h:58
+ 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 Context ctx,
int  msgno 
)
static

Find the next undeleted email.

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

Definition at line 328 of file index.c.

329 {
330  if (!ctx || !ctx->mailbox)
331  return -1;
332 
333  for (int i = msgno + 1; i < ctx->mailbox->vcount; i++)
334  {
335  struct Email *e = mutt_get_virt_email(ctx->mailbox, i);
336  if (!e)
337  continue;
338  if (!e->deleted)
339  return i;
340  }
341  return -1;
342 }
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:413
int vcount
The number of virtual messages.
Definition: mailbox.h:102
struct Mailbox * mailbox
Definition: context.h:51
bool deleted
Email is deleted.
Definition: email.h:45
int msgno
Number displayed to the user.
Definition: email.h:86
+ 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 Context ctx,
int  msgno 
)
static

Find the previous undeleted email.

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

Definition at line 351 of file index.c.

352 {
353  if (!ctx || !ctx->mailbox)
354  return -1;
355 
356  for (int i = msgno - 1; i >= 0; i--)
357  {
358  struct Email *e = mutt_get_virt_email(ctx->mailbox, i);
359  if (!e)
360  continue;
361  if (!e->deleted)
362  return i;
363  }
364  return -1;
365 }
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:413
struct Mailbox * mailbox
Definition: context.h:51
bool deleted
Email is deleted.
Definition: email.h:45
int msgno
Number displayed to the user.
Definition: email.h:86
+ 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 Context ctx)
static

Get index of first new message.

Parameters
ctxContext
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 375 of file index.c.

376 {
377  if (!ctx || !ctx->mailbox || (ctx->mailbox->msg_count == 0))
378  return 0;
379 
380  int old = -1;
381  for (int i = 0; i < ctx->mailbox->vcount; i++)
382  {
383  struct Email *e = mutt_get_virt_email(ctx->mailbox, i);
384  if (!e)
385  continue;
386  if (!e->read && !e->deleted)
387  {
388  if (!e->old)
389  return i;
390  if (old == -1)
391  old = i;
392  }
393  }
394  if (old != -1)
395  return old;
396 
397  /* If C_Sort is reverse and not threaded, the latest message is first.
398  * If C_Sort is threaded, the latest message is first if exactly one
399  * of C_Sort and C_SortAux are reverse. */
400  if (((C_Sort & SORT_REVERSE) && ((C_Sort & SORT_MASK) != SORT_THREADS)) ||
401  (((C_Sort & SORT_MASK) == SORT_THREADS) && ((C_Sort ^ C_SortAux) & SORT_REVERSE)))
402  {
403  return 0;
404  }
405  else
406  {
407  return ctx->mailbox->vcount ? ctx->mailbox->vcount - 1 : 0;
408  }
409 
410  return 0;
411 }
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:413
int vcount
The number of virtual messages.
Definition: mailbox.h:102
bool read
Email is read.
Definition: email.h:51
struct Mailbox * mailbox
Definition: context.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:58
WHERE short C_SortAux
Config: Secondary sort method for the index.
Definition: sort.h:59
Sort by email threads.
Definition: sort2.h:56
bool deleted
Email is deleted.
Definition: email.h:45
#define SORT_REVERSE
Reverse the order of the sort.
Definition: sort2.h:86
#define SORT_MASK
Mask for the sort id.
Definition: sort2.h:85
+ 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 421 of file index.c.

422 {
423  if (!m)
424  return -1;
425 
426  if (m->readonly)
427  {
428  mutt_error(_("Can't toggle write on a readonly mailbox"));
429  return -1;
430  }
431 
432  if (m->dontwrite)
433  {
434  m->dontwrite = false;
435  mutt_message(_("Changes to folder will be written on folder exit"));
436  }
437  else
438  {
439  m->dontwrite = true;
440  mutt_message(_("Changes to folder will not be written"));
441  }
442 
443  return 0;
444 }
#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 451 of file index.c.

452 {
453  if (!ctx || !ctx->mailbox)
454  return;
455 
456  struct Email *e_cur = get_cur_email(ctx, menu);
457 
458  menu->current = -1;
459  mutt_sort_headers(ctx, false);
460  /* Restore the current message */
461 
462  for (int i = 0; i < ctx->mailbox->vcount; i++)
463  {
464  struct Email *e = mutt_get_virt_email(ctx->mailbox, i);
465  if (!e)
466  continue;
467  if (e == e_cur)
468  {
469  menu->current = i;
470  break;
471  }
472  }
473 
474  if (((C_Sort & SORT_MASK) == SORT_THREADS) && (menu->current < 0))
475  menu->current = mutt_parent_message(ctx, e_cur, false);
476 
477  if (menu->current < 0)
478  menu->current = ci_first_message(ctx);
479 
480  menu->redraw |= REDRAW_INDEX | REDRAW_STATUS;
481 }
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:413
int vcount
The number of virtual messages.
Definition: mailbox.h:102
struct Mailbox * mailbox
Definition: context.h:51
int mutt_parent_message(struct Context *ctx, struct Email *e, bool find_root)
Find the parent of a message.
Definition: mutt_thread.c:1148
WHERE short C_Sort
Config: Sort method for the index.
Definition: sort.h:58
void mutt_sort_headers(struct Context *ctx, bool init)
Sort emails by their headers.
Definition: sort.c:364
Sort by email threads.
Definition: sort2.h:56
#define REDRAW_STATUS
Redraw the status bar.
Definition: mutt_menu.h:46
static struct Email * get_cur_email(struct Context *ctx, struct Menu *menu)
Get the currently-selected Email.
Definition: index.c:164
MuttRedrawFlags redraw
When to redraw the screen.
Definition: mutt_menu.h:89
#define REDRAW_INDEX
Redraw the index.
Definition: mutt_menu.h:42
int current
Current entry.
Definition: mutt_menu.h:87
static int ci_first_message(struct Context *ctx)
Get index of first new message.
Definition: index.c:375
#define SORT_MASK
Mask for the sort id.
Definition: sort2.h:85
+ 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 489 of file index.c.

490 {
491  struct Email **save_new = NULL;
492 
493  /* save the list of new messages */
494  if ((check != MUTT_REOPENED) && oldcount && (ctx->pattern || C_UncollapseNew))
495  {
496  save_new = mutt_mem_malloc(sizeof(struct Email *) * (ctx->mailbox->msg_count - oldcount));
497  for (int i = oldcount; i < ctx->mailbox->msg_count; i++)
498  save_new[i - oldcount] = ctx->mailbox->emails[i];
499  }
500 
501  /* Sort first to thread the new messages, because some patterns
502  * require the threading information.
503  *
504  * If the mailbox was reopened, need to rethread from scratch. */
505  mutt_sort_headers(ctx, (check == MUTT_REOPENED));
506 
507  if (ctx->pattern)
508  {
509  for (int i = (check == MUTT_REOPENED) ? 0 : oldcount; i < ctx->mailbox->msg_count; i++)
510  {
511  struct Email *e = NULL;
512 
513  if ((check != MUTT_REOPENED) && oldcount)
514  e = save_new[i - oldcount];
515  else
516  e = ctx->mailbox->emails[i];
517 
519  MUTT_MATCH_FULL_ADDRESS, ctx->mailbox, e, NULL))
520  {
521  /* vnum will get properly set by mutt_set_vnum(), which
522  * is called by mutt_sort_headers() just below. */
523  e->vnum = 1;
524  e->limited = true;
525  }
526  }
527  /* Need a second sort to set virtual numbers and redraw the tree */
528  mutt_sort_headers(ctx, false);
529  }
530 
531  /* uncollapse threads with new mail */
532  if (C_UncollapseNew)
533  {
534  if (check == MUTT_REOPENED)
535  {
536  ctx->collapsed = false;
537 
538  for (struct MuttThread *h = ctx->tree; h; h = h->next)
539  {
540  struct MuttThread *j = h;
541  for (; !j->message; j = j->child)
542  ;
544  }
545  mutt_set_vnum(ctx);
546  }
547  else if (oldcount)
548  {
549  for (int j = 0; j < (ctx->mailbox->msg_count - oldcount); j++)
550  {
551  if (!ctx->pattern || save_new[j]->limited)
552  {
553  mutt_uncollapse_thread(ctx, save_new[j]);
554  }
555  }
556  mutt_set_vnum(ctx);
557  }
558  }
559 
560  FREE(&save_new);
561 }
struct Email ** emails
Array of Emails.
Definition: mailbox.h:99
struct MuttThread * next
Next sibling Thread.
Definition: thread.h:47
int msg_count
Total number of messages.
Definition: mailbox.h:91
The envelope/body of an email.
Definition: email.h:37
void mutt_set_vnum(struct Context *ctx)
Set the virtual index number of all the messages in a mailbox.
Definition: mutt_thread.c:1197
struct MuttThread * tree
Top of thread tree.
Definition: context.h:43
struct Mailbox * mailbox
Definition: context.h:51
bool limited
Is this message in a limited view?
Definition: email.h:74
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: pattern.c:2122
struct MuttThread * child
Child of this Thread.
Definition: thread.h:46
void mutt_sort_headers(struct Context *ctx, bool init)
Sort emails by their headers.
Definition: sort.c:364
#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:41
int vnum
Virtual message number.
Definition: email.h:87
struct Email * message
Email this Thread refers to.
Definition: thread.h:49
#define MUTT_MATCH_FULL_ADDRESS
Match the full address.
Definition: pattern.h:77
An Email conversation.
Definition: thread.h:34
bool collapsed
Are all threads collapsed?
Definition: context.h:49
#define FREE(x)
Definition: memory.h:40
Mailbox was reopened.
Definition: mx.h:76
char * pattern
Limit pattern string.
Definition: context.h:40
bool C_UncollapseNew
Config: Open collapsed threads when new mail arrives.
Definition: index.c:110
#define mutt_uncollapse_thread(ctx, e)
Definition: mutt_thread.h:58
+ 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,
int  oldcount 
)
static

Update the index (if unthreaded)

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

Definition at line 569 of file index.c.

570 {
571  /* We are in a limited view. Check if the new message(s) satisfy
572  * the limit criteria. If they do, set their virtual msgno so that
573  * they will be visible in the limited view */
574  if (ctx->pattern)
575  {
576  int padding = mx_msg_padding_size(ctx->mailbox);
577  for (int i = (check == MUTT_REOPENED) ? 0 : oldcount; i < ctx->mailbox->msg_count; i++)
578  {
579  if (i == 0)
580  {
581  ctx->mailbox->vcount = 0;
582  ctx->vsize = 0;
583  }
584 
585  struct Email *e = ctx->mailbox->emails[i];
586  if (!e)
587  break;
589  MUTT_MATCH_FULL_ADDRESS, ctx->mailbox, e, NULL))
590  {
591  assert(ctx->mailbox->vcount < ctx->mailbox->msg_count);
592  e->vnum = ctx->mailbox->vcount;
593  ctx->mailbox->v2r[ctx->mailbox->vcount] = i;
594  e->limited = true;
595  ctx->mailbox->vcount++;
596  struct Body *b = e->content;
597  ctx->vsize += b->length + b->offset - b->hdr_offset + padding;
598  }
599  }
600  }
601 
602  /* if the mailbox was reopened, need to rethread from scratch */
603  mutt_sort_headers(ctx, (check == MUTT_REOPENED));
604 }
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 * content
List of MIME parts.
Definition: email.h:90
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:51
bool limited
Is this message in a limited view?
Definition: email.h:74
off_t vsize
Definition: context.h:39
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: pattern.c:2122
void mutt_sort_headers(struct Context *ctx, bool init)
Sort emails by their headers.
Definition: sort.c:364
#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:41
int vnum
Virtual message number.
Definition: email.h:87
#define MUTT_MATCH_FULL_ADDRESS
Match the full address.
Definition: pattern.h:77
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:1528
long hdr_offset
Offset in stream where the headers begin.
Definition: body.h:42
Mailbox was reopened.
Definition: mx.h:76
char * pattern
Limit pattern string.
Definition: context.h:40
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ update_index()

void update_index ( struct Menu menu,
struct Context ctx,
int  check,
int  oldcount,
int  index_hint 
)

Update the index.

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

Definition at line 614 of file index.c.

615 {
616  if (!menu || !ctx)
617  return;
618 
619  /* take note of the current message */
620  if (oldcount)
621  {
622  if (menu->current < ctx->mailbox->vcount)
623  menu->oldcurrent = index_hint;
624  else
625  oldcount = 0; /* invalid message number! */
626  }
627 
628  if ((C_Sort & SORT_MASK) == SORT_THREADS)
629  update_index_threaded(ctx, check, oldcount);
630  else
631  update_index_unthreaded(ctx, check, oldcount);
632 
633  menu->current = -1;
634  if (oldcount)
635  {
636  /* restore the current message to the message it was pointing to */
637  for (int i = 0; i < ctx->mailbox->vcount; i++)
638  {
639  struct Email *e = mutt_get_virt_email(ctx->mailbox, i);
640  if (!e)
641  continue;
642  if (e->index == menu->oldcurrent)
643  {
644  menu->current = i;
645  break;
646  }
647  }
648  }
649 
650  if (menu->current < 0)
652 }
The "current" mailbox.
Definition: context.h:37
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:413
int oldcurrent
For driver use only.
Definition: mutt_menu.h:109
static void update_index_unthreaded(struct Context *ctx, int check, int oldcount)
Update the index (if unthreaded)
Definition: index.c:569
int vcount
The number of virtual messages.
Definition: mailbox.h:102
struct Mailbox * mailbox
Definition: context.h:51
WHERE short C_Sort
Config: Sort method for the index.
Definition: sort.h:58
Sort by email threads.
Definition: sort2.h:56
int index
The absolute (unsorted) message number.
Definition: email.h:85
static void update_index_threaded(struct Context *ctx, int check, int oldcount)
Update the index (if threaded)
Definition: index.c:489
int current
Current entry.
Definition: mutt_menu.h:87
static int ci_first_message(struct Context *ctx)
Get index of first new message.
Definition: index.c:375
#define SORT_MASK
Mask for the sort id.
Definition: sort2.h:85
+ 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 659 of file index.c.

660 {
661  if (!nc->global_data)
662  return -1;
663  if ((nc->event_type != NT_MAILBOX) || (nc->event_subtype != NT_MAILBOX_CLOSED))
664  return 0;
665 
666  struct Mailbox **ptr = nc->global_data;
667  if (!ptr || !*ptr)
668  return 0;
669 
670  *ptr = NULL;
671  return 0;
672 }
Mailbox was closed.
Definition: mailbox.h:170
int event_subtype
Send: Event subtype, e.g. NT_ACCOUNT_ADD.
Definition: observer.h:42
enum NotifyType event_type
Send: Event type, e.g. NT_ACCOUNT.
Definition: observer.h:41
void * global_data
Data from notify_observer_add()
Definition: observer.h:44
A mailbox.
Definition: mailbox.h:81
Mailbox has changed.
Definition: notify_type.h:38
+ Here is the caller graph for this function:

◆ main_change_folder()

static int main_change_folder ( struct Menu menu,
int  op,
struct Mailbox m,
char *  buf,
size_t  buflen,
int *  oldcount,
int *  index_hint,
bool *  pager_return 
)
static

Change to a different mailbox.

Parameters
menuCurrent Menu
mMailbox
opOperation, e.g. OP_MAIN_CHANGE_FOLDER_READONLY
bufFolder to change to
buflenLength of buffer
oldcountHow many items are currently in the index
index_hintRemember our place in the index
pager_returnReturn to the pager afterwards
Return values
0Success
-1Error

Definition at line 687 of file index.c.

690 {
691 #ifdef USE_NNTP
692  if (OptNews)
693  {
694  OptNews = false;
695  nntp_expand_path(buf, buflen, &CurrentNewsSrv->conn->account);
696  }
697  else
698 #endif
699  {
700  mx_path_canon(buf, buflen, C_Folder, NULL);
701  }
702 
703  enum MailboxType type = mx_path_probe(buf);
704  if ((type == MUTT_MAILBOX_ERROR) || (type == MUTT_UNKNOWN))
705  {
706  // Try to see if the buffer matches a description before we bail.
707  // We'll receive a non-null pointer if there is a corresponding mailbox.
708  m = mailbox_find_name(buf);
709  if (m)
710  {
711  mutt_str_strfcpy(buf, mailbox_path(m), buflen);
712  }
713  else
714  {
715  // Bail.
716  mutt_error(_("%s is not a mailbox"), buf);
717  return -1;
718  }
719  }
720 
721  /* past this point, we don't return to the pager on error */
722  if (pager_return)
723  *pager_return = false;
724 
725  /* keepalive failure in mutt_enter_fname may kill connection. */
727  ctx_free(&Context);
728 
729  if (Context && Context->mailbox)
730  {
731  char *new_last_folder = NULL;
732 #ifdef USE_INOTIFY
733  int monitor_remove_rc = mutt_monitor_remove(NULL);
734 #endif
735 #ifdef USE_COMP_MBOX
736  if (Context->mailbox->compress_info && (Context->mailbox->realpath[0] != '\0'))
737  new_last_folder = mutt_str_strdup(Context->mailbox->realpath);
738  else
739 #endif
740  new_last_folder = mutt_str_strdup(mailbox_path(Context->mailbox));
741  *oldcount = Context->mailbox->msg_count;
742 
743  int check = mx_mbox_close(&Context);
744  if (check != 0)
745  {
746 #ifdef USE_INOTIFY
747  if (monitor_remove_rc == 0)
748  mutt_monitor_add(NULL);
749 #endif
750  if ((check == MUTT_NEW_MAIL) || (check == MUTT_REOPENED))
751  update_index(menu, Context, check, *oldcount, *index_hint);
752 
753  FREE(&new_last_folder);
754  OptSearchInvalid = true;
755  menu->redraw |= REDRAW_INDEX | REDRAW_STATUS;
756  return 0;
757  }
758  FREE(&LastFolder);
759  LastFolder = new_last_folder;
760  }
762 
763  mutt_sleep(0);
764 
765  if (m)
766  {
767  /* If the `folder-hook` were to call `unmailboxes`, then the Mailbox (`m`)
768  * could be deleted, leaving `m` dangling. */
769  // TODO: Refactor this function to avoid the need for an observer
771  }
772  mutt_folder_hook(buf, m ? m->name : NULL);
773  if (m)
774  {
775  /* `m` is still valid, but we won't need the observer again before the end
776  * of the function. */
778  }
779 
781  if (C_ReadOnly || (op == OP_MAIN_CHANGE_FOLDER_READONLY))
782  flags = MUTT_READONLY;
783 #ifdef USE_NOTMUCH
784  if (op == OP_MAIN_VFOLDER_FROM_QUERY_READONLY)
785  flags = MUTT_READONLY;
786 #endif
787 
788  bool free_m = false;
789  if (!m)
790  {
791  m = mx_path_resolve(buf);
792  free_m = true;
793  }
794  Context = mx_mbox_open(m, flags);
795  if (Context)
796  {
798 #ifdef USE_INOTIFY
799  mutt_monitor_add(NULL);
800 #endif
801  }
802  else
803  {
804  menu->current = 0;
805  if (free_m)
806  mailbox_free(&m);
807  }
808 
809  if (((C_Sort & SORT_MASK) == SORT_THREADS) && C_CollapseAll)
810  collapse_all(Context, menu, 0);
811 
812 #ifdef USE_SIDEBAR
814 #endif
815 
817  mutt_mailbox_check(Context ? Context->mailbox : NULL, MUTT_MAILBOX_CHECK_FORCE); /* force the mailbox check after we have changed the folder */
818  menu->redraw = REDRAW_FULL;
819  OptSearchInvalid = true;
820 
821  return 0;
822 }
#define MUTT_OPEN_NO_FLAGS
No flags are set.
Definition: mx.h:52
The "current" mailbox.
Definition: context.h:37
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox&#39;s path string.
Definition: mailbox.h:192
#define REDRAW_FULL
Redraw everything.
Definition: mutt_menu.h:47
enum MailboxType type
Mailbox type.
Definition: mailbox.h:105
int msg_count
Total number of messages.
Definition: mailbox.h:91
struct ConnAccount account
Account details: username, password, etc.
Definition: connection.h:36
int mx_mbox_close(struct Context **ptr)
Save changes and close mailbox.
Definition: mx.c:593
int mutt_monitor_remove(struct Mailbox *m)
Remove a watch for a mailbox.
Definition: monitor.c:523
char * realpath
Used for duplicate detection, context comparison, and the sidebar.
Definition: mailbox.h:84
#define _(a)
Definition: message.h:28
Mailbox wasn&#39;t recognised.
Definition: mailbox.h:47
Error occurred examining Mailbox.
Definition: mailbox.h:46
struct Context * mx_mbox_open(struct Mailbox *m, OpenMailboxFlags flags)
Open a mailbox and parse it.
Definition: mx.c:255
WHERE char * LastFolder
Previously selected mailbox.
Definition: globals.h:55
bool C_CollapseAll
Config: Collapse all threads when entering a folder.
Definition: index.c:104
#define MUTT_READONLY
Open in read-only mode.
Definition: mx.h:55
int mutt_monitor_add(struct Mailbox *m)
Add a watch for a mailbox.
Definition: monitor.c:478
void mutt_folder_hook(const char *path, const char *desc)
Perform a folder hook.
Definition: hook.c:508
char * name
A short name for the Mailbox.
Definition: mailbox.h:85
void mutt_sleep(short s)
Sleep for a while.
Definition: muttlib.c:1535
struct Mailbox * mailbox
Definition: context.h:51
void mailbox_free(struct Mailbox **ptr)
Free a Mailbox.
Definition: mailbox.c:60
WHERE char * CurrentFolder
Currently selected mailbox.
Definition: globals.h:54
WHERE short C_Sort
Config: Sort method for the index.
Definition: sort.h:58
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:113
WHERE bool C_ReadOnly
Config: Open folders in read-only mode.
Definition: globals.h:242
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:659
Sort by email threads.
Definition: sort2.h:56
#define REDRAW_STATUS
Redraw the status bar.
Definition: mutt_menu.h:46
WHERE char * C_Folder
Config: Base folder for a set of mailboxes.
Definition: globals.h:121
struct Mailbox * mailbox_find_name(const char *name)
Find the mailbox with a given name.
Definition: mailbox.c:124
int mutt_mailbox_check(struct Mailbox *m_cur, int force)
Check all all Mailboxes for new mail.
Definition: mutt_mailbox.c:152
size_t mutt_str_strfcpy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:773
WHERE bool OptSearchInvalid
(pseudo) used to invalidate the search pattern
Definition: options.h:53
void update_index(struct Menu *menu, struct Context *ctx, int check, int oldcount, int index_hint)
Update the index.
Definition: index.c:614
void mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:453
bool notify_observer_add(struct Notify *notify, observer_t callback, void *global_data)
Add an observer to an object.
Definition: notify.c:153
#define MUTT_MAILBOX_CHECK_FORCE
Definition: mutt_mailbox.h:17
MuttRedrawFlags redraw
When to redraw the screen.
Definition: mutt_menu.h:89
struct Connection * conn
Definition: lib.h:104
enum MailboxType mx_path_probe(const char *path)
Find a mailbox that understands a path.
Definition: mx.c:1318
MailboxType
Supported mailbox formats.
Definition: mailbox.h:43
#define REDRAW_INDEX
Redraw the index.
Definition: mutt_menu.h:42
char * mutt_str_strdup(const char *str)
Copy a string, safely.
Definition: string.c:380
#define mutt_error(...)
Definition: logging.h:84
void * compress_info
Compressed mbox module private data.
Definition: mailbox.h:124
static void collapse_all(struct Context *ctx, struct Menu *menu, int toggle)
Collapse/uncollapse all threads.
Definition: index.c:256
#define FREE(x)
Definition: memory.h:40
struct Mailbox * mx_path_resolve(const char *path)
Get a Mailbox for a path.
Definition: mx.c:1655
struct NntpAccountData * CurrentNewsSrv
Current NNTP news server.
Definition: nntp.c:84
bool notify_observer_remove(struct Notify *notify, observer_t callback, void *global_data)
Remove an observer from an object.
Definition: notify.c:185
void ctx_free(struct Context **ptr)
Free a Context.
Definition: context.c:48
New mail received in Mailbox.
Definition: mx.h:74
struct Notify * notify
Notifications handler.
Definition: mailbox.h:139
int current
Current entry.
Definition: mutt_menu.h:87
struct Buffer pathbuf
Definition: mailbox.h:83
void nntp_expand_path(char *buf, size_t buflen, struct ConnAccount *acct)
Make fully qualified url from newsgroup name.
Definition: newsrc.c:563
bool mutt_buffer_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:252
Mailbox was reopened.
Definition: mx.h:76
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:1358
static int ci_first_message(struct Context *ctx)
Get index of first new message.
Definition: index.c:375
WHERE bool OptNews
(pseudo) used to change reader mode
Definition: options.h:46
#define SORT_MASK
Mask for the sort id.
Definition: sort2.h:85
+ 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 827 of file index.c.

828 {
829  if (!Context || !Context->mailbox || !menu || (line < 0) ||
830  (line >= Context->mailbox->email_max))
831  return;
832 
834  if (!e)
835  return;
836 
838  struct MuttThread *tmp = NULL;
839 
840  if (((C_Sort & SORT_MASK) == SORT_THREADS) && e->tree)
841  {
842  flags |= MUTT_FORMAT_TREE; /* display the thread tree */
843  if (e->display_subject)
844  flags |= MUTT_FORMAT_FORCESUBJ;
845  else
846  {
847  const int reverse = C_Sort & SORT_REVERSE;
848  int edgemsgno;
849  if (reverse)
850  {
851  if (menu->top + menu->pagelen > menu->max)
852  edgemsgno = Context->mailbox->v2r[menu->max - 1];
853  else
854  edgemsgno = Context->mailbox->v2r[menu->top + menu->pagelen - 1];
855  }
856  else
857  edgemsgno = Context->mailbox->v2r[menu->top];
858 
859  for (tmp = e->thread->parent; tmp; tmp = tmp->parent)
860  {
861  if (!tmp->message)
862  continue;
863 
864  /* if no ancestor is visible on current screen, provisionally force
865  * subject... */
866  if (reverse ? (tmp->message->msgno > edgemsgno) : (tmp->message->msgno < edgemsgno))
867  {
868  flags |= MUTT_FORMAT_FORCESUBJ;
869  break;
870  }
871  else if (tmp->message->vnum >= 0)
872  break;
873  }
874  if (flags & MUTT_FORMAT_FORCESUBJ)
875  {
876  for (tmp = e->thread->prev; tmp; tmp = tmp->prev)
877  {
878  if (!tmp->message)
879  continue;
880 
881  /* ...but if a previous sibling is available, don't force it */
882  if (reverse ? (tmp->message->msgno > edgemsgno) : (tmp->message->msgno < edgemsgno))
883  break;
884  else if (tmp->message->vnum >= 0)
885  {
886  flags &= ~MUTT_FORMAT_FORCESUBJ;
887  break;
888  }
889  }
890  }
891  }
892  }
893 
894  mutt_make_string_flags(buf, buflen, menu->win_index->state.cols,
895  NONULL(C_IndexFormat), Context, Context->mailbox, e, flags);
896 }
The "current" mailbox.
Definition: context.h:37
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
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:413
#define MUTT_FORMAT_FORCESUBJ
Print the subject even if unchanged.
Definition: format_flags.h:31
struct MuttThread * thread
Thread of Emails.
Definition: email.h:94
#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:51
#define MUTT_FORMAT_TREE
Draw the thread tree.
Definition: format_flags.h:32
void mutt_make_string_flags(char *buf, size_t buflen, int cols, const char *s, struct Context *ctx, struct Mailbox *m, struct Email *e, MuttFormatFlags flags)
Create formatted strings using mailbox expandos.
Definition: hdrline.c:1505
WHERE short C_Sort
Config: Sort method for the index.
Definition: sort.h:58
short cols
Number of columns, can be MUTT_WIN_SIZE_UNLIMITED.
Definition: mutt_window.h:58
Sort by email threads.
Definition: sort2.h:56
struct WindowState state
Current state of the Window.
Definition: mutt_window.h:93
int email_max
Number of pointers in emails.
Definition: mailbox.h:100
WHERE char * C_IndexFormat
Config: printf-like format string for the index menu (emails)
Definition: globals.h:114
int top
Entry that is the top of the current page.
Definition: mutt_menu.h:108
int vnum
Virtual message number.
Definition: email.h:87
int pagelen
Number of entries per screen.
Definition: mutt_menu.h:92
char * tree
Character string to print thread tree.
Definition: email.h:93
struct Email * message
Email this Thread refers to.
Definition: thread.h:49
int max
Number of entries in the menu.
Definition: mutt_menu.h:88
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
int const char int line
Definition: acutest.h:602
struct MuttWindow * win_index
Definition: mutt_menu.h:95
#define SORT_REVERSE
Reverse the order of the sort.
Definition: sort2.h:86
#define SORT_MASK
Mask for the sort id.
Definition: sort2.h:85
int msgno
Number displayed to the user.
Definition: email.h:86
+ 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 901 of file index.c.

902 {
903  if (!Context || !Context->mailbox || (line < 0))
904  return 0;
905 
907  if (!e)
908  return 0;
909 
910  if (e->pair)
911  return e->pair;
912 
914  return e->pair;
915 }
The "current" mailbox.
Definition: context.h:37
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:413
struct Mailbox * mailbox
Definition: context.h:51
void mutt_set_header_color(struct Mailbox *m, struct Email *e)
Select a colour for a message.
Definition: index.c:3954
int const char int line
Definition: acutest.h:602
int pair
Color-pair to use when displaying in the index.
Definition: email.h:79
+ 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 929 of file index.c.

930 {
931  if (!buf)
932  return;
933 
934  size_t i = 0;
935  size_t offset = 0;
936  bool found = false;
937  size_t chunks = 0;
938  size_t len = 0;
939 
940  struct StatusSyntax
941  {
942  int color;
943  int first;
944  int last;
945  } *syntax = NULL;
946 
947  if (!buf || !stdscr)
948  return;
949 
950  do
951  {
952  struct ColorLine *cl = NULL;
953  found = false;
954 
955  if (!buf[offset])
956  break;
957 
958  /* loop through each "color status regex" */
959  STAILQ_FOREACH(cl, &Colors->status_list, entries)
960  {
961  regmatch_t pmatch[cl->match + 1];
962 
963  if (regexec(&cl->regex, buf + offset, cl->match + 1, pmatch, 0) != 0)
964  continue; /* regex doesn't match the status bar */
965 
966  int first = pmatch[cl->match].rm_so + offset;
967  int last = pmatch[cl->match].rm_eo + offset;
968 
969  if (first == last)
970  continue; /* ignore an empty regex */
971 
972  if (!found)
973  {
974  chunks++;
975  mutt_mem_realloc(&syntax, chunks * sizeof(struct StatusSyntax));
976  }
977 
978  i = chunks - 1;
979  if (!found || (first < syntax[i].first) ||
980  ((first == syntax[i].first) && (last > syntax[i].last)))
981  {
982  syntax[i].color = cl->pair;
983  syntax[i].first = first;
984  syntax[i].last = last;
985  }
986  found = true;
987  }
988 
989  if (syntax)
990  {
991  offset = syntax[i].last;
992  }
993  } while (found);
994 
995  /* Only 'len' bytes will fit into 'cols' screen columns */
996  len = mutt_wstr_trunc(buf, buflen, cols, NULL);
997 
998  offset = 0;
999 
1000  if ((chunks > 0) && (syntax[0].first > 0))
1001  {
1002  /* Text before the first highlight */
1003  mutt_window_addnstr(buf, MIN(len, syntax[0].first));
1004  attrset(Colors->defs[MT_COLOR_STATUS]);
1005  if (len <= syntax[0].first)
1006  goto dsl_finish; /* no more room */
1007 
1008  offset = syntax[0].first;
1009  }
1010 
1011  for (i = 0; i < chunks; i++)
1012  {
1013  /* Highlighted text */
1014  attrset(syntax[i].color);
1015  mutt_window_addnstr(buf + offset, MIN(len, syntax[i].last) - offset);
1016  if (len <= syntax[i].last)
1017  goto dsl_finish; /* no more room */
1018 
1019  size_t next;
1020  if ((i + 1) == chunks)
1021  {
1022  next = len;
1023  }
1024  else
1025  {
1026  next = MIN(len, syntax[i + 1].first);
1027  }
1028 
1029  attrset(Colors->defs[MT_COLOR_STATUS]);
1030  offset = syntax[i].last;
1031  mutt_window_addnstr(buf + offset, next - offset);
1032 
1033  offset = next;
1034  if (offset >= len)
1035  goto dsl_finish; /* no more room */
1036  }
1037 
1038  attrset(Colors->defs[MT_COLOR_STATUS]);
1039  if (offset < len)
1040  {
1041  /* Text after the last highlight */
1042  mutt_window_addnstr(buf + offset, len - offset);
1043  }
1044 
1045  int width = mutt_strwidth(buf);
1046  if (width < cols)
1047  {
1048  /* Pad the rest of the line with whitespace */
1049  mutt_paddstr(cols - width, "");
1050  }
1051 dsl_finish:
1052  FREE(&syntax);
1053 }
struct ColorLineList status_list
List of colours applied to the status bar.
Definition: color.h:142
#define MIN(a, b)
Definition: memory.h:31
int * defs
Array of all fixed colours, see enum ColorId.
Definition: color.h:132
int pair
Colour pair index.
Definition: color.h:44
void mutt_paddstr(int n, const char *s)
Display a string on screen, padded if necessary.
Definition: curs_lib.c:1244
int match
Substring to match, 0 for old behaviour.
Definition: color.h:39
int mutt_window_addnstr(const char *str, int num)
Write a partial string to a Window.
Definition: mutt_window.c:412
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:95
int mutt_strwidth(const char *s)
Measure a string&#39;s width in screen cells.
Definition: curs_lib.c:1337
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:1287
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:349
Definition: color.h:130
LOFF_T offset
Where in the stream does this message begin?
Definition: email.h:83
regex_t regex
Compiled regex.
Definition: color.h:38
#define FREE(x)
Definition: memory.h:40
A regular expression and a color to highlight a line.
Definition: color.h:36
+ 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 1058 of file index.c.

1059 {
1060  if (menu->redraw & REDRAW_FULL)
1061  {
1062  menu_redraw_full(menu);
1063  mutt_show_error();
1064  }
1065 
1066 #ifdef USE_SIDEBAR
1067  if (menu->redraw & REDRAW_SIDEBAR)
1068  menu_redraw_sidebar(menu);
1069 #endif
1070 
1071  if (Context && Context->mailbox && Context->mailbox->emails &&
1072  !(menu->current >= Context->mailbox->vcount))
1073  {
1074  menu_check_recenter(menu);
1075 
1076  if (menu->redraw & REDRAW_INDEX)
1077  {
1078  menu_redraw_index(menu);
1079  menu->redraw |= REDRAW_STATUS;
1080  }
1081  else if (menu->redraw & (REDRAW_MOTION_RESYNC | REDRAW_MOTION))
1082  menu_redraw_motion(menu);
1083  else if (menu->redraw & REDRAW_CURRENT)
1084  menu_redraw_current(menu);
1085  }
1086 
1087  if (menu->redraw & REDRAW_STATUS)
1088  {
1089  char buf[1024];
1090  menu_status_line(buf, sizeof(buf), menu, NONULL(C_StatusFormat));
1091  mutt_window_move(menu->win_ibar, 0, 0);
1093  mutt_draw_statusline(menu->win_ibar->state.cols, buf, sizeof(buf));
1095  menu->redraw &= ~REDRAW_STATUS;
1096  if (C_TsEnabled && TsSupported)
1097  {
1098  menu_status_line(buf, sizeof(buf), menu, NONULL(C_TsStatusFormat));
1099  mutt_ts_status(buf);
1100  menu_status_line(buf, sizeof(buf), menu, NONULL(C_TsIconFormat));
1101  mutt_ts_icon(buf);
1102  }
1103  }
1104 
1105  menu->redraw = REDRAW_NO_FLAGS;
1106 }
struct Email ** emails
Array of Emails.
Definition: mailbox.h:99
The "current" mailbox.
Definition: context.h:37
WHERE char * C_TsIconFormat
Config: printf-like format string for the terminal&#39;s icon title.
Definition: globals.h:148
#define REDRAW_FULL
Redraw everything.
Definition: mutt_menu.h:47
#define NONULL(x)
Definition: string2.h:37
void mutt_curses_set_color(enum ColorId color)
Set the current colour for text.
Definition: mutt_curses.c:55
void menu_status_line(char *buf, size_t buflen, struct Menu *menu, const char *p)
Create the status line.
Definition: status.c:409
WHERE char * C_StatusFormat
Config: printf-like format string for the index&#39;s status line.
Definition: globals.h:146
WHERE bool C_TsEnabled
Config: Allow NeoMutt to set the terminal status line and icon.
Definition: globals.h:255
int vcount
The number of virtual messages.
Definition: mailbox.h:102
#define REDRAW_SIDEBAR
Redraw the sidebar.
Definition: mutt_menu.h:51
struct Mailbox * mailbox
Definition: context.h:51
struct MuttWindow * win_ibar
Definition: mutt_menu.h:96
#define REDRAW_MOTION
Redraw after moving the menu list.
Definition: mutt_menu.h:43
Plain text.
Definition: color.h:78
#define REDRAW_MOTION_RESYNC
Redraw any changing the menu selection.
Definition: mutt_menu.h:44
short cols
Number of columns, can be MUTT_WIN_SIZE_UNLIMITED.
Definition: mutt_window.h:58
struct WindowState state
Current state of the Window.
Definition: mutt_window.h:93
#define REDRAW_STATUS
Redraw the status bar.
Definition: mutt_menu.h:46
Status bar (takes a pattern)
Definition: color.h:95
bool TsSupported
Terminal Setting is supported.
Definition: terminal.c:43
int mutt_window_move(struct MuttWindow *win, int row, int col)
Move the cursor in a Window.
Definition: mutt_window.c:278
WHERE char * C_TsStatusFormat
Config: printf-like format string for the terminal&#39;s status (window title)
Definition: globals.h:147
MuttRedrawFlags redraw
When to redraw the screen.
Definition: mutt_menu.h:89
#define REDRAW_INDEX
Redraw the index.
Definition: mutt_menu.h:42
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:533
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:87
#define REDRAW_NO_FLAGS
No flags are set.
Definition: mutt_menu.h:41
void mutt_draw_statusline(int cols, const char *buf, size_t buflen)
Draw a highlighted status bar.
Definition: index.c:929
#define REDRAW_CURRENT
Redraw the current line of the menu.
Definition: mutt_menu.h:45
+ 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 1116 of file index.c.

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