NeoMutt  2020-06-26-89-g172cd3
Teaching an old dog new tricks
DOXYGEN
index.c File Reference

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

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

Go to the source code of this file.

Data Structures

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

Macros

#define UNREAD(email)   mutt_thread_contains_unread(Context, email)
 
#define FLAGGED(email)   mutt_thread_contains_flagged(Context, email)
 
#define CAN_COLLAPSE(email)   ((C_CollapseUnread || !UNREAD(email)) && (C_CollapseFlagged || !FLAGGED(email)))
 
#define CHECK_NO_FLAGS   0
 No flags are set. More...
 
#define CHECK_IN_MAILBOX   (1 << 0)
 Is there a mailbox open? More...
 
#define CHECK_MSGCOUNT   (1 << 1)
 Are there any messages? More...
 
#define CHECK_VISIBLE   (1 << 2)
 Is the selected message visible in the index? More...
 
#define CHECK_READONLY   (1 << 3)
 Is the mailbox readonly? More...
 
#define CHECK_ATTACH   (1 << 4)
 Is the user in message-attach mode? More...
 

Typedefs

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

Functions

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

Variables

bool C_ChangeFolderNext
 Config: Suggest the next folder, rather than the first when using '<change-folder>'. More...
 
bool C_CollapseAll
 Config: Collapse all threads when entering a folder. More...
 
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_UncollapseJump
 Config: When opening a thread, jump to the next unread message. More...
 
bool C_UncollapseNew
 Config: Open collapsed threads when new mail arrives. More...
 
static const struct Mapping IndexHelp []
 
struct Mapping IndexNewsHelp []
 

Detailed Description

GUI manage the main index (list of emails)

Authors
  • Michael R. Elkins

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.

Definition in file index.c.

Macro Definition Documentation

◆ UNREAD

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

Definition at line 135 of file index.c.

◆ FLAGGED

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

Definition at line 136 of file index.c.

◆ CAN_COLLAPSE

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

Definition at line 138 of file index.c.

◆ CHECK_NO_FLAGS

#define CHECK_NO_FLAGS   0

No flags are set.

Definition at line 146 of file index.c.

◆ CHECK_IN_MAILBOX

#define CHECK_IN_MAILBOX   (1 << 0)

Is there a mailbox open?

Definition at line 147 of file index.c.

◆ CHECK_MSGCOUNT

#define CHECK_MSGCOUNT   (1 << 1)

Are there any messages?

Definition at line 148 of file index.c.

◆ CHECK_VISIBLE

#define CHECK_VISIBLE   (1 << 2)

Is the selected message visible in the index?

Definition at line 149 of file index.c.

◆ CHECK_READONLY

#define CHECK_READONLY   (1 << 3)

Is the mailbox readonly?

Definition at line 150 of file index.c.

◆ CHECK_ATTACH

#define CHECK_ATTACH   (1 << 4)

Is the user in message-attach mode?

Definition at line 151 of file index.c.

Typedef Documentation

◆ CheckFlags

typedef uint8_t CheckFlags

Checks to perform before running a function.

Flags, e.g. CHECK_IN_MAILBOX

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

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

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

◆ collapse_all()

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

Collapse/uncollapse all threads.

Parameters
ctxContext
menucurrent menu
toggletoggle collapsed state

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

Definition at line 238 of file index.c.

239 {
240  if (!ctx || !ctx->mailbox || (ctx->mailbox->msg_count == 0) || !menu)
241  return;
242 
243  struct Email *e_cur = mutt_get_virt_email(ctx->mailbox, menu->current);
244  if (!e_cur)
245  return;
246 
247  struct MuttThread *thread = NULL, *top = NULL;
248  int final;
249 
250  /* Figure out what the current message would be after folding / unfolding,
251  * so that we can restore the cursor in a sane way afterwards. */
252  if (e_cur->collapsed && toggle)
253  final = mutt_uncollapse_thread(ctx, e_cur);
254  else if (CAN_COLLAPSE(e_cur))
255  final = mutt_collapse_thread(ctx, e_cur);
256  else
257  final = e_cur->vnum;
258 
259  if (final == -1)
260  return;
261 
262  struct Email *base = mutt_get_virt_email(ctx->mailbox, final);
263  if (!base)
264  return;
265 
266  /* Iterate all threads, perform collapse/uncollapse as needed */
267  top = ctx->tree;
268  ctx->collapsed = toggle ? !ctx->collapsed : true;
269  struct Email *e = NULL;
270  while ((thread = top))
271  {
272  while (!thread->message)
273  thread = thread->child;
274  e = thread->message;
275 
276  if (e->collapsed != ctx->collapsed)
277  {
278  if (e->collapsed)
279  mutt_uncollapse_thread(ctx, e);
280  else if (CAN_COLLAPSE(e))
281  mutt_collapse_thread(ctx, e);
282  }
283  top = top->next;
284  }
285 
286  /* Restore the cursor */
287  mutt_set_vnum(ctx);
288  for (int i = 0; i < ctx->mailbox->vcount; i++)
289  {
290  e = mutt_get_virt_email(ctx->mailbox, i);
291  if (!e)
292  break;
293  if (e->index == base->index)
294  {
295  menu->current = i;
296  break;
297  }
298  }
299 
301 }
int msg_count
Total number of messages.
Definition: mailbox.h:91
The envelope/body of an email.
Definition: email.h:37
struct Email * mutt_get_virt_email(struct Mailbox *m, int vnum)
Get a virtual Email.
Definition: context.c:406
void mutt_set_vnum(struct Context *ctx)
Set the virtual index number of all the messages in a mailbox.
Definition: mutt_thread.c:1196
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:102
struct Mailbox * mailbox
Definition: context.h:50
struct MuttThread * child
Child of this Thread.
Definition: thread.h:46
#define CAN_COLLAPSE(email)
Definition: index.c:138
#define REDRAW_STATUS
Redraw the status bar.
Definition: mutt_menu.h:44
bool collapsed
Is this message part of a collapsed thread?
Definition: email.h:73
int vnum
Virtual message number.
Definition: email.h:87
struct Email * message
Email this Thread refers to.
Definition: thread.h:49
MuttRedrawFlags redraw
When to redraw the screen.
Definition: mutt_menu.h:87
An Email conversation.
Definition: thread.h:34
#define REDRAW_INDEX
Redraw the index.
Definition: mutt_menu.h:40
bool collapsed
Are all threads collapsed?
Definition: context.h:48
int index
The absolute (unsorted) message number.
Definition: email.h:85
int current
Current entry.
Definition: mutt_menu.h:85
#define mutt_uncollapse_thread(ctx, e)
Definition: mutt_thread.h:58
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ ci_next_undeleted()

