NeoMutt  2019-12-07-60-g0cfa53
Teaching an old dog new tricks
DOXYGEN
index.c File Reference

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

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

Go to the source code of this file.

Macros

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

Typedefs

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

Functions

static struct Emailget_cur_email (struct Context *ctx, struct Menu *menu)
 Get the currently-selected Email. More...
 
static bool prereq (struct Context *ctx, struct Menu *menu, CheckFlags checks)
 Check the pre-requisites for a function. More...
 
static bool check_acl (struct Context *ctx, AclFlags acl, const char *msg)
 Check the ACLs for a function. More...
 
static void collapse_all (struct Context *ctx, struct Menu *menu, int toggle)
 Collapse/uncollapse all threads. More...
 
static int ci_next_undeleted (struct Context *ctx, int msgno)
 Find the next undeleted email. More...
 
static int ci_previous_undeleted (struct Context *ctx, int msgno)
 Find the previous undeleted email. More...
 
static int ci_first_message (struct Context *ctx)
 Get index of first new message. More...
 
static int mx_toggle_write (struct Mailbox *m)
 Toggle the mailbox's readonly flag. More...
 
static void resort_index (struct Context *ctx, struct Menu *menu)
 Resort the index. More...
 
static void update_index_threaded (struct Context *ctx, int check, int oldcount)
 Update the index (if threaded) More...
 
static void update_index_unthreaded (struct Context *ctx, int check, int oldcount)
 Update the index (if unthreaded) More...
 
void update_index (struct Menu *menu, struct Context *ctx, int check, int oldcount, int index_hint)
 Update the index. More...
 
static int mailbox_index_observer (struct NotifyCallback *nc)
 Listen for Mailbox changes - Implements observer_t() More...
 
static int main_change_folder (struct Menu *menu, int op, struct Mailbox *m, char *buf, size_t buflen, int *oldcount, int *index_hint, bool *pager_return)
 Change to a different mailbox. More...
 
void index_make_entry (char *buf, size_t buflen, struct Menu *menu, int line)
 Format a menu item for the index list - Implements Menu::menu_make_entry() More...
 
int index_color (int line)
 Calculate the colour for a line of the index - Implements Menu::menu_color() More...
 
void mutt_draw_statusline (int cols, const char *buf, size_t buflen)
 Draw a highlighted status bar. More...
 
static void index_custom_redraw (struct Menu *menu)
 Redraw the index - Implements Menu::menu_custom_redraw() More...
 
int mutt_index_menu (struct MuttWindow *dlg)
 Display a list of emails. More...
 
void mutt_set_header_color (struct Mailbox *m, struct Email *e)
 Select a colour for a message. More...
 
int mutt_reply_observer (struct NotifyCallback *nc)
 Listen for config changes to "reply_regex" - Implements observer_t() More...
 
struct MuttWindowindex_pager_init (void)
 Allocate the Windows for the Index/Pager. More...
 
void index_pager_shutdown (struct MuttWindow *dlg)
 Clear up any non-Window parts. More...
 
int mutt_dlg_index_observer (struct NotifyCallback *nc)
 Listen for config changes affecting the Index/Pager - Implements observer_t() More...
 

Variables

bool C_ChangeFolderNext
 Config: Suggest the next folder, rather than the first when using '<change-folder>'. More...
 
bool C_CollapseAll
 Config: Collapse all threads when entering a folder. More...
 
bool C_CollapseFlagged
 Config: Prevent the collapse of threads with flagged emails. More...
 
bool C_CollapseUnread
 Config: Prevent the collapse of threads with unread emails. More...
 
char * C_MarkMacroPrefix
 Config: Prefix for macros using '<mark-message>'. More...
 
bool C_PgpAutoDecode
 Config: Automatically decrypt PGP messages. More...
 
bool C_UncollapseJump
 Config: When opening a thread, jump to the next unread message. More...
 
bool C_UncollapseNew
 Config: Open collapsed threads when new mail arrives. More...
 
static const struct Mapping IndexHelp []
 
struct Mapping IndexNewsHelp []
 

Detailed Description

GUI manage the main index (list of emails)

Authors
  • Michael R. Elkins

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

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

Definition in file index.c.

Macro Definition Documentation

◆ UNREAD

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

Definition at line 136 of file index.c.

◆ FLAGGED

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

Definition at line 137 of file index.c.

◆ CAN_COLLAPSE

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

Definition at line 139 of file index.c.

