NeoMutt  2019-11-11
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/mutt.h"
#include "config/lib.h"
#include "email/lib.h"
#include "core/lib.h"
#include "conn/conn.h"
#include "mutt.h"
#include "index.h"
#include "alias.h"
#include "browser.h"
#include "color.h"
#include "commands.h"
#include "context.h"
#include "curs_lib.h"
#include "format_flags.h"
#include "globals.h"
#include "hdrline.h"
#include "hook.h"
#include "keymap.h"
#include "mutt_curses.h"
#include "mutt_header.h"
#include "mutt_logging.h"
#include "mutt_mailbox.h"
#include "mutt_menu.h"
#include "mutt_thread.h"
#include "mutt_window.h"
#include "muttlib.h"
#include "mx.h"
#include "ncrypt/ncrypt.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 "terminal.h"
#include "sidebar.h"
#include "pop/pop.h"
#include "imap/imap.h"
#include "notmuch/mutt_notmuch.h"
#include "nntp/nntp.h"
#include <libintl.h>
#include "autocrypt/autocrypt.h"

Go to the source code of this file.

Macros

#define CUR_EMAIL   Context->mailbox->emails[Context->mailbox->v2r[menu->current]]
 
#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
 typedef CheckFlags - Checks to perform before running a function More...
 

Functions

static bool prereq (struct Context *ctx, struct Menu *menu, CheckFlags checks)
 Check the pre-requisites for a function. More...
 
static bool check_acl (struct Context *ctx, AclFlags acl, const char *msg)
 Check the ACLs for a function. More...
 
static void collapse_all (struct Menu *menu, int toggle)
 Collapse/uncollapse all threads. More...
 
static int ci_next_undeleted (int msgno)
 Find the next undeleted email. More...
 
static int ci_previous_undeleted (int msgno)
 Find the previous undeleted email. More...
 
static int ci_first_message (void)
 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 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...
 
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::menu_make_entry() More...
 
int index_color (int line)
 Calculate the colour for a line of the index - Implements Menu::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::menu_custom_redraw() More...
 
int mutt_index_menu (void)
 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...
 

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

◆ CUR_EMAIL

#define CUR_EMAIL   Context->mailbox->emails[Context->mailbox->v2r[menu->current]]

Definition at line 140 of file index.c.

◆ UNREAD

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

Definition at line 141 of file index.c.

◆ FLAGGED

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

Definition at line 142 of file index.c.

◆ CAN_COLLAPSE

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

Definition at line 144 of file index.c.

◆ CHECK_NO_FLAGS

#define CHECK_NO_FLAGS   0

No flags are set.

Definition at line 152 of file index.c.

◆ CHECK_IN_MAILBOX

#define CHECK_IN_MAILBOX   (1 << 0)

Is there a mailbox open?

Definition at line 153 of file index.c.

◆ CHECK_MSGCOUNT

#define CHECK_MSGCOUNT   (1 << 1)

Are there any messages?

Definition at line 154 of file index.c.

◆ CHECK_VISIBLE

#define CHECK_VISIBLE   (1 << 2)

Is the selected message visible in the index?

Definition at line 155 of file index.c.

◆ CHECK_READONLY

#define CHECK_READONLY   (1 << 3)

Is the mailbox readonly?

Definition at line 156 of file index.c.

◆ CHECK_ATTACH

#define CHECK_ATTACH   (1 << 4)

Is the user in message-attach mode?

Definition at line 157 of file index.c.

Typedef Documentation

◆ CheckFlags

typedef uint8_t CheckFlags

typedef CheckFlags - Checks to perform before running a function

Flags, e.g. CHECK_IN_MAILBOX

Definition at line 151 of file index.c.

Function Documentation

◆ prereq()

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

Check the pre-requisites for a function.

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

Definition at line 167 of file index.c.

168 {
169  bool result = true;
170 
171  if (checks & (CHECK_MSGCOUNT | CHECK_VISIBLE | CHECK_READONLY))
172  checks |= CHECK_IN_MAILBOX;
173 
174  if ((checks & CHECK_IN_MAILBOX) && (!ctx || !ctx->mailbox))
175  {
176  mutt_error(_("No mailbox is open"));
177  result = false;
178  }
179 
180  if (result && (checks & CHECK_MSGCOUNT) && (ctx->mailbox->msg_count == 0))
181  {
182  mutt_error(_("There are no messages"));
183  result = false;
184  }
185 
186  if (result && (checks & CHECK_VISIBLE) && (menu->current >= ctx->mailbox->vcount))
187  {
188  mutt_error(_("No visible messages"));
189  result = false;
190  }
191 
192  if (result && (checks & CHECK_READONLY) && ctx->mailbox->readonly)
193  {
194  mutt_error(_("Mailbox is read-only"));
195  result = false;
196  }
197 
198  if (result && (checks & CHECK_ATTACH) && OptAttachMsg)
199  {
200  mutt_error(_("Function not permitted in attach-message mode"));
201  result = false;
202  }
203 
204  if (!result)
205  mutt_flushinp();
206 
207  return result;
208 }
int msg_count
Total number of messages.
Definition: mailbox.h:102
void mutt_flushinp(void)
Empty all the keyboard buffers.
Definition: curs_lib.c:848
#define CHECK_ATTACH
Is the user in message-attach mode?
Definition: index.c:157
#define _(a)
Definition: message.h:28
int vcount
The number of virtual messages.
Definition: mailbox.h:113
#define CHECK_VISIBLE
Is the selected message visible in the index?
Definition: index.c:155
struct Mailbox * mailbox
Definition: context.h:50
#define CHECK_IN_MAILBOX
Is there a mailbox open?
Definition: index.c:153
bool readonly
Don&#39;t allow changes to the mailbox.
Definition: mailbox.h:130
WHERE bool OptAttachMsg
(pseudo) used by attach-message
Definition: options.h:31
#define CHECK_READONLY
Is the mailbox readonly?
Definition: index.c:156
#define mutt_error(...)
Definition: logging.h:84
#define CHECK_MSGCOUNT
Are there any messages?
Definition: index.c:154
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 217 of file index.c.

218 {
219  if (!ctx || !ctx->mailbox)
220  return false;
221 
222  if (!(ctx->mailbox->rights & acl))
223  {
224  /* L10N: %s is one of the CHECK_ACL entries below. */
225  mutt_error(_("%s: Operation not permitted by ACL"), msg);
226  return false;
227  }
228 
229  return true;
230 }
#define _(a)
Definition: message.h:28
struct Mailbox * mailbox
Definition: context.h:50
AclFlags rights
ACL bits, see AclFlags.
Definition: mailbox.h:132
#define mutt_error(...)
Definition: logging.h:84
+ Here is the caller graph for this function:

◆ collapse_all()

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

Collapse/uncollapse all threads.

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

244 {
245  struct Email *e = NULL, *base = NULL;
246  struct MuttThread *thread = NULL, *top = NULL;
247  int final;
248 
249  if (!Context || !Context->mailbox || (Context->mailbox->msg_count == 0))
250  return;
251 
252  /* Figure out what the current message would be after folding / unfolding,
253  * so that we can restore the cursor in a sane way afterwards. */
254  if (CUR_EMAIL->collapsed && toggle)
256  else if (CAN_COLLAPSE(CUR_EMAIL))
258  else
259  final = CUR_EMAIL->vnum;
260 
261  if (final == -1)
262  return;
263 
264  base = Context->mailbox->emails[Context->mailbox->v2r[final]];
265 
266  /* Iterate all threads, perform collapse/uncollapse as needed */
267  top = Context->tree;
268  Context->collapsed = toggle ? !Context->collapsed : true;
269  while ((thread = top))
270  {
271  while (!thread->message)
272  thread = thread->child;
273  e = thread->message;
274 
275  if (e->collapsed != Context->collapsed)
276  {
277  if (e->collapsed)
279  else if (CAN_COLLAPSE(e))
281  }
282  top = top->next;
283  }
284 
285  /* Restore the cursor */
287  for (int j = 0; j < Context->mailbox->vcount; j++)
288  {
289  if (Context->mailbox->emails[Context->mailbox->v2r[j]]->index == base->index)
290  {
291  menu->current = j;
292  break;
293  }
294  }
295 
297 }
struct Email ** emails
Array of Emails.
Definition: mailbox.h:110
The "current" mailbox.
Definition: context.h:36
int msg_count
Total number of messages.
Definition: mailbox.h:102
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:1183
struct MuttThread * tree
Top of thread tree.
Definition: context.h:42
#define mutt_collapse_thread(ctx, e)
Definition: mutt_thread.h:57
int vcount
The number of virtual messages.
Definition: mailbox.h:113
struct Mailbox * mailbox
Definition: context.h:50
#define CUR_EMAIL
Definition: index.c:140
struct MuttThread * child
Child of this Thread.
Definition: thread.h:46
#define CAN_COLLAPSE(email)
Definition: index.c:144
#define REDRAW_STATUS
Redraw the status bar.
Definition: mutt_menu.h:46
bool collapsed
Is this message part of a collapsed thread?
Definition: email.h:73
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
int * v2r
Mapping from virtual to real msgno.
Definition: mailbox.h:112
#define REDRAW_INDEX
Redraw the index.
Definition: mutt_menu.h:42
bool collapsed
Are all threads collapsed?
Definition: context.h:48
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 ( int  msgno)
static

Find the next undeleted email.

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

Definition at line 305 of file index.c.

306 {
307  if (!Context || !Context->mailbox)
308  return -1;
309 
310  for (int i = msgno + 1; i < Context->mailbox->vcount; i++)
312  return i;
313  return -1;
314 }
struct Email ** emails
Array of Emails.
Definition: mailbox.h:110
The "current" mailbox.
Definition: context.h:36
int vcount
The number of virtual messages.
Definition: mailbox.h:113
struct Mailbox * mailbox
Definition: context.h:50
int * v2r
Mapping from virtual to real msgno.
Definition: mailbox.h:112
bool deleted
Email is deleted.
Definition: email.h:45
+ Here is the caller graph for this function:

◆ ci_previous_undeleted()

static int ci_previous_undeleted ( int  msgno)
static

Find the previous undeleted email.

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

Definition at line 322 of file index.c.

323 {
324  if (!Context || !Context->mailbox)
325  return -1;
326 
327  for (int i = msgno - 1; i >= 0; i--)
329  return i;
330  return -1;
331 }
struct Email ** emails
Array of Emails.
Definition: mailbox.h:110
The "current" mailbox.
Definition: context.h:36
struct Mailbox * mailbox
Definition: context.h:50
int * v2r
Mapping from virtual to real msgno.
Definition: mailbox.h:112
bool deleted
Email is deleted.
Definition: email.h:45
+ Here is the caller graph for this function:

◆ ci_first_message()

static int ci_first_message ( void  )
static

Get index of first new message.

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

341 {
342  if (!Context || !Context->mailbox || (Context->mailbox->msg_count == 0))
343  return 0;
344 
345  int old = -1;
346  for (int i = 0; i < Context->mailbox->vcount; i++)
347  {
348  if (!Context->mailbox->emails[Context->mailbox->v2r[i]]->read &&
350  {
351  if (!Context->mailbox->emails[Context->mailbox->v2r[i]]->old)
352  return i;
353  if (old == -1)
354  old = i;
355  }
356  }
357  if (old != -1)
358  return old;
359 
360  /* If C_Sort is reverse and not threaded, the latest message is first.
361  * If C_Sort is threaded, the latest message is first if exactly one
362  * of C_Sort and C_SortAux are reverse. */
363  if (((C_Sort & SORT_REVERSE) && ((C_Sort & SORT_MASK) != SORT_THREADS)) ||
364  (((C_Sort & SORT_MASK) == SORT_THREADS) && ((C_Sort ^ C_SortAux) & SORT_REVERSE)))
365  {
366  return 0;
367  }
368  else
369  {
370  return Context->mailbox->vcount ? Context->mailbox->vcount - 1 : 0;
371  }
372 
373  return 0;
374 }
struct Email ** emails
Array of Emails.
Definition: mailbox.h:110
The "current" mailbox.
Definition: context.h:36
int msg_count
Total number of messages.
Definition: mailbox.h:102
int vcount
The number of virtual messages.
Definition: mailbox.h:113
bool read
Email is read.
Definition: email.h:51
struct Mailbox * mailbox
Definition: context.h:50
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
int * v2r
Mapping from virtual to real msgno.
Definition: mailbox.h:112
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 caller graph for this function:

◆ mx_toggle_write()

static int mx_toggle_write ( struct Mailbox m)
static

Toggle the mailbox's readonly flag.

Parameters
mMailbox
Return values
0Success
-1Error

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

Definition at line 384 of file index.c.

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

◆ resort_index()

static void resort_index ( struct Menu menu)
static

Resort the index.

Parameters
menuCurrent Menu

Definition at line 413 of file index.c.

414 {
415  if (!Context || !Context->mailbox)
416  return;
417 
418  struct Email *e = CUR_EMAIL;
419 
420  menu->current = -1;
421  mutt_sort_headers(Context, false);
422  /* Restore the current message */
423 
424  for (int i = 0; i < Context->mailbox->vcount; i++)
425  {
426  if (Context->mailbox->emails[Context->mailbox->v2r[i]] == e)
427  {
428  menu->current = i;
429  break;
430  }
431  }
432 
433  if (((C_Sort & SORT_MASK) == SORT_THREADS) && (menu->current < 0))
434  menu->current = mutt_parent_message(Context, e, false);
435 
436  if (menu->current < 0)
437  menu->current = ci_first_message();
438 
439  menu->redraw |= REDRAW_INDEX | REDRAW_STATUS;
440 }
struct Email ** emails
Array of Emails.
Definition: mailbox.h:110
The "current" mailbox.
Definition: context.h:36
The envelope/body of an email.
Definition: email.h:37
int vcount
The number of virtual messages.
Definition: mailbox.h:113
struct Mailbox * mailbox
Definition: context.h:50
int mutt_parent_message(struct Context *ctx, struct Email *e, bool find_root)
Find the parent of a message.
Definition: mutt_thread.c:1137
#define CUR_EMAIL
Definition: index.c:140
WHERE short C_Sort
Config: Sort method for the index.
Definition: sort.h:58
static int ci_first_message(void)
Get index of first new message.
Definition: index.c:340
void mutt_sort_headers(struct Context *ctx, bool init)
Sort emails by their headers.
Definition: sort.c:362
Sort by email threads.
Definition: sort2.h:56
#define REDRAW_STATUS
Redraw the status bar.
Definition: mutt_menu.h:46
MuttRedrawFlags redraw
When to redraw the screen.
Definition: mutt_menu.h:89
int * v2r
Mapping from virtual to real msgno.
Definition: mailbox.h:112
#define REDRAW_INDEX
Redraw the index.
Definition: mutt_menu.h:42
int current
Current entry.
Definition: mutt_menu.h:87
#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 448 of file index.c.

449 {
450  struct Email **save_new = NULL;
451 
452  /* save the list of new messages */
453  if ((check != MUTT_REOPENED) && oldcount && (ctx->pattern || C_UncollapseNew))
454  {
455  save_new = mutt_mem_malloc(sizeof(struct Email *) * (ctx->mailbox->msg_count - oldcount));
456  for (int i = oldcount; i < ctx->mailbox->msg_count; i++)
457  save_new[i - oldcount] = ctx->mailbox->emails[i];
458  }
459 
460  /* Sort first to thread the new messages, because some patterns
461  * require the threading information.
462  *
463  * If the mailbox was reopened, need to rethread from scratch. */
464  mutt_sort_headers(ctx, (check == MUTT_REOPENED));
465 
466  if (ctx->pattern)
467  {
468  for (int i = (check == MUTT_REOPENED) ? 0 : oldcount; i < ctx->mailbox->msg_count; i++)
469  {
470  struct Email *e = NULL;
471 
472  if ((check != MUTT_REOPENED) && oldcount)
473  e = save_new[i - oldcount];
474  else
475  e = ctx->mailbox->emails[i];
476 
478  MUTT_MATCH_FULL_ADDRESS, ctx->mailbox, e, NULL))
479  {
480  /* vnum will get properly set by mutt_set_vnum(), which
481  * is called by mutt_sort_headers() just below. */
482  e->vnum = 1;
483  e->limited = true;
484  }
485  }
486  /* Need a second sort to set virtual numbers and redraw the tree */
487  mutt_sort_headers(ctx, false);
488  }
489 
490  /* uncollapse threads with new mail */
491  if (C_UncollapseNew)
492  {
493  if (check == MUTT_REOPENED)
494  {
495  ctx->collapsed = false;
496 
497  for (struct MuttThread *h = ctx->tree; h; h = h->next)
498  {
499  struct MuttThread *j = h;
500  for (; !j->message; j = j->child)
501  ;
503  }
504  mutt_set_vnum(ctx);
505  }
506  else if (oldcount)
507  {
508  for (int j = 0; j < (ctx->mailbox->msg_count - oldcount); j++)
509  {
510  if (!ctx->pattern || save_new[j]->limited)
511  {
512  mutt_uncollapse_thread(ctx, save_new[j]);
513  }
514  }
515  mutt_set_vnum(ctx);
516  }
517  }
518 
519  FREE(&save_new);
520 }
struct Email ** emails
Array of Emails.
Definition: mailbox.h:110
struct MuttThread * next
Next sibling Thread.
Definition: thread.h:47
int msg_count
Total number of messages.
Definition: mailbox.h:102
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:1183
struct MuttThread * tree
Top of thread tree.
Definition: context.h:42
struct Mailbox * mailbox
Definition: context.h:50
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:2001
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:362
#define SLIST_FIRST(head)
Definition: queue.h:229
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:40
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:75
An Email conversation.
Definition: thread.h:34
bool collapsed
Are all threads collapsed?
Definition: context.h:48
#define FREE(x)
Definition: memory.h:40
Mailbox was reopened.
Definition: mx.h:74
char * pattern
Limit pattern string.
Definition: context.h:39
bool C_UncollapseNew
Config: Open collapsed threads when new mail arrives.
Definition: index.c:112
#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 528 of file index.c.

529 {
530  /* We are in a limited view. Check if the new message(s) satisfy
531  * the limit criteria. If they do, set their virtual msgno so that
532  * they will be visible in the limited view */
533  if (ctx->pattern)
534  {
535  int padding = mx_msg_padding_size(ctx->mailbox);
536  for (int i = (check == MUTT_REOPENED) ? 0 : oldcount; i < ctx->mailbox->msg_count; i++)
537  {
538  if (i == 0)
539  {
540  ctx->mailbox->vcount = 0;
541  ctx->vsize = 0;
542  }
543 
545  ctx->mailbox, ctx->mailbox->emails[i], NULL))
546  {
547  assert(ctx->mailbox->vcount < ctx->mailbox->msg_count);
548  ctx->mailbox->emails[i]->vnum = ctx->mailbox->vcount;
549  ctx->mailbox->v2r[ctx->mailbox->vcount] = i;
550  ctx->mailbox->emails[i]->limited = true;
551  ctx->mailbox->vcount++;
552  struct Body *b = ctx->mailbox->emails[i]->content;
553  ctx->vsize += b->length + b->offset - b->hdr_offset + padding;
554  }
555  }
556  }
557 
558  /* if the mailbox was reopened, need to rethread from scratch */
559  mutt_sort_headers(ctx, (check == MUTT_REOPENED));
560 }
struct Email ** emails
Array of Emails.
Definition: mailbox.h:110
int msg_count
Total number of messages.
Definition: mailbox.h:102
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:113
The body of an email.
Definition: body.h:34
struct Mailbox * mailbox
Definition: context.h:50
bool limited
Is this message in a limited view?
Definition: email.h:74
off_t vsize
Definition: context.h:38
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:2001
void mutt_sort_headers(struct Context *ctx, bool init)
Sort emails by their headers.
Definition: sort.c:362
#define SLIST_FIRST(head)
Definition: queue.h:229
LOFF_T length
length (in bytes) of attachment
Definition: body.h:45
struct PatternList * limit_pattern
Compiled limit pattern.
Definition: context.h:40
int vnum
Virtual message number.
Definition: email.h:87
#define MUTT_MATCH_FULL_ADDRESS
Match the full address.
Definition: pattern.h:75
int * v2r
Mapping from virtual to real msgno.
Definition: mailbox.h:112
int mx_msg_padding_size(struct Mailbox *m)
Bytes of padding between messages - Wrapper for MxOps::msg_padding_size()
Definition: mx.c:1475
long hdr_offset
Offset in stream where the headers begin.
Definition: body.h:42
Mailbox was reopened.
Definition: mx.h:74
char * pattern
Limit pattern string.
Definition: context.h:39
+ 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 570 of file index.c.