static int ci_next_undeleted ( struct Context ctx,
int  msgno 
)
static

Find the next undeleted email.

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

Definition at line 310 of file index.c.

311 {
312  if (!ctx || !ctx->mailbox)
313  return -1;
314 
315  for (int i = msgno + 1; i < ctx->mailbox->vcount; i++)
316  {
317  struct Email *e = mutt_get_virt_email(ctx->mailbox, i);
318  if (!e)
319  continue;
320  if (!e->deleted)
321  return i;
322  }
323  return -1;
324 }
The envelope/body of an email.
Definition: email.h:37
struct Email * mutt_get_virt_email(struct Mailbox *m, int vnum)
Get a virtual Email.
Definition: context.c:406
int vcount
The number of virtual messages.
Definition: mailbox.h:102
struct Mailbox * mailbox
Definition: context.h:50
bool deleted
Email is deleted.
Definition: email.h:45
int msgno
Number displayed to the user.
Definition: email.h:86
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ ci_previous_undeleted()

static int ci_previous_undeleted ( struct Context ctx,
int  msgno 
)
static

Find the previous undeleted email.

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

Definition at line 333 of file index.c.

334 {
335  if (!ctx || !ctx->mailbox)
336  return -1;
337 
338  for (int i = msgno - 1; i >= 0; i--)
339  {
340  struct Email *e = mutt_get_virt_email(ctx->mailbox, i);
341  if (!e)
342  continue;
343  if (!e->deleted)
344  return i;
345  }
346  return -1;
347 }
The envelope/body of an email.
Definition: email.h:37
struct Email * mutt_get_virt_email(struct Mailbox *m, int vnum)
Get a virtual Email.
Definition: context.c:406
struct Mailbox * mailbox
Definition: context.h:50
bool deleted
Email is deleted.
Definition: email.h:45
int msgno
Number displayed to the user.
Definition: email.h:86
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ ci_first_message()

static int ci_first_message ( struct Context ctx)
static

Get index of first new message.

Parameters
ctxContext
Return values
numIndex of first new message

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

Definition at line 357 of file index.c.

358 {
359  if (!ctx || !ctx->mailbox || (ctx->mailbox->msg_count == 0))
360  return 0;
361 
362  int old = -1;
363  for (int i = 0; i < ctx->mailbox->vcount; i++)
364  {
365  struct Email *e = mutt_get_virt_email(ctx->mailbox, i);
366  if (!e)
367  continue;
368  if (!e->read && !e->deleted)
369  {
370  if (!e->old)
371  return i;
372  if (old == -1)
373  old = i;
374  }
375  }
376  if (old != -1)
377  return old;
378 
379  /* If C_Sort is reverse and not threaded, the latest message is first.
380  * If C_Sort is threaded, the latest message is first if exactly one
381  * of C_Sort and C_SortAux are reverse. */
382  if (((C_Sort & SORT_REVERSE) && ((C_Sort & SORT_MASK) != SORT_THREADS)) ||
383  (((C_Sort & SORT_MASK) == SORT_THREADS) && ((C_Sort ^ C_SortAux) & SORT_REVERSE)))
384  {
385  return 0;
386  }
387  else
388  {
389  return ctx->mailbox->vcount ? ctx->mailbox->vcount - 1 : 0;
390  }
391 
392  return 0;
393 }
int msg_count
Total number of messages.
Definition: mailbox.h:91
The envelope/body of an email.
Definition: email.h:37
struct Email * mutt_get_virt_email(struct Mailbox *m, int vnum)
Get a virtual Email.
Definition: context.c:406
int vcount
The number of virtual messages.
Definition: mailbox.h:102
bool read
Email is read.
Definition: email.h:51
struct Mailbox * mailbox
Definition: context.h: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
bool deleted
Email is deleted.
Definition: email.h:45
#define SORT_REVERSE
Reverse the order of the sort.
Definition: sort2.h:86
#define SORT_MASK
Mask for the sort id.
Definition: sort2.h:85
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mx_toggle_write()

static int mx_toggle_write ( struct Mailbox m)
static

Toggle the mailbox's readonly flag.

Parameters
mMailbox
Return values
0Success
-1Error

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

Definition at line 403 of file index.c.

404 {
405  if (!m)
406  return -1;
407 
408  if (m->readonly)
409  {
410  mutt_error(_("Can't toggle write on a readonly mailbox"));
411  return -1;
412  }
413 
414  if (m->dontwrite)
415  {
416  m->dontwrite = false;
417  mutt_message(_("Changes to folder will be written on folder exit"));
418  }
419  else
420  {
421  m->dontwrite = true;
422  mutt_message(_("Changes to folder will not be written"));
423  }
424 
425  return 0;
426 }
#define mutt_message(...)
Definition: logging.h:83
#define _(a)
Definition: message.h:28
bool readonly
Don&#39;t allow changes to the mailbox.
Definition: mailbox.h:119
bool dontwrite
Don&#39;t write the mailbox on close.
Definition: mailbox.h:115
#define mutt_error(...)
Definition: logging.h:84
+ Here is the caller graph for this function:

◆ resort_index()

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

Resort the index.

Parameters
ctxContext
menuCurrent Menu

Definition at line 433 of file index.c.

