NeoMutt  2018-07-16 +952-a2da0a
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 <stdio.h>
#include <string.h>
#include "mutt/mutt.h"
#include "config/lib.h"
#include "email/lib.h"
#include "conn/conn.h"
#include "mutt.h"
#include "index.h"
#include "account.h"
#include "alias.h"
#include "browser.h"
#include "commands.h"
#include "context.h"
#include "curs_lib.h"
#include "format_flags.h"
#include "globals.h"
#include "hdrline.h"
#include "hook.h"
#include "keymap.h"
#include "mailbox.h"
#include "menu.h"
#include "mutt_account.h"
#include "mutt_curses.h"
#include "mutt_header.h"
#include "mutt_logging.h"
#include "mutt_thread.h"
#include "mutt_window.h"
#include "muttlib.h"
#include "mx.h"
#include "ncrypt/ncrypt.h"
#include "opcodes.h"
#include "options.h"
#include "pager.h"
#include "pattern.h"
#include "progress.h"
#include "protos.h"
#include "query.h"
#include "recvattach.h"
#include "score.h"
#include "send.h"
#include "sort.h"
#include "status.h"
#include "terminal.h"
#include "sidebar.h"
#include "pop/pop.h"
#include "imap/imap.h"
#include "notmuch/mutt_notmuch.h"
#include "nntp/nntp.h"
#include <libintl.h>

Go to the source code of this file.

Macros

#define CHECK_IN_MAILBOX
 
#define CHECK_MSGCOUNT
 
#define CHECK_VISIBLE
 
#define CHECK_READONLY
 
#define CHECK_ACL(aclbit, action)
 
#define CHECK_ATTACH
 
#define CURHDR   Context->mailbox->hdrs[Context->mailbox->v2r[menu->current]]
 
#define UNREAD(h)   mutt_thread_contains_unread(Context, h)
 
#define FLAGGED(h)   mutt_thread_contains_flagged(Context, h)
 
#define CAN_COLLAPSE(header)   ((CollapseUnread || !UNREAD(header)) && (CollapseFlagged || !FLAGGED(header)))
 

Functions

static void collapse_all (struct Menu *menu, int toggle)
 Collapse/uncollapse all threads. More...
 
static int ci_next_undeleted (int msgno)
 Find the next undeleted email. More...
 
static int ci_previous_undeleted (int msgno)
 Find the previous undeleted email. More...
 
static int ci_first_message (void)
 Get index of first new message. More...
 
static int mx_toggle_write (struct Mailbox *m)
 Toggle the mailbox's readonly flag. More...
 
static void resort_index (struct Menu *menu)
 Resort the index. More...
 
static void update_index_threaded (struct Context *ctx, int check, int oldcount)
 Update the index (if threaded) More...
 
static void update_index_unthreaded (struct Context *ctx, int check, int oldcount)
 Update the index (if unthreaded) More...
 
void update_index (struct Menu *menu, struct Context *ctx, int check, int oldcount, int index_hint)
 Update the index. More...
 
static int main_change_folder (struct Menu *menu, int op, struct Mailbox *m, char *buf, size_t buflen, int *oldcount, int *index_hint)
 Change to a different mailbox. More...
 
void index_make_entry (char *buf, size_t buflen, struct Menu *menu, int line)
 Format a menu item for the index list - Implements Menu::menu_make_entry() More...
 
int index_color (int line)
 Calculate the colour for a line of the index - Implements Menu::menu_color() More...
 
void mutt_draw_statusline (int cols, const char *buf, size_t buflen)
 Draw a highlighted status bar. More...
 
static void index_custom_redraw (struct Menu *menu)
 Redraw the index - Implements Menu::menu_custom_redraw() More...
 
int mutt_index_menu (void)
 Display a list of emails. More...
 
void mutt_set_header_color (struct Mailbox *m, struct Email *curhdr)
 Select a colour for a message. More...
 
bool mutt_reply_listener (const struct ConfigSet *cs, struct HashElem *he, const char *name, enum ConfigEvent ev)
 Listen for config changes to "reply_regex" - Implements cs_listener() More...
 

Variables

bool ChangeFolderNext
 Config: Suggest the next folder, rather than the first when using '<change-folder>'. More...
 
bool CollapseAll
 Config: Collapse all threads when entering a folder. More...
 
bool CollapseFlagged
 Config: Prevent the collapse of threads with flagged emails. More...
 
bool CollapseUnread
 Config: Prevent the collapse of threads with unread emails. More...
 
char * MarkMacroPrefix
 Config: Prefix for macros using '<mark-message>'. More...
 
bool PgpAutoDecode
 Config: Automatically decrypt PGP messages. More...
 
bool UncollapseJump
 Config: When opening a thread, jump to the next unread message. More...
 
bool UncollapseNew
 Config: Open collapsed threads when new mail arrives. More...
 
static const char * No_mailbox_is_open = N_("No mailbox is open")
 
static const char * There_are_no_messages = N_("There are no messages")
 
static const char * Mailbox_is_read_only = N_("Mailbox is read-only")
 
static const char * Function_not_permitted_in_attach_message_mode
 
static const char * NoVisible = N_("No visible messages")
 
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

#define CHECK_IN_MAILBOX
Value:
if (!Context) \
{ \
break; \
}
The "current" mailbox.
Definition: context.h:36
void mutt_flushinp(void)
Empty all the keyboard buffers.
Definition: curs_lib.c:753
static const char * No_mailbox_is_open
Definition: index.c:110
#define _(a)
Definition: message.h:28
#define mutt_error(...)
Definition: logging.h:88

Definition at line 117 of file index.c.

#define CHECK_MSGCOUNT
Value:
if (!Context) \
{ \
break; \
} \
else if (!Context->mailbox->msg_count) \
{ \
break; \
}
The "current" mailbox.
Definition: context.h:36
int msg_count
total number of messages
Definition: mailbox.h:86
void mutt_flushinp(void)
Empty all the keyboard buffers.
Definition: curs_lib.c:753
static const char * No_mailbox_is_open
Definition: index.c:110
#define _(a)
Definition: message.h:28
struct Mailbox * mailbox
Definition: context.h:50
static const char * There_are_no_messages
Definition: index.c:111
#define mutt_error(...)
Definition: logging.h:88

Definition at line 125 of file index.c.

#define CHECK_VISIBLE
Value:
if (Context && menu->current >= Context->mailbox->vcount) \
{ \
break; \
}
The "current" mailbox.
Definition: context.h:36
static const char * NoVisible
Definition: index.c:115
void mutt_flushinp(void)
Empty all the keyboard buffers.
Definition: curs_lib.c:753
#define _(a)
Definition: message.h:28
int vcount
the number of virtual messages
Definition: mailbox.h:96
struct Mailbox * mailbox
Definition: context.h:50
#define mutt_error(...)
Definition: logging.h:88

Definition at line 139 of file index.c.

#define CHECK_READONLY
Value:
{ \
break; \
}
The "current" mailbox.
Definition: context.h:36
void mutt_flushinp(void)
Empty all the keyboard buffers.
Definition: curs_lib.c:753
#define _(a)
Definition: message.h:28
struct Mailbox * mailbox
Definition: context.h:50
bool readonly
don&#39;t allow changes to the mailbox
Definition: mailbox.h:113
static const char * Mailbox_is_read_only
Definition: index.c:112
#define mutt_error(...)
Definition: logging.h:88

Definition at line 147 of file index.c.

#define CHECK_ACL (   aclbit,
  action 
)
Value:
{ \
/* L10N: %s is one of the CHECK_ACL entries below. */ \
mutt_error(_("%s: Operation not permitted by ACL"), action); \
break; \
}
The "current" mailbox.
Definition: context.h:36
#define mutt_bit_isset(v, n)
Definition: memory.h:39
unsigned char rights[(MUTT_ACL_MAX+7)/8]
ACL bits.
Definition: mailbox.h:115
void mutt_flushinp(void)
Empty all the keyboard buffers.
Definition: curs_lib.c:753
#define _(a)
Definition: message.h:28
struct Mailbox * mailbox
Definition: context.h:50
#define mutt_error(...)
Definition: logging.h:88

Definition at line 155 of file index.c.

#define CHECK_ATTACH
Value:
{ \
break; \
}
void mutt_flushinp(void)
Empty all the keyboard buffers.
Definition: curs_lib.c:753
#define _(a)
Definition: message.h:28
WHERE bool OptAttachMsg
(pseudo) used by attach-message
Definition: options.h:31
#define mutt_error(...)
Definition: logging.h:88
static const char * Function_not_permitted_in_attach_message_mode
Definition: index.c:113

Definition at line 164 of file index.c.

#define CURHDR   Context->mailbox->hdrs[Context->mailbox->v2r[menu->current]]

Definition at line 172 of file index.c.

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

Definition at line 173 of file index.c.

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

Definition at line 174 of file index.c.

#define CAN_COLLAPSE (   header)    ((CollapseUnread || !UNREAD(header)) && (CollapseFlagged || !FLAGGED(header)))

Definition at line 176 of file index.c.

Function Documentation

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

Collapse/uncollapse all threads.

Parameters
menucurrent menu
toggletoggle collapsed state

This function is called by the OP_MAIN_COLLAPSE_ALL command and on folder enter if the 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 190 of file index.c.

191 {
192  struct Email *e = NULL, *base = NULL;
193  struct MuttThread *thread = NULL, *top = NULL;
194  int final;
195 
196  if (!Context || (Context->mailbox->msg_count == 0))
197  return;
198 
199  /* Figure out what the current message would be after folding / unfolding,
200  * so that we can restore the cursor in a sane way afterwards. */
201  if (CURHDR->collapsed && toggle)
203  else if (CAN_COLLAPSE(CURHDR))
205  else
206  final = CURHDR->virtual;
207 
208  base = Context->mailbox->hdrs[Context->mailbox->v2r[final]];
209 
210  /* Iterate all threads, perform collapse/uncollapse as needed */
211  top = Context->tree;
212  Context->collapsed = toggle ? !Context->collapsed : true;
213  while ((thread = top))
214  {
215  while (!thread->message)
216  thread = thread->child;
217  e = thread->message;
218 
219  if (e->collapsed != Context->collapsed)
220  {
221  if (e->collapsed)
223  else if (CAN_COLLAPSE(e))
225  }
226  top = top->next;
227  }
228 
229  /* Restore the cursor */
231  for (int j = 0; j < Context->mailbox->vcount; j++)
232  {
233  if (Context->mailbox->hdrs[Context->mailbox->v2r[j]]->index == base->index)
234  {
235  menu->current = j;
236  break;
237  }
238  }
239 
241 }
The "current" mailbox.
Definition: context.h:36
int msg_count
total number of messages
Definition: mailbox.h:86
int redraw
when to redraw the screen
Definition: menu.h:63
The envelope/body of an email.
Definition: email.h:35
struct MuttThread * tree
top of thread tree
Definition: context.h:42
#define mutt_uncollapse_thread(x, y)
Definition: mutt_thread.h:60
struct Email ** hdrs
Definition: mailbox.h:93
int vcount
the number of virtual messages
Definition: mailbox.h:96
#define mutt_collapse_thread(x, y)
Definition: mutt_thread.h:59
struct Mailbox * mailbox
Definition: context.h:50
struct MuttThread * child
Definition: thread.h:45
#define CAN_COLLAPSE(header)
Definition: index.c:176
bool collapsed
is this message part of a collapsed thread?
Definition: email.h:75
struct Email * message
Definition: thread.h:48
An email conversation.
Definition: thread.h:34
int * v2r
mapping from virtual to real msgno
Definition: mailbox.h:95
bool collapsed
are all threads collapsed?
Definition: context.h:48
int index
the absolute (unsorted) message number
Definition: email.h:87
#define CURHDR
Definition: index.c:172
int current
current entry
Definition: menu.h:61
void mutt_set_virtual(struct Context *ctx)
Set the virtual index number of all the messages in a mailbox.
Definition: mutt_thread.c:1187

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static int ci_next_undeleted ( int  msgno)
static

Find the next undeleted email.

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

Definition at line 249 of file index.c.

250 {
251  for (int i = msgno + 1; i < Context->mailbox->vcount; i++)
252  if (!Context->mailbox->hdrs[Context->mailbox->v2r[i]]->deleted)
253  return i;
254  return -1;
255 }
The "current" mailbox.
Definition: context.h:36
struct Email ** hdrs
Definition: mailbox.h:93
int vcount
the number of virtual messages
Definition: mailbox.h:96
struct Mailbox * mailbox
Definition: context.h:50
int * v2r
mapping from virtual to real msgno
Definition: mailbox.h:95
bool deleted
Definition: email.h:43

+ Here is the caller graph for this function:

static int ci_previous_undeleted ( int  msgno)
static

Find the previous undeleted email.

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

Definition at line 263 of file index.c.

264 {
265  for (int i = msgno - 1; i >= 0; i--)
266  if (!Context->mailbox->hdrs[Context->mailbox->v2r[i]]->deleted)
267  return i;
268  return -1;
269 }
The "current" mailbox.
Definition: context.h:36
struct Email ** hdrs
Definition: mailbox.h:93
struct Mailbox * mailbox
Definition: context.h:50
int * v2r
mapping from virtual to real msgno
Definition: mailbox.h:95
bool deleted
Definition: email.h:43

+ Here is the caller graph for this function:

static int ci_first_message ( void  )
static

Get index of first new message.

Return values
numIndex of first new message

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

Definition at line 278 of file index.c.

279 {
280  if (!Context || !Context->mailbox->msg_count)
281  return 0;
282 
283  int old = -1;
284  for (int i = 0; i < Context->mailbox->vcount; i++)
285  {
286  if (!Context->mailbox->hdrs[Context->mailbox->v2r[i]]->read &&
288  {
289  if (!Context->mailbox->hdrs[Context->mailbox->v2r[i]]->old)
290  return i;
291  else if (old == -1)
292  old = i;
293  }
294  }
295  if (old != -1)
296  return old;
297 
298  /* If Sort is reverse and not threaded, the latest message is first.
299  * If Sort is threaded, the latest message is first iff exactly one
300  * of Sort and SortAux are reverse.
301  */
302  if (((Sort & SORT_REVERSE) && (Sort & SORT_MASK) != SORT_THREADS) ||
303  ((Sort & SORT_MASK) == SORT_THREADS && ((Sort ^ SortAux) & SORT_REVERSE)))
304  {
305  return 0;
306  }
307  else
308  {
309  return Context->mailbox->vcount ? Context->mailbox->vcount - 1 : 0;
310  }
311 
312  return 0;
313 }
The "current" mailbox.
Definition: context.h:36
int msg_count
total number of messages
Definition: mailbox.h:86
struct Email ** hdrs
Definition: mailbox.h:93
int vcount
the number of virtual messages
Definition: mailbox.h:96
bool read
Definition: email.h:49
struct Mailbox * mailbox
Definition: context.h:50
bool old
Definition: email.h:48
#define SORT_THREADS
Sort by email threads.
Definition: sort.h:51
int * v2r
mapping from virtual to real msgno
Definition: mailbox.h:95
WHERE short Sort
Config: Sort method for the index.
Definition: sort.h:58
bool deleted
Definition: email.h:43
#define SORT_REVERSE
Reverse the order of the sort.
Definition: sort.h:78
WHERE short SortAux
Config: Secondary sort method for the index.
Definition: sort.h:59
#define SORT_MASK
Mask for the sort id.
Definition: sort.h:77

+ Here is the caller graph for this function:

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

324 {
325  if (!m)
326  return -1;
327 
328  if (m->readonly)
329  {
330  mutt_error(_("Cannot toggle write on a readonly mailbox"));
331  return -1;
332  }
333 
334  if (m->dontwrite)
335  {
336  m->dontwrite = false;
337  mutt_message(_("Changes to folder will be written on folder exit"));
338  }
339  else
340  {
341  m->dontwrite = true;
342  mutt_message(_("Changes to folder will not be written"));
343  }
344 
345  return 0;
346 }
#define mutt_message(...)
Definition: logging.h:87
#define _(a)
Definition: message.h:28
bool readonly
don&#39;t allow changes to the mailbox
Definition: mailbox.h:113
bool dontwrite
don&#39;t write the mailbox on close
Definition: mailbox.h:109
#define mutt_error(...)
Definition: logging.h:88

+ Here is the caller graph for this function:

static void resort_index ( struct Menu menu)
static

Resort the index.

Parameters
menuCurrent Menu

Definition at line 352 of file index.c.

353 {
354  struct Email *current = CURHDR;
355 
356  menu->current = -1;
357  mutt_sort_headers(Context, false);
358  /* Restore the current message */
359 
360  for (int i = 0; i < Context->mailbox->vcount; i++)
361  {
362  if (Context->mailbox->hdrs[Context->mailbox->v2r[i]] == current)
363  {
364  menu->current = i;
365  break;
366  }
367  }
368 
369  if ((Sort & SORT_MASK) == SORT_THREADS && menu->current < 0)
370  menu->current = mutt_parent_message(Context, current, false);
371 
372  if (menu->current < 0)
373  menu->current = ci_first_message();
374 
375  menu->redraw |= REDRAW_INDEX | REDRAW_STATUS;
376 }
The "current" mailbox.
Definition: context.h:36
int redraw
when to redraw the screen
Definition: menu.h:63
The envelope/body of an email.
Definition: email.h:35
struct Email ** hdrs
Definition: mailbox.h:93
int vcount
the number of virtual messages
Definition: mailbox.h:96
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:1141
static int ci_first_message(void)
Get index of first new message.
Definition: index.c:278
void mutt_sort_headers(struct Context *ctx, bool init)
Sort emails by their headers.
Definition: sort.c:360
#define SORT_THREADS
Sort by email threads.
Definition: sort.h:51
int * v2r
mapping from virtual to real msgno
Definition: mailbox.h:95
WHERE short Sort
Config: Sort method for the index.
Definition: sort.h:58
#define CURHDR
Definition: index.c:172
int current
current entry
Definition: menu.h:61
#define SORT_MASK
Mask for the sort id.
Definition: sort.h:77

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

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

385 {
386  struct Email **save_new = NULL;
387 
388  /* save the list of new messages */
389  if ((check != MUTT_REOPENED) && oldcount && (ctx->pattern || UncollapseNew))
390  {
391  save_new = mutt_mem_malloc(sizeof(struct Email *) * (ctx->mailbox->msg_count - oldcount));
392  for (int i = oldcount; i < ctx->mailbox->msg_count; i++)
393  save_new[i - oldcount] = ctx->mailbox->hdrs[i];
394  }
395 
396  /* Sort first to thread the new messages, because some patterns
397  * require the threading information.
398  *
399  * If the mailbox was reopened, need to rethread from scratch. */
400  mutt_sort_headers(ctx, (check == MUTT_REOPENED));
401 
402  if (ctx->pattern)
403  {
404  for (int i = (check == MUTT_REOPENED) ? 0 : oldcount; i < ctx->mailbox->msg_count; i++)
405  {
406  struct Email *e = NULL;
407 
408  if ((check != MUTT_REOPENED) && oldcount)
409  e = save_new[i - oldcount];
410  else
411  e = ctx->mailbox->hdrs[i];
412 
414  {
415  /* virtual will get properly set by mutt_set_virtual(), which
416  * is called by mutt_sort_headers() just below. */
417  e->virtual = 1;
418  e->limited = true;
419  }
420  }
421  /* Need a second sort to set virtual numbers and redraw the tree */
422  mutt_sort_headers(ctx, false);
423  }
424 
425  /* uncollapse threads with new mail */
426  if (UncollapseNew)
427  {
428  if (check == MUTT_REOPENED)
429  {
430  ctx->collapsed = false;
431 
432  for (struct MuttThread *h = ctx->tree; h; h = h->next)
433  {
434  struct MuttThread *j = h;
435  for (; !j->message; j = j->child)
436  ;
438  }
439  mutt_set_virtual(ctx);
440  }
441  else if (oldcount)
442  {
443  for (int j = 0; j < (ctx->mailbox->msg_count - oldcount); j++)
444  {
445  if (!ctx->pattern || save_new[j]->limited)
446  {
447  mutt_uncollapse_thread(ctx, save_new[j]);
448  }
449  }
450  mutt_set_virtual(ctx);
451  }
452  }
453 
454  FREE(&save_new);
455 }
struct MuttThread * next
Definition: thread.h:46
int msg_count
total number of messages
Definition: mailbox.h:86
bool UncollapseNew
Config: Open collapsed threads when new mail arrives.
Definition: index.c:108
The envelope/body of an email.
Definition: email.h:35
struct MuttThread * tree
top of thread tree
Definition: context.h:42
int virtual
virtual message number
Definition: email.h:89
Match the full address.
Definition: pattern.h:69
#define mutt_uncollapse_thread(x, y)
Definition: mutt_thread.h:60
struct Email ** hdrs
Definition: mailbox.h:93
struct Mailbox * mailbox
Definition: context.h:50
bool limited
is this message in a limited view?
Definition: email.h:76
struct MuttThread * child
Definition: thread.h:45
void mutt_sort_headers(struct Context *ctx, bool init)
Sort emails by their headers.
Definition: sort.c:360
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:99
struct Email * message
Definition: thread.h:48
struct Pattern * limit_pattern
compiled limit pattern
Definition: context.h:40
An email conversation.
Definition: thread.h:34
bool collapsed
are all threads collapsed?
Definition: context.h:48
#define FREE(x)
Definition: memory.h:46
int mutt_pattern_exec(struct Pattern *pat, enum PatternExecFlag flags, struct Mailbox *m, struct Email *e, struct PatternCache *cache)
Match a pattern against an email header.
Definition: pattern.c:1837
mailbox was reopened
Definition: mx.h:74
void mutt_set_virtual(struct Context *ctx)
Set the virtual index number of all the messages in a mailbox.
Definition: mutt_thread.c:1187
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:

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

464 {
465  /* We are in a limited view. Check if the new message(s) satisfy
466  * the limit criteria. If they do, set their virtual msgno so that
467  * they will be visible in the limited view */
468  if (ctx->pattern)
469  {
470  int padding = mx_msg_padding_size(ctx->mailbox);
471  for (int i = (check == MUTT_REOPENED) ? 0 : oldcount; i < ctx->mailbox->msg_count; i++)
472  {
473  if (!i)
474  {
475  ctx->mailbox->vcount = 0;
476  ctx->vsize = 0;
477  }
478 
480  ctx->mailbox, ctx->mailbox->hdrs[i], NULL))
481  {
482  assert(ctx->mailbox->vcount < ctx->mailbox->msg_count);
483  ctx->mailbox->hdrs[i]->virtual = ctx->mailbox->vcount;
484  ctx->mailbox->v2r[ctx->mailbox->vcount] = i;
485  ctx->mailbox->hdrs[i]->limited = true;
486  ctx->mailbox->vcount++;
487  struct Body *b = ctx->mailbox->hdrs[i]->content;
488  ctx->vsize += b->length + b->offset - b->hdr_offset + padding;
489  }
490  }
491  }
492 
493  /* if the mailbox was reopened, need to rethread from scratch */
494  mutt_sort_headers(ctx, (check == MUTT_REOPENED));
495 }
int msg_count
total number of messages
Definition: mailbox.h:86
int virtual
virtual message number
Definition: email.h:89
struct Body * content
list of MIME parts
Definition: email.h:92
LOFF_T offset
offset where the actual data begins
Definition: body.h:45
Match the full address.
Definition: pattern.h:69
struct Email ** hdrs
Definition: mailbox.h:93
int vcount
the number of virtual messages
Definition: mailbox.h:96
The body of an email.
Definition: body.h:33
struct Mailbox * mailbox
Definition: context.h:50
bool limited
is this message in a limited view?
Definition: email.h:76
off_t vsize
Definition: context.h:38
void mutt_sort_headers(struct Context *ctx, bool init)
Sort emails by their headers.
Definition: sort.c:360
LOFF_T length
length (in bytes) of attachment
Definition: body.h:46
struct Pattern * limit_pattern
compiled limit pattern
Definition: context.h:40
int * v2r
mapping from virtual to real msgno
Definition: mailbox.h:95
int mx_msg_padding_size(struct Mailbox *m)
Bytes of padding between messages - Wrapper for MxOps::msg_padding_size.
Definition: mx.c:1660
long hdr_offset
offset in stream where the headers begin.
Definition: body.h:41
int mutt_pattern_exec(struct Pattern *pat, enum PatternExecFlag flags, struct Mailbox *m, struct Email *e, struct PatternCache *cache)
Match a pattern against an email header.
Definition: pattern.c:1837
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:

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

