NeoMutt  2021-02-05-89-gabe350
Teaching an old dog new tricks
DOXYGEN
pager.c File Reference
#include "config.h"
#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <inttypes.h>
#include <limits.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include <wchar.h>
#include "mutt/lib.h"
#include "config/lib.h"
#include "email/lib.h"
#include "core/lib.h"
#include "alias/lib.h"
#include "gui/lib.h"
#include "mutt.h"
#include "lib.h"
#include "index/lib.h"
#include "ncrypt/lib.h"
#include "send/lib.h"
#include "commands.h"
#include "context.h"
#include "format_flags.h"
#include "hdrline.h"
#include "hook.h"
#include "init.h"
#include "keymap.h"
#include "mutt_attach.h"
#include "mutt_globals.h"
#include "mutt_header.h"
#include "mutt_logging.h"
#include "mutt_mailbox.h"
#include "mutt_menu.h"
#include "muttlib.h"
#include "mx.h"
#include "opcodes.h"
#include "options.h"
#include "protos.h"
#include "recvattach.h"
#include "recvcmd.h"
#include "status.h"
#include "sidebar/lib.h"
#include "nntp/lib.h"
#include "nntp/mdata.h"
#include <libintl.h>
+ Include dependency graph for pager.c:

Go to the source code of this file.

Data Structures

struct  QClass
 Style of quoted text. More...
 
struct  TextSyntax
 Highlighting for a line of text. More...
 
struct  Line
 A line of text in the pager. More...
 
struct  AnsiAttr
 An ANSI escape sequence. More...
 
struct  Resize
 Keep track of screen resizing. More...
 
struct  PagerRedrawData
 Keep track when the pager needs redrawing. More...
 

Macros

#define ANSI_NO_FLAGS   0
 No flags are set. More...
 
#define ANSI_OFF   (1 << 0)
 Turn off colours and attributes. More...
 
#define ANSI_BLINK   (1 << 1)
 Blinking text. More...
 
#define ANSI_BOLD   (1 << 2)
 Bold text. More...
 
#define ANSI_UNDERLINE   (1 << 3)
 Underlined text. More...
 
#define ANSI_REVERSE   (1 << 4)
 Reverse video. More...
 
#define ANSI_COLOR   (1 << 5)
 Use colours. More...
 
#define IS_HEADER(x)   ((x) == MT_COLOR_HEADER || (x) == MT_COLOR_HDRDEFAULT)
 
#define IsAttach(pager)   (pager && (pager)->body)
 
#define IsMsgAttach(pager)   (pager && (pager)->fp && (pager)->body && (pager)->body->email)
 
#define IsEmail(pager)   (pager && (pager)->email && !(pager)->body)
 

Typedefs

typedef uint8_t AnsiFlags
 Flags, e.g. ANSI_OFF. More...
 

Functions

static bool assert_pager_mode (bool test)
 Check that pager is in correct mode. More...
 
static bool assert_mailbox_writable (struct Mailbox *mailbox)
 checks that mailbox is writable More...
 
static bool assert_attach_msg_mode (bool attach_msg)
 Check that attach message mode is on. More...
 
static bool assert_mailbox_permissions (struct Mailbox *m, AclFlags acl, char *action)
 checks that mailbox is has requested acl flags set More...
 
static int check_sig (const char *s, struct Line *info, int offset)
 Check for an email signature. More...
 
static int comp_syntax_t (const void *m1, const void *m2)
 Search for a Syntax using bsearch. More...
 
static void resolve_color (struct Line *line_info, int n, int cnt, PagerFlags flags, int special, struct AnsiAttr *a)
 Set the colour for a line of text. More...
 
static void append_line (struct Line *line_info, int n, int cnt)
 Add a new Line to the array. More...
 
static void class_color_new (struct QClass *qc, int *q_level)
 Create a new quoting colour. More...
 
static void shift_class_colors (struct QClass *quote_list, struct QClass *new_class, int index, int *q_level)
 Insert a new quote colour class into a list. More...
 
static void cleanup_quote (struct QClass **quote_list)
 Free a quote list. More...
 
static struct QClassclassify_quote (struct QClass **quote_list, const char *qptr, size_t length, bool *force_redraw, int *q_level)
 Find a style for a string. More...
 
static int check_marker (const char *q, const char *p)
 Check that the unique marker is present. More...
 
static int check_attachment_marker (const char *p)
 Check that the unique marker is present. More...
 
static int check_protected_header_marker (const char *p)
 Check that the unique marker is present. More...
 
int mutt_is_quote_line (char *line, regmatch_t *pmatch)
 Is a line of message text a quote? More...
 
static void resolve_types (char *buf, char *raw, struct Line *line_info, int n, int last, struct QClass **quote_list, int *q_level, bool *force_redraw, bool q_classify)
 Determine the style for a line of text. More...
 
static bool is_ansi (const char *str)
 Is this an ANSI escape sequence? More...
 
static int grok_ansi (unsigned char *buf, int pos, struct AnsiAttr *a)
 Parse an ANSI escape sequence. More...
 
void mutt_buffer_strip_formatting (struct Buffer *dest, const char *src, bool strip_markers)
 Removes ANSI and backspace formatting. More...
 
static int fill_buffer (FILE *fp, LOFF_T *last_pos, LOFF_T offset, unsigned char **buf, unsigned char **fmt, size_t *blen, int *buf_ready)
 Fill a buffer from a file. More...
 
static int format_line (struct Line **line_info, int n, unsigned char *buf, PagerFlags flags, struct AnsiAttr *pa, int cnt, int *pspace, int *pvch, int *pcol, int *pspecial, int width)
 Display a line of text in the pager. More...
 
static int display_line (FILE *fp, LOFF_T *last_pos, struct Line **line_info, int n, int *last, int *max, PagerFlags flags, struct QClass **quote_list, int *q_level, bool *force_redraw, regex_t *search_re, struct MuttWindow *win_pager)
 Print a line on screen. More...
 
static int up_n_lines (int nlines, struct Line *info, int cur, bool hiding)
 Reposition the pager's view up by n lines. More...
 
void mutt_clear_pager_position (void)
 Reset the pager's viewing position. More...
 
static void pager_custom_redraw (struct Menu *pager_menu)
 Redraw the pager window - Implements Menu::custom_redraw() More...
 
int mutt_pager (const char *banner, const char *fname, PagerFlags flags, struct Pager *extra)
 Display a file, or help, in a window. More...
 

Variables

static int TopLine = 0
 
static struct EmailOldEmail = NULL
 
static bool InHelp = false
 
static int braille_line = -1
 
static int braille_col = -1
 
static struct ResizeResize = NULL
 
static const char * Not_available_in_this_menu
 
static const char * Mailbox_is_read_only = N_("Mailbox is read-only")
 
static const char * Function_not_permitted_in_attach_message_mode
 
static const struct Mapping PagerHelp []
 Help Bar for the Pager's Help Page. More...
 
static const struct Mapping PagerHelpHelp []
 Help Bar for the Help Page itself. More...
 
static const struct Mapping PagerNormalHelp []
 Help Bar for the Pager of a normal Mailbox. More...
 
static const struct Mapping PagerNewsHelp []
 Help Bar for the Pager of an NNTP Mailbox. More...
 

Detailed Description

GUI display a file/email/help in a viewport with paging

Authors
  • Michael R. Elkins
  • R Primus

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 pager.c.

Macro Definition Documentation

◆ ANSI_NO_FLAGS

#define ANSI_NO_FLAGS   0

No flags are set.

Definition at line 87 of file pager.c.

◆ ANSI_OFF

#define ANSI_OFF   (1 << 0)

Turn off colours and attributes.

Definition at line 88 of file pager.c.

◆ ANSI_BLINK

#define ANSI_BLINK   (1 << 1)

Blinking text.

Definition at line 89 of file pager.c.

◆ ANSI_BOLD

#define ANSI_BOLD   (1 << 2)

Bold text.

Definition at line 90 of file pager.c.

◆ ANSI_UNDERLINE

#define ANSI_UNDERLINE   (1 << 3)

Underlined text.

Definition at line 91 of file pager.c.

◆ ANSI_REVERSE

#define ANSI_REVERSE   (1 << 4)

Reverse video.

Definition at line 92 of file pager.c.

◆ ANSI_COLOR

#define ANSI_COLOR   (1 << 5)

Use colours.

Definition at line 93 of file pager.c.

◆ IS_HEADER

#define IS_HEADER (   x)    ((x) == MT_COLOR_HEADER || (x) == MT_COLOR_HDRDEFAULT)

Definition at line 260 of file pager.c.

◆ IsAttach

#define IsAttach (   pager)    (pager && (pager)->body)

Definition at line 309 of file pager.c.

◆ IsMsgAttach

#define IsMsgAttach (   pager)    (pager && (pager)->fp && (pager)->body && (pager)->body->email)

Definition at line 310 of file pager.c.

◆ IsEmail

#define IsEmail (   pager)    (pager && (pager)->email && !(pager)->body)

Definition at line 312 of file pager.c.

Typedef Documentation

◆ AnsiFlags

typedef uint8_t AnsiFlags

Flags, e.g. ANSI_OFF.

Definition at line 86 of file pager.c.

Function Documentation

◆ assert_pager_mode()

static bool assert_pager_mode ( bool  test)
inlinestatic

Check that pager is in correct mode.

Parameters
testTest condition
Return values
trueExpected mode is set
falsePager is is some other mode
Note
On failure, the input will be flushed and an error message displayed

Definition at line 322 of file pager.c.

323 {
324  if (test)
325  return true;
326 
327  mutt_flushinp();
329  return false;
330 }
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ assert_mailbox_writable()

static bool assert_mailbox_writable ( struct Mailbox mailbox)
inlinestatic

checks that mailbox is writable

Parameters
mailboxmailbox to check
Return values
trueMailbox is writable
falseMailbox is not writable
Note
On failure, the input will be flushed and an error message displayed

Definition at line 340 of file pager.c.

341 {
342  assert(mailbox);
343  if (mailbox->readonly)
344  {
345  mutt_flushinp();
347  return false;
348  }
349  return true;
350 }
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ assert_attach_msg_mode()

static bool assert_attach_msg_mode ( bool  attach_msg)
inlinestatic

Check that attach message mode is on.

Parameters
attach_msgGlobally-named boolean pseudo-option
Return values
trueAttach message mode in on
falseAttach message mode is off
Note
On true, the input will be flushed and an error message displayed

Definition at line 360 of file pager.c.

361 {
362  if (attach_msg)
363  {
364  mutt_flushinp();
366  return true;
367  }
368  return false;
369 }
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ assert_mailbox_permissions()

static bool assert_mailbox_permissions ( struct Mailbox m,
AclFlags  acl,
char *  action 
)
inlinestatic

checks that mailbox is has requested acl flags set

Parameters
mMailbox to check
aclAclFlags required to be set on a given mailbox
actionString to augment error message
Return values
trueMailbox has necessary flags set
falseMailbox does not have necessary flags set
Note
On failure, the input will be flushed and an error message displayed

Definition at line 381 of file pager.c.

382 {
383  assert(m);
384  assert(action);
385  if (m->rights & acl)
386  {
387  return true;
388  }
389  mutt_flushinp();
390  /* L10N: %s is one of the CHECK_ACL entries below. */
391  mutt_error(_("%s: Operation not permitted by ACL"), action);
392  return false;
393 }
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ check_sig()

static int check_sig ( const char *  s,
struct Line info,
int  offset 
)
static

Check for an email signature.

Parameters
sText to examine
infoLine info array to update
offsetAn offset line to start the check from
Return values
0Success
-1Error

Definition at line 403 of file pager.c.

404 {
405  const unsigned int NUM_SIG_LINES = 4; // The amount of lines a signature takes
406  unsigned int count = 0;
407 
408  while ((offset > 0) && (count <= NUM_SIG_LINES))
409  {
410  if (info[offset].type != MT_COLOR_SIGNATURE)
411  break;
412  count++;
413  offset--;
414  }
415 
416  if (count == 0)
417  return -1;
418 
419  if (count > NUM_SIG_LINES)
420  {
421  /* check for a blank line */
422  while (*s)
423  {
424  if (!IS_SPACE(*s))
425  return 0;
426  s++;
427  }
428 
429  return -1;
430  }
431 
432  return 0;
433 }
+ Here is the caller graph for this function:

◆ comp_syntax_t()

static int comp_syntax_t ( const void *  m1,
const void *  m2 
)
static

Search for a Syntax using bsearch.

Parameters
m1Search key
m2Array member
Return values
-1m1 precedes m2
0m1 matches m2
1m2 precedes m1

Definition at line 443 of file pager.c.

444 {
445  const int *cnt = (const int *) m1;
446  const struct TextSyntax *stx = (const struct TextSyntax *) m2;
447 
448  if (*cnt < stx->first)
449  return -1;
450  if (*cnt >= stx->last)
451  return 1;
452  return 0;
453 }
+ Here is the caller graph for this function:

◆ resolve_color()

static void resolve_color ( struct Line line_info,
int  n,
int  cnt,
PagerFlags  flags,
int  special,
struct AnsiAttr a 
)
static

Set the colour for a line of text.

Parameters
line_infoLine info array
nLine Number (index into line_info)
cntIf true, this is a continuation line
flagsFlags, see PagerFlags
specialFlags, e.g. A_BOLD
aANSI attributes

Definition at line 464 of file pager.c.

466 {
467  int def_color; /* color without syntax highlight */
468  int color; /* final color */
469  static int last_color; /* last color set */
470  bool search = false;
471  int m;
472  struct TextSyntax *matching_chunk = NULL;
473 
474  if (cnt == 0)
475  last_color = -1; /* force attrset() */
476 
477  if (line_info[n].continuation)
478  {
479  if (!cnt && C_Markers)
480  {
482  mutt_window_addch('+');
483  last_color = Colors->defs[MT_COLOR_MARKERS];
484  }
485  m = (line_info[n].syntax)[0].first;
486  cnt += (line_info[n].syntax)[0].last;
487  }
488  else
489  m = n;
490  if (flags & MUTT_PAGER_LOGS)
491  {
492  def_color = Colors->defs[(line_info[n].syntax)[0].color];
493  }
494  else if (!(flags & MUTT_SHOWCOLOR))
495  def_color = Colors->defs[MT_COLOR_NORMAL];
496  else if (line_info[m].type == MT_COLOR_HEADER)
497  def_color = (line_info[m].syntax)[0].color;
498  else
499  def_color = Colors->defs[line_info[m].type];
500 
501  if ((flags & MUTT_SHOWCOLOR) && (line_info[m].type == MT_COLOR_QUOTED))
502  {
503  struct QClass *qc = line_info[m].quote;
504 
505  if (qc)
506  {
507  def_color = qc->color;
508 
509  while (qc && (qc->length > cnt))
510  {
511  def_color = qc->color;
512  qc = qc->up;
513  }
514  }
515  }
516 
517  color = def_color;
518  if ((flags & MUTT_SHOWCOLOR) && line_info[m].chunks)
519  {
520  matching_chunk = bsearch(&cnt, line_info[m].syntax, line_info[m].chunks,
521  sizeof(struct TextSyntax), comp_syntax_t);
522  if (matching_chunk && (cnt >= matching_chunk->first) &&
523  (cnt < matching_chunk->last))
524  {
525  color = matching_chunk->color;
526  }
527  }
528 
529  if ((flags & MUTT_SEARCH) && line_info[m].search_cnt)
530  {
531  matching_chunk = bsearch(&cnt, line_info[m].search, line_info[m].search_cnt,
532  sizeof(struct TextSyntax), comp_syntax_t);
533  if (matching_chunk && (cnt >= matching_chunk->first) &&
534  (cnt < matching_chunk->last))
535  {
537  search = 1;
538  }
539  }
540 
541  /* handle "special" bold & underlined characters */
542  if (special || a->attr)
543  {
544 #ifdef HAVE_COLOR
545  if ((a->attr & ANSI_COLOR))
546  {
547  if (a->pair == -1)
548  a->pair = mutt_color_alloc(Colors, a->fg, a->bg);
549  color = a->pair;
550  if (a->attr & ANSI_BOLD)
551  color |= A_BOLD;
552  }
553  else
554 #endif
555  if ((special & A_BOLD) || (a->attr & ANSI_BOLD))
556  {
557  if (Colors->defs[MT_COLOR_BOLD] && !search)
559  else
560  color ^= A_BOLD;
561  }
562  if ((special & A_UNDERLINE) || (a->attr & ANSI_UNDERLINE))
563  {
566  else
567  color ^= A_UNDERLINE;
568  }
569  else if (a->attr & ANSI_REVERSE)
570  {
571  color ^= A_REVERSE;
572  }
573  else if (a->attr & ANSI_BLINK)
574  {
575  color ^= A_BLINK;
576  }
577  else if (a->attr == ANSI_OFF)
578  {
579  a->attr = 0;
580  }
581  }
582 
583  if (color != last_color)
584  {
586  last_color = color;
587  }
588 }
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ append_line()

static void append_line ( struct Line line_info,
int  n,
int  cnt 
)
static

Add a new Line to the array.

Parameters
line_infoArray of Line info
nLine number to add
cnttrue, if line is a continuation

Definition at line 596 of file pager.c.

597 {
598  int m;
599 
600  line_info[n + 1].type = line_info[n].type;
601  (line_info[n + 1].syntax)[0].color = (line_info[n].syntax)[0].color;
602  line_info[n + 1].continuation = 1;
603 
604  /* find the real start of the line */
605  for (m = n; m >= 0; m--)
606  if (line_info[m].continuation == 0)
607  break;
608 
609  (line_info[n + 1].syntax)[0].first = m;
610  (line_info[n + 1].syntax)[0].last =
611  (line_info[n].continuation) ? cnt + (line_info[n].syntax)[0].last : cnt;
612 }
+ Here is the caller graph for this function:

◆ class_color_new()

static void class_color_new ( struct QClass qc,
int *  q_level 
)
static

Create a new quoting colour.

Parameters
[in]qcClass of quoted text
[in,out]q_levelQuote level

Definition at line 619 of file pager.c.

620 {
621  qc->index = (*q_level)++;
622  qc->color = Colors->quotes[qc->index % Colors->quotes_used];
623 }
+ Here is the caller graph for this function:

◆ shift_class_colors()

static void shift_class_colors ( struct QClass quote_list,
struct QClass new_class,
int  index,
int *  q_level 
)
static

Insert a new quote colour class into a list.

Parameters
[in]quote_listList of quote colours
[in]new_classNew quote colour to inset
[in]indexIndex to insert at
[in,out]q_levelQuote level

Definition at line 632 of file pager.c.

634 {
635  struct QClass *q_list = quote_list;
636  new_class->index = -1;
637 
638  while (q_list)
639  {
640  if (q_list->index >= index)
641  {
642  q_list->index++;
643  q_list->color = Colors->quotes[q_list->index % Colors->quotes_used];
644  }
645  if (q_list->down)
646  q_list = q_list->down;
647  else if (q_list->next)
648  q_list = q_list->next;
649  else
650  {
651  while (!q_list->next)
652  {
653  q_list = q_list->up;
654  if (!q_list)
655  break;
656  }
657  if (q_list)
658  q_list = q_list->next;
659  }
660  }
661 
662  new_class->index = index;
663  new_class->color = Colors->quotes[index % Colors->quotes_used];
664  (*q_level)++;
665 }
+ Here is the caller graph for this function:

◆ cleanup_quote()

static void cleanup_quote ( struct QClass **  quote_list)
static

Free a quote list.

Parameters
[out]quote_listQuote list to free

Definition at line 671 of file pager.c.

672 {
673  struct QClass *ptr = NULL;
674 
675  while (*quote_list)
676  {
677  if ((*quote_list)->down)
678  cleanup_quote(&((*quote_list)->down));
679  ptr = (*quote_list)->next;
680  FREE(&(*quote_list)->prefix);
681  FREE(quote_list);
682  *quote_list = ptr;
683  }
684 }
+ Here is the caller graph for this function:

◆ classify_quote()

static struct QClass* classify_quote ( struct QClass **  quote_list,
const char *  qptr,
size_t  length,
bool *  force_redraw,
int *  q_level 
)
static

Find a style for a string.

Parameters
[out]quote_listList of quote colours
[in]qptrString to classify
[in]lengthLength of string
[out]force_redrawSet to true if a screen redraw is needed
[out]q_levelQuoting level
Return values
ptrQuoting style

Definition at line 695 of file pager.c.