434 {
435  if (!ctx || !ctx->mailbox || !menu)
436  return;
437 
438  struct Email *e_cur = mutt_get_virt_email(ctx->mailbox, menu->current);
439 
440  menu->current = -1;
441  mutt_sort_headers(ctx, false);
442  /* Restore the current message */
443 
444  for (int i = 0; i < ctx->mailbox->vcount; i++)
445  {
446  struct Email *e = mutt_get_virt_email(ctx->mailbox, i);
447  if (!e)
448  continue;
449  if (e == e_cur)
450  {
451  menu->current = i;
452  break;
453  }
454  }
455 
456  if (((C_Sort & SORT_MASK) == SORT_THREADS) && (menu->current < 0))
457  menu->current = mutt_parent_message(ctx, e_cur, false);
458 
459  if (menu->current < 0)
460  menu->current = ci_first_message(ctx);
461 
462  menu->redraw |= REDRAW_INDEX | REDRAW_STATUS;
463 }
The envelope/body of an email.
Definition: email.h:37
struct Email * mutt_get_virt_email(struct Mailbox *m, int vnum)
Get a virtual Email.
Definition: context.c:406
int vcount
The number of virtual messages.
Definition: mailbox.h:102
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:1147
WHERE short C_Sort
Config: Sort method for the index.
Definition: sort.h:58
void mutt_sort_headers(struct Context *ctx, bool init)
Sort emails by their headers.
Definition: sort.c:364
Sort by email threads.
Definition: sort2.h:56
#define REDRAW_STATUS
Redraw the status bar.
Definition: mutt_menu.h:44
MuttRedrawFlags redraw
When to redraw the screen.
Definition: mutt_menu.h:87
#define REDRAW_INDEX
Redraw the index.
Definition: mutt_menu.h:40
int current
Current entry.
Definition: mutt_menu.h:85
static int ci_first_message(struct Context *ctx)
Get index of first new message.
Definition: index.c:357
#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 471 of file index.c.

472 {
473  struct Email **save_new = NULL;
474 
475  /* save the list of new messages */
476  if ((check != MUTT_REOPENED) && oldcount && (ctx->pattern || C_UncollapseNew))
477  {
478  save_new = mutt_mem_malloc(sizeof(struct Email *) * (ctx->mailbox->msg_count - oldcount));
479  for (int i = oldcount; i < ctx->mailbox->msg_count; i++)
480  save_new[i - oldcount] = ctx->mailbox->emails[i];
481  }
482 
483  /* Sort first to thread the new messages, because some patterns
484  * require the threading information.
485  *
486  * If the mailbox was reopened, need to rethread from scratch. */
487  mutt_sort_headers(ctx, (check == MUTT_REOPENED));
488 
489  if (ctx->pattern)
490  {
491  for (int i = (check == MUTT_REOPENED) ? 0 : oldcount; i < ctx->mailbox->msg_count; i++)
492  {
493  struct Email *e = NULL;
494 
495  if ((check != MUTT_REOPENED) && oldcount)
496  e = save_new[i - oldcount];
497  else
498  e = ctx->mailbox->emails[i];
499 
501  MUTT_MATCH_FULL_ADDRESS, ctx->mailbox, e, NULL))
502  {
503  /* vnum will get properly set by mutt_set_vnum(), which
504  * is called by mutt_sort_headers() just below. */
505  e->vnum = 1;
506  e->limited = true;
507  }
508  }
509  /* Need a second sort to set virtual numbers and redraw the tree */
510  mutt_sort_headers(ctx, false);
511  }
512 
513  /* uncollapse threads with new mail */
514  if (C_UncollapseNew)
515  {
516  if (check == MUTT_REOPENED)
517  {
518  ctx->collapsed = false;
519 
520  for (struct MuttThread *h = ctx->tree; h; h = h->next)
521  {
522  struct MuttThread *j = h;
523  for (; !j->message; j = j->child)
524  ; // do nothing
525 
527  }
528  mutt_set_vnum(ctx);
529  }
530  else if (oldcount)
531  {
532  for (int j = 0; j < (ctx->mailbox->msg_count - oldcount); j++)
533  {
534  if (!ctx->pattern || save_new[j]->limited)
535  {
536  mutt_uncollapse_thread(ctx, save_new[j]);
537  }
538  }
539  mutt_set_vnum(ctx);
540  }
541  }
542 
543  FREE(&save_new);
544 }
struct Email ** emails
Array of Emails.
Definition: mailbox.h:99
struct MuttThread * next
Next sibling Thread.
Definition: thread.h:47
int msg_count
Total number of messages.
Definition: mailbox.h:91
The envelope/body of an email.
Definition: email.h:37
void mutt_set_vnum(struct Context *ctx)
Set the virtual index number of all the messages in a mailbox.
Definition: mutt_thread.c:1196
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:2129
struct MuttThread * child
Child of this Thread.
Definition: thread.h:46
void mutt_sort_headers(struct Context *ctx, bool init)
Sort emails by their headers.
Definition: sort.c:364
#define SLIST_FIRST(head)
Definition: queue.h:228
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:90
struct PatternList * limit_pattern
Compiled limit pattern.
Definition: context.h:41
int vnum
Virtual message number.
Definition: email.h:87
struct Email * message
Email this Thread refers to.
Definition: thread.h:49
#define MUTT_MATCH_FULL_ADDRESS
Match the full address.
Definition: pattern.h:76
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:76
char * pattern
Limit pattern string.
Definition: context.h:40
bool C_UncollapseNew
Config: Open collapsed threads when new mail arrives.
Definition: index.c:107
#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 552 of file index.c.