506 {
507  if (!menu || !ctx)
508  return;
509 
510  /* take note of the current message */
511  if (oldcount)
512  {
513  if (menu->current < ctx->mailbox->vcount)
514  menu->oldcurrent = index_hint;
515  else
516  oldcount = 0; /* invalid message number! */
517  }
518 
519  if ((Sort & SORT_MASK) == SORT_THREADS)
520  update_index_threaded(ctx, check, oldcount);
521  else
522  update_index_unthreaded(ctx, check, oldcount);
523 
524  menu->current = -1;
525  if (oldcount)
526  {
527  /* restore the current message to the message it was pointing to */
528  for (int i = 0; i < ctx->mailbox->vcount; i++)
529  {
530  if (ctx->mailbox->hdrs[ctx->mailbox->v2r[i]]->index == menu->oldcurrent)
531  {
532  menu->current = i;
533  break;
534  }
535  }
536  }
537 
538  if (menu->current < 0)
539  menu->current = ci_first_message();
540 }
int oldcurrent
for driver use only
Definition: menu.h:85
static void update_index_unthreaded(struct Context *ctx, int check, int oldcount)
Update the index (if unthreaded)
Definition: index.c:463
struct Email ** hdrs
Definition: mailbox.h:93
int vcount
the number of virtual messages
Definition: mailbox.h:96
struct Mailbox * mailbox
Definition: context.h:50
static int ci_first_message(void)
Get index of first new message.
Definition: index.c:278
#define SORT_THREADS
Sort by email threads.
Definition: sort.h:51
int * v2r
mapping from virtual to real msgno
Definition: mailbox.h:95
WHERE short Sort
Config: Sort method for the index.
Definition: sort.h:58
int index
the absolute (unsorted) message number
Definition: email.h:87
static void update_index_threaded(struct Context *ctx, int check, int oldcount)
Update the index (if threaded)
Definition: index.c:384
int current
current entry
Definition: menu.h:61
#define SORT_MASK
Mask for the sort id.
Definition: sort.h:77

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static int main_change_folder ( struct Menu menu,
int  op,
struct Mailbox m,
char *  buf,
size_t  buflen,
int *  oldcount,
int *  index_hint 
)
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
Return values
0Success
-1Error

Definition at line 554 of file index.c.

556 {
557 #ifdef USE_NNTP
558  if (OptNews)
559  {
560  OptNews = false;
561  nntp_expand_path(buf, buflen, &CurrentNewsSrv->conn->account);
562  }
563  else
564 #endif
565  {
566  mx_path_canon(buf, buflen, Folder, NULL);
567  }
568 
569  enum MailboxType magic = mx_path_probe(buf, NULL);
570  if ((magic == MUTT_MAILBOX_ERROR) || (magic == MUTT_UNKNOWN))
571  {
572  mutt_error(_("%s is not a mailbox"), buf);
573  return -1;
574  }
575 
576  /* keepalive failure in mutt_enter_fname may kill connection. #3028 */
577  if (Context && (Context->mailbox->path[0] == '\0'))
579 
580  if (Context)
581  {
582  char *new_last_folder = NULL;
583 #ifdef USE_INOTIFY
584  int monitor_remove_rc = mutt_monitor_remove(NULL);
585 #endif
586 #ifdef USE_COMPRESSED
587  if (Context->mailbox->compress_info && (Context->mailbox->realpath[0] != '\0'))
588  new_last_folder = mutt_str_strdup(Context->mailbox->realpath);
589  else
590 #endif
591  new_last_folder = mutt_str_strdup(Context->mailbox->path);
592  *oldcount = Context ? Context->mailbox->msg_count : 0;
593 
594  int check = mx_mbox_close(&Context, index_hint);
595  if (check != 0)
596  {
597 #ifdef USE_INOTIFY
598  if (monitor_remove_rc == 0)
599  mutt_monitor_add(NULL);
600 #endif
601  if (check == MUTT_NEW_MAIL || check == MUTT_REOPENED)
602  update_index(menu, Context, check, *oldcount, *index_hint);
603 
604  FREE(&new_last_folder);
605  OptSearchInvalid = true;
606  menu->redraw |= REDRAW_INDEX | REDRAW_STATUS;
607  return 0;
608  }
609  FREE(&LastFolder);
610  LastFolder = new_last_folder;
611  }
613 
614  mutt_sleep(0);
615 
616  /* Note that menu->menu may be MENU_PAGER if the change folder
617  * operation originated from the pager.
618  *
619  * However, exec commands currently use CurrentMenu to determine what
620  * functions are available, which is automatically set by the
621  * mutt_push/pop_current_menu() functions. If that changes, the menu
622  * would need to be reset here, and the pager cleanup code after the
623  * switch statement would need to be run. */
624  mutt_folder_hook(buf);
625 
626  const int flags =
627  (ReadOnly || (op == OP_MAIN_CHANGE_FOLDER_READONLY)) ? MUTT_READONLY : 0;
628  Context = mx_mbox_open(m, buf, flags);
629  if (Context)
630  {
631  menu->current = ci_first_message();
632 #ifdef USE_INOTIFY
633  mutt_monitor_add(NULL);
634 #endif
635  }
636  else
637  menu->current = 0;
638 
639  if (((Sort & SORT_MASK) == SORT_THREADS) && CollapseAll)
640  collapse_all(menu, 0);
641 
642 #ifdef USE_SIDEBAR
644 #endif
645 
647  mutt_mailbox_check(MUTT_MAILBOX_CHECK_FORCE); /* force the mailbox check after we have changed the folder */
648  menu->redraw = REDRAW_FULL;
649  OptSearchInvalid = true;
650 
651  return 0;
652 }
The "current" mailbox.
Definition: context.h:36
int msg_count
total number of messages
Definition: mailbox.h:86
int redraw
when to redraw the screen
Definition: menu.h:63
void mutt_folder_hook(const char *path)
Perform a folder hook.
Definition: hook.c:371
struct ConnAccount account
Definition: connection.h:37
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:1497
int mutt_monitor_remove(struct Mailbox *m)
Remove a watch for a mailbox.
Definition: monitor.c:478
#define _(a)
Definition: message.h:28
WHERE char * LastFolder
Previously selected mailbox.
Definition: globals.h:53
#define MUTT_READONLY
open in read-only mode
Definition: mx.h:51
int mutt_monitor_add(struct Mailbox *m)
Add a watch for a mailbox.
Definition: monitor.c:440
int mutt_mailbox_check(int force)
Check all AllMailboxes for new mail.
Definition: mailbox.c:538
static void collapse_all(struct Menu *menu, int toggle)
Collapse/uncollapse all threads.
Definition: index.c:190
void mutt_sleep(short s)
Sleep for a while.
Definition: muttlib.c:1478
struct Context * mx_mbox_open(struct Mailbox *m, const char *path, int flags)
Open a mailbox and parse it.
Definition: mx.c:254
struct Mailbox * mailbox
Definition: context.h:50
WHERE char * CurrentFolder
Currently selected mailbox.
Definition: globals.h:52
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:141
bool CollapseAll
Config: Collapse all threads when entering a folder.
Definition: index.c:102
int mx_mbox_close(struct Context **pctx, int *index_hint)
Save changes and close mailbox.
Definition: mx.c:568
A folder/dir in the browser.
Definition: browser.h:47
static int ci_first_message(void)
Get index of first new message.
Definition: index.c:278
MailboxType
Supported mailbox formats.
Definition: magic.h:33
#define SORT_THREADS
Sort by email threads.
Definition: sort.h:51
#define MUTT_MAILBOX_CHECK_FORCE
Definition: mailbox.h:160
Error occurred examining mailbox.
Definition: magic.h:35
WHERE bool ReadOnly
Config: Open folders in read-only mode.
Definition: globals.h:247
WHERE bool OptSearchInvalid
(pseudo) used to invalidate the search pat
Definition: options.h:49
void update_index(struct Menu *menu, struct Context *ctx, int check, int oldcount, int index_hint)
Update the index.
Definition: index.c:505
void mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:460
void nntp_expand_path(char *buf, size_t buflen, struct ConnAccount *acct)
Make fully qualified url from newsgroup name.
Definition: newsrc.c:564
char path[PATH_MAX]
Definition: mailbox.h:78
struct Connection * conn
Definition: nntp.h:103
WHERE short Sort
Config: Sort method for the index.
Definition: sort.h:58
Mailbox wasn&#39;t recognised.
Definition: magic.h:36
char * mutt_str_strdup(const char *str)
Copy a string, safely.
Definition: string.c:384
#define mutt_error(...)
Definition: logging.h:88
void * compress_info
compressed mbox module private data
Definition: mailbox.h:118
#define FREE(x)
Definition: memory.h:46
char realpath[PATH_MAX]
used for duplicate detection, context comparison, and the sidebar
Definition: mailbox.h:79
new mail received in mailbox
Definition: mx.h:72
int current
current entry
Definition: menu.h:61
enum MailboxType mx_path_probe(const char *path, struct stat *st)
Find a mailbox that understands a path.
Definition: mx.c:1438
mailbox was reopened
Definition: mx.h:74
#define SORT_MASK
Mask for the sort id.
Definition: sort.h:77
WHERE bool OptNews
(pseudo) used to change reader mode
Definition: options.h:42
struct NntpAccountData * CurrentNewsSrv
Current NNTP news server.
Definition: nntp.c:80
void mutt_context_free(struct Context **ctx)
Free a Context.
Definition: mailbox.c:730

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

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

658 {
659  if (!Context || !menu || (line < 0) || (line >= Context->mailbox->hdrmax))
660  return;
661 
662  struct Email *e = Context->mailbox->hdrs[Context->mailbox->v2r[line]];
663  if (!e)
664  return;
665 
667  struct MuttThread *tmp = NULL;
668 
669  if ((Sort & SORT_MASK) == SORT_THREADS && e->tree)
670  {
671  flag |= MUTT_FORMAT_TREE; /* display the thread tree */
672  if (e->display_subject)
673  flag |= MUTT_FORMAT_FORCESUBJ;
674  else
675  {
676  const int reverse = Sort & SORT_REVERSE;
677  int edgemsgno;
678  if (reverse)
679  {
680  if (menu->top + menu->pagelen > menu->max)
681  edgemsgno = Context->mailbox->v2r[menu->max - 1];
682  else
683  edgemsgno = Context->mailbox->v2r[menu->top + menu->pagelen - 1];
684  }
685  else
686  edgemsgno = Context->mailbox->v2r[menu->top];
687 
688  for (tmp = e->thread->parent; tmp; tmp = tmp->parent)
689  {
690  if (!tmp->message)
691  continue;
692 
693  /* if no ancestor is visible on current screen, provisionally force
694  * subject... */
695  if (reverse ? tmp->message->msgno > edgemsgno : tmp->message->msgno < edgemsgno)
696  {
697  flag |= MUTT_FORMAT_FORCESUBJ;
698  break;
699  }
700  else if (tmp->message->virtual >= 0)
701  break;
702  }
703  if (flag & MUTT_FORMAT_FORCESUBJ)
704  {
705  for (tmp = e->thread->prev; tmp; tmp = tmp->prev)
706  {
707  if (!tmp->message)
708  continue;
709 
710  /* ...but if a previous sibling is available, don't force it */
711  if (reverse ? tmp->message->msgno > edgemsgno : tmp->message->msgno < edgemsgno)
712  break;
713  else if (tmp->message->virtual >= 0)
714  {
715  flag &= ~MUTT_FORMAT_FORCESUBJ;
716  break;
717  }
718  }
719  }
720  }
721  }
722 
723  mutt_make_string_flags(buf, buflen, NONULL(IndexFormat), Context, e, flag);
724 }
The "current" mailbox.
Definition: context.h:36
#define NONULL(x)
Definition: string2.h:39
The envelope/body of an email.
Definition: email.h:35
struct MuttThread * thread
Definition: email.h:96
int virtual
virtual message number
Definition: email.h:89
bool display_subject
used for threading
Definition: email.h:55
struct MuttThread * parent
Definition: thread.h:44
WHERE char * IndexFormat
Config: printf-like format string for the index menu (emails)
Definition: globals.h:112
make sure that all chars are printable
Definition: format_flags.h:35
struct Email ** hdrs
Definition: mailbox.h:93
struct MuttThread * prev
Definition: thread.h:47
struct Mailbox * mailbox
Definition: context.h:50
this is a main index entry
Definition: format_flags.h:39
const char * line
Definition: common.c:35
int top
entry that is the top of the current page
Definition: menu.h:84
#define SORT_THREADS
Sort by email threads.
Definition: sort.h:51
draw the thread tree
Definition: format_flags.h:34
reserve space for arrow_cursor
Definition: format_flags.h:38
int pagelen
number of entries per screen
Definition: menu.h:66
char * tree
character string to print thread tree
Definition: email.h:95
struct Email * message
Definition: thread.h:48
int max
the number of entries in the menu
Definition: menu.h:62
An email conversation.
Definition: thread.h:34
int * v2r
mapping from virtual to real msgno
Definition: mailbox.h:95
WHERE short Sort
Config: Sort method for the index.
Definition: sort.h:58
void mutt_make_string_flags(char *buf, size_t buflen, const char *s, struct Context *ctx, struct Email *e, enum FormatFlag flags)
Create formatted strings using mailbox expandos.
Definition: hdrline.c:1454
#define SORT_REVERSE
Reverse the order of the sort.
Definition: sort.h:78
int hdrmax
number of pointers in hdrs
Definition: mailbox.h:94
FormatFlag
Control the behaviour of mutt_expando_format()
Definition: format_flags.h:31
#define SORT_MASK
Mask for the sort id.
Definition: sort.h:77
int msgno
number displayed to the user
Definition: email.h:88
print the subject even if unchanged
Definition: format_flags.h:33

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

int index_color ( int  line)

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

Definition at line 729 of file index.c.

730 {
731  if (!Context || (line < 0))
732  return 0;
733 
734  struct Email *e = Context->mailbox->hdrs[Context->mailbox->v2r[line]];
735 
736  if (e && e->pair)
737  return e->pair;
738 
740  if (e)
741  return e->pair;
742 
743  return 0;
744 }
The "current" mailbox.
Definition: context.h:36
The envelope/body of an email.
Definition: email.h:35
void mutt_set_header_color(struct Mailbox *m, struct Email *curhdr)
Select a colour for a message.
Definition: index.c:3514
struct Email ** hdrs
Definition: mailbox.h:93
struct Mailbox * mailbox
Definition: context.h:50
const char * line
Definition: common.c:35
int * v2r
mapping from virtual to real msgno
Definition: mailbox.h:95
int pair
color-pair to use when displaying in the index
Definition: email.h:81

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

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