◆ CHECK_NO_FLAGS

#define CHECK_NO_FLAGS   0

No flags are set.

Definition at line 147 of file index.c.

◆ CHECK_IN_MAILBOX

#define CHECK_IN_MAILBOX   (1 << 0)

Is there a mailbox open?

Definition at line 148 of file index.c.

◆ CHECK_MSGCOUNT

#define CHECK_MSGCOUNT   (1 << 1)

Are there any messages?

Definition at line 149 of file index.c.

◆ CHECK_VISIBLE

#define CHECK_VISIBLE   (1 << 2)

Is the selected message visible in the index?

Definition at line 150 of file index.c.

◆ CHECK_READONLY

#define CHECK_READONLY   (1 << 3)

Is the mailbox readonly?

Definition at line 151 of file index.c.

◆ CHECK_ATTACH

#define CHECK_ATTACH   (1 << 4)

Is the user in message-attach mode?

Definition at line 152 of file index.c.

Typedef Documentation

◆ CheckFlags

typedef uint8_t CheckFlags

typedef CheckFlags - Checks to perform before running a function

Flags, e.g. CHECK_IN_MAILBOX

Definition at line 146 of file index.c.

Function Documentation

◆ get_cur_email()

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

Get the currently-selected Email.

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

Definition at line 162 of file index.c.

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

◆ prereq()

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

Check the pre-requisites for a function.

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

Definition at line 177 of file index.c.

178 {
179  bool result = true;
180 
181  if (checks & (CHECK_MSGCOUNT | CHECK_VISIBLE | CHECK_READONLY))
182  checks |= CHECK_IN_MAILBOX;
183 
184  if ((checks & CHECK_IN_MAILBOX) && (!ctx || !ctx->mailbox))
185  {
186  mutt_error(_("No mailbox is open"));
187  result = false;
188  }
189 
190  if (result && (checks & CHECK_MSGCOUNT) && (ctx->mailbox->msg_count == 0))
191  {
192  mutt_error(_("There are no messages"));
193  result = false;
194  }
195 
196  if (result && (checks & CHECK_VISIBLE) && (menu->current >= ctx->mailbox->vcount))
197  {
198  mutt_error(_("No visible messages"));
199  result = false;
200  }
201 
202  if (result && (checks & CHECK_READONLY) && ctx->mailbox->readonly)
203  {
204  mutt_error(_("Mailbox is read-only"));
205  result = false;
206  }
207 
208  if (result && (checks & CHECK_ATTACH) && OptAttachMsg)
209  {
210  mutt_error(_("Function not permitted in attach-message mode"));
211  result = false;
212  }
213 
214  if (!result)
215  mutt_flushinp();
216 
217  return result;
218 }
int msg_count
Total number of messages.
Definition: mailbox.h:90
void mutt_flushinp(void)
Empty all the keyboard buffers.
Definition: curs_lib.c:919
#define CHECK_ATTACH
Is the user in message-attach mode?
Definition: index.c:152
#define _(a)
Definition: message.h:28
int vcount
The number of virtual messages.
Definition: mailbox.h:101
#define CHECK_VISIBLE
Is the selected message visible in the index?
Definition: index.c:150
struct Mailbox * mailbox
Definition: context.h:50
#define CHECK_IN_MAILBOX
Is there a mailbox open?
Definition: index.c:148
bool readonly
Don&#39;t allow changes to the mailbox.
Definition: mailbox.h:118
WHERE bool OptAttachMsg
(pseudo) used by attach-message
Definition: options.h:31
#define CHECK_READONLY
Is the mailbox readonly?
Definition: index.c:151
#define mutt_error(...)
Definition: logging.h:84
#define CHECK_MSGCOUNT
Are there any messages?
Definition: index.c:149
int current
Current entry.
Definition: mutt_menu.h:87
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ check_acl()

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

Check the ACLs for a function.

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

Definition at line 227 of file index.c.

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

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

◆ ci_next_undeleted()