553 {
554  /* We are in a limited view. Check if the new message(s) satisfy
555  * the limit criteria. If they do, set their virtual msgno so that
556  * they will be visible in the limited view */
557  if (ctx->pattern)
558  {
559  int padding = mx_msg_padding_size(ctx->mailbox);
560  for (int i = (check == MUTT_REOPENED) ? 0 : oldcount; i < ctx->mailbox->msg_count; i++)
561  {
562  if (i == 0)
563  {
564  ctx->mailbox->vcount = 0;
565  ctx->vsize = 0;
566  }
567 
568  struct Email *e = ctx->mailbox->emails[i];
569  if (!e)
570  break;
572  MUTT_MATCH_FULL_ADDRESS, ctx->mailbox, e, NULL))
573  {
574  assert(ctx->mailbox->vcount < ctx->mailbox->msg_count);
575  e->vnum = ctx->mailbox->vcount;
576  ctx->mailbox->v2r[ctx->mailbox->vcount] = i;
577  e->limited = true;
578  ctx->mailbox->vcount++;
579  struct Body *b = e->content;
580  ctx->vsize += b->length + b->offset - b->hdr_offset + padding;
581  }
582  }
583  }
584 
585  /* if the mailbox was reopened, need to rethread from scratch */
586  mutt_sort_headers(ctx, (check == MUTT_REOPENED));
587 }
struct Email ** emails
Array of Emails.
Definition: mailbox.h:99
int msg_count
Total number of messages.
Definition: mailbox.h:91
The envelope/body of an email.
Definition: email.h:37
struct Body * content
List of MIME parts.
Definition: email.h:90
LOFF_T offset
offset where the actual data begins
Definition: body.h:44
int vcount
The number of virtual messages.
Definition: mailbox.h:102
The body of an email.
Definition: body.h:34
struct Mailbox * mailbox
Definition: context.h:50
bool limited
Is this message in a limited view?
Definition: email.h:74
off_t vsize
Definition: context.h:39
int mutt_pattern_exec(struct Pattern *pat, PatternExecFlags flags, struct Mailbox *m, struct Email *e, struct PatternCache *cache)
Match a pattern against an email header.
Definition: pattern.c:2129
void mutt_sort_headers(struct Context *ctx, bool init)
Sort emails by their headers.
Definition: sort.c:364
#define SLIST_FIRST(head)
Definition: queue.h:228
LOFF_T length
length (in bytes) of attachment
Definition: body.h:45
struct PatternList * limit_pattern
Compiled limit pattern.
Definition: context.h:41
int vnum
Virtual message number.
Definition: email.h:87
#define MUTT_MATCH_FULL_ADDRESS
Match the full address.
Definition: pattern.h:76
int * v2r
Mapping from virtual to real msgno.
Definition: mailbox.h:101
int mx_msg_padding_size(struct Mailbox *m)
Bytes of padding between messages - Wrapper for MxOps::msg_padding_size()
Definition: mx.c:1543
long hdr_offset
Offset in stream where the headers begin.
Definition: body.h:42
Mailbox was reopened.
Definition: mx.h:76
char * pattern
Limit pattern string.
Definition: context.h:40
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ is_current_email()

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

Check whether an email is the currently selected Email.

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

Definition at line 606 of file index.c.

607 {
608  return (e->received == cur->received) &&
610 }
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:876
time_t received
From Email.received.
Definition: index.c:595
char * message_id
Message ID.
Definition: envelope.h:69
struct Envelope * env
Envelope information.
Definition: email.h:89
char * message_id
From Email.Envelope.message_id.
Definition: index.c:596
time_t received
Time when the message was placed in the mailbox.
Definition: email.h:82
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ set_current_email()

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

Keep track of the currently selected Email.

Parameters
curCurrently selected Email
eEmail to set as current

Definition at line 617 of file index.c.

618 {
619  *cur = (struct CurrentEmail){
620  .e = e,
621  .received = e ? e->received : 0,
622  .message_id = mutt_str_replace(&cur->message_id, e ? e->env->message_id : NULL),
623  };
624 }
struct Email * e
The current Email.
Definition: index.c:594
Keep track of the currently selected Email.
Definition: index.c:592
char * message_id
Message ID.
Definition: envelope.h:69
struct Envelope * env
Envelope information.
Definition: email.h:89
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:451
char * message_id
From Email.Envelope.message_id.
Definition: index.c:596
time_t received
Time when the message was placed in the mailbox.
Definition: email.h:82
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ update_index()

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

Update the index.

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

Definition at line 634 of file index.c.

636 {
637  if (!menu || !ctx)
638  return;
639 
640  if ((C_Sort & SORT_MASK) == SORT_THREADS)
641  update_index_threaded(ctx, check, oldcount);
642  else
643  update_index_unthreaded(ctx, check, oldcount);
644 
645  menu->current = -1;
646  if (oldcount)
647  {
648  /* restore the current message to the message it was pointing to */
649  for (int i = 0; i < ctx->mailbox->vcount; i++)
650  {
651  struct Email *e = mutt_get_virt_email(ctx->mailbox, i);
652  if (!e)
653  continue;
654  if (is_current_email(cur, e))
655  {
656  menu->current = i;
657  break;
658  }
659  }
660  }
661 
662  if (menu->current < 0)
664 }
The "current" mailbox.
Definition: context.h:37
The envelope/body of an email.
Definition: email.h:37
struct Email * mutt_get_virt_email(struct Mailbox *m, int vnum)
Get a virtual Email.
Definition: context.c:406
static void update_index_unthreaded(struct Context *ctx, int check, int oldcount)
Update the index (if unthreaded)
Definition: index.c:552
int vcount
The number of virtual messages.
Definition: mailbox.h:102
struct Mailbox * mailbox
Definition: context.h:50
WHERE short C_Sort
Config: Sort method for the index.
Definition: sort.h:58
Sort by email threads.
Definition: sort2.h:56
static bool is_current_email(const struct CurrentEmail *cur, const struct Email *e)
Check whether an email is the currently selected Email.
Definition: index.c:606
static void update_index_threaded(struct Context *ctx, int check, int oldcount)
Update the index (if threaded)
Definition: index.c:471
int current
Current entry.
Definition: mutt_menu.h:85
static int ci_first_message(struct Context *ctx)
Get index of first new message.
Definition: index.c:357
#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:

◆ mutt_update_index()

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

Update the index.

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

Definition at line 676 of file index.c.