697 {
698  struct QClass *q_list = *quote_list;
699  struct QClass *qc = NULL, *tmp = NULL, *ptr = NULL, *save = NULL;
700  const char *tail_qptr = NULL;
701  int offset, tail_lng;
702  int index = -1;
703 
704  if (Colors->quotes_used <= 1)
705  {
706  /* not much point in classifying quotes... */
707 
708  if (!*quote_list)
709  {
710  qc = mutt_mem_calloc(1, sizeof(struct QClass));
711  qc->color = Colors->quotes[0];
712  *quote_list = qc;
713  }
714  return *quote_list;
715  }
716 
717  /* classify quoting prefix */
718  while (q_list)
719  {
720  if (length <= q_list->length)
721  {
722  /* case 1: check the top level nodes */
723 
724  if (mutt_strn_equal(qptr, q_list->prefix, length))
725  {
726  if (length == q_list->length)
727  return q_list; /* same prefix: return the current class */
728 
729  /* found shorter prefix */
730  if (!tmp)
731  {
732  /* add a node above q_list */
733  tmp = mutt_mem_calloc(1, sizeof(struct QClass));
734  tmp->prefix = mutt_mem_calloc(1, length + 1);
735  strncpy(tmp->prefix, qptr, length);
736  tmp->length = length;
737 
738  /* replace q_list by tmp in the top level list */
739  if (q_list->next)
740  {
741  tmp->next = q_list->next;
742  q_list->next->prev = tmp;
743  }
744  if (q_list->prev)
745  {
746  tmp->prev = q_list->prev;
747  q_list->prev->next = tmp;
748  }
749 
750  /* make q_list a child of tmp */
751  tmp->down = q_list;
752  q_list->up = tmp;
753 
754  /* q_list has no siblings for now */
755  q_list->next = NULL;
756  q_list->prev = NULL;
757 
758  /* update the root if necessary */
759  if (q_list == *quote_list)
760  *quote_list = tmp;
761 
762  index = q_list->index;
763 
764  /* tmp should be the return class too */
765  qc = tmp;
766 
767  /* next class to test; if tmp is a shorter prefix for another
768  * node, that node can only be in the top level list, so don't
769  * go down after this point */
770  q_list = tmp->next;
771  }
772  else
773  {
774  /* found another branch for which tmp is a shorter prefix */
775 
776  /* save the next sibling for later */
777  save = q_list->next;
778 
779  /* unlink q_list from the top level list */
780  if (q_list->next)
781  q_list->next->prev = q_list->prev;
782  if (q_list->prev)
783  q_list->prev->next = q_list->next;
784 
785  /* at this point, we have a tmp->down; link q_list to it */
786  ptr = tmp->down;
787  /* sibling order is important here, q_list should be linked last */
788  while (ptr->next)
789  ptr = ptr->next;
790  ptr->next = q_list;
791  q_list->next = NULL;
792  q_list->prev = ptr;
793  q_list->up = tmp;
794 
795  index = q_list->index;
796 
797  /* next class to test; as above, we shouldn't go down */
798  q_list = save;
799  }
800 
801  /* we found a shorter prefix, so certain quotes have changed classes */
802  *force_redraw = true;
803  continue;
804  }
805  else
806  {
807  /* shorter, but not a substring of the current class: try next */
808  q_list = q_list->next;
809  continue;
810  }
811  }
812  else
813  {
814  /* case 2: try subclassing the current top level node */
815 
816  /* tmp != NULL means we already found a shorter prefix at case 1 */
817  if (!tmp && mutt_strn_equal(qptr, q_list->prefix, q_list->length))
818  {
819  /* ok, it's a subclass somewhere on this branch */
820 
821  ptr = q_list;
822  offset = q_list->length;
823 
824  q_list = q_list->down;
825  tail_lng = length - offset;
826  tail_qptr = qptr + offset;
827 
828  while (q_list)
829  {
830  if (length <= q_list->length)
831  {
832  if (mutt_strn_equal(tail_qptr, (q_list->prefix) + offset, tail_lng))
833  {
834  /* same prefix: return the current class */
835  if (length == q_list->length)
836  return q_list;
837 
838  /* found shorter common prefix */
839  if (!tmp)
840  {
841  /* add a node above q_list */
842  tmp = mutt_mem_calloc(1, sizeof(struct QClass));
843  tmp->prefix = mutt_mem_calloc(1, length + 1);
844  strncpy(tmp->prefix, qptr, length);
845  tmp->length = length;
846 
847  /* replace q_list by tmp */
848  if (q_list->next)
849  {
850  tmp->next = q_list->next;
851  q_list->next->prev = tmp;
852  }
853  if (q_list->prev)
854  {
855  tmp->prev = q_list->prev;
856  q_list->prev->next = tmp;
857  }
858 
859  /* make q_list a child of tmp */
860  tmp->down = q_list;
861  tmp->up = q_list->up;
862  q_list->up = tmp;
863  if (tmp->up->down == q_list)
864  tmp->up->down = tmp;
865 
866  /* q_list has no siblings */
867  q_list->next = NULL;
868  q_list->prev = NULL;
869 
870  index = q_list->index;
871 
872  /* tmp should be the return class too */
873  qc = tmp;
874 
875  /* next class to test */
876  q_list = tmp->next;
877  }
878  else
879  {
880  /* found another branch for which tmp is a shorter prefix */
881 
882  /* save the next sibling for later */
883  save = q_list->next;
884 
885  /* unlink q_list from the top level list */
886  if (q_list->next)
887  q_list->next->prev = q_list->prev;
888  if (q_list->prev)
889  q_list->prev->next = q_list->next;
890 
891  /* at this point, we have a tmp->down; link q_list to it */
892  ptr = tmp->down;
893  while (ptr->next)
894  ptr = ptr->next;
895  ptr->next = q_list;
896  q_list->next = NULL;
897  q_list->prev = ptr;
898  q_list->up = tmp;
899 
900  index = q_list->index;
901 
902  /* next class to test */
903  q_list = save;
904  }
905 
906  /* we found a shorter prefix, so we need a redraw */
907  *force_redraw = true;
908  continue;
909  }
910  else
911  {
912  q_list = q_list->next;
913  continue;
914  }
915  }
916  else
917  {
918  /* longer than the current prefix: try subclassing it */
919  if (!tmp && mutt_strn_equal(tail_qptr, (q_list->prefix) + offset,
920  q_list->length - offset))
921  {
922  /* still a subclass: go down one level */
923  ptr = q_list;
924  offset = q_list->length;
925 
926  q_list = q_list->down;
927  tail_lng = length - offset;
928  tail_qptr = qptr + offset;
929 
930  continue;
931  }
932  else
933  {
934  /* nope, try the next prefix */
935  q_list = q_list->next;
936  continue;
937  }
938  }
939  }
940 
941  /* still not found so far: add it as a sibling to the current node */
942  if (!qc)
943  {
944  tmp = mutt_mem_calloc(1, sizeof(struct QClass));
945  tmp->prefix = mutt_mem_calloc(1, length + 1);
946  strncpy(tmp->prefix, qptr, length);
947  tmp->length = length;
948 
949  if (ptr->down)
950  {
951  tmp->next = ptr->down;
952  ptr->down->prev = tmp;
953  }
954  ptr->down = tmp;
955  tmp->up = ptr;
956 
957  class_color_new(tmp, q_level);
958 
959  return tmp;
960  }
961  else
962  {
963  if (index != -1)
964  shift_class_colors(*quote_list, tmp, index, q_level);
965 
966  return qc;
967  }
968  }
969  else
970  {
971  /* nope, try the next prefix */
972  q_list = q_list->next;
973  continue;
974  }
975  }
976  }
977 
978  if (!qc)
979  {
980  /* not found so far: add it as a top level class */
981  qc = mutt_mem_calloc(1, sizeof(struct QClass));
982  qc->prefix = mutt_mem_calloc(1, length + 1);
983  strncpy(qc->prefix, qptr, length);
984  qc->length = length;
985  class_color_new(qc, q_level);
986 
987  if (*quote_list)
988  {
989  qc->next = *quote_list;
990  (*quote_list)->prev = qc;
991  }
992  *quote_list = qc;
993  }
994 
995  if (index != -1)
996  shift_class_colors(*quote_list, tmp, index, q_level);
997 
998  return qc;
999 }
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ check_marker()

static int check_marker ( const char *  q,
const char *  p 
)
static

Check that the unique marker is present.

Parameters
qMarker string
pString to check
Return values
numOffset of marker

Definition at line 1007 of file pager.c.

1008 {
1009  for (; (p[0] == q[0]) && (q[0] != '\0') && (p[0] != '\0') && (q[0] != '\a') &&
1010  (p[0] != '\a');
1011  p++, q++)
1012  {
1013  }
1014 
1015  return (int) (*p - *q);
1016 }
+ Here is the caller graph for this function:

◆ check_attachment_marker()

static int check_attachment_marker ( const char *  p)
static

Check that the unique marker is present.

Parameters
pString to check
Return values
numOffset of marker

Definition at line 1023 of file pager.c.

1024 {
1025  return check_marker(AttachmentMarker, p);
1026 }
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ check_protected_header_marker()

static int check_protected_header_marker ( const char *  p)
static

Check that the unique marker is present.

Parameters
pString to check
Return values
numOffset of marker

Definition at line 1033 of file pager.c.

1034 {
1036 }
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_is_quote_line()

int mutt_is_quote_line ( char *  line,
regmatch_t *  pmatch 
)

Is a line of message text a quote?

Parameters
[in]lineLine to test
[out]pmatchRegex sub-matches
Return values
trueLine is quoted

Checks if line matches the $quote_regex and doesn't match $smileys. This is used by the pager for calling classify_quote.

Definition at line 1047 of file pager.c.

1048 {
1049  bool is_quote = false;
1050  const struct Regex *c_smileys = cs_subset_regex(NeoMutt->sub, "smileys");
1051  regmatch_t pmatch_internal[1], smatch[1];
1052 
1053  if (!pmatch)
1054  pmatch = pmatch_internal;
1055 
1056  if (mutt_regex_capture(C_QuoteRegex, line, 1, pmatch))
1057  {
1058  if (mutt_regex_capture(c_smileys, line, 1, smatch))
1059  {
1060  if (smatch[0].rm_so > 0)
1061  {
1062  char c = line[smatch[0].rm_so];
1063  line[smatch[0].rm_so] = 0;
1064 
1065  if (mutt_regex_capture(C_QuoteRegex, line, 1, pmatch))
1066  is_quote = true;
1067 
1068  line[smatch[0].rm_so] = c;
1069  }
1070  }
1071  else
1072  is_quote = true;
1073  }
1074 
1075  return is_quote;
1076 }
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ resolve_types()

static void resolve_types ( char *  buf,
char *  raw,
struct Line line_info,
int  n,
int  last,
struct QClass **  quote_list,
int *  q_level,
bool *  force_redraw,
bool  q_classify 
)
static

Determine the style for a line of text.

Parameters
[in]bufFormatted text
[in]rawRaw text
[in]line_infoLine info array
[in]nLine number (index into line_info)
[in]lastLast line
[out]quote_listList of quote colours
[out]q_levelQuote level
[out]force_redrawSet to true if a screen redraw is needed
[in]q_classifyIf true, style the text

Definition at line 1090 of file pager.c.

1093 {
1094  struct ColorLine *color_line = NULL;
1095  struct ColorLineList *head = NULL;
1096  regmatch_t pmatch[1];
1097  bool found;
1098  bool null_rx;
1099  const bool c_header_color_partial =
1100  cs_subset_bool(NeoMutt->sub, "header_color_partial");
1101  int offset, i = 0;
1102 
1103  if ((n == 0) || IS_HEADER(line_info[n - 1].type) ||
1104  (check_protected_header_marker(raw) == 0))
1105  {
1106  if (buf[0] == '\n') /* end of header */
1107  {
1108  line_info[n].type = MT_COLOR_NORMAL;
1109  getyx(stdscr, braille_line, braille_col);
1110  }
1111  else
1112  {
1113  /* if this is a continuation of the previous line, use the previous
1114  * line's color as default. */
1115  if ((n > 0) && ((buf[0] == ' ') || (buf[0] == '\t')))
1116  {
1117  line_info[n].type = line_info[n - 1].type; /* wrapped line */
1118  if (!c_header_color_partial)
1119  {
1120  (line_info[n].syntax)[0].color = (line_info[n - 1].syntax)[0].color;
1121  line_info[n].is_cont_hdr = 1;
1122  }
1123  }
1124  else
1125  {
1126  line_info[n].type = MT_COLOR_HDRDEFAULT;
1127  }
1128 
1129  /* When this option is unset, we color the entire header the
1130  * same color. Otherwise, we handle the header patterns just
1131  * like body patterns (further below). */
1132  if (!c_header_color_partial)
1133  {
1134  STAILQ_FOREACH(color_line, &Colors->hdr_list, entries)
1135  {
1136  if (regexec(&color_line->regex, buf, 0, NULL, 0) == 0)
1137  {
1138  line_info[n].type = MT_COLOR_HEADER;
1139  line_info[n].syntax[0].color = color_line->pair;
1140  if (line_info[n].is_cont_hdr)
1141  {
1142  /* adjust the previous continuation lines to reflect the color of this continuation line */
1143  int j;
1144  for (j = n - 1; j >= 0 && line_info[j].is_cont_hdr; --j)
1145  {
1146  line_info[j].type = line_info[n].type;
1147  line_info[j].syntax[0].color = line_info[n].syntax[0].color;
1148  }
1149  /* now adjust the first line of this header field */
1150  if (j >= 0)
1151  {
1152  line_info[j].type = line_info[n].type;
1153  line_info[j].syntax[0].color = line_info[n].syntax[0].color;
1154  }
1155  *force_redraw = true; /* the previous lines have already been drawn on the screen */
1156  }
1157  break;
1158  }
1159  }
1160  }
1161  }
1162  }
1163  else if (mutt_str_startswith(raw, "\033[0m")) // Escape: a little hack...
1164  line_info[n].type = MT_COLOR_NORMAL;
1165  else if (check_attachment_marker((char *) raw) == 0)
1166  line_info[n].type = MT_COLOR_ATTACHMENT;
1167  else if (mutt_str_equal("-- \n", buf) || mutt_str_equal("-- \r\n", buf))
1168  {
1169  i = n + 1;
1170 
1171  line_info[n].type = MT_COLOR_SIGNATURE;
1172  while ((i < last) && (check_sig(buf, line_info, i - 1) == 0) &&
1173  ((line_info[i].type == MT_COLOR_NORMAL) || (line_info[i].type == MT_COLOR_QUOTED) ||
1174  (line_info[i].type == MT_COLOR_HEADER)))
1175  {
1176  /* oops... */
1177  if (line_info[i].chunks)
1178  {
1179  line_info[i].chunks = 0;
1180  mutt_mem_realloc(&(line_info[n].syntax), sizeof(struct TextSyntax));
1181  }
1182  line_info[i++].type = MT_COLOR_SIGNATURE;
1183  }
1184  }
1185  else if (check_sig(buf, line_info, n - 1) == 0)
1186  line_info[n].type = MT_COLOR_SIGNATURE;
1187  else if (mutt_is_quote_line(buf, pmatch))
1188 
1189  {
1190  if (q_classify && (line_info[n].quote == NULL))
1191  {
1192  line_info[n].quote = classify_quote(quote_list, buf + pmatch[0].rm_so,
1193  pmatch[0].rm_eo - pmatch[0].rm_so,
1194  force_redraw, q_level);
1195  }
1196  line_info[n].type = MT_COLOR_QUOTED;
1197  }
1198  else
1199  line_info[n].type = MT_COLOR_NORMAL;
1200 
1201  /* body patterns */
1202  if ((line_info[n].type == MT_COLOR_NORMAL) || (line_info[n].type == MT_COLOR_QUOTED) ||
1203  ((line_info[n].type == MT_COLOR_HDRDEFAULT) && c_header_color_partial))
1204  {
1205  size_t nl;
1206 
1207  /* don't consider line endings part of the buffer
1208  * for regex matching */
1209  nl = mutt_str_len(buf);
1210  if ((nl > 0) && (buf[nl - 1] == '\n'))
1211  buf[nl - 1] = '\0';
1212 
1213  i = 0;
1214  offset = 0;
1215  line_info[n].chunks = 0;
1216  if (line_info[n].type == MT_COLOR_HDRDEFAULT)
1217  head = &Colors->hdr_list;
1218  else
1219  head = &Colors->body_list;
1220  STAILQ_FOREACH(color_line, head, entries)
1221  {
1222  color_line->stop_matching = false;
1223  }
1224  do
1225  {
1226  if (!buf[offset])
1227  break;
1228 
1229  found = false;
1230  null_rx = false;
1231  STAILQ_FOREACH(color_line, head, entries)
1232  {
1233  if (!color_line->stop_matching &&
1234  (regexec(&color_line->regex, buf + offset, 1, pmatch,
1235  ((offset != 0) ? REG_NOTBOL : 0)) == 0))
1236  {
1237  if (pmatch[0].rm_eo != pmatch[0].rm_so)
1238  {
1239  if (!found)
1240  {
1241  /* Abort if we fill up chunks.
1242  * Yes, this really happened. */
1243  if (line_info[n].chunks == SHRT_MAX)
1244  {
1245  null_rx = false;
1246  break;
1247  }
1248  if (++(line_info[n].chunks) > 1)
1249  {
1250  mutt_mem_realloc(&(line_info[n].syntax),
1251  (line_info[n].chunks) * sizeof(struct TextSyntax));
1252  }
1253  }
1254  i = line_info[n].chunks - 1;
1255  pmatch[0].rm_so += offset;
1256  pmatch[0].rm_eo += offset;
1257  if (!found || (pmatch[0].rm_so < (line_info[n].syntax)[i].first) ||
1258  ((pmatch[0].rm_so == (line_info[n].syntax)[i].first) &&
1259  (pmatch[0].rm_eo > (line_info[n].syntax)[i].last)))
1260  {
1261  (line_info[n].syntax)[i].color = color_line->pair;
1262  (line_info[n].syntax)[i].first = pmatch[0].rm_so;
1263  (line_info[n].syntax)[i].last = pmatch[0].rm_eo;
1264  }
1265  found = true;
1266  null_rx = false;
1267  }
1268  else
1269  null_rx = true; /* empty regex; don't add it, but keep looking */
1270  }
1271  else
1272  {
1273  /* Once a regexp fails to match, don't try matching it again.
1274  * On very long lines this can cause a performance issue if there
1275  * are other regexps that have many matches. */
1276  color_line->stop_matching = true;
1277  }
1278  }
1279 
1280  if (null_rx)
1281  offset++; /* avoid degenerate cases */
1282  else
1283  offset = (line_info[n].syntax)[i].last;
1284  } while (found || null_rx);
1285  if (nl > 0)
1286  buf[nl] = '\n';
1287  }
1288 
1289  /* attachment patterns */
1290  if (line_info[n].type == MT_COLOR_ATTACHMENT)
1291  {
1292  size_t nl;
1293 
1294  /* don't consider line endings part of the buffer for regex matching */
1295  nl = mutt_str_len(buf);
1296  if ((nl > 0) && (buf[nl - 1] == '\n'))
1297  buf[nl - 1] = '\0';
1298 
1299  i = 0;
1300  offset = 0;
1301  line_info[n].chunks = 0;
1302  do
1303  {
1304  if (!buf[offset])
1305  break;
1306 
1307  found = false;
1308  null_rx = false;
1309  STAILQ_FOREACH(color_line, &Colors->attach_list, entries)
1310  {
1311  if (regexec(&color_line->regex, buf + offset, 1, pmatch,
1312  ((offset != 0) ? REG_NOTBOL : 0)) == 0)
1313  {
1314  if (pmatch[0].rm_eo != pmatch[0].rm_so)
1315  {
1316  if (!found)
1317  {
1318  if (++(line_info[n].chunks) > 1)
1319  {
1320  mutt_mem_realloc(&(line_info[n].syntax),
1321  (line_info[n].chunks) * sizeof(struct TextSyntax));
1322  }
1323  }
1324  i = line_info[n].chunks - 1;
1325  pmatch[0].rm_so += offset;
1326  pmatch[0].rm_eo += offset;
1327  if (!found || (pmatch[0].rm_so < (line_info[n].syntax)[i].first) ||
1328  ((pmatch[0].rm_so == (line_info[n].syntax)[i].first) &&
1329  (pmatch[0].rm_eo > (line_info[n].syntax)[i].last)))
1330  {
1331  (line_info[n].syntax)[i].color = color_line->pair;
1332  (line_info[n].syntax)[i].first = pmatch[0].rm_so;
1333  (line_info[n].syntax)[i].last = pmatch[0].rm_eo;
1334  }
1335  found = 1;
1336  null_rx = 0;
1337  }
1338  else
1339  null_rx = 1; /* empty regex; don't add it, but keep looking */
1340  }
1341  }
1342 
1343  if (null_rx)
1344  offset++; /* avoid degenerate cases */
1345  else
1346  offset = (line_info[n].syntax)[i].last;
1347  } while (found || null_rx);
1348  if (nl > 0)
1349  buf[nl] = '\n';
1350  }
1351 }
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ is_ansi()

static bool is_ansi ( const char *  str)
static

Is this an ANSI escape sequence?

Parameters
strString to test
Return values
booltrue, if it's an ANSI escape sequence

Definition at line 1358 of file pager.c.

1359 {
1360  while (*str && (isdigit(*str) || *str == ';'))
1361  str++;
1362  return (*str == 'm');
1363 }
+ Here is the caller graph for this function:

◆ grok_ansi()

static int grok_ansi ( unsigned char *  buf,
int  pos,
struct AnsiAttr a 
)
static

Parse an ANSI escape sequence.

Parameters
bufString to parse
posStarting position in string
aAnsiAttr for the result
Return values
numIndex of first character after the escape sequence

Definition at line 1372 of file pager.c.

1373 {
1374  int x = pos;
1375 
1376  while (isdigit(buf[x]) || (buf[x] == ';'))
1377  x++;
1378 
1379  /* Character Attributes */
1380  const bool c_allow_ansi = cs_subset_bool(NeoMutt->sub, "allow_ansi");
1381  if (c_allow_ansi && a && (buf[x] == 'm'))
1382  {
1383  if (pos == x)
1384  {
1385 #ifdef HAVE_COLOR
1386  if (a->pair != -1)
1387  mutt_color_free(Colors, a->fg, a->bg);
1388 #endif
1389  a->attr = ANSI_OFF;
1390  a->pair = -1;
1391  }
1392  while (pos < x)
1393  {
1394  if ((buf[pos] == '1') && ((pos + 1 == x) || (buf[pos + 1] == ';')))
1395  {
1396  a->attr |= ANSI_BOLD;
1397  pos += 2;
1398  }
1399  else if ((buf[pos] == '4') && ((pos + 1 == x) || (buf[pos + 1] == ';')))
1400  {
1401  a->attr |= ANSI_UNDERLINE;
1402  pos += 2;
1403  }
1404  else if ((buf[pos] == '5') && ((pos + 1 == x) || (buf[pos + 1] == ';')))
1405  {
1406  a->attr |= ANSI_BLINK;
1407  pos += 2;
1408  }
1409  else if ((buf[pos] == '7') && ((pos + 1 == x) || (buf[pos + 1] == ';')))
1410  {
1411  a->attr |= ANSI_REVERSE;
1412  pos += 2;
1413  }
1414  else if ((buf[pos] == '0') && ((pos + 1 == x) || (buf[pos + 1] == ';')))
1415  {
1416 #ifdef HAVE_COLOR
1417  if (a->pair != -1)
1418  mutt_color_free(Colors, a->fg, a->bg);
1419 #endif
1420  a->attr = ANSI_OFF;
1421  a->pair = -1;
1422  pos += 2;
1423  }
1424  else if ((buf[pos] == '3') && isdigit(buf[pos + 1]))
1425  {
1426 #ifdef HAVE_COLOR
1427  if (a->pair != -1)
1428  mutt_color_free(Colors, a->fg, a->bg);
1429 #endif
1430  a->pair = -1;
1431  a->attr |= ANSI_COLOR;
1432  a->fg = buf[pos + 1] - '0';
1433  pos += 3;
1434  }
1435  else if ((buf[pos] == '4') && isdigit(buf[pos + 1]))
1436  {
1437 #ifdef HAVE_COLOR
1438  if (a->pair != -1)
1439  mutt_color_free(Colors, a->fg, a->bg);
1440 #endif
1441  a->pair = -1;
1442  a->attr |= ANSI_COLOR;
1443  a->bg = buf[pos + 1] - '0';
1444  pos += 3;
1445  }
1446  else
1447  {
1448  while ((pos < x) && (buf[pos] != ';'))
1449  pos++;
1450  pos++;
1451  }
1452  }
1453  }
1454  pos = x;
1455  return pos;
1456 }
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_buffer_strip_formatting()

void mutt_buffer_strip_formatting ( struct Buffer dest,
const char *  src,
bool  strip_markers 
)

Removes ANSI and backspace formatting.

Parameters
destBuffer for the result
srcString to strip
strip_markersRemove

Removes ANSI and backspace formatting, and optionally markers. This is separated out so that it can be used both by the pager and the autoview handler.

This logic is pulled from the pager fill_buffer() function, for use in stripping reply-quoted autoview output of ansi sequences.

Definition at line 1471 of file pager.c.