static int ci_next_undeleted ( 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 326 of file index.c.

327 {
328  if (!ctx || !ctx->mailbox)
329  return -1;
330 
331  for (int i = msgno + 1; i < ctx->mailbox->vcount; i++)
332  {
333  struct Email *e = mutt_get_virt_email(ctx->mailbox, i);
334  if (!e)
335  continue;
336  if (!e->deleted)
337  return i;
338  }
339  return -1;
340 }
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:414
int vcount
The number of virtual messages.
Definition: mailbox.h:101
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 349 of file index.c.

350 {
351  if (!ctx || !ctx->mailbox)
352  return -1;
353 
354  for (int i = msgno - 1; i >= 0; i--)
355  {
356  struct Email *e = mutt_get_virt_email(ctx->mailbox, i);
357  if (!e)
358  continue;
359  if (!e->deleted)
360  return i;
361  }
362  return -1;
363 }
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:414
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 373 of file index.c.

374 {
375  if (!ctx || !ctx->mailbox || (ctx->mailbox->msg_count == 0))
376  return 0;
377 
378  int old = -1;
379  for (int i = 0; i < ctx->mailbox->vcount; i++)
380  {
381  struct Email *e = mutt_get_virt_email(ctx->mailbox, i);
382  if (!e)
383  continue;
384  if (!e->read && !e->deleted)
385  {
386  if (!e->old)
387  return i;
388  if (old == -1)
389  old = i;
390  }
391  }
392  if (old != -1)
393  return old;
394 
395  /* If C_Sort is reverse and not threaded, the latest message is first.
396  * If C_Sort is threaded, the latest message is first if exactly one
397  * of C_Sort and C_SortAux are reverse. */
398  if (((C_Sort & SORT_REVERSE) && ((C_Sort & SORT_MASK) != SORT_THREADS)) ||
399  (((C_Sort & SORT_MASK) == SORT_THREADS) && ((C_Sort ^ C_SortAux) & SORT_REVERSE)))
400  {
401  return 0;
402  }
403  else
404  {
405  return ctx->mailbox->vcount ? ctx->mailbox->vcount - 1 : 0;
406  }
407 
408  return 0;
409 }
int msg_count
Total number of messages.
Definition: mailbox.h:90
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:414
int vcount
The number of virtual messages.
Definition: mailbox.h:101
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 419 of file index.c.

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

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

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

568 {
569  /* We are in a limited view. Check if the new message(s) satisfy
570  * the limit criteria. If they do, set their virtual msgno so that
571  * they will be visible in the limited view */
572  if (ctx->pattern)
573  {
574  int padding = mx_msg_padding_size(ctx->mailbox);
575  for (int i = (check == MUTT_REOPENED) ? 0 : oldcount; i < ctx->mailbox->msg_count; i++)
576  {
577  if (i == 0)
578  {
579  ctx->mailbox->vcount = 0;
580  ctx->vsize = 0;
581  }
582 
583  struct Email *e = ctx->mailbox->emails[i];
584  if (!e)
585  break;
587  MUTT_MATCH_FULL_ADDRESS, ctx->mailbox, e, NULL))
588  {
589  assert(ctx->mailbox->vcount < ctx->mailbox->msg_count);
590  e->vnum = ctx->mailbox->vcount;
591  ctx->mailbox->v2r[ctx->mailbox->vcount] = i;
592  e->limited = true;
593  ctx->mailbox->vcount++;
594  struct Body *b = e->content;
595  ctx->vsize += b->length + b->offset - b->hdr_offset + padding;
596  }
597  }
598  }
599 
600  /* if the mailbox was reopened, need to rethread from scratch */
601  mutt_sort_headers(ctx, (check == MUTT_REOPENED));
602 }
struct Email ** emails
Array of Emails.
Definition: mailbox.h:98
int msg_count
Total number of messages.
Definition: mailbox.h:90
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:101
The body of an email.
Definition: body.h:34
struct Mailbox * mailbox
Definition: context.h:50
bool limited
Is this message in a limited view?
Definition: email.h:74
off_t vsize
Definition: context.h:38
int mutt_pattern_exec(struct Pattern *pat, PatternExecFlags flags, struct Mailbox *m, struct Email *e, struct PatternCache *cache)
Match a pattern against an email header.
Definition: pattern.c:2008
void mutt_sort_headers(struct Context *ctx, bool init)
Sort emails by their headers.
Definition: sort.c:362
#define SLIST_FIRST(head)
Definition: queue.h:228
LOFF_T length
length (in bytes) of attachment
Definition: body.h:45
struct PatternList * limit_pattern
Compiled limit pattern.
Definition: context.h:40
int vnum
Virtual message number.
Definition: email.h:87
#define MUTT_MATCH_FULL_ADDRESS
Match the full address.
Definition: pattern.h:75
int * v2r
Mapping from virtual to real msgno.
Definition: mailbox.h:100
int mx_msg_padding_size(struct Mailbox *m)
Bytes of padding between messages - Wrapper for MxOps::msg_padding_size()
Definition: mx.c:1517
long hdr_offset
Offset in stream where the headers begin.
Definition: body.h:42
Mailbox was reopened.
Definition: mx.h:74
char * pattern
Limit pattern string.
Definition: context.h:39
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ update_index()

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