571 {
572  if (!menu || !ctx)
573  return;
574 
575  /* take note of the current message */
576  if (oldcount)
577  {
578  if (menu->current < ctx->mailbox->vcount)
579  menu->oldcurrent = index_hint;
580  else
581  oldcount = 0; /* invalid message number! */
582  }
583 
584  if ((C_Sort & SORT_MASK) == SORT_THREADS)
585  update_index_threaded(ctx, check, oldcount);
586  else
587  update_index_unthreaded(ctx, check, oldcount);
588 
589  menu->current = -1;
590  if (oldcount)
591  {
592  /* restore the current message to the message it was pointing to */
593  for (int i = 0; i < ctx->mailbox->vcount; i++)
594  {
595  if (ctx->mailbox->emails[ctx->mailbox->v2r[i]]->index == menu->oldcurrent)
596  {
597  menu->current = i;
598  break;
599  }
600  }
601  }
602 
603  if (menu->current < 0)
604  menu->current = ci_first_message();
605 }
struct Email ** emails
Array of Emails.
Definition: mailbox.h:110
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:528
int vcount
The number of virtual messages.
Definition: mailbox.h:113
struct Mailbox * mailbox
Definition: context.h:50
WHERE short C_Sort
Config: Sort method for the index.
Definition: sort.h:58
static int ci_first_message(void)
Get index of first new message.
Definition: index.c:340
Sort by email threads.
Definition: sort2.h:56
int * v2r
Mapping from virtual to real msgno.
Definition: mailbox.h:112
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:448
int current
Current entry.
Definition: mutt_menu.h:87
#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()

int mailbox_index_observer ( struct NotifyCallback nc)

Listen for Mailbox changes - Implements observer_t()

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

Definition at line 612 of file index.c.

613 {
614  if (!nc)
615  return -1;
616 
617  if ((nc->event_type != NT_MAILBOX) || (nc->event_subtype != MBN_CLOSED))
618  return 0;
619 
620  struct Mailbox **ptr = (struct Mailbox **) nc->data;
621  if (!ptr || !*ptr)
622  return 0;
623 
624  *ptr = NULL;
625  return 0;
626 }
intptr_t data
Observer: private to observer.
Definition: observer.h:48
Mailbox was closed.
Definition: mailbox.h:63
int event_subtype
Send: event subtype.
Definition: observer.h:45
int event_type
Send: event type.
Definition: observer.h:44
A mailbox.
Definition: mailbox.h:92
Mailbox has changed.
Definition: notify_type.h:35
+ 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 641 of file index.c.

644 {
645 #ifdef USE_NNTP
646  if (OptNews)
647  {
648  OptNews = false;
649  nntp_expand_path(buf, buflen, &CurrentNewsSrv->conn->account);
650  }
651  else
652 #endif
653  {
654  mx_path_canon(buf, buflen, C_Folder, NULL);
655  }
656 
657  enum MailboxType magic = mx_path_probe(buf, NULL);
658  if ((magic == MUTT_MAILBOX_ERROR) || (magic == MUTT_UNKNOWN))
659  {
660  // Try to see if the buffer matches a description before we bail.
661  // We'll receive a non-null pointer if there is a corresponding mailbox.
662  m = mailbox_find_name(buf);
663  if (m)
664  {
665  mutt_str_strfcpy(buf, mailbox_path(m), buflen);
666  }
667  else
668  {
669  // Bail.
670  mutt_error(_("%s is not a mailbox"), buf);
671  return -1;
672  }
673  }
674 
675  /* past this point, we don't return to the pager on error */
676  if (pager_return)
677  *pager_return = false;
678 
679  /* keepalive failure in mutt_enter_fname may kill connection. */
681  ctx_free(&Context);
682 
683  if (Context && Context->mailbox)
684  {
685  char *new_last_folder = NULL;
686 #ifdef USE_INOTIFY
687  int monitor_remove_rc = mutt_monitor_remove(NULL);
688 #endif
689 #ifdef USE_COMPRESSED
690  if (Context->mailbox->compress_info && (Context->mailbox->realpath[0] != '\0'))
691  new_last_folder = mutt_str_strdup(Context->mailbox->realpath);
692  else
693 #endif
694  new_last_folder = mutt_str_strdup(mailbox_path(Context->mailbox));
695  *oldcount = Context->mailbox->msg_count;
696 
697  int check = mx_mbox_close(&Context);
698  if (check != 0)
699  {
700 #ifdef USE_INOTIFY
701  if (monitor_remove_rc == 0)
702  mutt_monitor_add(NULL);
703 #endif
704  if ((check == MUTT_NEW_MAIL) || (check == MUTT_REOPENED))
705  update_index(menu, Context, check, *oldcount, *index_hint);
706 
707  FREE(&new_last_folder);
708  OptSearchInvalid = true;
709  menu->redraw |= REDRAW_INDEX | REDRAW_STATUS;
710  return 0;
711  }
712  FREE(&LastFolder);
713  LastFolder = new_last_folder;
714  }
716 
717  mutt_sleep(0);
718 
719  if (m)
720  {
721  /* If the `folder-hook` were to call `unmailboxes`, then the Mailbox (`m`)
722  * could be deleted, leaving `m` dangling. */
723  // TODO: Refactor this function to avoid the need for an observer
725  }
726  mutt_folder_hook(buf, m ? m->name : NULL);
727  if (m)
728  {
729  /* `m` is still valid, but we won't need the observer again before the end
730  * of the function. */
732  }
733 
735  if (C_ReadOnly || (op == OP_MAIN_CHANGE_FOLDER_READONLY))
736  flags = MUTT_READONLY;
737 #ifdef USE_NOTMUCH
738  if (op == OP_MAIN_VFOLDER_FROM_QUERY_READONLY)
739  flags = MUTT_READONLY;
740 #endif
741 
742  bool free_m = false;
743  if (!m)
744  {
745  m = mx_path_resolve(buf);
746  free_m = true;
747  }
748  Context = mx_mbox_open(m, flags);
749  if (Context)
750  {
751  menu->current = ci_first_message();
752 #ifdef USE_INOTIFY
753  mutt_monitor_add(NULL);
754 #endif
755  }
756  else
757  {
758  menu->current = 0;
759  if (free_m)
760  mailbox_free(&m);
761  }
762 
763  if (((C_Sort & SORT_MASK) == SORT_THREADS) && C_CollapseAll)
764  collapse_all(menu, 0);
765 
766 #ifdef USE_SIDEBAR
768 #endif
769 
771  mutt_mailbox_check(Context ? Context->mailbox : NULL, MUTT_MAILBOX_CHECK_FORCE); /* force the mailbox check after we have changed the folder */
772  menu->redraw = REDRAW_FULL;
773  OptSearchInvalid = true;
774 
775  return 0;
776 }
#define MUTT_OPEN_NO_FLAGS
No flags are set.
Definition: mx.h:50
The "current" mailbox.
Definition: context.h:36
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox&#39;s path string.
Definition: mailbox.h:194
#define REDRAW_FULL
Redraw everything.
Definition: mutt_menu.h:47
int msg_count
Total number of messages.
Definition: mailbox.h:102
struct ConnAccount account
Definition: connection.h:36
int mx_mbox_close(struct Context **ptr)
Save changes and close mailbox.
Definition: mx.c:561
int mx_path_canon(char *buf, size_t buflen, const char *folder, enum MailboxType *magic)
Canonicalise a mailbox path - Wrapper for MxOps::path_canon()
Definition: mx.c:1308
int mutt_monitor_remove(struct Mailbox *m)
Remove a watch for a mailbox.
Definition: monitor.c:521
char * realpath
Used for duplicate detection, context comparison, and the sidebar.
Definition: mailbox.h:95
#define _(a)
Definition: message.h:28
Mailbox wasn&#39;t recognised.
Definition: mailbox.h:46
Error occurred examining Mailbox.
Definition: mailbox.h:45
struct Context * mx_mbox_open(struct Mailbox *m, OpenMailboxFlags flags)
Open a mailbox and parse it.
Definition: mx.c:253
WHERE char * LastFolder
Previously selected mailbox.
Definition: globals.h:57
bool C_CollapseAll
Config: Collapse all threads when entering a folder.
Definition: index.c:106
#define MUTT_READONLY
Open in read-only mode.
Definition: mx.h:53
int mutt_monitor_add(struct Mailbox *m)
Add a watch for a mailbox.
Definition: monitor.c:476
static void collapse_all(struct Menu *menu, int toggle)
Collapse/uncollapse all threads.
Definition: index.c:243
int mailbox_index_observer(struct NotifyCallback *nc)
Listen for Mailbox changes - Implements observer_t()
Definition: index.c:612
void mutt_folder_hook(const char *path, const char *desc)
Perform a folder hook.
Definition: hook.c:502
bool notify_observer_remove(struct Notify *notify, observer_t callback, intptr_t data)
Remove an observer from an object.
Definition: notify.c:194
char * name
A short name for the Mailbox.
Definition: mailbox.h:96
bool notify_observer_add(struct Notify *notify, enum NotifyType type, int subtype, observer_t callback, intptr_t data)
Add an observer to an object.
Definition: notify.c:159
void mutt_sleep(short s)
Sleep for a while.
Definition: muttlib.c:1546
struct Mailbox * mailbox
Definition: context.h:50
void mailbox_free(struct Mailbox **ptr)
Free a Mailbox.
Definition: mailbox.c:55
enum MailboxType magic
Mailbox type.
Definition: mailbox.h:116
WHERE char * CurrentFolder
Currently selected mailbox.
Definition: globals.h:56
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:115
WHERE bool C_ReadOnly
Config: Open folders in read-only mode.
Definition: globals.h:250
int flags
e.g. MB_NORMAL
Definition: mailbox.h:145
static int ci_first_message(void)
Get index of first new message.
Definition: index.c:340
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:115
int mutt_mailbox_check(struct Mailbox *m_cur, int force)
Check all all Mailboxes for new mail.
Definition: mutt_mailbox.c:127
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:750
WHERE bool OptSearchInvalid
(pseudo) used to invalidate the search pat
Definition: options.h:50
void update_index(struct Menu *menu, struct Context *ctx, int check, int oldcount, int index_hint)
Update the index.
Definition: index.c:570
void mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:453
void nntp_expand_path(char *buf, size_t buflen, struct ConnAccount *acct)
Make fully qualified url from newsgroup name.
Definition: newsrc.c:551
#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: nntp.h:102
MailboxType
Supported mailbox formats.
Definition: mailbox.h:42
#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:135
#define IP
Definition: set.h:144
#define FREE(x)
Definition: memory.h:40
struct Mailbox * mx_path_resolve(const char *path)
XXX.
Definition: mx.c:1552
Mailbox has changed.
Definition: notify_type.h:35
void ctx_free(struct Context **ptr)
Free a Context.
Definition: context.c:49
New mail received in Mailbox.
Definition: mx.h:72
struct Notify * notify
Notifications handler.
Definition: mailbox.h:150
int current
Current entry.
Definition: mutt_menu.h:87
struct Buffer pathbuf
Definition: mailbox.h:94
bool mutt_buffer_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:252
enum MailboxType mx_path_probe(const char *path, struct stat *st)
Find a mailbox that understands a path.
Definition: mx.c:1249
Mailbox was reopened.
Definition: mx.h:74
WHERE bool OptNews
(pseudo) used to change reader mode
Definition: options.h:43
#define SORT_MASK
Mask for the sort id.
Definition: sort2.h:85
struct NntpAccountData * CurrentNewsSrv
Current NNTP news server.
Definition: nntp.c:75
+ 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::menu_make_entry()

Definition at line 781 of file index.c.

782 {
783  if (!Context || !Context->mailbox || !menu || (line < 0) ||
784  (line >= Context->mailbox->email_max))
785  return;
786 
787  struct Email *e = Context->mailbox->emails[Context->mailbox->v2r[line]];
788  if (!e)
789  return;
790 
792  struct MuttThread *tmp = NULL;
793 
794  if (((C_Sort & SORT_MASK) == SORT_THREADS) && e->tree)
795  {
796  flags |= MUTT_FORMAT_TREE; /* display the thread tree */
797  if (e->display_subject)
798  flags |= MUTT_FORMAT_FORCESUBJ;
799  else
800  {
801  const int reverse = C_Sort & SORT_REVERSE;
802  int edgemsgno;
803  if (reverse)
804  {
805  if (menu->top + menu->pagelen > menu->max)
806  edgemsgno = Context->mailbox->v2r[menu->max - 1];
807  else
808  edgemsgno = Context->mailbox->v2r[menu->top + menu->pagelen - 1];
809  }
810  else
811  edgemsgno = Context->mailbox->v2r[menu->top];
812 
813  for (tmp = e->thread->parent; tmp; tmp = tmp->parent)
814  {
815  if (!tmp->message)
816  continue;
817 
818  /* if no ancestor is visible on current screen, provisionally force
819  * subject... */
820  if (reverse ? (tmp->message->msgno > edgemsgno) : (tmp->message->msgno < edgemsgno))
821  {
822  flags |= MUTT_FORMAT_FORCESUBJ;
823  break;
824  }
825  else if (tmp->message->vnum >= 0)
826  break;
827  }
828  if (flags & MUTT_FORMAT_FORCESUBJ)
829  {
830  for (tmp = e->thread->prev; tmp; tmp = tmp->prev)
831  {
832  if (!tmp->message)
833  continue;
834 
835  /* ...but if a previous sibling is available, don't force it */
836  if (reverse ? (tmp->message->msgno > edgemsgno) : (tmp->message->msgno < edgemsgno))
837  break;
838  else if (tmp->message->vnum >= 0)
839  {
840  flags &= ~MUTT_FORMAT_FORCESUBJ;
841  break;
842  }
843  }
844  }
845  }
846  }
847 
849  Context, Context->mailbox, e, flags);
850 }
struct Email ** emails
Array of Emails.
Definition: mailbox.h:110
The "current" mailbox.
Definition: context.h:36
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
#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:50
#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:1498
WHERE short C_Sort
Config: Sort method for the index.
Definition: sort.h:58
const char * line
Definition: common.c:36
Sort by email threads.
Definition: sort2.h:56
int email_max
Number of pointers in emails.
Definition: mailbox.h:111
WHERE char * C_IndexFormat
Config: printf-like format string for the index menu (emails)
Definition: globals.h:114
struct MuttWindow * indexwin
Definition: mutt_menu.h:95
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:112
#define MUTT_FORMAT_INDEX
This is a main index entry.
Definition: format_flags.h:36
#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::menu_color()

Definition at line 855 of file index.c.

856 {
857  if (!Context || !Context->mailbox || (line < 0))
858  return 0;
859 
860  struct Email *e = Context->mailbox->emails[Context->mailbox->v2r[line]];
861 
862  if (e && e->pair)
863  return e->pair;
864 
866  if (e)
867  return e->pair;
868 
869  return 0;
870 }
struct Email ** emails
Array of Emails.
Definition: mailbox.h:110
The "current" mailbox.
Definition: context.h:36
The envelope/body of an email.
Definition: email.h:37
struct Mailbox * mailbox
Definition: context.h:50
const char * line
Definition: common.c:36
void mutt_set_header_color(struct Mailbox *m, struct Email *e)
Select a colour for a message.
Definition: index.c:3709
int * v2r
Mapping from virtual to real msgno.
Definition: mailbox.h:112
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 884 of file index.c.

885 {
886  if (!buf)
887  return;
888 
889  size_t i = 0;
890  size_t offset = 0;
891  bool found = false;
892  size_t chunks = 0;
893  size_t len = 0;
894 
895  struct StatusSyntax
896  {
897  int color;
898  int first;
899  int last;
900  } *syntax = NULL;
901 
902  do
903  {
904  struct ColorLine *cl = NULL;
905  found = false;
906 
907  if (!buf[offset])
908  break;
909 
910  /* loop through each "color status regex" */
911  STAILQ_FOREACH(cl, &Colors->status_list, entries)
912  {
913  regmatch_t pmatch[cl->match + 1];
914 
915  if (regexec(&cl->regex, buf + offset, cl->match + 1, pmatch, 0) != 0)
916  continue; /* regex doesn't match the status bar */
917 
918  int first = pmatch[cl->match].rm_so + offset;
919  int last = pmatch[cl->match].rm_eo + offset;
920 
921  if (first == last)
922  continue; /* ignore an empty regex */
923 
924  if (!found)
925  {
926  chunks++;
927  mutt_mem_realloc(&syntax, chunks * sizeof(struct StatusSyntax));
928  }
929 
930  i = chunks - 1;
931  if (!found || (first < syntax[i].first) ||
932  ((first == syntax[i].first) && (last > syntax[i].last)))
933  {
934  syntax[i].color = cl->pair;
935  syntax[i].first = first;
936  syntax[i].last = last;
937  }
938  found = true;
939  }
940 
941  if (syntax)
942  {
943  offset = syntax[i].last;
944  }
945  } while (found);
946 
947  /* Only 'len' bytes will fit into 'cols' screen columns */
948  len = mutt_wstr_trunc(buf, buflen, cols, NULL);
949 
950  offset = 0;
951 
952  if ((chunks > 0) && (syntax[0].first > 0))
953  {
954  /* Text before the first highlight */
955  mutt_window_addnstr(buf, MIN(len, syntax[0].first));
956  attrset(Colors->defs[MT_COLOR_STATUS]);
957  if (len <= syntax[0].first)
958  goto dsl_finish; /* no more room */
959 
960  offset = syntax[0].first;
961  }
962 
963  for (i = 0; i < chunks; i++)
964  {
965  /* Highlighted text */
966  attrset(syntax[i].color);
967  mutt_window_addnstr(buf + offset, MIN(len, syntax[i].last) - offset);
968  if (len <= syntax[i].last)
969  goto dsl_finish; /* no more room */
970 
971  size_t next;
972  if ((i + 1) == chunks)
973  {
974  next = len;
975  }
976  else
977  {
978  next = MIN(len, syntax[i + 1].first);
979  }
980 
981  attrset(Colors->defs[MT_COLOR_STATUS]);
982  offset = syntax[i].last;
983  mutt_window_addnstr(buf + offset, next - offset);
984 
985  offset = next;
986  if (offset >= len)
987  goto dsl_finish; /* no more room */
988  }
989 
990  attrset(Colors->defs[MT_COLOR_STATUS]);
991  if (offset < len)
992  {
993  /* Text after the last highlight */
994  mutt_window_addnstr(buf + offset, len - offset);
995  }
996 
997  int width = mutt_strwidth(buf);
998  if (width < cols)
999  {
1000  /* Pad the rest of the line with whitespace */
1001  mutt_paddstr(cols - width, "");
1002  }
1003 dsl_finish:
1004  FREE(&syntax);
1005 }
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:1194
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:378
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:1287
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:1237
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:350
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::menu_custom_redraw()