759 {
760  size_t i = 0;
761  size_t offset = 0;
762  bool found = false;
763  size_t chunks = 0;
764  size_t len = 0;
765 
766  struct Syntax
767  {
768  int color;
769  int first;
770  int last;
771  } *syntax = NULL;
772 
773  if (!buf || !stdscr)
774  return;
775 
776  do
777  {
778  struct ColorLine *cl = NULL;
779  found = false;
780 
781  if (!buf[offset])
782  break;
783 
784  /* loop through each "color status regex" */
785  STAILQ_FOREACH(cl, &ColorStatusList, entries)
786  {
787  regmatch_t pmatch[cl->match + 1];
788 
789  if (regexec(&cl->regex, buf + offset, cl->match + 1, pmatch, 0) != 0)
790  continue; /* regex doesn't match the status bar */
791 
792  int first = pmatch[cl->match].rm_so + offset;
793  int last = pmatch[cl->match].rm_eo + offset;
794 
795  if (first == last)
796  continue; /* ignore an empty regex */
797 
798  if (!found)
799  {
800  chunks++;
801  mutt_mem_realloc(&syntax, chunks * sizeof(struct Syntax));
802  }
803 
804  i = chunks - 1;
805  if (!found || (first < syntax[i].first) ||
806  ((first == syntax[i].first) && (last > syntax[i].last)))
807  {
808  syntax[i].color = cl->pair;
809  syntax[i].first = first;
810  syntax[i].last = last;
811  }
812  found = true;
813  }
814 
815  if (syntax)
816  {
817  offset = syntax[i].last;
818  }
819  } while (found);
820 
821  /* Only 'len' bytes will fit into 'cols' screen columns */
822  len = mutt_wstr_trunc(buf, buflen, cols, NULL);
823 
824  offset = 0;
825 
826  if ((chunks > 0) && (syntax[0].first > 0))
827  {
828  /* Text before the first highlight */
829  addnstr(buf, MIN(len, syntax[0].first));
830  attrset(ColorDefs[MT_COLOR_STATUS]);
831  if (len <= syntax[0].first)
832  goto dsl_finish; /* no more room */
833 
834  offset = syntax[0].first;
835  }
836 
837  for (i = 0; i < chunks; i++)
838  {
839  /* Highlighted text */
840  attrset(syntax[i].color);
841  addnstr(buf + offset, MIN(len, syntax[i].last) - offset);
842  if (len <= syntax[i].last)
843  goto dsl_finish; /* no more room */
844 
845  size_t next;
846  if ((i + 1) == chunks)
847  {
848  next = len;
849  }
850  else
851  {
852  next = MIN(len, syntax[i + 1].first);
853  }
854 
855  attrset(ColorDefs[MT_COLOR_STATUS]);
856  offset = syntax[i].last;
857  addnstr(buf + offset, next - offset);
858 
859  offset = next;
860  if (offset >= len)
861  goto dsl_finish; /* no more room */
862  }
863 
864  attrset(ColorDefs[MT_COLOR_STATUS]);
865  if (offset < len)
866  {
867  /* Text after the last highlight */
868  addnstr(buf + offset, len - offset);
869  }
870 
871  int width = mutt_strwidth(buf);
872  if (width < cols)
873  {
874  /* Pad the rest of the line with whitespace */
875  mutt_paddstr(cols - width, "");
876  }
877 dsl_finish:
878  FREE(&syntax);
879 }
int first
Definition: pager.c:165
#define MIN(a, b)
Definition: memory.h:31
int last
Definition: pager.c:166
Highlighting for a line of text.
Definition: pager.c:162
int color
Definition: pager.c:164
void mutt_paddstr(int n, const char *s)
Display a string on screen, padded if necessary.
Definition: curs_lib.c:1083
int match
which substringmap 0 for old behaviour
Definition: mutt_curses.h:181
void mutt_mem_realloc(void *ptr, size_t size)
Resize a block of memory on the heap.
Definition: memory.c:124
int mutt_strwidth(const char *s)
Measure a string&#39;s width in screen cells.
Definition: curs_lib.c:1176
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:1126
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:350
int ColorDefs[MT_COLOR_MAX]
Array of all fixed colours, see enum ColorId.
Definition: color.c:51
LOFF_T offset
where in the stream does this message begin?
Definition: email.h:85
regex_t regex
Definition: mutt_curses.h:180
#define FREE(x)
Definition: memory.h:46
Status bar.
Definition: mutt_curses.h:128
struct ColorLineHead ColorStatusList
List of colours applied to the status bar.
Definition: color.c:60
A regular expression and a color to highlight a line.
Definition: mutt_curses.h:178

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static void index_custom_redraw ( struct Menu menu)
static

Redraw the index - Implements Menu::menu_custom_redraw()

Definition at line 910 of file index.c.

911 {
912  if (menu->redraw & REDRAW_FULL)
913  {
914  menu_redraw_full(menu);
915  mutt_show_error();
916  }
917 
918 #ifdef USE_SIDEBAR
919  if (menu->redraw & REDRAW_SIDEBAR)
920  menu_redraw_sidebar(menu);
921 #endif
922 
923  if (Context && Context->mailbox->hdrs && !(menu->current >= Context->mailbox->vcount))
924  {
925  menu_check_recenter(menu);
926 
927  if (menu->redraw & REDRAW_INDEX)
928  {
929  menu_redraw_index(menu);
930  menu->redraw |= REDRAW_STATUS;
931  }
932  else if (menu->redraw & (REDRAW_MOTION_RESYNCH | REDRAW_MOTION))
933  menu_redraw_motion(menu);
934  else if (menu->redraw & REDRAW_CURRENT)
935  menu_redraw_current(menu);
936  }
937 
938  if (menu->redraw & REDRAW_STATUS)
939  {
940  char buf[LONG_STRING];
941  menu_status_line(buf, sizeof(buf), menu, NONULL(StatusFormat));
944  mutt_draw_statusline(MuttStatusWindow->cols, buf, sizeof(buf));
945  NORMAL_COLOR;
946  menu->redraw &= ~REDRAW_STATUS;
947  if (TsEnabled && TsSupported)
948  {
949  menu_status_line(buf, sizeof(buf), menu, NONULL(TsStatusFormat));
950  mutt_ts_status(buf);
951  menu_status_line(buf, sizeof(buf), menu, NONULL(TsIconFormat));
952  mutt_ts_icon(buf);
953  }
954  }
955 
956  menu->redraw = 0;
957 }
The "current" mailbox.
Definition: context.h:36
#define NONULL(x)
Definition: string2.h:39
int redraw
when to redraw the screen
Definition: menu.h:63
struct MuttWindow * MuttStatusWindow
Status Window.
Definition: mutt_window.c:40
#define NORMAL_COLOR
Definition: mutt_curses.h:235
void menu_status_line(char *buf, size_t buflen, struct Menu *menu, const char *p)
Create the status line.
Definition: status.c:387
#define LONG_STRING
Definition: string2.h:36
struct Email ** hdrs
Definition: mailbox.h:93
int vcount
the number of virtual messages
Definition: mailbox.h:96
struct Mailbox * mailbox
Definition: context.h:50
WHERE char * TsIconFormat
Config: printf-like format string for the terminal&#39;s icon title.
Definition: globals.h:150
WHERE char * TsStatusFormat
Config: printf-like format string for the terminal&#39;s status (window title)
Definition: globals.h:149
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:162
#define SETCOLOR(X)
Definition: mutt_curses.h:220
WHERE char * StatusFormat
Config: printf-like format string for the index&#39;s status line.
Definition: globals.h:148
Status bar.
Definition: mutt_curses.h:128
WHERE bool TsEnabled
Config: Allow NeoMutt to set the terminal status line and icon.
Definition: globals.h:260
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:484
void mutt_ts_status(char *str)
Set the text of the terminal title bar.
Definition: terminal.c:104
int current
current entry
Definition: menu.h:61
void mutt_draw_statusline(int cols, const char *buf, size_t buflen)
Draw a highlighted status bar.
Definition: index.c:758

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

int mutt_index_menu ( void  )

Display a list of emails.

Return values
numHow the menu was finished, e.g. OP_QUIT, OP_EXIT

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

Definition at line 966 of file index.c.