Update the index.

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

Definition at line 612 of file index.c.

613 {
614  if (!menu || !ctx)
615  return;
616 
617  /* take note of the current message */
618  if (oldcount)
619  {
620  if (menu->current < ctx->mailbox->vcount)
621  menu->oldcurrent = index_hint;
622  else
623  oldcount = 0; /* invalid message number! */
624  }
625 
626  if ((C_Sort & SORT_MASK) == SORT_THREADS)
627  update_index_threaded(ctx, check, oldcount);
628  else
629  update_index_unthreaded(ctx, check, oldcount);
630 
631  menu->current = -1;
632  if (oldcount)
633  {
634  /* restore the current message to the message it was pointing to */
635  for (int i = 0; i < ctx->mailbox->vcount; i++)
636  {
637  struct Email *e = mutt_get_virt_email(ctx->mailbox, i);
638  if (!e)
639  continue;
640  if (e->index == menu->oldcurrent)
641  {
642  menu->current = i;
643  break;
644  }
645  }
646  }
647 
648  if (menu->current < 0)
650 }
The "current" mailbox.
Definition: context.h:36
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:414
int oldcurrent
For driver use only.
Definition: mutt_menu.h:109
static void update_index_unthreaded(struct Context *ctx, int check, int oldcount)
Update the index (if unthreaded)
Definition: index.c:567
int vcount
The number of virtual messages.
Definition: mailbox.h:101
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
int index
The absolute (unsorted) message number.
Definition: email.h:85
static void update_index_threaded(struct Context *ctx, int check, int oldcount)
Update the index (if threaded)
Definition: index.c:487
int current
Current entry.
Definition: mutt_menu.h:87
static int ci_first_message(struct Context *ctx)
Get index of first new message.
Definition: index.c:373
#define SORT_MASK
Mask for the sort id.
Definition: sort2.h:85
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mailbox_index_observer()

static int mailbox_index_observer ( struct NotifyCallback nc)
static

Listen for Mailbox changes - Implements observer_t()

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

Definition at line 657 of file index.c.

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

◆ main_change_folder()

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

Change to a different mailbox.

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

Definition at line 685 of file index.c.

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

◆ index_make_entry()

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

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

Definition at line 825 of file index.c.