Definition at line 1010 of file index.c.

1011 {
1012  if (menu->redraw & REDRAW_FULL)
1013  {
1014  menu_redraw_full(menu);
1015  mutt_show_error();
1016  }
1017 
1018 #ifdef USE_SIDEBAR
1019  if (menu->redraw & REDRAW_SIDEBAR)
1020  menu_redraw_sidebar(menu);
1021 #endif
1022 
1023  if (Context && Context->mailbox && Context->mailbox->emails &&
1024  !(menu->current >= Context->mailbox->vcount))
1025  {
1026  menu_check_recenter(menu);
1027 
1028  if (menu->redraw & REDRAW_INDEX)
1029  {
1030  menu_redraw_index(menu);
1031  menu->redraw |= REDRAW_STATUS;
1032  }
1033  else if (menu->redraw & (REDRAW_MOTION_RESYNC | REDRAW_MOTION))
1034  menu_redraw_motion(menu);
1035  else if (menu->redraw & REDRAW_CURRENT)
1036  menu_redraw_current(menu);
1037  }
1038 
1039  if (menu->redraw & REDRAW_STATUS)
1040  {
1041  char buf[1024];
1042  menu_status_line(buf, sizeof(buf), menu, NONULL(C_StatusFormat));
1043  mutt_window_move(menu->statuswin, 0, 0);
1045  mutt_draw_statusline(menu->statuswin->cols, buf, sizeof(buf));
1047  menu->redraw &= ~REDRAW_STATUS;
1048  if (C_TsEnabled && TsSupported)
1049  {
1050  menu_status_line(buf, sizeof(buf), menu, NONULL(C_TsStatusFormat));
1051  mutt_ts_status(buf);
1052  menu_status_line(buf, sizeof(buf), menu, NONULL(C_TsIconFormat));
1053  mutt_ts_icon(buf);
1054  }
1055  }
1056 
1057  menu->redraw = REDRAW_NO_FLAGS;
1058 }
struct Email ** emails
Array of Emails.
Definition: mailbox.h:110
The "current" mailbox.
Definition: context.h:36
WHERE char * C_TsIconFormat
Config: printf-like format string for the terminal&#39;s icon title.
Definition: globals.h:149
#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:49
void menu_status_line(char *buf, size_t buflen, struct Menu *menu, const char *p)
Create the status line.
Definition: status.c:408
WHERE char * C_StatusFormat
Config: printf-like format string for the index&#39;s status line.
Definition: globals.h:147
WHERE bool C_TsEnabled
Config: Allow NeoMutt to set the terminal status line and icon.
Definition: globals.h:267
int vcount
The number of virtual messages.
Definition: mailbox.h:113
#define REDRAW_SIDEBAR
Redraw the sidebar.
Definition: mutt_menu.h:51
struct Mailbox * mailbox
Definition: context.h:50
#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
struct MuttWindow * statuswin
Definition: mutt_menu.h:96
#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:42
int mutt_window_move(struct MuttWindow *win, int row, int col)
Move the cursor in a Window.
Definition: mutt_window.c:198
WHERE char * C_TsStatusFormat
Config: printf-like format string for the terminal&#39;s status (window title)
Definition: globals.h:148
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:117
void mutt_show_error(void)
Show the user an error message.
Definition: curs_lib.c:530
void mutt_ts_status(char *str)
Set the text of the terminal title bar.
Definition: terminal.c:103
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:884
#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 ( void  )

Display a list of emails.

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