1472 {
1473  const char *s = src;
1474 
1475  mutt_buffer_reset(dest);
1476 
1477  if (!s)
1478  return;
1479 
1480  while (s[0] != '\0')
1481  {
1482  if ((s[0] == '\010') && (s > src))
1483  {
1484  if (s[1] == '_') /* underline */
1485  s += 2;
1486  else if (s[1] && mutt_buffer_len(dest)) /* bold or overstrike */
1487  {
1488  dest->dptr--;
1489  mutt_buffer_addch(dest, s[1]);
1490  s += 2;
1491  }
1492  else /* ^H */
1493  mutt_buffer_addch(dest, *s++);
1494  }
1495  else if ((s[0] == '\033') && (s[1] == '[') && is_ansi(s + 2))
1496  {
1497  while (*s++ != 'm')
1498  ; /* skip ANSI sequence */
1499  }
1500  else if (strip_markers && (s[0] == '\033') && (s[1] == ']') &&
1501  ((check_attachment_marker(s) == 0) || (check_protected_header_marker(s) == 0)))
1502  {
1503  mutt_debug(LL_DEBUG2, "Seen attachment marker\n");
1504  while (*s++ != '\a')
1505  ; /* skip pseudo-ANSI sequence */
1506  }
1507  else
1508  mutt_buffer_addch(dest, *s++);
1509  }
1510 }
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ fill_buffer()

static int fill_buffer ( FILE *  fp,
LOFF_T *  last_pos,
LOFF_T  offset,
unsigned char **  buf,
unsigned char **  fmt,
size_t *  blen,
int *  buf_ready 
)
static

Fill a buffer from a file.

Parameters
[in]fpFile to read from
[in,out]last_posEnd of last read
[in]offsetPosition start reading from
[out]bufBuffer to fill
[out]fmtCopy of buffer, stripped of attributes
[out]blenLength of the buffer
[in,out]buf_readytrue if the buffer already has data in it
Return values
>=0Bytes read
-1Error

Definition at line 1524 of file pager.c.

1526 {
1527  static int b_read;
1528  struct Buffer stripped;
1529 
1530  if (*buf_ready == 0)
1531  {
1532  if (offset != *last_pos)
1533  fseeko(fp, offset, SEEK_SET);
1534 
1535  *buf = (unsigned char *) mutt_file_read_line((char *) *buf, blen, fp, NULL, MUTT_RL_EOL);
1536  if (!*buf)
1537  {
1538  fmt[0] = NULL;
1539  return -1;
1540  }
1541 
1542  *last_pos = ftello(fp);
1543  b_read = (int) (*last_pos - offset);
1544  *buf_ready = 1;
1545 
1546  mutt_buffer_init(&stripped);
1547  mutt_buffer_alloc(&stripped, *blen);
1548  mutt_buffer_strip_formatting(&stripped, (const char *) *buf, 1);
1549  /* This should be a noop, because *fmt should be NULL */
1550  FREE(fmt);
1551  *fmt = (unsigned char *) stripped.data;
1552  }
1553 
1554  return b_read;
1555 }
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ format_line()

static int format_line ( struct Line **  line_info,
int  n,
unsigned char *  buf,
PagerFlags  flags,
struct AnsiAttr pa,
int  cnt,
int *  pspace,
int *  pvch,
int *  pcol,
int *  pspecial,
int  width 
)
static

Display a line of text in the pager.

Parameters
[out]line_infoLine info
[in]nLine number (index into line_info)
[in]bufText to display
[in]flagsFlags, see PagerFlags
[out]paANSI attributes used
[in]cntLength of text buffer
[out]pspaceIndex of last whitespace character
[out]pvchNumber of bytes read
[out]pcolNumber of columns used
[out]pspecialAttribute flags, e.g. A_UNDERLINE
[in]widthWidth of screen (to wrap to)
Return values
numNumber of characters displayed

Definition at line 1572 of file pager.c.

1575 {
1576  int space = -1; /* index of the last space or TAB */
1577  int col = C_Markers ? (*line_info)[n].continuation : 0;
1578  size_t k;
1579  int ch, vch, last_special = -1, special = 0, t;
1580  wchar_t wc;
1581  mbstate_t mbstate;
1582  int wrap_cols = mutt_window_wrap_cols(width, (flags & MUTT_PAGER_NOWRAP) ? 0 : C_Wrap);
1583 
1584  if (check_attachment_marker((char *) buf) == 0)
1585  wrap_cols = width;
1586 
1587  /* FIXME: this should come from line_info */
1588  memset(&mbstate, 0, sizeof(mbstate));
1589 
1590  for (ch = 0, vch = 0; ch < cnt; ch += k, vch += k)
1591  {
1592  /* Handle ANSI sequences */
1593  while ((cnt - ch >= 2) && (buf[ch] == '\033') && (buf[ch + 1] == '[') && // Escape
1594  is_ansi((char *) buf + ch + 2))
1595  {
1596  ch = grok_ansi(buf, ch + 2, pa) + 1;
1597  }
1598 
1599  while ((cnt - ch >= 2) && (buf[ch] == '\033') && (buf[ch + 1] == ']') && // Escape
1600  ((check_attachment_marker((char *) buf + ch) == 0) ||
1601  (check_protected_header_marker((char *) buf + ch) == 0)))
1602  {
1603  while (buf[ch++] != '\a')
1604  if (ch >= cnt)
1605  break;
1606  }
1607 
1608  /* is anything left to do? */
1609  if (ch >= cnt)
1610  break;
1611 
1612  k = mbrtowc(&wc, (char *) buf + ch, cnt - ch, &mbstate);
1613  if ((k == (size_t)(-2)) || (k == (size_t)(-1)))
1614  {
1615  if (k == (size_t)(-1))
1616  memset(&mbstate, 0, sizeof(mbstate));
1617  mutt_debug(LL_DEBUG1, "mbrtowc returned %lu; errno = %d\n", k, errno);
1618  if (col + 4 > wrap_cols)
1619  break;
1620  col += 4;
1621  if (pa)
1622  mutt_window_printf("\\%03o", buf[ch]);
1623  k = 1;
1624  continue;
1625  }
1626  if (k == 0)
1627  k = 1;
1628 
1629  if (CharsetIsUtf8)
1630  {
1631  /* zero width space, zero width no-break space */
1632  if ((wc == 0x200B) || (wc == 0xFEFF))
1633  {
1634  mutt_debug(LL_DEBUG3, "skip zero-width character U+%04X\n", (unsigned short) wc);
1635  continue;
1636  }
1638  {
1639  mutt_debug(LL_DEBUG3, "filtered U+%04X\n", (unsigned short) wc);
1640  continue;
1641  }
1642  }
1643 
1644  /* Handle backspace */
1645  special = 0;
1646  if (IsWPrint(wc))
1647  {
1648  wchar_t wc1;
1649  mbstate_t mbstate1 = mbstate;
1650  size_t k1 = mbrtowc(&wc1, (char *) buf + ch + k, cnt - ch - k, &mbstate1);
1651  while ((k1 != (size_t)(-2)) && (k1 != (size_t)(-1)) && (k1 > 0) && (wc1 == '\b'))
1652  {
1653  const size_t k2 =
1654  mbrtowc(&wc1, (char *) buf + ch + k + k1, cnt - ch - k - k1, &mbstate1);
1655  if ((k2 == (size_t)(-2)) || (k2 == (size_t)(-1)) || (k2 == 0) || (!IsWPrint(wc1)))
1656  break;
1657 
1658  if (wc == wc1)
1659  {
1660  special |= ((wc == '_') && (special & A_UNDERLINE)) ? A_UNDERLINE : A_BOLD;
1661  }
1662  else if ((wc == '_') || (wc1 == '_'))
1663  {
1664  special |= A_UNDERLINE;
1665  wc = (wc1 == '_') ? wc : wc1;
1666  }
1667  else
1668  {
1669  /* special = 0; / * overstrike: nothing to do! */
1670  wc = wc1;
1671  }
1672 
1673  ch += k + k1;
1674  k = k2;
1675  mbstate = mbstate1;
1676  k1 = mbrtowc(&wc1, (char *) buf + ch + k, cnt - ch - k, &mbstate1);
1677  }
1678  }
1679 
1680  if (pa && ((flags & (MUTT_SHOWCOLOR | MUTT_SEARCH | MUTT_PAGER_MARKER)) ||
1681  special || last_special || pa->attr))
1682  {
1683  resolve_color(*line_info, n, vch, flags, special, pa);
1684  last_special = special;
1685  }
1686 
1687  /* no-break space, narrow no-break space */
1688  if (IsWPrint(wc) || (CharsetIsUtf8 && ((wc == 0x00A0) || (wc == 0x202F))))
1689  {
1690  if (wc == ' ')
1691  {
1692  space = ch;
1693  }
1694  t = wcwidth(wc);
1695  if (col + t > wrap_cols)
1696  break;
1697  col += t;
1698  if (pa)
1699  mutt_addwch(wc);
1700  }
1701  else if (wc == '\n')
1702  break;
1703  else if (wc == '\t')
1704  {
1705  space = ch;
1706  t = (col & ~7) + 8;
1707  if (t > wrap_cols)
1708  break;
1709  if (pa)
1710  for (; col < t; col++)
1711  mutt_window_addch(' ');
1712  else
1713  col = t;
1714  }
1715  else if ((wc < 0x20) || (wc == 0x7f))
1716  {
1717  if (col + 2 > wrap_cols)
1718  break;
1719  col += 2;
1720  if (pa)
1721  mutt_window_printf("^%c", ('@' + wc) & 0x7f);
1722  }
1723  else if (wc < 0x100)
1724  {
1725  if (col + 4 > wrap_cols)
1726  break;
1727  col += 4;
1728  if (pa)
1729  mutt_window_printf("\\%03o", wc);
1730  }
1731  else
1732  {
1733  if (col + 1 > wrap_cols)
1734  break;
1735  col += k;
1736  if (pa)
1738  }
1739  }
1740  *pspace = space;
1741  *pcol = col;
1742  *pvch = vch;
1743  *pspecial = special;
1744  return ch;
1745 }
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ display_line()

static int display_line ( FILE *  fp,
LOFF_T *  last_pos,
struct Line **  line_info,
int  n,
int *  last,
int *  max,
PagerFlags  flags,
struct QClass **  quote_list,
int *  q_level,
bool *  force_redraw,
regex_t *  search_re,
struct MuttWindow win_pager 
)
static

Print a line on screen.

Parameters
[in]fpFile to read from
[out]last_posOffset into file
[out]line_infoLine attributes
[in]nLine number
[out]lastLast line
[out]maxMaximum number of lines
[in]flagsFlags, see PagerFlags
[out]quote_listEmail quoting style
[out]q_levelLevel of quoting
[out]force_redrawForce a repaint
[out]search_reRegex to highlight
[in]win_pagerWindow to draw into
Return values
-1EOF was reached
0normal exit, line was not displayed
>0normal exit, line was displayed

Definition at line 1765 of file pager.c.

1769 {
1770  unsigned char *buf = NULL, *fmt = NULL;
1771  size_t buflen = 0;
1772  unsigned char *buf_ptr = NULL;
1773  int ch, vch, col, cnt, b_read;
1774  int buf_ready = 0;
1775  bool change_last = false;
1776  const bool c_smart_wrap = cs_subset_bool(NeoMutt->sub, "smart_wrap");
1777  int special;
1778  int offset;
1779  int def_color;
1780  int m;
1781  int rc = -1;
1782  struct AnsiAttr a = { 0, 0, 0, -1 };
1783  regmatch_t pmatch[1];
1784 
1785  if (n == *last)
1786  {
1787  (*last)++;
1788  change_last = true;
1789  }
1790 
1791  if (*last == *max)
1792  {
1793  mutt_mem_realloc(line_info, sizeof(struct Line) * (*max += LINES));
1794  for (ch = *last; ch < *max; ch++)
1795  {
1796  memset(&((*line_info)[ch]), 0, sizeof(struct Line));
1797  (*line_info)[ch].type = -1;
1798  (*line_info)[ch].search_cnt = -1;
1799  (*line_info)[ch].syntax = mutt_mem_malloc(sizeof(struct TextSyntax));
1800  ((*line_info)[ch].syntax)[0].first = -1;
1801  ((*line_info)[ch].syntax)[0].last = -1;
1802  }
1803  }
1804 
1805  struct Line *const curr_line = &(*line_info)[n];
1806 
1807  if (flags & MUTT_PAGER_LOGS)
1808  {
1809  /* determine the line class */
1810  if (fill_buffer(fp, last_pos, curr_line->offset, &buf, &fmt, &buflen, &buf_ready) < 0)
1811  {
1812  if (change_last)
1813  (*last)--;
1814  goto out;
1815  }
1816 
1817  curr_line->type = MT_COLOR_MESSAGE_LOG;
1818  if (buf[11] == 'M')
1819  curr_line->syntax[0].color = MT_COLOR_MESSAGE;
1820  else if (buf[11] == 'W')
1821  curr_line->syntax[0].color = MT_COLOR_WARNING;
1822  else if (buf[11] == 'E')
1823  curr_line->syntax[0].color = MT_COLOR_ERROR;
1824  else
1825  curr_line->syntax[0].color = MT_COLOR_NORMAL;
1826  }
1827 
1828  /* only do color highlighting if we are viewing a message */
1829  if (flags & (MUTT_SHOWCOLOR | MUTT_TYPES))
1830  {
1831  if (curr_line->type == -1)
1832  {
1833  /* determine the line class */
1834  if (fill_buffer(fp, last_pos, curr_line->offset, &buf, &fmt, &buflen, &buf_ready) < 0)
1835  {
1836  if (change_last)
1837  (*last)--;
1838  goto out;
1839  }
1840 
1841  resolve_types((char *) fmt, (char *) buf, *line_info, n, *last,
1842  quote_list, q_level, force_redraw, flags & MUTT_SHOWCOLOR);
1843 
1844  /* avoid race condition for continuation lines when scrolling up */
1845  for (m = n + 1; m < *last && (*line_info)[m].offset && (*line_info)[m].continuation; m++)
1846  (*line_info)[m].type = curr_line->type;
1847  }
1848 
1849  /* this also prevents searching through the hidden lines */
1850  if ((flags & MUTT_HIDE) && (curr_line->type == MT_COLOR_QUOTED) &&
1851  ((curr_line->quote == NULL) || (curr_line->quote->index >= C_ToggleQuotedShowLevels)))
1852  {
1853  flags = 0; /* MUTT_NOSHOW */
1854  }
1855  }
1856 
1857  /* At this point, (*line_info[n]).quote may still be undefined. We
1858  * don't want to compute it every time MUTT_TYPES is set, since this
1859  * would slow down the "bottom" function unacceptably. A compromise
1860  * solution is hence to call regexec() again, just to find out the
1861  * length of the quote prefix. */
1862  if ((flags & MUTT_SHOWCOLOR) && !curr_line->continuation &&
1863  (curr_line->type == MT_COLOR_QUOTED) && !curr_line->quote)
1864  {
1865  if (fill_buffer(fp, last_pos, curr_line->offset, &buf, &fmt, &buflen, &buf_ready) < 0)
1866  {
1867  if (change_last)
1868  (*last)--;
1869  goto out;
1870  }
1871 
1872  if (mutt_regex_capture(C_QuoteRegex, (char *) fmt, 1, pmatch))
1873  {
1874  curr_line->quote =
1875  classify_quote(quote_list, (char *) fmt + pmatch[0].rm_so,
1876  pmatch[0].rm_eo - pmatch[0].rm_so, force_redraw, q_level);
1877  }
1878  else
1879  {
1880  goto out;
1881  }
1882  }
1883 
1884  if ((flags & MUTT_SEARCH) && !curr_line->continuation && (curr_line->search_cnt == -1))
1885  {
1886  if (fill_buffer(fp, last_pos, curr_line->offset, &buf, &fmt, &buflen, &buf_ready) < 0)
1887  {
1888  if (change_last)
1889  (*last)--;
1890  goto out;
1891  }
1892 
1893  offset = 0;
1894  curr_line->search_cnt = 0;
1895  while (regexec(search_re, (char *) fmt + offset, 1, pmatch,
1896  (offset ? REG_NOTBOL : 0)) == 0)
1897  {
1898  if (++(curr_line->search_cnt) > 1)
1899  {
1900  mutt_mem_realloc(&(curr_line->search),
1901  (curr_line->search_cnt) * sizeof(struct TextSyntax));
1902  }
1903  else
1904  curr_line->search = mutt_mem_malloc(sizeof(struct TextSyntax));
1905  pmatch[0].rm_so += offset;
1906  pmatch[0].rm_eo += offset;
1907  (curr_line->search)[curr_line->search_cnt - 1].first = pmatch[0].rm_so;
1908  (curr_line->search)[curr_line->search_cnt - 1].last = pmatch[0].rm_eo;
1909 
1910  if (pmatch[0].rm_eo == pmatch[0].rm_so)
1911  offset++; /* avoid degenerate cases */
1912  else
1913  offset = pmatch[0].rm_eo;
1914  if (!fmt[offset])
1915  break;
1916  }
1917  }
1918 
1919  if (!(flags & MUTT_SHOW) && ((*line_info)[n + 1].offset > 0))
1920  {
1921  /* we've already scanned this line, so just exit */
1922  rc = 0;
1923  goto out;
1924  }
1925  if ((flags & MUTT_SHOWCOLOR) && *force_redraw && ((*line_info)[n + 1].offset > 0))
1926  {
1927  /* no need to try to display this line... */
1928  rc = 1;
1929  goto out; /* fake display */
1930  }
1931 
1932  b_read = fill_buffer(fp, last_pos, curr_line->offset, &buf, &fmt, &buflen, &buf_ready);
1933  if (b_read < 0)
1934  {
1935  if (change_last)
1936  (*last)--;
1937  goto out;
1938  }
1939 
1940  /* now chose a good place to break the line */
1941  cnt = format_line(line_info, n, buf, flags, NULL, b_read, &ch, &vch, &col,
1942  &special, win_pager->state.cols);
1943  buf_ptr = buf + cnt;
1944 
1945  /* move the break point only if smart_wrap is set */
1946  if (c_smart_wrap)
1947  {
1948  if ((cnt < b_read) && (ch != -1) && !IS_HEADER(curr_line->type) && !IS_SPACE(buf[cnt]))
1949  {
1950  buf_ptr = buf + ch;
1951  /* skip trailing blanks */
1952  while (ch && ((buf[ch] == ' ') || (buf[ch] == '\t') || (buf[ch] == '\r')))
1953  ch--;
1954  /* A very long word with leading spaces causes infinite
1955  * wrapping when MUTT_PAGER_NSKIP is set. A folded header
1956  * with a single long word shouldn't be smartwrapped
1957  * either. So just disable smart_wrap if it would wrap at the
1958  * beginning of the line. */
1959  if (ch == 0)
1960  buf_ptr = buf + cnt;
1961  else
1962  cnt = ch + 1;
1963  }
1964  if (!(flags & MUTT_PAGER_NSKIP))
1965  {
1966  /* skip leading blanks on the next line too */
1967  while ((*buf_ptr == ' ') || (*buf_ptr == '\t'))
1968  buf_ptr++;
1969  }
1970  }
1971 
1972  if (*buf_ptr == '\r')
1973  buf_ptr++;
1974  if (*buf_ptr == '\n')
1975  buf_ptr++;
1976 
1977  if (((int) (buf_ptr - buf) < b_read) && !(*line_info)[n + 1].continuation)
1978  append_line(*line_info, n, (int) (buf_ptr - buf));
1979  (*line_info)[n + 1].offset = curr_line->offset + (long) (buf_ptr - buf);
1980 
1981  /* if we don't need to display the line we are done */
1982  if (!(flags & MUTT_SHOW))
1983  {
1984  rc = 0;
1985  goto out;
1986  }
1987 
1988  /* display the line */
1989  format_line(line_info, n, buf, flags, &a, cnt, &ch, &vch, &col, &special,
1990  win_pager->state.cols);
1991 
1992 /* avoid a bug in ncurses... */
1993 #ifndef USE_SLANG_CURSES
1994  if (col == 0)
1995  {
1997  mutt_window_addch(' ');
1998  }
1999 #endif
2000 
2001  /* end the last color pattern (needed by S-Lang) */
2002  if (special || ((col != win_pager->state.cols) && (flags & (MUTT_SHOWCOLOR | MUTT_SEARCH))))
2003  resolve_color(*line_info, n, vch, flags, 0, &a);
2004 
2005  /* Fill the blank space at the end of the line with the prevailing color.
2006  * ncurses does an implicit clrtoeol() when you do mutt_window_addch('\n') so we have
2007  * to make sure to reset the color *after* that */
2008  if (flags & MUTT_SHOWCOLOR)
2009  {
2010  m = (curr_line->continuation) ? (curr_line->syntax)[0].first : n;
2011  if ((*line_info)[m].type == MT_COLOR_HEADER)
2012  def_color = ((*line_info)[m].syntax)[0].color;
2013  else
2014  def_color = Colors->defs[(*line_info)[m].type];
2015 
2016  mutt_curses_set_attr(def_color);
2017  }
2018 
2019  if (col < win_pager->state.cols)
2020  mutt_window_clrtoeol(win_pager);
2021 
2022  /* reset the color back to normal. This *must* come after the
2023  * clrtoeol, otherwise the color for this line will not be
2024  * filled to the right margin. */
2025  if (flags & MUTT_SHOWCOLOR)
2027 
2028  /* build a return code */
2029  if (!(flags & MUTT_SHOW))
2030  flags = 0;
2031 
2032  rc = flags;
2033 
2034 out:
2035  FREE(&buf);
2036  FREE(&fmt);
2037  return rc;
2038 }
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ up_n_lines()

static int up_n_lines ( int  nlines,
struct Line info,
int  cur,
bool  hiding 
)
static

Reposition the pager's view up by n lines.

Parameters
nlinesNumber of lines to move
infoLine info array
curCurrent line number
hidingtrue if lines have been hidden
Return values
numNew current line number

Definition at line 2048 of file pager.c.

2049 {
2050  while ((cur > 0) && (nlines > 0))
2051  {
2052  cur--;
2053  if (!hiding || (info[cur].type != MT_COLOR_QUOTED))
2054  nlines--;
2055  }
2056 
2057  return cur;
2058 }
+ Here is the caller graph for this function:

◆ mutt_clear_pager_position()

void mutt_clear_pager_position ( void  )

Reset the pager's viewing position.

Definition at line 2063 of file pager.c.

2064 {
2065  TopLine = 0;
2066  OldEmail = NULL;
2067 }
+ Here is the caller graph for this function:

◆ pager_custom_redraw()

static void pager_custom_redraw ( struct Menu pager_menu)
static

Redraw the pager window - Implements Menu::custom_redraw()

Definition at line 2072 of file pager.c.