678 {
679  struct CurrentEmail se = { .received = cur_email->received,
680  .message_id = cur_email->env->message_id };
681  update_index(menu, ctx, check, oldcount, &se);
682 }
time_t received
From Email.received.
Definition: index.c:595
Keep track of the currently selected Email.
Definition: index.c:592
char * message_id
Message ID.
Definition: envelope.h:69
struct Envelope * env
Envelope information.
Definition: email.h:89
static void update_index(struct Menu *menu, struct Context *ctx, int check, int oldcount, const struct CurrentEmail *cur)
Update the index.
Definition: index.c:634
time_t received
Time when the message was placed in the mailbox.
Definition: email.h:82
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mailbox_index_observer()

static int mailbox_index_observer ( struct NotifyCallback nc)
static

Listen for Mailbox changes - Implements observer_t.

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

Definition at line 689 of file index.c.

690 {
691  if (!nc->global_data)
692  return -1;
693  if ((nc->event_type != NT_MAILBOX) || (nc->event_subtype != NT_MAILBOX_CLOSED))
694  return 0;
695 
696  struct Mailbox **ptr = nc->global_data;
697  if (!ptr || !*ptr)
698  return 0;
699 
700  *ptr = NULL;
701  return 0;
702 }
Mailbox was closed.
Definition: mailbox.h:165
int event_subtype
Send: Event subtype, e.g. NT_ACCOUNT_ADD.
Definition: observer.h:42
enum NotifyType event_type
Send: Event type, e.g. NT_ACCOUNT.
Definition: observer.h:41
void * global_data
Data from notify_observer_add()
Definition: observer.h:44
A mailbox.
Definition: mailbox.h:81
Mailbox has changed, NotifyMailbox, EventMailbox.
Definition: notify_type.h:40
+ Here is the caller graph for this function:

◆ change_folder_mailbox()

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

Change to a different Mailbox by pointer.

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

Definition at line 712 of file index.c.

714 {
715  if (!m)
716  return;
717 
718  /* keepalive failure in mutt_enter_fname may kill connection. */
720  ctx_free(&Context);
721 
722  if (Context && Context->mailbox)
723  {
724  char *new_last_folder = NULL;
725 #ifdef USE_INOTIFY
726  int monitor_remove_rc = mutt_monitor_remove(NULL);
727 #endif
728 #ifdef USE_COMP_MBOX
729  if (Context->mailbox->compress_info && (Context->mailbox->realpath[0] != '\0'))
730  new_last_folder = mutt_str_dup(Context->mailbox->realpath);
731  else
732 #endif
733  new_last_folder = mutt_str_dup(mailbox_path(Context->mailbox));
734  *oldcount = Context->mailbox->msg_count;
735 
736  int check = mx_mbox_close(&Context);
737  if (check != 0)
738  {
739 #ifdef USE_INOTIFY
740  if (monitor_remove_rc == 0)
741  mutt_monitor_add(NULL);
742 #endif
743  if ((check == MUTT_NEW_MAIL) || (check == MUTT_REOPENED))
744  update_index(menu, Context, check, *oldcount, cur);
745 
746  FREE(&new_last_folder);
747  OptSearchInvalid = true;
748  menu->redraw |= REDRAW_INDEX | REDRAW_STATUS;
749  return;
750  }
751  FREE(&LastFolder);
752  LastFolder = new_last_folder;
753  }
755 
756  /* If the `folder-hook` were to call `unmailboxes`, then the Mailbox (`m`)
757  * could be deleted, leaving `m` dangling. */
758  // TODO: Refactor this function to avoid the need for an observer
760  char *dup_path = mutt_str_dup(mailbox_path(m));
761 
762  mutt_folder_hook(mailbox_path(m), m ? m->name : NULL);
763  if (m)
764  {
765  /* `m` is still valid, but we won't need the observer again before the end
766  * of the function. */
768  }
769  else
770  {
771  // Recreate the Mailbox (probably because a hook has done `unmailboxes *`)
772  m = mx_path_resolve(dup_path);
773  }
774  FREE(&dup_path);
775 
776  if (!m)
777  return;
778 
779  const int flags = read_only ? MUTT_READONLY : MUTT_OPEN_NO_FLAGS;
780  Context = mx_mbox_open(m, flags);
781  if (Context)
782  {
784 #ifdef USE_INOTIFY
785  mutt_monitor_add(NULL);
786 #endif
787  }
788  else
789  {
790  menu->current = 0;
791  }
792 
793  if (((C_Sort & SORT_MASK) == SORT_THREADS) && C_CollapseAll)
794  collapse_all(Context, menu, 0);
795 
796 #ifdef USE_SIDEBAR
797  struct MuttWindow *dlg = mutt_window_dialog(menu->win_index);
798  struct MuttWindow *win_sidebar = mutt_window_find(dlg, WT_SIDEBAR);
799  sb_set_open_mailbox(win_sidebar, Context ? Context->mailbox : NULL);
800 #endif
801 
803  mutt_mailbox_check(Context ? Context->mailbox : NULL, MUTT_MAILBOX_CHECK_FORCE); /* force the mailbox check after we have changed the folder */
804  menu->redraw = REDRAW_FULL;
805  OptSearchInvalid = true;
806 }
#define MUTT_OPEN_NO_FLAGS
No flags are set.
Definition: mx.h:52
The "current" mailbox.
Definition: context.h:37
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox&#39;s path string.
Definition: mailbox.h:196
#define REDRAW_FULL
Redraw everything.
Definition: mutt_menu.h:45
int msg_count
Total number of messages.
Definition: mailbox.h:91
int mx_mbox_close(struct Context **ptr)
Save changes and close mailbox.
Definition: mx.c:604
int mutt_monitor_remove(struct Mailbox *m)
Remove a watch for a mailbox.
Definition: monitor.c:524
struct MuttWindow * mutt_window_find(struct MuttWindow *root, enum WindowType type)
Find a Window of a given type.
Definition: mutt_window.c:692
char * realpath
Used for duplicate detection, context comparison, and the sidebar.
Definition: mailbox.h:84
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:375
struct Context * mx_mbox_open(struct Mailbox *m, OpenMailboxFlags flags)
Open a mailbox and parse it.
Definition: mx.c:267
A division of the screen.
Definition: mutt_window.h:114
bool C_CollapseAll
Config: Collapse all threads when entering a folder.
Definition: index.c:102
#define MUTT_READONLY
Open in read-only mode.
Definition: mx.h:55
int mutt_monitor_add(struct Mailbox *m)
Add a watch for a mailbox.
Definition: monitor.c:479
void mutt_folder_hook(const char *path, const char *desc)
Perform a folder hook.
Definition: hook.c:504
char * name
A short name for the Mailbox.
Definition: mailbox.h:85
struct Mailbox * mailbox
Definition: context.h:50
WHERE short C_Sort
Config: Sort method for the index.
Definition: sort.h:58
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:113
int flags
e.g. MB_NORMAL
Definition: mailbox.h:134
static int mailbox_index_observer(struct NotifyCallback *nc)
Listen for Mailbox changes - Implements observer_t.
Definition: index.c:689
Side panel containing Accounts or groups of data.
Definition: mutt_window.h:98
Sort by email threads.
Definition: sort2.h:56
#define REDRAW_STATUS
Redraw the status bar.
Definition: mutt_menu.h:44
int mutt_mailbox_check(struct Mailbox *m_cur, int force)
Check all all Mailboxes for new mail.
Definition: mutt_mailbox.c:153
static void update_index(struct Menu *menu, struct Context *ctx, int check, int oldcount, const struct CurrentEmail *cur)
Update the index.
Definition: index.c:634
WHERE bool OptSearchInvalid
(pseudo) used to invalidate the search pattern
Definition: options.h:52
bool notify_observer_add(struct Notify *notify, observer_t callback, void *global_data)
Add an observer to an object.
Definition: notify.c:153
WHERE char * LastFolder
Previously selected mailbox.
Definition: mutt_globals.h:56
#define MUTT_MAILBOX_CHECK_FORCE
Definition: mutt_mailbox.h:16
struct MuttWindow * mutt_window_dialog(struct MuttWindow *win)
Find the parent Dialog of a Window.
Definition: mutt_window.c:674
MuttRedrawFlags redraw
When to redraw the screen.
Definition: mutt_menu.h:87
#define REDRAW_INDEX
Redraw the index.
Definition: mutt_menu.h:40
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:451
void * compress_info
Compressed mbox module private data.
Definition: mailbox.h:124
WHERE char * CurrentFolder
Currently selected mailbox.
Definition: mutt_globals.h:55
static void collapse_all(struct Context *ctx, struct Menu *menu, int toggle)
Collapse/uncollapse all threads.
Definition: index.c:238
#define FREE(x)
Definition: memory.h:40
struct Mailbox * mx_path_resolve(const char *path)
Get a Mailbox for a path.
Definition: mx.c:1670
bool notify_observer_remove(struct Notify *notify, observer_t callback, void *global_data)
Remove an observer from an object.
Definition: notify.c:185
void ctx_free(struct Context **ptr)
Free a Context.
Definition: context.c:49
New mail received in Mailbox.
Definition: mx.h:74
struct Notify * notify
Notifications handler.
Definition: mailbox.h:139
int current
Current entry.
Definition: mutt_menu.h:85
struct Buffer pathbuf
Definition: mailbox.h:83
struct MuttWindow * win_index
Definition: mutt_menu.h:92
bool mutt_buffer_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:252
Mailbox was reopened.
Definition: mx.h:76
static int ci_first_message(struct Context *ctx)
Get index of first new message.
Definition: index.c:357
#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:

◆ change_folder_notmuch()

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

Change to a different Notmuch Mailbox by string.

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

Definition at line 818 of file index.c.

821 {
822  if (!nm_url_from_query(NULL, buf, buflen))
823  {
824  mutt_message(_("Failed to create query, aborting"));
825  return NULL;
826  }
827 
828  struct Mailbox *m_query = mx_path_resolve(buf);
829  change_folder_mailbox(menu, m_query, oldcount, cur, read_only);
830  return m_query;
831 }
#define mutt_message(...)
Definition: logging.h:83
#define _(a)
Definition: message.h:28
A mailbox.
Definition: mailbox.h:81
struct Mailbox * mx_path_resolve(const char *path)
Get a Mailbox for a path.
Definition: mx.c:1670
static void change_folder_mailbox(struct Menu *menu, struct Mailbox *m, int *oldcount, const struct CurrentEmail *cur, bool read_only)
Change to a different Mailbox by pointer.
Definition: index.c:712
char * nm_url_from_query(struct Mailbox *m, char *buf, size_t buflen)
Turn a query into a URL.
Definition: notmuch.c:1732
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ change_folder_string()

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

Change to a different Mailbox by string.

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

Definition at line 844 of file index.c.

847 {
848 #ifdef USE_NNTP
849  if (OptNews)
850  {
851  OptNews = false;
852  nntp_expand_path(buf, buflen, &CurrentNewsSrv->conn->account);
853  }
854  else
855 #endif
856  {
857  mx_path_canon(buf, buflen, C_Folder, NULL);
858  }
859 
860  enum MailboxType type = mx_path_probe(buf);
861  if ((type == MUTT_MAILBOX_ERROR) || (type == MUTT_UNKNOWN))
862  {
863  // Look for a Mailbox by its description, before failing
864  struct Mailbox *m = mailbox_find_name(buf);
865  if (m)
866  {
867  change_folder_mailbox(menu, m, oldcount, cur, read_only);
868  *pager_return = false;
869  }
870  else
871  mutt_error(_("%s is not a mailbox"), buf);
872  return;
873  }
874 
875  /* past this point, we don't return to the pager on error */
876  *pager_return = false;
877 
878  struct Mailbox *m = mx_path_resolve(buf);
879  change_folder_mailbox(menu, m, oldcount, cur, read_only);
880 }
enum MailboxType type
Mailbox type.
Definition: mailbox.h:105
struct ConnAccount account
Account details: username, password, etc.
Definition: connection.h:36
#define _(a)
Definition: message.h:28
Mailbox wasn&#39;t recognised.
Definition: mailbox.h:47
Error occurred examining Mailbox.
Definition: mailbox.h:46
struct Mailbox * mailbox_find_name(const char *name)
Find the mailbox with a given name.
Definition: mailbox.c:128
A mailbox.
Definition: mailbox.h:81
WHERE char * C_Folder
Config: Base folder for a set of mailboxes.
Definition: mutt_globals.h:99
struct Connection * conn
Definition: lib.h:102
enum MailboxType mx_path_probe(const char *path)
Find a mailbox that understands a path.
Definition: mx.c:1327
MailboxType
Supported mailbox formats.
Definition: mailbox.h:43
#define mutt_error(...)
Definition: logging.h:84
struct Mailbox * mx_path_resolve(const char *path)
Get a Mailbox for a path.
Definition: mx.c:1670
struct NntpAccountData * CurrentNewsSrv
Current NNTP news server.
Definition: nntp.c:76
static void change_folder_mailbox(struct Menu *menu, struct Mailbox *m, int *oldcount, const struct CurrentEmail *cur, bool read_only)
Change to a different Mailbox by pointer.
Definition: index.c:712
void nntp_expand_path(char *buf, size_t buflen, struct ConnAccount *acct)
Make fully qualified url from newsgroup name.
Definition: newsrc.c:557
int mx_path_canon(char *buf, size_t buflen, const char *folder, enum MailboxType *type)
Canonicalise a mailbox path - Wrapper for MxOps::path_canon()
Definition: mx.c:1373
WHERE bool OptNews
(pseudo) used to change reader mode
Definition: options.h:45
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ index_make_entry()

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

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