1068 {
1069  char buf[PATH_MAX], helpstr[1024];
1070  OpenMailboxFlags flags;
1071  int op = OP_NULL;
1072  bool done = false; /* controls when to exit the "event" loop */
1073  bool tag = false; /* has the tag-prefix command been pressed? */
1074  int newcount = -1;
1075  int oldcount = -1;
1076  int index_hint = 0; /* used to restore cursor position */
1077  bool do_mailbox_notify = true;
1078  int close = 0; /* did we OP_QUIT or OP_EXIT out of this menu? */
1079  int attach_msg = OptAttachMsg;
1080  bool in_pager = false; /* set when pager redirects a function through the index */
1081 
1082  struct Menu *menu = mutt_menu_new(MENU_MAIN);
1084  menu->menu_color = index_color;
1085  menu->current = ci_first_message();
1086  menu->help = mutt_compile_help(
1087  helpstr, sizeof(helpstr), MENU_MAIN,
1088 #ifdef USE_NNTP
1090  IndexNewsHelp :
1091 #endif
1092  IndexHelp);
1094  mutt_menu_push_current(menu);
1096 
1097  if (!attach_msg)
1098  {
1099  /* force the mailbox check after we enter the folder */
1101  }
1102 #ifdef USE_INOTIFY
1103  mutt_monitor_add(NULL);
1104 #endif
1105 
1106  if (((C_Sort & SORT_MASK) == SORT_THREADS) && C_CollapseAll)
1107  {
1108  collapse_all(menu, 0);
1109  menu->redraw = REDRAW_FULL;
1110  }
1111 
1112  while (true)
1113  {
1114  /* Clear the tag prefix unless we just started it. Don't clear
1115  * the prefix on a timeout (op==-2), but do clear on an abort (op==-1) */
1116  if (tag && (op != OP_TAG_PREFIX) && (op != OP_TAG_PREFIX_COND) && (op != -2))
1117  tag = false;
1118 
1119  /* check if we need to resort the index because just about
1120  * any 'op' below could do mutt_enter_command(), either here or
1121  * from any new menu launched, and change $sort/$sort_aux */
1122  if (OptNeedResort && Context && Context->mailbox &&
1123  (Context->mailbox->msg_count != 0) && (menu->current >= 0))
1124  resort_index(menu);
1125 
1126  menu->max = (Context && Context->mailbox) ? Context->mailbox->vcount : 0;
1127  oldcount = (Context && Context->mailbox) ? Context->mailbox->msg_count : 0;
1128 
1129  if (OptRedrawTree && Context && Context->mailbox &&
1130  (Context->mailbox->msg_count != 0) && ((C_Sort & SORT_MASK) == SORT_THREADS))
1131  {
1133  menu->redraw |= REDRAW_STATUS;
1134  OptRedrawTree = false;
1135  }
1136 
1137  if (Context)
1138  Context->menu = menu;
1139 
1140  if (Context && Context->mailbox && !attach_msg)
1141  {
1142  int check;
1143  /* check for new mail in the mailbox. If nonzero, then something has
1144  * changed about the file (either we got new mail or the file was
1145  * modified underneath us.) */
1146 
1147  index_hint = ((Context->mailbox->vcount != 0) && (menu->current >= 0) &&
1148  (menu->current < Context->mailbox->vcount)) ?
1149  CUR_EMAIL->index :
1150  0;
1151 
1152  check = mx_mbox_check(Context->mailbox, &index_hint);
1153  if (check < 0)
1154  {
1156  {
1157  /* fatal error occurred */
1158  ctx_free(&Context);
1159  menu->redraw = REDRAW_FULL;
1160  }
1161 
1162  OptSearchInvalid = true;
1163  }
1164  else if ((check == MUTT_NEW_MAIL) || (check == MUTT_REOPENED) || (check == MUTT_FLAGS))
1165  {
1166  /* notify the user of new mail */
1167  if (check == MUTT_REOPENED)
1168  {
1169  mutt_error(
1170  _("Mailbox was externally modified. Flags may be wrong."));
1171  }
1172  else if (check == MUTT_NEW_MAIL)
1173  {
1174  for (size_t i = oldcount; i < Context->mailbox->msg_count; i++)
1175  {
1176  if (!Context->mailbox->emails[i]->read)
1177  {
1178  mutt_message(_("New mail in this mailbox"));
1179  if (C_BeepNew)
1180  mutt_beep(true);
1181  if (C_NewMailCommand)
1182  {
1183  char cmd[1024];
1184  menu_status_line(cmd, sizeof(cmd), menu, NONULL(C_NewMailCommand));
1185  if (mutt_system(cmd) != 0)
1186  mutt_error(_("Error running \"%s\""), cmd);
1187  }
1188  break;
1189  }
1190  }
1191  }
1192  else if (check == MUTT_FLAGS)
1193  mutt_message(_("Mailbox was externally modified"));
1194 
1195  /* avoid the message being overwritten by mailbox */
1196  do_mailbox_notify = false;
1197 
1198  bool q = Context->mailbox->quiet;
1199  Context->mailbox->quiet = true;
1200  update_index(menu, Context, check, oldcount, index_hint);
1201  Context->mailbox->quiet = q;
1202 
1203  menu->redraw = REDRAW_FULL;
1204  menu->max = Context->mailbox->vcount;
1205 
1206  OptSearchInvalid = true;
1207  }
1208  }
1209 
1210  if (!attach_msg)
1211  {
1212  /* check for new mail in the incoming folders */
1213  oldcount = newcount;
1214  newcount = mutt_mailbox_check(Context ? Context->mailbox : NULL, 0);
1215  if (newcount != oldcount)
1216  menu->redraw |= REDRAW_STATUS;
1217  if (do_mailbox_notify)
1218  {
1219  if (mutt_mailbox_notify(Context ? Context->mailbox : NULL))
1220  {
1221  menu->redraw |= REDRAW_STATUS;
1222  if (C_BeepNew)
1223  mutt_beep(true);
1224  if (C_NewMailCommand)
1225  {
1226  char cmd[1024];
1227  menu_status_line(cmd, sizeof(cmd), menu, NONULL(C_NewMailCommand));
1228  if (mutt_system(cmd) != 0)
1229  mutt_error(_("Error running \"%s\""), cmd);
1230  }
1231  }
1232  }
1233  else
1234  do_mailbox_notify = true;
1235  }
1236 
1237  if (op >= 0)
1239 
1240  if (!in_pager)
1241  {
1242  index_custom_redraw(menu);
1243 
1244  /* give visual indication that the next command is a tag- command */
1245  if (tag)
1246  {
1247  mutt_window_mvaddstr(MuttMessageWindow, 0, 0, "tag-");
1249  }
1250 
1251  if (menu->current < menu->max)
1252  menu->oldcurrent = menu->current;
1253  else
1254  menu->oldcurrent = -1;
1255 
1256  if (C_ArrowCursor)
1257  mutt_window_move(menu->indexwin, menu->current - menu->top + menu->offset, 2);
1258  else if (C_BrailleFriendly)
1259  mutt_window_move(menu->indexwin, menu->current - menu->top + menu->offset, 0);
1260  else
1261  {
1262  mutt_window_move(menu->indexwin, menu->current - menu->top + menu->offset,
1263  menu->indexwin->cols - 1);
1264  }
1265  mutt_refresh();
1266 
1267  if (SigWinch)
1268  {
1269  SigWinch = 0;
1271  menu->top = 0; /* so we scroll the right amount */
1272  /* force a real complete redraw. clrtobot() doesn't seem to be able
1273  * to handle every case without this. */
1275  continue;
1276  }
1277 
1278  op = km_dokey(MENU_MAIN);
1279 
1280  mutt_debug(LL_DEBUG3, "[%d]: Got op %d\n", __LINE__, op);
1281 
1282  /* either user abort or timeout */
1283  if (op < 0)
1284  {
1286  if (tag)
1288  continue;
1289  }
1290 
1292 
1293  /* special handling for the tag-prefix function */
1294  if ((op == OP_TAG_PREFIX) || (op == OP_TAG_PREFIX_COND))
1295  {
1296  /* A second tag-prefix command aborts */
1297  if (tag)
1298  {
1299  tag = false;
1301  continue;
1302  }
1303 
1304  if (!Context || !Context->mailbox)
1305  {
1306  mutt_error(_("No mailbox is open"));
1307  continue;
1308  }
1309 
1310  if (Context->mailbox->msg_tagged == 0)
1311  {
1312  if (op == OP_TAG_PREFIX)
1313  mutt_error(_("No tagged messages"));
1314  else if (op == OP_TAG_PREFIX_COND)
1315  {
1317  mutt_message(_("Nothing to do"));
1318  }
1319  continue;
1320  }
1321 
1322  /* get the real command */
1323  tag = true;
1324  continue;
1325  }
1326  else if (C_AutoTag && Context && Context->mailbox &&
1327  (Context->mailbox->msg_tagged != 0))
1328  tag = true;
1329 
1330  mutt_clear_error();
1331  }
1332  else
1333  {
1334  if (menu->current < menu->max)
1335  menu->oldcurrent = menu->current;
1336  else
1337  menu->oldcurrent = -1;
1338 
1339  mutt_curses_set_cursor(MUTT_CURSOR_VISIBLE); /* fallback from the pager */
1340  }
1341 
1342 #ifdef USE_NNTP
1343  OptNews = false; /* for any case */
1344 #endif
1345 
1346 #ifdef USE_NOTMUCH
1347  if (Context)
1349 #endif
1350 
1351  switch (op)
1352  {
1353  /* ----------------------------------------------------------------------
1354  * movement commands
1355  */
1356 
1357  case OP_BOTTOM_PAGE:
1358  menu_bottom_page(menu);
1359  break;
1360  case OP_CURRENT_BOTTOM:
1361  menu_current_bottom(menu);
1362  break;
1363  case OP_CURRENT_MIDDLE:
1364  menu_current_middle(menu);
1365  break;
1366  case OP_CURRENT_TOP:
1367  menu_current_top(menu);
1368  break;
1369  case OP_FIRST_ENTRY:
1370  menu_first_entry(menu);
1371  break;
1372  case OP_HALF_DOWN:
1373  menu_half_down(menu);
1374  break;
1375  case OP_HALF_UP:
1376  menu_half_up(menu);
1377  break;
1378  case OP_LAST_ENTRY:
1379  menu_last_entry(menu);
1380  break;
1381  case OP_MIDDLE_PAGE:
1382  menu_middle_page(menu);
1383  break;
1384  case OP_NEXT_LINE:
1385  menu_next_line(menu);
1386  break;
1387  case OP_NEXT_PAGE:
1388  menu_next_page(menu);
1389  break;
1390  case OP_PREV_LINE:
1391  menu_prev_line(menu);
1392  break;
1393  case OP_PREV_PAGE:
1394  menu_prev_page(menu);
1395  break;
1396  case OP_TOP_PAGE:
1397  menu_top_page(menu);
1398  break;
1399 
1400 #ifdef USE_NNTP
1401  case OP_GET_PARENT:
1403  break;
1404  /* fallthrough */
1405 
1406  case OP_GET_MESSAGE:
1408  break;
1409  if (Context->mailbox->magic == MUTT_NNTP)
1410  {
1411  struct Email *e = NULL;
1412 
1413  if (op == OP_GET_MESSAGE)
1414  {
1415  buf[0] = '\0';
1416  if ((mutt_get_field(_("Enter Message-Id: "), buf, sizeof(buf), 0) != 0) ||
1417  !buf[0])
1418  {
1419  break;
1420  }
1421  }
1422  else
1423  {
1424  if (STAILQ_EMPTY(&CUR_EMAIL->env->references))
1425  {
1426  mutt_error(_("Article has no parent reference"));
1427  break;
1428  }
1429  mutt_str_strfcpy(buf, STAILQ_FIRST(&CUR_EMAIL->env->references)->data,
1430  sizeof(buf));
1431  }
1432  if (!Context->mailbox->id_hash)
1434  e = mutt_hash_find(Context->mailbox->id_hash, buf);
1435  if (e)
1436  {
1437  if (e->vnum != -1)
1438  {
1439  menu->current = e->vnum;
1440  menu->redraw = REDRAW_MOTION_RESYNC;
1441  }
1442  else if (e->collapsed)
1443  {
1446  menu->current = e->vnum;
1447  menu->redraw = REDRAW_MOTION_RESYNC;
1448  }
1449  else
1450  mutt_error(_("Message is not visible in limited view"));
1451  }
1452  else
1453  {
1454  mutt_message(_("Fetching %s from server..."), buf);
1455  int rc = nntp_check_msgid(Context->mailbox, buf);
1456  if (rc == 0)
1457  {
1459  mutt_sort_headers(Context, false);
1460  menu->current = e->vnum;
1461  menu->redraw = REDRAW_FULL;
1462  }
1463  else if (rc > 0)
1464  mutt_error(_("Article %s not found on the server"), buf);
1465  }
1466  }
1467  break;
1468 
1469  case OP_GET_CHILDREN:
1470  case OP_RECONSTRUCT_THREAD:
1471  if (!prereq(Context, menu,
1473  {
1474  break;
1475  }
1476  if (Context->mailbox->magic == MUTT_NNTP)
1477  {
1478  int oldmsgcount = Context->mailbox->msg_count;
1479  int oldindex = CUR_EMAIL->index;
1480  int rc = 0;
1481 
1482  if (!CUR_EMAIL->env->message_id)
1483  {
1484  mutt_error(_("No Message-Id. Unable to perform operation."));
1485  break;
1486  }
1487 
1488  mutt_message(_("Fetching message headers..."));
1489  if (!Context->mailbox->id_hash)
1491  mutt_str_strfcpy(buf, CUR_EMAIL->env->message_id, sizeof(buf));
1492 
1493  /* trying to find msgid of the root message */
1494  if (op == OP_RECONSTRUCT_THREAD)
1495  {
1496  struct ListNode *ref = NULL;
1497  STAILQ_FOREACH(ref, &CUR_EMAIL->env->references, entries)
1498  {
1499  if (!mutt_hash_find(Context->mailbox->id_hash, ref->data))
1500  {
1501  rc = nntp_check_msgid(Context->mailbox, ref->data);
1502  if (rc < 0)
1503  break;
1504  }
1505 
1506  /* the last msgid in References is the root message */
1507  if (!STAILQ_NEXT(ref, entries))
1508  mutt_str_strfcpy(buf, ref->data, sizeof(buf));
1509  }
1510  }
1511 
1512  /* fetching all child messages */
1513  if (rc >= 0)
1514  rc = nntp_check_children(Context->mailbox, buf);
1515 
1516  /* at least one message has been loaded */
1517  if (Context->mailbox->msg_count > oldmsgcount)
1518  {
1519  struct Email *e_oldcur = CUR_EMAIL;
1520  struct Email *e = NULL;
1521  bool quiet = Context->mailbox->quiet;
1522 
1523  if (rc < 0)
1524  Context->mailbox->quiet = true;
1525  mutt_sort_headers(Context, (op == OP_RECONSTRUCT_THREAD));
1526  Context->mailbox->quiet = quiet;
1527 
1528  /* Similar to OP_MAIN_ENTIRE_THREAD, keep displaying the old message, but
1529  * update the index */
1530  if (in_pager)
1531  {
1532  menu->current = e_oldcur->vnum;
1533  menu->redraw = REDRAW_STATUS | REDRAW_INDEX;
1534  op = OP_DISPLAY_MESSAGE;
1535  continue;
1536  }
1537 
1538  /* if the root message was retrieved, move to it */
1539  e = mutt_hash_find(Context->mailbox->id_hash, buf);
1540  if (e)
1541  menu->current = e->vnum;
1542 
1543  /* try to restore old position */
1544  else
1545  {
1546  for (int i = 0; i < Context->mailbox->msg_count; i++)
1547  {
1548  if (Context->mailbox->emails[i]->index == oldindex)
1549  {
1550  menu->current = Context->mailbox->emails[i]->vnum;
1551  /* as an added courtesy, recenter the menu
1552  * with the current entry at the middle of the screen */
1553  menu_check_recenter(menu);
1554  menu_current_middle(menu);
1555  }
1556  }
1557  }
1558  menu->redraw = REDRAW_FULL;
1559  }
1560  else if (rc >= 0)
1561  {
1562  mutt_error(_("No deleted messages found in the thread"));
1563  /* Similar to OP_MAIN_ENTIRE_THREAD, keep displaying the old message, but
1564  * update the index */
1565  if (in_pager)
1566  {
1567  op = OP_DISPLAY_MESSAGE;
1568  continue;
1569  }
1570  }
1571  }
1572  break;
1573 #endif
1574 
1575  case OP_JUMP:
1576  {
1577  int msg_num = 0;
1579  break;
1580  if (isdigit(LastKey))
1582  buf[0] = '\0';
1583  if ((mutt_get_field(_("Jump to message: "), buf, sizeof(buf), 0) != 0) ||
1584  (buf[0] == '\0'))
1585  {
1586  mutt_error(_("Nothing to do"));
1587  }
1588  else if (mutt_str_atoi(buf, &msg_num) < 0)
1589  mutt_error(_("Argument must be a message number"));
1590  else if ((msg_num < 1) || (msg_num > Context->mailbox->msg_count))
1591  mutt_error(_("Invalid message number"));
1592  else if (!message_is_visible(Context, msg_num - 1))
1593  mutt_error(_("That message is not visible"));
1594  else
1595  {
1596  struct Email *e = Context->mailbox->emails[msg_num - 1];
1597 
1598  if (mutt_messages_in_thread(Context->mailbox, e, 1) > 1)
1599  {
1602  }
1603  menu->current = e->vnum;
1604  }
1605 
1606  if (in_pager)
1607  {
1608  op = OP_DISPLAY_MESSAGE;
1609  continue;
1610  }
1611  else
1612  menu->redraw = REDRAW_FULL;
1613 
1614  break;
1615  }
1616 
1617  /* --------------------------------------------------------------------
1618  * 'index' specific commands
1619  */
1620 
1621  case OP_MAIN_DELETE_PATTERN:
1622  if (!prereq(Context, menu,
1624  {
1625  break;
1626  }
1627  /* L10N: CHECK_ACL */
1628  /* L10N: Due to the implementation details we do not know whether we
1629  delete zero, 1, 12, ... messages. So in English we use
1630  "messages". Your language might have other means to express this. */
1631  if (!check_acl(Context, MUTT_ACL_DELETE, _("Can't delete messages")))
1632  break;
1633 
1634  mutt_pattern_func(MUTT_DELETE, _("Delete messages matching: "));
1635  menu->redraw |= REDRAW_INDEX | REDRAW_STATUS;
1636  break;
1637 
1638 #ifdef USE_POP
1639  case OP_MAIN_FETCH_MAIL:
1640  if (!prereq(Context, menu, CHECK_ATTACH))
1641  break;
1642  pop_fetch_mail();
1643  menu->redraw = REDRAW_FULL;
1644  break;
1645 #endif /* USE_POP */
1646 
1647  case OP_SHOW_LOG_MESSAGES:
1648  {
1649  char tempfile[PATH_MAX];
1650  mutt_mktemp(tempfile, sizeof(tempfile));
1651 
1652  FILE *fp = mutt_file_fopen(tempfile, "a+");
1653  if (!fp)
1654  {
1655  mutt_perror("fopen");
1656  break;
1657  }
1658 
1659  log_queue_save(fp);
1660  mutt_file_fclose(&fp);
1661 
1662  mutt_do_pager("messages", tempfile, MUTT_PAGER_LOGS, NULL);
1663  break;
1664  }
1665 
1666  case OP_HELP:
1668  menu->redraw = REDRAW_FULL;
1669  break;
1670 
1671  case OP_MAIN_SHOW_LIMIT:
1672  if (!prereq(Context, menu, CHECK_IN_MAILBOX))
1673  break;
1674  if (!Context->pattern)
1675  mutt_message(_("No limit pattern is in effect"));
1676  else
1677  {
1678  char buf2[256];
1679  /* L10N: ask for a limit to apply */
1680  snprintf(buf2, sizeof(buf2), _("Limit: %s"), Context->pattern);
1681  mutt_message("%s", buf2);
1682  }
1683  break;
1684 
1685  case OP_LIMIT_CURRENT_THREAD:
1686  case OP_MAIN_LIMIT:
1687  case OP_TOGGLE_READ:
1688  if (!prereq(Context, menu, CHECK_IN_MAILBOX))
1689  break;
1690  menu->oldcurrent = ((Context->mailbox->vcount != 0) && (menu->current >= 0) &&
1691  (menu->current < Context->mailbox->vcount)) ?
1692  CUR_EMAIL->index :
1693  -1;
1694  if (op == OP_TOGGLE_READ)
1695  {
1696  char buf2[1024];
1697 
1698  if (!Context->pattern || (strncmp(Context->pattern, "!~R!~D~s", 8) != 0))
1699  {
1700  snprintf(buf2, sizeof(buf2), "!~R!~D~s%s",
1701  Context->pattern ? Context->pattern : ".*");
1702  }
1703  else
1704  {
1705  mutt_str_strfcpy(buf2, Context->pattern + 8, sizeof(buf2));
1706  if (!*buf2 || (strncmp(buf2, ".*", 2) == 0))
1707  snprintf(buf2, sizeof(buf2), "~A");
1708  }
1709  FREE(&Context->pattern);
1710  Context->pattern = mutt_str_strdup(buf2);
1712  }
1713 
1714  if (((op == OP_LIMIT_CURRENT_THREAD) && mutt_limit_current_thread(CUR_EMAIL)) ||
1715  (op == OP_TOGGLE_READ) ||
1716  ((op == OP_MAIN_LIMIT) &&
1718  _("Limit to messages matching: ")) == 0)))
1719  {
1720  if (menu->oldcurrent >= 0)
1721  {
1722  /* try to find what used to be the current message */
1723  menu->current = -1;
1724  for (size_t i = 0; i < Context->mailbox->vcount; i++)
1725  {
1726  if (Context->mailbox->emails[Context->mailbox->v2r[i]]->index == menu->oldcurrent)
1727  {
1728  menu->current = i;
1729  break;
1730  }
1731  }
1732  if (menu->current < 0)
1733  menu->current = 0;
1734  }
1735  else
1736  menu->current = 0;
1737  if ((Context->mailbox->msg_count != 0) && ((C_Sort & SORT_MASK) == SORT_THREADS))
1738  {
1739  if (C_CollapseAll)
1740  collapse_all(menu, 0);
1742  }
1743  menu->redraw = REDRAW_FULL;
1744  }
1745  if (Context->pattern)
1746  mutt_message(_("To view all messages, limit to \"all\""));
1747  break;
1748 
1749  case OP_QUIT:
1750  close = op;
1751  if (attach_msg)
1752  {
1753  done = true;
1754  break;
1755  }
1756 
1757  if (query_quadoption(C_Quit, _("Quit NeoMutt?")) == MUTT_YES)
1758  {
1759  int check;
1760 
1761  oldcount = (Context && Context->mailbox) ? Context->mailbox->msg_count : 0;
1762 
1765 
1766  if (!Context || ((check = mx_mbox_close(&Context)) == 0))
1767  done = true;
1768  else
1769  {
1770  if ((check == MUTT_NEW_MAIL) || (check == MUTT_REOPENED))
1771  update_index(menu, Context, check, oldcount, index_hint);
1772 
1773  menu->redraw = REDRAW_FULL; /* new mail arrived? */
1774  OptSearchInvalid = true;
1775  }
1776  }
1777  break;
1778 
1779  case OP_REDRAW:
1781  menu->redraw = REDRAW_FULL;
1782  break;
1783 
1784  case OP_SEARCH:
1785  case OP_SEARCH_REVERSE:
1786  case OP_SEARCH_NEXT:
1787  case OP_SEARCH_OPPOSITE:
1789  break;
1790  menu->current = mutt_search_command(menu->current, op);
1791  if (menu->current == -1)
1792  menu->current = menu->oldcurrent;
1793  else
1794  menu->redraw = REDRAW_MOTION;
1795  break;
1796 
1797  case OP_SORT:
1798  case OP_SORT_REVERSE:
1799  if (mutt_select_sort((op == OP_SORT_REVERSE)) == 0)
1800  {
1801  if (Context && Context->mailbox && (Context->mailbox->msg_count != 0))
1802  {
1803  resort_index(menu);
1804  OptSearchInvalid = true;
1805  }
1806  if (in_pager)
1807  {
1808  op = OP_DISPLAY_MESSAGE;
1809  continue;
1810  }
1811  menu->redraw |= REDRAW_STATUS;
1812  }
1813  break;
1814 
1815  case OP_TAG:
1817  break;
1818  if (tag && !C_AutoTag)
1819  {
1820  for (size_t i = 0; i < Context->mailbox->msg_count; i++)
1821  if (message_is_visible(Context, i))
1823  menu->redraw |= REDRAW_STATUS | REDRAW_INDEX;
1824  }
1825  else
1826  {
1828 
1829  Context->last_tag =
1830  CUR_EMAIL->tagged ?
1831  CUR_EMAIL :
1832  (((Context->last_tag == CUR_EMAIL) && !CUR_EMAIL->tagged) ?
1833  NULL :
1834  Context->last_tag);
1835 
1836  menu->redraw |= REDRAW_STATUS;
1837  if (C_Resolve && (menu->current < Context->mailbox->vcount - 1))
1838  {
1839  menu->current++;
1840  menu->redraw |= REDRAW_MOTION_RESYNC;
1841  }
1842  else
1843  menu->redraw |= REDRAW_CURRENT;
1844  }
1845  break;
1846 
1847  case OP_MAIN_TAG_PATTERN:
1849  break;
1850  mutt_pattern_func(MUTT_TAG, _("Tag messages matching: "));
1851  menu->redraw |= REDRAW_INDEX | REDRAW_STATUS;
1852  break;
1853 
1854  case OP_MAIN_UNDELETE_PATTERN:
1856  break;
1857  /* L10N: CHECK_ACL */
1858  /* L10N: Due to the implementation details we do not know whether we
1859  undelete zero, 1, 12, ... messages. So in English we use
1860  "messages". Your language might have other means to express this. */
1861  if (!check_acl(Context, MUTT_ACL_DELETE, _("Can't undelete messages")))
1862  break;
1863 
1865  _("Undelete messages matching: ")) == 0)
1866  {
1867  menu->redraw |= REDRAW_INDEX | REDRAW_STATUS;
1868  }
1869  break;
1870 
1871  case OP_MAIN_UNTAG_PATTERN:
1873  break;
1874  if (mutt_pattern_func(MUTT_UNTAG, _("Untag messages matching: ")) == 0)
1875  menu->redraw |= REDRAW_INDEX | REDRAW_STATUS;
1876  break;
1877 
1878  case OP_COMPOSE_TO_SENDER:
1879  {
1881  break;
1882  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
1883  el_add_tagged(&el, Context, CUR_EMAIL, tag);
1884  ci_send_message(SEND_TO_SENDER, NULL, NULL, Context, &el);
1885  emaillist_clear(&el);
1886  menu->redraw = REDRAW_FULL;
1887  break;
1888  }
1889 
1890  /* --------------------------------------------------------------------
1891  * The following operations can be performed inside of the pager.
1892  */
1893 
1894 #ifdef USE_IMAP
1895  case OP_MAIN_IMAP_FETCH:
1896  if (Context && Context->mailbox && (Context->mailbox->magic == MUTT_IMAP))
1898  break;
1899 
1900  case OP_MAIN_IMAP_LOGOUT_ALL:
1901  if (Context && Context->mailbox && (Context->mailbox->magic == MUTT_IMAP))
1902  {
1903  int check = mx_mbox_close(&Context);
1904  if (check != 0)
1905  {
1906  if ((check == MUTT_NEW_MAIL) || (check == MUTT_REOPENED))
1907  update_index(menu, Context, check, oldcount, index_hint);
1908  OptSearchInvalid = true;
1909  menu->redraw = REDRAW_FULL;
1910  break;
1911  }
1912  }
1913  imap_logout_all();
1914  mutt_message(_("Logged out of IMAP servers"));
1915  OptSearchInvalid = true;
1916  menu->redraw = REDRAW_FULL;
1917  break;
1918 #endif
1919 
1920  case OP_MAIN_SYNC_FOLDER:
1921  if (!Context || !Context->mailbox || (Context->mailbox->msg_count == 0))
1922  break;
1923 
1925  break;
1926  {
1927  int ovc = Context->mailbox->vcount;
1928  int oc = Context->mailbox->msg_count;
1929  struct Email *e = NULL;
1930 
1931  /* don't attempt to move the cursor if there are no visible messages in the current limit */
1932  if (menu->current < Context->mailbox->vcount)
1933  {
1934  /* threads may be reordered, so figure out what header the cursor
1935  * should be on. */
1936  int newidx = menu->current;
1937  if (CUR_EMAIL->deleted)
1938  newidx = ci_next_undeleted(menu->current);
1939  if (newidx < 0)
1940  newidx = ci_previous_undeleted(menu->current);
1941  if (newidx >= 0)
1942  e = Context->mailbox->emails[Context->mailbox->v2r[newidx]];
1943  }
1944 
1945  int check = mx_mbox_sync(Context->mailbox, &index_hint);
1946  if (check == 0)
1947  {
1948  if (e && (Context->mailbox->vcount != ovc))
1949  {
1950  for (size_t i = 0; i < Context->mailbox->vcount; i++)
1951  {
1952  if (Context->mailbox->emails[Context->mailbox->v2r[i]] == e)
1953  {
1954  menu->current = i;
1955  break;
1956  }
1957  }
1958  }
1959  OptSearchInvalid = true;
1960  }
1961  else if ((check == MUTT_NEW_MAIL) || (check == MUTT_REOPENED))
1962  update_index(menu, Context, check, oc, index_hint);
1963 
1964  /* do a sanity check even if mx_mbox_sync failed. */
1965 
1966  if ((menu->current < 0) || (Context && Context->mailbox &&
1967  (menu->current >= Context->mailbox->vcount)))
1968  {
1969  menu->current = ci_first_message();
1970  }
1971  }
1972 
1973  /* check for a fatal error, or all messages deleted */
1974  if (Context && Context->mailbox &&
1976  ctx_free(&Context);
1977 
1978  /* if we were in the pager, redisplay the message */
1979  if (in_pager)
1980  {
1981  op = OP_DISPLAY_MESSAGE;
1982  continue;
1983  }
1984  else
1985  menu->redraw = REDRAW_FULL;
1986  break;
1987 
1988  case OP_MAIN_QUASI_DELETE:
1990  break;
1991  if (tag)
1992  {
1993  for (size_t i = 0; i < Context->mailbox->msg_count; i++)
1994  {
1995  if (message_is_tagged(Context, i))
1996  {
1997  Context->mailbox->emails[i]->quasi_deleted = true;
1998  Context->mailbox->changed = true;
1999  }
2000  }
2001  }
2002  else
2003  {
2004  CUR_EMAIL->quasi_deleted = true;
2005  Context->mailbox->changed = true;
2006  }
2007  break;
2008 
2009 #ifdef USE_NOTMUCH
2010  case OP_MAIN_ENTIRE_THREAD:
2011  {
2013  break;
2014  if (Context->mailbox->magic != MUTT_NOTMUCH)
2015  {
2016  if (!CUR_EMAIL || !CUR_EMAIL->env || !CUR_EMAIL->env->message_id)
2017  {
2018  mutt_message(_("No virtual folder and no Message-Id, aborting"));
2019  break;
2020  } // no virtual folder, but we have message-id, reconstruct thread on-the-fly
2021  strncpy(buf, "id:", sizeof(buf));
2022  int msg_id_offset = 0;
2023  if ((CUR_EMAIL->env->message_id)[0] == '<')
2024  msg_id_offset = 1;
2025  mutt_str_strcat(buf, sizeof(buf), (CUR_EMAIL->env->message_id) + msg_id_offset);
2026  if (buf[strlen(buf) - 1] == '>')
2027  buf[strlen(buf) - 1] = '\0';
2028  if (!nm_uri_from_query(Context->mailbox, buf, sizeof(buf)))
2029  {
2030  mutt_message(_("Failed to create query, aborting"));
2031  break;
2032  }
2033 
2034  main_change_folder(menu, op, NULL, buf, sizeof(buf), &oldcount, &index_hint, NULL);
2035 
2036  // If notmuch doesn't contain the message, we're left in an empty
2037  // vfolder. No messages are found, but nm_read_entire_thread assumes
2038  // a valid message-id and will throw a segfault.
2039  //
2040  // To prevent that, stay in the empty vfolder and print an error.
2041  if (Context->mailbox->msg_count == 0)
2042  {
2043  mutt_error(_("failed to find message in notmuch database. try "
2044  "running 'notmuch new'."));
2045  break;
2046  }
2047  }
2048  oldcount = Context->mailbox->msg_count;
2049  struct Email *e_oldcur = CUR_EMAIL;
2051  {
2052  mutt_message(_("Failed to read thread, aborting"));
2053  break;
2054  }
2055  if (oldcount < Context->mailbox->msg_count)
2056  {
2057  /* nm_read_entire_thread() triggers mutt_sort_headers() if necessary */
2058  menu->current = e_oldcur->vnum;
2059  menu->redraw = REDRAW_STATUS | REDRAW_INDEX;
2060 
2061  if (e_oldcur->collapsed || Context->collapsed)
2062  {
2065  }
2066  }
2067  if (in_pager)
2068  {
2069  op = OP_DISPLAY_MESSAGE;
2070  continue;
2071  }
2072  break;
2073  }
2074 
2075 #endif
2076  case OP_MAIN_MODIFY_TAGS:
2077  case OP_MAIN_MODIFY_TAGS_THEN_HIDE:
2078  {
2079  if (!Context || !Context->mailbox)
2080  break;
2082  {
2083  mutt_message(_("Folder doesn't support tagging, aborting"));
2084  break;
2085  }
2087  break;
2088  char *tags = NULL;
2089  if (!tag)
2090  tags = driver_tags_get_with_hidden(&CUR_EMAIL->tags);
2091  int rc = mx_tags_edit(Context->mailbox, tags, buf, sizeof(buf));
2092  FREE(&tags);
2093  if (rc < 0)
2094  break;
2095  else if (rc == 0)
2096  {
2097  mutt_message(_("No tag specified, aborting"));
2098  break;
2099  }
2100 
2101  if (tag)
2102  {
2103  struct Progress progress;
2104 
2105  if (!Context->mailbox->quiet)
2106  {
2107  mutt_progress_init(&progress, _("Update tags..."),
2109  }
2110 
2111 #ifdef USE_NOTMUCH
2112  if (Context->mailbox->magic == MUTT_NOTMUCH)
2114 #endif
2115  for (int px = 0, i = 0; i < Context->mailbox->msg_count; i++)
2116  {
2117  if (!message_is_tagged(Context, i))
2118  continue;
2119 
2120  if (!Context->mailbox->quiet)
2121  mutt_progress_update(&progress, ++px, -1);
2123  if (op == OP_MAIN_MODIFY_TAGS_THEN_HIDE)
2124  {
2125  bool still_queried = false;
2126 #ifdef USE_NOTMUCH
2127  if (Context->mailbox->magic == MUTT_NOTMUCH)
2128  still_queried = nm_message_is_still_queried(
2130 #endif
2131  Context->mailbox->emails[i]->quasi_deleted = !still_queried;
2132  Context->mailbox->changed = true;
2133  }
2134  }
2135 #ifdef USE_NOTMUCH
2136  if (Context->mailbox->magic == MUTT_NOTMUCH)
2138 #endif
2139  menu->redraw = REDRAW_STATUS | REDRAW_INDEX;
2140  }
2141  else
2142  {
2144  {
2145  mutt_message(_("Failed to modify tags, aborting"));
2146  break;
2147  }
2148  if (op == OP_MAIN_MODIFY_TAGS_THEN_HIDE)
2149  {
2150  bool still_queried = false;
2151 #ifdef USE_NOTMUCH
2152  if (Context->mailbox->magic == MUTT_NOTMUCH)
2154 #endif
2155  CUR_EMAIL->quasi_deleted = !still_queried;
2156  Context->mailbox->changed = true;
2157  }
2158  if (in_pager)
2159  {
2160  op = OP_DISPLAY_MESSAGE;
2161  continue;
2162  }
2163  if (C_Resolve)
2164  {
2165  menu->current = ci_next_undeleted(menu->current);
2166  if (menu->current == -1)
2167  {
2168  menu->current = menu->oldcurrent;
2169  menu->redraw = REDRAW_CURRENT;
2170  }
2171  else
2172  menu->redraw = REDRAW_MOTION_RESYNC;
2173  }
2174  else
2175  menu->redraw = REDRAW_CURRENT;
2176  }
2177  menu->redraw |= REDRAW_STATUS;
2178  break;
2179  }
2180 
2181  case OP_CHECK_STATS:
2182  mutt_check_stats();
2183  break;
2184 
2185 #ifdef USE_NOTMUCH
2186  case OP_MAIN_VFOLDER_FROM_QUERY:
2187  case OP_MAIN_VFOLDER_FROM_QUERY_READONLY:
2188  buf[0] = '\0';
2189  if ((mutt_get_field("Query: ", buf, sizeof(buf), MUTT_NM_QUERY) != 0) || !buf[0])
2190  {
2191  mutt_message(_("No query, aborting"));
2192  break;
2193  }
2194  if (!nm_uri_from_query(NULL, buf, sizeof(buf)))
2195  mutt_message(_("Failed to create query, aborting"));
2196  else
2197  main_change_folder(menu, op, NULL, buf, sizeof(buf), &oldcount, &index_hint, NULL);
2198  break;
2199 
2200  case OP_MAIN_WINDOWED_VFOLDER_BACKWARD:
2201  if (!prereq(Context, menu, CHECK_IN_MAILBOX))
2202  break;
2203  mutt_debug(LL_DEBUG2, "OP_MAIN_WINDOWED_VFOLDER_BACKWARD\n");
2204  if (C_NmQueryWindowDuration <= 0)
2205  {
2206  mutt_message(_("Windowed queries disabled"));
2207  break;
2208  }
2210  {
2211  mutt_message(_("No notmuch vfolder currently loaded"));
2212  break;
2213  }
2216  if (!nm_uri_from_query(Context->mailbox, buf, sizeof(buf)))
2217  mutt_message(_("Failed to create query, aborting"));
2218  else
2219  main_change_folder(menu, op, NULL, buf, sizeof(buf), &oldcount, &index_hint, NULL);
2220  break;
2221 
2222  case OP_MAIN_WINDOWED_VFOLDER_FORWARD:
2223  if (!prereq(Context, menu, CHECK_IN_MAILBOX))
2224  break;
2225  if (C_NmQueryWindowDuration <= 0)
2226  {
2227  mutt_message(_("Windowed queries disabled"));
2228  break;
2229  }
2231  {
2232  mutt_message(_("No notmuch vfolder currently loaded"));
2233  break;
2234  }
2237  if (!nm_uri_from_query(Context->mailbox, buf, sizeof(buf)))
2238  mutt_message(_("Failed to create query, aborting"));
2239  else
2240  {
2241  mutt_debug(LL_DEBUG2, "nm: + windowed query (%s)\n", buf);
2242  main_change_folder(menu, op, NULL, buf, sizeof(buf), &oldcount, &index_hint, NULL);
2243  }
2244  break;
2245 
2246  case OP_MAIN_CHANGE_VFOLDER:
2247 #endif
2248 
2249 #ifdef USE_SIDEBAR
2250  case OP_SIDEBAR_OPEN:
2251 #endif
2252  case OP_MAIN_CHANGE_FOLDER:
2253  case OP_MAIN_NEXT_UNREAD_MAILBOX:
2254  case OP_MAIN_CHANGE_FOLDER_READONLY:
2255 #ifdef USE_NNTP
2256  case OP_MAIN_CHANGE_GROUP:
2257  case OP_MAIN_CHANGE_GROUP_READONLY:
2258 #endif
2259  {
2260  bool pager_return = true; /* return to display message in pager */
2261 
2262  struct Buffer *folderbuf = mutt_buffer_pool_get();
2263  mutt_buffer_alloc(folderbuf, PATH_MAX);
2264  struct Mailbox *m = NULL;
2265  char *cp = NULL;
2266 #ifdef USE_NNTP
2267  OptNews = false;
2268 #endif
2269  if (attach_msg || C_ReadOnly ||
2270 #ifdef USE_NNTP
2271  (op == OP_MAIN_CHANGE_GROUP_READONLY) ||
2272 #endif
2273  (op == OP_MAIN_CHANGE_FOLDER_READONLY))
2274  {
2275  flags = MUTT_READONLY;
2276  }
2277  else
2278  flags = MUTT_OPEN_NO_FLAGS;
2279 
2280  if (flags)
2281  cp = _("Open mailbox in read-only mode");
2282  else
2283  cp = _("Open mailbox");
2284 
2285  if ((op == OP_MAIN_NEXT_UNREAD_MAILBOX) && Context && Context->mailbox &&
2287  {
2289  mutt_buffer_pretty_mailbox(folderbuf);
2290  mutt_mailbox_next_buffer(Context ? Context->mailbox : NULL, folderbuf);
2291  if (mutt_buffer_is_empty(folderbuf))
2292  {
2293  mutt_error(_("No mailboxes have new mail"));
2294  goto changefoldercleanup;
2295  }
2296  }
2297 #ifdef USE_SIDEBAR
2298  else if (op == OP_SIDEBAR_OPEN)
2299  {
2300  m = mutt_sb_get_highlight();
2301  if (!m)
2302  goto changefoldercleanup;
2303  mutt_buffer_strcpy(folderbuf, mailbox_path(m));
2304 
2305  /* Mark the selected dir for the neomutt browser */
2307  }
2308 #endif
2309  else
2310  {
2313  {
2315  mutt_buffer_pretty_mailbox(folderbuf);
2316  }
2317 #ifdef USE_NNTP
2318  if ((op == OP_MAIN_CHANGE_GROUP) || (op == OP_MAIN_CHANGE_GROUP_READONLY))
2319  {
2320  OptNews = true;
2322  C_NewsServer, false);
2323  if (!CurrentNewsSrv)
2324  goto changefoldercleanup;
2325  if (flags)
2326  cp = _("Open newsgroup in read-only mode");
2327  else
2328  cp = _("Open newsgroup");
2329  nntp_mailbox(Context ? Context->mailbox : NULL, folderbuf->data,
2330  folderbuf->dsize);
2331  }
2332  else
2333 #endif
2334  {
2335  /* By default, fill buf with the next mailbox that contains unread
2336  * mail */
2337  mutt_mailbox_next_buffer(Context ? Context->mailbox : NULL, folderbuf);
2338  }
2339 
2340  if (mutt_buffer_enter_fname(cp, folderbuf, true) == -1)
2341  {
2342  goto changefoldercleanup;
2343  }
2344 
2345  /* Selected directory is okay, let's save it. */
2346  mutt_browser_select_dir(mutt_b2s(folderbuf));
2347 
2348  if (mutt_buffer_is_empty(folderbuf))
2349  {
2351  goto changefoldercleanup;
2352  }
2353  }
2354 
2355  if (!m)
2356  m = mx_mbox_find2(mutt_b2s(folderbuf));
2357 
2358  main_change_folder(menu, op, m, folderbuf->data, folderbuf->dsize,
2359  &oldcount, &index_hint, &pager_return);
2360 #ifdef USE_NNTP
2361  /* mutt_mailbox_check() must be done with mail-reader mode! */
2362  menu->help = mutt_compile_help(helpstr, sizeof(helpstr), MENU_MAIN,
2363  (Context && Context->mailbox &&
2364  (Context->mailbox->magic == MUTT_NNTP)) ?
2365  IndexNewsHelp :
2366  IndexHelp);
2367 #endif
2368  mutt_buffer_expand_path(folderbuf);
2369 #ifdef USE_SIDEBAR
2371 #endif
2372  goto changefoldercleanup;
2373 
2374  changefoldercleanup:
2375  mutt_buffer_pool_release(&folderbuf);
2376  if (in_pager && pager_return)
2377  {
2378  op = OP_DISPLAY_MESSAGE;
2379  continue;
2380  }
2381  break;
2382  }
2383 
2384  case OP_DISPLAY_MESSAGE:
2385  case OP_DISPLAY_HEADERS: /* don't weed the headers */
2387  break;
2388  /* toggle the weeding of headers so that a user can press the key
2389  * again while reading the message. */
2390  if (op == OP_DISPLAY_HEADERS)
2391  bool_str_toggle(Config, "weed", NULL);
2392 
2393  OptNeedResort = false;
2394 
2395  if (((C_Sort & SORT_MASK) == SORT_THREADS) && CUR_EMAIL->collapsed)
2396  {
2399  if (C_UncollapseJump)
2401  }
2402 
2403  if (C_PgpAutoDecode && (tag || !(CUR_EMAIL->security & PGP_TRADITIONAL_CHECKED)))
2404  {
2405  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
2406  el_add_tagged(&el, Context, CUR_EMAIL, tag);
2407  mutt_check_traditional_pgp(&el, &menu->redraw);
2408  emaillist_clear(&el);
2409  }
2410  int hint =
2412 
2414  if (op < 0)
2415  {
2416  OptNeedResort = false;
2417  break;
2418  }
2419 
2420  /* This is used to redirect a single operation back here afterwards. If
2421  * mutt_display_message() returns 0, then this flag and pager state will
2422  * be cleaned up after this switch statement. */
2423  in_pager = true;
2424  menu->oldcurrent = menu->current;
2425  if (Context && Context->mailbox)
2427  continue;
2428 
2429  case OP_EXIT:
2430  close = op;
2431  if ((!in_pager) && attach_msg)
2432  {
2433  done = true;
2434  break;
2435  }
2436 
2437  if ((!in_pager) &&
2438  (query_quadoption(C_Quit, _("Exit NeoMutt without saving?")) == MUTT_YES))
2439  {
2440  if (Context)
2441  {
2443  ctx_free(&Context);
2444  }
2445  done = true;
2446  }
2447  break;
2448 
2449  case OP_MAIN_BREAK_THREAD:
2451  break;
2452  /* L10N: CHECK_ACL */
2453  if (!check_acl(Context, MUTT_ACL_WRITE, _("Can't break thread")))
2454  break;
2455 
2456  if ((C_Sort & SORT_MASK) != SORT_THREADS)
2457  mutt_error(_("Threading is not enabled"));
2458  else if (!STAILQ_EMPTY(&CUR_EMAIL->env->in_reply_to) ||
2459  !STAILQ_EMPTY(&CUR_EMAIL->env->references))
2460  {
2461  {
2462  struct Email *e_oldcur = CUR_EMAIL;
2463 
2465  mutt_sort_headers(Context, true);
2466  menu->current = e_oldcur->vnum;
2467  }
2468 
2469  Context->mailbox->changed = true;
2470  mutt_message(_("Thread broken"));
2471 
2472  if (in_pager)
2473  {
2474  op = OP_DISPLAY_MESSAGE;
2475  continue;
2476  }
2477  else
2478  menu->redraw |= REDRAW_INDEX;
2479  }
2480  else
2481  {
2482  mutt_error(
2483  _("Thread can't be broken, message is not part of a thread"));
2484  }
2485 
2486  break;
2487 
2488  case OP_MAIN_LINK_THREADS:
2490  break;
2491  /* L10N: CHECK_ACL */
2492  if (!check_acl(Context, MUTT_ACL_WRITE, _("Can't link threads")))
2493  break;
2494 
2495  if ((C_Sort & SORT_MASK) != SORT_THREADS)
2496  mutt_error(_("Threading is not enabled"));
2497  else if (!CUR_EMAIL->env->message_id)
2498  mutt_error(_("No Message-ID: header available to link thread"));
2499  else if (!tag && (!Context->last_tag || !Context->last_tag->tagged))
2500  mutt_error(_("First, please tag a message to be linked here"));
2501  else
2502  {
2503  struct Email *e_oldcur = CUR_EMAIL;
2504  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
2505  el_add_tagged(&el, Context, Context->last_tag, tag);
2506 
2508  {
2509  mutt_sort_headers(Context, true);
2510  menu->current = e_oldcur->vnum;
2511 
2512  Context->mailbox->changed = true;
2513  mutt_message(_("Threads linked"));
2514  }
2515  else
2516  mutt_error(_("No thread linked"));
2517 
2518  emaillist_clear(&el);
2519  }
2520 
2521  if (in_pager)
2522  {
2523  op = OP_DISPLAY_MESSAGE;
2524  continue;
2525  }
2526  else
2527  menu->redraw |= REDRAW_STATUS | REDRAW_INDEX;
2528 
2529  break;
2530 
2531  case OP_EDIT_TYPE:
2533  break;
2534  mutt_edit_content_type(CUR_EMAIL, CUR_EMAIL->content, NULL);
2535  /* if we were in the pager, redisplay the message */
2536  if (in_pager)
2537  {
2538  op = OP_DISPLAY_MESSAGE;
2539  continue;
2540  }
2541  else
2542  menu->redraw = REDRAW_CURRENT;
2543  break;
2544 
2545  case OP_MAIN_NEXT_UNDELETED:
2547  break;
2548  if (menu->current >= (Context->mailbox->vcount - 1))
2549  {
2550  if (!in_pager)
2551  mutt_message(_("You are on the last message"));
2552  break;
2553  }
2554  menu->current = ci_next_undeleted(menu->current);
2555  if (menu->current == -1)
2556  {
2557  menu->current = menu->oldcurrent;
2558  if (!in_pager)
2559  mutt_error(_("No undeleted messages"));
2560  }
2561  else if (in_pager)
2562  {
2563  op = OP_DISPLAY_MESSAGE;
2564  continue;
2565  }
2566  else
2567  menu->redraw = REDRAW_MOTION;
2568  break;
2569 
2570  case OP_NEXT_ENTRY:
2572  break;
2573  if (menu->current >= (Context->mailbox->vcount - 1))
2574  {
2575  if (!in_pager)
2576  mutt_message(_("You are on the last message"));
2577  break;
2578  }
2579  menu->current++;
2580  if (in_pager)
2581  {
2582  op = OP_DISPLAY_MESSAGE;
2583  continue;
2584  }
2585  else
2586  menu->redraw = REDRAW_MOTION;
2587  break;
2588 
2589  case OP_MAIN_PREV_UNDELETED:
2591  break;
2592  if (menu->current < 1)
2593  {
2594  mutt_message(_("You are on the first message"));
2595  break;
2596  }
2597  menu->current = ci_previous_undeleted(menu->current);
2598  if (menu->current == -1)
2599  {
2600  menu->current = menu->oldcurrent;
2601  if (!in_pager)
2602  mutt_error(_("No undeleted messages"));
2603  }
2604  else if (in_pager)
2605  {
2606  op = OP_DISPLAY_MESSAGE;
2607  continue;
2608  }
2609  else
2610  menu->redraw = REDRAW_MOTION;
2611  break;
2612 
2613  case OP_PREV_ENTRY:
2615  break;
2616  if (menu->current < 1)
2617  {
2618  if (!in_pager)
2619  mutt_message(_("You are on the first message"));
2620  break;
2621  }
2622  menu->current--;
2623  if (in_pager)
2624  {
2625  op = OP_DISPLAY_MESSAGE;
2626  continue;
2627  }
2628  else
2629  menu->redraw = REDRAW_MOTION;
2630  break;
2631 
2632  case OP_DECRYPT_COPY:
2633  case OP_DECRYPT_SAVE:
2634  if (!WithCrypto)
2635  break;
2636  /* fallthrough */
2637  case OP_COPY_MESSAGE:
2638  case OP_SAVE:
2639  case OP_DECODE_COPY:
2640  case OP_DECODE_SAVE:
2641  {
2643  break;
2644  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
2645  el_add_tagged(&el, Context, CUR_EMAIL, tag);
2646  if ((mutt_save_message(Context->mailbox, &el,
2647  (op == OP_DECRYPT_SAVE) || (op == OP_SAVE) || (op == OP_DECODE_SAVE),
2648  (op == OP_DECODE_SAVE) || (op == OP_DECODE_COPY),
2649  (op == OP_DECRYPT_SAVE) || (op == OP_DECRYPT_COPY)) == 0) &&
2650  ((op == OP_SAVE) || (op == OP_DECODE_SAVE) || (op == OP_DECRYPT_SAVE)))
2651  {
2652  menu->redraw |= REDRAW_STATUS;
2653  if (tag)
2654  menu->redraw |= REDRAW_INDEX;
2655  else if (C_Resolve)
2656  {
2657  menu->current = ci_next_undeleted(menu->current);
2658  if (menu->current == -1)
2659  {
2660  menu->current = menu->oldcurrent;
2661  menu->redraw |= REDRAW_CURRENT;
2662  }
2663  else
2664  menu->redraw |= REDRAW_MOTION_RESYNC;
2665  }
2666  else
2667  menu->redraw |= REDRAW_CURRENT;
2668  }
2669  emaillist_clear(&el);
2670  break;
2671  }
2672 
2673  case OP_MAIN_NEXT_NEW:
2674  case OP_MAIN_NEXT_UNREAD:
2675  case OP_MAIN_PREV_NEW:
2676  case OP_MAIN_PREV_UNREAD:
2677  case OP_MAIN_NEXT_NEW_THEN_UNREAD:
2678  case OP_MAIN_PREV_NEW_THEN_UNREAD:
2679  {
2681  break;
2682 
2683  int first_unread = -1;
2684  int first_new = -1;
2685 
2686  const int saved_current = menu->current;
2687  int cur = menu->current;
2688  menu->current = -1;
2689  for (size_t i = 0; i != Context->mailbox->vcount; i++)
2690  {
2691  if ((op == OP_MAIN_NEXT_NEW) || (op == OP_MAIN_NEXT_UNREAD) ||
2692  (op == OP_MAIN_NEXT_NEW_THEN_UNREAD))
2693  {
2694  cur++;
2695  if (cur > (Context->mailbox->vcount - 1))
2696  {
2697  cur = 0;
2698  }
2699  }
2700  else
2701  {
2702  cur--;
2703  if (cur < 0)
2704  {
2705  cur = Context->mailbox->vcount - 1;
2706  }
2707  }
2708 
2709  struct Email *e = Context->mailbox->emails[Context->mailbox->v2r[cur]];
2710  if (e->collapsed && ((C_Sort & SORT_MASK) == SORT_THREADS))
2711  {
2712  if ((UNREAD(e) != 0) && (first_unread == -1))
2713  first_unread = cur;
2714  if ((UNREAD(e) == 1) && (first_new == -1))
2715  first_new = cur;
2716  }
2717  else if (!e->deleted && !e->read)
2718  {
2719  if (first_unread == -1)
2720  first_unread = cur;
2721  if (!e->old && (first_new == -1))
2722  first_new = cur;
2723  }
2724 
2725  if (((op == OP_MAIN_NEXT_UNREAD) || (op == OP_MAIN_PREV_UNREAD)) &&
2726  (first_unread != -1))
2727  break;
2728  if (((op == OP_MAIN_NEXT_NEW) || (op == OP_MAIN_PREV_NEW) ||
2729  (op == OP_MAIN_NEXT_NEW_THEN_UNREAD) || (op == OP_MAIN_PREV_NEW_THEN_UNREAD)) &&
2730  (first_new != -1))
2731  {
2732  break;
2733  }
2734  }
2735  if (((op == OP_MAIN_NEXT_NEW) || (op == OP_MAIN_PREV_NEW) ||
2736  (op == OP_MAIN_NEXT_NEW_THEN_UNREAD) || (op == OP_MAIN_PREV_NEW_THEN_UNREAD)) &&
2737  (first_new != -1))
2738  {
2739  menu->current = first_new;
2740  }
2741  else if (((op == OP_MAIN_NEXT_UNREAD) || (op == OP_MAIN_PREV_UNREAD) ||
2742  (op == OP_MAIN_NEXT_NEW_THEN_UNREAD) || (op == OP_MAIN_PREV_NEW_THEN_UNREAD)) &&
2743  (first_unread != -1))
2744  {
2745  menu->current = first_unread;
2746  }
2747 
2748  if (menu->current == -1)
2749  {
2750  menu->current = menu->oldcurrent;
2751  if ((op == OP_MAIN_NEXT_NEW) || (op == OP_MAIN_PREV_NEW))
2752  {
2753  if (Context->pattern)
2754  mutt_error(_("No new messages in this limited view"));
2755  else
2756  mutt_error(_("No new messages"));
2757  }
2758  else
2759  {
2760  if (Context->pattern)
2761  mutt_error(_("No unread messages in this limited view"));
2762  else
2763  mutt_error(_("No unread messages"));
2764  }
2765  break;
2766  }
2767 
2768  if ((op == OP_MAIN_NEXT_NEW) || (op == OP_MAIN_NEXT_UNREAD) ||
2769  (op == OP_MAIN_NEXT_NEW_THEN_UNREAD))
2770  {
2771  if (saved_current > menu->current)
2772  {
2773  mutt_message(_("Search wrapped to top"));
2774  }
2775  }
2776  else if (saved_current < menu->current)
2777  {
2778  mutt_message(_("Search wrapped to bottom"));
2779  }
2780 
2781  if (in_pager)
2782  {
2783  op = OP_DISPLAY_MESSAGE;
2784  continue;
2785  }
2786  else
2787  menu->redraw = REDRAW_MOTION;
2788  break;
2789  }
2790  case OP_FLAG_MESSAGE:
2792  break;
2793  /* L10N: CHECK_ACL */
2794  if (!check_acl(Context, MUTT_ACL_WRITE, _("Can't flag message")))
2795  break;
2796 
2797  if (tag)
2798  {
2799  for (size_t i = 0; i < Context->mailbox->msg_count; i++)
2800  {
2801  if (message_is_tagged(Context, i))
2802  {
2805  }
2806  }
2807 
2808  menu->redraw |= REDRAW_INDEX;
2809  }
2810  else
2811  {
2813  if (C_Resolve)
2814  {
2815  menu->current = ci_next_undeleted(menu->current);
2816  if (menu->current == -1)
2817  {
2818  menu->current = menu->oldcurrent;
2819  menu->redraw |= REDRAW_CURRENT;
2820  }
2821  else
2822  menu->redraw |= REDRAW_MOTION_RESYNC;
2823  }
2824  else
2825  menu->redraw |= REDRAW_CURRENT;
2826  }
2827  menu->redraw |= REDRAW_STATUS;
2828  break;
2829 
2830  case OP_TOGGLE_NEW:
2832  break;
2833  /* L10N: CHECK_ACL */
2834  if (!check_acl(Context, MUTT_ACL_SEEN, _("Can't toggle new")))
2835  break;
2836 
2837  if (tag)
2838  {
2839  for (size_t i = 0; i < Context->mailbox->msg_count; i++)
2840  {
2841  if (!message_is_tagged(Context, i))
2842  continue;
2843 
2844  if (Context->mailbox->emails[i]->read || Context->mailbox->emails[i]->old)
2846  else
2848  }
2849  menu->redraw |= REDRAW_STATUS | REDRAW_INDEX;
2850  }
2851  else
2852  {
2853  if (CUR_EMAIL->read || CUR_EMAIL->old)
2855  else
2857 
2858  if (C_Resolve)
2859  {
2860  menu->current = ci_next_undeleted(menu->current);
2861  if (menu->current == -1)
2862  {
2863  menu->current = menu->oldcurrent;
2864  menu->redraw |= REDRAW_CURRENT;
2865  }
2866  else
2867  menu->redraw |= REDRAW_MOTION_RESYNC;
2868  }
2869  else
2870  menu->redraw |= REDRAW_CURRENT;
2871  menu->redraw |= REDRAW_STATUS;
2872  }
2873  break;
2874 
2875  case OP_TOGGLE_WRITE:
2876  if (!prereq(Context, menu, CHECK_IN_MAILBOX))
2877  break;
2878  if (mx_toggle_write(Context->mailbox) == 0)
2879  {
2880  if (in_pager)
2881  {
2882  op = OP_DISPLAY_MESSAGE;
2883  continue;
2884  }
2885  else
2886  menu->redraw |= REDRAW_STATUS;
2887  }
2888  break;
2889 
2890  case OP_MAIN_NEXT_THREAD:
2891  case OP_MAIN_NEXT_SUBTHREAD:
2892  case OP_MAIN_PREV_THREAD:
2893  case OP_MAIN_PREV_SUBTHREAD:
2895  break;
2896 
2897  switch (op)
2898  {
2899  case OP_MAIN_NEXT_THREAD:
2901  break;
2902 
2903  case OP_MAIN_NEXT_SUBTHREAD:
2905  break;
2906 
2907  case OP_MAIN_PREV_THREAD:
2909  break;
2910 
2911  case OP_MAIN_PREV_SUBTHREAD:
2913  break;
2914  }
2915 
2916  if (menu->current < 0)
2917  {
2918  menu->current = menu->oldcurrent;
2919  if ((op == OP_MAIN_NEXT_THREAD) || (op == OP_MAIN_NEXT_SUBTHREAD))
2920  mutt_error(_("No more threads"));
2921  else
2922  mutt_error(_("You are on the first thread"));
2923  }
2924  else if (in_pager)
2925  {
2926  op = OP_DISPLAY_MESSAGE;
2927  continue;
2928  }
2929  else
2930  menu->redraw = REDRAW_MOTION;
2931  break;
2932 
2933  case OP_MAIN_ROOT_MESSAGE:
2934  case OP_MAIN_PARENT_MESSAGE:
2936  break;
2937 
2938  menu->current = mutt_parent_message(Context, CUR_EMAIL, op == OP_MAIN_ROOT_MESSAGE);
2939  if (menu->current < 0)
2940  {
2941  menu->current = menu->oldcurrent;
2942  }
2943  else if (in_pager)
2944  {
2945  op = OP_DISPLAY_MESSAGE;
2946  continue;
2947  }
2948  else
2949  menu->redraw = REDRAW_MOTION;
2950  break;
2951 
2952  case OP_MAIN_SET_FLAG:
2953  case OP_MAIN_CLEAR_FLAG:
2954  {
2956  break;
2957  /* check_acl(MUTT_ACL_WRITE); */
2958 
2959  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
2960  el_add_tagged(&el, Context, CUR_EMAIL, tag);
2961 
2962  if (mutt_change_flag(Context->mailbox, &el, (op == OP_MAIN_SET_FLAG)) == 0)
2963  {
2964  menu->redraw |= REDRAW_STATUS;
2965  if (tag)
2966  menu->redraw |= REDRAW_INDEX;
2967  else if (C_Resolve)
2968  {
2969  menu->current = ci_next_undeleted(menu->current);
2970  if (menu->current == -1)
2971  {
2972  menu->current = menu->oldcurrent;
2973  menu->redraw |= REDRAW_CURRENT;
2974  }
2975  else
2976  menu->redraw |= REDRAW_MOTION_RESYNC;
2977  }
2978  else
2979  menu->redraw |= REDRAW_CURRENT;
2980  }
2981  emaillist_clear(&el);
2982  break;
2983  }
2984 
2985  case OP_MAIN_COLLAPSE_THREAD:
2987  break;
2988 
2989  if ((C_Sort & SORT_MASK) != SORT_THREADS)
2990  {
2991  mutt_error(_("Threading is not enabled"));
2992  break;
2993  }
2994 
2995  if (CUR_EMAIL->collapsed)
2996  {
2999  if (C_UncollapseJump)
3001  }
3002  else if (CAN_COLLAPSE(CUR_EMAIL))
3003  {
3006  }
3007  else
3008  {
3009  mutt_error(_("Thread contains unread or flagged messages"));
3010  break;
3011  }
3012 
3013  menu->redraw = REDRAW_INDEX | REDRAW_STATUS;
3014 
3015  break;
3016 
3017  case OP_MAIN_COLLAPSE_ALL:
3019  break;
3020 
3021  if ((C_Sort & SORT_MASK) != SORT_THREADS)
3022  {
3023  mutt_error(_("Threading is not enabled"));
3024  break;
3025  }
3026  collapse_all(menu, 1);
3027  break;
3028 
3029  /* --------------------------------------------------------------------
3030  * These functions are invoked directly from the internal-pager
3031  */
3032 
3033  case OP_BOUNCE_MESSAGE:
3034  {
3036  break;
3037 
3038  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3039  el_add_tagged(&el, Context, CUR_EMAIL, tag);
3041  emaillist_clear(&el);
3042  break;
3043  }
3044 
3045  case OP_CREATE_ALIAS:
3047  CUR_EMAIL->env :
3048  NULL,
3049  NULL);
3050  menu->redraw |= REDRAW_CURRENT;
3051  break;
3052 
3053  case OP_QUERY:
3054  if (!prereq(Context, menu, CHECK_ATTACH))
3055  break;
3056  mutt_query_menu(NULL, 0);
3057  break;
3058 
3059  case OP_PURGE_MESSAGE:
3060  case OP_DELETE:
3061  {
3063  break;
3064  /* L10N: CHECK_ACL */
3065  if (!check_acl(Context, MUTT_ACL_DELETE, _("Can't delete message")))
3066  break;
3067 
3068  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3069  el_add_tagged(&el, Context, CUR_EMAIL, tag);
3070 
3072  mutt_emails_set_flag(Context->mailbox, &el, MUTT_PURGE, (op == OP_PURGE_MESSAGE));
3073  if (C_DeleteUntag)
3075  emaillist_clear(&el);
3076 
3077  if (tag)
3078  {
3079  menu->redraw |= REDRAW_INDEX;
3080  }
3081  else
3082  {
3083  if (C_Resolve)
3084  {
3085  menu->current = ci_next_undeleted(menu->current);
3086  if (menu->current == -1)
3087  {
3088  menu->current = menu->oldcurrent;
3089  menu->redraw |= REDRAW_CURRENT;
3090  }
3091  else if (in_pager)
3092  {
3093  op = OP_DISPLAY_MESSAGE;
3094  continue;
3095  }
3096  else
3097  menu->redraw |= REDRAW_MOTION_RESYNC;
3098  }
3099  else
3100  menu->redraw |= REDRAW_CURRENT;
3101  }
3102  menu->redraw |= REDRAW_STATUS;
3103  break;
3104  }
3105 
3106  case OP_DELETE_THREAD:
3107  case OP_DELETE_SUBTHREAD:
3108  case OP_PURGE_THREAD:
3109  {
3111  break;
3112  /* L10N: CHECK_ACL */
3113  /* L10N: Due to the implementation details we do not know whether we
3114  delete zero, 1, 12, ... messages. So in English we use
3115  "messages". Your language might have other means to express this. */
3116  if (!check_acl(Context, MUTT_ACL_DELETE, _("Can't delete messages")))
3117  break;
3118 
3119  int subthread = (op == OP_DELETE_SUBTHREAD);
3120  int rc = mutt_thread_set_flag(CUR_EMAIL, MUTT_DELETE, true, subthread);
3121  if (rc == -1)
3122  break;
3123  if (op == OP_PURGE_THREAD)
3124  {
3125  rc = mutt_thread_set_flag(CUR_EMAIL, MUTT_PURGE, true, subthread);
3126  if (rc == -1)
3127  break;
3128  }
3129 
3130  if (C_DeleteUntag)
3131  mutt_thread_set_flag(CUR_EMAIL, MUTT_TAG, false, subthread);
3132  if (C_Resolve)
3133  {
3134  menu->current = ci_next_undeleted(menu->current);
3135  if (menu->current == -1)
3136  menu->current = menu->oldcurrent;
3137  }
3138  menu->redraw |= REDRAW_INDEX | REDRAW_STATUS;
3139  break;
3140  }
3141 
3142 #ifdef USE_NNTP
3143  case OP_CATCHUP:
3145  break;
3146  if (Context && (Context->mailbox->magic == MUTT_NNTP))
3147  {
3148  struct NntpMboxData *mdata = Context->mailbox->mdata;
3149  if (mutt_newsgroup_catchup(Context->mailbox, mdata->adata, mdata->group))
3150  menu->redraw = REDRAW_INDEX | REDRAW_STATUS;
3151  }
3152  break;
3153 #endif
3154 
3155  case OP_DISPLAY_ADDRESS:
3157  break;
3159  break;
3160 
3161  case OP_ENTER_COMMAND:
3163  if (Context)
3165  break;
3166 
3167  case OP_EDIT_OR_VIEW_RAW_MESSAGE:
3168  case OP_EDIT_RAW_MESSAGE:
3169  case OP_VIEW_RAW_MESSAGE:
3170  {
3171  /* TODO split this into 3 cases? */
3173  break;
3174  bool edit;
3175  if (op == OP_EDIT_RAW_MESSAGE)
3176  {
3177  if (!prereq(Context, menu, CHECK_READONLY))
3178  break;
3179  /* L10N: CHECK_ACL */
3180  if (!check_acl(Context, MUTT_ACL_INSERT, _("Can't edit message")))
3181  break;
3182  edit = true;
3183  }
3184  else if (op == OP_EDIT_OR_VIEW_RAW_MESSAGE)
3186  else
3187  edit = false;
3188 
3189  if (C_PgpAutoDecode && (tag || !(CUR_EMAIL->security & PGP_TRADITIONAL_CHECKED)))
3190  {
3191  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3192  el_add_tagged(&el, Context, CUR_EMAIL, tag);
3193  mutt_check_traditional_pgp(&el, &menu->redraw);
3194  emaillist_clear(&el);
3195  }
3196  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3197  el_add_tagged(&el, Context, CUR_EMAIL, tag);
3198  mutt_ev_message(Context->mailbox, &el, edit ? EVM_EDIT : EVM_VIEW);
3199  emaillist_clear(&el);
3200  menu->redraw = REDRAW_FULL;
3201 
3202  break;
3203  }
3204 
3205  case OP_FORWARD_MESSAGE:
3206  {
3208  break;
3209  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3210  el_add_tagged(&el, Context, CUR_EMAIL, tag);
3211  if (C_PgpAutoDecode && (tag || !(CUR_EMAIL->security & PGP_TRADITIONAL_CHECKED)))
3212  {
3213  mutt_check_traditional_pgp(&el, &menu->redraw);
3214  }
3215  ci_send_message(SEND_FORWARD, NULL, NULL, Context, &el);
3216  emaillist_clear(&el);
3217  menu->redraw = REDRAW_FULL;
3218  break;
3219  }
3220 
3221  case OP_FORGET_PASSPHRASE:
3223  break;
3224 
3225  case OP_GROUP_REPLY:
3226  case OP_GROUP_CHAT_REPLY:
3227  {
3228  SendFlags replyflags = SEND_REPLY;
3229  if (op == OP_GROUP_REPLY)
3230  replyflags |= SEND_GROUP_REPLY;
3231  else
3232  replyflags |= SEND_GROUP_CHAT_REPLY;
3234  break;
3235  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3236  el_add_tagged(&el, Context, CUR_EMAIL, tag);
3237  if (C_PgpAutoDecode && (tag || !(CUR_EMAIL->security & PGP_TRADITIONAL_CHECKED)))
3238  {
3239  mutt_check_traditional_pgp(&el, &menu->redraw);
3240  }
3241  ci_send_message(replyflags, NULL, NULL, Context, &el);
3242  emaillist_clear(&el);
3243  menu->redraw = REDRAW_FULL;
3244  break;
3245  }
3246 
3247  case OP_EDIT_LABEL:
3248  {
3250  break;
3251 
3252  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3253  el_add_tagged(&el, Context, CUR_EMAIL, tag);
3254  int num_changed = mutt_label_message(Context->mailbox, &el);
3255  emaillist_clear(&el);
3256 
3257  if (num_changed > 0)
3258  {
3259  Context->mailbox->changed = true;
3260  menu->redraw = REDRAW_FULL;
3261  /* L10N: This is displayed when the x-label on one or more
3262  messages is edited. */
3263  mutt_message(ngettext("%d label changed", "%d labels changed", num_changed),
3264  num_changed);
3265  }
3266  else
3267  {
3268  /* L10N: This is displayed when editing an x-label, but no messages
3269  were updated. Possibly due to canceling at the prompt or if the new
3270  label is the same as the old label. */
3271  mutt_message(_("No labels changed"));
3272  }
3273  break;
3274  }
3275 
3276  case OP_LIST_REPLY:
3277  {
3279  break;
3280  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3281  el_add_tagged(&el, Context, CUR_EMAIL, tag);
3282  if (C_PgpAutoDecode && (tag || !(CUR_EMAIL->security & PGP_TRADITIONAL_CHECKED)))
3283  {
3284  mutt_check_traditional_pgp(&el, &menu->redraw);
3285  }
3286  ci_send_message(SEND_REPLY | SEND_LIST_REPLY, NULL, NULL, Context, &el);
3287  emaillist_clear(&el);
3288  menu->redraw = REDRAW_FULL;
3289  break;
3290  }
3291 
3292  case OP_MAIL:
3293  if (!prereq(Context, menu, CHECK_ATTACH))
3294  break;
3295  ci_send_message(SEND_NO_FLAGS, NULL, NULL, Context, NULL);
3296  menu->redraw = REDRAW_FULL;
3297  break;
3298 
3299  case OP_MAIL_KEY:
3300  if (!(WithCrypto & APPLICATION_PGP))
3301  break;
3302  if (!prereq(Context, menu, CHECK_ATTACH))
3303  break;
3304  ci_send_message(SEND_KEY, NULL, NULL, NULL, NULL);
3305  menu->redraw = REDRAW_FULL;
3306  break;
3307 
3308  case OP_EXTRACT_KEYS:
3309  {
3310  if (!WithCrypto)
3311  break;
3313  break;
3314  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3315  el_add_tagged(&el, Context, CUR_EMAIL, tag);
3317  emaillist_clear(&el);
3318  menu->redraw = REDRAW_FULL;
3319  break;
3320  }
3321 
3322  case OP_CHECK_TRADITIONAL:
3323  {
3324  if (!(WithCrypto & APPLICATION_PGP))
3325  break;
3327  break;
3328  if (tag || !(CUR_EMAIL->security & PGP_TRADITIONAL_CHECKED))
3329  {
3330  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3331  el_add_tagged(&el, Context, CUR_EMAIL, tag);
3332  mutt_check_traditional_pgp(&el, &menu->redraw);
3333  emaillist_clear(&el);
3334  }
3335 
3336  if (in_pager)
3337  {
3338  op = OP_DISPLAY_MESSAGE;
3339  continue;
3340  }
3341  break;
3342  }
3343 
3344  case OP_PIPE:
3345  {
3347  break;
3348  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3349  el_add_tagged(&el, Context, CUR_EMAIL, tag);
3351  emaillist_clear(&el);
3352 
3353 #ifdef USE_IMAP
3354  /* in an IMAP folder index with imap_peek=no, piping could change
3355  * new or old messages status to read. Redraw what's needed. */
3356  if ((Context->mailbox->magic == MUTT_IMAP) && !C_ImapPeek)
3357  {
3358  menu->redraw |= (tag ? REDRAW_INDEX : REDRAW_CURRENT) | REDRAW_STATUS;
3359  }
3360 #endif
3361  break;
3362  }
3363 
3364  case OP_PRINT:
3365  {
3367  break;
3368  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3369  el_add_tagged(&el, Context, CUR_EMAIL, tag);
3371  emaillist_clear(&el);
3372 
3373 #ifdef USE_IMAP
3374  /* in an IMAP folder index with imap_peek=no, printing could change
3375  * new or old messages status to read. Redraw what's needed. */
3376  if ((Context->mailbox->magic == MUTT_IMAP) && !C_ImapPeek)
3377  {
3378  menu->redraw |= (tag ? REDRAW_INDEX : REDRAW_CURRENT) | REDRAW_STATUS;
3379  }
3380 #endif
3381  break;
3382  }
3383 
3384  case OP_MAIN_READ_THREAD:
3385  case OP_MAIN_READ_SUBTHREAD:
3386  {
3388  break;
3389  /* L10N: CHECK_ACL */
3390  /* L10N: Due to the implementation details we do not know whether we
3391  mark zero, 1, 12, ... messages as read. So in English we use
3392  "messages". Your language might have other means to express this. */
3393  if (!check_acl(Context, MUTT_ACL_SEEN, _("Can't mark messages as read")))
3394  break;
3395 
3396  int rc = mutt_thread_set_flag(CUR_EMAIL, MUTT_READ, true, (op != OP_MAIN_READ_THREAD));
3397  if (rc != -1)
3398  {
3399  if (C_Resolve)
3400  {
3401  menu->current =
3402  ((op == OP_MAIN_READ_THREAD) ? mutt_next_thread(CUR_EMAIL) :
3404  if (menu->current == -1)
3405  {
3406  menu->current = menu->oldcurrent;
3407  }
3408  else if (in_pager)
3409  {
3410  op = OP_DISPLAY_MESSAGE;
3411  continue;
3412  }
3413  }
3414  menu->redraw |= REDRAW_INDEX | REDRAW_STATUS;
3415  }
3416  break;
3417  }
3418 
3419  case OP_MARK_MSG:
3421  break;
3422  if (CUR_EMAIL->env->message_id)
3423  {
3424  char buf2[128];
3425 
3426  buf2[0] = '\0';
3427  /* L10N: This is the prompt for <mark-message>. Whatever they
3428  enter will be prefixed by $mark_macro_prefix and will become
3429  a macro hotkey to jump to the currently selected message. */
3430  if (!mutt_get_field(_("Enter macro stroke: "), buf2, sizeof(buf2), MUTT_CLEAR) &&
3431  buf2[0])
3432  {
3433  char str[256], macro[256];
3434  snprintf(str, sizeof(str), "%s%s", C_MarkMacroPrefix, buf2);
3435  snprintf(macro, sizeof(macro), "<search>~i \"%s\"\n", CUR_EMAIL->env->message_id);
3436  /* L10N: "message hotkey" is the key bindings menu description of a
3437  macro created by <mark-message>. */
3438  km_bind(str, MENU_MAIN, OP_MACRO, macro, _("message hotkey"));
3439 
3440  /* L10N: This is echoed after <mark-message> creates a new hotkey
3441  macro. %s is the hotkey string ($mark_macro_prefix followed
3442  by whatever they typed at the prompt.) */
3443  snprintf(buf2, sizeof(buf2), _("Message bound to %s"), str);
3444  mutt_message(buf2);
3445  mutt_debug(LL_DEBUG1, "Mark: %s => %s\n", str, macro);
3446  }
3447  }
3448  else
3449  {
3450  /* L10N: This error is printed if <mark-message> can't find a
3451  Message-ID for the currently selected message in the index. */
3452  mutt_error(_("No message ID to macro"));
3453  }
3454  break;
3455 
3456  case OP_RECALL_MESSAGE:
3457  if (!prereq(Context, menu, CHECK_ATTACH))
3458  break;
3459  ci_send_message(SEND_POSTPONED, NULL, NULL, Context, NULL);
3460  menu->redraw = REDRAW_FULL;
3461  break;
3462 
3463  case OP_RESEND:
3465  break;
3466 
3467  if (tag)
3468  {
3469  for (size_t i = 0; i < Context->mailbox->msg_count; i++)
3470  {
3471  if (message_is_tagged(Context, i))
3473  }
3474  }
3475  else
3477 
3478  menu->redraw = REDRAW_FULL;
3479  break;
3480 
3481 #ifdef USE_NNTP
3482  case OP_FOLLOWUP:
3483  case OP_FORWARD_TO_GROUP:
3485  break;
3486  /* fallthrough */
3487 
3488  case OP_POST:
3490  break;
3491  if ((op != OP_FOLLOWUP) || !CUR_EMAIL->env->followup_to ||
3492  (mutt_str_strcasecmp(CUR_EMAIL->env->followup_to, "poster") != 0) ||
3494  _("Reply by mail as poster prefers?")) != MUTT_YES))
3495  {
3496  if (Context && (Context->mailbox->magic == MUTT_NNTP) &&
3497  !((struct NntpMboxData *) Context->mailbox->mdata)->allowed && (query_quadoption(C_PostModerated, _("Posting to this group not allowed, may be moderated. Continue?")) != MUTT_YES))
3498  {
3499  break;
3500  }
3501  if (op == OP_POST)
3502  ci_send_message(SEND_NEWS, NULL, NULL, Context, NULL);
3503  else
3504  {
3506  break;
3507  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3508  el_add_tagged(&el, Context, CUR_EMAIL, tag);
3509  ci_send_message(((op == OP_FOLLOWUP) ? SEND_REPLY : SEND_FORWARD) | SEND_NEWS,
3510  NULL, NULL, Context, &el);
3511  emaillist_clear(&el);
3512  }
3513  menu->redraw = REDRAW_FULL;
3514  break;
3515  }
3516 #endif
3517  /* fallthrough */
3518  case OP_REPLY:
3519  {
3521  break;
3522  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3523  el_add_tagged(&el, Context, CUR_EMAIL, tag);
3524  if (C_PgpAutoDecode && (tag || !(CUR_EMAIL->security & PGP_TRADITIONAL_CHECKED)))
3525  {
3526  mutt_check_traditional_pgp(&el, &menu->redraw);
3527  }
3528  ci_send_message(SEND_REPLY, NULL, NULL, Context, &el);
3529  emaillist_clear(&el);
3530  menu->redraw = REDRAW_FULL;
3531  break;
3532  }
3533 
3534  case OP_SHELL_ESCAPE:
3536  break;
3537 
3538  case OP_TAG_THREAD:
3539  case OP_TAG_SUBTHREAD:
3540  {
3542  break;
3543 
3544  int rc = mutt_thread_set_flag(CUR_EMAIL, MUTT_TAG, !CUR_EMAIL->tagged,
3545  (op != OP_TAG_THREAD));
3546  if (rc != -1)
3547  {
3548  if (C_Resolve)
3549  {
3550  if (op == OP_TAG_THREAD)
3552  else
3554 
3555  if (menu->current == -1)
3556  menu->current = menu->oldcurrent;
3557  }
3558  menu->redraw |= REDRAW_INDEX | REDRAW_STATUS;
3559  }
3560  break;
3561  }
3562 
3563  case OP_UNDELETE:
3564  {
3566  break;
3567  /* L10N: CHECK_ACL */
3568  if (!check_acl(Context, MUTT_ACL_DELETE, _("Can't undelete message")))
3569  break;
3570 
3571  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3572  el_add_tagged(&el, Context, CUR_EMAIL, tag);
3573 
3576  emaillist_clear(&el);
3577 
3578  if (tag)
3579  {
3580  menu->redraw |= REDRAW_INDEX;
3581  }
3582  else
3583  {
3584  if (C_Resolve && (menu->current < (Context->mailbox->vcount - 1)))
3585  {
3586  menu->current++;
3587  menu->redraw |= REDRAW_MOTION_RESYNC;
3588  }
3589  else
3590  menu->redraw |= REDRAW_CURRENT;
3591  }
3592 
3593  menu->redraw |= REDRAW_STATUS;
3594  break;
3595  }
3596 
3597  case OP_UNDELETE_THREAD:
3598  case OP_UNDELETE_SUBTHREAD:
3599  {
3601  break;
3602  /* L10N: CHECK_ACL */
3603  /* L10N: Due to the implementation details we do not know whether we
3604  undelete zero, 1, 12, ... messages. So in English we use
3605  "messages". Your language might have other means to express this. */
3606  if (!check_acl(Context, MUTT_ACL_DELETE, _("Can't undelete messages")))
3607  break;
3608 
3609  int rc = mutt_thread_set_flag(CUR_EMAIL, MUTT_DELETE, false,
3610  (op != OP_UNDELETE_THREAD));
3611  if (rc != -1)
3612  {
3613  rc = mutt_thread_set_flag(CUR_EMAIL, MUTT_PURGE, false, (op != OP_UNDELETE_THREAD));
3614  }
3615  if (rc != -1)
3616  {
3617  if (C_Resolve)
3618  {
3619  if (op == OP_UNDELETE_THREAD)
3621  else
3623 
3624  if (menu->current == -1)
3625  menu->current = menu->oldcurrent;
3626  }
3627  menu->redraw |= REDRAW_INDEX | REDRAW_STATUS;
3628  }
3629  break;
3630  }
3631 
3632  case OP_VERSION:
3634  break;
3635 
3636  case OP_MAILBOX_LIST:
3638  break;
3639 
3640  case OP_VIEW_ATTACHMENTS:
3642  break;
3644  if (CUR_EMAIL->attach_del)
3645  Context->mailbox->changed = true;
3646  menu->redraw = REDRAW_FULL;
3647  break;
3648 
3649  case OP_END_COND:
3650  break;
3651 
3652  case OP_WHAT_KEY:
3653  mutt_what_key();
3654  break;
3655 
3656 #ifdef USE_SIDEBAR
3657  case OP_SIDEBAR_NEXT:
3658  case OP_SIDEBAR_NEXT_NEW:
3659  case OP_SIDEBAR_PAGE_DOWN:
3660  case OP_SIDEBAR_PAGE_UP:
3661  case OP_SIDEBAR_PREV:
3662  case OP_SIDEBAR_PREV_NEW:
3664  break;
3665 
3666  case OP_SIDEBAR_TOGGLE_VISIBLE:
3667  bool_str_toggle(Config, "sidebar_visible", NULL);
3669  break;
3670 #endif
3671 
3672 #ifdef USE_AUTOCRYPT
3673  case OP_AUTOCRYPT_ACCT_MENU:
3675  break;
3676 #endif
3677 
3678  default:
3679  if (!in_pager)
3681  }
3682 
3683 #ifdef USE_NOTMUCH
3684  if (Context)
3686 #endif
3687 
3688  if (in_pager)
3689  {
3691  in_pager = false;
3692  menu->redraw = REDRAW_FULL;
3693  }
3694 
3695  if (done)
3696  break;
3697  }
3698 
3699  mutt_menu_pop_current(menu);
3700  mutt_menu_free(&menu);
3701  return close;
3702 }
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:290
struct Email ** emails
Array of Emails.
Definition: mailbox.h:110
#define MUTT_OPEN_NO_FLAGS
No flags are set.
Definition: mx.h:50
int mutt_save_message(struct Mailbox *m, struct EmailList *el, bool delete_original, bool decode, bool decrypt)
Save an email.
Definition: commands.c:1016
The "current" mailbox.
Definition: context.h:36
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox&#39;s path string.
Definition: mailbox.h:194
struct NntpAccountData * nntp_select_server(struct Mailbox *m, char *server, bool leave_lock)
Open a connection to an NNTP server.
Definition: newsrc.c:982
int mutt_pattern_func(int op, char *prompt)
Perform some Pattern matching.
Definition: pattern.c:2413
int mutt_thread_set_flag(struct Email *e, int flag, bool bf, bool subthread)
Set a flag on an entire thread.
Definition: flags.c:375
#define REDRAW_FULL
Redraw everything.
Definition: mutt_menu.h:47
bool mutt_mailbox_list(void)
List the mailboxes with new mail.
Definition: mutt_mailbox.c:202
#define NONULL(x)
Definition: string2.h:37
int msg_count
Total number of messages.
Definition: mailbox.h:102
#define mutt_set_flag(m, e, flag, bf)
Definition: protos.h:69
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:690
The envelope/body of an email.
Definition: email.h:37
#define MUTT_CLEAR
Clear input if printable character is pressed.
Definition: mutt.h:68
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:100
#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:1183
struct NntpMboxData * mutt_newsgroup_catchup(struct Mailbox *m, struct NntpAccountData *adata, char *group)
Catchup newsgroup.
Definition: newsrc.c:1263
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:209
int mx_mbox_check(struct Mailbox *m, int *index_hint)
Check for new mail - Wrapper for MxOps::mbox_check()
Definition: mx.c:1034
&#39;NNTP&#39; (Usenet) Mailbox type
Definition: mailbox.h:51
int mx_mbox_close(struct Context **ptr)
Save changes and close mailbox.
Definition: mx.c:561
void nm_query_window_backward(void)
Function to move the current search window backward in time.
bool C_UncollapseJump
Config: When opening a thread, jump to the next unread message.
Definition: index.c:111
enum QuadOption query_quadoption(enum QuadOption opt, const char *prompt)
Ask the user a quad-question.
Definition: init.c:3340
#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:70
int oldcurrent
For driver use only.
Definition: mutt_menu.h:109
User answered &#39;Yes&#39;, or assume &#39;Yes&#39;.
Definition: quad.h:39
WHERE unsigned char C_Quit
Config: Prompt before exiting NeoMutt.
Definition: globals.h:189
void mutt_display_address(struct Envelope *env)
Display the address of a message.
Definition: commands.c:899
struct NntpAccountData * adata
Definition: nntp.h:153
void mutt_emails_set_flag(struct Mailbox *m, struct EmailList *el, int flag, bool bf)
Set flag on messages.
Definition: flags.c:354
static void index_custom_redraw(struct Menu *menu)
Redraw the index - Implements Menu::menu_custom_redraw()
Definition: index.c:1010
#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:109
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:195
void mutt_view_attachments(struct Email *e)
Show the attachments in a Menu.
Definition: recvattach.c:1408
bool mutt_limit_current_thread(struct Email *e)
Limit the email view to the current thread.
Definition: pattern.c:2372
#define SEND_FORWARD
Forward email.
Definition: send.h:91
void mutt_window_clrtoeol(struct MuttWindow *win)
Clear to the end of the line.
Definition: mutt_window.c:117
void mutt_resize_screen(void)
Update NeoMutt&#39;s opinion about the window size (CURSES)
Definition: resize.c:100
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:111
#define CHECK_ATTACH
Is the user in message-attach mode?
Definition: index.c:157
WHERE bool OptNeedResort
(pseudo) used to force a re-sort
Definition: options.h:41
void index_make_entry(char *buf, size_t buflen, struct Menu *menu, int line)
Format a menu item for the index list - Implements Menu::menu_make_entry()
Definition: index.c:781
void mutt_check_stats(void)
Forcibly update mailbox stats.
Definition: commands.c:1382
#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:105
bool mutt_link_threads(struct Email *parent, struct EmailList *children, struct Mailbox *m)
Forcibly link threads together.
Definition: mutt_thread.c:1476
WHERE char * C_NmQueryWindowCurrentSearch
Config: (notmuch) Current search parameters.
Definition: globals.h:174
static bool check_acl(struct Context *ctx, AclFlags acl, const char *msg)
Check the ACLs for a function.
Definition: index.c:217
#define MUTT_NM_QUERY
Notmuch query mode.
Definition: mutt.h:72
void mutt_enter_command(void)
enter a neomutt command
Definition: commands.c:853
String manipulation buffer.
Definition: buffer.h:33
#define MUTT_ACL_INSERT
Add/copy into the mailbox (used when editing a message)
Definition: mailbox.h:80
Messages to be un-deleted.
Definition: mutt.h:103
Flagged messages.
Definition: mutt.h:106
#define PGP_TRADITIONAL_CHECKED
Email has a traditional (inline) signature.
Definition: ncrypt.h:136
void mutt_unget_event(int ch, int op)
Return a keystroke to the input buffer.
Definition: curs_lib.c:763
WHERE bool C_ImapPeek
Config: (imap) Don&#39;t mark messages as read when fetching them from the server.
Definition: globals.h:231
#define _(a)
Definition: message.h:28
WHERE struct ConfigSet * Config
Wrapper around the user&#39;s config settings.
Definition: globals.h:41
WHERE bool C_BrailleFriendly
Config: Move the cursor to the beginning of the line.
Definition: globals.h:210
int index_color(int line)
Calculate the colour for a line of the index - Implements Menu::menu_color()
Definition: index.c:855
void mutt_autocrypt_account_menu(void)
Display the Autocrypt account Menu.
void menu_status_line(char *buf, size_t buflen, struct Menu *menu, const char *p)
Create the status line.
Definition: status.c:408
bool mutt_check_traditional_pgp(struct EmailList *el, MuttRedrawFlags *redraw)
Check if a message has inline PGP content.
Definition: commands.c:1366
Messages to be purged (bypass trash)
Definition: mutt.h:104
void pop_fetch_mail(void)
Fetch messages and save them in $spoolfile.
Definition: pop.c:578
char * C_MarkMacroPrefix
Config: Prefix for macros using &#39;<mark-message>&#39;.
Definition: index.c:109
bool C_CollapseAll
Config: Collapse all threads when entering a folder.
Definition: index.c:106
Index panel (list of emails)
Definition: keymap.h:77
uint8_t OpenMailboxFlags
Flags for mutt_open_mailbox(), e.g. MUTT_NOSORT.
Definition: mx.h:49
static void resort_index(struct Menu *menu)
Resort the index.
Definition: index.c:413
#define MUTT_READONLY
Open in read-only mode.
Definition: mx.h:53
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:476
struct Mailbox * mx_mbox_find2(const char *path)
XXX.
Definition: mx.c:1529
#define SEND_POSTPONED
Recall a postponed email.
Definition: send.h:92
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:704
void(* menu_make_entry)(char *buf, size_t buflen, struct Menu *menu, int line)
Format a item for a menu.
Definition: mutt_menu.h:120
#define MUTT_ACL_DELETE
Delete a message.
Definition: mailbox.h:77
struct Mapping IndexNewsHelp[]
Definition: index.c:127
#define mutt_get_field(field, buf, buflen, complete)
Definition: curs_lib.h:91
#define mutt_collapse_thread(ctx, e)
Definition: mutt_thread.h:57
int vcount
The number of virtual messages.
Definition: mailbox.h:113
void imap_logout_all(void)
close all open connections
Definition: imap.c:687
static void collapse_all(struct Menu *menu, int toggle)
Collapse/uncollapse all threads.
Definition: index.c:243
void mutt_print_message(struct Mailbox *m, struct EmailList *el)
Print a message.
Definition: commands.c:712
#define SEND_NO_FLAGS
No flags are set.
Definition: send.h:87
void mutt_beep(bool force)
Irritate the user.
Definition: curs_lib.c:96
static int ci_previous_undeleted(int msgno)
Find the previous undeleted email.
Definition: index.c:322
#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:155
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:215
void mutt_startup_shutdown_hook(HookFlags type)
Execute any startup/shutdown hooks.
Definition: hook.c:846
void mutt_window_clear_screen(void)
Clear the entire screen.
Definition: mutt_window.c:437
void mutt_curses_set_cursor(enum MuttCursorState state)
Set the cursor state.
Definition: mutt_curses.c:70
struct Mailbox * mailbox
Definition: context.h:50
Log at debug level 2.
Definition: logging.h:57
#define CHECK_IN_MAILBOX
Is there a mailbox open?
Definition: index.c:153
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:167
void mutt_flush_macro_to_endcond(void)
Drop a macro from the input buffer.
Definition: curs_lib.c:819
enum MailboxType magic
Mailbox type.
Definition: mailbox.h:116
bool message_is_visible(struct Context *ctx, int index)
Is a message in the index within limit.
Definition: context.c:332
bool readonly
Don&#39;t allow changes to the mailbox.
Definition: mailbox.h:130
void mutt_window_clearline(struct MuttWindow *win, int row)
Clear a row of a Window.
Definition: mutt_window.c:95
void emaillist_clear(struct EmailList *el)
Drop a private list of Emails.
Definition: email.c:123
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:152
int mutt_parent_message(struct Context *ctx, struct Email *e, bool find_root)
Find the parent of a message.
Definition: mutt_thread.c:1137
void mutt_what_key(void)
Ask the user to press a key.
Definition: keymap.c:1580
Display a normal cursor.
Definition: mutt_curses.h:82
int LastKey
contains the last key the user pressed
Definition: keymap.c:147
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:1221
bool mutt_mailbox_notify(struct Mailbox *m_cur)
Notify the user if there&#39;s new mail.
Definition: mutt_mailbox.c:189
void mx_fastclose_mailbox(struct Mailbox *m)
free up memory associated with the Mailbox
Definition: mx.c:395
void mutt_shell_escape(void)
invoke a command in a subshell
Definition: commands.c:825
char * group
Definition: nntp.h:140
WHERE SIG_ATOMIC_VOLATILE_T SigWinch
true after SIGWINCH is received
Definition: globals.h:82
bool nm_message_is_still_queried(struct Mailbox *m, struct Email *e)
Is a message still visible in the query?
struct Menu * menu
Needed for pattern compilation.
Definition: context.h:46
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:173
void(* menu_custom_redraw)(struct Menu *menu)
Redraw the menu.
Definition: mutt_menu.h:149
WHERE unsigned char C_PostModerated
Config: (nntp) Allow posting to moderated newsgroups.
Definition: globals.h:194
#define SEND_LIST_REPLY
Reply to mailing list.
Definition: send.h:90
#define CUR_EMAIL
Definition: index.c:140
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:115
static int mx_toggle_write(struct Mailbox *m)
Toggle the mailbox&#39;s readonly flag.
Definition: index.c:384
int mutt_display_message(struct MuttWindow *win, struct Mailbox *m, struct Email *e)
Display a message in the pager.
Definition: commands.c:196
WHERE bool C_ReadOnly
Config: Open folders in read-only mode.
Definition: globals.h:250
void * mdata
Driver specific data.
Definition: mailbox.h:147
#define MUTT_ACL_WRITE
Write to a message (for flagging or linking threads)
Definition: mailbox.h:85
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
char * nm_uri_from_query(struct Mailbox *m, char *buf, size_t buflen)
Turn a query into a URI.
void mutt_window_reflow(void)
Resize the Windows to fit the screen.
Definition: mutt_window.c:264
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
static int ci_next_undeleted(int msgno)
Find the next undeleted email.
Definition: index.c:305
#define REDRAW_MOTION_RESYNC
Redraw any changing the menu selection.
Definition: mutt_menu.h:44
#define mutt_b2s(buf)
Definition: buffer.h:41
WHERE char * C_NewsServer
Config: (nntp) Url of the news server.
Definition: globals.h:131
View the message.
Definition: protos.h:57
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:105
void nm_db_longrun_done(struct Mailbox *m)
Finish a long transaction.
Definition: nm_db.c:304
Edit the message.
Definition: protos.h:58
static int ci_first_message(void)
Get index of first new message.
Definition: index.c:340
#define mutt_mktemp(buf, buflen)
Definition: muttlib.h:76
void mutt_sort_headers(struct Context *ctx, bool init)
Sort emails by their headers.
Definition: sort.c:362
Sort by email threads.
Definition: sort2.h:56
#define CAN_COLLAPSE(email)
Definition: index.c:144
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:1054
Messages to be deleted.
Definition: mutt.h:102
A mailbox.
Definition: mailbox.h:92
#define PATH_MAX
Definition: mutt.h:50
struct MuttWindow * MuttIndexWindow
Index Window.
Definition: mutt_window.c:40
int mutt_mailbox_check(struct Mailbox *m_cur, int force)
Check all all Mailboxes for new mail.
Definition: mutt_mailbox.c:127
struct MuttWindow * indexwin
Definition: mutt_menu.h:95
int top
Entry that is the top of the current page.
Definition: mutt_menu.h:108
Nondestructive flags change (IMAP)
Definition: mx.h:75
int log_queue_save(FILE *fp)
Save the contents of the queue to a temporary file.
Definition: logging.c:378
#define UNREAD(email)
Definition: index.c:141
int nntp_check_msgid(struct Mailbox *m, const char *msgid)
Fetch article by Message-ID.
Definition: nntp.c:2222
WHERE bool C_Resolve
Config: Move to the next email whenever a command modifies an email.
Definition: globals.h:251
void nm_query_window_forward(void)
Function to move the current search window forward in time.
Tagged messages.
Definition: mutt.h:107
char * data
Pointer to data.
Definition: buffer.h:35
WHERE char * C_NewMailCommand
Config: External command to run when new mail arrives.
Definition: globals.h:139
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:750
#define mutt_next_thread(e)
Definition: mutt_thread.h:65
New messages.
Definition: mutt.h:97
Messages that have been read.
Definition: mutt.h:100
Not object-related.
Definition: notify_type.h:32
bool collapsed
Is this message part of a collapsed thread?
Definition: email.h:73
bool quiet
Inhibit status messages?
Definition: mailbox.h:129
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:1201
int msg_tagged
How many messages are tagged?
Definition: mailbox.h:108
#define CHECK_READONLY
Is the mailbox readonly?
Definition: index.c:156
int vnum
Virtual message number.
Definition: email.h:87
#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:1868
void nntp_mailbox(struct Mailbox *m, char *buf, size_t buflen)
Get first newsgroup with new messages.
Definition: newsrc.c:1335
WHERE bool OptSearchInvalid
(pseudo) used to invalidate the search pat
Definition: options.h:50
AclFlags rights
ACL bits, see AclFlags.
Definition: mailbox.h:132
int mutt_messages_in_thread(struct Mailbox *m, struct Email *e, int flag)
Count the messages in a thread.
Definition: mutt_thread.c:1392
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:350
void update_index(struct Menu *menu, struct Context *ctx, int check, int oldcount, int index_hint)
Update the index.
Definition: index.c:570
void mutt_progress_init(struct Progress *progress, const char *msg, enum ProgressType type, size_t size)
Set up a progress bar.
Definition: progress.c:156
struct Notify * notify
Notifications handler.
Definition: neomutt.h:37
WHERE bool OptRedrawTree
(pseudo) redraw the thread tree
Definition: options.h:48
#define STAILQ_NEXT(elm, field)
Definition: queue.h:398
#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:1434
NNTP-specific Mailbox data -.
Definition: nntp.h:138
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:212
int mutt_window_move(struct MuttWindow *win, int row, int col)
Move the cursor in a Window.
Definition: mutt_window.c:198
void mutt_clear_pager_position(void)
Reset the pager&#39;s viewing position.
Definition: pager.c:1930
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:312
int(* menu_color)(int line)
Calculate the colour for a line of the menu.
Definition: mutt_menu.h:144
#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:53
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: ncrypt.h:134
WHERE bool C_DeleteUntag
Config: Untag messages when they are marked for deletion.
Definition: globals.h:214
MuttRedrawFlags redraw
When to redraw the screen.
Definition: mutt_menu.h:89
int * v2r
Mapping from virtual to real msgno.
Definition: mailbox.h:112
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:399
int imap_check_mailbox(struct Mailbox *m, bool force)
use the NOOP or IDLE command to poll for new mail
Definition: imap.c:1186
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:343
int mutt_label_message(struct Mailbox *m, struct EmailList *el)
Let the user label a message.
Definition: mutt_header.c:124
Log at debug level 1.
Definition: logging.h:56
bool flagged
Marked important?
Definition: email.h:43
void mutt_browser_select_dir(const char *f)
Remember the last directory selected.
Definition: browser.c:1129
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:631
int mx_mbox_sync(struct Mailbox *m, int *index_hint)
Save changes to mailbox.
Definition: mx.c:839
#define REDRAW_INDEX
Redraw the index.
Definition: mutt_menu.h:42
int nntp_check_children(struct Mailbox *m, const char *msgid)
Fetch children of article with the Message-ID.
Definition: nntp.c:2292
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:641
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:443
bool collapsed
Are all threads collapsed?
Definition: context.h:48
bool deleted
Email is deleted.
Definition: email.h:45
#define mutt_error(...)
Definition: logging.h:84
static const struct Mapping IndexHelp[]
Definition: index.c:114
void mutt_query_menu(char *buf, size_t buflen)
Show the user the results of a Query.
Definition: query.c:650
int mutt_str_strcasecmp(const char *a, const char *b)
Compare two strings ignoring case, safely.
Definition: string.c:628
NeoMutt is about to close.
Definition: neomutt.h:50
void mutt_timeout_hook(void)
Execute any timeout hooks.
Definition: hook.c:807
int mutt_select_sort(bool reverse)
Ask the user for a sort method.
Definition: commands.c:751
int index
The absolute (unsorted) message number.
Definition: email.h:85
#define FREE(x)
Definition: memory.h:40
void crypt_extract_keys_from_messages(struct Mailbox *m, struct EmailList *el)
Extract keys from a message.
Definition: crypt.c:853
#define MUTT_ACL_SEEN
Change the &#39;seen&#39; status of a message.
Definition: mailbox.h:84
#define STAILQ_EMPTY(head)
Definition: queue.h:346
Hide the cursor.
Definition: mutt_curses.h:81
#define STAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:322
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:207
bool C_PgpAutoDecode
Config: Automatically decrypt PGP messages.
Definition: index.c:110
struct MuttWindow * MuttMessageWindow
Message Window.
Definition: mutt_window.c:42
int nm_read_entire_thread(struct Mailbox *m, struct Email *e)
Get the entire thread of an email.
bool C_ChangeFolderNext
Config: Suggest the next folder, rather than the first when using &#39;<change-folder>&#39;.
Definition: index.c:105
Messages to be un-tagged.
Definition: mutt.h:108
bool changed
Mailbox has been modified.
Definition: mailbox.h:125
void nm_db_longrun_init(struct Mailbox *m, bool writable)
Start a long transaction.
Definition: nm_db.c:289
int mutt_change_flag(struct Mailbox *m, struct EmailList *el, bool bf)
Change the flag on a Message.
Definition: flags.c:433
void ctx_free(struct Context **ptr)
Free a Context.
Definition: context.c:49
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
int bool_str_toggle(struct ConfigSet *cs, const char *name, struct Buffer *err)
Toggle the value of a bool.
Definition: bool.c:240
New mail received in Mailbox.
Definition: mx.h:72
bool mx_tags_is_supported(struct Mailbox *m)
return true if mailbox support tagging
Definition: mx.c:1238
#define CHECK_MSGCOUNT
Are there any messages?
Definition: index.c:154
#define SEND_GROUP_CHAT_REPLY
Reply to all recipients preserving To/Cc.
Definition: send.h:101
bool mutt_edit_content_type(struct Email *e, struct Body *b, FILE *fp)
Edit the content type of an attachment.
Definition: commands.c:1229
int current
Current entry.
Definition: mutt_menu.h:87
int el_add_tagged(struct EmailList *el, struct Context *ctx, struct Email *e, bool use_tagged)
Get a list of the tagged Emails.
Definition: context.c:362
struct Buffer pathbuf
Definition: mailbox.h:94
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:585
char * mutt_compile_help(char *buf, size_t buflen, enum MenuType menu, const struct Mapping *items)
Create the text for the help menu.
Definition: help.c:115
A List node for strings.
Definition: list.h:33
bool mutt_buffer_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:252
Mailbox was reopened.
Definition: mx.h:74
int mutt_resend_message(FILE *fp, struct Context *ctx, struct Email *e_cur)
Resend an email.
Definition: send.c:1493
&#39;IMAP&#39; Mailbox type
Definition: mailbox.h:52
bool notify_send(struct Notify *notify, int type, int subtype, intptr_t data)
Send out a notification message.
Definition: notify.c:145
char * pattern
Limit pattern string.
Definition: context.h:39
int mutt_search_command(int cur, int op)
Perform a search.
Definition: pattern.c:2554
#define STAILQ_FIRST(head)
Definition: queue.h:348
#define WithCrypto
Definition: ncrypt.h:160
WHERE bool OptNews
(pseudo) used to change reader mode
Definition: options.h:43
char * help
Quickref for the current menu.
Definition: mutt_menu.h:85
int mutt_ev_message(struct Mailbox *m, struct EmailList *el, enum EvMessage action)
Edit or view a message.
Definition: editmsg.c:265
int mutt_system(const char *cmd)
Run an external command.
Definition: system.c:51
#define mutt_buffer_enter_fname(prompt, fname, mailbox)
Definition: curs_lib.h:87
#define mutt_uncollapse_thread(ctx, e)
Definition: mutt_thread.h:58
Log at debug level 3.
Definition: logging.h:58
struct Hash * id_hash
Hash table by msg id.
Definition: mailbox.h:138
bool message_is_tagged(struct Context *ctx, int index)
Is a message in the index tagged (and within limit)
Definition: context.c:348
#define REDRAW_CURRENT
Redraw the current line of the menu.
Definition: mutt_menu.h:45
#define SORT_MASK
Mask for the sort id.
Definition: sort2.h:85
struct Email * last_tag
Last tagged msg (used to link threads)
Definition: context.h:41
void mutt_draw_tree(struct Context *ctx)
Draw a tree of threaded emails.
Definition: mutt_thread.c:285
void nm_db_debug_check(struct Mailbox *m)
Check if the database is open.
Definition: nm_db.c:322
#define mutt_previous_subthread(e)
Definition: mutt_thread.h:68
struct NntpAccountData * CurrentNewsSrv
Current NNTP news server.
Definition: nntp.c:75
const char * mutt_make_version(void)
Generate the NeoMutt version string.
Definition: muttlib.c:1560
void mutt_buffer_alloc(struct Buffer *buf, size_t new_size)
Make sure a buffer can store at least new_size bytes.
Definition: buffer.c:265
WHERE bool C_ArrowCursor
Config: Use an arrow &#39;->&#39; instead of highlighting in the index.
Definition: globals.h:198
+ Here is the caller graph for this function:

◆ mutt_set_header_color()

void mutt_set_header_color ( struct Mailbox m,
struct Email e 
)

Select a colour for a message.

Parameters
mMailbox
eCurrent Email

Definition at line 3709 of file index.c.

3710 {
3711  if (!e)
3712  return;
3713 
3714  struct ColorLine *color = NULL;
3715  struct PatternCache cache = { 0 };
3716 
3717  STAILQ_FOREACH(color, &Colors->index_list, entries)
3718  {
3720  MUTT_MATCH_FULL_ADDRESS, m, e, &cache))
3721  {
3722  e->pair = color->pair;
3723  return;
3724  }
3725  }
3727 }
int * defs
Array of all fixed colours, see enum ColorId.
Definition: color.h:132
struct PatternList * color_pattern
Compiled pattern to speed up index color calculation.
Definition: color.h:41
int pair
Colour pair index.
Definition: color.h:44
Plain text.
Definition: color.h:78
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:2001
#define SLIST_FIRST(head)
Definition: queue.h:229
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:350
Definition: color.h:130
#define MUTT_MATCH_FULL_ADDRESS
Match the full address.
Definition: pattern.h:75
struct ColorLineList index_list
List of default colours applied to the index.
Definition: color.h:139
Cache commonly-used patterns.
Definition: pattern.h:85
int pair
Color-pair to use when displaying in the index.
Definition: email.h:79
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:

◆ mutt_reply_observer()

int mutt_reply_observer ( struct NotifyCallback nc)

Listen for config changes to "reply_regex" - Implements observer_t()

Definition at line 3732 of file index.c.

3733 {
3734  if (!nc)
3735  return -1;
3736 
3737  struct EventConfig *ec = (struct EventConfig *) nc->event;
3738 
3739  if (mutt_str_strcmp(ec->name, "reply_regex") != 0)
3740  return 0;
3741 
3742  if (!Context || !Context->mailbox)
3743  return 0;
3744 
3745  regmatch_t pmatch[1];
3746 
3747  for (int i = 0; i < Context->mailbox->msg_count; i++)
3748  {
3749  struct Envelope *e = Context->mailbox->emails[i]->env;
3750  if (!e || !e->subject)
3751  continue;
3752 
3753  if (mutt_regex_capture(C_ReplyRegex, e->subject, 1, pmatch))
3754  {
3755  e->real_subj = e->subject + pmatch[0].rm_eo;
3756  continue;
3757  }
3758 
3759  e->real_subj = e->subject;
3760  }
3761 
3762  OptResortInit = true; /* trigger a redraw of the index */
3763  return 0;
3764 }
struct Email ** emails
Array of Emails.
Definition: mailbox.h:110
The "current" mailbox.
Definition: context.h:36
int msg_count
Total number of messages.
Definition: mailbox.h:102
A config-change event.
Definition: set.h:199
char * real_subj
Offset of the real subject.
Definition: envelope.h:67
intptr_t event
Send: event data.
Definition: observer.h:46
struct Mailbox * mailbox
Definition: context.h:50
struct Envelope * env
Envelope information.
Definition: email.h:89
struct Regex * C_ReplyRegex
Config: Regex to match message reply subjects like "re: ".
Definition: email_globals.c:37
WHERE bool OptResortInit
(pseudo) used to force the next resort to be from scratch
Definition: options.h:49
bool mutt_regex_capture(const struct Regex *regex, const char *str, size_t nmatch, regmatch_t matches[])
match a regex against a string, with provided options
Definition: regex.c:594
char * subject
Email&#39;s subject.
Definition: envelope.h:66
const char * name
Name of config item that changed.
Definition: set.h:203
int mutt_str_strcmp(const char *a, const char *b)
Compare two strings, safely.
Definition: string.c:615
The header of an Email.
Definition: envelope.h:54
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

Variable Documentation

◆ C_ChangeFolderNext

bool C_ChangeFolderNext

Config: Suggest the next folder, rather than the first when using '<change-folder>'.

Definition at line 105 of file index.c.

◆ C_CollapseAll

bool C_CollapseAll

Config: Collapse all threads when entering a folder.

Definition at line 106 of file index.c.

◆ C_CollapseFlagged

bool C_CollapseFlagged

Config: Prevent the collapse of threads with flagged emails.

Definition at line 107 of file index.c.

◆ C_CollapseUnread

bool C_CollapseUnread

Config: Prevent the collapse of threads with unread emails.

Definition at line 108 of file