2073 {
2074  struct PagerRedrawData *rd = pager_menu->redraw_data;
2075  struct Mailbox *m = ctx_mailbox(Context);
2076  char buf[1024];
2077  const bool c_tilde = cs_subset_bool(NeoMutt->sub, "tilde");
2078  const short c_pager_index_lines =
2079  cs_subset_number(NeoMutt->sub, "pager_index_lines");
2080 
2081  if (!rd)
2082  return;
2083 
2084  if (pager_menu->redraw & REDRAW_FULL)
2085  {
2088 
2089  if (IsEmail(rd->extra) && m && ((m->vcount + 1) < c_pager_index_lines))
2090  {
2091  rd->indexlen = m->vcount + 1;
2092  }
2093  else
2094  rd->indexlen = c_pager_index_lines;
2095 
2096  rd->indicator = rd->indexlen / 3;
2097 
2098  if (Resize)
2099  {
2101  if (rd->search_compiled)
2102  {
2103  uint16_t flags = mutt_mb_is_lower(rd->searchbuf) ? REG_ICASE : 0;
2104  const int err = REG_COMP(&rd->search_re, rd->searchbuf, REG_NEWLINE | flags);
2105  if (err == 0)
2106  {
2107  rd->search_flag = MUTT_SEARCH;
2109  }
2110  else
2111  {
2112  regerror(err, &rd->search_re, buf, sizeof(buf));
2113  mutt_error("%s", buf);
2114  rd->search_compiled = false;
2115  }
2116  }
2117  rd->lines = Resize->line;
2118  pager_menu->redraw |= REDRAW_FLOW;
2119 
2120  FREE(&Resize);
2121  }
2122 
2123  if (IsEmail(rd->extra) && (c_pager_index_lines != 0))
2124  {
2125  if (!rd->menu)
2126  {
2127  /* only allocate the space if/when we need the index.
2128  * Initialise the menu as per the main index */
2129  rd->menu = mutt_menu_new(MENU_MAIN);
2131  rd->menu->color = index_color;
2132  rd->menu->max = Context ? m->vcount : 0;
2133  rd->menu->current = rd->extra->email->vnum;
2134  rd->menu->win_index = rd->extra->win_index;
2135  rd->menu->win_ibar = rd->extra->win_ibar;
2136  }
2137 
2139  rd->menu->pagelen = rd->extra->win_index->state.rows;
2140 
2141  /* some fudge to work out whereabouts the indicator should go */
2142  if (rd->menu->current - rd->indicator < 0)
2143  rd->menu->top = 0;
2144  else if (rd->menu->max - rd->menu->current < rd->menu->pagelen - rd->indicator)
2145  rd->menu->top = rd->menu->max - rd->menu->pagelen;
2146  else
2147  rd->menu->top = rd->menu->current - rd->indicator;
2148 
2149  menu_redraw_index(rd->menu);
2150  }
2151 
2152  pager_menu->redraw |= REDRAW_BODY | REDRAW_INDEX | REDRAW_STATUS;
2153  mutt_show_error();
2154  }
2155 
2156  if (pager_menu->redraw & REDRAW_FLOW)
2157  {
2158  if (!(rd->flags & MUTT_PAGER_RETWINCH))
2159  {
2160  rd->lines = -1;
2161  for (int i = 0; i <= rd->topline; i++)
2162  if (!rd->line_info[i].continuation)
2163  rd->lines++;
2164  for (int i = 0; i < rd->max_line; i++)
2165  {
2166  rd->line_info[i].offset = 0;
2167  rd->line_info[i].type = -1;
2168  rd->line_info[i].continuation = 0;
2169  rd->line_info[i].chunks = 0;
2170  rd->line_info[i].search_cnt = -1;
2171  rd->line_info[i].quote = NULL;
2172 
2173  mutt_mem_realloc(&(rd->line_info[i].syntax), sizeof(struct TextSyntax));
2174  if (rd->search_compiled && rd->line_info[i].search)
2175  FREE(&(rd->line_info[i].search));
2176  }
2177 
2178  rd->last_line = 0;
2179  rd->topline = 0;
2180  }
2181  int i = -1;
2182  int j = -1;
2183  while (display_line(rd->fp, &rd->last_pos, &rd->line_info, ++i, &rd->last_line,
2184  &rd->max_line, rd->has_types | rd->search_flag | (rd->flags & MUTT_PAGER_NOWRAP),
2185  &rd->quote_list, &rd->q_level, &rd->force_redraw,
2186  &rd->search_re, rd->extra->win_pager) == 0)
2187  {
2188  if (!rd->line_info[i].continuation && (++j == rd->lines))
2189  {
2190  rd->topline = i;
2191  if (!rd->search_flag)
2192  break;
2193  }
2194  }
2195  }
2196 
2197  if ((pager_menu->redraw & REDRAW_BODY) || (rd->topline != rd->oldtopline))
2198  {
2199  do
2200  {
2201  mutt_window_move(rd->extra->win_pager, 0, 0);
2202  rd->curline = rd->topline;
2203  rd->oldtopline = rd->topline;
2204  rd->lines = 0;
2205  rd->force_redraw = false;
2206 
2207  while ((rd->lines < rd->extra->win_pager->state.rows) &&
2208  (rd->line_info[rd->curline].offset <= rd->sb.st_size - 1))
2209  {
2210  if (display_line(rd->fp, &rd->last_pos, &rd->line_info, rd->curline,
2211  &rd->last_line, &rd->max_line,
2212  (rd->flags & MUTT_DISPLAYFLAGS) | rd->hide_quoted |
2213  rd->search_flag | (rd->flags & MUTT_PAGER_NOWRAP),
2214  &rd->quote_list, &rd->q_level, &rd->force_redraw,
2215  &rd->search_re, rd->extra->win_pager) > 0)
2216  {
2217  rd->lines++;
2218  }
2219  rd->curline++;
2220  mutt_window_move(rd->extra->win_pager, 0, rd->lines);
2221  }
2222  rd->last_offset = rd->line_info[rd->curline].offset;
2223  } while (rd->force_redraw);
2224 
2226  while (rd->lines < rd->extra->win_pager->state.rows)
2227  {
2229  if (c_tilde)
2230  mutt_window_addch('~');
2231  rd->lines++;
2232  mutt_window_move(rd->extra->win_pager, 0, rd->lines);
2233  }
2235 
2236  /* We are going to update the pager status bar, so it isn't
2237  * necessary to reset to normal color now. */
2238 
2239  pager_menu->redraw |= REDRAW_STATUS; /* need to update the % seen */
2240  }
2241 
2242  if (pager_menu->redraw & REDRAW_STATUS)
2243  {
2244  char pager_progress_str[65]; /* Lots of space for translations */
2245 
2246  if (rd->last_pos < rd->sb.st_size - 1)
2247  {
2248  snprintf(pager_progress_str, sizeof(pager_progress_str), OFF_T_FMT "%%",
2249  (100 * rd->last_offset / rd->sb.st_size));
2250  }
2251  else
2252  {
2253  const char *msg = (rd->topline == 0) ?
2254  /* L10N: Status bar message: the entire email is visible in the pager */
2255  _("all") :
2256  /* L10N: Status bar message: the end of the email is visible in the pager */
2257  _("end");
2258  mutt_str_copy(pager_progress_str, msg, sizeof(pager_progress_str));
2259  }
2260 
2261  /* print out the pager status bar */
2262  mutt_window_move(rd->extra->win_pbar, 0, 0);
2264 
2265  if (IsEmail(rd->extra) || IsMsgAttach(rd->extra))
2266  {
2267  const size_t l1 = rd->extra->win_pbar->state.cols * MB_LEN_MAX;
2268  const size_t l2 = sizeof(buf);
2269  const int buflen = (l1 < l2) ? l1 : l2;
2270  struct Email *e =
2271  (IsEmail(rd->extra)) ? rd->extra->email : rd->extra->body->email;
2272  mutt_make_string(buf, buflen, rd->extra->win_pbar->state.cols,
2274  e, MUTT_FORMAT_NO_FLAGS, pager_progress_str);
2275  mutt_draw_statusline(rd->extra->win_pbar->state.cols, buf, l2);
2276  }
2277  else
2278  {
2279  char bn[256];
2280  snprintf(bn, sizeof(bn), "%s (%s)", rd->banner, pager_progress_str);
2281  mutt_draw_statusline(rd->extra->win_pbar->state.cols, bn, sizeof(bn));
2282  }
2284  if (C_TsEnabled && TsSupported && rd->menu)
2285  {
2286  menu_status_line(buf, sizeof(buf), rd->menu, m, NONULL(C_TsStatusFormat));
2287  mutt_ts_status(buf);
2288  menu_status_line(buf, sizeof(buf), rd->menu, m, NONULL(C_TsIconFormat));
2289  mutt_ts_icon(buf);
2290  }
2291  }
2292 
2293  if ((pager_menu->redraw & REDRAW_INDEX) && rd->menu)
2294  {
2295  /* redraw the pager_index indicator, because the
2296  * flags for this message might have changed. */
2297  if (rd->extra->win_index->state.rows > 0)
2299 
2300  /* print out the index status bar */
2301  menu_status_line(buf, sizeof(buf), rd->menu, m, NONULL(C_StatusFormat));
2302 
2303  mutt_window_move(rd->extra->win_ibar, 0, 0);
2305  mutt_draw_statusline(rd->extra->win_ibar->state.cols, buf, sizeof(buf));
2307  }
2308 
2309  pager_menu->redraw = REDRAW_NO_FLAGS;
2310 }
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_pager()

int mutt_pager ( const char *  banner,
const char *  fname,
PagerFlags  flags,
struct Pager extra 
)

Display a file, or help, in a window.

Parameters
bannerTitle to display in status bar
fnameName of file to read
flagsFlags, e.g. MUTT_SHOWCOLOR
extraInfo about email to display
Return values
0Success
-1Error

This pager is actually not so simple as it once was. It now operates in two modes: one for viewing messages and the other for viewing help. These can be distinguished by whether or not "email" is NULL. The "email" arg is there so that we can do operations on the current message without the need to pop back out to the main-menu.

Definition at line 2327 of file pager.c.