Definition at line 885 of file index.c.

886 {
887  buf[0] = '\0';
888 
889  if (!Context || !Context->mailbox || !menu || (line < 0) ||
890  (line >= Context->mailbox->email_max))
891  return;
892 
894  if (!e)
895  return;
896 
898  struct MuttThread *tmp = NULL;
899 
900  if (((C_Sort & SORT_MASK) == SORT_THREADS) && e->tree)
901  {
902  flags |= MUTT_FORMAT_TREE; /* display the thread tree */
903  if (e->display_subject)
904  flags |= MUTT_FORMAT_FORCESUBJ;
905  else
906  {
907  const int reverse = C_Sort & SORT_REVERSE;
908  int edgemsgno;
909  if (reverse)
910  {
911  if (menu->top + menu->pagelen > menu->max)
912  edgemsgno = Context->mailbox->v2r[menu->max - 1];
913  else
914  edgemsgno = Context->mailbox->v2r[menu->top + menu->pagelen - 1];
915  }
916  else
917  edgemsgno = Context->mailbox->v2r[menu->top];
918 
919  for (tmp = e->thread->parent; tmp; tmp = tmp->parent)
920  {
921  if (!tmp->message)
922  continue;
923 
924  /* if no ancestor is visible on current screen, provisionally force
925  * subject... */
926  if (reverse ? (tmp->message->msgno > edgemsgno) : (tmp->message->msgno < edgemsgno))
927  {
928  flags |= MUTT_FORMAT_FORCESUBJ;
929  break;
930  }
931  else if (tmp->message->vnum >= 0)
932  break;
933  }
934  if (flags & MUTT_FORMAT_FORCESUBJ)
935  {
936  for (tmp = e->thread->prev; tmp; tmp = tmp->prev)
937  {
938  if (!tmp->message)
939  continue;
940 
941  /* ...but if a previous sibling is available, don't force it */
942  if (reverse ? (tmp->message->msgno > edgemsgno) : (tmp->message->msgno < edgemsgno))
943  break;
944  else if (tmp->message->vnum >= 0)
945  {
946  flags &= ~MUTT_FORMAT_FORCESUBJ;
947  break;
948  }
949  }
950  }
951  }
952  }
953 
954  mutt_make_string_flags(buf, buflen, menu->win_index->state.cols,
955  NONULL(C_IndexFormat), Context, Context->mailbox, e, flags);
956 }
The "current" mailbox.
Definition: context.h:37
uint8_t MuttFormatFlags
Flags for mutt_expando_format(), e.g. MUTT_FORMAT_FORCESUBJ.
Definition: format_flags.h:29
#define NONULL(x)
Definition: string2.h:37
The envelope/body of an email.
Definition: email.h:37
struct Email * mutt_get_virt_email(struct Mailbox *m, int vnum)
Get a virtual Email.
Definition: context.c:406
#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
WHERE char * C_IndexFormat
Config: printf-like format string for the index menu (emails)
Definition: mutt_globals.h:95
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:1407
WHERE short C_Sort
Config: Sort method for the index.
Definition: sort.h:58
short cols
Number of columns, can be MUTT_WIN_SIZE_UNLIMITED.
Definition: mutt_window.h:57
Sort by email threads.
Definition: sort2.h:56
struct WindowState state
Current state of the Window.
Definition: mutt_window.h:119
int email_max
Number of pointers in emails.
Definition: mailbox.h:100
int top
Entry that is the top of the current page.
Definition: mutt_menu.h:105
int vnum
Virtual message number.
Definition: email.h:87
int pagelen
Number of entries per screen.
Definition: mutt_menu.h:89
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:86
An Email conversation.
Definition: thread.h:34
int * v2r
Mapping from virtual to real msgno.
Definition: mailbox.h:101
#define MUTT_FORMAT_INDEX
This is a main index entry.
Definition: format_flags.h:36
int const char int line
Definition: acutest.h:617
struct MuttWindow * win_index
Definition: mutt_menu.h:92
#define SORT_REVERSE
Reverse the order of the sort.
Definition: sort2.h:86
#define SORT_MASK
Mask for the sort id.
Definition: sort2.h:85
int msgno
Number displayed to the user.
Definition: email.h:86
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ index_color()

int index_color ( int  line)

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

Definition at line 961 of file index.c.