967 {
968  char buf[LONG_STRING], helpstr[LONG_STRING];
969  int flags;
970  int op = OP_NULL;
971  bool done = false; /* controls when to exit the "event" loop */
972  int i = 0, j;
973  bool tag = false; /* has the tag-prefix command been pressed? */
974  int newcount = -1;
975  int oldcount = -1;
976  int rc = -1;
977  char *cp = NULL; /* temporary variable. */
978  int index_hint; /* used to restore cursor position */
979  bool do_mailbox_notify = true;
980  int close = 0; /* did we OP_QUIT or OP_EXIT out of this menu? */
981  int attach_msg = OptAttachMsg;
982 
983  struct Menu *menu = mutt_menu_new(MENU_MAIN);
985  menu->menu_color = index_color;
986  menu->current = ci_first_message();
987  menu->help = mutt_compile_help(helpstr, sizeof(helpstr), MENU_MAIN,
988 #ifdef USE_NNTP
989  (Context && (Context->mailbox->magic == MUTT_NNTP)) ?
990  IndexNewsHelp :
991 #endif
992  IndexHelp);
995 
996  if (!attach_msg)
997  {
998  /* force the mailbox check after we enter the folder */
1000  }
1001 #ifdef USE_INOTIFY
1002  mutt_monitor_add(NULL);
1003 #endif
1004 
1005  if (((Sort & SORT_MASK) == SORT_THREADS) && CollapseAll)
1006  {
1007  collapse_all(menu, 0);
1008  menu->redraw = REDRAW_FULL;
1009  }
1010 
1011  while (true)
1012  {
1013  /* Clear the tag prefix unless we just started it. Don't clear
1014  * the prefix on a timeout (op==-2), but do clear on an abort (op==-1)
1015  */
1016  if (tag && op != OP_TAG_PREFIX && op != OP_TAG_PREFIX_COND && op != -2)
1017  tag = false;
1018 
1019  /* check if we need to resort the index because just about
1020  * any 'op' below could do mutt_enter_command(), either here or
1021  * from any new menu launched, and change $sort/$sort_aux
1022  */
1023  if (OptNeedResort && Context && Context->mailbox->msg_count && menu->current >= 0)
1024  resort_index(menu);
1025 
1026  menu->max = Context ? Context->mailbox->vcount : 0;
1027  oldcount = Context ? Context->mailbox->msg_count : 0;
1028 
1029  if (OptRedrawTree && Context && Context->mailbox->msg_count && (Sort & SORT_MASK) == SORT_THREADS)
1030  {
1032  menu->redraw |= REDRAW_STATUS;
1033  OptRedrawTree = false;
1034  }
1035 
1036  if (Context)
1037  Context->menu = menu;
1038 
1039  if (Context && !attach_msg)
1040  {
1041  int check;
1042  /* check for new mail in the mailbox. If nonzero, then something has
1043  * changed about the file (either we got new mail or the file was
1044  * modified underneath us.)
1045  */
1046 
1047  index_hint = (Context->mailbox->vcount && menu->current >= 0 &&
1048  menu->current < Context->mailbox->vcount) ?
1049  CURHDR->index :
1050  0;
1051 
1052  check = mx_mbox_check(Context, &index_hint);
1053  if (check < 0)
1054  {
1055  if (!Context->mailbox || Context->mailbox->path[0] == '\0')
1056  {
1057  /* fatal error occurred */
1059  menu->redraw = REDRAW_FULL;
1060  }
1061 
1062  OptSearchInvalid = true;
1063  }
1064  else if (check == MUTT_NEW_MAIL || check == MUTT_REOPENED || check == MUTT_FLAGS)
1065  {
1066  /* notify the user of new mail */
1067  if (check == MUTT_REOPENED)
1068  {
1069  mutt_error(
1070  _("Mailbox was externally modified. Flags may be wrong."));
1071  }
1072  else if (check == MUTT_NEW_MAIL)
1073  {
1074  for (i = oldcount; i < Context->mailbox->msg_count; i++)
1075  {
1076  if (!Context->mailbox->hdrs[i]->read)
1077  {
1078  mutt_message(_("New mail in this mailbox"));
1079  if (BeepNew)
1080  beep();
1081  if (NewMailCommand)
1082  {
1083  char cmd[LONG_STRING];
1084  menu_status_line(cmd, sizeof(cmd), menu, NONULL(NewMailCommand));
1085  if (mutt_system(cmd) != 0)
1086  mutt_error(_("Error running \"%s\""), cmd);
1087  }
1088  break;
1089  }
1090  }
1091  }
1092  else if (check == MUTT_FLAGS)
1093  mutt_message(_("Mailbox was externally modified"));
1094 
1095  /* avoid the message being overwritten by mailbox */
1096  do_mailbox_notify = false;
1097 
1098  bool q = Context->mailbox->quiet;
1099  Context->mailbox->quiet = true;
1100  update_index(menu, Context, check, oldcount, index_hint);
1101  Context->mailbox->quiet = q;
1102 
1103  menu->redraw = REDRAW_FULL;
1104  menu->max = Context->mailbox->vcount;
1105 
1106  OptSearchInvalid = true;
1107  }
1108  }
1109 
1110  if (!attach_msg)
1111  {
1112  /* check for new mail in the incoming folders */
1113  oldcount = newcount;
1114  newcount = mutt_mailbox_check(0);
1115  if (newcount != oldcount)
1116  menu->redraw |= REDRAW_STATUS;
1117  if (do_mailbox_notify)
1118  {
1119  if (mutt_mailbox_notify())
1120  {
1121  menu->redraw |= REDRAW_STATUS;
1122  if (BeepNew)
1123  beep();
1124  if (NewMailCommand)
1125  {
1126  char cmd[LONG_STRING];
1127  menu_status_line(cmd, sizeof(cmd), menu, NONULL(NewMailCommand));
1128  if (mutt_system(cmd) != 0)
1129  mutt_error(_("Error running \"%s\""), cmd);
1130  }
1131  }
1132  }
1133  else
1134  do_mailbox_notify = true;
1135  }
1136 
1137  if (op >= 0)
1138  mutt_curs_set(0);
1139 
1140  if (menu->menu == MENU_MAIN)
1141  {
1142  index_custom_redraw(menu);
1143 
1144  /* give visual indication that the next command is a tag- command */
1145  if (tag)
1146  {
1147  mutt_window_mvaddstr(MuttMessageWindow, 0, 0, "tag-");
1149  }
1150 
1151  if (menu->current < menu->max)
1152  menu->oldcurrent = menu->current;
1153  else
1154  menu->oldcurrent = -1;
1155 
1156  if (ArrowCursor)
1157  mutt_window_move(MuttIndexWindow, menu->current - menu->top + menu->offset, 2);
1158  else if (BrailleFriendly)
1159  mutt_window_move(MuttIndexWindow, menu->current - menu->top + menu->offset, 0);
1160  else
1161  {
1162  mutt_window_move(MuttIndexWindow, menu->current - menu->top + menu->offset,
1163  MuttIndexWindow->cols - 1);
1164  }
1165  mutt_refresh();
1166 
1167  if (SigWinch)
1168  {
1169  mutt_flushinp();
1171  SigWinch = 0;
1172  menu->top = 0; /* so we scroll the right amount */
1173  /* force a real complete redraw. clrtobot() doesn't seem to be able
1174  * to handle every case without this.
1175  */
1176  clearok(stdscr, true);
1177  continue;
1178  }
1179 
1180  op = km_dokey(MENU_MAIN);
1181 
1182  mutt_debug(4, "[%d]: Got op %d\n", __LINE__, op);
1183 
1184  /* either user abort or timeout */
1185  if (op < 0)
1186  {
1188  if (tag)
1190  continue;
1191  }
1192 
1193  mutt_curs_set(1);
1194 
1195  /* special handling for the tag-prefix function */
1196  if (op == OP_TAG_PREFIX || op == OP_TAG_PREFIX_COND)
1197  {
1198  /* A second tag-prefix command aborts */
1199  if (tag)
1200  {
1201  tag = false;
1203  continue;
1204  }
1205 
1206  if (!Context || !Context->mailbox)
1207  {
1208  mutt_error(_("No mailbox is open"));
1209  continue;
1210  }
1211 
1212  if (!Context->mailbox->msg_tagged)
1213  {
1214  if (op == OP_TAG_PREFIX)
1215  mutt_error(_("No tagged messages"));
1216  else if (op == OP_TAG_PREFIX_COND)
1217  {
1219  mutt_message(_("Nothing to do"));
1220  }
1221  continue;
1222  }
1223 
1224  /* get the real command */
1225  tag = true;
1226  continue;
1227  }
1228  else if (AutoTag && Context && Context->mailbox && Context->mailbox->msg_tagged)
1229  tag = true;
1230 
1231  mutt_clear_error();
1232  }
1233  else
1234  {
1235  if (menu->current < menu->max)
1236  menu->oldcurrent = menu->current;
1237  else
1238  menu->oldcurrent = -1;
1239 
1240  mutt_curs_set(1); /* fallback from the pager */
1241  }
1242 
1243 #ifdef USE_NNTP
1244  OptNews = false; /* for any case */
1245 #endif
1246 
1247 #ifdef USE_NOTMUCH
1248  if (Context)
1250 #endif
1251 
1252  switch (op)
1253  {
1254  /* ----------------------------------------------------------------------
1255  * movement commands
1256  */
1257 
1258  case OP_BOTTOM_PAGE:
1259  menu_bottom_page(menu);
1260  break;
1261  case OP_CURRENT_BOTTOM:
1262  menu_current_bottom(menu);
1263  break;
1264  case OP_CURRENT_MIDDLE:
1265  menu_current_middle(menu);
1266  break;
1267  case OP_CURRENT_TOP:
1268  menu_current_top(menu);
1269  break;
1270  case OP_FIRST_ENTRY:
1271  menu_first_entry(menu);
1272  break;
1273  case OP_HALF_DOWN:
1274  menu_half_down(menu);
1275  break;
1276  case OP_HALF_UP:
1277  menu_half_up(menu);
1278  break;
1279  case OP_LAST_ENTRY:
1280  menu_last_entry(menu);
1281  break;
1282  case OP_MIDDLE_PAGE:
1283  menu_middle_page(menu);
1284  break;
1285  case OP_NEXT_LINE:
1286  menu_next_line(menu);
1287  break;
1288  case OP_NEXT_PAGE:
1289  menu_next_page(menu);
1290  break;
1291  case OP_PREV_LINE:
1292  menu_prev_line(menu);
1293  break;
1294  case OP_PREV_PAGE:
1295  menu_prev_page(menu);
1296  break;
1297  case OP_TOP_PAGE:
1298  menu_top_page(menu);
1299  break;
1300 
1301 #ifdef USE_NNTP
1302  case OP_GET_PARENT:
1304  CHECK_VISIBLE;
1305  /* fallthrough */
1306 
1307  case OP_GET_MESSAGE:
1310  CHECK_ATTACH;
1311  if (Context->mailbox->magic == MUTT_NNTP)
1312  {
1313  struct Email *e = NULL;
1314 
1315  if (op == OP_GET_MESSAGE)
1316  {
1317  buf[0] = 0;
1318  if (mutt_get_field(_("Enter Message-Id: "), buf, sizeof(buf), 0) != 0 ||
1319  !buf[0])
1320  {
1321  break;
1322  }
1323  }
1324  else
1325  {
1326  if (STAILQ_EMPTY(&CURHDR->env->references))
1327  {
1328  mutt_error(_("Article has no parent reference"));
1329  break;
1330  }
1331  mutt_str_strfcpy(buf, STAILQ_FIRST(&CURHDR->env->references)->data,
1332  sizeof(buf));
1333  }
1334  if (!Context->mailbox->id_hash)
1336  e = mutt_hash_find(Context->mailbox->id_hash, buf);
1337  if (e)
1338  {
1339  if (e->virtual != -1)
1340  {
1341  menu->current = e->virtual;
1342  menu->redraw = REDRAW_MOTION_RESYNCH;
1343  }
1344  else if (e->collapsed)
1345  {
1348  menu->current = e->virtual;
1349  menu->redraw = REDRAW_MOTION_RESYNCH;
1350  }
1351  else
1352  mutt_error(_("Message is not visible in limited view"));
1353  }
1354  else
1355  {
1356  int rc2;
1357 
1358  mutt_message(_("Fetching %s from server..."), buf);
1359  rc2 = nntp_check_msgid(Context, buf);
1360  if (rc2 == 0)
1361  {
1363  mutt_sort_headers(Context, false);
1364  menu->current = e->virtual;
1365  menu->redraw = REDRAW_FULL;
1366  }
1367  else if (rc2 > 0)
1368  mutt_error(_("Article %s not found on the server"), buf);
1369  }
1370  }
1371  break;
1372 
1373  case OP_GET_CHILDREN:
1374  case OP_RECONSTRUCT_THREAD:
1376  CHECK_VISIBLE;
1378  CHECK_ATTACH;
1379  if (Context->mailbox->magic == MUTT_NNTP)
1380  {
1381  int oldmsgcount = Context->mailbox->msg_count;
1382  int oldindex = CURHDR->index;
1383  int rc2 = 0;
1384 
1385  if (!CURHDR->env->message_id)
1386  {
1387  mutt_error(_("No Message-Id. Unable to perform operation."));
1388  break;
1389  }
1390 
1391  mutt_message(_("Fetching message headers..."));
1392  if (!Context->mailbox->id_hash)
1394  mutt_str_strfcpy(buf, CURHDR->env->message_id, sizeof(buf));
1395 
1396  /* trying to find msgid of the root message */
1397  if (op == OP_RECONSTRUCT_THREAD)
1398  {
1399  struct ListNode *ref = NULL;
1400  STAILQ_FOREACH(ref, &CURHDR->env->references, entries)
1401  {
1402  if (!mutt_hash_find(Context->mailbox->id_hash, ref->data))
1403  {
1404  rc2 = nntp_check_msgid(Context, ref->data);
1405  if (rc2 < 0)
1406  break;
1407  }
1408 
1409  /* the last msgid in References is the root message */
1410  if (!STAILQ_NEXT(ref, entries))
1411  mutt_str_strfcpy(buf, ref->data, sizeof(buf));
1412  }
1413  }
1414 
1415  /* fetching all child messages */
1416  if (rc2 >= 0)
1417  rc2 = nntp_check_children(Context, buf);
1418 
1419  /* at least one message has been loaded */
1420  if (Context->mailbox->msg_count > oldmsgcount)
1421  {
1422  struct Email *oldcur = CURHDR;
1423  struct Email *e = NULL;
1424  bool quiet = Context->mailbox->quiet;
1425 
1426  if (rc2 < 0)
1427  Context->mailbox->quiet = true;
1428  mutt_sort_headers(Context, (op == OP_RECONSTRUCT_THREAD));
1429  Context->mailbox->quiet = quiet;
1430 
1431  /* Similar to OP_MAIN_ENTIRE_THREAD, keep displaying the old message, but
1432  update the index */
1433  if (menu->menu == MENU_PAGER)
1434  {
1435  menu->current = oldcur->virtual;
1436  menu->redraw = REDRAW_STATUS | REDRAW_INDEX;
1437  op = OP_DISPLAY_MESSAGE;
1438  continue;
1439  }
1440 
1441  /* if the root message was retrieved, move to it */
1442  e = mutt_hash_find(Context->mailbox->id_hash, buf);
1443  if (e)
1444  menu->current = e->virtual;
1445 
1446  /* try to restore old position */
1447  else
1448  {
1449  for (int k = 0; k < Context->mailbox->msg_count; k++)
1450  {
1451  if (Context->mailbox->hdrs[k]->index == oldindex)
1452  {
1453  menu->current = Context->mailbox->hdrs[k]->virtual;
1454  /* as an added courtesy, recenter the menu
1455  * with the current entry at the middle of the screen */
1456  menu_check_recenter(menu);
1457  menu_current_middle(menu);
1458  }
1459  }
1460  }
1461  menu->redraw = REDRAW_FULL;
1462  }
1463  else if (rc2 >= 0)
1464  {
1465  mutt_error(_("No deleted messages found in the thread"));
1466  /* Similar to OP_MAIN_ENTIRE_THREAD, keep displaying the old message, but
1467  update the index */
1468  if (menu->menu == MENU_PAGER)
1469  {
1470  op = OP_DISPLAY_MESSAGE;
1471  continue;
1472  }
1473  }
1474  }
1475  break;
1476 #endif
1477 
1478  case OP_JUMP:
1479 
1481  CHECK_VISIBLE;
1482  if (isdigit(LastKey))
1484  buf[0] = 0;
1485  if ((mutt_get_field(_("Jump to message: "), buf, sizeof(buf), 0) != 0) ||
1486  (buf[0] == '\0'))
1487  {
1488  mutt_error(_("Nothing to do"));
1489  }
1490  else if (mutt_str_atoi(buf, &i) < 0)
1491  mutt_error(_("Argument must be a message number"));
1492  else if ((i < 1) || (i > Context->mailbox->msg_count))
1493  mutt_error(_("Invalid message number"));
1494  else if (!message_is_visible(Context, i - 1))
1495  mutt_error(_("That message is not visible"));
1496  else
1497  {
1498  struct Email *e = Context->mailbox->hdrs[i - 1];
1499 
1500  if (mutt_messages_in_thread(Context->mailbox, e, 1) > 1)
1501  {
1504  }
1505  menu->current = e->virtual;
1506  }
1507 
1508  if (menu->menu == MENU_PAGER)
1509  {
1510  op = OP_DISPLAY_MESSAGE;
1511  continue;
1512  }
1513  else
1514  menu->redraw = REDRAW_FULL;
1515 
1516  break;
1517 
1518  /* --------------------------------------------------------------------
1519  * `index' specific commands
1520  */
1521 
1522  case OP_MAIN_DELETE_PATTERN:
1523 
1525  CHECK_VISIBLE;
1527  /* L10N: CHECK_ACL */
1528  /* L10N: Due to the implementation details we do not know whether we
1529  delete zero, 1, 12, ... messages. So in English we use
1530  "messages". Your language might have other means to express this.
1531  */
1532  CHECK_ACL(MUTT_ACL_DELETE, _("Cannot delete messages"));
1533 
1534  CHECK_ATTACH;
1535  mutt_pattern_func(MUTT_DELETE, _("Delete messages matching: "));
1536  menu->redraw |= REDRAW_INDEX | REDRAW_STATUS;
1537  break;
1538 
1539 #ifdef USE_POP
1540  case OP_MAIN_FETCH_MAIL:
1541 
1542  CHECK_ATTACH;
1543  pop_fetch_mail();
1544  menu->redraw = REDRAW_FULL;
1545  break;
1546 #endif /* USE_POP */
1547 
1548  case OP_SHOW_LOG_MESSAGES:
1549  {
1550  char tempfile[PATH_MAX];
1551  mutt_mktemp(tempfile, sizeof(tempfile));
1552 
1553  FILE *fp = mutt_file_fopen(tempfile, "a+");
1554  if (!fp)
1555  {
1556  mutt_perror("fopen");
1557  break;
1558  }
1559 
1560  log_queue_save(fp);
1561  mutt_file_fclose(&fp);
1562 
1563  mutt_do_pager("messages", tempfile, MUTT_PAGER_LOGS, NULL);
1564  break;
1565  }
1566 
1567  case OP_HELP:
1568 
1570  menu->redraw = REDRAW_FULL;
1571  break;
1572 
1573  case OP_MAIN_SHOW_LIMIT:
1575  if (!Context->pattern)
1576  mutt_message(_("No limit pattern is in effect"));
1577  else
1578  {
1579  char buf2[STRING];
1580  /* L10N: ask for a limit to apply */
1581  snprintf(buf2, sizeof(buf2), _("Limit: %s"), Context->pattern);
1582  mutt_message("%s", buf2);
1583  }
1584  break;
1585 
1586  case OP_LIMIT_CURRENT_THREAD:
1587  case OP_MAIN_LIMIT:
1588  case OP_TOGGLE_READ:
1589 
1591  menu->oldcurrent = (Context->mailbox->vcount && menu->current >= 0 &&
1592  menu->current < Context->mailbox->vcount) ?
1593  CURHDR->index :
1594  -1;
1595  if (op == OP_TOGGLE_READ)
1596  {
1597  char buf2[LONG_STRING];
1598 
1599  if (!Context->pattern || (strncmp(Context->pattern, "!~R!~D~s", 8) != 0))
1600  {
1601  snprintf(buf2, sizeof(buf2), "!~R!~D~s%s",
1602  Context->pattern ? Context->pattern : ".*");
1603  }
1604  else
1605  {
1606  mutt_str_strfcpy(buf2, Context->pattern + 8, sizeof(buf2));
1607  if (!*buf2 || (strncmp(buf2, ".*", 2) == 0))
1608  snprintf(buf2, sizeof(buf2), "~A");
1609  }
1610  FREE(&Context->pattern);
1611  Context->pattern = mutt_str_strdup(buf2);
1613  }
1614 
1615  if (((op == OP_LIMIT_CURRENT_THREAD) && mutt_limit_current_thread(CURHDR)) ||
1616  (op == OP_TOGGLE_READ) ||
1617  ((op == OP_MAIN_LIMIT) &&
1619  _("Limit to messages matching: ")) == 0)))
1620  {
1621  if (menu->oldcurrent >= 0)
1622  {
1623  /* try to find what used to be the current message */
1624  menu->current = -1;
1625  for (i = 0; i < Context->mailbox->vcount; i++)
1626  {
1627  if (Context->mailbox->hdrs[Context->mailbox->v2r[i]]->index == menu->oldcurrent)
1628  {
1629  menu->current = i;
1630  break;
1631  }
1632  }
1633  if (menu->current < 0)
1634  menu->current = 0;
1635  }
1636  else
1637  menu->current = 0;
1638  if (Context->mailbox->msg_count && (Sort & SORT_MASK) == SORT_THREADS)
1640  menu->redraw = REDRAW_FULL;
1641  }
1642  if (Context->pattern)
1643  mutt_message(_("To view all messages, limit to \"all\""));
1644  break;
1645 
1646  case OP_QUIT:
1647 
1648  close = op;
1649  if (attach_msg)
1650  {
1651  done = true;
1652  break;
1653  }
1654 
1655  if (query_quadoption(Quit, _("Quit NeoMutt?")) == MUTT_YES)
1656  {
1657  int check;
1658 
1659  oldcount = Context ? Context->mailbox->msg_count : 0;
1660 
1662 
1663  if (!Context || (check = mx_mbox_close(&Context, &index_hint)) == 0)
1664  done = true;
1665  else
1666  {
1667  if (check == MUTT_NEW_MAIL || check == MUTT_REOPENED)
1668  update_index(menu, Context, check, oldcount, index_hint);
1669 
1670  menu->redraw = REDRAW_FULL; /* new mail arrived? */
1671  OptSearchInvalid = true;
1672  }
1673  }
1674  break;
1675 
1676  case OP_REDRAW:
1677 
1678  clearok(stdscr, true);
1679  menu->redraw = REDRAW_FULL;
1680  break;
1681 
1682  case OP_SEARCH:
1683  case OP_SEARCH_REVERSE:
1684  case OP_SEARCH_NEXT:
1685  case OP_SEARCH_OPPOSITE:
1686 
1688  CHECK_VISIBLE;
1689  menu->current = mutt_search_command(menu->current, op);
1690  if (menu->current == -1)
1691  menu->current = menu->oldcurrent;
1692  else
1693  menu->redraw = REDRAW_MOTION;
1694  break;
1695 
1696  case OP_SORT:
1697  case OP_SORT_REVERSE:
1698 
1699  if (mutt_select_sort((op == OP_SORT_REVERSE)) == 0)
1700  {
1701  if (Context && Context->mailbox->msg_count)
1702  {
1703  resort_index(menu);
1704  OptSearchInvalid = true;
1705  }
1706  if (menu->menu == MENU_PAGER)
1707  {
1708  op = OP_DISPLAY_MESSAGE;
1709  continue;
1710  }
1711  menu->redraw |= REDRAW_STATUS;
1712  }
1713  break;
1714 
1715  case OP_TAG:
1716 
1718  CHECK_VISIBLE;
1719  if (tag && !AutoTag)
1720  {
1721  for (j = 0; j < Context->mailbox->msg_count; j++)
1722  if (message_is_visible(Context, j))
1724  menu->redraw |= REDRAW_STATUS | REDRAW_INDEX;
1725  }
1726  else
1727  {
1729 
1730  Context->last_tag = CURHDR->tagged ?
1731  CURHDR :
1732  ((Context->last_tag == CURHDR && !CURHDR->tagged) ?
1733  NULL :
1734  Context->last_tag);
1735 
1736  menu->redraw |= REDRAW_STATUS;
1737  if (Resolve && menu->current < Context->mailbox->vcount - 1)
1738  {
1739  menu->current++;
1740  menu->redraw |= REDRAW_MOTION_RESYNCH;
1741  }
1742  else
1743  menu->redraw |= REDRAW_CURRENT;
1744  }
1745  break;
1746 
1747  case OP_MAIN_TAG_PATTERN:
1748 
1750  CHECK_VISIBLE;
1751  mutt_pattern_func(MUTT_TAG, _("Tag messages matching: "));
1752  menu->redraw |= REDRAW_INDEX | REDRAW_STATUS;
1753  break;
1754 
1755  case OP_MAIN_UNDELETE_PATTERN:
1756 
1758  CHECK_VISIBLE;
1760  /* L10N: CHECK_ACL */
1761  /* L10N: Due to the implementation details we do not know whether we
1762  undelete zero, 1, 12, ... messages. So in English we use
1763  "messages". Your language might have other means to express this.
1764  */
1765  CHECK_ACL(MUTT_ACL_DELETE, _("Cannot undelete messages"));
1766 
1768  _("Undelete messages matching: ")) == 0)
1769  {
1770  menu->redraw |= REDRAW_INDEX | REDRAW_STATUS;
1771  }
1772  break;
1773 
1774  case OP_MAIN_UNTAG_PATTERN:
1775 
1777  CHECK_VISIBLE;
1778  if (mutt_pattern_func(MUTT_UNTAG, _("Untag messages matching: ")) == 0)
1779  menu->redraw |= REDRAW_INDEX | REDRAW_STATUS;
1780  break;
1781 
1782  case OP_COMPOSE_TO_SENDER:
1783  CHECK_ATTACH;
1785  CHECK_VISIBLE;
1786  ci_send_message(SEND_TO_SENDER, NULL, NULL, Context, tag ? NULL : CURHDR);
1787  menu->redraw = REDRAW_FULL;
1788  break;
1789 
1790  /* --------------------------------------------------------------------
1791  * The following operations can be performed inside of the pager.
1792  */
1793 
1794 #ifdef USE_IMAP
1795  case OP_MAIN_IMAP_FETCH:
1796  if (Context && Context->mailbox->magic == MUTT_IMAP)
1798  break;
1799 
1800  case OP_MAIN_IMAP_LOGOUT_ALL:
1801  if (Context && Context->mailbox->magic == MUTT_IMAP)
1802  {
1803  int check = mx_mbox_close(&Context, &index_hint);
1804  if (check != 0)
1805  {
1806  if ((check == MUTT_NEW_MAIL) || (check == MUTT_REOPENED))
1807  update_index(menu, Context, check, oldcount, index_hint);
1808  OptSearchInvalid = true;
1809  menu->redraw = REDRAW_FULL;
1810  break;
1811  }
1812  }
1813  imap_logout_all();
1814  mutt_message(_("Logged out of IMAP servers"));
1815  OptSearchInvalid = true;
1816  menu->redraw = REDRAW_FULL;
1817  break;
1818 #endif
1819 
1820  case OP_MAIN_SYNC_FOLDER:
1821 
1822  if (Context && !Context->mailbox->msg_count)
1823  break;
1824 
1827  {
1828  int ovc = Context->mailbox->vcount;
1829  int oc = Context->mailbox->msg_count;
1830  int check;
1831  struct Email *newhdr = NULL;
1832 
1833  /* don't attempt to move the cursor if there are no visible messages in the current limit */
1834  if (menu->current < Context->mailbox->vcount)
1835  {
1836  /* threads may be reordered, so figure out what header the cursor
1837  * should be on. #3092 */
1838  int newidx = menu->current;
1839  if (CURHDR->deleted)
1840  newidx = ci_next_undeleted(menu->current);
1841  if (newidx < 0)
1842  newidx = ci_previous_undeleted(menu->current);
1843  if (newidx >= 0)
1844  newhdr = Context->mailbox->hdrs[Context->mailbox->v2r[newidx]];
1845  }
1846 
1847  check = mx_mbox_sync(Context, &index_hint);
1848  if (check == 0)
1849  {
1850  if (newhdr && Context->mailbox->vcount != ovc)
1851  {
1852  for (j = 0; j < Context->mailbox->vcount; j++)
1853  {
1854  if (Context->mailbox->hdrs[Context->mailbox->v2r[j]] == newhdr)
1855  {
1856  menu->current = j;
1857  break;
1858  }
1859  }
1860  }
1861  OptSearchInvalid = true;
1862  }
1863  else if (check == MUTT_NEW_MAIL || check == MUTT_REOPENED)
1864  update_index(menu, Context, check, oc, index_hint);
1865 
1866  /* do a sanity check even if mx_mbox_sync failed. */
1867 
1868  if ((menu->current < 0) || (Context && Context->mailbox &&
1869  (menu->current >= Context->mailbox->vcount)))
1870  {
1871  menu->current = ci_first_message();
1872  }
1873  }
1874 
1875  /* check for a fatal error, or all messages deleted */
1876  if (Context->mailbox->path[0] == '\0')
1878 
1879  /* if we were in the pager, redisplay the message */
1880  if (menu->menu == MENU_PAGER)
1881  {
1882  op = OP_DISPLAY_MESSAGE;
1883  continue;
1884  }
1885  else
1886  menu->redraw = REDRAW_FULL;
1887  break;
1888 
1889  case OP_MAIN_QUASI_DELETE:
1891  CHECK_VISIBLE;
1892  if (tag)
1893  {
1894  for (j = 0; j < Context->mailbox->msg_count; j++)
1895  {
1896  if (message_is_tagged(Context, j))
1897  {
1898  Context->mailbox->hdrs[j]->quasi_deleted = true;
1899  Context->mailbox->changed = true;
1900  }
1901  }
1902  }
1903  else
1904  {
1905  CURHDR->quasi_deleted = true;
1906  Context->mailbox->changed = true;
1907  }
1908  break;
1909 
1910 #ifdef USE_NOTMUCH
1911  case OP_MAIN_ENTIRE_THREAD:
1912  {
1913  if (!Context || (Context->mailbox->magic != MUTT_NOTMUCH))
1914  {
1915  if (!CURHDR || !CURHDR->env || !CURHDR->env->message_id)
1916  {
1917  mutt_message(_("No virtual folder and no Message-Id, aborting"));
1918  break;
1919  } // no virtual folder, but we have message-id, reconstruct thread on-the-fly
1920  strncpy(buf, "id:", sizeof(buf));
1921  int msg_id_offset = 0;
1922  if ((CURHDR->env->message_id)[0] == '<')
1923  msg_id_offset = 1;
1924  mutt_str_strcat(buf, sizeof(buf), (CURHDR->env->message_id) + msg_id_offset);
1925  if (buf[strlen(buf) - 1] == '>')
1926  buf[strlen(buf) - 1] = '\0';
1927  if (!nm_uri_from_query(Context->mailbox, buf, sizeof(buf)))
1928  {
1929  mutt_message(_("Failed to create query, aborting"));
1930  break;
1931  }
1932  else
1933  main_change_folder(menu, op, NULL, buf, sizeof(buf), &oldcount, &index_hint);
1934  }
1936  CHECK_VISIBLE;
1937  int oc = Context->mailbox->msg_count;
1939  {
1940  mutt_message(_("Failed to read thread, aborting"));
1941  break;
1942  }
1943  if (oc < Context->mailbox->msg_count)
1944  {
1945  struct Email *oldcur = CURHDR;
1946 
1947  if ((Sort & SORT_MASK) == SORT_THREADS)
1948  mutt_sort_headers(Context, false);
1949  menu->current = oldcur->virtual;
1950  menu->redraw = REDRAW_STATUS | REDRAW_INDEX;
1951 
1952  if (oldcur->collapsed || Context->collapsed)
1953  {
1956  }
1957  }
1958  if (menu->menu == MENU_PAGER)
1959  {
1960  op = OP_DISPLAY_MESSAGE;
1961  continue;
1962  }
1963  break;
1964  }
1965 
1966 #endif
1967  case OP_MAIN_MODIFY_TAGS:
1968  case OP_MAIN_MODIFY_TAGS_THEN_HIDE:
1969  {
1971  {
1972  mutt_message(_("Folder doesn't support tagging, aborting"));
1973  break;
1974  }
1976  CHECK_VISIBLE;
1978  char *tags = NULL;
1979  if (!tag)
1980  tags = driver_tags_get_with_hidden(&CURHDR->tags);
1981  rc = mx_tags_edit(Context->mailbox, tags, buf, sizeof(buf));
1982  FREE(&tags);
1983  if (rc < 0)
1984  break;
1985  else if (rc == 0)
1986  {
1987  mutt_message(_("No tag specified, aborting"));
1988  break;
1989  }
1990 
1991  if (tag)
1992  {
1993  struct Progress progress;
1994  int px;
1995 
1996  if (!Context->mailbox->quiet)
1997  {
1998  char msgbuf[STRING];
1999  snprintf(msgbuf, sizeof(msgbuf), _("Update tags..."));
2000  mutt_progress_init(&progress, msgbuf, MUTT_PROGRESS_MSG, 1,
2002  }
2003 
2004 #ifdef USE_NOTMUCH
2005  if (Context->mailbox->magic == MUTT_NOTMUCH)
2007 #endif
2008  for (px = 0, j = 0; j < Context->mailbox->msg_count; j++)
2009  {
2010  if (!message_is_tagged(Context, j))
2011  continue;
2012 
2013  if (!Context->mailbox->quiet)
2014  mutt_progress_update(&progress, ++px, -1);
2016  if (op == OP_MAIN_MODIFY_TAGS_THEN_HIDE)
2017  {
2018  bool still_queried = false;
2019 #ifdef USE_NOTMUCH
2020  if (Context->mailbox->magic == MUTT_NOTMUCH)
2021  still_queried = nm_message_is_still_queried(
2023 #endif
2024  Context->mailbox->hdrs[j]->quasi_deleted = !still_queried;
2025  Context->mailbox->changed = true;
2026  }
2027  }
2028 #ifdef USE_NOTMUCH
2029  if (Context->mailbox->magic == MUTT_NOTMUCH)
2031 #endif
2032  menu->redraw = REDRAW_STATUS | REDRAW_INDEX;
2033  }
2034  else
2035  {
2036  if (mx_tags_commit(Context->mailbox, CURHDR, buf))
2037  {
2038  mutt_message(_("Failed to modify tags, aborting"));
2039  break;
2040  }
2041  if (op == OP_MAIN_MODIFY_TAGS_THEN_HIDE)
2042  {
2043  bool still_queried = false;
2044 #ifdef USE_NOTMUCH
2045  if (Context->mailbox->magic == MUTT_NOTMUCH)
2047 #endif
2048  CURHDR->quasi_deleted = !still_queried;
2049  Context->mailbox->changed = true;
2050  }
2051  if (menu->menu == MENU_PAGER)
2052  {
2053  op = OP_DISPLAY_MESSAGE;
2054  continue;
2055  }
2056  if (Resolve)
2057  {
2058  menu->current = ci_next_undeleted(menu->current);
2059  if (menu->current == -1)
2060  {
2061  menu->current = menu->oldcurrent;
2062  menu->redraw = REDRAW_CURRENT;
2063  }
2064  else
2065  menu->redraw = REDRAW_MOTION_RESYNCH;
2066  }
2067  else
2068  menu->redraw = REDRAW_CURRENT;
2069  }
2070  menu->redraw |= REDRAW_STATUS;
2071  break;
2072  }
2073 
2074  case OP_CHECK_STATS:
2075  mutt_check_stats();
2076  break;
2077 
2078 #ifdef USE_NOTMUCH
2079  case OP_MAIN_VFOLDER_FROM_QUERY:
2080  buf[0] = '\0';
2081  if (mutt_get_field("Query: ", buf, sizeof(buf), MUTT_NM_QUERY) != 0 || !buf[0])
2082  {
2083  mutt_message(_("No query, aborting"));
2084  break;
2085  }
2086  if (!nm_uri_from_query(NULL, buf, sizeof(buf)))
2087  mutt_message(_("Failed to create query, aborting"));
2088  else
2089  main_change_folder(menu, op, NULL, buf, sizeof(buf), &oldcount, &index_hint);
2090  break;
2091 
2092  case OP_MAIN_WINDOWED_VFOLDER_BACKWARD:
2094  mutt_debug(2, "OP_MAIN_WINDOWED_VFOLDER_BACKWARD\n");
2095  if (NmQueryWindowDuration <= 0)
2096  {
2097  mutt_message(_("Windowed queries disabled"));
2098  break;
2099  }
2101  {
2102  mutt_message(_("No notmuch vfolder currently loaded"));
2103  break;
2104  }
2106  mutt_str_strfcpy(buf, NmQueryWindowCurrentSearch, sizeof(buf));
2107  if (!nm_uri_from_query(Context->mailbox, buf, sizeof(buf)))
2108  mutt_message(_("Failed to create query, aborting"));
2109  else
2110  main_change_folder(menu, op, NULL, buf, sizeof(buf), &oldcount, &index_hint);
2111  break;
2112 
2113  case OP_MAIN_WINDOWED_VFOLDER_FORWARD:
2115  if (NmQueryWindowDuration <= 0)
2116  {
2117  mutt_message(_("Windowed queries disabled"));
2118  break;
2119  }
2121  {
2122  mutt_message(_("No notmuch vfolder currently loaded"));
2123  break;
2124  }
2126  mutt_str_strfcpy(buf, NmQueryWindowCurrentSearch, sizeof(buf));
2127  if (!nm_uri_from_query(Context->mailbox, buf, sizeof(buf)))
2128  mutt_message(_("Failed to create query, aborting"));
2129  else
2130  {
2131  mutt_debug(2, "nm: + windowed query (%s)\n", buf);
2132  main_change_folder(menu, op, NULL, buf, sizeof(buf), &oldcount, &index_hint);
2133  }
2134  break;
2135 
2136  case OP_MAIN_CHANGE_VFOLDER:
2137 #endif
2138 
2139 #ifdef USE_SIDEBAR
2140  case OP_SIDEBAR_OPEN:
2141 #endif
2142  case OP_MAIN_CHANGE_FOLDER:
2143  case OP_MAIN_NEXT_UNREAD_MAILBOX:
2144  case OP_MAIN_CHANGE_FOLDER_READONLY:
2145 #ifdef USE_NNTP
2146  case OP_MAIN_CHANGE_GROUP:
2147  case OP_MAIN_CHANGE_GROUP_READONLY:
2148  {
2149  struct Mailbox *m = NULL;
2150  OptNews = false;
2151 #endif
2152  if (attach_msg || ReadOnly ||
2153 #ifdef USE_NNTP
2154  op == OP_MAIN_CHANGE_GROUP_READONLY ||
2155 #endif
2156  op == OP_MAIN_CHANGE_FOLDER_READONLY)
2157  flags = MUTT_READONLY;
2158  else
2159  flags = 0;
2160 
2161  if (flags)
2162  cp = _("Open mailbox in read-only mode");
2163  else
2164  cp = _("Open mailbox");
2165 
2166  buf[0] = '\0';
2167  if ((op == OP_MAIN_NEXT_UNREAD_MAILBOX) && Context &&
2168  (Context->mailbox->path[0] != '\0'))
2169  {
2170  mutt_str_strfcpy(buf, Context->mailbox->path, sizeof(buf));
2171  mutt_pretty_mailbox(buf, sizeof(buf));
2172  mutt_mailbox(buf, sizeof(buf));
2173  if (!buf[0])
2174  {
2175  mutt_error(_("No mailboxes have new mail"));
2176  break;
2177  }
2178  }
2179 #ifdef USE_SIDEBAR
2180  else if (op == OP_SIDEBAR_OPEN)
2181  {
2182  m = mutt_sb_get_highlight();
2183  if (!m)
2184  break;
2185  mutt_str_strfcpy(buf, m->path, sizeof(buf));
2186 
2187  /* Mark the selected dir for the neomutt browser */
2189  }
2190 #endif
2191  else
2192  {
2193  if (ChangeFolderNext && Context && (Context->mailbox->path[0] != '\0'))
2194  {
2195  mutt_str_strfcpy(buf, Context->mailbox->path, sizeof(buf));
2196  mutt_pretty_mailbox(buf, sizeof(buf));
2197  }
2198 #ifdef USE_NNTP
2199  if (op == OP_MAIN_CHANGE_GROUP || op == OP_MAIN_CHANGE_GROUP_READONLY)
2200  {
2201  OptNews = true;
2202  m = Context ? Context->mailbox : NULL;
2204  if (!CurrentNewsSrv)
2205  break;
2206  if (flags)
2207  cp = _("Open newsgroup in read-only mode");
2208  else
2209  cp = _("Open newsgroup");
2210  nntp_mailbox(m, buf, sizeof(buf));
2211  }
2212  else
2213 #endif
2214  {
2215  /* By default, fill buf with the next mailbox that contains unread
2216  * mail */
2217  mutt_mailbox(buf, sizeof(buf));
2218  }
2219 
2220  if (mutt_enter_fname(cp, buf, sizeof(buf), 1) == -1)
2221  {
2222  if (menu->menu == MENU_PAGER)
2223  {
2224  op = OP_DISPLAY_MESSAGE;
2225  continue;
2226  }
2227  else
2228  break;
2229  }
2230 
2231  /* Selected directory is okay, let's save it. */
2233 
2234  if (!buf[0])
2235  {
2237  break;
2238  }
2239  }
2240 
2241  if (!m)
2242  m = mx_mbox_find2(buf);
2243 
2244  main_change_folder(menu, op, m, buf, sizeof(buf), &oldcount, &index_hint);
2245 #ifdef USE_NNTP
2246  /* mutt_mailbox_check() must be done with mail-reader mode! */
2247  menu->help = mutt_compile_help(
2248  helpstr, sizeof(helpstr), MENU_MAIN,
2250 #endif
2251  mutt_expand_path(buf, sizeof(buf));
2252 #ifdef USE_SIDEBAR
2254 #endif
2255  break;
2256  }
2257 
2258  case OP_DISPLAY_MESSAGE:
2259  case OP_DISPLAY_HEADERS: /* don't weed the headers */
2260 
2262  CHECK_VISIBLE;
2263  /* toggle the weeding of headers so that a user can press the key
2264  * again while reading the message.
2265  */
2266  if (op == OP_DISPLAY_HEADERS)
2267  bool_str_toggle(Config, "weed", NULL);
2268 
2269  OptNeedResort = false;
2270 
2271  if ((Sort & SORT_MASK) == SORT_THREADS && CURHDR->collapsed)
2272  {
2275  if (UncollapseJump)
2277  }
2278 
2279  if (PgpAutoDecode && (tag || !(CURHDR->security & PGP_TRADITIONAL_CHECKED)))
2280  {
2281  mutt_check_traditional_pgp(tag ? NULL : CURHDR, &menu->redraw);
2282  }
2283  int hint = Context->mailbox->hdrs[Context->mailbox->v2r[menu->current]]->index;
2284 
2285  /* If we are returning to the pager via an index menu redirection, we
2286  * need to reset the menu->menu. Otherwise mutt_menu_pop_current() will
2287  * set CurrentMenu incorrectly when we return back to the index menu. */
2288  menu->menu = MENU_MAIN;
2289 
2291  if (op < 0)
2292  {
2293  OptNeedResort = false;
2294  break;
2295  }
2296 
2297  /* This is used to redirect a single operation back here afterwards. If
2298  * mutt_display_message() returns 0, then the menu and pager state will
2299  * be cleaned up after this switch statement. */
2300  menu->menu = MENU_PAGER;
2301  menu->oldcurrent = menu->current;
2302  if (Context)
2304 
2305  continue;
2306 
2307  case OP_EXIT:
2308 
2309  close = op;
2310  if (menu->menu == MENU_MAIN && attach_msg)
2311  {
2312  done = true;
2313  break;
2314  }
2315 
2316  if ((menu->menu == MENU_MAIN) &&
2317  (query_quadoption(Quit, _("Exit NeoMutt without saving?")) == MUTT_YES))
2318  {
2319  if (Context)
2320  {
2323  }
2324  done = true;
2325  }
2326  break;
2327 
2328  case OP_MAIN_BREAK_THREAD:
2329 
2331  CHECK_VISIBLE;
2333  CHECK_ACL(MUTT_ACL_WRITE, _("Cannot break thread"));
2334 
2335  if ((Sort & SORT_MASK) != SORT_THREADS)
2336  mutt_error(_("Threading is not enabled"));
2337  else if (!STAILQ_EMPTY(&CURHDR->env->in_reply_to) ||
2338  !STAILQ_EMPTY(&CURHDR->env->references))
2339  {
2340  {
2341  struct Email *oldcur = CURHDR;
2342 
2344  mutt_sort_headers(Context, true);
2345  menu->current = oldcur->virtual;
2346  }
2347 
2348  Context->mailbox->changed = true;
2349  mutt_message(_("Thread broken"));
2350 
2351  if (menu->menu == MENU_PAGER)
2352  {
2353  op = OP_DISPLAY_MESSAGE;
2354  continue;
2355  }
2356  else
2357  menu->redraw |= REDRAW_INDEX;
2358  }
2359  else
2360  {
2361  mutt_error(
2362  _("Thread cannot be broken, message is not part of a thread"));
2363  }
2364 
2365  break;
2366 
2367  case OP_MAIN_LINK_THREADS:
2368 
2370  CHECK_VISIBLE;
2372  /* L10N: CHECK_ACL */
2373  CHECK_ACL(MUTT_ACL_WRITE, _("Cannot link threads"));
2374 
2375  if ((Sort & SORT_MASK) != SORT_THREADS)
2376  mutt_error(_("Threading is not enabled"));
2377  else if (!CURHDR->env->message_id)
2378  mutt_error(_("No Message-ID: header available to link thread"));
2379  else if (!tag && (!Context->last_tag || !Context->last_tag->tagged))
2380  mutt_error(_("First, please tag a message to be linked here"));
2381  else
2382  {
2383  struct Email *oldcur = CURHDR;
2384 
2385  if (mutt_link_threads(CURHDR, tag ? NULL : Context->last_tag, Context))
2386  {
2387  mutt_sort_headers(Context, true);
2388  menu->current = oldcur->virtual;
2389 
2390  Context->mailbox->changed = true;
2391  mutt_message(_("Threads linked"));
2392  }
2393  else
2394  mutt_error(_("No thread linked"));
2395  }
2396 
2397  if (menu->menu == MENU_PAGER)
2398  {
2399  op = OP_DISPLAY_MESSAGE;
2400  continue;
2401  }
2402  else
2403  menu->redraw |= REDRAW_STATUS | REDRAW_INDEX;
2404 
2405  break;
2406 
2407  case OP_EDIT_TYPE:
2408 
2410  CHECK_VISIBLE;
2411  CHECK_ATTACH;
2412  mutt_edit_content_type(CURHDR, CURHDR->content, NULL);
2413  /* if we were in the pager, redisplay the message */
2414  if (menu->menu == MENU_PAGER)
2415  {
2416  op = OP_DISPLAY_MESSAGE;
2417  continue;
2418  }
2419  else
2420  menu->redraw = REDRAW_CURRENT;
2421  break;
2422 
2423  case OP_MAIN_NEXT_UNDELETED:
2424 
2426  CHECK_VISIBLE;
2427  if (menu->current >= Context->mailbox->vcount - 1)
2428  {
2429  if (menu->menu == MENU_MAIN)
2430  mutt_error(_("You are on the last message"));
2431  break;
2432  }
2433  menu->current = ci_next_undeleted(menu->current);
2434  if (menu->current == -1)
2435  {
2436  menu->current = menu->oldcurrent;
2437  if (menu->menu == MENU_MAIN)
2438  mutt_error(_("No undeleted messages"));
2439  }
2440  else if (menu->menu == MENU_PAGER)
2441  {
2442  op = OP_DISPLAY_MESSAGE;
2443  continue;
2444  }
2445  else
2446  menu->redraw = REDRAW_MOTION;
2447  break;
2448 
2449  case OP_NEXT_ENTRY:
2450 
2452  CHECK_VISIBLE;
2453  if (menu->current >= Context->mailbox->vcount - 1)
2454  {
2455  if (menu->menu == MENU_MAIN)
2456  mutt_error(_("You are on the last message"));
2457  break;
2458  }
2459  menu->current++;
2460  if (menu->menu == MENU_PAGER)
2461  {
2462  op = OP_DISPLAY_MESSAGE;
2463  continue;
2464  }
2465  else
2466  menu->redraw = REDRAW_MOTION;
2467  break;
2468 
2469  case OP_MAIN_PREV_UNDELETED:
2470 
2472  CHECK_VISIBLE;
2473  if (menu->current < 1)
2474  {
2475  mutt_error(_("You are on the first message"));
2476  break;
2477  }
2478  menu->current = ci_previous_undeleted(menu->current);
2479  if (menu->current == -1)
2480  {
2481  menu->current = menu->oldcurrent;
2482  if (menu->menu == MENU_MAIN)
2483  mutt_error(_("No undeleted messages"));
2484  }
2485  else if (menu->menu == MENU_PAGER)
2486  {
2487  op = OP_DISPLAY_MESSAGE;
2488  continue;
2489  }
2490  else
2491  menu->redraw = REDRAW_MOTION;
2492  break;
2493 
2494  case OP_PREV_ENTRY:
2495 
2497  CHECK_VISIBLE;
2498  if (menu->current < 1)
2499  {
2500  if (menu->menu == MENU_MAIN)
2501  mutt_error(_("You are on the first message"));
2502  break;
2503  }
2504  menu->current--;
2505  if (menu->menu == MENU_PAGER)
2506  {
2507  op = OP_DISPLAY_MESSAGE;
2508  continue;
2509  }
2510  else
2511  menu->redraw = REDRAW_MOTION;
2512  break;
2513 
2514  case OP_DECRYPT_COPY:
2515  case OP_DECRYPT_SAVE:
2516  if (!WithCrypto)
2517  break;
2518  /* fallthrough */
2519  case OP_COPY_MESSAGE:
2520  case OP_SAVE:
2521  case OP_DECODE_COPY:
2522  case OP_DECODE_SAVE:
2524  CHECK_VISIBLE;
2525  if ((mutt_save_message(tag ? NULL : CURHDR,
2526  (op == OP_DECRYPT_SAVE) || (op == OP_SAVE) || (op == OP_DECODE_SAVE),
2527  (op == OP_DECODE_SAVE) || (op == OP_DECODE_COPY),
2528  (op == OP_DECRYPT_SAVE) || (op == OP_DECRYPT_COPY)) == 0) &&
2529  ((op == OP_SAVE) || (op == OP_DECODE_SAVE) || (op == OP_DECRYPT_SAVE)))
2530  {
2531  menu->redraw |= REDRAW_STATUS;
2532  if (tag)
2533  menu->redraw |= REDRAW_INDEX;
2534  else if (Resolve)
2535  {
2536  menu->current = ci_next_undeleted(menu->current);
2537  if (menu->current == -1)
2538  {
2539  menu->current = menu->oldcurrent;
2540  menu->redraw |= REDRAW_CURRENT;
2541  }
2542  else
2543  menu->redraw |= REDRAW_MOTION_RESYNCH;
2544  }
2545  else
2546  menu->redraw |= REDRAW_CURRENT;
2547  }
2548  break;
2549 
2550  case OP_MAIN_NEXT_NEW:
2551  case OP_MAIN_NEXT_UNREAD:
2552  case OP_MAIN_PREV_NEW:
2553  case OP_MAIN_PREV_UNREAD:
2554  case OP_MAIN_NEXT_NEW_THEN_UNREAD:
2555  case OP_MAIN_PREV_NEW_THEN_UNREAD:
2556 
2557  {
2558  int first_unread = -1;
2559  int first_new = -1;
2560 
2562  CHECK_VISIBLE;
2563 
2564  const int saved_current = menu->current;
2565  i = menu->current;
2566  menu->current = -1;
2567  for (j = 0; j != Context->mailbox->vcount; j++)
2568  {
2569  if (op == OP_MAIN_NEXT_NEW || op == OP_MAIN_NEXT_UNREAD || op == OP_MAIN_NEXT_NEW_THEN_UNREAD)
2570  {
2571  i++;
2572  if (i > Context->mailbox->vcount - 1)
2573  {
2574  i = 0;
2575  }
2576  }
2577  else
2578  {
2579  i--;
2580  if (i < 0)
2581  {
2582  i = Context->mailbox->vcount - 1;
2583  }
2584  }
2585 
2586  struct Email *e = Context->mailbox->hdrs[Context->mailbox->v2r[i]];
2587  if (e->collapsed && (Sort & SORT_MASK) == SORT_THREADS)
2588  {
2589  if (UNREAD(e) && first_unread == -1)
2590  first_unread = i;
2591  if (UNREAD(e) == 1 && first_new == -1)
2592  first_new = i;
2593  }
2594  else if ((!e->deleted && !e->read))
2595  {
2596  if (first_unread == -1)
2597  first_unread = i;
2598  if ((!e->old) && first_new == -1)
2599  first_new = i;
2600  }
2601 
2602  if ((op == OP_MAIN_NEXT_UNREAD || op == OP_MAIN_PREV_UNREAD) && first_unread != -1)
2603  break;
2604  if ((op == OP_MAIN_NEXT_NEW || op == OP_MAIN_PREV_NEW ||
2605  op == OP_MAIN_NEXT_NEW_THEN_UNREAD || op == OP_MAIN_PREV_NEW_THEN_UNREAD) &&
2606  first_new != -1)
2607  {
2608  break;
2609  }
2610  }
2611  if ((op == OP_MAIN_NEXT_NEW || op == OP_MAIN_PREV_NEW ||
2612  op == OP_MAIN_NEXT_NEW_THEN_UNREAD || op == OP_MAIN_PREV_NEW_THEN_UNREAD) &&
2613  first_new != -1)
2614  {
2615  menu->current = first_new;
2616  }
2617  else if ((op == OP_MAIN_NEXT_UNREAD || op == OP_MAIN_PREV_UNREAD ||
2618  op == OP_MAIN_NEXT_NEW_THEN_UNREAD || op == OP_MAIN_PREV_NEW_THEN_UNREAD) &&
2619  first_unread != -1)
2620  {
2621  menu->current = first_unread;
2622  }
2623 
2624  if (menu->current == -1)
2625  {
2626  menu->current = menu->oldcurrent;
2627  if (op == OP_MAIN_NEXT_NEW || op == OP_MAIN_PREV_NEW)
2628  {
2629  if (Context->pattern)
2630  mutt_error(_("No new messages in this limited view"));
2631  else
2632  mutt_error(_("No new messages"));
2633  }
2634  else
2635  {
2636  if (Context->pattern)
2637  mutt_error(_("No unread messages in this limited view"));
2638  else
2639  mutt_error(_("No unread messages"));
2640  }
2641  break;
2642  }
2643 
2644  if (op == OP_MAIN_NEXT_NEW || op == OP_MAIN_NEXT_UNREAD || op == OP_MAIN_NEXT_NEW_THEN_UNREAD)
2645  {
2646  if (saved_current > menu->current)
2647  {
2648  mutt_message(_("Search wrapped to top"));
2649  }
2650  }
2651  else if (saved_current < menu->current)
2652  {
2653  mutt_message(_("Search wrapped to bottom"));
2654  }
2655 
2656  if (menu->menu == MENU_PAGER)
2657  {
2658  op = OP_DISPLAY_MESSAGE;
2659  continue;
2660  }
2661  else
2662  menu->redraw = REDRAW_MOTION;
2663  break;
2664  }
2665  case OP_FLAG_MESSAGE:
2666 
2668  CHECK_VISIBLE;
2670  /* L10N: CHECK_ACL */
2671  CHECK_ACL(MUTT_ACL_WRITE, _("Cannot flag message"));
2672 
2673  if (tag)
2674  {
2675  for (j = 0; j < Context->mailbox->msg_count; j++)
2676  {
2677  if (message_is_tagged(Context, j))
2678  {
2681  }
2682  }
2683 
2684  menu->redraw |= REDRAW_INDEX;
2685  }
2686  else
2687  {
2688  mutt_set_flag(Context->mailbox, CURHDR, MUTT_FLAG, !CURHDR->flagged);
2689  if (Resolve)
2690  {
2691  menu->current = ci_next_undeleted(menu->current);
2692  if (menu->current == -1)
2693  {
2694  menu->current = menu->oldcurrent;
2695  menu->redraw |= REDRAW_CURRENT;
2696  }
2697  else
2698  menu->redraw |= REDRAW_MOTION_RESYNCH;
2699  }
2700  else
2701  menu->redraw |= REDRAW_CURRENT;
2702  }
2703  menu->redraw |= REDRAW_STATUS;
2704  break;
2705 
2706  case OP_TOGGLE_NEW:
2707 
2709  CHECK_VISIBLE;
2711  /* L10N: CHECK_ACL */
2712  CHECK_ACL(MUTT_ACL_SEEN, _("Cannot toggle new"));
2713 
2714  if (tag)
2715  {
2716  for (j = 0; j < Context->mailbox->msg_count; j++)
2717  {
2718  if (!message_is_tagged(Context, j))
2719  continue;
2720 
2721  if (Context->mailbox->hdrs[j]->read || Context->mailbox->hdrs[j]->old)
2723  else
2725  }
2726  menu->redraw |= REDRAW_STATUS | REDRAW_INDEX;
2727  }
2728  else
2729  {
2730  if (CURHDR->read || CURHDR->old)
2731  mutt_set_flag(Context->mailbox, CURHDR, MUTT_NEW, 1);
2732  else
2733  mutt_set_flag(Context->mailbox, CURHDR, MUTT_READ, 1);
2734 
2735  if (Resolve)
2736  {
2737  menu->current = ci_next_undeleted(menu->current);
2738  if (menu->current == -1)
2739  {
2740  menu->current = menu->oldcurrent;
2741  menu->redraw |= REDRAW_CURRENT;
2742  }
2743  else
2744  menu->redraw |= REDRAW_MOTION_RESYNCH;
2745  }
2746  else
2747  menu->redraw |= REDRAW_CURRENT;
2748  menu->redraw |= REDRAW_STATUS;
2749  }
2750  break;
2751 
2752  case OP_TOGGLE_WRITE:
2753 
2755  if (mx_toggle_write(Context->mailbox) == 0)
2756  menu->redraw |= REDRAW_STATUS;
2757  break;
2758 
2759  case OP_MAIN_NEXT_THREAD:
2760  case OP_MAIN_NEXT_SUBTHREAD:
2761  case OP_MAIN_PREV_THREAD:
2762  case OP_MAIN_PREV_SUBTHREAD:
2763 
2765  CHECK_VISIBLE;
2766  switch (op)
2767  {
2768  case OP_MAIN_NEXT_THREAD:
2769  menu->current = mutt_next_thread(CURHDR);
2770  break;
2771 
2772  case OP_MAIN_NEXT_SUBTHREAD:
2773  menu->current = mutt_next_subthread(CURHDR);
2774  break;
2775 
2776  case OP_MAIN_PREV_THREAD:
2777  menu->current = mutt_previous_thread(CURHDR);
2778  break;
2779 
2780  case OP_MAIN_PREV_SUBTHREAD:
2781  menu->current = mutt_previous_subthread(CURHDR);
2782  break;
2783  }
2784 
2785  if (menu->current < 0)
2786  {
2787  menu->current = menu->oldcurrent;
2788  if (op == OP_MAIN_NEXT_THREAD || op == OP_MAIN_NEXT_SUBTHREAD)
2789  mutt_error(_("No more threads"));
2790  else
2791  mutt_error(_("You are on the first thread"));
2792  }
2793  else if (menu->menu == MENU_PAGER)
2794  {
2795  op = OP_DISPLAY_MESSAGE;
2796  continue;
2797  }
2798  else
2799  menu->redraw = REDRAW_MOTION;
2800  break;
2801 
2802  case OP_MAIN_ROOT_MESSAGE:
2803  case OP_MAIN_PARENT_MESSAGE:
2804 
2806  CHECK_VISIBLE;
2807 
2808  menu->current = mutt_parent_message(Context, CURHDR, op == OP_MAIN_ROOT_MESSAGE);
2809  if (menu->current < 0)
2810  {
2811  menu->current = menu->oldcurrent;
2812  }
2813  else if (menu->menu == MENU_PAGER)
2814  {
2815  op = OP_DISPLAY_MESSAGE;
2816  continue;
2817  }
2818  else
2819  menu->redraw = REDRAW_MOTION;
2820  break;
2821 
2822  case OP_MAIN_SET_FLAG:
2823  case OP_MAIN_CLEAR_FLAG:
2824 
2826  CHECK_VISIBLE;
2828  /* CHECK_ACL(MUTT_ACL_WRITE); */
2829 
2830  if (mutt_change_flag(tag ? NULL : CURHDR, (op == OP_MAIN_SET_FLAG)) == 0)
2831  {
2832  menu->redraw |= REDRAW_STATUS;
2833  if (tag)
2834  menu->redraw |= REDRAW_INDEX;
2835  else if (Resolve)
2836  {
2837  menu->current = ci_next_undeleted(menu->current);
2838  if (menu->current == -1)
2839  {
2840  menu->current = menu->oldcurrent;
2841  menu->redraw |= REDRAW_CURRENT;
2842  }
2843  else
2844  menu->redraw |= REDRAW_MOTION_RESYNCH;
2845  }
2846  else
2847  menu->redraw |= REDRAW_CURRENT;
2848  }
2849  break;
2850 
2851  case OP_MAIN_COLLAPSE_THREAD:
2853  CHECK_VISIBLE;
2854 
2855  if ((Sort & SORT_MASK) != SORT_THREADS)
2856  {
2857  mutt_error(_("Threading is not enabled"));
2858  break;
2859  }
2860 
2861  if (CURHDR->collapsed)
2862  {
2863  menu->current = mutt_uncollapse_thread(Context, CURHDR);
2865  if (UncollapseJump)
2866  menu->current = mutt_thread_next_unread(Context, CURHDR);
2867  }
2868  else if (CAN_COLLAPSE(CURHDR))
2869  {
2870  menu->current = mutt_collapse_thread(Context, CURHDR);
2872  }
2873  else
2874  {
2875  mutt_error(_("Thread contains unread or flagged messages"));
2876  break;
2877  }
2878 
2879  menu->redraw = REDRAW_INDEX | REDRAW_STATUS;
2880 
2881  break;
2882 
2883  case OP_MAIN_COLLAPSE_ALL:
2885  CHECK_VISIBLE;
2886 
2887  if ((Sort & SORT_MASK) != SORT_THREADS)
2888  {
2889  mutt_error(_("Threading is not enabled"));
2890  break;
2891  }
2892  collapse_all(menu, 1);
2893  break;
2894 
2895  /* --------------------------------------------------------------------
2896  * These functions are invoked directly from the internal-pager
2897  */
2898 
2899  case OP_BOUNCE_MESSAGE:
2900 
2901  CHECK_ATTACH;
2903  CHECK_VISIBLE;
2904  ci_bounce_message(tag ? NULL : CURHDR);
2905  break;
2906 
2907  case OP_CREATE_ALIAS:
2908 
2909  mutt_alias_create(Context && Context->mailbox->vcount ? CURHDR->env : NULL, NULL);
2910  menu->redraw |= REDRAW_CURRENT;
2911  break;
2912 
2913  case OP_QUERY:
2914  CHECK_ATTACH;
2915  mutt_query_menu(NULL, 0);
2916  break;
2917 
2918  case OP_PURGE_MESSAGE:
2919  case OP_DELETE:
2920 
2922  CHECK_VISIBLE;
2924  /* L10N: CHECK_ACL */
2925  CHECK_ACL(MUTT_ACL_DELETE, _("Cannot delete message"));
2926 
2927  if (tag)
2928  {
2930  mutt_tag_set_flag(MUTT_PURGE, (op == OP_PURGE_MESSAGE));
2931  if (DeleteUntag)
2933  menu->redraw |= REDRAW_INDEX;
2934  }
2935  else
2936  {
2937  mutt_set_flag(Context->mailbox, CURHDR, MUTT_DELETE, 1);
2938  mutt_set_flag(Context->mailbox, CURHDR, MUTT_PURGE, (op == OP_PURGE_MESSAGE));
2939  if (DeleteUntag)
2940  mutt_set_flag(Context->mailbox, CURHDR, MUTT_TAG, 0);
2941  if (Resolve)
2942  {
2943  menu->current = ci_next_undeleted(menu->current);
2944  if (menu->current == -1)
2945  {
2946  menu->current = menu->oldcurrent;
2947  menu->redraw |= REDRAW_CURRENT;
2948  }
2949  else if (menu->menu == MENU_PAGER)
2950  {
2951  op = OP_DISPLAY_MESSAGE;
2952  continue;
2953  }
2954  else
2955  menu->redraw |= REDRAW_MOTION_RESYNCH;
2956  }
2957  else
2958  menu->redraw |= REDRAW_CURRENT;
2959  }
2960  menu->redraw |= REDRAW_STATUS;
2961  break;
2962 
2963  case OP_DELETE_THREAD:
2964  case OP_DELETE_SUBTHREAD:
2965  case OP_PURGE_THREAD:
2966 
2968  CHECK_VISIBLE;
2970  /* L10N: CHECK_ACL */
2971  /* L10N: Due to the implementation details we do not know whether we
2972  delete zero, 1, 12, ... messages. So in English we use
2973  "messages". Your language might have other means to express this.
2974  */
2975  CHECK_ACL(MUTT_ACL_DELETE, _("Cannot delete messages"));
2976 
2977  {
2978  int subthread = (op == OP_DELETE_SUBTHREAD);
2979  rc = mutt_thread_set_flag(CURHDR, MUTT_DELETE, 1, subthread);
2980  if (rc == -1)
2981  break;
2982  if (op == OP_PURGE_THREAD)
2983  {
2984  rc = mutt_thread_set_flag(CURHDR, MUTT_PURGE, 1, subthread);
2985  if (rc == -1)
2986  break;
2987  }
2988 
2989  if (DeleteUntag)
2990  mutt_thread_set_flag(CURHDR, MUTT_TAG, 0, subthread);
2991  if (Resolve)
2992  {
2993  menu->current = ci_next_undeleted(menu->current);
2994  if (menu->current == -1)
2995  menu->current = menu->oldcurrent;
2996  }
2997  menu->redraw |= REDRAW_INDEX | REDRAW_STATUS;
2998  }
2999  break;
3000 
3001 #ifdef USE_NNTP
3002  case OP_CATCHUP:
3005  CHECK_ATTACH
3006  if (Context && Context->mailbox->magic == MUTT_NNTP)
3007  {
3008  struct NntpMboxData *mdata = Context->mailbox->mdata;
3009  if (mutt_newsgroup_catchup(Context->mailbox, mdata->adata, mdata->group))
3010  menu->redraw = REDRAW_INDEX | REDRAW_STATUS;
3011  }
3012  break;
3013 #endif
3014 
3015  case OP_DISPLAY_ADDRESS:
3016 
3018  CHECK_VISIBLE;
3019  mutt_display_address(CURHDR->env);
3020  break;
3021 
3022  case OP_ENTER_COMMAND:
3023 
3025  if (Context)
3027  break;
3028 
3029  case OP_EDIT_OR_VIEW_RAW_MESSAGE:
3030  case OP_EDIT_RAW_MESSAGE:
3031  case OP_VIEW_RAW_MESSAGE:
3032 
3033  /* TODO split this into 3 cases? */
3035  CHECK_VISIBLE;
3036  CHECK_ATTACH;
3037  bool edit;
3038  if (op == OP_EDIT_RAW_MESSAGE)
3039  {
3041  /* L10N: CHECK_ACL */
3042  CHECK_ACL(MUTT_ACL_INSERT, _("Cannot edit message"));
3043  edit = true;
3044  }
3045  else if (op == OP_EDIT_OR_VIEW_RAW_MESSAGE)
3046  edit = !Context->mailbox->readonly &&
3048  else
3049  edit = false;
3050 
3051  if (PgpAutoDecode && (tag || !(CURHDR->security & PGP_TRADITIONAL_CHECKED)))
3052  {
3053  mutt_check_traditional_pgp(tag ? NULL : CURHDR, &menu->redraw);
3054  }
3055  if (edit)
3056  mutt_edit_message(Context, tag ? NULL : CURHDR);
3057  else
3058  mutt_view_message(Context, tag ? NULL : CURHDR);
3059  menu->redraw = REDRAW_FULL;
3060 
3061  break;
3062 
3063  case OP_FORWARD_MESSAGE:
3064 
3066  CHECK_VISIBLE;
3067  CHECK_ATTACH;
3068  if (PgpAutoDecode && (tag || !(CURHDR->security & PGP_TRADITIONAL_CHECKED)))
3069  {
3070  mutt_check_traditional_pgp(tag ? NULL : CURHDR, &menu->redraw);
3071  }
3072  ci_send_message(SEND_FORWARD, NULL, NULL, Context, tag ? NULL : CURHDR);
3073  menu->redraw = REDRAW_FULL;
3074  break;
3075 
3076  case OP_FORGET_PASSPHRASE:
3078  break;
3079 
3080  case OP_GROUP_REPLY:
3081 
3083  CHECK_VISIBLE;
3084  CHECK_ATTACH;
3085  if (PgpAutoDecode && (tag || !(CURHDR->security & PGP_TRADITIONAL_CHECKED)))
3086  {
3087  mutt_check_traditional_pgp(tag ? NULL : CURHDR, &menu->redraw);
3088  }
3090  tag ? NULL : CURHDR);
3091  menu->redraw = REDRAW_FULL;
3092  break;
3093 
3094  case OP_EDIT_LABEL:
3095 
3097  CHECK_VISIBLE;
3099  rc = mutt_label_message(tag ? NULL : CURHDR);
3100  if (rc > 0)
3101  {
3102  Context->mailbox->changed = true;
3103  menu->redraw = REDRAW_FULL;
3104  /* L10N: This is displayed when the x-label on one or more
3105  * messages is edited. */
3106  mutt_message(ngettext("%d label changed", "%d labels changed", rc), rc);
3107  }
3108  else
3109  {
3110  /* L10N: This is displayed when editing an x-label, but no messages
3111  * were updated. Possibly due to canceling at the prompt or if the new
3112  * label is the same as the old label. */
3113  mutt_message(_("No labels changed"));
3114  }
3115  break;
3116 
3117  case OP_LIST_REPLY:
3118 
3119  CHECK_ATTACH;
3121  CHECK_VISIBLE;
3122  if (PgpAutoDecode && (tag || !(CURHDR->security & PGP_TRADITIONAL_CHECKED)))
3123  {
3124  mutt_check_traditional_pgp(tag ? NULL : CURHDR, &menu->redraw);
3125  }
3127  tag ? NULL : CURHDR);
3128  menu->redraw = REDRAW_FULL;
3129  break;
3130 
3131  case OP_MAIL:
3132 
3133  CHECK_ATTACH;
3134  ci_send_message(0, NULL, NULL, Context, NULL);
3135  menu->redraw = REDRAW_FULL;
3136  break;
3137 
3138  case OP_MAIL_KEY:
3139  if (!(WithCrypto & APPLICATION_PGP))
3140  break;
3141  CHECK_ATTACH;
3142  ci_send_message(SEND_KEY, NULL, NULL, NULL, NULL);
3143  menu->redraw = REDRAW_FULL;
3144  break;
3145 
3146  case OP_EXTRACT_KEYS:
3147  if (!WithCrypto)
3148  break;
3150  CHECK_VISIBLE;
3151  crypt_extract_keys_from_messages(tag ? NULL : CURHDR);
3152  menu->redraw = REDRAW_FULL;
3153  break;
3154 
3155  case OP_CHECK_TRADITIONAL:
3156  if (!(WithCrypto & APPLICATION_PGP))
3157  break;
3159  CHECK_VISIBLE;
3160  if (tag || !(CURHDR->security & PGP_TRADITIONAL_CHECKED))
3161  mutt_check_traditional_pgp(tag ? NULL : CURHDR, &menu->redraw);
3162 
3163  if (menu->menu == MENU_PAGER)
3164  {
3165  op = OP_DISPLAY_MESSAGE;
3166  continue;
3167  }
3168  break;
3169 
3170  case OP_PIPE:
3171 
3173  CHECK_VISIBLE;
3174  mutt_pipe_message(tag ? NULL : CURHDR);
3175 
3176 #ifdef USE_IMAP
3177  /* in an IMAP folder index with imap_peek=no, piping could change
3178  * new or old messages status to read. Redraw what's needed.
3179  */
3180  if (Context->mailbox->magic == MUTT_IMAP && !ImapPeek)
3181  {
3182  menu->redraw |= (tag ? REDRAW_INDEX : REDRAW_CURRENT) | REDRAW_STATUS;
3183  }
3184 #endif
3185 
3186  break;
3187 
3188  case OP_PRINT:
3189 
3191  CHECK_VISIBLE;
3192  mutt_print_message(tag ? NULL : CURHDR);
3193 
3194 #ifdef USE_IMAP
3195  /* in an IMAP folder index with imap_peek=no, printing could change
3196  * new or old messages status to read. Redraw what's needed.
3197  */
3198  if (Context->mailbox->magic == MUTT_IMAP && !ImapPeek)
3199  {
3200  menu->redraw |= (tag ? REDRAW_INDEX : REDRAW_CURRENT) | REDRAW_STATUS;
3201  }
3202 #endif
3203 
3204  break;
3205 
3206  case OP_MAIN_READ_THREAD:
3207  case OP_MAIN_READ_SUBTHREAD:
3208 
3210  CHECK_VISIBLE;
3212  /* L10N: CHECK_ACL */
3213  /* L10N: Due to the implementation details we do not know whether we
3214  mark zero, 1, 12, ... messages as read. So in English we use
3215  "messages". Your language might have other means to express this.
3216  */
3217  CHECK_ACL(MUTT_ACL_SEEN, _("Cannot mark messages as read"));
3218 
3219  rc = mutt_thread_set_flag(CURHDR, MUTT_READ, 1, op == OP_MAIN_READ_THREAD ? 0 : 1);
3220 
3221  if (rc != -1)
3222  {
3223  if (Resolve)
3224  {
3225  menu->current = (op == OP_MAIN_READ_THREAD ? mutt_next_thread(CURHDR) :
3226  mutt_next_subthread(CURHDR));
3227  if (menu->current == -1)
3228  {
3229  menu->current = menu->oldcurrent;
3230  }
3231  else if (menu->menu == MENU_PAGER)
3232  {
3233  op = OP_DISPLAY_MESSAGE;
3234  continue;
3235  }
3236  }
3237  menu->redraw |= REDRAW_INDEX | REDRAW_STATUS;
3238  }
3239  break;
3240 
3241  case OP_MARK_MSG:
3242 
3244  CHECK_VISIBLE;
3245  if (CURHDR->env->message_id)
3246  {
3247  char buf2[128];
3248 
3249  buf2[0] = '\0';
3250  /* L10N: This is the prompt for <mark-message>. Whatever they
3251  enter will be prefixed by $mark_macro_prefix and will become
3252  a macro hotkey to jump to the currently selected message. */
3253  if (!mutt_get_field(_("Enter macro stroke: "), buf2, sizeof(buf2), MUTT_CLEAR) &&
3254  buf2[0])
3255  {
3256  char str[STRING], macro[STRING];
3257  snprintf(str, sizeof(str), "%s%s", MarkMacroPrefix, buf2);
3258  snprintf(macro, sizeof(macro), "<search>~i \"%s\"\n", CURHDR->env->message_id);
3259  /* L10N: "message hotkey" is the key bindings menu description of a
3260  macro created by <mark-message>. */
3261  km_bind(str, MENU_MAIN, OP_MACRO, macro, _("message hotkey"));
3262 
3263  /* L10N: This is echoed after <mark-message> creates a new hotkey
3264  macro. %s is the hotkey string ($mark_macro_prefix followed
3265  by whatever they typed at the prompt.) */
3266  snprintf(buf2, sizeof(buf2), _("Message bound to %s"), str);
3267  mutt_message(buf2);
3268  mutt_debug(1, "Mark: %s => %s\n", str, macro);
3269  }
3270  }
3271  else
3272  {
3273  /* L10N: This error is printed if <mark-message> cannot find a
3274  Message-ID for the currently selected message in the index. */
3275  mutt_error(_("No message ID to macro"));
3276  }
3277  break;
3278 
3279  case OP_RECALL_MESSAGE:
3280 
3281  CHECK_ATTACH;
3282  ci_send_message(SEND_POSTPONED, NULL, NULL, Context, NULL);
3283  menu->redraw = REDRAW_FULL;
3284  break;
3285 
3286  case OP_RESEND:
3287 
3288  CHECK_ATTACH;
3290  CHECK_VISIBLE;
3291 
3292  if (tag)
3293  {
3294  for (j = 0; j < Context->mailbox->msg_count; j++)
3295  {
3296  if (message_is_tagged(Context, j))
3298  }
3299  }
3300  else
3301  mutt_resend_message(NULL, Context, CURHDR);
3302 
3303  menu->redraw = REDRAW_FULL;
3304  break;
3305 
3306 #ifdef USE_NNTP
3307  case OP_FOLLOWUP:
3308  case OP_FORWARD_TO_GROUP:
3310  CHECK_VISIBLE;
3311  /* fallthrough */
3312 
3313  case OP_POST:
3314  CHECK_ATTACH;
3315  if (op != OP_FOLLOWUP || !CURHDR->env->followup_to ||
3316  (mutt_str_strcasecmp(CURHDR->env->followup_to, "poster") != 0) ||
3318  _("Reply by mail as poster prefers?")) != MUTT_YES)
3319  {
3320  if (Context && Context->mailbox->magic == MUTT_NNTP &&
3321  !((struct NntpMboxData *) Context->mailbox->mdata)->allowed && query_quadoption(PostModerated, _("Posting to this group not allowed, may be moderated. Continue?")) != MUTT_YES)
3322  {
3323  break;
3324  }
3325  if (op == OP_POST)
3326  ci_send_message(SEND_NEWS, NULL, NULL, Context, NULL);
3327  else
3328  {
3330  ci_send_message((op == OP_FOLLOWUP ? SEND_REPLY : SEND_FORWARD) | SEND_NEWS,
3331  NULL, NULL, Context, tag ? NULL : CURHDR);
3332  }
3333  menu->redraw = REDRAW_FULL;
3334  break;
3335  }
3336 #endif
3337  /* fallthrough */
3338  case OP_REPLY:
3339 
3340  CHECK_ATTACH;
3342  CHECK_VISIBLE;
3343  if (PgpAutoDecode && (tag || !(CURHDR->security & PGP_TRADITIONAL_CHECKED)))
3344  {
3345  mutt_check_traditional_pgp(tag ? NULL : CURHDR, &menu->redraw);
3346  }
3347  ci_send_message(SEND_REPLY, NULL, NULL, Context, tag ? NULL : CURHDR);
3348  menu->redraw = REDRAW_FULL;
3349  break;
3350 
3351  case OP_SHELL_ESCAPE:
3352 
3354  break;
3355 
3356  case OP_TAG_THREAD:
3357  case OP_TAG_SUBTHREAD:
3358 
3360  CHECK_VISIBLE;
3361  rc = mutt_thread_set_flag(CURHDR, MUTT_TAG, !CURHDR->tagged,
3362  op == OP_TAG_THREAD ? 0 : 1);
3363 
3364  if (rc != -1)
3365  {
3366  if (Resolve)
3367  {
3368  if (op == OP_TAG_THREAD)
3369  menu->current = mutt_next_thread(CURHDR);
3370  else
3371  menu->current = mutt_next_subthread(CURHDR);
3372 
3373  if (menu->current == -1)
3374  menu->current = menu->oldcurrent;
3375  }
3376  menu->redraw |= REDRAW_INDEX | REDRAW_STATUS;
3377  }
3378  break;
3379 
3380  case OP_UNDELETE:
3381 
3383  CHECK_VISIBLE;
3385  /* L10N: CHECK_ACL */
3386  CHECK_ACL(MUTT_ACL_DELETE, _("Cannot undelete message"));
3387 
3388  if (tag)
3389  {
3392  menu->redraw |= REDRAW_INDEX;
3393  }
3394  else
3395  {
3396  mutt_set_flag(Context->mailbox, CURHDR, MUTT_DELETE, 0);
3397  mutt_set_flag(Context->mailbox, CURHDR, MUTT_PURGE, 0);
3398  if (Resolve && menu->current < Context->mailbox->vcount - 1)
3399  {
3400  menu->current++;
3401  menu->redraw |= REDRAW_MOTION_RESYNCH;
3402  }
3403  else
3404  menu->redraw |= REDRAW_CURRENT;
3405  }
3406  menu->redraw |= REDRAW_STATUS;
3407  break;
3408 
3409  case OP_UNDELETE_THREAD:
3410  case OP_UNDELETE_SUBTHREAD:
3411 
3413  CHECK_VISIBLE;
3415  /* L10N: CHECK_ACL */
3416  /* L10N: Due to the implementation details we do not know whether we
3417  undelete zero, 1, 12, ... messages. So in English we use
3418  "messages". Your language might have other means to express this.
3419  */
3420  CHECK_ACL(MUTT_ACL_DELETE, _("Cannot undelete messages"));
3421 
3422  rc = mutt_thread_set_flag(CURHDR, MUTT_DELETE, 0, op == OP_UNDELETE_THREAD ? 0 : 1);
3423  if (rc != -1)
3424  {
3425  rc = mutt_thread_set_flag(CURHDR, MUTT_PURGE, 0,
3426  op == OP_UNDELETE_THREAD ? 0 : 1);
3427  }
3428  if (rc != -1)
3429  {
3430  if (Resolve)
3431  {
3432  if (op == OP_UNDELETE_THREAD)
3433  menu->current = mutt_next_thread(CURHDR);
3434  else
3435  menu->current = mutt_next_subthread(CURHDR);
3436 
3437  if (menu->current == -1)
3438  menu->current = menu->oldcurrent;
3439  }
3440  menu->redraw |= REDRAW_INDEX | REDRAW_STATUS;
3441  }
3442  break;
3443 
3444  case OP_VERSION:
3446  break;
3447 
3448  case OP_MAILBOX_LIST:
3450  break;
3451 
3452  case OP_VIEW_ATTACHMENTS:
3454  CHECK_VISIBLE;
3455  mutt_view_attachments(CURHDR);
3456  if (Context && CURHDR->attach_del)
3457  Context->mailbox->changed = true;
3458  menu->redraw = REDRAW_FULL;
3459  break;
3460 
3461  case OP_END_COND:
3462  break;
3463 
3464  case OP_WHAT_KEY:
3465  mutt_what_key();
3466  break;
3467 
3468 #ifdef USE_SIDEBAR
3469  case OP_SIDEBAR_NEXT:
3470  case OP_SIDEBAR_NEXT_NEW:
3471  case OP_SIDEBAR_PAGE_DOWN:
3472  case OP_SIDEBAR_PAGE_UP:
3473  case OP_SIDEBAR_PREV:
3474  case OP_SIDEBAR_PREV_NEW:
3476  break;
3477 
3478  case OP_SIDEBAR_TOGGLE_VISIBLE:
3479  bool_str_toggle(Config, "sidebar_visible", NULL);
3481  break;
3482 #endif
3483  default:
3484  if (menu->menu == MENU_MAIN)
3486  }
3487 
3488 #ifdef USE_NOTMUCH
3489  if (Context)
3491 #endif
3492 
3493  if (menu->menu == MENU_PAGER)
3494  {
3496  menu->menu = MENU_MAIN;
3497  menu->redraw = REDRAW_FULL;
3498  }
3499 
3500  if (done)
3501  break;
3502  }
3503 
3504  mutt_menu_pop_current(menu);
3505  mutt_menu_destroy(&menu);
3506  return close;
3507 }
WHERE unsigned char FollowupToPoster
Config: (nntp) Reply to the poster if &#39;poster&#39; is in the &#39;Followup-To&#39; header.
Definition: globals.h:196
The "current" mailbox.
Definition: context.h:36
struct NntpAccountData * nntp_select_server(struct Mailbox *m, char *server, bool leave_lock)
Open a connection to an NNTP server.
Definition: newsrc.c:997
void mutt_print_message(struct Email *e)
Print a message.
Definition: commands.c:588
&#39;Notmuch&#39; (virtual) Mailbox type
Definition: magic.h:43
#define mutt_next_thread(x)
Definition: mutt_thread.h:53
int mutt_pattern_func(int op, char *prompt)
Perform some Pattern matching.
Definition: pattern.c:2239
#define MUTT_PROGRESS_MSG
message-based progress
Definition: progress.h:33
#define mutt_bit_isset(v, n)
Definition: memory.h:39
#define NONULL(x)
Definition: string2.h:39
int msg_count
total number of messages
Definition: mailbox.h:86
int mutt_str_atoi(const char *str, int *dst)
Convert ASCII string to an integer.
Definition: string.c:262
int redraw
when to redraw the screen
Definition: menu.h:63
#define SEND_TO_SENDER
Definition: send.h:94
The envelope/body of an email.
Definition: email.h:35
#define MUTT_CLEAR
clear input if printable character is pressed
Definition: mutt.h:63
add/copy into the mailbox (used when editing a message)
Definition: mailbox.h:64
#define mutt_perror(...)
Definition: logging.h:89
#define MUTT_SHUTDOWN_HOOK
Definition: hook.h:60
struct NntpMboxData * mutt_newsgroup_catchup(struct Mailbox *m, struct NntpAccountData *adata, char *group)
Catchup newsgroup.
Definition: newsrc.c:1286
GUI selectable list of items.
Definition: menu.h:56
int km_dokey(int menu)
Determine what a keypress should do.
Definition: keymap.c:572
void mutt_pipe_message(struct Email *e)
Pipe a message.
Definition: commands.c:569
void nm_query_window_backward(void)
Function to move the current search window backward in time.
int mutt_edit_message(struct Context *ctx, struct Email *e)
Edit a message.
Definition: editmsg.c:296
&#39;NNTP&#39; (Usenet) Mailbox type
Definition: magic.h:41
void mutt_pretty_mailbox(char *s, size_t buflen)
Shorten a mailbox path using &#39;~&#39; or &#39;=&#39;.
Definition: muttlib.c:606
#define mutt_message(...)
Definition: logging.h:87
unsigned char rights[(MUTT_ACL_MAX+7)/8]
ACL bits.
Definition: mailbox.h:115
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: menu.h:85
User answered &#39;Yes&#39;, or assume &#39;Yes&#39;.
Definition: quad.h:39
void mutt_display_address(struct Envelope *env)
Display the address of a message.
Definition: commands.c:765
int nm_read_entire_thread(struct Context *ctx, struct Email *e)
Get the entire thread of an email.
Messages to be deleted.
Definition: mutt.h:118
struct NntpAccountData * adata
Definition: nntp.h:154
int virtual
virtual message number
Definition: email.h:89
void mutt_mailbox(char *s, size_t slen)
incoming folders completion routine
Definition: mailbox.c:693
static void index_custom_redraw(struct Menu *menu)
Redraw the index - Implements Menu::menu_custom_redraw()
Definition: index.c:910
void mutt_view_attachments(struct Email *e)
Show the attachments in a Menu.
Definition: recvattach.c:1317
void mutt_flushinp(void)
Empty all the keyboard buffers.
Definition: curs_lib.c:753
bool mutt_limit_current_thread(struct Email *e)
Limit the email view to the current thread.
Definition: pattern.c:2196
#define SEND_FORWARD
Definition: send.h:85
void mutt_window_clrtoeol(struct MuttWindow *win)
Clear to the end of the line.
Definition: mutt_window.c:81
void mutt_resize_screen(void)
Update NeoMutt&#39;s opinion about the window size (CURSES)
Definition: resize.c:98
#define CHECK_ATTACH
Definition: index.c:164
WHERE bool OptNeedResort
(pseudo) used to force a re-sort
Definition: options.h:40
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:657
void mutt_check_stats(void)
Forcibly update mailbox stats.
Definition: commands.c:1260
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:374
void crypt_forget_passphrase(void)
Forget a passphrase and display a message.
Definition: crypt.c:102
void mutt_progress_update(struct Progress *progress, long pos, int percent)
Update the state of the progress bar.
Definition: progress.c:170
void mutt_progress_init(struct Progress *progress, const char *msg, unsigned short flags, unsigned short inc, size_t size)
Set up a progress bar.
Definition: progress.c:113
#define MUTT_NM_QUERY
Notmuch query mode.
Definition: mutt.h:67
void mutt_enter_command(void)
enter a neomutt command
Definition: commands.c:731
#define PGP_TRADITIONAL_CHECKED
Definition: ncrypt.h:132
void mutt_unget_event(int ch, int op)
Return a keystroke to the input buffer.
Definition: curs_lib.c:668
#define _(a)
Definition: message.h:28
WHERE struct ConfigSet * Config
Wrapper around the user&#39;s config settings.
Definition: globals.h:39
int index_color(int line)
Calculate the colour for a line of the index - Implements Menu::menu_color()
Definition: index.c:729
void crypt_extract_keys_from_messages(struct Email *e)
Extract keys from a message.
Definition: crypt.c:808
void menu_status_line(char *buf, size_t buflen, struct Menu *menu, const char *p)
Create the status line.
Definition: status.c:387
&#39;IMAP&#39; Mailbox type
Definition: magic.h:42
struct TagHead tags
for drivers that support server tagging
Definition: email.h:109
void pop_fetch_mail(void)
Fetch messages and save them in $spoolfile.
Definition: pop.c:584
WHERE bool BrailleFriendly
Config: Move the cursor to the beginning of the line.
Definition: globals.h:207
int menu
menu definition for keymap entries.
Definition: menu.h:64
static void resort_index(struct Menu *menu)
Resort the index.
Definition: index.c:352
#define MUTT_READONLY
open in read-only mode
Definition: mx.h:51
#define LONG_STRING
Definition: string2.h:36
#define mutt_uncollapse_thread(x, y)
Definition: mutt_thread.h:60
int mutt_monitor_add(struct Mailbox *m)
Add a watch for a mailbox.
Definition: monitor.c:440
struct Mailbox * mx_mbox_find2(const char *path)
XXX.
Definition: mx.c:1714
int nntp_check_children(struct Context *ctx, const char *msgid)
Fetch children of article with the Message-ID.
Definition: nntp.c:2297
#define SEND_POSTPONED
Definition: send.h:86
int mutt_mailbox_check(int force)
Check all AllMailboxes for new mail.
Definition: mailbox.c:538
bool mutt_link_threads(struct Email *cur, struct Email *last, struct Context *ctx)
Forcibly link threads together.
Definition: mutt_thread.c:1483
#define mutt_enter_fname(A, B, C, D)
Definition: curs_lib.h:77
A progress bar.
Definition: progress.h:38
void(* menu_make_entry)(char *buf, size_t buflen, struct Menu *menu, int line)
Format a item for a menu.
Definition: menu.h:96
void km_error_key(int menu)
Handle an unbound key sequence.
Definition: keymap.c:1037
struct Email ** hdrs
Definition: mailbox.h:93
int mutt_thread_set_flag(struct Email *e, int flag, int bf, int subthread)
Set a flag on an entire thread.
Definition: flags.c:371
struct Mapping IndexNewsHelp[]
Definition: index.c:894
int vcount
the number of virtual messages
Definition: mailbox.h:96
char * mutt_compile_help(char *buf, size_t buflen, int menu, const struct Mapping *items)
Create the text for the help menu.
Definition: help.c:115
bool UncollapseJump
Config: When opening a thread, jump to the next unread message.
Definition: index.c:107
delete a message
Definition: mailbox.h:61
void imap_logout_all(void)
close all open connections
Definition: imap.c:680
static void collapse_all(struct Menu *menu, int toggle)
Collapse/uncollapse all threads.
Definition: index.c:190
int mutt_change_flag(struct Email *e, int bf)
Change the flag on a Message.
Definition: flags.c:427
#define CHECK_ACL(aclbit, action)
Definition: index.c:155
void ci_bounce_message(struct Email *e)
Bounce an email.
Definition: commands.c:288
static int ci_previous_undeleted(int msgno)
Find the previous undeleted email.
Definition: index.c:263
char * mutt_expand_path(char *buf, size_t buflen)
Create the canonical path.
Definition: muttlib.c:157
bool tagged
Definition: email.h:42
#define CHECK_VISIBLE
Definition: index.c:139
bool read
Definition: email.h:49
int mutt_save_message(struct Email *e, bool delete, bool decode, bool decrypt)
Save an email.
Definition: commands.c:882
#define mutt_collapse_thread(x, y)
Definition: mutt_thread.h:59
bool mutt_check_traditional_pgp(struct Email *e, int *redraw)
Check if a message has inline PGP content.
Definition: commands.c:1238
struct Mailbox * mailbox
Definition: context.h:50
#define CHECK_IN_MAILBOX
Definition: index.c:117
bool old
Definition: email.h:48
void mutt_flush_macro_to_endcond(void)
Drop a macro from the input buffer.
Definition: curs_lib.c:724
enum MailboxType magic
mailbox type
Definition: mailbox.h:99
bool PgpAutoDecode
Config: Automatically decrypt PGP messages.
Definition: index.c:106
bool readonly
don&#39;t allow changes to the mailbox
Definition: mailbox.h:113
void mutt_window_clearline(struct MuttWindow *win, int row)
Clear a row of a Window.
Definition: mutt_window.c:69
int mutt_resend_message(FILE *fp, struct Context *ctx, struct Email *cur)
Resend an email.
Definition: send.c:1430
int mutt_parent_message(struct Context *ctx, struct Email *e, bool find_root)
Find the parent of a message.
Definition: mutt_thread.c:1141
WHERE char * NewsServer
Config: (nntp) Url of the news server.
Definition: globals.h:132
void mutt_what_key(void)
Ask the user to press a key.
Definition: keymap.c:1410
int LastKey
contains the last key the user pressed
Definition: keymap.c:144
void mutt_tag_set_flag(int flag, int bf)
Set flag on tagged messages.
Definition: flags.c:355
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:1410
int mutt_view_message(struct Context *ctx, struct Email *e)
Edit a message.
Definition: editmsg.c:309
WHERE bool DeleteUntag
Config: Untag messages when they are marked for deletion.
Definition: globals.h:211
void mutt_shell_escape(void)
invoke a command in a subshell
Definition: commands.c:703
char * group
Definition: nntp.h:141
Tagged messages.
Definition: mutt.h:123
WHERE SIG_ATOMIC_VOLATILE_T SigWinch
true after SIGWINCH is received
Definition: globals.h:91
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
WHERE bool Resolve
Config: Move to the next email whenever a command modifies an email.
Definition: globals.h:248
void mutt_break_thread(struct Email *e)
Break the email Thread.
Definition: thread.c:217
void(* menu_custom_redraw)(struct Menu *menu)
Redraw the menu.
Definition: menu.h:125
#define SEND_LIST_REPLY
Definition: send.h:84
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:141
static int mx_toggle_write(struct Mailbox *m)
Toggle the mailbox&#39;s readonly flag.
Definition: index.c:323
void * mdata
driver specific data
Definition: mailbox.h:130
bool CollapseAll
Config: Collapse all threads when entering a folder.
Definition: index.c:102
char * nm_uri_from_query(struct Mailbox *m, char *buf, size_t buflen)
Turn a query into a URI.
void mutt_window_reflow(void)
Resize the Windows to fit the screen.
Definition: mutt_window.c:222
bool quasi_deleted
deleted from neomutt, but not modified on disk
Definition: email.h:45
#define SEND_KEY
Definition: send.h:89
static int ci_next_undeleted(int msgno)
Find the next undeleted email.
Definition: index.c:249
int mx_mbox_close(struct Context **pctx, int *index_hint)
Save changes and close mailbox.
Definition: mx.c:568
void mutt_refresh(void)
Force a refresh of the screen.
Definition: curs_lib.c:99
void nm_db_longrun_done(struct Mailbox *m)
Finish a long transaction.
Definition: nm_db.c:301
static int ci_first_message(void)
Get index of first new message.
Definition: index.c:278
Messages to be un-tagged.
Definition: mutt.h:124
void mutt_sort_headers(struct Context *ctx, bool init)
Sort emails by their headers.
Definition: sort.c:360
#define mutt_mktemp(a, b)
Definition: muttlib.h:71
WHERE bool OptAttachMsg
(pseudo) used by attach-message
Definition: options.h:31
int mx_mbox_sync(struct Context *ctx, int *index_hint)
Save changes to mailbox.
Definition: mx.c:919
A mailbox.
Definition: mailbox.h:76
#define PATH_MAX
Definition: mutt.h:46
struct MuttWindow * MuttIndexWindow
Index Window.
Definition: mutt_window.c:39
int query_quadoption(int opt, const char *prompt)
Ask the user a quad-question.
Definition: init.c:3227
New messages.
Definition: mutt.h:113
int top
entry that is the top of the current page
Definition: menu.h:84
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:370
#define SORT_THREADS
Sort by email threads.
Definition: sort.h:51
void mx_fastclose_mailbox(struct Context *ctx)
free up memory associated with the mailbox context
Definition: mx.c:404
#define CAN_COLLAPSE(header)
Definition: index.c:176
Messages to be purged (bypass trash)
Definition: mutt.h:120
int nntp_check_msgid(struct Context *ctx, const char *msgid)
Fetch article by Message-ID.
Definition: nntp.c:2225
void nm_query_window_forward(void)
Function to move the current search window forward in time.
int km_bind(char *s, int menu, int op, char *macro, char *desc)
Bind a key to a macro.
Definition: keymap.c:393
int mutt_select_sort(int reverse)
Ask the user for a sort method.
Definition: commands.c:629
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:742
#define mutt_next_subthread(x)
Definition: mutt_thread.h:55
WHERE bool ImapPeek
Config: (imap) Don&#39;t mark messages as read when fetching them from the server.
Definition: globals.h:228
#define MUTT_MAILBOX_CHECK_FORCE
Definition: mailbox.h:160
#define UNREAD(h)
Definition: index.c:173
bool message_is_tagged(struct Context *ctx, int index)
Is a message in the index tagged (and within limit)
Definition: curs_lib.c:1236
#define mutt_set_flag(a, b, c, d)
Definition: protos.h:54
bool collapsed
is this message part of a collapsed thread?
Definition: email.h:75
bool quiet
inhibit status messages?
Definition: mailbox.h:112
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:1390
bool message_is_visible(struct Context *ctx, int index)
Is a message in the index within limit.
Definition: curs_lib.c:1220
int msg_tagged
how many messages are tagged?
Definition: mailbox.h:91
#define CHECK_READONLY
Definition: index.c:147
WHERE bool ReadOnly
Config: Open folders in read-only mode.
Definition: globals.h:247
#define SEND_NEWS
Definition: send.h:95
void nntp_mailbox(struct Mailbox *m, char *buf, size_t buflen)
Get first newsgroup with new messages.
Definition: newsrc.c:1362
WHERE bool OptSearchInvalid
(pseudo) used to invalidate the search pat
Definition: options.h:49
int mutt_messages_in_thread(struct Mailbox *m, struct Email *e, int flag)
Count the messages in a thread.
Definition: mutt_thread.c:1397
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:350
void update_index(struct Menu *menu, struct Context *ctx, int check, int oldcount, int index_hint)
Update the index.
Definition: index.c:505
WHERE bool OptRedrawTree
(pseudo) redraw the thread tree
Definition: options.h:47
#define STAILQ_NEXT(elm, field)
Definition: queue.h:398
#define mutt_get_field(A, B, C, D)
Definition: curs_lib.h:78
#define SEND_REPLY
Definition: send.h:82
#define MUTT_PAGER_LOGS
Logview mode.
Definition: pager.h:56
struct Hash * mutt_make_id_hash(struct Mailbox *m)
Create a Hash Table for message-ids.
Definition: mutt_thread.c:1439
NNTP-specific Mailbox data -.
Definition: nntp.h:139
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:190
char * driver_tags_get_with_hidden(struct TagHead *head)
Get tags with hiddens.
Definition: tags.c:163
void mutt_startup_shutdown_hook(int type)
Execute any startup/shutdown hooks.
Definition: hook.c:706
int mutt_window_move(struct MuttWindow *win, int row, int col)
Move the cursor in a Window.
Definition: mutt_window.c:162
WHERE bool ArrowCursor
Config: Use an arrow &#39;->&#39; instead of highlighting in the index.
Definition: globals.h:199
void mutt_help(int menu)
Display the help menu.
Definition: help.c:438
void mutt_clear_pager_position(void)
Reset the pager&#39;s viewing position.
Definition: pager.c:1848
int(* menu_color)(int line)
Calculate the colour for a line of the menu.
Definition: menu.h:120
int max
the number of entries in the menu
Definition: menu.h:62
#define APPLICATION_PGP
Definition: ncrypt.h:129
Messages that have been read.
Definition: mutt.h:116
char path[PATH_MAX]
Definition: mailbox.h:78
char * MarkMacroPrefix
Config: Prefix for macros using &#39;<mark-message>&#39;.
Definition: index.c:105
Messages in limited view.
Definition: mutt.h:125
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:548
static int main_change_folder(struct Menu *menu, int op, struct Mailbox *m, char *buf, size_t buflen, int *oldcount, int *index_hint)
Change to a different mailbox.
Definition: index.c:554
int * v2r
mapping from virtual to real msgno
Definition: mailbox.h:95
bool mutt_mailbox_list(void)
List the mailboxes with new mail.
Definition: mailbox.c:598
char * mutt_str_strcat(char *buf, size_t buflen, const char *s)
Concatenate two strings.
Definition: string.c:402
int imap_check_mailbox(struct Mailbox *m, bool force)
use the NOOP or IDLE command to poll for new mail
Definition: imap.c:1193
#define mutt_thread_next_unread(x, y)
Definition: mutt_thread.h:64
int offset
row offset within the window to start the index
Definition: menu.h:65
#define SEND_GROUP_REPLY
Definition: send.h:83
#define mutt_previous_subthread(x)
Definition: mutt_thread.h:56
char * data
Definition: list.h:35
#define STRING
Definition: string2.h:35
WHERE unsigned char Quit
Config: Prompt before exiting NeoMutt.
Definition: globals.h:190
bool flagged
marked important?
Definition: email.h:41
void mutt_browser_select_dir(const char *f)
Remember the last directory selected.
Definition: browser.c:1070
#define mutt_curs_set(x)
Definition: mutt_curses.h:93
WHERE short Sort
Config: Sort method for the index.
Definition: sort.h:58
char * mutt_str_strdup(const char *str)
Copy a string, safely.
Definition: string.c:384
change the &#39;seen&#39; status of a message
Definition: mailbox.h:68
bool collapsed
are all threads collapsed?
Definition: context.h:48
bool deleted
Definition: email.h:43
int mutt_file_fclose(FILE **f)
Close a FILE handle (and NULL the pointer)
Definition: file.c:149
#define mutt_error(...)
Definition: logging.h:88
static const struct Mapping IndexHelp[]
Definition: index.c:881
int ci_send_message(int flags, struct Email *msg, char *tempfile, struct Context *ctx, struct Email *cur)
Send an email.
Definition: send.c:1530
void mutt_query_menu(char *buf, size_t buflen)
Show the user the results of a Query.
Definition: query.c:601
int mutt_str_strcasecmp(const char *a, const char *b)
Compare two strings ignoring case, safely.
Definition: string.c:625
void mutt_timeout_hook(void)
Execute any timeout hooks.
Definition: hook.c:667
WHERE char * NewMailCommand
Config: External command to run when new mail arrives.
Definition: globals.h:140
int mutt_do_pager(const char *banner, const char *tempfile, int do_color, struct Pager *info)
Display some page-able text to the user.
Definition: curs_lib.c:570
bool ChangeFolderNext
Config: Suggest the next folder, rather than the first when using &#39;<change-folder>&#39;.
Definition: index.c:101
int index
the absolute (unsorted) message number
Definition: email.h:87
#define FREE(x)
Definition: memory.h:46
WHERE bool BeepNew
Config: Make a noise when new mail arrives.
Definition: globals.h:206
#define STAILQ_EMPTY(head)
Definition: queue.h:346
Flagged messages.
Definition: mutt.h:122
Messages to be un-deleted.
Definition: mutt.h:119
int mutt_label_message(struct Email *e)
Let the user label a message.
Definition: mutt_header.c:127
struct MuttWindow * MuttMessageWindow
Message Window.
Definition: mutt_window.c:41
void mutt_alias_create(struct Envelope *cur, struct Address *iaddr)
Create a new Alias from an Envelope or an Address.
Definition: alias.c:367
#define mutt_previous_thread(x)
Definition: mutt_thread.h:54
bool mutt_mailbox_notify(void)
Notify the user if there&#39;s new mail.
Definition: mailbox.c:677
write to a message (for flagging, or linking threads)
Definition: mailbox.h:69
int mutt_display_message(struct Email *cur)
Display a message in the pager.
Definition: commands.c:98
bool changed
mailbox has been modified
Definition: mailbox.h:108
void nm_db_longrun_init(struct Mailbox *m, bool writable)
Start a long transaction.
Definition: nm_db.c:286
#define CURHDR
Definition: index.c:172
#define mutt_debug(LEVEL,...)
Definition: logging.h:85
int bool_str_toggle(struct ConfigSet *cs, const char *name, struct Buffer *err)
Toggle the value of a bool.
Definition: bool.c:247
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:1427
WHERE bool AutoTag
Config: Automatically apply actions to all tagged messages.
Definition: globals.h:204
WHERE int NmQueryWindowDuration
Config: (notmuch) Time duration of the current search window.
Definition: globals.h:176
#define CHECK_MSGCOUNT
Definition: index.c:125
int current
current entry
Definition: menu.h:61
A List node for strings.
Definition: list.h:33
int mutt_edit_content_type(struct Email *e, struct Body *b, FILE *fp)
Edit the content type of an attachment.
Definition: commands.c:1106
mailbox was reopened
Definition: mx.h:74
void mutt_set_virtual(struct Context *ctx)
Set the virtual index number of all the messages in a mailbox.
Definition: mutt_thread.c:1187
char * pattern
limit pattern string
Definition: context.h:39
int mutt_search_command(int cur, int op)
Perform a search.
Definition: pattern.c:2376
#define STAILQ_FIRST(head)
Definition: queue.h:348
#define WithCrypto
Definition: ncrypt.h:154
#define SORT_MASK
Mask for the sort id.
Definition: sort.h:77
WHERE bool OptNews
(pseudo) used to change reader mode
Definition: options.h:42
Pager pager (email viewer)
Definition: keymap.h:74
char * help
quickref for the current menu
Definition: menu.h:59
WHERE char * NmQueryWindowCurrentSearch
Config: (notmuch) Current search parameters.
Definition: globals.h:177
int mutt_system(const char *cmd)
Run an external command.
Definition: system.c:50
struct Hash * id_hash
hash table by msg id
Definition: mailbox.h:121
Index panel (list of emails)
Definition: keymap.h:73
struct Email * last_tag
last tagged msg.
Definition: context.h:41
void mutt_draw_tree(struct Context *ctx)
Draw a tree of threaded emails.
Definition: mutt_thread.c:286
void nm_db_debug_check(struct Mailbox *m)
Check if the database is open.
Definition: nm_db.c:313
struct NntpAccountData * CurrentNewsSrv
Current NNTP news server.
Definition: nntp.c:80
const char * mutt_make_version(void)
Generate the NeoMutt version string.
Definition: muttlib.c:1492
int mx_mbox_check(struct Context *ctx, int *index_hint)
Check for new mail - Wrapper for MxOps::mbox_check()
Definition: mx.c:1117
WHERE unsigned char PostModerated
Config: (nntp) Allow posting to moderated newsgroups.
Definition: globals.h:195
void mutt_context_free(struct Context **ctx)
Free a Context.
Definition: mailbox.c:730