826 {
827  if (!Context || !Context->mailbox || !menu || (line < 0) ||
828  (line >= Context->mailbox->email_max))
829  return;
830 
832  if (!e)
833  return;
834 
836  struct MuttThread *tmp = NULL;
837 
838  if (((C_Sort & SORT_MASK) == SORT_THREADS) && e->tree)
839  {
840  flags |= MUTT_FORMAT_TREE; /* display the thread tree */
841  if (e->display_subject)
842  flags |= MUTT_FORMAT_FORCESUBJ;
843  else
844  {
845  const int reverse = C_Sort & SORT_REVERSE;
846  int edgemsgno;
847  if (reverse)
848  {
849  if (menu->top + menu->pagelen > menu->max)
850  edgemsgno = Context->mailbox->v2r[menu->max - 1];
851  else
852  edgemsgno = Context->mailbox->v2r[menu->top + menu->pagelen - 1];
853  }
854  else
855  edgemsgno = Context->mailbox->v2r[menu->top];
856 
857  for (tmp = e->thread->parent; tmp; tmp = tmp->parent)
858  {
859  if (!tmp->message)
860  continue;
861 
862  /* if no ancestor is visible on current screen, provisionally force
863  * subject... */
864  if (reverse ? (tmp->message->msgno > edgemsgno) : (tmp->message->msgno < edgemsgno))
865  {
866  flags |= MUTT_FORMAT_FORCESUBJ;
867  break;
868  }
869  else if (tmp->message->vnum >= 0)
870  break;
871  }
872  if (flags & MUTT_FORMAT_FORCESUBJ)
873  {
874  for (tmp = e->thread->prev; tmp; tmp = tmp->prev)
875  {
876  if (!tmp->message)
877  continue;
878 
879  /* ...but if a previous sibling is available, don't force it */
880  if (reverse ? (tmp->message->msgno > edgemsgno) : (tmp->message->msgno < edgemsgno))
881  break;
882  else if (tmp->message->vnum >= 0)
883  {
884  flags &= ~MUTT_FORMAT_FORCESUBJ;
885  break;
886  }
887  }
888  }
889  }
890  }
891 
892  mutt_make_string_flags(buf, buflen, menu->win_index->state.cols,
893  NONULL(C_IndexFormat), Context, Context->mailbox, e, flags);
894 }
The "current" mailbox.
Definition: context.h:36
uint8_t MuttFormatFlags
Flags for mutt_expando_format(), e.g. MUTT_FORMAT_FORCESUBJ.
Definition: format_flags.h:29
#define NONULL(x)
Definition: string2.h:37
The envelope/body of an email.
Definition: email.h:37
struct Email * mutt_get_virt_email(struct Mailbox *m, int vnum)
Get a virtual Email.
Definition: context.c:414
#define MUTT_FORMAT_FORCESUBJ
Print the subject even if unchanged.
Definition: format_flags.h:31
struct MuttThread * thread
Thread of Emails.
Definition: email.h:94
#define MUTT_FORMAT_ARROWCURSOR
Reserve space for arrow_cursor.
Definition: format_flags.h:35
bool display_subject
Used for threading.
Definition: email.h:57
struct MuttThread * parent
Parent of this Thread.
Definition: thread.h:45
struct MuttThread * prev
Previous sibling Thread.
Definition: thread.h:48
struct Mailbox * mailbox
Definition: context.h:50
#define MUTT_FORMAT_TREE
Draw the thread tree.
Definition: format_flags.h:32
void mutt_make_string_flags(char *buf, size_t buflen, int cols, const char *s, struct Context *ctx, struct Mailbox *m, struct Email *e, MuttFormatFlags flags)
Create formatted strings using mailbox expandos.
Definition: hdrline.c:1505
WHERE short C_Sort
Config: Sort method for the index.
Definition: sort.h:58
short cols
Number of columns, can be MUTT_WIN_SIZE_UNLIMITED.
Definition: mutt_window.h:56
const char * line
Definition: common.c:36
Sort by email threads.
Definition: sort2.h:56
struct WindowState state
Current state of the Window.
Definition: mutt_window.h:91
int email_max
Number of pointers in emails.
Definition: mailbox.h:99
WHERE char * C_IndexFormat
Config: printf-like format string for the index menu (emails)
Definition: globals.h:112
int top
Entry that is the top of the current page.
Definition: mutt_menu.h:108
int vnum
Virtual message number.
Definition: email.h:87
int pagelen
Number of entries per screen.
Definition: mutt_menu.h:92
char * tree
Character string to print thread tree.
Definition: email.h:93
struct Email * message
Email this Thread refers to.
Definition: thread.h:49
int max
Number of entries in the menu.
Definition: mutt_menu.h:88
An Email conversation.
Definition: thread.h:34
int * v2r
Mapping from virtual to real msgno.
Definition: mailbox.h:100
#define MUTT_FORMAT_INDEX
This is a main index entry.
Definition: format_flags.h:36
struct MuttWindow * win_index
Definition: mutt_menu.h:95
#define SORT_REVERSE
Reverse the order of the sort.
Definition: sort2.h:86
#define SORT_MASK
Mask for the sort id.
Definition: sort2.h:85
int msgno
Number displayed to the user.
Definition: email.h:86
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ index_color()

int index_color ( int  line)

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

Definition at line 899 of file index.c.

900 {
901  if (!Context || !Context->mailbox || (line < 0))
902  return 0;
903 
905  if (!e)
906  return 0;
907 
908  if (e->pair)
909  return e->pair;
910 
912  return e->pair;
913 }
The "current" mailbox.
Definition: context.h:36
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:414
struct Mailbox * mailbox
Definition: context.h:50
const char * line
Definition: common.c:36
void mutt_set_header_color(struct Mailbox *m, struct Email *e)
Select a colour for a message.
Definition: index.c:3921
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 927 of file index.c.

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

◆ index_custom_redraw()

static void index_custom_redraw ( struct Menu menu)
static

Redraw the index - Implements Menu::menu_custom_redraw()

Definition at line 1056 of file index.c.

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

◆ mutt_index_menu()

int mutt_index_menu ( struct MuttWindow dlg)

Display a list of emails.

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

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

Definition at line 1114 of file index.c.

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