2328 {
2329  static char searchbuf[256] = { 0 };
2330  char buf[1024];
2331  int ch = 0, rc = -1;
2332  bool first = true;
2333  int searchctx = 0;
2334  bool wrapped = false;
2335  const bool c_pager_stop = cs_subset_bool(NeoMutt->sub, "pager_stop");
2336  const short c_pager_context = cs_subset_number(NeoMutt->sub, "pager_context");
2337  const short c_pager_index_lines =
2338  cs_subset_number(NeoMutt->sub, "pager_index_lines");
2339  const short c_search_context =
2340  cs_subset_number(NeoMutt->sub, "search_context");
2341  const short c_skip_quoted_offset =
2342  cs_subset_number(NeoMutt->sub, "skip_quoted_offset");
2343 
2344  struct Menu *pager_menu = NULL;
2345  int old_PagerIndexLines; /* some people want to resize it while inside the pager */
2346 #ifdef USE_NNTP
2347  char *followup_to = NULL;
2348 #endif
2349 
2350  struct Mailbox *m = ctx_mailbox(Context);
2351 
2352  if (!(flags & MUTT_SHOWCOLOR))
2353  flags |= MUTT_SHOWFLAT;
2354 
2355  int index_space = c_pager_index_lines;
2356  if (extra->ctx && extra->ctx->mailbox)
2357  index_space = MIN(index_space, extra->ctx->mailbox->vcount);
2358 
2359  struct PagerRedrawData rd = { 0 };
2360  rd.banner = banner;
2361  rd.flags = flags;
2362  rd.extra = extra;
2363  rd.indexlen = index_space;
2364  rd.indicator = rd.indexlen / 3;
2365  rd.searchbuf = searchbuf;
2366  rd.has_types = (IsEmail(extra) || (flags & MUTT_SHOWCOLOR)) ? MUTT_TYPES : 0; /* main message or rfc822 attachment */
2367 
2368  rd.fp = fopen(fname, "r");
2369  if (!rd.fp)
2370  {
2371  mutt_perror(fname);
2372  return -1;
2373  }
2374 
2375  if (stat(fname, &rd.sb) != 0)
2376  {
2377  mutt_perror(fname);
2378  mutt_file_fclose(&rd.fp);
2379  return -1;
2380  }
2381  unlink(fname);
2382 
2383  if (rd.extra->win_index)
2384  {
2386  rd.extra->win_index->req_rows = index_space;
2388  window_set_visible(rd.extra->win_index->parent, (index_space > 0));
2389  }
2393 
2394  /* Initialize variables */
2395 
2396  if (Context && IsEmail(extra) && !extra->email->read)
2397  {
2399  mutt_set_flag(m, extra->email, MUTT_READ, true);
2400  }
2401 
2402  rd.max_line = LINES; /* number of lines on screen, from curses */
2403  rd.line_info = mutt_mem_calloc(rd.max_line, sizeof(struct Line));
2404  for (size_t i = 0; i < rd.max_line; i++)
2405  {
2406  rd.line_info[i].type = -1;
2407  rd.line_info[i].search_cnt = -1;
2408  rd.line_info[i].syntax = mutt_mem_malloc(sizeof(struct TextSyntax));
2409  (rd.line_info[i].syntax)[0].first = -1;
2410  (rd.line_info[i].syntax)[0].last = -1;
2411  }
2412 
2413  pager_menu = mutt_menu_new(MENU_PAGER);
2414  pager_menu->pagelen = extra->win_pager->state.rows;
2415  pager_menu->win_index = extra->win_pager;
2416  pager_menu->win_ibar = extra->win_pbar;
2417 
2418  pager_menu->custom_redraw = pager_custom_redraw;
2419  pager_menu->redraw_data = &rd;
2420  mutt_menu_push_current(pager_menu);
2421 
2422  if (IsEmail(extra))
2423  {
2424  // Viewing a Mailbox
2425 #ifdef USE_NNTP
2426  if (m && (m->type == MUTT_NNTP))
2428  else
2429 #endif
2431  }
2432  else
2433  {
2434  // Viewing Help
2435  if (InHelp)
2437  else
2439  }
2442 
2443  while (ch != -1)
2444  {
2446 
2447  pager_custom_redraw(pager_menu);
2448  window_redraw(RootWindow, true);
2449 
2450  if (C_BrailleFriendly)
2451  {
2452  if (braille_line != -1)
2453  {
2455  braille_line = -1;
2456  }
2457  }
2458  else
2460 
2461  mutt_refresh();
2462 
2463  if (IsEmail(extra) && (OldEmail == extra->email) && (TopLine != rd.topline) &&
2464  (rd.line_info[rd.curline].offset < (rd.sb.st_size - 1)))
2465  {
2466  if ((TopLine - rd.topline) > rd.lines)
2467  rd.topline += rd.lines;
2468  else
2469  rd.topline = TopLine;
2470  continue;
2471  }
2472  else
2473  OldEmail = NULL;
2474 
2475  bool do_new_mail = false;
2476 
2477  if (m && !OptAttachMsg)
2478  {
2479  int oldcount = m->msg_count;
2480  /* check for new mail */
2481  enum MxStatus check = mx_mbox_check(m);
2482  if (check == MX_STATUS_ERROR)
2483  {
2484  if (!m || mutt_buffer_is_empty(&m->pathbuf))
2485  {
2486  /* fatal error occurred */
2487  ctx_free(&Context);
2488  pager_menu->redraw = REDRAW_FULL;
2489  break;
2490  }
2491  }
2492  else if ((check == MX_STATUS_NEW_MAIL) || (check == MX_STATUS_REOPENED) ||
2493  (check == MX_STATUS_FLAGS))
2494  {
2495  /* notify user of newly arrived mail */
2496  if (check == MX_STATUS_NEW_MAIL)
2497  {
2498  for (size_t i = oldcount; i < m->msg_count; i++)
2499  {
2500  struct Email *e = m->emails[i];
2501 
2502  if (e && !e->read)
2503  {
2504  mutt_message(_("New mail in this mailbox"));
2505  do_new_mail = true;
2506  break;
2507  }
2508  }
2509  }
2510 
2511  if ((check == MX_STATUS_NEW_MAIL) || (check == MX_STATUS_REOPENED))
2512  {
2513  if (rd.menu && m)
2514  {
2515  /* After the mailbox has been updated,
2516  * rd.menu->current might be invalid */
2517  rd.menu->current = MIN(rd.menu->current, MAX(m->msg_count - 1, 0));
2518  struct Email *e = mutt_get_virt_email(m, rd.menu->current);
2519  if (!e)
2520  continue;
2521 
2522  bool verbose = m->verbose;
2523  m->verbose = false;
2524  mutt_update_index(rd.menu, Context, check, oldcount, e);
2525  m->verbose = verbose;
2526 
2527  rd.menu->max = m->vcount;
2528 
2529  /* If these header pointers don't match, then our email may have
2530  * been deleted. Make the pointer safe, then leave the pager.
2531  * This have a unpleasant behaviour to close the pager even the
2532  * deleted message is not the opened one, but at least it's safe. */
2533  e = mutt_get_virt_email(m, rd.menu->current);
2534  if (extra->email != e)
2535  {
2536  extra->email = e;
2537  break;
2538  }
2539  }
2540 
2541  pager_menu->redraw = REDRAW_FULL;
2542  OptSearchInvalid = true;
2543  }
2544  }
2545 
2546  if (mutt_mailbox_notify(m) || do_new_mail)
2547  {
2548  if (C_BeepNew)
2549  mutt_beep(true);
2550  if (C_NewMailCommand)
2551  {
2552  char cmd[1024];
2553  menu_status_line(cmd, sizeof(cmd), rd.menu, m, NONULL(C_NewMailCommand));
2554  if (mutt_system(cmd) != 0)
2555  mutt_error(_("Error running \"%s\""), cmd);
2556  }
2557  }
2558  }
2559 
2560  if (SigWinch)
2561  {
2562  SigWinch = 0;
2564  clearok(stdscr, true); /* force complete redraw */
2566 
2567  if (flags & MUTT_PAGER_RETWINCH)
2568  {
2569  /* Store current position. */
2570  rd.lines = -1;
2571  for (size_t i = 0; i <= rd.topline; i++)
2572  if (!rd.line_info[i].continuation)
2573  rd.lines++;
2574 
2575  Resize = mutt_mem_malloc(sizeof(struct Resize));
2576 
2577  Resize->line = rd.lines;
2580 
2581  ch = -1;
2582  rc = OP_REFORMAT_WINCH;
2583  }
2584  else
2585  {
2586  /* note: mutt_resize_screen() -> mutt_window_reflow() sets
2587  * REDRAW_FULL and REDRAW_FLOW */
2588  ch = 0;
2589  }
2590  continue;
2591  }
2592 
2593  ch = km_dokey(MENU_PAGER);
2594  if (ch >= 0)
2595  {
2596  mutt_clear_error();
2597  mutt_debug(LL_DEBUG1, "Got op %s (%d)\n", OpStrings[ch][0], ch);
2598  }
2600 
2601  if (ch < 0)
2602  {
2603  ch = 0;
2605  continue;
2606  }
2607 
2608  rc = ch;
2609 
2610  switch (ch)
2611  {
2612  case OP_EXIT:
2613  rc = -1;
2614  ch = -1;
2615  break;
2616 
2617  case OP_QUIT:
2618  if (query_quadoption(C_Quit, _("Quit NeoMutt?")) == MUTT_YES)
2619  {
2620  /* avoid prompting again in the index menu */
2621  cs_subset_str_native_set(NeoMutt->sub, "quit", MUTT_YES, NULL);
2622  ch = -1;
2623  }
2624  break;
2625 
2626  case OP_NEXT_PAGE:
2627  if (rd.line_info[rd.curline].offset < (rd.sb.st_size - 1))
2628  {
2629  rd.topline = up_n_lines(c_pager_context, rd.line_info, rd.curline, rd.hide_quoted);
2630  }
2631  else if (c_pager_stop)
2632  {
2633  /* emulate "less -q" and don't go on to the next message. */
2634  mutt_error(_("Bottom of message is shown"));
2635  }
2636  else
2637  {
2638  /* end of the current message, so display the next message. */
2639  rc = OP_MAIN_NEXT_UNDELETED;
2640  ch = -1;
2641  }
2642  break;
2643 
2644  case OP_PREV_PAGE:
2645  if (rd.topline == 0)
2646  {
2647  mutt_message(_("Top of message is shown"));
2648  }
2649  else
2650  {
2651  rd.topline = up_n_lines(rd.extra->win_pager->state.rows - c_pager_context,
2652  rd.line_info, rd.topline, rd.hide_quoted);
2653  }
2654  break;
2655 
2656  case OP_NEXT_LINE:
2657  if (rd.line_info[rd.curline].offset < (rd.sb.st_size - 1))
2658  {
2659  rd.topline++;
2660  if (rd.hide_quoted)
2661  {
2662  while ((rd.line_info[rd.topline].type == MT_COLOR_QUOTED) &&
2663  (rd.topline < rd.last_line))
2664  {
2665  rd.topline++;
2666  }
2667  }
2668  }
2669  else
2670  mutt_message(_("Bottom of message is shown"));
2671  break;
2672 
2673  case OP_PREV_LINE:
2674  if (rd.topline)
2675  rd.topline = up_n_lines(1, rd.line_info, rd.topline, rd.hide_quoted);
2676  else
2677  mutt_error(_("Top of message is shown"));
2678  break;
2679 
2680  case OP_PAGER_TOP:
2681  if (rd.topline)
2682  rd.topline = 0;
2683  else
2684  mutt_error(_("Top of message is shown"));
2685  break;
2686 
2687  case OP_HALF_UP:
2688  if (rd.topline)
2689  {
2690  rd.topline = up_n_lines(rd.extra->win_pager->state.rows / 2 +
2691  (rd.extra->win_pager->state.rows % 2),
2692  rd.line_info, rd.topline, rd.hide_quoted);
2693  }
2694  else
2695  mutt_error(_("Top of message is shown"));
2696  break;
2697 
2698  case OP_HALF_DOWN:
2699  if (rd.line_info[rd.curline].offset < (rd.sb.st_size - 1))
2700  {
2701  rd.topline = up_n_lines(rd.extra->win_pager->state.rows / 2,
2702  rd.line_info, rd.curline, rd.hide_quoted);
2703  }
2704  else if (c_pager_stop)
2705  {
2706  /* emulate "less -q" and don't go on to the next message. */
2707  mutt_error(_("Bottom of message is shown"));
2708  }
2709  else
2710  {
2711  /* end of the current message, so display the next message. */
2712  rc = OP_MAIN_NEXT_UNDELETED;
2713  ch = -1;
2714  }
2715  break;
2716 
2717  case OP_SEARCH_NEXT:
2718  case OP_SEARCH_OPPOSITE:
2719  if (rd.search_compiled)
2720  {
2721  wrapped = false;
2722 
2723  if (c_search_context < rd.extra->win_pager->state.rows)
2724  searchctx = c_search_context;
2725  else
2726  searchctx = 0;
2727 
2728  search_next:
2729  if ((!rd.search_back && (ch == OP_SEARCH_NEXT)) ||
2730  (rd.search_back && (ch == OP_SEARCH_OPPOSITE)))
2731  {
2732  /* searching forward */
2733  int i;
2734  for (i = wrapped ? 0 : rd.topline + searchctx + 1; i < rd.last_line; i++)
2735  {
2736  if ((!rd.hide_quoted || (rd.line_info[i].type != MT_COLOR_QUOTED)) &&
2737  !rd.line_info[i].continuation && (rd.line_info[i].search_cnt > 0))
2738  {
2739  break;
2740  }
2741  }
2742 
2743  if (i < rd.last_line)
2744  rd.topline = i;
2745  else if (wrapped || !C_WrapSearch)
2746  mutt_error(_("Not found"));
2747  else
2748  {
2749  mutt_message(_("Search wrapped to top"));
2750  wrapped = true;
2751  goto search_next;
2752  }
2753  }
2754  else
2755  {
2756  /* searching backward */
2757  int i;
2758  for (i = wrapped ? rd.last_line : rd.topline + searchctx - 1; i >= 0; i--)
2759  {
2760  if ((!rd.hide_quoted ||
2761  (rd.has_types && (rd.line_info[i].type != MT_COLOR_QUOTED))) &&
2762  !rd.line_info[i].continuation && (rd.line_info[i].search_cnt > 0))
2763  {
2764  break;
2765  }
2766  }
2767 
2768  if (i >= 0)
2769  rd.topline = i;
2770  else if (wrapped || !C_WrapSearch)
2771  mutt_error(_("Not found"));
2772  else
2773  {
2774  mutt_message(_("Search wrapped to bottom"));
2775  wrapped = true;
2776  goto search_next;
2777  }
2778  }
2779 
2780  if (rd.line_info[rd.topline].search_cnt > 0)
2781  {
2782  rd.search_flag = MUTT_SEARCH;
2783  /* give some context for search results */
2784  if (rd.topline - searchctx > 0)
2785  rd.topline -= searchctx;
2786  }
2787 
2788  break;
2789  }
2790  /* no previous search pattern */
2791  /* fallthrough */
2792 
2793  case OP_SEARCH:
2794  case OP_SEARCH_REVERSE:
2795  mutt_str_copy(buf, searchbuf, sizeof(buf));
2796  if (mutt_get_field(((ch == OP_SEARCH) || (ch == OP_SEARCH_NEXT)) ?
2797  _("Search for: ") :
2798  _("Reverse search for: "),
2799  buf, sizeof(buf), MUTT_CLEAR | MUTT_PATTERN, false,
2800  NULL, NULL) != 0)
2801  {
2802  break;
2803  }
2804 
2805  if (strcmp(buf, searchbuf) == 0)
2806  {
2807  if (rd.search_compiled)
2808  {
2809  /* do an implicit search-next */
2810  if (ch == OP_SEARCH)
2811  ch = OP_SEARCH_NEXT;
2812  else
2813  ch = OP_SEARCH_OPPOSITE;
2814 
2815  wrapped = false;
2816  goto search_next;
2817  }
2818  }
2819 
2820  if (buf[0] == '\0')
2821  break;
2822 
2823  mutt_str_copy(searchbuf, buf, sizeof(searchbuf));
2824 
2825  /* leave search_back alone if ch == OP_SEARCH_NEXT */
2826  if (ch == OP_SEARCH)
2827  rd.search_back = false;
2828  else if (ch == OP_SEARCH_REVERSE)
2829  rd.search_back = true;
2830 
2831  if (rd.search_compiled)
2832  {
2833  regfree(&rd.search_re);
2834  for (size_t i = 0; i < rd.last_line; i++)
2835  {
2836  FREE(&(rd.line_info[i].search));
2837  rd.line_info[i].search_cnt = -1;
2838  }
2839  }
2840 
2841  uint16_t rflags = mutt_mb_is_lower(searchbuf) ? REG_ICASE : 0;
2842  int err = REG_COMP(&rd.search_re, searchbuf, REG_NEWLINE | rflags);
2843  if (err != 0)
2844  {
2845  regerror(err, &rd.search_re, buf, sizeof(buf));
2846  mutt_error("%s", buf);
2847  for (size_t i = 0; i < rd.max_line; i++)
2848  {
2849  /* cleanup */
2850  FREE(&(rd.line_info[i].search));
2851  rd.line_info[i].search_cnt = -1;
2852  }
2853  rd.search_flag = 0;
2854  rd.search_compiled = false;
2855  }
2856  else
2857  {
2858  rd.search_compiled = true;
2859  /* update the search pointers */
2860  int line_num = 0;
2861  while (display_line(rd.fp, &rd.last_pos, &rd.line_info, line_num,
2862  &rd.last_line, &rd.max_line,
2863  MUTT_SEARCH | (flags & MUTT_PAGER_NSKIP) | (flags & MUTT_PAGER_NOWRAP),
2864  &rd.quote_list, &rd.q_level, &rd.force_redraw,
2865  &rd.search_re, rd.extra->win_pager) == 0)
2866  {
2867  line_num++;
2868  }
2869 
2870  if (!rd.search_back)
2871  {
2872  /* searching forward */
2873  int i;
2874  for (i = rd.topline; i < rd.last_line; i++)
2875  {
2876  if ((!rd.hide_quoted || (rd.line_info[i].type != MT_COLOR_QUOTED)) &&
2877  !rd.line_info[i].continuation && (rd.line_info[i].search_cnt > 0))
2878  {
2879  break;
2880  }
2881  }
2882 
2883  if (i < rd.last_line)
2884  rd.topline = i;
2885  }
2886  else
2887  {
2888  /* searching backward */
2889  int i;
2890  for (i = rd.topline; i >= 0; i--)
2891  {
2892  if ((!rd.hide_quoted || (rd.line_info[i].type != MT_COLOR_QUOTED)) &&
2893  !rd.line_info[i].continuation && (rd.line_info[i].search_cnt > 0))
2894  {
2895  break;
2896  }
2897  }
2898 
2899  if (i >= 0)
2900  rd.topline = i;
2901  }
2902 
2903  if (rd.line_info[rd.topline].search_cnt == 0)
2904  {
2905  rd.search_flag = 0;
2906  mutt_error(_("Not found"));
2907  }
2908  else
2909  {
2910  rd.search_flag = MUTT_SEARCH;
2911  /* give some context for search results */
2912  if (c_search_context < rd.extra->win_pager->state.rows)
2913  searchctx = c_search_context;
2914  else
2915  searchctx = 0;
2916  if (rd.topline - searchctx > 0)
2917  rd.topline -= searchctx;
2918  }
2919  }
2920  pager_menu->redraw = REDRAW_BODY;
2921  break;
2922 
2923  case OP_SEARCH_TOGGLE:
2924  if (rd.search_compiled)
2925  {
2926  rd.search_flag ^= MUTT_SEARCH;
2927  pager_menu->redraw = REDRAW_BODY;
2928  }
2929  break;
2930 
2931  case OP_SORT:
2932  case OP_SORT_REVERSE:
2933  if (!assert_pager_mode(IsEmail(extra)))
2934  break;
2935  if (mutt_select_sort((ch == OP_SORT_REVERSE)) == 0)
2936  {
2937  OptNeedResort = true;
2938  ch = -1;
2939  rc = OP_DISPLAY_MESSAGE;
2940  }
2941  break;
2942 
2943  case OP_HELP:
2944  if (InHelp)
2945  {
2946  /* don't let the user enter the help-menu from the help screen! */
2947  mutt_error(_("Help is currently being shown"));
2948  break;
2949  }
2950 
2951  InHelp = true;
2953  pager_menu->redraw = REDRAW_FULL;
2954  InHelp = false;
2955  break;
2956 
2957  case OP_PAGER_HIDE_QUOTED:
2958  if (!rd.has_types)
2959  break;
2960 
2961  rd.hide_quoted ^= MUTT_HIDE;
2962  if (rd.hide_quoted && (rd.line_info[rd.topline].type == MT_COLOR_QUOTED))
2963  rd.topline = up_n_lines(1, rd.line_info, rd.topline, rd.hide_quoted);
2964  else
2965  pager_menu->redraw = REDRAW_BODY;
2966  break;
2967 
2968  case OP_PAGER_SKIP_QUOTED:
2969  {
2970  if (!rd.has_types)
2971  break;
2972 
2973  int dretval = 0;
2974  int new_topline = rd.topline;
2975 
2976  /* Skip all the email headers */
2977  if (IS_HEADER(rd.line_info[new_topline].type))
2978  {
2979  while (((new_topline < rd.last_line) ||
2980  (0 == (dretval = display_line(
2981  rd.fp, &rd.last_pos, &rd.line_info, new_topline, &rd.last_line,
2982  &rd.max_line, MUTT_TYPES | (flags & MUTT_PAGER_NOWRAP),
2983  &rd.quote_list, &rd.q_level, &rd.force_redraw,
2984  &rd.search_re, rd.extra->win_pager)))) &&
2985  IS_HEADER(rd.line_info[new_topline].type))
2986  {
2987  new_topline++;
2988  }
2989  rd.topline = new_topline;
2990  break;
2991  }
2992 
2993  while ((((new_topline + c_skip_quoted_offset) < rd.last_line) ||
2994  (0 == (dretval = display_line(
2995  rd.fp, &rd.last_pos, &rd.line_info, new_topline, &rd.last_line,
2996  &rd.max_line, MUTT_TYPES | (flags & MUTT_PAGER_NOWRAP),
2997  &rd.quote_list, &rd.q_level, &rd.force_redraw,
2998  &rd.search_re, rd.extra->win_pager)))) &&
2999  (rd.line_info[new_topline + c_skip_quoted_offset].type != MT_COLOR_QUOTED))
3000  {
3001  new_topline++;
3002  }
3003 
3004  if (dretval < 0)
3005  {
3006  mutt_error(_("No more quoted text"));
3007  break;
3008  }
3009 
3010  while ((((new_topline + c_skip_quoted_offset) < rd.last_line) ||
3011  (0 == (dretval = display_line(
3012  rd.fp, &rd.last_pos, &rd.line_info, new_topline, &rd.last_line,
3013  &rd.max_line, MUTT_TYPES | (flags & MUTT_PAGER_NOWRAP),
3014  &rd.quote_list, &rd.q_level, &rd.force_redraw,
3015  &rd.search_re, rd.extra->win_pager)))) &&
3016  (rd.line_info[new_topline + c_skip_quoted_offset].type == MT_COLOR_QUOTED))
3017  {
3018  new_topline++;
3019  }
3020 
3021  if (dretval < 0)
3022  {
3023  mutt_error(_("No more unquoted text after quoted text"));
3024  break;
3025  }
3026  rd.topline = new_topline;
3027  break;
3028  }
3029 
3030  case OP_PAGER_SKIP_HEADERS:
3031  {
3032  if (!rd.has_types)
3033  break;
3034 
3035  int dretval = 0;
3036  int new_topline = rd.topline;
3037 
3038  if (!IS_HEADER(rd.line_info[new_topline].type))
3039  {
3040  /* L10N: Displayed if <skip-headers> is invoked in the pager, but we
3041  are already past the headers */
3042  mutt_message(_("Already skipped past headers"));
3043  break;
3044  }
3045 
3046  while (((new_topline < rd.last_line) ||
3047  (0 == (dretval = display_line(
3048  rd.fp, &rd.last_pos, &rd.line_info, new_topline, &rd.last_line,
3049  &rd.max_line, MUTT_TYPES | (flags & MUTT_PAGER_NOWRAP),
3050  &rd.quote_list, &rd.q_level, &rd.force_redraw,
3051  &rd.search_re, rd.extra->win_pager)))) &&
3052  IS_HEADER(rd.line_info[new_topline].type))
3053  {
3054  new_topline++;
3055  }
3056 
3057  if (dretval < 0)
3058  {
3059  /* L10N: Displayed if <skip-headers> is invoked in the pager, but
3060  there is no text past the headers.
3061  (I don't think this is actually possible in Mutt's code, but
3062  display some kind of message in case it somehow occurs.) */
3063  mutt_warning(_("No text past headers"));
3064  break;
3065  }
3066  rd.topline = new_topline;
3067  break;
3068  }
3069 
3070  case OP_PAGER_BOTTOM: /* move to the end of the file */
3071  if (rd.line_info[rd.curline].offset < (rd.sb.st_size - 1))
3072  {
3073  int line_num = rd.curline;
3074  /* make sure the types are defined to the end of file */
3075  while (display_line(rd.fp, &rd.last_pos, &rd.line_info, line_num, &rd.last_line,
3076  &rd.max_line, rd.has_types | (flags & MUTT_PAGER_NOWRAP),
3077  &rd.quote_list, &rd.q_level, &rd.force_redraw,
3078  &rd.search_re, rd.extra->win_pager) == 0)
3079  {
3080  line_num++;
3081  }
3083  rd.last_line, rd.hide_quoted);
3084  }
3085  else
3086  mutt_error(_("Bottom of message is shown"));
3087  break;
3088 
3089  case OP_REDRAW:
3090  mutt_window_reflow(NULL);
3091  clearok(stdscr, true);
3092  pager_menu->redraw = REDRAW_FULL;
3093  break;
3094 
3095  case OP_NULL:
3097  break;
3098 
3099  /* --------------------------------------------------------------------
3100  * The following are operations on the current message rather than
3101  * adjusting the view of the message. */
3102 
3103  case OP_BOUNCE_MESSAGE:
3104  {
3105  if (!assert_pager_mode(IsEmail(extra) || IsMsgAttach(extra)))
3106  break;
3108  break;
3109  if (IsMsgAttach(extra))
3110  mutt_attach_bounce(m, extra->fp, extra->actx, extra->body);
3111  else
3112  {
3113  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3114  emaillist_add_email(&el, extra->email);
3115  ci_bounce_message(m, &el);
3116  emaillist_clear(&el);
3117  }
3118  break;
3119  }
3120 
3121  case OP_RESEND:
3122  if (!assert_pager_mode(IsEmail(extra) || IsMsgAttach(extra)))
3123  break;
3125  break;
3126  if (IsMsgAttach(extra))
3127  mutt_attach_resend(extra->fp, extra->ctx, extra->actx, extra->body);
3128  else
3129  mutt_resend_message(NULL, extra->ctx, extra->email, NeoMutt->sub);
3130  pager_menu->redraw = REDRAW_FULL;
3131  break;
3132 
3133  case OP_COMPOSE_TO_SENDER:
3134  if (!assert_pager_mode(IsEmail(extra) || IsMsgAttach(extra)))
3135  break;
3137  break;
3138  if (IsMsgAttach(extra))
3139  mutt_attach_mail_sender(extra->fp, extra->email, extra->actx, extra->body);
3140  else
3141  {
3142  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3143  emaillist_add_email(&el, extra->email);
3144  mutt_send_message(SEND_TO_SENDER, NULL, NULL, extra->ctx, &el, NeoMutt->sub);
3145  emaillist_clear(&el);
3146  }
3147  pager_menu->redraw = REDRAW_FULL;
3148  break;
3149 
3150  case OP_CHECK_TRADITIONAL:
3151  if (!assert_pager_mode(IsEmail(extra)))
3152  break;
3153  if (!(WithCrypto & APPLICATION_PGP))
3154  break;
3155  if (!(extra->email->security & PGP_TRADITIONAL_CHECKED))
3156  {
3157  ch = -1;
3158  rc = OP_CHECK_TRADITIONAL;
3159  }
3160  break;
3161 
3162  case OP_CREATE_ALIAS:
3163  if (!assert_pager_mode(IsEmail(extra) || IsMsgAttach(extra)))
3164  break;
3165  struct AddressList *al = NULL;
3166  if (IsMsgAttach(extra))
3167  al = mutt_get_address(extra->body->email->env, NULL);
3168  else
3169  al = mutt_get_address(extra->email->env, NULL);
3170  alias_create(al, NeoMutt->sub);
3171  break;
3172 
3173  case OP_PURGE_MESSAGE:
3174  case OP_DELETE:
3175  if (!assert_pager_mode(IsEmail(extra)))
3176  break;
3178  break;
3179  /* L10N: CHECK_ACL */
3181  _("Can't delete message")))
3182  {
3183  break;
3184  }
3185 
3186  mutt_set_flag(Context->mailbox, extra->email, MUTT_DELETE, true);
3187  mutt_set_flag(Context->mailbox, extra->email, MUTT_PURGE, (ch == OP_PURGE_MESSAGE));
3188  if (C_DeleteUntag)
3189  mutt_set_flag(Context->mailbox, extra->email, MUTT_TAG, false);
3190  pager_menu->redraw |= REDRAW_STATUS | REDRAW_INDEX;
3191  if (C_Resolve)
3192  {
3193  ch = -1;
3194  rc = OP_MAIN_NEXT_UNDELETED;
3195  }
3196  break;
3197 
3198  case OP_MAIN_SET_FLAG:
3199  case OP_MAIN_CLEAR_FLAG:
3200  {
3201  if (!assert_pager_mode(IsEmail(extra)))
3202  break;
3204  break;
3205 
3206  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3207  emaillist_add_email(&el, extra->email);
3208 
3209  if (mutt_change_flag(Context->mailbox, &el, (ch == OP_MAIN_SET_FLAG)) == 0)
3210  pager_menu->redraw |= REDRAW_STATUS | REDRAW_INDEX;
3211  if (extra->email->deleted && C_Resolve)
3212  {
3213  ch = -1;
3214  rc = OP_MAIN_NEXT_UNDELETED;
3215  }
3216  emaillist_clear(&el);
3217  break;
3218  }
3219 
3220  case OP_DELETE_THREAD:
3221  case OP_DELETE_SUBTHREAD:
3222  case OP_PURGE_THREAD:
3223  {
3224  if (!assert_pager_mode(IsEmail(extra)))
3225  break;
3227  break;
3228  /* L10N: CHECK_ACL */
3229  /* L10N: Due to the implementation details we do not know whether we
3230  delete zero, 1, 12, ... messages. So in English we use
3231  "messages". Your language might have other means to express this. */
3233  _("Can't delete messages")))
3234  {
3235  break;
3236  }
3237 
3238  int subthread = (ch == OP_DELETE_SUBTHREAD);
3239  int r = mutt_thread_set_flag(m, extra->email, MUTT_DELETE, 1, subthread);
3240  if (r == -1)
3241  break;
3242  if (ch == OP_PURGE_THREAD)
3243  {
3244  r = mutt_thread_set_flag(m, extra->email, MUTT_PURGE, true, subthread);
3245  if (r == -1)
3246  break;
3247  }
3248 
3249  if (C_DeleteUntag)
3250  mutt_thread_set_flag(m, extra->email, MUTT_TAG, 0, subthread);
3251  if (C_Resolve)
3252  {
3253  rc = OP_MAIN_NEXT_UNDELETED;
3254  ch = -1;
3255  }
3256 
3257  if (!C_Resolve && (c_pager_index_lines != 0))
3258  pager_menu->redraw = REDRAW_FULL;
3259  else
3260  pager_menu->redraw |= REDRAW_STATUS | REDRAW_INDEX;
3261 
3262  break;
3263  }
3264 
3265  case OP_DISPLAY_ADDRESS:
3266  if (!assert_pager_mode(IsEmail(extra) || IsMsgAttach(extra)))
3267  break;
3268  if (IsMsgAttach(extra))
3269  mutt_display_address(extra->body->email->env);
3270  else
3271  mutt_display_address(extra->email->env);
3272  break;
3273 
3274  case OP_ENTER_COMMAND:
3275  old_PagerIndexLines = c_pager_index_lines;
3276 
3279  pager_menu->redraw = REDRAW_FULL;
3280 
3281  if (OptNeedResort)
3282  {
3283  OptNeedResort = false;
3284  if (!assert_pager_mode(IsEmail(extra)))
3285  break;
3286  OptNeedResort = true;
3287  }
3288 
3289  if (old_PagerIndexLines != c_pager_index_lines)
3290  {
3291  mutt_menu_free(&rd.menu);
3292  }
3293 
3294  if ((pager_menu->redraw & REDRAW_FLOW) && (flags & MUTT_PAGER_RETWINCH))
3295  {
3296  ch = -1;
3297  rc = OP_REFORMAT_WINCH;
3298  continue;
3299  }
3300 
3301  ch = 0;
3302  break;
3303 
3304  case OP_FLAG_MESSAGE:
3305  if (!assert_pager_mode(IsEmail(extra)))
3306  break;
3308  break;
3309  /* L10N: CHECK_ACL */
3310  if (!assert_mailbox_permissions(Context->mailbox, MUTT_ACL_WRITE, "Can't flag message"))
3311  break;
3312 
3313  mutt_set_flag(Context->mailbox, extra->email, MUTT_FLAG, !extra->email->flagged);
3314  pager_menu->redraw |= REDRAW_STATUS | REDRAW_INDEX;
3315  if (C_Resolve)
3316  {
3317  ch = -1;
3318  rc = OP_MAIN_NEXT_UNDELETED;
3319  }
3320  break;
3321 
3322  case OP_PIPE:
3323  if (!assert_pager_mode(IsEmail(extra) || IsAttach(extra)))
3324  break;
3325  if (IsAttach(extra))
3326  mutt_pipe_attachment_list(extra->actx, extra->fp, false, extra->body, false);
3327  else
3328  {
3329  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3330  el_add_tagged(&el, extra->ctx, extra->email, false);
3331  mutt_pipe_message(extra->ctx->mailbox, &el);
3332  emaillist_clear(&el);
3333  }
3334  break;
3335 
3336  case OP_PRINT:
3337  if (!assert_pager_mode(IsEmail(extra) || IsAttach(extra)))
3338  break;
3339  if (IsAttach(extra))
3340  mutt_print_attachment_list(extra->actx, extra->fp, false, extra->body);
3341  else
3342  {
3343  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3344  el_add_tagged(&el, extra->ctx, extra->email, false);
3345  mutt_print_message(extra->ctx->mailbox, &el);
3346  emaillist_clear(&el);
3347  }
3348  break;
3349 
3350  case OP_MAIL:
3351  if (!assert_pager_mode(IsEmail(extra)))
3352  break;
3354  break;
3355  mutt_send_message(SEND_NO_FLAGS, NULL, NULL, extra->ctx, NULL, NeoMutt->sub);
3356  pager_menu->redraw = REDRAW_FULL;
3357  break;
3358 
3359 #ifdef USE_NNTP
3360  case OP_POST:
3361  if (!assert_pager_mode(IsEmail(extra)))
3362  break;
3364  break;
3365  if (extra->ctx && (extra->ctx->mailbox->type == MUTT_NNTP) &&
3366  !((struct NntpMboxData *) extra->ctx->mailbox->mdata)->allowed && (query_quadoption(C_PostModerated, _("Posting to this group not allowed, may be moderated. Continue?")) != MUTT_YES))
3367  {
3368  break;
3369  }
3370  mutt_send_message(SEND_NEWS, NULL, NULL, extra->ctx, NULL, NeoMutt->sub);
3371  pager_menu->redraw = REDRAW_FULL;
3372  break;
3373 
3374  case OP_FORWARD_TO_GROUP:
3375  if (!assert_pager_mode(IsEmail(extra) || IsMsgAttach(extra)))
3376  break;
3378  break;
3379  if (extra->ctx && (extra->ctx->mailbox->type == MUTT_NNTP) &&
3380  !((struct NntpMboxData *) extra->ctx->mailbox->mdata)->allowed && (query_quadoption(C_PostModerated, _("Posting to this group not allowed, may be moderated. Continue?")) != MUTT_YES))
3381  {
3382  break;
3383  }
3384  if (IsMsgAttach(extra))
3385  mutt_attach_forward(extra->fp, m, extra->email, extra->actx, extra->body, SEND_NEWS);
3386  else
3387  {
3388  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3389  emaillist_add_email(&el, extra->email);
3390  mutt_send_message(SEND_NEWS | SEND_FORWARD, NULL, NULL, extra->ctx,
3391  &el, NeoMutt->sub);
3392  emaillist_clear(&el);
3393  }
3394  pager_menu->redraw = REDRAW_FULL;
3395  break;
3396 
3397  case OP_FOLLOWUP:
3398  if (!assert_pager_mode(IsEmail(extra) || IsMsgAttach(extra)))
3399  break;
3401  break;
3402 
3403  if (IsMsgAttach(extra))
3404  followup_to = extra->body->email->env->followup_to;
3405  else
3406  followup_to = extra->email->env->followup_to;
3407 
3408  if (!followup_to || !mutt_istr_equal(followup_to, "poster") ||
3410  _("Reply by mail as poster prefers?")) != MUTT_YES))
3411  {
3412  if (extra->ctx && (extra->ctx->mailbox->type == MUTT_NNTP) &&
3413  !((struct NntpMboxData *) extra->ctx->mailbox->mdata)->allowed && (query_quadoption(C_PostModerated, _("Posting to this group not allowed, may be moderated. Continue?")) != MUTT_YES))
3414  {
3415  break;
3416  }
3417  if (IsMsgAttach(extra))
3418  {
3419  mutt_attach_reply(extra->fp, m, extra->email, extra->actx,
3420  extra->body, SEND_NEWS | SEND_REPLY);
3421  }
3422  else
3423  {
3424  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3425  emaillist_add_email(&el, extra->email);
3426  mutt_send_message(SEND_NEWS | SEND_REPLY, NULL, NULL, extra->ctx,
3427  &el, NeoMutt->sub);
3428  emaillist_clear(&el);
3429  }
3430  pager_menu->redraw = REDRAW_FULL;
3431  break;
3432  }
3433 #endif
3434  /* fallthrough */
3435  case OP_REPLY:
3436  case OP_GROUP_REPLY:
3437  case OP_GROUP_CHAT_REPLY:
3438  case OP_LIST_REPLY:
3439  {
3440  if (!assert_pager_mode(IsEmail(extra) || IsMsgAttach(extra)))
3441  break;
3443  break;
3444 
3445  SendFlags replyflags = SEND_REPLY;
3446  if (ch == OP_GROUP_REPLY)
3447  replyflags |= SEND_GROUP_REPLY;
3448  else if (ch == OP_GROUP_CHAT_REPLY)
3449  replyflags |= SEND_GROUP_CHAT_REPLY;
3450  else if (ch == OP_LIST_REPLY)
3451  replyflags |= SEND_LIST_REPLY;
3452 
3453  if (IsMsgAttach(extra))
3454  mutt_attach_reply(extra->fp, m, extra->email, extra->actx, extra->body, replyflags);
3455  else
3456  {
3457  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3458  emaillist_add_email(&el, extra->email);
3459  mutt_send_message(replyflags, NULL, NULL, extra->ctx, &el, NeoMutt->sub);
3460  emaillist_clear(&el);
3461  }
3462  pager_menu->redraw = REDRAW_FULL;
3463  break;
3464  }
3465 
3466  case OP_RECALL_MESSAGE:
3467  {
3468  if (!assert_pager_mode(IsEmail(extra)))
3469  break;
3471  break;
3472  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3473  emaillist_add_email(&el, extra->email);
3474  mutt_send_message(SEND_POSTPONED, NULL, NULL, extra->ctx, &el, NeoMutt->sub);
3475  emaillist_clear(&el);
3476  pager_menu->redraw = REDRAW_FULL;
3477  break;
3478  }
3479 
3480  case OP_FORWARD_MESSAGE:
3481  if (!assert_pager_mode(IsEmail(extra) || IsMsgAttach(extra)))
3482  break;
3484  break;
3485  if (IsMsgAttach(extra))
3486  mutt_attach_forward(extra->fp, m, extra->email, extra->actx,
3487  extra->body, SEND_NO_FLAGS);
3488  else
3489  {
3490  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3491  emaillist_add_email(&el, extra->email);
3492  mutt_send_message(SEND_FORWARD, NULL, NULL, extra->ctx, &el, NeoMutt->sub);
3493  emaillist_clear(&el);
3494  }
3495  pager_menu->redraw = REDRAW_FULL;
3496  break;
3497 
3498  case OP_DECRYPT_SAVE:
3499  if (!WithCrypto)
3500  {
3501  ch = -1;
3502  break;
3503  }
3504  /* fallthrough */
3505  case OP_SAVE:
3506  if (IsAttach(extra))
3507  {
3508  mutt_save_attachment_list(extra->actx, extra->fp, false, extra->body,
3509  extra->email, NULL);
3510  break;
3511  }
3512  /* fallthrough */
3513  case OP_COPY_MESSAGE:
3514  case OP_DECODE_SAVE:
3515  case OP_DECODE_COPY:
3516  case OP_DECRYPT_COPY:
3517  {
3518  if (!(WithCrypto != 0) && (ch == OP_DECRYPT_COPY))
3519  {
3520  ch = -1;
3521  break;
3522  }
3523  if (!assert_pager_mode(IsEmail(extra)))
3524  break;
3525  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3526  emaillist_add_email(&el, extra->email);
3527 
3528  const enum MessageSaveOpt save_opt =
3529  ((ch == OP_SAVE) || (ch == OP_DECODE_SAVE) || (ch == OP_DECRYPT_SAVE)) ?
3530  SAVE_MOVE :
3531  SAVE_COPY;
3532 
3533  enum MessageTransformOpt transform_opt =
3534  ((ch == OP_DECODE_SAVE) || (ch == OP_DECODE_COPY)) ? TRANSFORM_DECODE :
3535  ((ch == OP_DECRYPT_SAVE) || (ch == OP_DECRYPT_COPY)) ? TRANSFORM_DECRYPT :
3537 
3538  const int rc2 = mutt_save_message(Context->mailbox, &el, save_opt, transform_opt);
3539  if ((rc2 == 0) && (save_opt == SAVE_MOVE))
3540  {
3541  if (C_Resolve)
3542  {
3543  ch = -1;
3544  rc = OP_MAIN_NEXT_UNDELETED;
3545  }
3546  else
3547  pager_menu->redraw |= REDRAW_STATUS | REDRAW_INDEX;
3548  }
3549  emaillist_clear(&el);
3550  break;
3551  }
3552 
3553  case OP_SHELL_ESCAPE:
3554  if (mutt_shell_escape())
3555  {
3557  }
3558  break;
3559 
3560  case OP_TAG:
3561  if (!assert_pager_mode(IsEmail(extra)))
3562  break;
3563  if (Context)
3564  {
3565  mutt_set_flag(Context->mailbox, extra->email, MUTT_TAG, !extra->email->tagged);
3566  }
3567 
3568  pager_menu->redraw |= REDRAW_STATUS | REDRAW_INDEX;
3569  if (C_Resolve)
3570  {
3571  ch = -1;
3572  rc = OP_NEXT_ENTRY;
3573  }
3574  break;
3575 
3576  case OP_TOGGLE_NEW:
3577  if (!assert_pager_mode(IsEmail(extra)))
3578  break;
3580  break;
3581  /* L10N: CHECK_ACL */
3582  if (!assert_mailbox_permissions(Context->mailbox, MUTT_ACL_SEEN, _("Can't toggle new")))
3583  break;
3584 
3585  if (extra->email->read || extra->email->old)
3586  mutt_set_flag(Context->mailbox, extra->email, MUTT_NEW, true);
3587  else if (!first)
3588  mutt_set_flag(Context->mailbox, extra->email, MUTT_READ, true);
3589  first = false;
3590  Context->msg_in_pager = -1;
3591  pager_menu->redraw |= REDRAW_STATUS | REDRAW_INDEX;
3592  if (C_Resolve)
3593  {
3594  ch = -1;
3595  rc = OP_MAIN_NEXT_UNDELETED;
3596  }
3597  break;
3598 
3599  case OP_UNDELETE:
3600  if (!assert_pager_mode(IsEmail(extra)))
3601  break;
3603  break;
3604  /* L10N: CHECK_ACL */
3606  _("Can't undelete message")))
3607  {
3608  break;
3609  }
3610 
3611  mutt_set_flag(Context->mailbox, extra->email, MUTT_DELETE, false);
3612  mutt_set_flag(Context->mailbox, extra->email, MUTT_PURGE, false);
3613  pager_menu->redraw |= REDRAW_STATUS | REDRAW_INDEX;
3614  if (C_Resolve)
3615  {
3616  ch = -1;
3617  rc = OP_NEXT_ENTRY;
3618  }
3619  break;
3620 
3621  case OP_UNDELETE_THREAD:
3622  case OP_UNDELETE_SUBTHREAD:
3623  {
3624  if (!assert_pager_mode(IsEmail(extra)))
3625  break;
3627  break;
3628  /* L10N: CHECK_ACL */
3629  /* L10N: Due to the implementation details we do not know whether we
3630  undelete zero, 1, 12, ... messages. So in English we use
3631  "messages". Your language might have other means to express this. */
3633  _("Can't undelete messages")))
3634  {
3635  break;
3636  }
3637 
3638  int r = mutt_thread_set_flag(m, extra->email, MUTT_DELETE, false,
3639  (ch != OP_UNDELETE_THREAD));
3640  if (r != -1)
3641  {
3642  r = mutt_thread_set_flag(m, extra->email, MUTT_PURGE, false,
3643  (ch != OP_UNDELETE_THREAD));
3644  }
3645  if (r != -1)
3646  {
3647  if (C_Resolve)
3648  {
3649  rc = (ch == OP_DELETE_THREAD) ? OP_MAIN_NEXT_THREAD : OP_MAIN_NEXT_SUBTHREAD;
3650  ch = -1;
3651  }
3652 
3653  if (!C_Resolve && (c_pager_index_lines != 0))
3654  pager_menu->redraw = REDRAW_FULL;
3655  else
3656  pager_menu->redraw |= REDRAW_STATUS | REDRAW_INDEX;
3657  }
3658  break;
3659  }
3660 
3661  case OP_VERSION:
3663  break;
3664 
3665  case OP_MAILBOX_LIST:
3667  break;
3668 
3669  case OP_VIEW_ATTACHMENTS:
3670  if (flags & MUTT_PAGER_ATTACHMENT)
3671  {
3672  ch = -1;
3673  rc = OP_ATTACH_COLLAPSE;
3674  break;
3675  }
3676  if (!assert_pager_mode(IsEmail(extra)))
3677  break;
3678  dlg_select_attachment(extra->email);
3679  if (Context && extra->email->attach_del)
3680  Context->mailbox->changed = true;
3681  pager_menu->redraw = REDRAW_FULL;
3682  break;
3683 
3684  case OP_MAIL_KEY:
3685  {
3686  if (!(WithCrypto & APPLICATION_PGP))
3687  {
3688  ch = -1;
3689  break;
3690  }
3691  if (!assert_pager_mode(IsEmail(extra)))
3692  break;
3694  break;
3695  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3696  emaillist_add_email(&el, extra->email);
3697  mutt_send_message(SEND_KEY, NULL, NULL, extra->ctx, &el, NeoMutt->sub);
3698  emaillist_clear(&el);
3699  pager_menu->redraw = REDRAW_FULL;
3700  break;
3701  }
3702 
3703  case OP_EDIT_LABEL:
3704  {
3705  if (!assert_pager_mode(IsEmail(extra)))
3706  break;
3707 
3708  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3709  emaillist_add_email(&el, extra->email);
3710  rc = mutt_label_message(Context->mailbox, &el);
3711  emaillist_clear(&el);
3712 
3713  if (rc > 0)
3714  {
3715  Context->mailbox->changed = true;
3716  pager_menu->redraw = REDRAW_FULL;
3717  mutt_message(ngettext("%d label changed", "%d labels changed", rc), rc);
3718  }
3719  else
3720  {
3721  mutt_message(_("No labels changed"));
3722  }
3723  break;
3724  }
3725 
3726  case OP_FORGET_PASSPHRASE:
3728  break;
3729 
3730  case OP_EXTRACT_KEYS:
3731  {
3732  if (!WithCrypto)
3733  {
3734  ch = -1;
3735  break;
3736  }
3737  if (!assert_pager_mode(IsEmail(extra)))
3738  break;
3739  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3740  emaillist_add_email(&el, extra->email);
3742  emaillist_clear(&el);
3743  pager_menu->redraw = REDRAW_FULL;
3744  break;
3745  }
3746 
3747  case OP_WHAT_KEY:
3748  mutt_what_key();
3749  break;
3750 
3751  case OP_CHECK_STATS:
3753  break;
3754 
3755 #ifdef USE_SIDEBAR
3756  case OP_SIDEBAR_FIRST:
3757  case OP_SIDEBAR_LAST:
3758  case OP_SIDEBAR_NEXT:
3759  case OP_SIDEBAR_NEXT_NEW:
3760  case OP_SIDEBAR_PAGE_DOWN:
3761  case OP_SIDEBAR_PAGE_UP:
3762  case OP_SIDEBAR_PREV:
3763  case OP_SIDEBAR_PREV_NEW:
3764  {
3765  struct MuttWindow *win_sidebar =
3767  if (!win_sidebar)
3768  break;
3769  sb_change_mailbox(win_sidebar, ch);
3770  break;
3771  }
3772 
3773  case OP_SIDEBAR_TOGGLE_VISIBLE:
3774  bool_str_toggle(NeoMutt->sub, "sidebar_visible", NULL);
3776  break;
3777 #endif
3778 
3779  default:
3780  ch = -1;
3781  break;
3782  }
3783  }
3784 
3785  mutt_file_fclose(&rd.fp);
3786  if (IsEmail(extra))
3787  {
3788  if (Context)
3789  Context->msg_in_pager = -1;
3790  switch (rc)
3791  {
3792  case -1:
3793  case OP_DISPLAY_HEADERS:
3795  break;
3796  default:
3797  TopLine = rd.topline;
3798  OldEmail = extra->email;
3799  break;
3800  }
3801  }
3802 
3804 
3805  for (size_t i = 0; i < rd.max_line; i++)
3806  {
3807  FREE(&(rd.line_info[i].syntax));
3808  if (rd.search_compiled && rd.line_info[i].search)
3809  FREE(&(rd.line_info[i].search));
3810  }
3811  if (rd.search_compiled)
3812  {
3813  regfree(&rd.search_re);
3814  rd.search_compiled = false;
3815  }
3816  FREE(&rd.line_info);
3817  mutt_menu_pop_current(pager_menu);
3818  mutt_menu_free(&pager_menu);
3819  mutt_menu_free(&rd.menu);
3820 
3821  if (rd.extra->win_index)
3822  {
3828  }
3831 
3832  return (rc != -1) ? rc : 0;
3833 }
+ Here is the caller graph for this function:

Variable Documentation

◆ TopLine

int TopLine = 0
static

Definition at line 191 of file pager.c.

◆ OldEmail

struct Email* OldEmail = NULL
static

Definition at line 192 of file pager.c.

◆ InHelp

bool InHelp = false
static

Definition at line 194 of file pager.c.

◆ braille_line

int braille_line = -1
static

Definition at line 196 of file pager.c.

◆ braille_col

int braille_col = -1
static

Definition at line 197 of file pager.c.

◆ Resize

struct Resize* Resize = NULL
static

Definition at line 199 of file pager.c.

◆ Not_available_in_this_menu

const char* Not_available_in_this_menu
static
Initial value:
=
N_("Not available in this menu")

Definition at line 201 of file pager.c.

◆ Mailbox_is_read_only

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

Definition at line 203 of file pager.c.

◆ Function_not_permitted_in_attach_message_mode

const char* Function_not_permitted_in_attach_message_mode
static
Initial value:
=
N_("Function not permitted in attach-message mode")

Definition at line 204 of file pager.c.

◆ PagerHelp

const struct Mapping PagerHelp[]
static
Initial value:
= {
{ N_("Exit"), OP_EXIT },
{ N_("PrevPg"), OP_PREV_PAGE },
{ N_("NextPg"), OP_NEXT_PAGE },
{ N_("Help"), OP_HELP },
{ NULL, 0 },
}

Help Bar for the Pager's Help Page.

Definition at line 208 of file pager.c.

◆ PagerHelpHelp

const struct Mapping PagerHelpHelp[]
static
Initial value:
= {
{ N_("Exit"), OP_EXIT },
{ N_("PrevPg"), OP_PREV_PAGE },
{ N_("NextPg"), OP_NEXT_PAGE },
{ NULL, 0 },
}

Help Bar for the Help Page itself.

Definition at line 219 of file pager.c.

◆ PagerNormalHelp

const struct Mapping PagerNormalHelp[]
static
Initial value:
= {
{ N_("Exit"), OP_EXIT },
{ N_("PrevPg"), OP_PREV_PAGE },
{ N_("NextPg"), OP_NEXT_PAGE },
{ N_("View Attachm."), OP_VIEW_ATTACHMENTS },
{ N_("Del"), OP_DELETE },
{ N_("Reply"), OP_REPLY },
{ N_("Next"), OP_MAIN_NEXT_UNDELETED },
{ N_("Help"), OP_HELP },
{ NULL, 0 },
}

Help Bar for the Pager of a normal Mailbox.

Definition at line 229 of file pager.c.

◆ PagerNewsHelp

const struct Mapping PagerNewsHelp[]
static
Initial value:
= {
{ N_("Exit"), OP_EXIT },
{ N_("PrevPg"), OP_PREV_PAGE },
{ N_("NextPg"), OP_NEXT_PAGE },
{ N_("Post"), OP_POST },
{ N_("Followup"), OP_FOLLOWUP },
{ N_("Del"), OP_DELETE },
{ N_("Next"), OP_MAIN_NEXT_UNDELETED },
{ N_("Help"), OP_HELP },
{ NULL, 0 },
}

Help Bar for the Pager of an NNTP Mailbox.

Definition at line 245 of file pager.c.