+ Here is the caller graph for this function:

void mutt_set_header_color ( struct Mailbox m,
struct Email curhdr 
)

Select a colour for a message.

Parameters
mMailbox
curhdrHeader of message

Definition at line 3514 of file index.c.

3515 {
3516  struct ColorLine *color = NULL;
3517  struct PatternCache cache = { 0 };
3518 
3519  if (!curhdr)
3520  return;
3521 
3522  STAILQ_FOREACH(color, &ColorIndexList, entries)
3523  {
3524  if (mutt_pattern_exec(color->color_pattern, MUTT_MATCH_FULL_ADDRESS, m, curhdr, &cache))
3525  {
3526  curhdr->pair = color->pair;
3527  return;
3528  }
3529  }
3530  curhdr->pair = ColorDefs[MT_COLOR_NORMAL];
3531 }
Match the full address.
Definition: pattern.h:69
Plain text.
Definition: mutt_curses.h:130
struct Pattern * color_pattern
compiled pattern to speed up index color calculation
Definition: mutt_curses.h:183
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:350
int ColorDefs[MT_COLOR_MAX]
Array of all fixed colours, see enum ColorId.
Definition: color.c:51
Cache commonly-used patterns.
Definition: pattern.h:80
int mutt_pattern_exec(struct Pattern *pat, enum PatternExecFlag flags, struct Mailbox *m, struct Email *e, struct PatternCache *cache)
Match a pattern against an email header.
Definition: pattern.c:1837
struct ColorLineHead ColorIndexList
List of default colours applied to the index.
Definition: color.c:57
int pair
color-pair to use when displaying in the index
Definition: email.h:81
A regular expression and a color to highlight a line.
Definition: mutt_curses.h:178

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