962 {
963  if (!Context || !Context->mailbox || (line < 0))
964  return 0;
965 
967  if (!e)
968  return 0;
969 
970  if (e->pair)
971  return e->pair;
972 
974  return e->pair;
975 }
The "current" mailbox.
Definition: context.h:37
The envelope/body of an email.
Definition: email.h:37
struct Email * mutt_get_virt_email(struct Mailbox *m, int vnum)
Get a virtual Email.
Definition: context.c:406
struct Mailbox * mailbox
Definition: context.h:50
void mutt_set_header_color(struct Mailbox *m, struct Email *e)
Select a colour for a message.
Definition: index.c:3983
int const char int line
Definition: acutest.h:617
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 989 of file index.c.

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

◆ index_custom_redraw()

static void index_custom_redraw ( struct Menu menu)
static

Redraw the index - Implements Menu::custom_redraw()

Definition at line 1115 of file index.c.

1116 {
1117  if (menu->redraw & REDRAW_FULL)
1118  {
1119  menu_redraw_full(menu);
1120  mutt_show_error();
1121  }
1122 
1123 #ifdef USE_SIDEBAR
1124  if (menu->redraw & REDRAW_SIDEBAR)
1125  menu_redraw_sidebar(menu);
1126 #endif
1127 
1128  if (Context && Context->mailbox && Context->mailbox->emails &&
1129  !(menu->current >= Context->mailbox->vcount))
1130  {
1131  menu_check_recenter(menu);
1132 
1133  if (menu->redraw & REDRAW_INDEX)
1134  {
1135  menu_redraw_index(menu);
1136  menu->redraw |= REDRAW_STATUS;
1137  }
1138  else if (menu->redraw & (REDRAW_MOTION_RESYNC | REDRAW_MOTION))
1139  menu_redraw_motion(menu);
1140  else if (menu->redraw & REDRAW_CURRENT)
1141  menu_redraw_current(menu);
1142  }
1143 
1144  if (menu->redraw & REDRAW_STATUS)
1145  {
1146  char buf[1024];
1147  menu_status_line(buf, sizeof(buf), menu, NONULL(C_StatusFormat));
1148  mutt_window_move(menu->win_ibar, 0, 0);
1150  mutt_draw_statusline(menu->win_ibar->state.cols, buf, sizeof(buf));
1152  menu->redraw &= ~REDRAW_STATUS;
1153  if (C_TsEnabled && TsSupported)
1154  {
1155  menu_status_line(buf, sizeof(buf), menu, NONULL(C_TsStatusFormat));
1156  mutt_ts_status(buf);
1157  menu_status_line(buf, sizeof(buf), menu, NONULL(C_TsIconFormat));
1158  mutt_ts_icon(buf);
1159  }
1160  }
1161 
1162  menu->redraw = REDRAW_NO_FLAGS;
1163 }
struct Email ** emails
Array of Emails.
Definition: mailbox.h:99
The "current" mailbox.
Definition: context.h:37
#define REDRAW_FULL
Redraw everything.
Definition: mutt_menu.h:45
#define NONULL(x)
Definition: string2.h:37
WHERE char * C_TsIconFormat
Config: printf-like format string for the terminal&#39;s icon title.
Definition: mutt_globals.h:114
void mutt_curses_set_color(enum ColorId color)
Set the current colour for text.
Definition: mutt_curses.c:55
void menu_status_line(char *buf, size_t buflen, struct Menu *menu, const char *p)
Create the status line.
Definition: status.c:410
int vcount
The number of virtual messages.
Definition: mailbox.h:102
#define REDRAW_SIDEBAR
Redraw the sidebar.
Definition: mutt_menu.h:49
int mutt_window_move(struct MuttWindow *win, int col, int row)
Move the cursor in a Window.
Definition: mutt_window.c:362
struct Mailbox * mailbox
Definition: context.h:50
struct MuttWindow * win_ibar
Definition: mutt_menu.h:93
WHERE char * C_StatusFormat
Config: printf-like format string for the index&#39;s status line.
Definition: mutt_globals.h:112
#define REDRAW_MOTION
Redraw after moving the menu list.
Definition: mutt_menu.h:41
Plain text.
Definition: color.h:77
#define REDRAW_MOTION_RESYNC
Redraw any changing the menu selection.
Definition: mutt_menu.h:42
short cols
Number of columns, can be MUTT_WIN_SIZE_UNLIMITED.
Definition: mutt_window.h:57
struct WindowState state
Current state of the Window.
Definition: mutt_window.h:119
#define REDRAW_STATUS
Redraw the status bar.
Definition: mutt_menu.h:44
Status bar (takes a pattern)
Definition: color.h:94
WHERE bool C_TsEnabled
Config: Allow NeoMutt to set the terminal status line and icon.
Definition: mutt_globals.h:169
bool TsSupported
Terminal Setting is supported.
Definition: terminal.c:43
WHERE char * C_TsStatusFormat
Config: printf-like format string for the terminal&#39;s status (window title)
Definition: mutt_globals.h:113
MuttRedrawFlags redraw
When to redraw the screen.
Definition: mutt_menu.h:87
#define REDRAW_INDEX
Redraw the index.
Definition: mutt_menu.h:40
void mutt_ts_icon(char *str)
Set the icon in the terminal title bar.
Definition: terminal.c:118
void mutt_show_error(void)
Show the user an error message.
Definition: curs_lib.c:555
void mutt_ts_status(char *str)
Set the text of the terminal title bar.
Definition: terminal.c:104
int current
Current entry.
Definition: mutt_menu.h:85
#define REDRAW_NO_FLAGS
No flags are set.
Definition: mutt_menu.h:39
void mutt_draw_statusline(int cols, const char *buf, size_t buflen)
Draw a highlighted status bar.
Definition: index.c:989
#define REDRAW_CURRENT
Redraw the current line of the menu.
Definition: mutt_menu.h:43
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_index_menu()

int mutt_index_menu ( struct MuttWindow dlg)

Display a list of emails.

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

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

Definition at line 1173 of file index.c.

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