MT_COLOR_UNDERLINE
@ MT_COLOR_UNDERLINE
Underlined text.
Definition: color.h:97
ctx_free
void ctx_free(struct Context **ptr)
Free a Context.
Definition: context.c:50
Function_not_permitted_in_attach_message_mode
static const char * Function_not_permitted_in_attach_message_mode
Definition: pager.c:204
AnsiAttr::bg
int bg
Background colour.
Definition: pager.c:142
Line::syntax
struct TextSyntax * syntax
Definition: pager.c:129
mutt_get_virt_email
struct Email * mutt_get_virt_email(struct Mailbox *m, int vnum)
Get a virtual Email.
Definition: context.c:397
mutt_color_free
void mutt_color_free(struct Colors *c, uint32_t fg, uint32_t bg)
Free a colour.
Definition: color.c:252
mutt_curses_set_cursor
void mutt_curses_set_cursor(enum MuttCursorState state)
Set the cursor state.
Definition: mutt_curses.c:78
SendFlags
uint16_t SendFlags
Flags for mutt_send_message(), e.g. SEND_REPLY.
Definition: send.h:37
Email::msgno
int msgno
Number displayed to the user.
Definition: email.h:87
SEND_GROUP_CHAT_REPLY
#define SEND_GROUP_CHAT_REPLY
Reply to all recipients preserving To/Cc.
Definition: send.h:53
mutt_beep
void mutt_beep(bool force)
Irritate the user.
Definition: curs_lib.c:99
up_n_lines
static int up_n_lines(int nlines, struct Line *info, int cur, bool hiding)
Reposition the pager's view up by n lines.
Definition: pager.c:2048
el_add_tagged
int el_add_tagged(struct EmailList *el, struct Context *ctx, struct Email *e, bool use_tagged)
Get a list of the tagged Emails.
Definition: context.c:349
Resize::search_back
bool search_back
Definition: pager.c:153
is_ansi
static bool is_ansi(const char *str)
Is this an ANSI escape sequence?
Definition: pager.c:1358
mx_mbox_check
enum MxStatus mx_mbox_check(struct Mailbox *m)
Check for new mail - Wrapper for MxOps::mbox_check()
Definition: mx.c:1137
mutt_window_clrtoeol
void mutt_window_clrtoeol(struct MuttWindow *win)
Clear to the end of the line.
Definition: mutt_window.c:244
Mailbox::rights
AclFlags rights
ACL bits, see AclFlags.
Definition: mailbox.h:121
PagerRedrawData::indexlen
int indexlen
Definition: pager.c:163
resolve_types
static void resolve_types(char *buf, char *raw, struct Line *line_info, int n, int last, struct QClass **quote_list, int *q_level, bool *force_redraw, bool q_classify)
Determine the style for a line of text.
Definition: pager.c:1090
MUTT_SHOW
#define MUTT_SHOW
Definition: lib.h:48
MUTT_SHOWFLAT
#define MUTT_SHOWFLAT
Show characters (used for displaying help)
Definition: lib.h:43
MUTT_FLAG
@ MUTT_FLAG
Flagged messages.
Definition: mutt.h:102
braille_line
static int braille_line
Definition: pager.c:196
SEND_REPLY
#define SEND_REPLY
Reply to sender.
Definition: send.h:41
Line::is_cont_hdr
unsigned int is_cont_hdr
this line is a continuation of the previous header line
Definition: pager.c:132
TopLine
static int TopLine
Definition: pager.c:191
Envelope::followup_to
char * followup_to
List of 'followup-to' fields.
Definition: envelope.h:77
mutt_window_move
int mutt_window_move(struct MuttWindow *win, int col, int row)
Move the cursor in a Window.
Definition: mutt_window.c:382
index_make_entry
void index_make_entry(struct Menu *menu, char *buf, size_t buflen, int line)
Format a menu item for the index list - Implements Menu::make_entry()
Definition: index.c:866
SigWinch
WHERE SIG_ATOMIC_VOLATILE_T SigWinch
true after SIGWINCH is received
Definition: mutt_globals.h:75
MxStatus
MxStatus
Return values from mx_mbox_check(), mx_mbox_sync(), and mx_mbox_close()
Definition: mx.h:71
ColorLine::regex
regex_t regex
Compiled regex.
Definition: color.h:37
mutt_mem_calloc
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:50
IsEmail
#define IsEmail(pager)
Definition: pager.c:312
MessageWindow
struct MuttWindow * MessageWindow
Message Window, ":set", etc.
Definition: mutt_window.c:47
mutt_timeout_hook
void mutt_timeout_hook(void)
Execute any timeout hooks.
Definition: hook.c:801
Line::offset
LOFF_T offset
Definition: pager.c:124
_
#define _(a)
Definition: message.h:28
NONULL
#define NONULL(x)
Definition: string2.h:37
mutt_window_printf
int mutt_window_printf(const char *fmt,...)
Write a formatted string to a Window.
Definition: mutt_window.c:550
Mailbox
A mailbox.
Definition: mailbox.h:81
ColorLine::stop_matching
bool stop_matching
Used by the pager for body patterns, to prevent the color from being retried once it fails.
Definition: color.h:45
mutt_addwch
int mutt_addwch(wchar_t wc)
addwch would be provided by an up-to-date curses library
Definition: curs_lib.c:1063
TRANSFORM_NONE
@ TRANSFORM_NONE
No transformation.
Definition: commands.h:51
mutt_make_string
void mutt_make_string(char *buf, size_t buflen, int cols, const char *s, struct Mailbox *m, int inpgr, struct Email *e, MuttFormatFlags flags, const char *progress)
Create formatted strings using mailbox expandos.
Definition: hdrline.c:1427
OptNeedResort
WHERE bool OptNeedResort
(pseudo) used to force a re-sort
Definition: options.h:43
Mailbox::emails
struct Email ** emails
Array of Emails.
Definition: mailbox.h:99
mutt_strn_equal
bool mutt_strn_equal(const char *a, const char *b, size_t num)
Check for equality of two strings (to a maximum), safely.
Definition: string.c:593
mutt_window_clear
void mutt_window_clear(struct MuttWindow *win)
Clear a Window.
Definition: mutt_window.c:806
mutt_system
int mutt_system(const char *cmd)
Run an external command.
Definition: system.c:51
MT_COLOR_ERROR
@ MT_COLOR_ERROR
Error message.
Definition: color.h:70
QClass::color
int color
Definition: pager.c:103
mutt_mailbox_list
bool mutt_mailbox_list(void)
List the mailboxes with new mail.
Definition: mutt_mailbox.c:220
PagerRedrawData::search_flag
PagerFlags search_flag
Definition: pager.c:181
Pager::actx
struct AttachCtx * actx
Attachment information.
Definition: lib.h:70
MT_COLOR_STATUS
@ MT_COLOR_STATUS
Status bar (takes a pattern)
Definition: color.h:94
TextSyntax::color
int color
Definition: pager.c:114
Buffer
String manipulation buffer.
Definition: buffer.h:33
Mailbox_is_read_only
static const char * Mailbox_is_read_only
Definition: pager.c:203
menu_redraw_index
void menu_redraw_index(struct Menu *menu)
Force the redraw of the index.
Definition: menu.c:381
ANSI_OFF
#define ANSI_OFF
Turn off colours and attributes.
Definition: pager.c:88
LL_DEBUG3
@ LL_DEBUG3
Log at debug level 3.
Definition: logging.h:42
C_DeleteUntag
WHERE bool C_DeleteUntag
Config: Untag messages when they are marked for deletion.
Definition: mutt_globals.h:145
mutt_show_error
void mutt_show_error(void)
Show the user an error message.
Definition: curs_lib.c:558
mutt_curses_set_attr
void mutt_curses_set_attr(int attr)
Set the attributes for text.
Definition: mutt_curses.c:40
ctx_mailbox
struct Mailbox * ctx_mailbox(struct Context *ctx)
wrapper to get the mailbox in a Context, or NULL
Definition: context.c:429
PagerRedrawData::sb
struct stat sb
Definition: pager.c:187
SAVE_COPY
@ SAVE_COPY
Copy message, making a duplicate in another mailbox.
Definition: commands.h:61
C_BeepNew
WHERE bool C_BeepNew
Config: Make a noise when new mail arrives.
Definition: mutt_globals.h:139
MUTT_HIDE
#define MUTT_HIDE
Don't show quoted text.
Definition: lib.h:45
MUTT_PATTERN
#define MUTT_PATTERN
Pattern mode - only used for history classes.
Definition: mutt.h:64
window_set_focus
void window_set_focus(struct MuttWindow *win)
Set the Window focus.
Definition: mutt_window.c:763
mutt_file_fclose
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:153
ANSI_REVERSE
#define ANSI_REVERSE
Reverse video.
Definition: pager.c:92
mutt_buffer_is_empty
bool mutt_buffer_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:252
MUTT_ACL_DELETE
#define MUTT_ACL_DELETE
Delete a message.
Definition: mailbox.h:66
InHelp
static bool InHelp
Definition: pager.c:194
MT_COLOR_HDRDEFAULT
@ MT_COLOR_HDRDEFAULT
Header default colour.
Definition: color.h:71
MT_COLOR_WARNING
@ MT_COLOR_WARNING
Warning messages.
Definition: color.h:98
mutt_window_wrap_cols
int mutt_window_wrap_cols(int width, short wrap)
Calculate the wrap column for a given screen width.
Definition: mutt_window.c:477
SEND_KEY
#define SEND_KEY
Mail a PGP public key.
Definition: send.h:47
mutt_window_clearline
void mutt_window_clearline(struct MuttWindow *win, int row)
Clear a row of a Window.
Definition: mutt_window.c:232
dialog_find
struct MuttWindow * dialog_find(struct MuttWindow *win)
Find the parent Dialog of a Window.
Definition: dialog.c:46
Pager::email
struct Email * email
Current message.
Definition: lib.h:67
C_BrailleFriendly
WHERE bool C_BrailleFriendly
Config: Move the cursor to the beginning of the line.
Definition: mutt_globals.h:140
PagerRedrawData::last_pos
LOFF_T last_pos
Definition: pager.c:176
index_color
int index_color(struct Menu *menu, int line)
Calculate the colour for a line of the index - Implements Menu::color()
Definition: index.c:945
Colors::body_list
struct ColorLineList body_list
List of colours applied to the email body.
Definition: color.h:134
MuttWindow
A division of the screen.
Definition: mutt_window.h:115
cs_subset_bool
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:69
mutt_is_quote_line
int mutt_is_quote_line(char *line, regmatch_t *pmatch)
Is a line of message text a quote?
Definition: pager.c:1047
MT_COLOR_QUOTED
@ MT_COLOR_QUOTED
Pager: quoted text.
Definition: color.h:81
mutt_buffer_init
struct Buffer * mutt_buffer_init(struct Buffer *buf)
Initialise a new Buffer.
Definition: buffer.c:46
Regex
Cached regular expression.
Definition: regex3.h:89
menu_redraw_current
void menu_redraw_current(struct Menu *menu)
Redraw the current menu.
Definition: menu.c:494
PagerRedrawData::lines
int lines
Definition: pager.c:166
MUTT_YES
@ MUTT_YES
User answered 'Yes', or assume 'Yes'.
Definition: quad.h:40
PagerRedrawData::extra
struct Pager * extra
Definition: pager.c:162
PagerRedrawData::search_re
regex_t search_re
Definition: pager.c:179
Context
The "current" mailbox.
Definition: context.h:38
MT_COLOR_BOLD
@ MT_COLOR_BOLD
Bold text.
Definition: color.h:64
LL_DEBUG1
@ LL_DEBUG1
Log at debug level 1.
Definition: logging.h:40
Mailbox::flags
uint8_t flags
e.g. MB_NORMAL
Definition: mailbox.h:134
C_StatusFormat
WHERE char * C_StatusFormat
Config: printf-like format string for the index's status line.
Definition: mutt_globals.h:109
PagerRedrawData::max_line
int max_line
Definition: pager.c:167
SAVE_MOVE
@ SAVE_MOVE
Move message to another mailbox, removing the original.
Definition: commands.h:62
FREE
#define FREE(x)
Definition: memory.h:40
PagerHelp
static const struct Mapping PagerHelp[]
Help Bar for the Pager's Help Page.
Definition: pager.c:208
mutt_perror
#define mutt_perror(...)
Definition: logging.h:85
mutt_draw_statusline
void mutt_draw_statusline(int cols, const char *buf, size_t buflen)
Draw a highlighted status bar.
Definition: index.c:974
mutt_shell_escape
bool mutt_shell_escape(void)
invoke a command in a subshell
Definition: commands.c:845
RootWindow
struct MuttWindow * RootWindow
Parent of all Windows.
Definition: mutt_window.c:45
mutt_update_index
void mutt_update_index(struct Menu *menu, struct Context *ctx, enum MxStatus check, int oldcount, const struct Email *cur_email)
Update the index.
Definition: index.c:654
mutt_print_message
void mutt_print_message(struct Mailbox *m, struct EmailList *el)
Print a message.
Definition: commands.c:730
Buffer::dptr
char * dptr
Current read/write position.
Definition: buffer.h:36
mutt_menu_new
struct Menu * mutt_menu_new(enum MenuType type)
Create a new Menu.
Definition: menu.c:956
mutt_window_move_abs
void mutt_window_move_abs(int col, int row)
Move the cursor to an absolute screen position.
Definition: mutt_window.c:539
PagerRedrawData::search_compiled
bool search_compiled
Definition: pager.c:180
mutt_label_message
int mutt_label_message(struct Mailbox *m, struct EmailList *el)
Let the user label a message.
Definition: mutt_header.c:124
mutt_regex_capture
bool mutt_regex_capture(const struct Regex *regex, const char *str, size_t nmatch, regmatch_t matches[])
match a regex against a string, with provided options
Definition: regex.c:595
MuttWindow::help_menu
int help_menu
Menu for key bindings, e.g. MENU_PAGER.
Definition: mutt_window.h:134
ANSI_BLINK
#define ANSI_BLINK
Blinking text.
Definition: pager.c:89
QClass::index
int index
Definition: pager.c:102
ci_bounce_message
void ci_bounce_message(struct Mailbox *m, struct EmailList *el)
Bounce an email.
Definition: commands.c:411
PagerRedrawData::fp
FILE * fp
Definition: pager.c:186
C_TsIconFormat
WHERE char * C_TsIconFormat
Config: printf-like format string for the terminal's icon title.
Definition: mutt_globals.h:111
Line::type
short type
Definition: pager.c:125
Menu::make_entry
void(* make_entry)(struct Menu *menu, char *buf, size_t buflen, int line)
Format a item for a menu.
Definition: mutt_menu.h:88
mutt_buffer_reset
void mutt_buffer_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:79
mutt_change_flag
int mutt_change_flag(struct Mailbox *m, struct EmailList *el, bool bf)
Change the flag on a Message.
Definition: flags.c:436
TextSyntax
Highlighting for a line of text.
Definition: pager.c:112
MUTT_FORMAT_NO_FLAGS
#define MUTT_FORMAT_NO_FLAGS
No flags are set.
Definition: format_flags.h:30
C_FollowupToPoster
unsigned char C_FollowupToPoster
Config: (nntp) Reply to the poster if 'poster' is in the 'Followup-To' header.
Definition: config.c:38
MUTT_WIN_SIZE_MAXIMISE
@ MUTT_WIN_SIZE_MAXIMISE
Window wants as much space as possible.
Definition: mutt_window.h:45
MUTT_RL_EOL
#define MUTT_RL_EOL
don't strip \n / \r\n
Definition: file.h:41
C_PostModerated
unsigned char C_PostModerated
Config: (nntp) Allow posting to moderated newsgroups.
Definition: config.c:51
Menu::win_ibar
struct MuttWindow * win_ibar
Definition: mutt_menu.h:64
STAILQ_FOREACH
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:349
cs_subset_str_native_set
int cs_subset_str_native_set(const struct ConfigSubset *sub, const char *name, intptr_t value, struct Buffer *err)
Natively set the value of a string config item.
Definition: subset.c:292
mutt_attach_mail_sender
void mutt_attach_mail_sender(FILE *fp, struct Email *e, struct AttachCtx *actx, struct Body *cur)
Compose an email to the sender in the email attachment.
Definition: recvcmd.c:1099
Mailbox::vcount
int vcount
The number of virtual messages.
Definition: mailbox.h:102
MT_COLOR_NORMAL
@ MT_COLOR_NORMAL
Plain text.
Definition: color.h:77
MX_STATUS_REOPENED
@ MX_STATUS_REOPENED
Mailbox was reopened.
Definition: mx.h:77
mutt_buffer_alloc
void mutt_buffer_alloc(struct Buffer *buf, size_t new_size)
Make sure a buffer can store at least new_size bytes.
Definition: buffer.c:265
grok_ansi
static int grok_ansi(unsigned char *buf, int pos, struct AnsiAttr *a)
Parse an ANSI escape sequence.
Definition: pager.c:1372
WT_SIDEBAR
@ WT_SIDEBAR
Side panel containing Accounts or groups of data.
Definition: mutt_window.h:99
TRANSFORM_DECODE
@ TRANSFORM_DECODE
Decode message.
Definition: commands.h:53
Colors::hdr_list
struct ColorLineList hdr_list
List of colours applied to the email headers.
Definition: color.h:135
Context::msg_in_pager
int msg_in_pager
Message currently shown in the pager.
Definition: context.h:44
MUTT_READ
@ MUTT_READ
Messages that have been read.
Definition: mutt.h:96
PagerRedrawData::search_back
bool search_back
Definition: pager.c:182
mutt_istr_equal
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:883
mutt_mailbox_notify
bool mutt_mailbox_notify(struct Mailbox *m_cur)
Notify the user if there's new mail.
Definition: mutt_mailbox.c:207
PagerRedrawData::menu
struct Menu * menu
the Pager Index (PI)
Definition: pager.c:178
mutt_str_equal
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:871
MT_COLOR_SEARCH
@ MT_COLOR_SEARCH
Pager: search matches.
Definition: color.h:82
assert_mailbox_permissions
static bool assert_mailbox_permissions(struct Mailbox *m, AclFlags acl, char *action)
checks that mailbox is has requested acl flags set
Definition: pager.c:381
mutt_attach_forward
void mutt_attach_forward(FILE *fp, struct Mailbox *m, struct Email *e, struct AttachCtx *actx, struct Body *cur, SendFlags flags)
Forward an Attachment.
Definition: recvcmd.c:776
mutt_ts_icon
void mutt_ts_icon(char *str)
Set the icon in the terminal title bar.
Definition: terminal.c:118
MX_STATUS_NEW_MAIL
@ MX_STATUS_NEW_MAIL
New mail received in Mailbox.
Definition: mx.h:75
alias_create
void alias_create(struct AddressList *al, const struct ConfigSubset *sub)
Create a new Alias from an Address.
Definition: alias.c:366
mutt_save_message
int mutt_save_message(struct Mailbox *m, struct EmailList *el, enum MessageSaveOpt save_opt, enum MessageTransformOpt transform_opt)
Save an email.
Definition: commands.c:1037
PGP_TRADITIONAL_CHECKED
#define PGP_TRADITIONAL_CHECKED
Email has a traditional (inline) signature.
Definition: lib.h:99
MUTT_PAGER_RETWINCH
#define MUTT_PAGER_RETWINCH
Need reformatting on SIGWINCH.
Definition: lib.h:53
SEND_NEWS
#define SEND_NEWS
Reply to a news article.
Definition: send.h:54
Menu::redraw_data
void * redraw_data
Definition: mutt_menu.h:124
Line::search_cnt
short search_cnt
Definition: pager.c:128
Email::old
bool old
Email is seen, but unread.
Definition: email.h:50
Line::search
struct TextSyntax * search
Definition: pager.c:130
Pager::win_index
struct MuttWindow * win_index
Definition: lib.h:73
MUTT_PURGE
@ MUTT_PURGE
Messages to be purged (bypass trash)
Definition: mutt.h:100
MT_COLOR_SIGNATURE
@ MT_COLOR_SIGNATURE
Pager: signature lines.
Definition: color.h:93
assert_pager_mode
static bool assert_pager_mode(bool test)
Check that pager is in correct mode.
Definition: pager.c:322
mutt_resend_message
int mutt_resend_message(FILE *fp, struct Context *ctx, struct Email *e_cur, struct ConfigSubset *sub)
Resend an email.
Definition: send.c:1521
query_quadoption
enum QuadOption query_quadoption(enum QuadOption opt, const char *prompt)
Ask the user a quad-question.
Definition: curs_lib.c:518
Colors::quotes_used
int quotes_used
Number of colours for quoted email text.
Definition: color.h:144
Pager::win_pbar
struct MuttWindow * win_pbar
Definition: lib.h:74
AnsiAttr
An ANSI escape sequence.
Definition: pager.c:138
mutt_menu_push_current
void mutt_menu_push_current(struct Menu *menu)
Add a new Menu to the stack.
Definition: menu.c:1015
mutt_buffer_addch
size_t mutt_buffer_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:240
TextSyntax::last
int last
Definition: pager.c:116
MT_COLOR_MESSAGE
@ MT_COLOR_MESSAGE
Informational message.
Definition: color.h:75
PagerRedrawData::force_redraw
bool force_redraw
Definition: pager.c:171
AttachmentMarker
WHERE char AttachmentMarker[256]
Unique ANSI string to mark PGP messages in an email.
Definition: mutt_globals.h:46
SEND_FORWARD
#define SEND_FORWARD
Forward email.
Definition: send.h:44
PagerRedrawData::last_offset
LOFF_T last_offset
Definition: pager.c:177
display_line
static int display_line(FILE *fp, LOFF_T *last_pos, struct Line **line_info, int n, int *last, int *max, PagerFlags flags, struct QClass **quote_list, int *q_level, bool *force_redraw, regex_t *search_re, struct MuttWindow *win_pager)
Print a line on screen.
Definition: pager.c:1765
QClass::prefix
char * prefix
Definition: pager.c:104
Line::quote
struct QClass * quote
Definition: pager.c:131
MUTT_NNTP
@ MUTT_NNTP
'NNTP' (Usenet) Mailbox type
Definition: mailbox.h:52
sb_change_mailbox
void sb_change_mailbox(struct MuttWindow *win, int op)
Perform a Sidebar function.
Definition: functions.c:265
mutt_ts_status
void mutt_ts_status(char *str)
Set the text of the terminal title bar.
Definition: terminal.c:104
Mailbox::type
enum MailboxType type
Mailbox type.
Definition: mailbox.h:105
MUTT_PAGER_NOWRAP
#define MUTT_PAGER_NOWRAP
Format for term width, ignore $wrap.
Definition: lib.h:55
Mailbox::mdata
void * mdata
Driver specific data.
Definition: mailbox.h:136
ANSI_COLOR
#define ANSI_COLOR
Use colours.
Definition: pager.c:93
Resize
Keep track of screen resizing.
Definition: pager.c:149
Line::continuation
short continuation
Definition: pager.c:126
cs_subset_number
short cs_subset_number(const struct ConfigSubset *sub, const char *name)
Get a number config item by name.
Definition: helpers.c:111
braille_col
static int braille_col
Definition: pager.c:197
SEND_POSTPONED
#define SEND_POSTPONED
Recall a postponed email.
Definition: send.h:45
mutt_help
void mutt_help(enum MenuType menu)
Display the help menu.
Definition: help.c:385
SEND_TO_SENDER
#define SEND_TO_SENDER
Compose new email to sender.
Definition: send.h:52
Line
A line of text in the pager.
Definition: pager.c:122
MUTT_NEW
@ MUTT_NEW
New messages.
Definition: mutt.h:93
C_Wrap
WHERE short C_Wrap
Config: Width to wrap text in the pager.
Definition: mutt_globals.h:116
PagerRedrawData::q_level
int q_level
Definition: pager.c:174
mutt_pipe_attachment_list
void mutt_pipe_attachment_list(struct AttachCtx *actx, FILE *fp, bool tag, struct Body *top, bool filter)
Pipe a list of attachments to a command.
Definition: recvattach.c:1011
PagerRedrawData::oldtopline
int oldtopline
Definition: pager.c:165
Email::tagged
bool tagged
Email is tagged.
Definition: email.h:44
MT_COLOR_ATTACHMENT
@ MT_COLOR_ATTACHMENT
MIME attachments text (entire line)
Definition: color.h:61
PagerRedrawData::line_info
struct Line * line_info
Definition: pager.c:185
OptAttachMsg
WHERE bool OptAttachMsg
(pseudo) used by attach-message
Definition: options.h:31
C_QuoteRegex
WHERE struct Regex * C_QuoteRegex
Config: Regex to match quoted text in a reply.
Definition: mutt_globals.h:120
Mailbox::changed
bool changed
Mailbox has been modified.
Definition: mailbox.h:114
OpStrings
const char * OpStrings[][2]
Definition: opcodes.c:28
APPLICATION_PGP
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: lib.h:97
REDRAW_FULL
#define REDRAW_FULL
Redraw everything.
Definition: mutt_menu.h:45
MessageSaveOpt
MessageSaveOpt
Message save option.
Definition: commands.h:59
window_redraw
void window_redraw(struct MuttWindow *win, bool force)
Reflow, recalc and repaint a tree of Windows.
Definition: mutt_window.c:747
Pager::ctx
struct Context * ctx
Current mailbox.
Definition: lib.h:66
TRANSFORM_DECRYPT
@ TRANSFORM_DECRYPT
Decrypt message.
Definition: commands.h:52
mutt_thread_set_flag
int mutt_thread_set_flag(struct Mailbox *m, struct Email *e, enum MessageType flag, bool bf, bool subthread)
Set a flag on an entire thread.
Definition: flags.c:377
PagerHelpHelp
static const struct Mapping PagerHelpHelp[]
Help Bar for the Help Page itself.
Definition: pager.c:219
format_line
static int format_line(struct Line **line_info, int n, unsigned char *buf, PagerFlags flags, struct AnsiAttr *pa, int cnt, int *pspace, int *pvch, int *pcol, int *pspecial, int width)
Display a line of text in the pager.
Definition: pager.c:1572
Mailbox::msg_count
int msg_count
Total number of messages.
Definition: mailbox.h:91
mutt_mailbox_check
int mutt_mailbox_check(struct Mailbox *m_cur, int force)
Check all all Mailboxes for new mail.
Definition: mutt_mailbox.c:141
cs_subset_regex
const struct Regex * cs_subset_regex(const struct ConfigSubset *sub, const char *name)
Get a regex config item by name.
Definition: helpers.c:176
mutt_clear_error
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:113
ProtectedHeaderMarker
WHERE char ProtectedHeaderMarker[256]
Unique ANSI string to mark protected headers in an email.
Definition: mutt_globals.h:47
check_sig
static int check_sig(const char *s, struct Line *info, int offset)
Check for an email signature.
Definition: pager.c:403
mutt_resize_screen
void mutt_resize_screen(void)
Update NeoMutt's opinion about the window size (CURSES)
Definition: resize.c:101
MAX
#define MAX(a, b)
Definition: memory.h:30
C_TsEnabled
WHERE bool C_TsEnabled
Config: Allow NeoMutt to set the terminal status line and icon.
Definition: mutt_globals.h:167
mutt_send_message
int mutt_send_message(SendFlags flags, struct Email *e_templ, const char *tempfile, struct Context *ctx, struct EmailList *el, struct ConfigSubset *sub)
Send an email.
Definition: send.c:2012
mutt_window_find
struct MuttWindow * mutt_window_find(struct MuttWindow *root, enum WindowType type)
Find a Window of a given type.
Definition: mutt_window.c:678
dlg_select_attachment
void dlg_select_attachment(struct Email *e)
Show the attachments in a Menu.
Definition: recvattach.c:1549
check_attachment_marker
static int check_attachment_marker(const char *p)
Check that the unique marker is present.
Definition: pager.c:1023
Menu::pagelen
int pagelen
Number of entries per screen.
Definition: mutt_menu.h:60
PagerRedrawData::topline
int topline
Definition: pager.c:170
Colors::attach_list
struct ColorLineList attach_list
List of colours applied to the attachment headers.
Definition: color.h:133
PagerRedrawData::has_types
int has_types
Definition: pager.c:172
Colors
Definition: color.h:129
IsAttach
#define IsAttach(pager)
Definition: pager.c:309
Context::mailbox
struct Mailbox * mailbox
Definition: context.h:50
ColorLine::pair
int pair
Colour pair index.
Definition: color.h:43
mutt_mem_realloc
void mutt_mem_realloc(void *ptr, size_t size)
Resize a block of memory on the heap.
Definition: memory.c:114
mutt_window_addch
int mutt_window_addch(int ch)
Write one character to a Window.
Definition: mutt_window.c:492
emaillist_add_email
int emaillist_add_email(struct EmailList *el, struct Email *e)
Add an Email to a list.
Definition: email.c:151
PagerRedrawData::curline
int curline
Definition: pager.c:169
MT_COLOR_MESSAGE_LOG
@ MT_COLOR_MESSAGE_LOG
Menu showing log messages.
Definition: color.h:76
Email::env
struct Envelope * env
Envelope information.
Definition: email.h:90
mutt_display_address
void mutt_display_address(struct Envelope *env)
Display the address of a message.
Definition: commands.c:927
mutt_debug
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
MUTT_PAGER_ATTACHMENT
#define MUTT_PAGER_ATTACHMENT
Attachments may exist.
Definition: lib.h:54
resolve_color
static void resolve_color(struct Line *line_info, int n, int cnt, PagerFlags flags, int special, struct AnsiAttr *a)
Set the colour for a line of text.
Definition: pager.c:464
SEND_GROUP_REPLY
#define SEND_GROUP_REPLY
Reply to all.
Definition: send.h:42
MUTT_WIN_SIZE_UNLIMITED
#define MUTT_WIN_SIZE_UNLIMITED
Use as much space as possible.
Definition: mutt_window.h:49
append_line
static void append_line(struct Line *line_info, int n, int cnt)
Add a new Line to the array.
Definition: pager.c:596
MessageTransformOpt
MessageTransformOpt
Message transformation option.
Definition: commands.h:49
check_marker
static int check_marker(const char *q, const char *p)
Check that the unique marker is present.
Definition: pager.c:1007
QClass::down
struct QClass * down
Definition: pager.c:106
mutt_pipe_message
void mutt_pipe_message(struct Mailbox *m, struct EmailList *el)
Pipe a message.
Definition: commands.c:702
REG_COMP
#define REG_COMP(preg, regex, cflags)
Compile a regular expression.
Definition: regex3.h:54
Pager::win_pager
struct MuttWindow * win_pager
Definition: lib.h:75
QClass
Style of quoted text.
Definition: pager.c:99
MT_COLOR_TILDE
@ MT_COLOR_TILDE
Pager: empty lines after message.
Definition: color.h:95
search
static int search(struct Menu *menu, int op)
Search a menu.
Definition: menu.c:1129
PagerRedrawData::last_line
int last_line
Definition: pager.c:168
bool_str_toggle
int bool_str_toggle(struct ConfigSubset *sub, const char *name, struct Buffer *err)
Toggle the value of a bool.
Definition: bool.c:213
SEND_NO_FLAGS
#define SEND_NO_FLAGS
No flags are set.
Definition: send.h:40
REDRAW_INDEX
#define REDRAW_INDEX
Redraw the index.
Definition: mutt_menu.h:40
MX_STATUS_ERROR
@ MX_STATUS_ERROR
An error occurred.
Definition: mx.h:73
Email::flagged
bool flagged
Marked important?
Definition: email.h:43
cleanup_quote
static void cleanup_quote(struct QClass **quote_list)
Free a quote list.
Definition: pager.c:671
mutt_str_len
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:631
QClass::up
struct QClass * up
Definition: pager.c:106
PagerRedrawData::flags
PagerFlags flags
Definition: pager.c:161
Mailbox::verbose
bool verbose
Display status messages?
Definition: mailbox.h:118
MUTT_DISPLAYFLAGS
#define MUTT_DISPLAYFLAGS
Definition: lib.h:59
WindowState::rows
short rows
Number of rows, can be MUTT_WIN_SIZE_UNLIMITED.
Definition: mutt_window.h:58
MuttWindow::parent
struct MuttWindow * parent
Parent Window.
Definition: mutt_window.h:128
Email::security
SecurityFlags security
bit 0-10: flags, bit 11,12: application, bit 13: traditional pgp See: ncrypt/lib.h pgplib....
Definition: email.h:39
C_ToggleQuotedShowLevels
WHERE int C_ToggleQuotedShowLevels
Config: Number of quote levels to show with toggle-quoted.
Definition: mutt_globals.h:121
C_Quit
WHERE unsigned char C_Quit
Config: Prompt before exiting NeoMutt.
Definition: mutt_globals.h:129
MUTT_CURSOR_INVISIBLE
@ MUTT_CURSOR_INVISIBLE
Hide the cursor.
Definition: mutt_curses.h:80
MuttWindow::help_data
const struct Mapping * help_data
Data for the Help Bar.
Definition: mutt_window.h:135
mutt_enter_command
void mutt_enter_command(void)
enter a neomutt command
Definition: commands.c:878
MUTT_ACL_WRITE
#define MUTT_ACL_WRITE
Write to a message (for flagging or linking threads)
Definition: mailbox.h:74
IsMsgAttach
#define IsMsgAttach(pager)
Definition: pager.c:310
Menu::top
int top
Entry that is the top of the current page.
Definition: mutt_menu.h:75
shift_class_colors
static void shift_class_colors(struct QClass *quote_list, struct QClass *new_class, int index, int *q_level)
Insert a new quote colour class into a list.
Definition: pager.c:632
IS_HEADER
#define IS_HEADER(x)
Definition: pager.c:260
WithCrypto
#define WithCrypto
Definition: lib.h:123
AnsiAttr::fg
int fg
Foreground colour.
Definition: pager.c:141
mutt_flushinp
void mutt_flushinp(void)
Empty all the keyboard buffers.
Definition: curs_lib.c:923
MuttWindow::state
struct WindowState state
Current state of the Window.
Definition: mutt_window.h:120
mutt_menu_pop_current
void mutt_menu_pop_current(struct Menu *menu)
Remove a Menu from the stack.
Definition: menu.c:1027
PagerNormalHelp
static const struct Mapping PagerNormalHelp[]
Help Bar for the Pager of a normal Mailbox.
Definition: pager.c:229
menu_status_line
void menu_status_line(char *buf, size_t buflen, struct Menu *menu, struct Mailbox *m, const char *p)
Create the status line.
Definition: status.c:420
classify_quote
static struct QClass * classify_quote(struct QClass **quote_list, const char *qptr, size_t length, bool *force_redraw, int *q_level)
Find a style for a string.
Definition: pager.c:695
Email::deleted
bool deleted
Email is deleted.
Definition: email.h:45
PagerRedrawData
Keep track when the pager needs redrawing.
Definition: pager.c:159
Not_available_in_this_menu
static const char * Not_available_in_this_menu
Definition: pager.c:201
crypt_forget_passphrase
void crypt_forget_passphrase(void)
Forget a passphrase and display a message.
Definition: crypt.c:93
MuttWindow::req_rows
short req_rows
Number of rows required.
Definition: mutt_window.h:118
STAILQ_HEAD_INITIALIZER
#define STAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:321
Colors::quotes
int * quotes
Array of colours for quoted email text.
Definition: color.h:143
class_color_new
static void class_color_new(struct QClass *qc, int *q_level)
Create a new quoting colour.
Definition: pager.c:619
Mailbox::readonly
bool readonly
Don't allow changes to the mailbox.
Definition: mailbox.h:119
Resize::search_compiled
bool search_compiled
Definition: pager.c:152
mutt_what_key
void mutt_what_key(void)
Ask the user to press a key.
Definition: keymap.c:1676
mutt_attach_resend
void mutt_attach_resend(FILE *fp, struct Context *ctx, struct AttachCtx *actx, struct Body *cur)
resend-message, from the attachment menu
Definition: recvcmd.c:299
PagerRedrawData::indicator
int indicator
the indicator line of the PI
Definition: pager.c:164
MUTT_DELETE
@ MUTT_DELETE
Messages to be deleted.
Definition: mutt.h:98
MuttWindow::size
enum MuttWindowSize size
Type of Window, e.g. MUTT_WIN_SIZE_FIXED.
Definition: mutt_window.h:124
MT_COLOR_MARKERS
@ MT_COLOR_MARKERS
Pager: markers, line continuation.
Definition: color.h:74
C_NewMailCommand
WHERE char * C_NewMailCommand
Config: External command to run when new mail arrives.
Definition: mutt_globals.h:104
window_set_visible
void window_set_visible(struct MuttWindow *win, bool visible)
Set a Window visible or hidden.
Definition: mutt_window.c:149
MUTT_WIN_SIZE_MINIMISE
@ MUTT_WIN_SIZE_MINIMISE
Window size depends on its children.
Definition: mutt_window.h:46
mutt_color_alloc
int mutt_color_alloc(struct Colors *c, uint32_t fg, uint32_t bg)
Allocate a colour pair.
Definition: color.c:472
MUTT_PAGER_MARKER
#define MUTT_PAGER_MARKER
Use markers if option is set.
Definition: lib.h:52
Menu::custom_redraw
void(* custom_redraw)(struct Menu *menu)
Redraw the menu.
Definition: mutt_menu.h:122
mutt_mem_malloc
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:90
OptSearchInvalid
WHERE bool OptSearchInvalid
(pseudo) used to invalidate the search pattern
Definition: options.h:52
Menu::max
int max
Number of entries in the menu.
Definition: mutt_menu.h:57
MT_COLOR_HEADER
@ MT_COLOR_HEADER
Message headers (takes a pattern)
Definition: color.h:72
MUTT_MAILBOX_CHECK_FORCE
#define MUTT_MAILBOX_CHECK_FORCE
Definition: mutt_mailbox.h:16
mutt_buffer_strip_formatting
void mutt_buffer_strip_formatting(struct Buffer *dest, const char *src, bool strip_markers)
Removes ANSI and backspace formatting.
Definition: pager.c:1471
comp_syntax_t
static int comp_syntax_t(const void *m1, const void *m2)
Search for a Syntax using bsearch.
Definition: pager.c:443
mutt_select_sort
int mutt_select_sort(bool reverse)
Ask the user for a sort method.
Definition: commands.c:769
MUTT_PAGER_NSKIP
#define MUTT_PAGER_NSKIP
Preserve whitespace with smartwrap.
Definition: lib.h:51
TsSupported
bool TsSupported
Terminal Setting is supported.
Definition: terminal.c:43
Pager::win_ibar
struct MuttWindow * win_ibar
Definition: lib.h:72
C_TsStatusFormat
WHERE char * C_TsStatusFormat
Config: printf-like format string for the terminal's status (window title)
Definition: mutt_globals.h:110
MUTT_TAG
@ MUTT_TAG
Tagged messages.
Definition: mutt.h:103
MENU_MAIN
@ MENU_MAIN
Index panel (list of emails)
Definition: keymap.h:80
mutt_mb_is_lower
bool mutt_mb_is_lower(const char *s)
Does a multi-byte string contain only lowercase characters?
Definition: mbyte.c:358
NeoMutt
Container for Accounts, Notifications.
Definition: neomutt.h:36
C_WrapSearch
WHERE bool C_WrapSearch
Config: Wrap around when the search hits the end.
Definition: mutt_globals.h:170
ReplacementChar
wchar_t ReplacementChar
When a Unicode character can't be displayed, use this instead.
Definition: charset.c:58
assert_attach_msg_mode
static bool assert_attach_msg_mode(bool attach_msg)
Check that attach message mode is on.
Definition: pager.c:360
mutt_clear_pager_position
void mutt_clear_pager_position(void)
Reset the pager's viewing position.
Definition: pager.c:2063
C_Markers
WHERE bool C_Markers
Config: Display a '+' at the beginning of wrapped lines in the pager.
Definition: mutt_globals.h:151
mutt_curses_set_color
void mutt_curses_set_color(enum ColorId color)
Set the current colour for text.
Definition: mutt_curses.c:57
Menu::redraw
MuttRedrawFlags redraw
When to redraw the screen.
Definition: mutt_menu.h:58
km_error_key
void km_error_key(enum MenuType menu)
Handle an unbound key sequence.
Definition: keymap.c:1137
mutt_buffer_len
size_t mutt_buffer_len(const struct Buffer *buf)
Calculate the length of a Buffer.
Definition: buffer.c:356
MUTT_SHOWCOLOR
#define MUTT_SHOWCOLOR
Show characters in color otherwise don't show characters.
Definition: lib.h:44
Email::vnum
int vnum
Virtual message number.
Definition: email.h:88
fill_buffer
static int fill_buffer(FILE *fp, LOFF_T *last_pos, LOFF_T offset, unsigned char **buf, unsigned char **fmt, size_t *blen, int *buf_ready)
Fill a buffer from a file.
Definition: pager.c:1524
MUTT_CURSOR_VISIBLE
@ MUTT_CURSOR_VISIBLE
Display a normal cursor.
Definition: mutt_curses.h:81
MUTT_WIN_SIZE_FIXED
@ MUTT_WIN_SIZE_FIXED
Window has a fixed size.
Definition: mutt_window.h:44
PagerRedrawData::banner
const char * banner
Definition: pager.c:183
QClass::length
size_t length
Definition: pager.c:101
ColorLine
A regular expression and a color to highlight a line.
Definition: color.h:35
ANSI_UNDERLINE
#define ANSI_UNDERLINE
Underlined text.
Definition: pager.c:91
MUTT_CLEAR
#define MUTT_CLEAR
Clear input if printable character is pressed.
Definition: mutt.h:62
mutt_refresh
void mutt_refresh(void)
Force a refresh of the screen.
Definition: curs_lib.c:108
Pager::fp
FILE * fp
Source stream.
Definition: lib.h:69
assert_mailbox_writable
static bool assert_mailbox_writable(struct Mailbox *mailbox)
checks that mailbox is writable
Definition: pager.c:340
NeoMutt::sub
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
PagerRedrawData::hide_quoted
PagerFlags hide_quoted
Definition: pager.c:173
C_Resolve
WHERE bool C_Resolve
Config: Move to the next email whenever a command modifies an email.
Definition: mutt_globals.h:155
AnsiAttr::pair
int pair
Curses colour pair.
Definition: pager.c:143
SEND_LIST_REPLY
#define SEND_LIST_REPLY
Reply to mailing list.
Definition: send.h:43
mutt_get_field
int mutt_get_field(const char *field, char *buf, size_t buflen, CompletionFlags complete, bool multiple, char ***files, int *numfiles)
Ask the user for a string.
Definition: curs_lib.c:311
crypt_extract_keys_from_messages
void crypt_extract_keys_from_messages(struct Mailbox *m, struct EmailList *el)
Extract keys from a message.
Definition: crypt.c:846
Body::email
struct Email * email
header information for message/rfc822
Definition: body.h:55
km_dokey
int km_dokey(enum MenuType menu)
Determine what a keypress should do.
Definition: keymap.c:658
WindowState::cols
short cols
Number of columns, can be MUTT_WIN_SIZE_UNLIMITED.
Definition: mutt_window.h:57
OldEmail
static struct Email * OldEmail
Definition: pager.c:192
MX_STATUS_FLAGS
@ MX_STATUS_FLAGS
Nondestructive flags change (IMAP)
Definition: mx.h:78
Email::attach_del
bool attach_del
Has an attachment marked for deletion.
Definition: email.h:49
TextSyntax::first
int first
Definition: pager.c:115
CharsetIsUtf8
bool CharsetIsUtf8
Is the user's current character set utf-8?
Definition: charset.c:63
AnsiAttr::attr
AnsiFlags attr
Attributes, e.g. underline, bold, etc.
Definition: pager.c:140
Menu::current
int current
Current entry.
Definition: mutt_menu.h:56
Colors::defs
int * defs
Array of all fixed colours, see enum ColorId.
Definition: color.h:131
mutt_attach_reply
void mutt_attach_reply(FILE *fp, struct Mailbox *m, struct Email *e, struct AttachCtx *actx, struct Body *e_cur, SendFlags flags)
Attach a reply.
Definition: recvcmd.c:929
MUTT_PAGER_LOGS
#define MUTT_PAGER_LOGS
Logview mode.
Definition: lib.h:56
REDRAW_NO_FLAGS
#define REDRAW_NO_FLAGS
No flags are set.
Definition: mutt_menu.h:39
QClass::prev
struct QClass * prev
Definition: pager.c:105
pager_custom_redraw
static void pager_custom_redraw(struct Menu *pager_menu)
Redraw the pager window - Implements Menu::custom_redraw()
Definition: pager.c:2072
mutt_attach_bounce
void mutt_attach_bounce(struct Mailbox *m, FILE *fp, struct AttachCtx *actx, struct Body *cur)
Bounce function, from the attachment menu.
Definition: recvcmd.c:168
IS_SPACE
#define IS_SPACE(ch)
Definition: string2.h:38
Email
The envelope/body of an email.
Definition: email.h:37
mutt_save_attachment_list
void mutt_save_attachment_list(struct AttachCtx *actx, FILE *fp, bool tag, struct Body *top, struct Email *e, struct Menu *menu)
Save a list of attachments.
Definition: recvattach.c:724
MUTT_ACL_SEEN
#define MUTT_ACL_SEEN
Change the 'seen' status of a message.
Definition: mailbox.h:73
mutt_str_startswith
size_t mutt_str_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix.
Definition: string.c:160
MUTT_SEARCH
#define MUTT_SEARCH
Resolve search patterns.
Definition: lib.h:46
mutt_message
#define mutt_message(...)
Definition: logging.h:83
mutt_set_flag
#define mutt_set_flag(m, e, flag, bf)
Definition: protos.h:67
MUTT_TYPES
#define MUTT_TYPES
Compute line's type.
Definition: lib.h:47
emaillist_clear
void emaillist_clear(struct EmailList *el)
Drop a private list of Emails.
Definition: email.c:130
mutt_print_attachment_list
void mutt_print_attachment_list(struct AttachCtx *actx, FILE *fp, bool tag, struct Body *top)
Print a list of Attachments.
Definition: recvattach.c:1166
mutt_make_version
const char * mutt_make_version(void)
Generate the NeoMutt version string.
Definition: muttlib.c:1462
Menu::win_index
struct MuttWindow * win_index
Definition: mutt_menu.h:63
mutt_warning
#define mutt_warning(...)
Definition: logging.h:82
QClass::next
struct QClass * next
Definition: pager.c:105
mutt_check_stats
void mutt_check_stats(struct Mailbox *m)
Forcibly update mailbox stats.
Definition: commands.c:1483
Menu
GUI selectable list of items.
Definition: mutt_menu.h:52
mutt_mb_is_display_corrupting_utf8
bool mutt_mb_is_display_corrupting_utf8(wchar_t wc)
Will this character corrupt the display?
Definition: mbyte.c:390
Email::read
bool read
Email is read.
Definition: email.h:51
Pager::body
struct Body * body
Current attachment.
Definition: lib.h:68
ANSI_BOLD
#define ANSI_BOLD
Bold text.
Definition: pager.c:90
REDRAW_BODY
#define REDRAW_BODY
Redraw the pager.
Definition: mutt_menu.h:46
C_PagerFormat
WHERE char * C_PagerFormat
Config: printf-like format string for the pager's status bar.
Definition: mutt_globals.h:100
Resize::line
int line
Definition: pager.c:151
N_
#define N_(a)
Definition: message.h:32
MENU_PAGER
@ MENU_PAGER
Pager pager (email viewer)
Definition: keymap.h:81
PagerNewsHelp
static const struct Mapping PagerNewsHelp[]
Help Bar for the Pager of an NNTP Mailbox.
Definition: pager.c:245
REDRAW_FLOW
#define REDRAW_FLOW
Used by pager to reflow text.
Definition: mutt_menu.h:47
LL_DEBUG2
@ LL_DEBUG2
Log at debug level 2.
Definition: logging.h:41
REDRAW_STATUS
#define REDRAW_STATUS
Redraw the status bar.
Definition: mutt_menu.h:44
Menu::color
int(* color)(struct Menu *menu, int line)
Calculate the colour for a line of the menu.
Definition: mutt_menu.h:116
PagerRedrawData::quote_list
struct QClass * quote_list
Definition: pager.c:175
Mailbox::pathbuf
struct Buffer pathbuf
Definition: mailbox.h:83
NntpMboxData
NNTP-specific Mailbox data -.
Definition: mdata.h:31
check_protected_header_marker
static int check_protected_header_marker(const char *p)
Check that the unique marker is present.
Definition: pager.c:1033
Line::chunks
short chunks
Definition: pager.c:127
mutt_menu_free
void mutt_menu_free(struct Menu **ptr)
Destroy a menu.
Definition: menu.c:972
MIN
#define MIN(a, b)
Definition: memory.h:31
mutt_error
#define mutt_error(...)
Definition: logging.h:84
PagerRedrawData::searchbuf
char * searchbuf
Definition: pager.c:184
mutt_window_reflow
void mutt_window_reflow(struct MuttWindow *win)
Resize a Window and its children.
Definition: mutt_window.c:433
IsWPrint
#define IsWPrint(wc)
Definition: mbyte.h:40
mutt_get_address
struct AddressList * mutt_get_address(struct Envelope *env, const char **prefix)
Get an Address from an Envelope.
Definition: alias.c:326
mutt_file_read_line
char * mutt_file_read_line(char *line, size_t *size, FILE *fp, int *line_num, ReadLineFlags flags)
Read a line from a file.
Definition: file.c:667
mutt_str_copy
size_t mutt_str_copy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:716