bool mutt_reply_listener ( const struct ConfigSet cs,
struct HashElem he,
const char *  name,
enum ConfigEvent  ev 
)

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

Definition at line 3536 of file index.c.

3538 {
3539  if (mutt_str_strcmp(name, "reply_regex") != 0)
3540  return true;
3541 
3542  if (!Context)
3543  return true;
3544 
3545  regmatch_t pmatch[1];
3546 
3547  for (int i = 0; i < Context->mailbox->msg_count; i++)
3548  {
3549  struct Envelope *e = Context->mailbox->hdrs[i]->env;
3550  if (!e || !e->subject)
3551  continue;
3552 
3553  if (ReplyRegex && ReplyRegex->regex &&
3554  (regexec(ReplyRegex->regex, e->subject, 1, pmatch, 0) == 0))
3555  {
3556  e->real_subj = e->subject + pmatch[0].rm_eo;
3557  continue;
3558  }
3559 
3560  e->real_subj = e->subject;
3561  }
3562 
3563  OptResortInit = true; /* trigger a redraw of the index */
3564  return true;
3565 }
The "current" mailbox.
Definition: context.h:36
int msg_count
total number of messages
Definition: mailbox.h:86
regex_t * regex
compiled expression
Definition: regex3.h:60
char * real_subj
offset of the real subject
Definition: envelope.h:45
struct Regex * ReplyRegex
Config: Regex to match message reply subjects like "re: ".
Definition: email_globals.c:35
struct Email ** hdrs
Definition: mailbox.h:93
struct Mailbox * mailbox
Definition: context.h:50
const char * name
Definition: pgpmicalg.c:42
struct Envelope * env
envelope information
Definition: email.h:91
WHERE bool OptResortInit
(pseudo) used to force the next resort to be from scratch
Definition: options.h:48
char * subject
Definition: envelope.h:44
int mutt_str_strcmp(const char *a, const char *b)
Compare two strings, safely.
Definition: string.c:612
The header of an email.
Definition: envelope.h:32

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

Variable Documentation

bool ChangeFolderNext

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

Definition at line 101 of file index.c.

bool CollapseAll

Config: Collapse all threads when entering a folder.

Definition at line 102 of file index.c.

bool CollapseFlagged

Config: Prevent the collapse of threads with flagged emails.

Definition at line 103 of file index.c.

bool CollapseUnread

Config: Prevent the collapse of threads with unread emails.

Definition at line 104 of file index.c.

char* MarkMacroPrefix

Config: Prefix for macros using '<mark-message>'.

Definition at line 105 of file index.c.

bool PgpAutoDecode

Config: Automatically decrypt PGP messages.

Definition at line 106 of file index.c.

bool UncollapseJump

Config: When opening a thread, jump to the next unread message.

Definition at line 107 of file index.c.

bool UncollapseNew

Config: Open collapsed threads when new mail arrives.

Definition at line 108 of file index.c.

const char* No_mailbox_is_open = N_("No mailbox is open")
static

Definition at line 110 of file index.c.

const char* There_are_no_messages = N_("There are no messages")
static

Definition at line 111 of file index.c.

const char* Mailbox_is_read_only = N_("Mailbox is read-only")
static

Definition at line 112 of file index.c.

const char* Function_not_permitted_in_attach_message_mode
static
Initial value:
=
N_("Function not permitted in attach-message mode")
#define N_(a)
Definition: message.h:32

Definition at line 113 of file index.c.

const char* NoVisible = N_("No visible messages")
static

Definition at line 115 of file index.c.

const struct Mapping IndexHelp[]
static
Initial value:
= {
{ N_("Quit"), OP_QUIT },
{ N_("Del"), OP_DELETE },
{ N_("Undel"), OP_UNDELETE },
{ N_("Save"), OP_SAVE },
{ N_("Mail"), OP_MAIL },
{ N_("Reply"), OP_REPLY },
{ N_("Group"), OP_GROUP_REPLY },
{ N_("Help"), OP_HELP },
{ NULL, 0 },
}
#define N_(a)
Definition: message.h:32

Definition at line 881 of file index.c.

struct Mapping IndexNewsHelp[]
Initial value:
= {
{ N_("Quit"), OP_QUIT },
{ N_("Del"), OP_DELETE },
{ N_("Undel"), OP_UNDELETE },
{ N_("Save"), OP_SAVE },
{ N_("Post"), OP_POST },
{ N_("Followup"), OP_FOLLOWUP },
{ N_("Catchup"), OP_CATCHUP },
{ N_("Help"), OP_HELP },
{ NULL, 0 },
}
#define N_(a)
Definition: message.h:32

Definition at line 894 of file index.c.