NeoMutt  2020-03-20-65-g141838
Teaching an old dog new tricks
DOXYGEN
pager.c File Reference

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

#include "config.h"
#include <ctype.h>
#include <errno.h>
#include <inttypes.h>
#include <limits.h>
#include <regex.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 "gui/lib.h"
#include "mutt.h"
#include "pager.h"
#include "alias.h"
#include "commands.h"
#include "context.h"
#include "format_flags.h"
#include "globals.h"
#include "hdrline.h"
#include "hook.h"
#include "index.h"
#include "init.h"
#include "keymap.h"
#include "mutt_attach.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 "send.h"
#include "status.h"
#include "ncrypt/lib.h"
#include "sidebar.h"
#include "nntp/lib.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)
 
#define NUM_SIG_LINES   4
 
#define CHECK_MODE(test)
 
#define CHECK_READONLY
 
#define CHECK_ATTACH
 
#define CHECK_ACL(aclbit, action)
 

Typedefs

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

Functions

static int check_sig (const char *s, struct Line *info, int n)
 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 (unsigned char *buf)
 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...
 
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

bool C_AllowAnsi
 Config: Allow ANSI colour codes in rich text messages. More...
 
bool C_HeaderColorPartial
 Config: Only colour the part of the header matching the regex. More...
 
short C_PagerContext
 Config: Number of lines of overlap when changing pages in the pager. More...
 
short C_PagerIndexLines
 Config: Number of index lines to display above the pager. More...
 
bool C_PagerStop
 Config: Don't automatically open the next message when at the end of a message. More...
 
short C_SearchContext
 Config: Context to display around search matches. More...
 
short C_SkipQuotedOffset
 Config: Lines of context to show when skipping quoted text. More...
 
bool C_SmartWrap
 Config: Wrap text at word boundaries. More...
 
struct RegexC_Smileys
 Config: Regex to match smileys to prevent mistakes when quoting text. More...
 
bool C_Tilde
 Config: Character to pad blank lines in the pager. More...
 
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 []
 
static const struct Mapping PagerHelpExtra []
 
static struct Mapping PagerNewsHelpExtra []
 

Detailed Description

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

Authors
  • Michael R. Elkins

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

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

Definition in file pager.c.

Macro Definition Documentation

◆ ANSI_NO_FLAGS

#define ANSI_NO_FLAGS   0

No flags are set.

Definition at line 99 of file pager.c.

◆ ANSI_OFF

#define ANSI_OFF   (1 << 0)

Turn off colours and attributes.

Definition at line 100 of file pager.c.

◆ ANSI_BLINK

#define ANSI_BLINK   (1 << 1)

Blinking text.

Definition at line 101 of file pager.c.

◆ ANSI_BOLD

#define ANSI_BOLD   (1 << 2)

Bold text.

Definition at line 102 of file pager.c.

◆ ANSI_UNDERLINE

#define ANSI_UNDERLINE   (1 << 3)

Underlined text.

Definition at line 103 of file pager.c.

◆ ANSI_REVERSE

#define ANSI_REVERSE   (1 << 4)

Reverse video.

Definition at line 104 of file pager.c.

◆ ANSI_COLOR

#define ANSI_COLOR   (1 << 5)

Use colours.

Definition at line 105 of file pager.c.

◆ IS_HEADER

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

Definition at line 245 of file pager.c.

◆ IsAttach

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

Definition at line 247 of file pager.c.

◆ IsMsgAttach

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

Definition at line 248 of file pager.c.

◆ IsEmail

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

Definition at line 250 of file pager.c.

◆ NUM_SIG_LINES

#define NUM_SIG_LINES   4

Definition at line 252 of file pager.c.

◆ CHECK_MODE

#define CHECK_MODE (   test)
Value:
if (!(test)) \
{ \
mutt_flushinp(); \
mutt_error(_(Not_available_in_this_menu)); \
break; \
}
#define _(a)
Definition: message.h:28
static const char * Not_available_in_this_menu
Definition: pager.c:214
static struct UrlTest test[]
Definition: url_parse.c:40

Definition at line 254 of file pager.c.

◆ CHECK_READONLY

#define CHECK_READONLY
Value:
{ \
mutt_flushinp(); \
mutt_error(_(Mailbox_is_read_only)); \
break; \
}
The "current" mailbox.
Definition: context.h:37
#define _(a)
Definition: message.h:28
struct Mailbox * mailbox
Definition: context.h:51
bool readonly
Don&#39;t allow changes to the mailbox.
Definition: mailbox.h:119
static const char * Mailbox_is_read_only
Definition: pager.c:216

Definition at line 262 of file pager.c.

◆ CHECK_ATTACH

#define CHECK_ATTACH
Value:
{ \
mutt_flushinp(); \
break; \
}
#define _(a)
Definition: message.h:28
WHERE bool OptAttachMsg
(pseudo) used by attach-message
Definition: options.h:31
static const char * Function_not_permitted_in_attach_message_mode
Definition: pager.c:217

Definition at line 270 of file pager.c.

◆ CHECK_ACL

#define CHECK_ACL (   aclbit,
  action 
)
Value:
if (!Context || !(Context->mailbox->rights & aclbit)) \
{ \
mutt_flushinp(); \
/* L10N: %s is one of the CHECK_ACL entries below. */ \
mutt_error(_("%s: Operation not permitted by ACL"), action); \
break; \
}
The "current" mailbox.
Definition: context.h:37
#define _(a)
Definition: message.h:28
struct Mailbox * mailbox
Definition: context.h:51
AclFlags rights
ACL bits, see AclFlags.
Definition: mailbox.h:121

Definition at line 278 of file pager.c.

Typedef Documentation

◆ AnsiFlags

typedef uint8_t AnsiFlags

Flags, e.g. ANSI_OFF.

Definition at line 98 of file pager.c.

Function Documentation

◆ check_sig()

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

Check for an email signature.

Parameters
sText to examine
infoLine info array to update
nFirst line to check
Return values
0Success
-1Error

Definition at line 295 of file pager.c.

296 {
297  int count = 0;
298 
299  while ((n > 0) && (count <= NUM_SIG_LINES))
300  {
301  if (info[n].type != MT_COLOR_SIGNATURE)
302  break;
303  count++;
304  n--;
305  }
306 
307  if (count == 0)
308  return -1;
309 
310  if (count > NUM_SIG_LINES)
311  {
312  /* check for a blank line */
313  while (*s)
314  {
315  if (!IS_SPACE(*s))
316  return 0;
317  s++;
318  }
319 
320  return -1;
321  }
322 
323  return 0;
324 }
enum MailboxType type
Mailbox type.
Definition: mailbox.h:105
Pager: signature lines.
Definition: color.h:94
#define NUM_SIG_LINES
Definition: pager.c:252
#define IS_SPACE(ch)
Definition: string2.h:38
int n
Definition: acutest.h:477
+ 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 334 of file pager.c.

335 {
336  const int *cnt = (const int *) m1;
337  const struct TextSyntax *stx = (const struct TextSyntax *) m2;
338 
339  if (*cnt < stx->first)
340  return -1;
341  if (*cnt >= stx->last)
342  return 1;
343  return 0;
344 }
int last
Definition: pager.c:128
Highlighting for a line of text.
Definition: pager.c:124
int first
Definition: pager.c:127
+ 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 355 of file pager.c.

357 {
358  int def_color; /* color without syntax highlight */
359  int color; /* final color */
360  static int last_color; /* last color set */
361  bool search = false;
362  int m;
363  struct TextSyntax *matching_chunk = NULL;
364 
365  if (cnt == 0)
366  last_color = -1; /* force attrset() */
367 
368  if (line_info[n].continuation)
369  {
370  if (!cnt && C_Markers)
371  {
373  mutt_window_addch('+');
374  last_color = Colors->defs[MT_COLOR_MARKERS];
375  }
376  m = (line_info[n].syntax)[0].first;
377  cnt += (line_info[n].syntax)[0].last;
378  }
379  else
380  m = n;
381  if (flags & MUTT_PAGER_LOGS)
382  {
383  def_color = Colors->defs[(line_info[n].syntax)[0].color];
384  }
385  else if (!(flags & MUTT_SHOWCOLOR))
386  def_color = Colors->defs[MT_COLOR_NORMAL];
387  else if (line_info[m].type == MT_COLOR_HEADER)
388  def_color = (line_info[m].syntax)[0].color;
389  else
390  def_color = Colors->defs[line_info[m].type];
391 
392  if ((flags & MUTT_SHOWCOLOR) && (line_info[m].type == MT_COLOR_QUOTED))
393  {
394  struct QClass *qc = line_info[m].quote;
395 
396  if (qc)
397  {
398  def_color = qc->color;
399 
400  while (qc && (qc->length > cnt))
401  {
402  def_color = qc->color;
403  qc = qc->up;
404  }
405  }
406  }
407 
408  color = def_color;
409  if ((flags & MUTT_SHOWCOLOR) && line_info[m].chunks)
410  {
411  matching_chunk = bsearch(&cnt, line_info[m].syntax, line_info[m].chunks,
412  sizeof(struct TextSyntax), comp_syntax_t);
413  if (matching_chunk && (cnt >= matching_chunk->first) &&
414  (cnt < matching_chunk->last))
415  {
416  color = matching_chunk->color;
417  }
418  }
419 
420  if ((flags & MUTT_SEARCH) && line_info[m].search_cnt)
421  {
422  matching_chunk = bsearch(&cnt, line_info[m].search, line_info[m].search_cnt,
423  sizeof(struct TextSyntax), comp_syntax_t);
424  if (matching_chunk && (cnt >= matching_chunk->first) &&
425  (cnt < matching_chunk->last))
426  {
427  color = Colors->defs[MT_COLOR_SEARCH];
428  search = 1;
429  }
430  }
431 
432  /* handle "special" bold & underlined characters */
433  if (special || a->attr)
434  {
435 #ifdef HAVE_COLOR
436  if ((a->attr & ANSI_COLOR))
437  {
438  if (a->pair == -1)
439  a->pair = mutt_color_alloc(Colors, a->fg, a->bg);
440  color = a->pair;
441  if (a->attr & ANSI_BOLD)
442  color |= A_BOLD;
443  }
444  else
445 #endif
446  if ((special & A_BOLD) || (a->attr & ANSI_BOLD))
447  {
448  if (Colors->defs[MT_COLOR_BOLD] && !search)
449  color = Colors->defs[MT_COLOR_BOLD];
450  else
451  color ^= A_BOLD;
452  }
453  if ((special & A_UNDERLINE) || (a->attr & ANSI_UNDERLINE))
454  {
455  if (Colors->defs[MT_COLOR_UNDERLINE] && !search)
456  color = Colors->defs[MT_COLOR_UNDERLINE];
457  else
458  color ^= A_UNDERLINE;
459  }
460  else if (a->attr & ANSI_REVERSE)
461  {
462  color ^= A_REVERSE;
463  }
464  else if (a->attr & ANSI_BLINK)
465  {
466  color ^= A_BLINK;
467  }
468  else if (a->attr == ANSI_OFF)
469  {
470  a->attr = 0;
471  }
472  }
473 
474  if (color != last_color)
475  {
476  mutt_curses_set_attr(color);
477  last_color = color;
478  }
479 }
Bold text.
Definition: color.h:65
Underlined text.
Definition: color.h:98
if(!test_colorize_)
Definition: acutest.h:484
#define ANSI_COLOR
Use colours.
Definition: pager.c:105
short chunks
Definition: pager.c:139
#define MUTT_SHOWCOLOR
Show characters in color otherwise don&#39;t show characters.
Definition: pager.h:45
void mutt_curses_set_color(enum ColorId color)
Set the current colour for text.
Definition: mutt_curses.c:55
size_t length
Definition: pager.c:113
int pair
Curses colour pair.
Definition: pager.c:155
int * defs
Array of all fixed colours, see enum ColorId.
Definition: color.h:132
int last
Definition: pager.c:128
short type
Definition: pager.c:137
Pager: quoted text.
Definition: color.h:82
#define ANSI_BOLD
Bold text.
Definition: pager.c:102
AnsiFlags attr
Attributes, e.g. underline, bold, etc.
Definition: pager.c:152
static int comp_syntax_t(const void *m1, const void *m2)
Search for a Syntax using bsearch.
Definition: pager.c:334
#define ANSI_BLINK
Blinking text.
Definition: pager.c:101
Message headers (takes a pattern)
Definition: color.h:73
Pager: markers, line continuation.
Definition: color.h:75
Plain text.
Definition: color.h:78
#define ANSI_REVERSE
Reverse video.
Definition: pager.c:104
struct QClass * quote
Definition: pager.c:143
int bg
Background colour.
Definition: pager.c:154
#define ANSI_UNDERLINE
Underlined text.
Definition: pager.c:103
Definition: color.h:130
#define MUTT_PAGER_LOGS
Logview mode.
Definition: pager.h:57
int fg
Foreground colour.
Definition: pager.c:153
Highlighting for a line of text.
Definition: pager.c:124
int mutt_window_addch(int ch)
Write one character to a Window.
Definition: mutt_window.c:400
#define MUTT_SEARCH
Resolve search patterns.
Definition: pager.h:47
int n
Definition: acutest.h:477
int mutt_color_alloc(struct Colors *c, uint32_t fg, uint32_t bg)
Allocate a colour pair.
Definition: color.c:472
int color
Definition: pager.c:115
Pager: search matches.
Definition: color.h:83
struct TextSyntax * syntax
Definition: pager.c:141
int first
Definition: pager.c:127
void mutt_curses_set_attr(int attr)
Set the attributes for text.
Definition: mutt_curses.c:40
WHERE bool C_Markers
Config: Display a &#39;+&#39; at the beginning of wrapped lines in the pager.
Definition: globals.h:238
struct QClass * up
Definition: pager.c:118
Style of quoted text.
Definition: pager.c:111
int color
Definition: pager.c:126
#define ANSI_OFF
Turn off colours and attributes.
Definition: pager.c:100
+ 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 487 of file pager.c.

488 {
489  int m;
490 
491  line_info[n + 1].type = line_info[n].type;
492  (line_info[n + 1].syntax)[0].color = (line_info[n].syntax)[0].color;
493  line_info[n + 1].continuation = 1;
494 
495  /* find the real start of the line */
496  for (m = n; m >= 0; m--)
497  if (line_info[m].continuation == 0)
498  break;
499 
500  (line_info[n + 1].syntax)[0].first = m;
501  (line_info[n + 1].syntax)[0].last =
502  (line_info[n].continuation) ? cnt + (line_info[n].syntax)[0].last : cnt;
503 }
short type
Definition: pager.c:137
short continuation
Definition: pager.c:138
int n
Definition: acutest.h:477
int color
Definition: pager.c:115
struct TextSyntax * syntax
Definition: pager.c:141
+ 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 510 of file pager.c.

511 {
512  qc->index = (*q_level)++;
513  qc->color = Colors->quotes[qc->index % Colors->quotes_used];
514 }
Definition: color.h:130
int color
Definition: pager.c:115
int index
Definition: pager.c:114
int quotes_used
Number of colours for quoted email text.
Definition: color.h:145
int * quotes
Array of colours for quoted email text.
Definition: color.h:144
+ 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 523 of file pager.c.

525 {
526  struct QClass *q_list = quote_list;
527  new_class->index = -1;
528 
529  while (q_list)
530  {
531  if (q_list->index >= index)
532  {
533  q_list->index++;
534  q_list->color = Colors->quotes[q_list->index % Colors->quotes_used];
535  }
536  if (q_list->down)
537  q_list = q_list->down;
538  else if (q_list->next)
539  q_list = q_list->next;
540  else
541  {
542  while (!q_list->next)
543  {
544  q_list = q_list->up;
545  if (!q_list)
546  break;
547  }
548  if (q_list)
549  q_list = q_list->next;
550  }
551  }
552 
553  new_class->index = index;
554  new_class->color = Colors->quotes[index % Colors->quotes_used];
555  (*q_level)++;
556 }
struct QClass * down
Definition: pager.c:118
struct QClass * next
Definition: pager.c:117
Definition: color.h:130
int color
Definition: pager.c:115
int index
Definition: pager.c:114
int quotes_used
Number of colours for quoted email text.
Definition: color.h:145
struct QClass * up
Definition: pager.c:118
Style of quoted text.
Definition: pager.c:111
int * quotes
Array of colours for quoted email text.
Definition: color.h:144
+ 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 562 of file pager.c.

563 {
564  struct QClass *ptr = NULL;
565 
566  while (*quote_list)
567  {
568  if ((*quote_list)->down)
569  cleanup_quote(&((*quote_list)->down));
570  ptr = (*quote_list)->next;
571  FREE(&(*quote_list)->prefix);
572  FREE(quote_list);
573  *quote_list = ptr;
574  }
575 }
static void cleanup_quote(struct QClass **quote_list)
Free a quote list.
Definition: pager.c:562
struct QClass * next
Definition: pager.c:117
#define FREE(x)
Definition: memory.h:40
Style of quoted text.
Definition: pager.c:111
+ 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 586 of file pager.c.

588 {
589  struct QClass *q_list = *quote_list;
590  struct QClass *qc = NULL, *tmp = NULL, *ptr = NULL, *save = NULL;
591  const char *tail_qptr = NULL;
592  int offset, tail_lng;
593  int index = -1;
594 
595  if (Colors->quotes_used <= 1)
596  {
597  /* not much point in classifying quotes... */
598 
599  if (!*quote_list)
600  {
601  qc = mutt_mem_calloc(1, sizeof(struct QClass));
602  qc->color = Colors->quotes[0];
603  *quote_list = qc;
604  }
605  return *quote_list;
606  }
607 
608  /* classify quoting prefix */
609  while (q_list)
610  {
611  if (length <= q_list->length)
612  {
613  /* case 1: check the top level nodes */
614 
615  if (mutt_str_strncmp(qptr, q_list->prefix, length) == 0)
616  {
617  if (length == q_list->length)
618  return q_list; /* same prefix: return the current class */
619 
620  /* found shorter prefix */
621  if (!tmp)
622  {
623  /* add a node above q_list */
624  tmp = mutt_mem_calloc(1, sizeof(struct QClass));
625  tmp->prefix = mutt_mem_calloc(1, length + 1);
626  strncpy(tmp->prefix, qptr, length);
627  tmp->length = length;
628 
629  /* replace q_list by tmp in the top level list */
630  if (q_list->next)
631  {
632  tmp->next = q_list->next;
633  q_list->next->prev = tmp;
634  }
635  if (q_list->prev)
636  {
637  tmp->prev = q_list->prev;
638  q_list->prev->next = tmp;
639  }
640 
641  /* make q_list a child of tmp */
642  tmp->down = q_list;
643  q_list->up = tmp;
644 
645  /* q_list has no siblings for now */
646  q_list->next = NULL;
647  q_list->prev = NULL;
648 
649  /* update the root if necessary */
650  if (q_list == *quote_list)
651  *quote_list = tmp;
652 
653  index = q_list->index;
654 
655  /* tmp should be the return class too */
656  qc = tmp;
657 
658  /* next class to test; if tmp is a shorter prefix for another
659  * node, that node can only be in the top level list, so don't
660  * go down after this point */
661  q_list = tmp->next;
662  }
663  else
664  {
665  /* found another branch for which tmp is a shorter prefix */
666 
667  /* save the next sibling for later */
668  save = q_list->next;
669 
670  /* unlink q_list from the top level list */
671  if (q_list->next)
672  q_list->next->prev = q_list->prev;
673  if (q_list->prev)
674  q_list->prev->next = q_list->next;
675 
676  /* at this point, we have a tmp->down; link q_list to it */
677  ptr = tmp->down;
678  /* sibling order is important here, q_list should be linked last */
679  while (ptr->next)
680  ptr = ptr->next;
681  ptr->next = q_list;
682  q_list->next = NULL;
683  q_list->prev = ptr;
684  q_list->up = tmp;
685 
686  index = q_list->index;
687 
688  /* next class to test; as above, we shouldn't go down */
689  q_list = save;
690  }
691 
692  /* we found a shorter prefix, so certain quotes have changed classes */
693  *force_redraw = true;
694  continue;
695  }
696  else
697  {
698  /* shorter, but not a substring of the current class: try next */
699  q_list = q_list->next;
700  continue;
701  }
702  }
703  else
704  {
705  /* case 2: try subclassing the current top level node */
706 
707  /* tmp != NULL means we already found a shorter prefix at case 1 */
708  if (!tmp && (mutt_str_strncmp(qptr, q_list->prefix, q_list->length) == 0))
709  {
710  /* ok, it's a subclass somewhere on this branch */
711 
712  ptr = q_list;
713  offset = q_list->length;
714 
715  q_list = q_list->down;
716  tail_lng = length - offset;
717  tail_qptr = qptr + offset;
718 
719  while (q_list)
720  {
721  if (length <= q_list->length)
722  {
723  if (mutt_str_strncmp(tail_qptr, (q_list->prefix) + offset, tail_lng) == 0)
724  {
725  /* same prefix: return the current class */
726  if (length == q_list->length)
727  return q_list;
728 
729  /* found shorter common 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 */
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  tmp->up = q_list->up;
753  q_list->up = tmp;
754  if (tmp->up->down == q_list)
755  tmp->up->down = tmp;
756 
757  /* q_list has no siblings */
758  q_list->next = NULL;
759  q_list->prev = NULL;
760 
761  index = q_list->index;
762 
763  /* tmp should be the return class too */
764  qc = tmp;
765 
766  /* next class to test */
767  q_list = tmp->next;
768  }
769  else
770  {
771  /* found another branch for which tmp is a shorter prefix */
772 
773  /* save the next sibling for later */
774  save = q_list->next;
775 
776  /* unlink q_list from the top level list */
777  if (q_list->next)
778  q_list->next->prev = q_list->prev;
779  if (q_list->prev)
780  q_list->prev->next = q_list->next;
781 
782  /* at this point, we have a tmp->down; link q_list to it */
783  ptr = tmp->down;
784  while (ptr->next)
785  ptr = ptr->next;
786  ptr->next = q_list;
787  q_list->next = NULL;
788  q_list->prev = ptr;
789  q_list->up = tmp;
790 
791  index = q_list->index;
792 
793  /* next class to test */
794  q_list = save;
795  }
796 
797  /* we found a shorter prefix, so we need a redraw */
798  *force_redraw = true;
799  continue;
800  }
801  else
802  {
803  q_list = q_list->next;
804  continue;
805  }
806  }
807  else
808  {
809  /* longer than the current prefix: try subclassing it */
810  if (!tmp && (mutt_str_strncmp(tail_qptr, (q_list->prefix) + offset,
811  q_list->length - offset) == 0))
812  {
813  /* still a subclass: go down one level */
814  ptr = q_list;
815  offset = q_list->length;
816 
817  q_list = q_list->down;
818  tail_lng = length - offset;
819  tail_qptr = qptr + offset;
820 
821  continue;
822  }
823  else
824  {
825  /* nope, try the next prefix */
826  q_list = q_list->next;
827  continue;
828  }
829  }
830  }
831 
832  /* still not found so far: add it as a sibling to the current node */
833  if (!qc)
834  {
835  tmp = mutt_mem_calloc(1, sizeof(struct QClass));
836  tmp->prefix = mutt_mem_calloc(1, length + 1);
837  strncpy(tmp->prefix, qptr, length);
838  tmp->length = length;
839 
840  if (ptr->down)
841  {
842  tmp->next = ptr->down;
843  ptr->down->prev = tmp;
844  }
845  ptr->down = tmp;
846  tmp->up = ptr;
847 
848  class_color_new(tmp, q_level);
849 
850  return tmp;
851  }
852  else
853  {
854  if (index != -1)
855  shift_class_colors(*quote_list, tmp, index, q_level);
856 
857  return qc;
858  }
859  }
860  else
861  {
862  /* nope, try the next prefix */
863  q_list = q_list->next;
864  continue;
865  }
866  }
867  }
868 
869  if (!qc)
870  {
871  /* not found so far: add it as a top level class */
872  qc = mutt_mem_calloc(1, sizeof(struct QClass));
873  qc->prefix = mutt_mem_calloc(1, length + 1);
874  strncpy(qc->prefix, qptr, length);
875  qc->length = length;
876  class_color_new(qc, q_level);
877 
878  if (*quote_list)
879  {
880  qc->next = *quote_list;
881  (*quote_list)->prev = qc;
882  }
883  *quote_list = qc;
884  }
885 
886  if (index != -1)
887  shift_class_colors(*quote_list, tmp, index, q_level);
888 
889  return qc;
890 }
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:50
size_t length
Definition: pager.c:113
static void class_color_new(struct QClass *qc, int *q_level)
Create a new quoting colour.
Definition: pager.c:510
struct QClass * down
Definition: pager.c:118
char * prefix
Definition: pager.c:116
struct QClass * next
Definition: pager.c:117
Definition: color.h:130
int mutt_str_strncmp(const char *a, const char *b, size_t l)
Compare two strings (to a maximum), safely.
Definition: string.c:665
int color
Definition: pager.c:115
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:523
int index
Definition: pager.c:114
struct QClass * prev
Definition: pager.c:117
int quotes_used
Number of colours for quoted email text.
Definition: color.h:145
struct QClass * up
Definition: pager.c:118
Style of quoted text.
Definition: pager.c:111
int * quotes
Array of colours for quoted email text.
Definition: color.h:144
+ 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 898 of file pager.c.

899 {
900  for (; (p[0] == q[0]) && (q[0] != '\0') && (p[0] != '\0') && (q[0] != '\a') &&
901  (p[0] != '\a');
902  p++, q++)
903  {
904  }
905 
906  return (int) (*p - *q);
907 }
+ 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 914 of file pager.c.

915 {
916  return check_marker(AttachmentMarker, p);
917 }
WHERE char AttachmentMarker[256]
Unique ANSI string to mark PGP messages in an email.
Definition: globals.h:46
static int check_marker(const char *q, const char *p)
Check that the unique marker is present.
Definition: pager.c:898
+ 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 924 of file pager.c.

925 {
927 }
static int check_marker(const char *q, const char *p)
Check that the unique marker is present.
Definition: pager.c:898
WHERE char ProtectedHeaderMarker[256]
Unique ANSI string to mark protected headers in an email.
Definition: globals.h:47
+ 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 C_QuoteRegex and doesn't match C_Smileys. This is used by the pager for calling classify_quote.

Definition at line 938 of file pager.c.

939 {
940  bool is_quote = false;
941  regmatch_t pmatch_internal[1], smatch[1];
942 
943  if (!pmatch)
944  pmatch = pmatch_internal;
945 
946  if (mutt_regex_capture(C_QuoteRegex, line, 1, pmatch))
947  {
948  if (mutt_regex_capture(C_Smileys, line, 1, smatch))
949  {
950  if (smatch[0].rm_so > 0)
951  {
952  char c = line[smatch[0].rm_so];
953  line[smatch[0].rm_so] = 0;
954 
955  if (mutt_regex_capture(C_QuoteRegex, line, 1, pmatch))
956  is_quote = true;
957 
958  line[smatch[0].rm_so] = c;
959  }
960  }
961  else
962  is_quote = true;
963  }
964 
965  return is_quote;
966 }
struct Regex * C_Smileys
Config: Regex to match smileys to prevent mistakes when quoting text.
Definition: pager.c:93
WHERE struct Regex * C_QuoteRegex
Config: Regex to match quoted text in a reply.
Definition: globals.h:175
bool mutt_regex_capture(const struct Regex *regex, const char *str, size_t nmatch, regmatch_t matches[])
match a regex against a string, with provided options
Definition: regex.c:594
int const char int line
Definition: acutest.h:602
+ 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 980 of file pager.c.

983 {
984  struct ColorLine *color_line = NULL;
985  struct ColorLineList *head = NULL;
986  regmatch_t pmatch[1];
987  bool found;
988  bool null_rx;
989  int offset, i = 0;
990 
991  if ((n == 0) || IS_HEADER(line_info[n - 1].type) ||
992  (check_protected_header_marker(raw) == 0))
993  {
994  if (buf[0] == '\n') /* end of header */
995  {
996  line_info[n].type = MT_COLOR_NORMAL;
997  getyx(stdscr, braille_line, braille_col);
998  }
999  else
1000  {
1001  /* if this is a continuation of the previous line, use the previous
1002  * line's color as default. */
1003  if ((n > 0) && ((buf[0] == ' ') || (buf[0] == '\t')))
1004  {
1005  line_info[n].type = line_info[n - 1].type; /* wrapped line */
1006  if (!C_HeaderColorPartial)
1007  {
1008  (line_info[n].syntax)[0].color = (line_info[n - 1].syntax)[0].color;
1009  line_info[n].is_cont_hdr = 1;
1010  }
1011  }
1012  else
1013  {
1014  line_info[n].type = MT_COLOR_HDRDEFAULT;
1015  }
1016 
1017  /* When this option is unset, we color the entire header the
1018  * same color. Otherwise, we handle the header patterns just
1019  * like body patterns (further below). */
1020  if (!C_HeaderColorPartial)
1021  {
1022  STAILQ_FOREACH(color_line, &Colors->hdr_list, entries)
1023  {
1024  if (regexec(&color_line->regex, buf, 0, NULL, 0) == 0)
1025  {
1026  line_info[n].type = MT_COLOR_HEADER;
1027  line_info[n].syntax[0].color = color_line->pair;
1028  if (line_info[n].is_cont_hdr)
1029  {
1030  /* adjust the previous continuation lines to reflect the color of this continuation line */
1031  int j;
1032  for (j = n - 1; j >= 0 && line_info[j].is_cont_hdr; --j)
1033  {
1034  line_info[j].type = line_info[n].type;
1035  line_info[j].syntax[0].color = line_info[n].syntax[0].color;
1036  }
1037  /* now adjust the first line of this header field */
1038  if (j >= 0)
1039  {
1040  line_info[j].type = line_info[n].type;
1041  line_info[j].syntax[0].color = line_info[n].syntax[0].color;
1042  }
1043  *force_redraw = true; /* the previous lines have already been drawn on the screen */
1044  }
1045  break;
1046  }
1047  }
1048  }
1049  }
1050  }
1051  else if (mutt_str_startswith(raw, "\033[0m", CASE_MATCH)) // Escape: a little hack...
1052  line_info[n].type = MT_COLOR_NORMAL;
1053  else if (check_attachment_marker((char *) raw) == 0)
1054  line_info[n].type = MT_COLOR_ATTACHMENT;
1055  else if ((mutt_str_strcmp("-- \n", buf) == 0) || (mutt_str_strcmp("-- \r\n", buf) == 0))
1056  {
1057  i = n + 1;
1058 
1059  line_info[n].type = MT_COLOR_SIGNATURE;
1060  while ((i < last) && (check_sig(buf, line_info, i - 1) == 0) &&
1061  ((line_info[i].type == MT_COLOR_NORMAL) || (line_info[i].type == MT_COLOR_QUOTED) ||
1062  (line_info[i].type == MT_COLOR_HEADER)))
1063  {
1064  /* oops... */
1065  if (line_info[i].chunks)
1066  {
1067  line_info[i].chunks = 0;
1068  mutt_mem_realloc(&(line_info[n].syntax), sizeof(struct TextSyntax));
1069  }
1070  line_info[i++].type = MT_COLOR_SIGNATURE;
1071  }
1072  }
1073  else if (check_sig(buf, line_info, n - 1) == 0)
1074  line_info[n].type = MT_COLOR_SIGNATURE;
1075  else if (mutt_is_quote_line(buf, pmatch))
1076 
1077  {
1078  if (q_classify && (line_info[n].quote == NULL))
1079  {
1080  line_info[n].quote = classify_quote(quote_list, buf + pmatch[0].rm_so,
1081  pmatch[0].rm_eo - pmatch[0].rm_so,
1082  force_redraw, q_level);
1083  }
1084  line_info[n].type = MT_COLOR_QUOTED;
1085  }
1086  else
1087  line_info[n].type = MT_COLOR_NORMAL;
1088 
1089  /* body patterns */
1090  if ((line_info[n].type == MT_COLOR_NORMAL) || (line_info[n].type == MT_COLOR_QUOTED) ||
1091  ((line_info[n].type == MT_COLOR_HDRDEFAULT) && C_HeaderColorPartial))
1092  {
1093  size_t nl;
1094 
1095  /* don't consider line endings part of the buffer
1096  * for regex matching */
1097  nl = mutt_str_strlen(buf);
1098  if ((nl > 0) && (buf[nl - 1] == '\n'))
1099  buf[nl - 1] = '\0';
1100 
1101  i = 0;
1102  offset = 0;
1103  line_info[n].chunks = 0;
1104  if (line_info[n].type == MT_COLOR_HDRDEFAULT)
1105  head = &Colors->hdr_list;
1106  else
1107  head = &Colors->body_list;
1108  STAILQ_FOREACH(color_line, head, entries)
1109  {
1110  color_line->stop_matching = false;
1111  }
1112  do
1113  {
1114  if (!buf[offset])
1115  break;
1116 
1117  found = false;
1118  null_rx = false;
1119  STAILQ_FOREACH(color_line, head, entries)
1120  {
1121  if (!color_line->stop_matching &&
1122  (regexec(&color_line->regex, buf + offset, 1, pmatch,
1123  ((offset != 0) ? REG_NOTBOL : 0)) == 0))
1124  {
1125  if (pmatch[0].rm_eo != pmatch[0].rm_so)
1126  {
1127  if (!found)
1128  {
1129  /* Abort if we fill up chunks.
1130  * Yes, this really happened. */
1131  if (line_info[n].chunks == SHRT_MAX)
1132  {
1133  null_rx = false;
1134  break;
1135  }
1136  if (++(line_info[n].chunks) > 1)
1137  {
1138  mutt_mem_realloc(&(line_info[n].syntax),
1139  (line_info[n].chunks) * sizeof(struct TextSyntax));
1140  }
1141  }
1142  i = line_info[n].chunks - 1;
1143  pmatch[0].rm_so += offset;
1144  pmatch[0].rm_eo += offset;
1145  if (!found || (pmatch[0].rm_so < (line_info[n].syntax)[i].first) ||
1146  ((pmatch[0].rm_so == (line_info[n].syntax)[i].first) &&
1147  (pmatch[0].rm_eo > (line_info[n].syntax)[i].last)))
1148  {
1149  (line_info[n].syntax)[i].color = color_line->pair;
1150  (line_info[n].syntax)[i].first = pmatch[0].rm_so;
1151  (line_info[n].syntax)[i].last = pmatch[0].rm_eo;
1152  }
1153  found = true;
1154  null_rx = false;
1155  }
1156  else
1157  null_rx = true; /* empty regex; don't add it, but keep looking */
1158  }
1159  else
1160  {
1161  /* Once a regexp fails to match, don't try matching it again.
1162  * On very long lines this can cause a performance issue if there
1163  * are other regexps that have many matches. */
1164  color_line->stop_matching = true;
1165  }
1166  }
1167 
1168  if (null_rx)
1169  offset++; /* avoid degenerate cases */
1170  else
1171  offset = (line_info[n].syntax)[i].last;
1172  } while (found || null_rx);
1173  if (nl > 0)
1174  buf[nl] = '\n';
1175  }
1176 
1177  /* attachment patterns */
1178  if (line_info[n].type == MT_COLOR_ATTACHMENT)
1179  {
1180  size_t nl;
1181 
1182  /* don't consider line endings part of the buffer for regex matching */
1183  nl = mutt_str_strlen(buf);
1184  if ((nl > 0) && (buf[nl - 1] == '\n'))
1185  buf[nl - 1] = '\0';
1186 
1187  i = 0;
1188  offset = 0;
1189  line_info[n].chunks = 0;
1190  do
1191  {
1192  if (!buf[offset])
1193  break;
1194 
1195  found = false;
1196  null_rx = false;
1197  STAILQ_FOREACH(color_line, &Colors->attach_list, entries)
1198  {
1199  if (regexec(&color_line->regex, buf + offset, 1, pmatch,
1200  ((offset != 0) ? REG_NOTBOL : 0)) == 0)
1201  {
1202  if (pmatch[0].rm_eo != pmatch[0].rm_so)
1203  {
1204  if (!found)
1205  {
1206  if (++(line_info[n].chunks) > 1)
1207  {
1208  mutt_mem_realloc(&(line_info[n].syntax),
1209  (line_info[n].chunks) * sizeof(struct TextSyntax));
1210  }
1211  }
1212  i = line_info[n].chunks - 1;
1213  pmatch[0].rm_so += offset;
1214  pmatch[0].rm_eo += offset;
1215  if (!found || (pmatch[0].rm_so < (line_info[n].syntax)[i].first) ||
1216  ((pmatch[0].rm_so == (line_info[n].syntax)[i].first) &&
1217  (pmatch[0].rm_eo > (line_info[n].syntax)[i].last)))
1218  {
1219  (line_info[n].syntax)[i].color = color_line->pair;
1220  (line_info[n].syntax)[i].first = pmatch[0].rm_so;
1221  (line_info[n].syntax)[i].last = pmatch[0].rm_eo;
1222  }
1223  found = 1;
1224  null_rx = 0;
1225  }
1226  else
1227  null_rx = 1; /* empty regex; don't add it, but keep looking */
1228  }
1229  }
1230 
1231  if (null_rx)
1232  offset++; /* avoid degenerate cases */
1233  else
1234  offset = (line_info[n].syntax)[i].last;
1235  } while (found || null_rx);
1236  if (nl > 0)
1237  buf[nl] = '\n';
1238  }
1239 }
Header default colour.
Definition: color.h:72
static int check_protected_header_marker(const char *p)
Check that the unique marker is present.
Definition: pager.c:924
struct ColorLineList body_list
List of colours applied to the email body.
Definition: color.h:135
short chunks
Definition: pager.c:139
int pair
Colour pair index.
Definition: color.h:44
Pager: signature lines.
Definition: color.h:94
Match case when comparing strings.
Definition: string2.h:67
size_t mutt_str_strlen(const char *a)
Calculate the length of a string, safely.
Definition: string.c:689
short type
Definition: pager.c:137
Pager: quoted text.
Definition: color.h:82
static int braille_line
Definition: pager.c:209
Message headers (takes a pattern)
Definition: color.h:73
struct ColorLineList hdr_list
List of colours applied to the email headers.
Definition: color.h:136
Plain text.
Definition: color.h:78
void mutt_mem_realloc(void *ptr, size_t size)
Resize a block of memory on the heap.
Definition: memory.c:114
struct QClass * quote
Definition: pager.c:143
static int braille_col
Definition: pager.c:210
bool stop_matching
Used by the pager for body patterns, to prevent the color from being retried once it fails...
Definition: color.h:46
#define IS_HEADER(x)
Definition: pager.c:245
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:349
Definition: color.h:130
size_t mutt_str_startswith(const char *str, const char *prefix, enum CaseSensitivity cs)
Check whether a string starts with a prefix.
Definition: string.c:168
regex_t regex
Compiled regex.
Definition: color.h:38
Highlighting for a line of text.
Definition: pager.c:124
int n
Definition: acutest.h:477
MIME attachments text (entire line)
Definition: color.h:62
bool C_HeaderColorPartial
Config: Only colour the part of the header matching the regex.
Definition: pager.c:86
struct TextSyntax * syntax
Definition: pager.c:141
struct ColorLineList attach_list
List of colours applied to the attachment headers.
Definition: color.h:134
int mutt_is_quote_line(char *line, regmatch_t *pmatch)
Is a line of message text a quote?
Definition: pager.c:938
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:586
static int check_attachment_marker(const char *p)
Check that the unique marker is present.
Definition: pager.c:914
static int check_sig(const char *s, struct Line *info, int n)
Check for an email signature.
Definition: pager.c:295
int mutt_str_strcmp(const char *a, const char *b)
Compare two strings, safely.
Definition: string.c:638
unsigned int is_cont_hdr
this line is a continuation of the previous header line
Definition: pager.c:144
A regular expression and a color to highlight a line.
Definition: color.h:36
int color
Definition: pager.c:126
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ is_ansi()

static bool is_ansi ( unsigned char *  buf)
static

Is this an ANSI escape sequence?

Parameters
bufString to check
Return values
trueIf it is

Definition at line 1246 of file pager.c.

1247 {
1248  while ((*buf != '\0') && (isdigit(*buf) || (*buf == ';')))
1249  buf++;
1250  return *buf == 'm';
1251 }
+ 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 1260 of file pager.c.

1261 {
1262  int x = pos;
1263 
1264  while (isdigit(buf[x]) || (buf[x] == ';'))
1265  x++;
1266 
1267  /* Character Attributes */
1268  if (C_AllowAnsi && a && (buf[x] == 'm'))
1269  {
1270  if (pos == x)
1271  {
1272 #ifdef HAVE_COLOR
1273  if (a->pair != -1)
1274  mutt_color_free(Colors, a->fg, a->bg);
1275 #endif
1276  a->attr = ANSI_OFF;
1277  a->pair = -1;
1278  }
1279  while (pos < x)
1280  {
1281  if ((buf[pos] == '1') && ((pos + 1 == x) || (buf[pos + 1] == ';')))
1282  {
1283  a->attr |= ANSI_BOLD;
1284  pos += 2;
1285  }
1286  else if ((buf[pos] == '4') && ((pos + 1 == x) || (buf[pos + 1] == ';')))
1287  {
1288  a->attr |= ANSI_UNDERLINE;
1289  pos += 2;
1290  }
1291  else if ((buf[pos] == '5') && ((pos + 1 == x) || (buf[pos + 1] == ';')))
1292  {
1293  a->attr |= ANSI_BLINK;
1294  pos += 2;
1295  }
1296  else if ((buf[pos] == '7') && ((pos + 1 == x) || (buf[pos + 1] == ';')))
1297  {
1298  a->attr |= ANSI_REVERSE;
1299  pos += 2;
1300  }
1301  else if ((buf[pos] == '0') && ((pos + 1 == x) || (buf[pos + 1] == ';')))
1302  {
1303 #ifdef HAVE_COLOR
1304  if (a->pair != -1)
1305  mutt_color_free(Colors, a->fg, a->bg);
1306 #endif
1307  a->attr = ANSI_OFF;
1308  a->pair = -1;
1309  pos += 2;
1310  }
1311  else if ((buf[pos] == '3') && isdigit(buf[pos + 1]))
1312  {
1313 #ifdef HAVE_COLOR
1314  if (a->pair != -1)
1315  mutt_color_free(Colors, a->fg, a->bg);
1316 #endif
1317  a->pair = -1;
1318  a->attr |= ANSI_COLOR;
1319  a->fg = buf[pos + 1] - '0';
1320  pos += 3;
1321  }
1322  else if ((buf[pos] == '4') && isdigit(buf[pos + 1]))
1323  {
1324 #ifdef HAVE_COLOR
1325  if (a->pair != -1)
1326  mutt_color_free(Colors, a->fg, a->bg);
1327 #endif
1328  a->pair = -1;
1329  a->attr |= ANSI_COLOR;
1330  a->bg = buf[pos + 1] - '0';
1331  pos += 3;
1332  }
1333  else
1334  {
1335  while ((pos < x) && (buf[pos] != ';'))
1336  pos++;
1337  pos++;
1338  }
1339  }
1340  }
1341  pos = x;
1342  return pos;
1343 }
bool C_AllowAnsi
Config: Allow ANSI colour codes in rich text messages.
Definition: pager.c:85
#define ANSI_COLOR
Use colours.
Definition: pager.c:105
void mutt_color_free(struct Colors *c, uint32_t fg, uint32_t bg)
Free a colour.
Definition: color.c:252
int pair
Curses colour pair.
Definition: pager.c:155
#define ANSI_BOLD
Bold text.
Definition: pager.c:102
AnsiFlags attr
Attributes, e.g. underline, bold, etc.
Definition: pager.c:152
#define ANSI_BLINK
Blinking text.
Definition: pager.c:101
#define ANSI_REVERSE
Reverse video.
Definition: pager.c:104
int bg
Background colour.
Definition: pager.c:154
#define ANSI_UNDERLINE
Underlined text.
Definition: pager.c:103
Definition: color.h:130
int fg
Foreground colour.
Definition: pager.c:153
#define ANSI_OFF
Turn off colours and attributes.
Definition: pager.c:100
+ 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 1357 of file pager.c.

1359 {
1360  unsigned char *p = NULL, *q = NULL;
1361  static int b_read;
1362  int l = 0;
1363 
1364  if (*buf_ready == 0)
1365  {
1366  if (offset != *last_pos)
1367  fseeko(fp, offset, SEEK_SET);
1368  *buf = (unsigned char *) mutt_file_read_line((char *) *buf, blen, fp, &l, MUTT_EOL);
1369  if (!*buf)
1370  {
1371  fmt[0] = NULL;
1372  return -1;
1373  }
1374  *last_pos = ftello(fp);
1375  b_read = (int) (*last_pos - offset);
1376  *buf_ready = 1;
1377 
1378  mutt_mem_realloc(fmt, *blen);
1379 
1380  /* copy "buf" to "fmt", but without bold and underline controls */
1381  p = *buf;
1382  q = *fmt;
1383  while (*p)
1384  {
1385  if ((p[0] == '\010') && (p > *buf)) // Ctrl-H (backspace)
1386  {
1387  if (p[1] == '_') /* underline */
1388  p += 2;
1389  else if ((p[1] != '\0') && (q > *fmt)) /* bold or overstrike */
1390  {
1391  q[-1] = p[1];
1392  p += 2;
1393  }
1394  else /* ^H */
1395  *q++ = *p++;
1396  }
1397  else if ((p[0] == '\033') && (p[1] == '[') && is_ansi(p + 2)) // Escape
1398  {
1399  while (*p++ != 'm') /* skip ANSI sequence */
1400  ;
1401  }
1402  else if ((p[0] == '\033') && (p[1] == ']') && // Escape
1403  ((check_attachment_marker((char *) p) == 0) ||
1404  (check_protected_header_marker((char *) p) == 0)))
1405  {
1406  mutt_debug(LL_DEBUG2, "Seen attachment marker\n");
1407  while (*p++ != '\a') /* skip pseudo-ANSI sequence */
1408  ;
1409  }
1410  else
1411  *q++ = *p++;
1412  }
1413  *q = '\0';
1414  }
1415  return b_read;
1416 }
static int check_protected_header_marker(const char *p)
Check that the unique marker is present.
Definition: pager.c:924
static int const char * fmt
Definition: acutest.h:473
char * mutt_file_read_line(char *line, size_t *size, FILE *fp, int *line_num, int flags)
Read a line from a file.
Definition: file.c:667
Log at debug level 2.
Definition: logging.h:41
void mutt_mem_realloc(void *ptr, size_t size)
Resize a block of memory on the heap.
Definition: memory.c:114
#define MUTT_EOL
don&#39;t strip \n / \r\n
Definition: file.h:39
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
static bool is_ansi(unsigned char *buf)
Is this an ANSI escape sequence?
Definition: pager.c:1246
static int check_attachment_marker(const char *p)
Check that the unique marker is present.
Definition: pager.c:914
+ 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 1433 of file pager.c.

1436 {
1437  int space = -1; /* index of the last space or TAB */
1438  int col = C_Markers ? (*line_info)[n].continuation : 0;
1439  size_t k;
1440  int ch, vch, last_special = -1, special = 0, t;
1441  wchar_t wc;
1442  mbstate_t mbstate;
1443  int wrap_cols = mutt_window_wrap_cols(width, (flags & MUTT_PAGER_NOWRAP) ? 0 : C_Wrap);
1444 
1445  if (check_attachment_marker((char *) buf) == 0)
1446  wrap_cols = width;
1447 
1448  /* FIXME: this should come from line_info */
1449  memset(&mbstate, 0, sizeof(mbstate));
1450 
1451  for (ch = 0, vch = 0; ch < cnt; ch += k, vch += k)
1452  {
1453  /* Handle ANSI sequences */
1454  while ((cnt - ch >= 2) && (buf[ch] == '\033') && (buf[ch + 1] == '[') && // Escape
1455  is_ansi(buf + ch + 2))
1456  {
1457  ch = grok_ansi(buf, ch + 2, pa) + 1;
1458  }
1459 
1460  while ((cnt - ch >= 2) && (buf[ch] == '\033') && (buf[ch + 1] == ']') && // Escape
1461  ((check_attachment_marker((char *) buf + ch) == 0) ||
1462  (check_protected_header_marker((char *) buf + ch) == 0)))
1463  {
1464  while (buf[ch++] != '\a')
1465  if (ch >= cnt)
1466  break;
1467  }
1468 
1469  /* is anything left to do? */
1470  if (ch >= cnt)
1471  break;
1472 
1473  k = mbrtowc(&wc, (char *) buf + ch, cnt - ch, &mbstate);
1474  if ((k == (size_t)(-2)) || (k == (size_t)(-1)))
1475  {
1476  if (k == (size_t)(-1))
1477  memset(&mbstate, 0, sizeof(mbstate));
1478  mutt_debug(LL_DEBUG1, "mbrtowc returned %lu; errno = %d\n", k, errno);
1479  if (col + 4 > wrap_cols)
1480  break;
1481  col += 4;
1482  if (pa)
1483  mutt_window_printf("\\%03o", buf[ch]);
1484  k = 1;
1485  continue;
1486  }
1487  if (k == 0)
1488  k = 1;
1489 
1490  if (CharsetIsUtf8)
1491  {
1492  /* zero width space, zero width no-break space */
1493  if ((wc == 0x200B) || (wc == 0xFEFF))
1494  {
1495  mutt_debug(LL_DEBUG3, "skip zero-width character U+%04X\n", (unsigned short) wc);
1496  continue;
1497  }
1499  {
1500  mutt_debug(LL_DEBUG3, "filtered U+%04X\n", (unsigned short) wc);
1501  continue;
1502  }
1503  }
1504 
1505  /* Handle backspace */
1506  special = 0;
1507  if (IsWPrint(wc))
1508  {
1509  wchar_t wc1;
1510  mbstate_t mbstate1 = mbstate;
1511  size_t k1 = mbrtowc(&wc1, (char *) buf + ch + k, cnt - ch - k, &mbstate1);
1512  while ((k1 != (size_t)(-2)) && (k1 != (size_t)(-1)) && (k1 > 0) && (wc1 == '\b'))
1513  {
1514  const size_t k2 =
1515  mbrtowc(&wc1, (char *) buf + ch + k + k1, cnt - ch - k - k1, &mbstate1);
1516  if ((k2 == (size_t)(-2)) || (k2 == (size_t)(-1)) || (k2 == 0) || (!IsWPrint(wc1)))
1517  break;
1518 
1519  if (wc == wc1)
1520  {
1521  special |= ((wc == '_') && (special & A_UNDERLINE)) ? A_UNDERLINE : A_BOLD;
1522  }
1523  else if ((wc == '_') || (wc1 == '_'))
1524  {
1525  special |= A_UNDERLINE;
1526  wc = (wc1 == '_') ? wc : wc1;
1527  }
1528  else
1529  {
1530  /* special = 0; / * overstrike: nothing to do! */
1531  wc = wc1;
1532  }
1533 
1534  ch += k + k1;
1535  k = k2;
1536  mbstate = mbstate1;
1537  k1 = mbrtowc(&wc1, (char *) buf + ch + k, cnt - ch - k, &mbstate1);
1538  }
1539  }
1540 
1541  if (pa && ((flags & (MUTT_SHOWCOLOR | MUTT_SEARCH | MUTT_PAGER_MARKER)) ||
1542  special || last_special || pa->attr))
1543  {
1544  resolve_color(*line_info, n, vch, flags, special, pa);
1545  last_special = special;
1546  }
1547 
1548  /* no-break space, narrow no-break space */
1549  if (IsWPrint(wc) || (CharsetIsUtf8 && ((wc == 0x00A0) || (wc == 0x202F))))
1550  {
1551  if (wc == ' ')
1552  {
1553  space = ch;
1554  }
1555  t = wcwidth(wc);
1556  if (col + t > wrap_cols)
1557  break;
1558  col += t;
1559  if (pa)
1560  mutt_addwch(wc);
1561  }
1562  else if (wc == '\n')
1563  break;
1564  else if (wc == '\t')
1565  {
1566  space = ch;
1567  t = (col & ~7) + 8;
1568  if (t > wrap_cols)
1569  break;
1570  if (pa)
1571  for (; col < t; col++)
1572  mutt_window_addch(' ');
1573  else
1574  col = t;
1575  }
1576  else if ((wc < 0x20) || (wc == 0x7f))
1577  {
1578  if (col + 2 > wrap_cols)
1579  break;
1580  col += 2;
1581  if (pa)
1582  mutt_window_printf("^%c", ('@' + wc) & 0x7f);
1583  }
1584  else if (wc < 0x100)
1585  {
1586  if (col + 4 > wrap_cols)
1587  break;
1588  col += 4;
1589  if (pa)
1590  mutt_window_printf("\\%03o", wc);
1591  }
1592  else
1593  {
1594  if (col + 1 > wrap_cols)
1595  break;
1596  col += k;
1597  if (pa)
1599  }
1600  }
1601  *pspace = space;
1602  *pcol = col;
1603  *pvch = vch;
1604  *pspecial = special;
1605  return ch;
1606 }
static int check_protected_header_marker(const char *p)
Check that the unique marker is present.
Definition: pager.c:924
bool mutt_mb_is_display_corrupting_utf8(wchar_t wc)
Will this character corrupt the display?
Definition: mbyte.c:390
#define IsWPrint(wc)
Definition: mbyte.h:40
#define MUTT_SHOWCOLOR
Show characters in color otherwise don&#39;t show characters.
Definition: pager.h:45
WHERE short C_Wrap
Config: Width to wrap text in the pager.
Definition: globals.h:153
#define MUTT_PAGER_NOWRAP
Format for term width, ignore $wrap.
Definition: pager.h:56
wchar_t ReplacementChar
When a Unicode character can&#39;t be displayed, use this instead.
Definition: charset.c:59
AnsiFlags attr
Attributes, e.g. underline, bold, etc.
Definition: pager.c:152
int mutt_window_wrap_cols(int width, short wrap)
Calculate the wrap column for a given screen width.
Definition: mutt_window.c:385
int mutt_window_printf(const char *fmt,...)
Write a formatted string to a Window.
Definition: mutt_window.c:458
int mutt_window_addch(int ch)
Write one character to a Window.
Definition: mutt_window.c:400
bool CharsetIsUtf8
Is the user&#39;s current character set utf-8?
Definition: charset.c:64
#define MUTT_SEARCH
Resolve search patterns.
Definition: pager.h:47
static int grok_ansi(unsigned char *buf, int pos, struct AnsiAttr *a)
Parse an ANSI escape sequence.
Definition: pager.c:1260
Log at debug level 1.
Definition: logging.h:40
int n
Definition: acutest.h:477
#define MUTT_PAGER_MARKER
Use markers if option is set.
Definition: pager.h:53
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
static bool is_ansi(unsigned char *buf)
Is this an ANSI escape sequence?
Definition: pager.c:1246
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:355
static int check_attachment_marker(const char *p)
Check that the unique marker is present.
Definition: pager.c:914
WHERE bool C_Markers
Config: Display a &#39;+&#39; at the beginning of wrapped lines in the pager.
Definition: globals.h:238
Log at debug level 3.
Definition: logging.h:42
int mutt_addwch(wchar_t wc)
addwch would be provided by an up-to-date curses library
Definition: curs_lib.c:1037
+ 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 1626 of file pager.c.

1630 {
1631  unsigned char *buf = NULL, *fmt = NULL;
1632  size_t buflen = 0;
1633  unsigned char *buf_ptr = NULL;
1634  int ch, vch, col, cnt, b_read;
1635  int buf_ready = 0;
1636  bool change_last = false;
1637  int special;
1638  int offset;
1639  int def_color;
1640  int m;
1641  int rc = -1;
1642  struct AnsiAttr a = { 0, 0, 0, -1 };
1643  regmatch_t pmatch[1];
1644 
1645  if (n == *last)
1646  {
1647  (*last)++;
1648  change_last = true;
1649  }
1650 
1651  if (*last == *max)
1652  {
1653  mutt_mem_realloc(line_info, sizeof(struct Line) * (*max += LINES));
1654  for (ch = *last; ch < *max; ch++)
1655  {
1656  memset(&((*line_info)[ch]), 0, sizeof(struct Line));
1657  (*line_info)[ch].type = -1;
1658  (*line_info)[ch].search_cnt = -1;
1659  (*line_info)[ch].syntax = mutt_mem_malloc(sizeof(struct TextSyntax));
1660  ((*line_info)[ch].syntax)[0].first = -1;
1661  ((*line_info)[ch].syntax)[0].last = -1;
1662  }
1663  }
1664 
1665  struct Line *const curr_line = &(*line_info)[n];
1666 
1667  if (flags & MUTT_PAGER_LOGS)
1668  {
1669  /* determine the line class */
1670  if (fill_buffer(fp, last_pos, curr_line->offset, &buf, &fmt, &buflen, &buf_ready) < 0)
1671  {
1672  if (change_last)
1673  (*last)--;
1674  goto out;
1675  }
1676 
1677  curr_line->type = MT_COLOR_MESSAGE_LOG;
1678  if (buf[11] == 'M')
1679  curr_line->syntax[0].color = MT_COLOR_MESSAGE;
1680  else if (buf[11] == 'W')
1681  curr_line->syntax[0].color = MT_COLOR_WARNING;
1682  else if (buf[11] == 'E')
1683  curr_line->syntax[0].color = MT_COLOR_ERROR;
1684  else
1685  curr_line->syntax[0].color = MT_COLOR_NORMAL;
1686  }
1687 
1688  /* only do color highlighting if we are viewing a message */
1689  if (flags & (MUTT_SHOWCOLOR | MUTT_TYPES))
1690  {
1691  if (curr_line->type == -1)
1692  {
1693  /* determine the line class */
1694  if (fill_buffer(fp, last_pos, curr_line->offset, &buf, &fmt, &buflen, &buf_ready) < 0)
1695  {
1696  if (change_last)
1697  (*last)--;
1698  goto out;
1699  }
1700 
1701  resolve_types((char *) fmt, (char *) buf, *line_info, n, *last,
1702  quote_list, q_level, force_redraw, flags & MUTT_SHOWCOLOR);
1703 
1704  /* avoid race condition for continuation lines when scrolling up */
1705  for (m = n + 1; m < *last && (*line_info)[m].offset && (*line_info)[m].continuation; m++)
1706  (*line_info)[m].type = curr_line->type;
1707  }
1708 
1709  /* this also prevents searching through the hidden lines */
1710  if ((flags & MUTT_HIDE) && (curr_line->type == MT_COLOR_QUOTED) &&
1711  ((curr_line->quote == NULL) || (curr_line->quote->index >= C_ToggleQuotedShowLevels)))
1712  {
1713  flags = 0; /* MUTT_NOSHOW */
1714  }
1715  }
1716 
1717  /* At this point, (*line_info[n]).quote may still be undefined. We
1718  * don't want to compute it every time MUTT_TYPES is set, since this
1719  * would slow down the "bottom" function unacceptably. A compromise
1720  * solution is hence to call regexec() again, just to find out the
1721  * length of the quote prefix. */
1722  if ((flags & MUTT_SHOWCOLOR) && !curr_line->continuation &&
1723  (curr_line->type == MT_COLOR_QUOTED) && !curr_line->quote)
1724  {
1725  if (fill_buffer(fp, last_pos, curr_line->offset, &buf, &fmt, &buflen, &buf_ready) < 0)
1726  {
1727  if (change_last)
1728  (*last)--;
1729  goto out;
1730  }
1731 
1732  if (mutt_regex_capture(C_QuoteRegex, (char *) fmt, 1, pmatch))
1733  {
1734  curr_line->quote =
1735  classify_quote(quote_list, (char *) fmt + pmatch[0].rm_so,
1736  pmatch[0].rm_eo - pmatch[0].rm_so, force_redraw, q_level);
1737  }
1738  else
1739  {
1740  goto out;
1741  }
1742  }
1743 
1744  if ((flags & MUTT_SEARCH) && !curr_line->continuation && (curr_line->search_cnt == -1))
1745  {
1746  if (fill_buffer(fp, last_pos, curr_line->offset, &buf, &fmt, &buflen, &buf_ready) < 0)
1747  {
1748  if (change_last)
1749  (*last)--;
1750  goto out;
1751  }
1752 
1753  offset = 0;
1754  curr_line->search_cnt = 0;
1755  while (regexec(search_re, (char *) fmt + offset, 1, pmatch,
1756  (offset ? REG_NOTBOL : 0)) == 0)
1757  {
1758  if (++(curr_line->search_cnt) > 1)
1759  {
1760  mutt_mem_realloc(&(curr_line->search),
1761  (curr_line->search_cnt) * sizeof(struct TextSyntax));
1762  }
1763  else
1764  curr_line->search = mutt_mem_malloc(sizeof(struct TextSyntax));
1765  pmatch[0].rm_so += offset;
1766  pmatch[0].rm_eo += offset;
1767  (curr_line->search)[curr_line->search_cnt - 1].first = pmatch[0].rm_so;
1768  (curr_line->search)[curr_line->search_cnt - 1].last = pmatch[0].rm_eo;
1769 
1770  if (pmatch[0].rm_eo == pmatch[0].rm_so)
1771  offset++; /* avoid degenerate cases */
1772  else
1773  offset = pmatch[0].rm_eo;
1774  if (!fmt[offset])
1775  break;
1776  }
1777  }
1778 
1779  if (!(flags & MUTT_SHOW) && ((*line_info)[n + 1].offset > 0))
1780  {
1781  /* we've already scanned this line, so just exit */
1782  rc = 0;
1783  goto out;
1784  }
1785  if ((flags & MUTT_SHOWCOLOR) && *force_redraw && ((*line_info)[n + 1].offset > 0))
1786  {
1787  /* no need to try to display this line... */
1788  rc = 1;
1789  goto out; /* fake display */
1790  }
1791 
1792  b_read = fill_buffer(fp, last_pos, curr_line->offset, &buf, &fmt, &buflen, &buf_ready);
1793  if (b_read < 0)
1794  {
1795  if (change_last)
1796  (*last)--;
1797  goto out;
1798  }
1799 
1800  /* now chose a good place to break the line */
1801  cnt = format_line(line_info, n, buf, flags, NULL, b_read, &ch, &vch, &col,
1802  &special, win_pager->state.cols);
1803  buf_ptr = buf + cnt;
1804 
1805  /* move the break point only if smart_wrap is set */
1806  if (C_SmartWrap)
1807  {
1808  if ((cnt < b_read) && (ch != -1) && !IS_HEADER(curr_line->type) && !IS_SPACE(buf[cnt]))
1809  {
1810  buf_ptr = buf + ch;
1811  /* skip trailing blanks */
1812  while (ch && ((buf[ch] == ' ') || (buf[ch] == '\t') || (buf[ch] == '\r')))
1813  ch--;
1814  /* A very long word with leading spaces causes infinite
1815  * wrapping when MUTT_PAGER_NSKIP is set. A folded header
1816  * with a single long word shouldn't be smartwrapped
1817  * either. So just disable smart_wrap if it would wrap at the
1818  * beginning of the line. */
1819  if (ch == 0)
1820  buf_ptr = buf + cnt;
1821  else
1822  cnt = ch + 1;
1823  }
1824  if (!(flags & MUTT_PAGER_NSKIP))
1825  {
1826  /* skip leading blanks on the next line too */
1827  while ((*buf_ptr == ' ') || (*buf_ptr == '\t'))
1828  buf_ptr++;
1829  }
1830  }
1831 
1832  if (*buf_ptr == '\r')
1833  buf_ptr++;
1834  if (*buf_ptr == '\n')
1835  buf_ptr++;
1836 
1837  if (((int) (buf_ptr - buf) < b_read) && !(*line_info)[n + 1].continuation)
1838  append_line(*line_info, n, (int) (buf_ptr - buf));
1839  (*line_info)[n + 1].offset = curr_line->offset + (long) (buf_ptr - buf);
1840 
1841  /* if we don't need to display the line we are done */
1842  if (!(flags & MUTT_SHOW))
1843  {
1844  rc = 0;
1845  goto out;
1846  }
1847 
1848  /* display the line */
1849  format_line(line_info, n, buf, flags, &a, cnt, &ch, &vch, &col, &special,
1850  win_pager->state.cols);
1851 
1852 /* avoid a bug in ncurses... */
1853 #ifndef USE_SLANG_CURSES
1854  if (col == 0)
1855  {
1857  mutt_window_addch(' ');
1858  }
1859 #endif
1860 
1861  /* end the last color pattern (needed by S-Lang) */
1862  if (special || ((col != win_pager->state.cols) && (flags & (MUTT_SHOWCOLOR | MUTT_SEARCH))))
1863  resolve_color(*line_info, n, vch, flags, 0, &a);
1864 
1865  /* Fill the blank space at the end of the line with the prevailing color.
1866  * ncurses does an implicit clrtoeol() when you do mutt_window_addch('\n') so we have
1867  * to make sure to reset the color *after* that */
1868  if (flags & MUTT_SHOWCOLOR)
1869  {
1870  m = (curr_line->continuation) ? (curr_line->syntax)[0].first : n;
1871  if ((*line_info)[m].type == MT_COLOR_HEADER)
1872  def_color = ((*line_info)[m].syntax)[0].color;
1873  else
1874  def_color = Colors->defs[(*line_info)[m].type];
1875 
1876  mutt_curses_set_attr(def_color);
1877  }
1878 
1879  if (col < win_pager->state.cols)
1880  mutt_window_clrtoeol(win_pager);
1881 
1882  /* reset the color back to normal. This *must* come after the
1883  * clrtoeol, otherwise the color for this line will not be
1884  * filled to the right margin. */
1885  if (flags & MUTT_SHOWCOLOR)
1887 
1888  /* build a return code */
1889  if (!(flags & MUTT_SHOW))
1890  flags = 0;
1891 
1892  rc = flags;
1893 
1894 out:
1895  FREE(&buf);
1896  FREE(&fmt);
1897  return rc;
1898 }
#define MUTT_TYPES
Compute line&#39;s type.
Definition: pager.h:48
Informational message.
Definition: color.h:76
#define MUTT_SHOWCOLOR
Show characters in color otherwise don&#39;t show characters.
Definition: pager.h:45
void mutt_curses_set_color(enum ColorId color)
Set the current colour for text.
Definition: mutt_curses.c:55
int * defs
Array of all fixed colours, see enum ColorId.
Definition: color.h:132
static int const char * fmt
Definition: acutest.h:473
void mutt_window_clrtoeol(struct MuttWindow *win)
Clear to the end of the line.
Definition: mutt_window.c:134
An ANSI escape sequence.
Definition: pager.c:150
short type
Definition: pager.c:137
Pager: quoted text.
Definition: color.h:82
Menu showing log messages.
Definition: color.h:77
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:980
Message headers (takes a pattern)
Definition: color.h:73
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:1433
short continuation
Definition: pager.c:138
#define MUTT_PAGER_NSKIP
Preserve whitespace with smartwrap.
Definition: pager.h:52
#define MUTT_SHOW
Definition: pager.h:49
Plain text.
Definition: color.h:78
void mutt_mem_realloc(void *ptr, size_t size)
Resize a block of memory on the heap.
Definition: memory.c:114
short cols
Number of columns, can be MUTT_WIN_SIZE_UNLIMITED.
Definition: mutt_window.h:58
struct QClass * quote
Definition: pager.c:143
short search_cnt
Definition: pager.c:140
struct TextSyntax * search
Definition: pager.c:142
struct WindowState state
Current state of the Window.
Definition: mutt_window.h:93
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:90
#define IS_HEADER(x)
Definition: pager.c:245
WHERE struct Regex * C_QuoteRegex
Config: Regex to match quoted text in a reply.
Definition: globals.h:175
A line of text in the pager.
Definition: pager.c:134
WHERE int C_ToggleQuotedShowLevels
Config: Number of quote levels to show with toggle-quoted.
Definition: globals.h:176
#define MUTT_HIDE
Don&#39;t show quoted text.
Definition: pager.h:46
Definition: color.h:130
#define MUTT_PAGER_LOGS
Logview mode.
Definition: pager.h:57
bool C_SmartWrap
Config: Wrap text at word boundaries.
Definition: pager.c:92
bool mutt_regex_capture(const struct Regex *regex, const char *str, size_t nmatch, regmatch_t matches[])
match a regex against a string, with provided options
Definition: regex.c:594
#define IS_SPACE(ch)
Definition: string2.h:38
Highlighting for a line of text.
Definition: pager.c:124
int mutt_window_addch(int ch)
Write one character to a Window.
Definition: mutt_window.c:400
#define MUTT_SEARCH
Resolve search patterns.
Definition: pager.h:47
Error message.
Definition: color.h:71
int n
Definition: acutest.h:477
#define FREE(x)
Definition: memory.h:40
int index
Definition: pager.c:114
struct TextSyntax * syntax
Definition: pager.c:141
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:1357
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:586
void mutt_curses_set_attr(int attr)
Set the attributes for text.
Definition: mutt_curses.c:40
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:355
LOFF_T offset
Definition: pager.c:136
static void append_line(struct Line *line_info, int n, int cnt)
Add a new Line to the array.
Definition: pager.c:487
Warning messages.
Definition: color.h:99
int color
Definition: pager.c:126
+ 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 1908 of file pager.c.

1909 {
1910  while ((cur > 0) && (nlines > 0))
1911  {
1912  cur--;
1913  if (!hiding || (info[cur].type != MT_COLOR_QUOTED))
1914  nlines--;
1915  }
1916 
1917  return cur;
1918 }
short type
Definition: pager.c:137
Pager: quoted text.
Definition: color.h:82
+ 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 1923 of file pager.c.

1924 {
1925  TopLine = 0;
1926  OldEmail = NULL;
1927 }
static int TopLine
Definition: pager.c:204
static struct Email * OldEmail
Definition: pager.c:205
+ 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 1932 of file pager.c.

1933 {
1934  struct PagerRedrawData *rd = pager_menu->redraw_data;
1935  char buf[1024];
1936 
1937  if (!rd)
1938  return;
1939 
1940  if (pager_menu->redraw & REDRAW_FULL)
1941  {
1943  /* clear() doesn't optimize screen redraws */
1944  mutt_window_move_abs(0, 0);
1946 
1947  if (IsEmail(rd->extra) && Context && Context->mailbox &&
1949  {
1950  rd->indexlen = Context->mailbox->vcount + 1;
1951  }
1952  else
1954 
1955  rd->indicator = rd->indexlen / 3;
1956 
1957  if (C_Help)
1958  {
1963  }
1964 
1965  if (Resize)
1966  {
1968  if (rd->search_compiled)
1969  {
1970  int flags = mutt_mb_is_lower(rd->searchbuf) ? REG_ICASE : 0;
1971  const int err = REG_COMP(&rd->search_re, rd->searchbuf, REG_NEWLINE | flags);
1972  if (err == 0)
1973  {
1974  rd->search_flag = MUTT_SEARCH;
1976  }
1977  else
1978  {
1979  regerror(err, &rd->search_re, buf, sizeof(buf));
1980  mutt_error("%s", buf);
1981  rd->search_compiled = false;
1982  }
1983  }
1984  rd->lines = Resize->line;
1985  pager_menu->redraw |= REDRAW_FLOW;
1986 
1987  FREE(&Resize);
1988  }
1989 
1990  if (IsEmail(rd->extra) && (C_PagerIndexLines != 0))
1991  {
1992  if (!rd->menu)
1993  {
1994  /* only allocate the space if/when we need the index.
1995  * Initialise the menu as per the main index */
1996  rd->menu = mutt_menu_new(MENU_MAIN);
1998  rd->menu->color = index_color;
1999  rd->menu->max = Context ? Context->mailbox->vcount : 0;
2000  rd->menu->current = rd->extra->email->vnum;
2001  rd->menu->win_index = rd->extra->win_index;
2002  rd->menu->win_ibar = rd->extra->win_ibar;
2003  }
2004 
2006  rd->menu->pagelen = rd->extra->win_index->state.rows;
2007 
2008  /* some fudge to work out whereabouts the indicator should go */
2009  if (rd->menu->current - rd->indicator < 0)
2010  rd->menu->top = 0;
2011  else if (rd->menu->max - rd->menu->current < rd->menu->pagelen - rd->indicator)
2012  rd->menu->top = rd->menu->max - rd->menu->pagelen;
2013  else
2014  rd->menu->top = rd->menu->current - rd->indicator;
2015 
2016  menu_redraw_index(rd->menu);
2017  }
2018 
2019  pager_menu->redraw |= REDRAW_BODY | REDRAW_INDEX | REDRAW_STATUS;
2020 #ifdef USE_SIDEBAR
2021  pager_menu->redraw |= REDRAW_SIDEBAR;
2022 #endif
2023  mutt_show_error();
2024  }
2025 
2026  if (pager_menu->redraw & REDRAW_FLOW)
2027  {
2028  if (!(rd->flags & MUTT_PAGER_RETWINCH))
2029  {
2030  rd->lines = -1;
2031  for (int i = 0; i <= rd->topline; i++)
2032  if (!rd->line_info[i].continuation)
2033  rd->lines++;
2034  for (int i = 0; i < rd->max_line; i++)
2035  {
2036  rd->line_info[i].offset = 0;
2037  rd->line_info[i].type = -1;
2038  rd->line_info[i].continuation = 0;
2039  rd->line_info[i].chunks = 0;
2040  rd->line_info[i].search_cnt = -1;
2041  rd->line_info[i].quote = NULL;
2042 
2043  mutt_mem_realloc(&(rd->line_info[i].syntax), sizeof(struct TextSyntax));
2044  if (rd->search_compiled && rd->line_info[i].search)
2045  FREE(&(rd->line_info[i].search));
2046  }
2047 
2048  rd->last_line = 0;
2049  rd->topline = 0;
2050  }
2051  int i = -1;
2052  int j = -1;
2053  while (display_line(rd->fp, &rd->last_pos, &rd->line_info, ++i, &rd->last_line,
2054  &rd->max_line, rd->has_types | rd->search_flag | (rd->flags & MUTT_PAGER_NOWRAP),
2055  &rd->quote_list, &rd->q_level, &rd->force_redraw,
2056  &rd->search_re, rd->extra->win_pager) == 0)
2057  {
2058  if (!rd->line_info[i].continuation && (++j == rd->lines))
2059  {
2060  rd->topline = i;
2061  if (!rd->search_flag)
2062  break;
2063  }
2064  }
2065  }
2066 
2067 #ifdef USE_SIDEBAR
2068  if (pager_menu->redraw & REDRAW_SIDEBAR)
2069  {
2070  menu_redraw_sidebar(pager_menu);
2071  }
2072 #endif
2073 
2074  if ((pager_menu->redraw & REDRAW_BODY) || (rd->topline != rd->oldtopline))
2075  {
2076  do
2077  {
2078  mutt_window_move(rd->extra->win_pager, 0, 0);
2079  rd->curline = rd->topline;
2080  rd->oldtopline = rd->topline;
2081  rd->lines = 0;
2082  rd->force_redraw = false;
2083 
2084  while ((rd->lines < rd->extra->win_pager->state.rows) &&
2085  (rd->line_info[rd->curline].offset <= rd->sb.st_size - 1))
2086  {
2087  if (display_line(rd->fp, &rd->last_pos, &rd->line_info, rd->curline,
2088  &rd->last_line, &rd->max_line,
2089  (rd->flags & MUTT_DISPLAYFLAGS) | rd->hide_quoted |
2090  rd->search_flag | (rd->flags & MUTT_PAGER_NOWRAP),
2091  &rd->quote_list, &rd->q_level, &rd->force_redraw,
2092  &rd->search_re, rd->extra->win_pager) > 0)
2093  {
2094  rd->lines++;
2095  }
2096  rd->curline++;
2097  mutt_window_move(rd->extra->win_pager, rd->lines, 0);
2098  }
2099  rd->last_offset = rd->line_info[rd->curline].offset;
2100  } while (rd->force_redraw);
2101 
2103  while (rd->lines < rd->extra->win_pager->state.rows)
2104  {
2106  if (C_Tilde)
2107  mutt_window_addch('~');
2108  rd->lines++;
2109  mutt_window_move(rd->extra->win_pager, rd->lines, 0);
2110  }
2112 
2113  /* We are going to update the pager status bar, so it isn't
2114  * necessary to reset to normal color now. */
2115 
2116  pager_menu->redraw |= REDRAW_STATUS; /* need to update the % seen */
2117  }
2118 
2119  if (pager_menu->redraw & REDRAW_STATUS)
2120  {
2121  struct HdrFormatInfo hfi;
2122  char pager_progress_str[65]; /* Lots of space for translations */
2123 
2124  hfi.ctx = Context;
2125  hfi.mailbox = Context ? Context->mailbox : NULL;
2126  hfi.pager_progress = pager_progress_str;
2127 
2128  if (rd->last_pos < rd->sb.st_size - 1)
2129  {
2130  snprintf(pager_progress_str, sizeof(pager_progress_str), OFF_T_FMT "%%",
2131  (100 * rd->last_offset / rd->sb.st_size));
2132  }
2133  else
2134  {
2135  const char *msg = (rd->topline == 0) ?
2136  /* L10N: Status bar message: the entire email is visible in the pager */
2137  _("all") :
2138  /* L10N: Status bar message: the end of the email is visible in the pager */
2139  _("end");
2140  mutt_str_strfcpy(pager_progress_str, msg, sizeof(pager_progress_str));
2141  }
2142 
2143  /* print out the pager status bar */
2144  mutt_window_move(rd->extra->win_pbar, 0, 0);
2146 
2147  if (IsEmail(rd->extra) || IsMsgAttach(rd->extra))
2148  {
2149  size_t l1 = rd->extra->win_pbar->state.cols * MB_LEN_MAX;
2150  size_t l2 = sizeof(buf);
2151  hfi.email = (IsEmail(rd->extra)) ? rd->extra->email : rd->extra->body->email;
2152  mutt_make_string_info(buf, (l1 < l2) ? l1 : l2, rd->extra->win_pbar->state.cols,
2154  mutt_draw_statusline(rd->extra->win_pbar->state.cols, buf, l2);
2155  }
2156  else
2157  {
2158  char bn[256];
2159  snprintf(bn, sizeof(bn), "%s (%s)", rd->banner, pager_progress_str);
2160  mutt_draw_statusline(rd->extra->win_pbar->state.cols, bn, sizeof(bn));
2161  }
2163  if (C_TsEnabled && TsSupported && rd->menu)
2164  {
2165  menu_status_line(buf, sizeof(buf), rd->menu, NONULL(C_TsStatusFormat));
2166  mutt_ts_status(buf);
2167  menu_status_line(buf, sizeof(buf), rd->menu, NONULL(C_TsIconFormat));
2168  mutt_ts_icon(buf);
2169  }
2170  }
2171 
2172  if ((pager_menu->redraw & REDRAW_INDEX) && rd->menu)
2173  {
2174  /* redraw the pager_index indicator, because the
2175  * flags for this message might have changed. */
2176  if (rd->extra->win_index->state.rows > 0)
2178 
2179  /* print out the index status bar */
2180  menu_status_line(buf, sizeof(buf), rd->menu, NONULL(C_StatusFormat));
2181 
2182  mutt_window_move(rd->extra->win_ibar, 0, 0);
2184  mutt_draw_statusline(rd->extra->win_ibar->state.cols, buf, sizeof(buf));
2186  }
2187 
2188  pager_menu->redraw = REDRAW_NO_FLAGS;
2189 }
struct Menu * menu
the Pager Index (PI)
Definition: pager.c:190
struct Context * ctx
Definition: hdrline.h:47
The "current" mailbox.
Definition: context.h:37
void mutt_window_move_abs(int row, int col)
Move the cursor to an absolute screen position.
Definition: mutt_window.c:447
WHERE char * C_TsIconFormat
Config: printf-like format string for the terminal&#39;s icon title.
Definition: globals.h:148
struct MuttWindow * win_index
Definition: pager.h:74
#define REDRAW_FULL
Redraw everything.
Definition: mutt_menu.h:47
#define NONULL(x)
Definition: string2.h:37
const char * banner
Definition: pager.c:195
PagerFlags hide_quoted
Definition: pager.c:185
PagerFlags search_flag
Definition: pager.c:193
#define MUTT_DISPLAYFLAGS
Definition: pager.h:60
short chunks
Definition: pager.c:139
Keep track when the pager needs redrawing.
Definition: pager.c:171
void mutt_curses_set_color(enum ColorId color)
Set the current colour for text.
Definition: mutt_curses.c:55
#define REDRAW_FLOW
Used by pager to reflow text.
Definition: mutt_menu.h:49
void mutt_window_clrtoeol(struct MuttWindow *win)
Clear to the end of the line.
Definition: mutt_window.c:134
WHERE bool C_Help
Config: Display a help line with common key bindings.
Definition: globals.h:217
void index_make_entry(char *buf, size_t buflen, struct Menu *menu, int line)
Format a menu item for the index list - Implements Menu::make_entry()
Definition: index.c:827
#define IsMsgAttach(pager)
Definition: pager.c:248
#define _(a)
Definition: message.h:28
const char * helpstr
Definition: pager.c:196
struct Line * line_info
Definition: pager.c:198
int index_color(int line)
Calculate the colour for a line of the index - Implements Menu::color()
Definition: index.c:901
void menu_status_line(char *buf, size_t buflen, struct Menu *menu, const char *p)
Create the status line.
Definition: status.c:409
struct MuttWindow * MuttHelpWindow
Help Window.
Definition: mutt_window.c:45
struct Body * body
Current attachment.
Definition: pager.h:69
PagerFlags flags
Definition: pager.c:173
Index panel (list of emails)
Definition: keymap.h:77
bool search_back
Definition: pager.c:165
WHERE char * C_StatusFormat
Config: printf-like format string for the index&#39;s status line.
Definition: globals.h:146
bool search_compiled
Definition: pager.c:164
short type
Definition: pager.c:137
#define MUTT_PAGER_NOWRAP
Format for term width, ignore $wrap.
Definition: pager.h:56
WHERE bool C_TsEnabled
Config: Allow NeoMutt to set the terminal status line and icon.
Definition: globals.h:255
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:1626
#define MUTT_FORMAT_NO_FLAGS
No flags are set.
Definition: format_flags.h:30
int vcount
The number of virtual messages.
Definition: mailbox.h:102
#define REDRAW_SIDEBAR
Redraw the sidebar.
Definition: mutt_menu.h:51
void mutt_paddstr(int n, const char *s)
Display a string on screen, padded if necessary.
Definition: curs_lib.c:1244
LOFF_T last_pos
Definition: pager.c:188
int line
Definition: pager.c:163
void * redraw_data
Definition: mutt_menu.h:155
Pager: empty lines after message.
Definition: color.h:96
struct Mailbox * mailbox
Definition: context.h:51
Data passed to index_format_str()
Definition: hdrline.h:45
int indexlen
Definition: pager.c:175
struct MuttWindow * win_ibar
Definition: mutt_menu.h:96
LOFF_T last_offset
Definition: pager.c:189
int has_types
Definition: pager.c:184
FILE * fp
Definition: pager.c:199
#define REG_COMP(preg, regex, cflags)
Compile a regular expression.
Definition: regex3.h:52
short continuation
Definition: pager.c:138
void mutt_window_clrtobot(void)
Clear to the bottom of the Window.
Definition: mutt_window.c:123
bool force_redraw
Definition: pager.c:183
Plain text.
Definition: color.h:78
void mutt_mem_realloc(void *ptr, size_t size)
Resize a block of memory on the heap.
Definition: memory.c:114
struct MuttWindow * win_pager
Definition: pager.h:76
short cols
Number of columns, can be MUTT_WIN_SIZE_UNLIMITED.
Definition: mutt_window.h:58
void mutt_make_string_info(char *buf, size_t buflen, int cols, const char *s, struct HdrFormatInfo *hfi, MuttFormatFlags flags)
Create pager status bar string.
Definition: hdrline.c:1528
int oldtopline
Definition: pager.c:177
struct Pager * extra
Definition: pager.c:174
struct QClass * quote
Definition: pager.c:143
short search_cnt
Definition: pager.c:140
WHERE struct Context * Context
Definition: globals.h:42
struct TextSyntax * search
Definition: pager.c:142
struct WindowState state
Current state of the Window.
Definition: mutt_window.h:93
#define REDRAW_STATUS
Redraw the status bar.
Definition: mutt_menu.h:46
bool search_compiled
Definition: pager.c:192
int(* color)(int line)
Calculate the colour for a line of the menu.
Definition: mutt_menu.h:147
Status bar (takes a pattern)
Definition: color.h:95
short rows
Number of rows, can be MUTT_WIN_SIZE_UNLIMITED.
Definition: mutt_window.h:57
int top
Entry that is the top of the current page.
Definition: mutt_menu.h:108
int max_line
Definition: pager.c:179
size_t mutt_str_strfcpy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:773
int last_line
Definition: pager.c:180
int vnum
Virtual message number.
Definition: email.h:87
int pagelen
Number of entries per screen.
Definition: mutt_menu.h:92
bool TsSupported
Terminal Setting is supported.
Definition: terminal.c:43
int mutt_window_move(struct MuttWindow *win, int row, int col)
Move the cursor in a Window.
Definition: mutt_window.c:278
WHERE char * C_TsStatusFormat
Config: printf-like format string for the terminal&#39;s status (window title)
Definition: globals.h:147
int max
Number of entries in the menu.
Definition: mutt_menu.h:88
MuttRedrawFlags redraw
When to redraw the screen.
Definition: mutt_menu.h:89
struct QClass * quote_list
Definition: pager.c:187
#define IsEmail(pager)
Definition: pager.c:250
int indicator
the indicator line of the PI
Definition: pager.c:176
struct Email * email
Current message.
Definition: pager.h:68
Highlighting for a line of text.
Definition: pager.c:124
int mutt_window_addch(int ch)
Write one character to a Window.
Definition: mutt_window.c:400
#define MUTT_PAGER_RETWINCH
Need reformatting on SIGWINCH.
Definition: pager.h:54
#define MUTT_SEARCH
Resolve search patterns.
Definition: pager.h:47
#define REDRAW_BODY
Redraw the pager.
Definition: mutt_menu.h:48
char * searchbuf
Definition: pager.c:197
#define REDRAW_INDEX
Redraw the index.
Definition: mutt_menu.h:42
#define mutt_error(...)
Definition: logging.h:84
#define FREE(x)
Definition: memory.h:40
void mutt_ts_icon(char *str)
Set the icon in the terminal title bar.
Definition: terminal.c:118
bool C_Tilde
Config: Character to pad blank lines in the pager.
Definition: pager.c:94
struct TextSyntax * syntax
Definition: pager.c:141
void mutt_show_error(void)
Show the user an error message.
Definition: curs_lib.c:533
struct MuttWindow * win_ibar
Definition: pager.h:73
Keep track of screen resizing.
Definition: pager.c:161
void mutt_ts_status(char *str)
Set the text of the terminal title bar.
Definition: terminal.c:104
struct stat sb
Definition: pager.c:200
int current
Current entry.
Definition: mutt_menu.h:87
struct MuttWindow * win_index
Definition: mutt_menu.h:95
#define REDRAW_NO_FLAGS
No flags are set.
Definition: mutt_menu.h:41
LOFF_T offset
Definition: pager.c:136
bool mutt_mb_is_lower(const char *s)
Does a multi-byte string contain only lowercase characters?
Definition: mbyte.c:358
struct Email * email
header information for message/rfc822
Definition: body.h:55
void(* make_entry)(char *buf, size_t buflen, struct Menu *menu, int line)
Format a item for a menu.
Definition: mutt_menu.h:120
void mutt_draw_statusline(int cols, const char *buf, size_t buflen)
Draw a highlighted status bar.
Definition: index.c:929
short C_PagerIndexLines
Config: Number of index lines to display above the pager.
Definition: pager.c:88
WHERE char * C_PagerFormat
Config: printf-like format string for the pager&#39;s status bar.
Definition: globals.h:134
regex_t search_re
Definition: pager.c:191
bool search_back
Definition: pager.c:194
struct MuttWindow * win_pbar
Definition: pager.h:75
+ 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 2206 of file pager.c.

2207 {
2208  static char searchbuf[256] = { 0 };
2209  char buf[1024];
2210  int ch = 0, rc = -1;
2211  bool first = true;
2212  int searchctx = 0;
2213  bool wrapped = false;
2214 
2215  struct Menu *pager_menu = NULL;
2216  int old_PagerIndexLines; /* some people want to resize it while inside the pager */
2217 #ifdef USE_NNTP
2218  char *followup_to = NULL;
2219 #endif
2220 
2221  if (!(flags & MUTT_SHOWCOLOR))
2222  flags |= MUTT_SHOWFLAT;
2223 
2224  int index_space = C_PagerIndexLines;
2225  if (extra->ctx && extra->ctx->mailbox)
2226  index_space = MIN(index_space, extra->ctx->mailbox->vcount);
2227 
2228  struct PagerRedrawData rd = { 0 };
2229  rd.banner = banner;
2230  rd.flags = flags;
2231  rd.extra = extra;
2232  rd.indexlen = index_space;
2233  rd.indicator = rd.indexlen / 3;
2234  rd.searchbuf = searchbuf;
2235  rd.has_types = (IsEmail(extra) || (flags & MUTT_SHOWCOLOR)) ? MUTT_TYPES : 0; /* main message or rfc822 attachment */
2236 
2237  rd.fp = fopen(fname, "r");
2238  if (!rd.fp)
2239  {
2240  mutt_perror(fname);
2241  return -1;
2242  }
2243 
2244  if (stat(fname, &rd.sb) != 0)
2245  {
2246  mutt_perror(fname);
2247  mutt_file_fclose(&rd.fp);
2248  return -1;
2249  }
2250  unlink(fname);
2251 
2252  if (rd.extra->win_index)
2253  {
2255  rd.extra->win_index->req_rows = index_space;
2257  rd.extra->win_index->parent->state.visible = (index_space > 0);
2258  }
2259  rd.extra->win_pager->parent->state.visible = true;
2262 
2263  /* Initialize variables */
2264 
2265  if (Context && IsEmail(extra) && !extra->email->read)
2266  {
2267  Context->msg_not_read_yet = extra->email->msgno;
2268  mutt_set_flag(Context->mailbox, extra->email, MUTT_READ, true);
2269  }
2270 
2271  rd.max_line = LINES; /* number of lines on screen, from curses */
2272  rd.line_info = mutt_mem_calloc(rd.max_line, sizeof(struct Line));
2273  for (size_t i = 0; i < rd.max_line; i++)
2274  {
2275  rd.line_info[i].type = -1;
2276  rd.line_info[i].search_cnt = -1;
2277  rd.line_info[i].syntax = mutt_mem_malloc(sizeof(struct TextSyntax));
2278  (rd.line_info[i].syntax)[0].first = -1;
2279  (rd.line_info[i].syntax)[0].last = -1;
2280  }
2281 
2282  struct Buffer helpstr = mutt_buffer_make(0);
2283  mutt_compile_help(buf, sizeof(buf), MENU_PAGER, PagerHelp);
2284  mutt_buffer_strcpy(&helpstr, buf);
2285  if (IsEmail(extra))
2286  {
2287  mutt_compile_help(buf, sizeof(buf), MENU_PAGER,
2288 #ifdef USE_NNTP
2289  (Context && (Context->mailbox->type == MUTT_NNTP)) ?
2291 #endif
2292  PagerHelpExtra);
2293  mutt_buffer_addch(&helpstr, ' ');
2294  mutt_buffer_addstr(&helpstr, buf);
2295  }
2296  if (!InHelp)
2297  {
2298  mutt_make_help(buf, sizeof(buf), _("Help"), MENU_PAGER, OP_HELP);
2299  mutt_buffer_addch(&helpstr, ' ');
2300  mutt_buffer_addstr(&helpstr, buf);
2301  }
2302  rd.helpstr = mutt_b2s(&helpstr);
2303 
2304  pager_menu = mutt_menu_new(MENU_PAGER);
2305  pager_menu->pagelen = extra->win_pager->state.rows;
2306  pager_menu->win_index = extra->win_pager;
2307  pager_menu->win_ibar = extra->win_pbar;
2308 
2309  pager_menu->custom_redraw = pager_custom_redraw;
2310  pager_menu->redraw_data = &rd;
2311  mutt_menu_push_current(pager_menu);
2312 
2313  while (ch != -1)
2314  {
2316 
2317  pager_custom_redraw(pager_menu);
2318 
2319  if (C_BrailleFriendly)
2320  {
2321  if (braille_line != -1)
2322  {
2324  braille_line = -1;
2325  }
2326  }
2327  else
2329 
2330  mutt_refresh();
2331 
2332  if (IsEmail(extra) && (OldEmail == extra->email) && (TopLine != rd.topline) &&
2333  (rd.line_info[rd.curline].offset < (rd.sb.st_size - 1)))
2334  {
2335  if ((TopLine - rd.topline) > rd.lines)
2336  rd.topline += rd.lines;
2337  else
2338  rd.topline = TopLine;
2339  continue;
2340  }
2341  else
2342  OldEmail = NULL;
2343 
2344  ch = km_dokey(MENU_PAGER);
2345  if (ch >= 0)
2346  {
2347  mutt_clear_error();
2348  }
2350 
2351  bool do_new_mail = false;
2352 
2353  if (Context && Context->mailbox && !OptAttachMsg)
2354  {
2355  int index_hint = 0; /* used to restore cursor position */
2356  int oldcount = Context->mailbox->msg_count;
2357  /* check for new mail */
2358  int check = mx_mbox_check(Context->mailbox, &index_hint);
2359  if (check < 0)
2360  {
2362  {
2363  /* fatal error occurred */
2364  ctx_free(&Context);
2365  pager_menu->redraw = REDRAW_FULL;
2366  break;
2367  }
2368  }
2369  else if ((check == MUTT_NEW_MAIL) || (check == MUTT_REOPENED) || (check == MUTT_FLAGS))
2370  {
2371  /* notify user of newly arrived mail */
2372  if (check == MUTT_NEW_MAIL)
2373  {
2374  for (size_t i = oldcount; i < Context->mailbox->msg_count; i++)
2375  {
2376  struct Email *e = Context->mailbox->emails[i];
2377 
2378  if (e && !e->read)
2379  {
2380  mutt_message(_("New mail in this mailbox"));
2381  do_new_mail = true;
2382  break;
2383  }
2384  }
2385  }
2386 
2387  if ((check == MUTT_NEW_MAIL) || (check == MUTT_REOPENED))
2388  {
2389  if (rd.menu && Context && Context->mailbox)
2390  {
2391  /* After the mailbox has been updated,
2392  * rd.menu->current might be invalid */
2393  rd.menu->current =
2394  MIN(rd.menu->current, MAX(Context->mailbox->msg_count - 1, 0));
2395  struct Email *e = mutt_get_virt_email(Context->mailbox, rd.menu->current);
2396  if (!e)
2397  continue;
2398 
2399  index_hint = e->index;
2400 
2401  bool q = Context->mailbox->quiet;
2402  Context->mailbox->quiet = true;
2403  update_index(rd.menu, Context, check, oldcount, index_hint);
2404  Context->mailbox->quiet = q;
2405 
2406  rd.menu->max = Context->mailbox->vcount;
2407 
2408  /* If these header pointers don't match, then our email may have
2409  * been deleted. Make the pointer safe, then leave the pager.
2410  * This have a unpleasant behaviour to close the pager even the
2411  * deleted message is not the opened one, but at least it's safe. */
2413  if (extra->email != e)
2414  {
2415  extra->email = e;
2416  break;
2417  }
2418  }
2419 
2420  pager_menu->redraw = REDRAW_FULL;
2421  OptSearchInvalid = true;
2422  }
2423  }
2424 
2425  if (mutt_mailbox_notify(Context ? Context->mailbox : NULL) || do_new_mail)
2426  {
2427  if (C_BeepNew)
2428  mutt_beep(true);
2429  if (C_NewMailCommand)
2430  {
2431  char cmd[1024];
2432  menu_status_line(cmd, sizeof(cmd), rd.menu, NONULL(C_NewMailCommand));
2433  if (mutt_system(cmd) != 0)
2434  mutt_error(_("Error running \"%s\""), cmd);
2435  }
2436  }
2437  }
2438 
2439  if (SigWinch)
2440  {
2441  SigWinch = 0;
2443  clearok(stdscr, true); /* force complete redraw */
2444 
2445  if (flags & MUTT_PAGER_RETWINCH)
2446  {
2447  /* Store current position. */
2448  rd.lines = -1;
2449  for (size_t i = 0; i <= rd.topline; i++)
2450  if (!rd.line_info[i].continuation)
2451  rd.lines++;
2452 
2453  Resize = mutt_mem_malloc(sizeof(struct Resize));
2454 
2455  Resize->line = rd.lines;
2458 
2459  ch = -1;
2460  rc = OP_REFORMAT_WINCH;
2461  }
2462  else
2463  {
2464  /* note: mutt_resize_screen() -> mutt_window_reflow() sets
2465  * REDRAW_FULL and REDRAW_FLOW */
2466  ch = 0;
2467  }
2468  continue;
2469  }
2470 
2471  if (ch < 0)
2472  {
2473  ch = 0;
2475  continue;
2476  }
2477 
2478  rc = ch;
2479 
2480  switch (ch)
2481  {
2482  case OP_EXIT:
2483  rc = -1;
2484  ch = -1;
2485  break;
2486 
2487  case OP_QUIT:
2488  if (query_quadoption(C_Quit, _("Quit NeoMutt?")) == MUTT_YES)
2489  {
2490  /* avoid prompting again in the index menu */
2491  cs_subset_str_native_set(NeoMutt->sub, "quit", MUTT_YES, NULL);
2492  ch = -1;
2493  }
2494  break;
2495 
2496  case OP_NEXT_PAGE:
2497  if (rd.line_info[rd.curline].offset < (rd.sb.st_size - 1))
2498  {
2500  }
2501  else if (C_PagerStop)
2502  {
2503  /* emulate "less -q" and don't go on to the next message. */
2504  mutt_error(_("Bottom of message is shown"));
2505  }
2506  else
2507  {
2508  /* end of the current message, so display the next message. */
2509  rc = OP_MAIN_NEXT_UNDELETED;
2510  ch = -1;
2511  }
2512  break;
2513 
2514  case OP_PREV_PAGE:
2515  if (rd.topline == 0)
2516  {
2517  mutt_message(_("Top of message is shown"));
2518  }
2519  else
2520  {
2522  rd.line_info, rd.topline, rd.hide_quoted);
2523  }
2524  break;
2525 
2526  case OP_NEXT_LINE:
2527  if (rd.line_info[rd.curline].offset < (rd.sb.st_size - 1))
2528  {
2529  rd.topline++;
2530  if (rd.hide_quoted)
2531  {
2532  while ((rd.line_info[rd.topline].type == MT_COLOR_QUOTED) &&
2533  (rd.topline < rd.last_line))
2534  {
2535  rd.topline++;
2536  }
2537  }
2538  }
2539  else
2540  mutt_message(_("Bottom of message is shown"));
2541  break;
2542 
2543  case OP_PREV_LINE:
2544  if (rd.topline)
2545  rd.topline = up_n_lines(1, rd.line_info, rd.topline, rd.hide_quoted);
2546  else
2547  mutt_error(_("Top of message is shown"));
2548  break;
2549 
2550  case OP_PAGER_TOP:
2551  if (rd.topline)
2552  rd.topline = 0;
2553  else
2554  mutt_error(_("Top of message is shown"));
2555  break;
2556 
2557  case OP_HALF_UP:
2558  if (rd.topline)
2559  {
2560  rd.topline = up_n_lines(rd.extra->win_pager->state.rows / 2 +
2561  (rd.extra->win_pager->state.rows % 2),
2562  rd.line_info, rd.topline, rd.hide_quoted);
2563  }
2564  else
2565  mutt_error(_("Top of message is shown"));
2566  break;
2567 
2568  case OP_HALF_DOWN:
2569  if (rd.line_info[rd.curline].offset < (rd.sb.st_size - 1))
2570  {
2571  rd.topline = up_n_lines(rd.extra->win_pager->state.rows / 2,
2572  rd.line_info, rd.curline, rd.hide_quoted);
2573  }
2574  else if (C_PagerStop)
2575  {
2576  /* emulate "less -q" and don't go on to the next message. */
2577  mutt_error(_("Bottom of message is shown"));
2578  }
2579  else
2580  {
2581  /* end of the current message, so display the next message. */
2582  rc = OP_MAIN_NEXT_UNDELETED;
2583  ch = -1;
2584  }
2585  break;
2586 
2587  case OP_SEARCH_NEXT:
2588  case OP_SEARCH_OPPOSITE:
2589  if (rd.search_compiled)
2590  {
2591  wrapped = false;
2592 
2593  if (C_SearchContext < rd.extra->win_pager->state.rows)
2594  searchctx = C_SearchContext;
2595  else
2596  searchctx = 0;
2597 
2598  search_next:
2599  if ((!rd.search_back && (ch == OP_SEARCH_NEXT)) ||
2600  (rd.search_back && (ch == OP_SEARCH_OPPOSITE)))
2601  {
2602  /* searching forward */
2603  int i;
2604  for (i = wrapped ? 0 : rd.topline + searchctx + 1; i < rd.last_line; i++)
2605  {
2606  if ((!rd.hide_quoted || (rd.line_info[i].type != MT_COLOR_QUOTED)) &&
2607  !rd.line_info[i].continuation && (rd.line_info[i].search_cnt > 0))
2608  {
2609  break;
2610  }
2611  }
2612 
2613  if (i < rd.last_line)
2614  rd.topline = i;
2615  else if (wrapped || !C_WrapSearch)
2616  mutt_error(_("Not found"));
2617  else
2618  {
2619  mutt_message(_("Search wrapped to top"));
2620  wrapped = true;
2621  goto search_next;
2622  }
2623  }
2624  else
2625  {
2626  /* searching backward */
2627  int i;
2628  for (i = wrapped ? rd.last_line : rd.topline + searchctx - 1; i >= 0; i--)
2629  {
2630  if ((!rd.hide_quoted ||
2631  (rd.has_types && (rd.line_info[i].type != MT_COLOR_QUOTED))) &&
2632  !rd.line_info[i].continuation && (rd.line_info[i].search_cnt > 0))
2633  {
2634  break;
2635  }
2636  }
2637 
2638  if (i >= 0)
2639  rd.topline = i;
2640  else if (wrapped || !C_WrapSearch)
2641  mutt_error(_("Not found"));
2642  else
2643  {
2644  mutt_message(_("Search wrapped to bottom"));
2645  wrapped = true;
2646  goto search_next;
2647  }
2648  }
2649 
2650  if (rd.line_info[rd.topline].search_cnt > 0)
2651  {
2652  rd.search_flag = MUTT_SEARCH;
2653  /* give some context for search results */
2654  if (rd.topline - searchctx > 0)
2655  rd.topline -= searchctx;
2656  }
2657 
2658  break;
2659  }
2660  /* no previous search pattern */
2661  /* fallthrough */
2662 
2663  case OP_SEARCH:
2664  case OP_SEARCH_REVERSE:
2665  mutt_str_strfcpy(buf, searchbuf, sizeof(buf));
2666  if (mutt_get_field(((ch == OP_SEARCH) || (ch == OP_SEARCH_NEXT)) ?
2667  _("Search for: ") :
2668  _("Reverse search for: "),
2669  buf, sizeof(buf), MUTT_CLEAR) != 0)
2670  {
2671  break;
2672  }
2673 
2674  if (strcmp(buf, searchbuf) == 0)
2675  {
2676  if (rd.search_compiled)
2677  {
2678  /* do an implicit search-next */
2679  if (ch == OP_SEARCH)
2680  ch = OP_SEARCH_NEXT;
2681  else
2682  ch = OP_SEARCH_OPPOSITE;
2683 
2684  wrapped = false;
2685  goto search_next;
2686  }
2687  }
2688 
2689  if (buf[0] == '\0')
2690  break;
2691 
2692  mutt_str_strfcpy(searchbuf, buf, sizeof(searchbuf));
2693 
2694  /* leave search_back alone if ch == OP_SEARCH_NEXT */
2695  if (ch == OP_SEARCH)
2696  rd.search_back = false;
2697  else if (ch == OP_SEARCH_REVERSE)
2698  rd.search_back = true;
2699 
2700  if (rd.search_compiled)
2701  {
2702  regfree(&rd.search_re);
2703  for (size_t i = 0; i < rd.last_line; i++)
2704  {
2705  FREE(&(rd.line_info[i].search));
2706  rd.line_info[i].search_cnt = -1;
2707  }
2708  }
2709 
2710  int rflags = mutt_mb_is_lower(searchbuf) ? REG_ICASE : 0;
2711  int err = REG_COMP(&rd.search_re, searchbuf, REG_NEWLINE | rflags);
2712  if (err != 0)
2713  {
2714  regerror(err, &rd.search_re, buf, sizeof(buf));
2715  mutt_error("%s", buf);
2716  for (size_t i = 0; i < rd.max_line; i++)
2717  {
2718  /* cleanup */
2719  FREE(&(rd.line_info[i].search));
2720  rd.line_info[i].search_cnt = -1;
2721  }
2722  rd.search_flag = 0;
2723  rd.search_compiled = false;
2724  }
2725  else
2726  {
2727  rd.search_compiled = true;
2728  /* update the search pointers */
2729  int line_num = 0;
2730  while (display_line(rd.fp, &rd.last_pos, &rd.line_info, line_num,
2731  &rd.last_line, &rd.max_line,
2732  MUTT_SEARCH | (flags & MUTT_PAGER_NSKIP) | (flags & MUTT_PAGER_NOWRAP),
2733  &rd.quote_list, &rd.q_level, &rd.force_redraw,
2734  &rd.search_re, rd.extra->win_pager) == 0)
2735  {
2736  line_num++;
2737  }
2738 
2739  if (!rd.search_back)
2740  {
2741  /* searching forward */
2742  int i;
2743  for (i = rd.topline; i < rd.last_line; i++)
2744  {
2745  if ((!rd.hide_quoted || (rd.line_info[i].type != MT_COLOR_QUOTED)) &&
2746  !rd.line_info[i].continuation && (rd.line_info[i].search_cnt > 0))
2747  {
2748  break;
2749  }
2750  }
2751 
2752  if (i < rd.last_line)
2753  rd.topline = i;
2754  }
2755  else
2756  {
2757  /* searching backward */
2758  int i;
2759  for (i = rd.topline; i >= 0; i--)
2760  {
2761  if ((!rd.hide_quoted || (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  }
2771 
2772  if (rd.line_info[rd.topline].search_cnt == 0)
2773  {
2774  rd.search_flag = 0;
2775  mutt_error(_("Not found"));
2776  }
2777  else
2778  {
2779  rd.search_flag = MUTT_SEARCH;
2780  /* give some context for search results */
2781  if (C_SearchContext < rd.extra->win_pager->state.rows)
2782  searchctx = C_SearchContext;
2783  else
2784  searchctx = 0;
2785  if (rd.topline - searchctx > 0)
2786  rd.topline -= searchctx;
2787  }
2788  }
2789  pager_menu->redraw = REDRAW_BODY;
2790  break;
2791 
2792  case OP_SEARCH_TOGGLE:
2793  if (rd.search_compiled)
2794  {
2795  rd.search_flag ^= MUTT_SEARCH;
2796  pager_menu->redraw = REDRAW_BODY;
2797  }
2798  break;
2799 
2800  case OP_SORT:
2801  case OP_SORT_REVERSE:
2802  CHECK_MODE(IsEmail(extra))
2803  if (mutt_select_sort((ch == OP_SORT_REVERSE)) == 0)
2804  {
2805  OptNeedResort = true;
2806  ch = -1;
2807  rc = OP_DISPLAY_MESSAGE;
2808  }
2809  break;
2810 
2811  case OP_HELP:
2812  if (InHelp)
2813  {
2814  /* don't let the user enter the help-menu from the help screen! */
2815  mutt_error(_("Help is currently being shown"));
2816  break;
2817  }
2818 
2819  InHelp = true;
2820  mutt_help(MENU_PAGER, pager_menu->win_index->state.cols);
2821  pager_menu->redraw = REDRAW_FULL;
2822  InHelp = false;
2823  break;
2824 
2825  case OP_PAGER_HIDE_QUOTED:
2826  if (!rd.has_types)
2827  break;
2828 
2829  rd.hide_quoted ^= MUTT_HIDE;
2830  if (rd.hide_quoted && (rd.line_info[rd.topline].type == MT_COLOR_QUOTED))
2831  rd.topline = up_n_lines(1, rd.line_info, rd.topline, rd.hide_quoted);
2832  else
2833  pager_menu->redraw = REDRAW_BODY;
2834  break;
2835 
2836  case OP_PAGER_SKIP_QUOTED:
2837  if (!rd.has_types)
2838  break;
2839 
2840  int dretval = 0;
2841  int new_topline = rd.topline;
2842 
2843  /* Skip all the email headers */
2844  if (IS_HEADER(rd.line_info[new_topline].type))
2845  {
2846  while (((new_topline < rd.last_line) ||
2847  (0 == (dretval = display_line(
2848  rd.fp, &rd.last_pos, &rd.line_info, new_topline, &rd.last_line,
2849  &rd.max_line, MUTT_TYPES | (flags & MUTT_PAGER_NOWRAP),
2850  &rd.quote_list, &rd.q_level, &rd.force_redraw,
2851  &rd.search_re, rd.extra->win_pager)))) &&
2852  IS_HEADER(rd.line_info[new_topline].type))
2853  {
2854  new_topline++;
2855  }
2856  rd.topline = new_topline;
2857  break;
2858  }
2859 
2860  while ((((new_topline + C_SkipQuotedOffset) < rd.last_line) ||
2861  (0 == (dretval = display_line(
2862  rd.fp, &rd.last_pos, &rd.line_info, new_topline, &rd.last_line,
2863  &rd.max_line, MUTT_TYPES | (flags & MUTT_PAGER_NOWRAP),
2864  &rd.quote_list, &rd.q_level, &rd.force_redraw,
2865  &rd.search_re, rd.extra->win_pager)))) &&
2866  (rd.line_info[new_topline + C_SkipQuotedOffset].type != MT_COLOR_QUOTED))
2867  {
2868  new_topline++;
2869  }
2870 
2871  if (dretval < 0)
2872  {
2873  mutt_error(_("No more quoted text"));
2874  break;
2875  }
2876 
2877  while ((((new_topline + C_SkipQuotedOffset) < rd.last_line) ||
2878  (0 == (dretval = display_line(
2879  rd.fp, &rd.last_pos, &rd.line_info, new_topline, &rd.last_line,
2880  &rd.max_line, MUTT_TYPES | (flags & MUTT_PAGER_NOWRAP),
2881  &rd.quote_list, &rd.q_level, &rd.force_redraw,
2882  &rd.search_re, rd.extra->win_pager)))) &&
2883  (rd.line_info[new_topline + C_SkipQuotedOffset].type == MT_COLOR_QUOTED))
2884  {
2885  new_topline++;
2886  }
2887 
2888  if (dretval < 0)
2889  {
2890  mutt_error(_("No more unquoted text after quoted text"));
2891  break;
2892  }
2893  rd.topline = new_topline;
2894  break;
2895 
2896  case OP_PAGER_BOTTOM: /* move to the end of the file */
2897  if (rd.line_info[rd.curline].offset < (rd.sb.st_size - 1))
2898  {
2899  int line_num = rd.curline;
2900  /* make sure the types are defined to the end of file */
2901  while (display_line(rd.fp, &rd.last_pos, &rd.line_info, line_num, &rd.last_line,
2902  &rd.max_line, rd.has_types | (flags & MUTT_PAGER_NOWRAP),
2903  &rd.quote_list, &rd.q_level, &rd.force_redraw,
2904  &rd.search_re, rd.extra->win_pager) == 0)
2905  {
2906  line_num++;
2907  }
2909  rd.last_line, rd.hide_quoted);
2910  }
2911  else
2912  mutt_error(_("Bottom of message is shown"));
2913  break;
2914 
2915  case OP_REDRAW:
2916  mutt_window_reflow(NULL);
2917  clearok(stdscr, true);
2918  pager_menu->redraw = REDRAW_FULL;
2919  break;
2920 
2921  case OP_NULL:
2923  break;
2924 
2925  /* --------------------------------------------------------------------
2926  * The following are operations on the current message rather than
2927  * adjusting the view of the message. */
2928 
2929  case OP_BOUNCE_MESSAGE:
2930  {
2931  struct Mailbox *m = Context ? Context->mailbox : NULL;
2932  CHECK_MODE(IsEmail(extra) || IsMsgAttach(extra))
2933  CHECK_ATTACH;
2934  if (IsMsgAttach(extra))
2935  mutt_attach_bounce(m, extra->fp, extra->actx, extra->body);
2936  else
2937  {
2938  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
2939  emaillist_add_email(&el, extra->email);
2940  ci_bounce_message(m, &el);
2941  emaillist_clear(&el);
2942  }
2943  break;
2944  }
2945 
2946  case OP_RESEND:
2947  CHECK_MODE(IsEmail(extra) || IsMsgAttach(extra))
2948  CHECK_ATTACH;
2949  if (IsMsgAttach(extra))
2950  mutt_attach_resend(extra->fp, extra->actx, extra->body);
2951  else
2952  mutt_resend_message(NULL, extra->ctx, extra->email);
2953  pager_menu->redraw = REDRAW_FULL;
2954  break;
2955 
2956  case OP_COMPOSE_TO_SENDER:
2957  CHECK_MODE(IsEmail(extra) || IsMsgAttach(extra));
2958  CHECK_ATTACH;
2959  if (IsMsgAttach(extra))
2960  mutt_attach_mail_sender(extra->fp, extra->email, extra->actx, extra->body);
2961  else
2962  {
2963  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
2964  emaillist_add_email(&el, extra->email);
2965  ci_send_message(SEND_TO_SENDER, NULL, NULL, extra->ctx, &el);
2966  emaillist_clear(&el);
2967  }
2968  pager_menu->redraw = REDRAW_FULL;
2969  break;
2970 
2971  case OP_CHECK_TRADITIONAL:
2972  CHECK_MODE(IsEmail(extra));
2973  if (!(WithCrypto & APPLICATION_PGP))
2974  break;
2975  if (!(extra->email->security & PGP_TRADITIONAL_CHECKED))
2976  {
2977  ch = -1;
2978  rc = OP_CHECK_TRADITIONAL;
2979  }
2980  break;
2981 
2982  case OP_CREATE_ALIAS:
2983  CHECK_MODE(IsEmail(extra) || IsMsgAttach(extra));
2984  if (IsMsgAttach(extra))
2985  mutt_alias_create(extra->body->email->env, NULL);
2986  else
2987  mutt_alias_create(extra->email->env, NULL);
2988  break;
2989 
2990  case OP_PURGE_MESSAGE:
2991  case OP_DELETE:
2992  CHECK_MODE(IsEmail(extra));
2994  /* L10N: CHECK_ACL */
2995  CHECK_ACL(MUTT_ACL_DELETE, _("Can't delete message"));
2996 
2997  mutt_set_flag(Context->mailbox, extra->email, MUTT_DELETE, true);
2998  mutt_set_flag(Context->mailbox, extra->email, MUTT_PURGE, (ch == OP_PURGE_MESSAGE));
2999  if (C_DeleteUntag)
3000  mutt_set_flag(Context->mailbox, extra->email, MUTT_TAG, false);
3001  pager_menu->redraw |= REDRAW_STATUS | REDRAW_INDEX;
3002  if (C_Resolve)
3003  {
3004  ch = -1;
3005  rc = OP_MAIN_NEXT_UNDELETED;
3006  }
3007  break;
3008 
3009  case OP_MAIN_SET_FLAG:
3010  case OP_MAIN_CLEAR_FLAG:
3011  {
3012  CHECK_MODE(IsEmail(extra));
3014 
3015  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3016  emaillist_add_email(&el, extra->email);
3017 
3018  if (mutt_change_flag(Context->mailbox, &el, (ch == OP_MAIN_SET_FLAG)) == 0)
3019  pager_menu->redraw |= REDRAW_STATUS | REDRAW_INDEX;
3020  if (extra->email->deleted && C_Resolve)
3021  {
3022  ch = -1;
3023  rc = OP_MAIN_NEXT_UNDELETED;
3024  }
3025  emaillist_clear(&el);
3026  break;
3027  }
3028 
3029  case OP_DELETE_THREAD:
3030  case OP_DELETE_SUBTHREAD:
3031  case OP_PURGE_THREAD:
3032  {
3033  CHECK_MODE(IsEmail(extra));
3035  /* L10N: CHECK_ACL */
3036  /* L10N: Due to the implementation details we do not know whether we
3037  delete zero, 1, 12, ... messages. So in English we use
3038  "messages". Your language might have other means to express this. */
3039  CHECK_ACL(MUTT_ACL_DELETE, _("Can't delete messages"));
3040 
3041  int subthread = (ch == OP_DELETE_SUBTHREAD);
3042  int r = mutt_thread_set_flag(extra->email, MUTT_DELETE, 1, subthread);
3043  if (r == -1)
3044  break;
3045  if (ch == OP_PURGE_THREAD)
3046  {
3047  r = mutt_thread_set_flag(extra->email, MUTT_PURGE, true, subthread);
3048  if (r == -1)
3049  break;
3050  }
3051 
3052  if (C_DeleteUntag)
3053  mutt_thread_set_flag(extra->email, MUTT_TAG, 0, subthread);
3054  if (C_Resolve)
3055  {
3056  rc = OP_MAIN_NEXT_UNDELETED;
3057  ch = -1;
3058  }
3059 
3060  if (!C_Resolve && (C_PagerIndexLines != 0))
3061  pager_menu->redraw = REDRAW_FULL;
3062  else
3063  pager_menu->redraw |= REDRAW_STATUS | REDRAW_INDEX;
3064 
3065  break;
3066  }
3067 
3068  case OP_DISPLAY_ADDRESS:
3069  CHECK_MODE(IsEmail(extra) || IsMsgAttach(extra));
3070  if (IsMsgAttach(extra))
3071  mutt_display_address(extra->body->email->env);
3072  else
3073  mutt_display_address(extra->email->env);
3074  break;
3075 
3076  case OP_ENTER_COMMAND:
3077  old_PagerIndexLines = C_PagerIndexLines;
3078 
3080  pager_menu->redraw = REDRAW_FULL;
3081 
3082  if (OptNeedResort)
3083  {
3084  OptNeedResort = false;
3085  CHECK_MODE(IsEmail(extra));
3086  OptNeedResort = true;
3087  }
3088 
3089  if (old_PagerIndexLines != C_PagerIndexLines)
3090  {
3091  mutt_menu_free(&rd.menu);
3092  }
3093 
3094  if ((pager_menu->redraw & REDRAW_FLOW) && (flags & MUTT_PAGER_RETWINCH))
3095  {
3096  ch = -1;
3097  rc = OP_REFORMAT_WINCH;
3098  continue;
3099  }
3100 
3101  ch = 0;
3102  break;
3103 
3104  case OP_FLAG_MESSAGE:
3105  CHECK_MODE(IsEmail(extra));
3107  /* L10N: CHECK_ACL */
3108  CHECK_ACL(MUTT_ACL_WRITE, "Can't flag message");
3109 
3110  mutt_set_flag(Context->mailbox, extra->email, MUTT_FLAG, !extra->email->flagged);
3111  pager_menu->redraw |= REDRAW_STATUS | REDRAW_INDEX;
3112  if (C_Resolve)
3113  {
3114  ch = -1;
3115  rc = OP_MAIN_NEXT_UNDELETED;
3116  }
3117  break;
3118 
3119  case OP_PIPE:
3120  CHECK_MODE(IsEmail(extra) || IsAttach(extra));
3121  if (IsAttach(extra))
3122  mutt_pipe_attachment_list(extra->actx, extra->fp, false, extra->body, false);
3123  else
3124  {
3125  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3126  el_add_tagged(&el, extra->ctx, extra->email, false);
3127  mutt_pipe_message(extra->ctx->mailbox, &el);
3128  emaillist_clear(&el);
3129  }
3130  break;
3131 
3132  case OP_PRINT:
3133  CHECK_MODE(IsEmail(extra) || IsAttach(extra));
3134  if (IsAttach(extra))
3135  mutt_print_attachment_list(extra->actx, extra->fp, false, extra->body);
3136  else
3137  {
3138  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3139  el_add_tagged(&el, extra->ctx, extra->email, false);
3140  mutt_print_message(extra->ctx->mailbox, &el);
3141  emaillist_clear(&el);
3142  }
3143  break;
3144 
3145  case OP_MAIL:
3146  CHECK_MODE(IsEmail(extra) && !IsAttach(extra));
3147  CHECK_ATTACH;
3148  ci_send_message(SEND_NO_FLAGS, NULL, NULL, extra->ctx, NULL);
3149  pager_menu->redraw = REDRAW_FULL;
3150  break;
3151 
3152 #ifdef USE_NNTP
3153  case OP_POST:
3154  CHECK_MODE(IsEmail(extra) && !IsAttach(extra));
3155  CHECK_ATTACH;
3156  if (extra->ctx && (extra->ctx->mailbox->type == MUTT_NNTP) &&
3157  !((struct NntpMboxData *) extra->ctx->mailbox->mdata)->allowed && (query_quadoption(C_PostModerated, _("Posting to this group not allowed, may be moderated. Continue?")) != MUTT_YES))
3158  {
3159  break;
3160  }
3161  ci_send_message(SEND_NEWS, NULL, NULL, extra->ctx, NULL);
3162  pager_menu->redraw = REDRAW_FULL;
3163  break;
3164 
3165  case OP_FORWARD_TO_GROUP:
3166  CHECK_MODE(IsEmail(extra) || IsMsgAttach(extra));
3167  CHECK_ATTACH;
3168  if (extra->ctx && (extra->ctx->mailbox->type == MUTT_NNTP) &&
3169  !((struct NntpMboxData *) extra->ctx->mailbox->mdata)->allowed && (query_quadoption(C_PostModerated, _("Posting to this group not allowed, may be moderated. Continue?")) != MUTT_YES))
3170  {
3171  break;
3172  }
3173  if (IsMsgAttach(extra))
3174  mutt_attach_forward(extra->fp, extra->email, extra->actx, extra->body, SEND_NEWS);
3175  else
3176  {
3177  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3178  emaillist_add_email(&el, extra->email);
3179  ci_send_message(SEND_NEWS | SEND_FORWARD, NULL, NULL, extra->ctx, &el);
3180  emaillist_clear(&el);
3181  }
3182  pager_menu->redraw = REDRAW_FULL;
3183  break;
3184 
3185  case OP_FOLLOWUP:
3186  CHECK_MODE(IsEmail(extra) || IsMsgAttach(extra));
3187  CHECK_ATTACH;
3188 
3189  if (IsMsgAttach(extra))
3190  followup_to = extra->body->email->env->followup_to;
3191  else
3192  followup_to = extra->email->env->followup_to;
3193 
3194  if (!followup_to || (mutt_str_strcasecmp(followup_to, "poster") != 0) ||
3196  _("Reply by mail as poster prefers?")) != MUTT_YES))
3197  {
3198  if (extra->ctx && (extra->ctx->mailbox->type == MUTT_NNTP) &&
3199  !((struct NntpMboxData *) extra->ctx->mailbox->mdata)->allowed && (query_quadoption(C_PostModerated, _("Posting to this group not allowed, may be moderated. Continue?")) != MUTT_YES))
3200  {
3201  break;
3202  }
3203  if (IsMsgAttach(extra))
3204  {
3205  mutt_attach_reply(extra->fp, extra->email, extra->actx, extra->body,
3206  SEND_NEWS | SEND_REPLY);
3207  }
3208  else
3209  {
3210  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3211  emaillist_add_email(&el, extra->email);
3212  ci_send_message(SEND_NEWS | SEND_REPLY, NULL, NULL, extra->ctx, &el);
3213  emaillist_clear(&el);
3214  }
3215  pager_menu->redraw = REDRAW_FULL;
3216  break;
3217  }
3218 #endif
3219  /* fallthrough */
3220  case OP_REPLY:
3221  case OP_GROUP_REPLY:
3222  case OP_GROUP_CHAT_REPLY:
3223  case OP_LIST_REPLY:
3224  {
3225  CHECK_MODE(IsEmail(extra) || IsMsgAttach(extra));
3226  CHECK_ATTACH;
3227 
3228  SendFlags replyflags = SEND_REPLY;
3229  if (ch == OP_GROUP_REPLY)
3230  replyflags |= SEND_GROUP_REPLY;
3231  else if (ch == OP_GROUP_CHAT_REPLY)
3232  replyflags |= SEND_GROUP_CHAT_REPLY;
3233  else if (ch == OP_LIST_REPLY)
3234  replyflags |= SEND_LIST_REPLY;
3235 
3236  if (IsMsgAttach(extra))
3237  mutt_attach_reply(extra->fp, extra->email, extra->actx, extra->body, replyflags);
3238  else
3239  {
3240  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3241  emaillist_add_email(&el, extra->email);
3242  ci_send_message(replyflags, NULL, NULL, extra->ctx, &el);
3243  emaillist_clear(&el);
3244  }
3245  pager_menu->redraw = REDRAW_FULL;
3246  break;
3247  }
3248 
3249  case OP_RECALL_MESSAGE:
3250  {
3251  CHECK_MODE(IsEmail(extra) && !IsAttach(extra));
3252  CHECK_ATTACH;
3253  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3254  emaillist_add_email(&el, extra->email);
3255  ci_send_message(SEND_POSTPONED, NULL, NULL, extra->ctx, &el);
3256  emaillist_clear(&el);
3257  pager_menu->redraw = REDRAW_FULL;
3258  break;
3259  }
3260 
3261  case OP_FORWARD_MESSAGE:
3262  CHECK_MODE(IsEmail(extra) || IsMsgAttach(extra));
3263  CHECK_ATTACH;
3264  if (IsMsgAttach(extra))
3265  mutt_attach_forward(extra->fp, extra->email, extra->actx, extra->body, SEND_NO_FLAGS);
3266  else
3267  {
3268  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3269  emaillist_add_email(&el, extra->email);
3270  ci_send_message(SEND_FORWARD, NULL, NULL, extra->ctx, &el);
3271  emaillist_clear(&el);
3272  }
3273  pager_menu->redraw = REDRAW_FULL;
3274  break;
3275 
3276  case OP_DECRYPT_SAVE:
3277  if (!WithCrypto)
3278  {
3279  ch = -1;
3280  break;
3281  }
3282  /* fallthrough */
3283  case OP_SAVE:
3284  if (IsAttach(extra))
3285  {
3286  mutt_save_attachment_list(extra->actx, extra->fp, false, extra->body,
3287  extra->email, NULL);
3288  break;
3289  }
3290  /* fallthrough */
3291  case OP_COPY_MESSAGE:
3292  case OP_DECODE_SAVE:
3293  case OP_DECODE_COPY:
3294  case OP_DECRYPT_COPY:
3295  {
3296  if (!(WithCrypto != 0) && (ch == OP_DECRYPT_COPY))
3297  {
3298  ch = -1;
3299  break;
3300  }
3301  CHECK_MODE(IsEmail(extra));
3302  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3303  emaillist_add_email(&el, extra->email);
3304 
3305  const bool delete_original =
3306  (ch == OP_SAVE) || (ch == OP_DECODE_SAVE) || (ch == OP_DECRYPT_SAVE);
3307  const bool decode = (ch == OP_DECODE_SAVE) || (ch == OP_DECODE_COPY);
3308  const bool decrypt = (ch == OP_DECRYPT_SAVE) || (ch == OP_DECRYPT_COPY);
3309 
3310  if ((mutt_save_message(Context->mailbox, &el, delete_original, decode, decrypt) == 0) &&
3311  delete_original)
3312  {
3313  if (C_Resolve)
3314  {
3315  ch = -1;
3316  rc = OP_MAIN_NEXT_UNDELETED;
3317  }
3318  else
3319  pager_menu->redraw |= REDRAW_STATUS | REDRAW_INDEX;
3320  }
3321  emaillist_clear(&el);
3322  break;
3323  }
3324 
3325  case OP_SHELL_ESCAPE:
3327  break;
3328 
3329  case OP_TAG:
3330  CHECK_MODE(IsEmail(extra));
3331  if (Context)
3332  {
3333  mutt_set_flag(Context->mailbox, extra->email, MUTT_TAG, !extra->email->tagged);
3334 
3335  Context->last_tag =
3336  extra->email->tagged ?
3337  extra->email :
3338  ((Context->last_tag == extra->email && !extra->email->tagged) ?
3339  NULL :
3340  Context->last_tag);
3341  }
3342 
3343  pager_menu->redraw |= REDRAW_STATUS | REDRAW_INDEX;
3344  if (C_Resolve)
3345  {
3346  ch = -1;
3347  rc = OP_NEXT_ENTRY;
3348  }
3349  break;
3350 
3351  case OP_TOGGLE_NEW:
3352  CHECK_MODE(IsEmail(extra));
3354  /* L10N: CHECK_ACL */
3355  CHECK_ACL(MUTT_ACL_SEEN, _("Can't toggle new"));
3356 
3357  if (extra->email->read || extra->email->old)
3358  mutt_set_flag(Context->mailbox, extra->email, MUTT_NEW, true);
3359  else if (!first)
3360  mutt_set_flag(Context->mailbox, extra->email, MUTT_READ, true);
3361  first = false;
3362  Context->msg_not_read_yet = -1;
3363  pager_menu->redraw |= REDRAW_STATUS | REDRAW_INDEX;
3364  if (C_Resolve)
3365  {
3366  ch = -1;
3367  rc = OP_MAIN_NEXT_UNDELETED;
3368  }
3369  break;
3370 
3371  case OP_UNDELETE:
3372  CHECK_MODE(IsEmail(extra));
3374  /* L10N: CHECK_ACL */
3375  CHECK_ACL(MUTT_ACL_DELETE, _("Can't undelete message"));
3376 
3377  mutt_set_flag(Context->mailbox, extra->email, MUTT_DELETE, false);
3378  mutt_set_flag(Context->mailbox, extra->email, MUTT_PURGE, false);
3379  pager_menu->redraw |= REDRAW_STATUS | REDRAW_INDEX;
3380  if (C_Resolve)
3381  {
3382  ch = -1;
3383  rc = OP_NEXT_ENTRY;
3384  }
3385  break;
3386 
3387  case OP_UNDELETE_THREAD:
3388  case OP_UNDELETE_SUBTHREAD:
3389  {
3390  CHECK_MODE(IsEmail(extra));
3392  /* L10N: CHECK_ACL */
3393  /* L10N: Due to the implementation details we do not know whether we
3394  undelete zero, 1, 12, ... messages. So in English we use
3395  "messages". Your language might have other means to express this. */
3396  CHECK_ACL(MUTT_ACL_DELETE, _("Can't undelete messages"));
3397 
3398  int r = mutt_thread_set_flag(extra->email, MUTT_DELETE, false,
3399  (ch != OP_UNDELETE_THREAD));
3400  if (r != -1)
3401  {
3402  r = mutt_thread_set_flag(extra->email, MUTT_PURGE, false,
3403  (ch != OP_UNDELETE_THREAD));
3404  }
3405  if (r != -1)
3406  {
3407  if (C_Resolve)
3408  {
3409  rc = (ch == OP_DELETE_THREAD) ? OP_MAIN_NEXT_THREAD : OP_MAIN_NEXT_SUBTHREAD;
3410  ch = -1;
3411  }
3412 
3413  if (!C_Resolve && (C_PagerIndexLines != 0))
3414  pager_menu->redraw = REDRAW_FULL;
3415  else
3416  pager_menu->redraw |= REDRAW_STATUS | REDRAW_INDEX;
3417  }
3418  break;
3419  }
3420 
3421  case OP_VERSION:
3423  break;
3424 
3425  case OP_MAILBOX_LIST:
3427  break;
3428 
3429  case OP_VIEW_ATTACHMENTS:
3430  if (flags & MUTT_PAGER_ATTACHMENT)
3431  {
3432  ch = -1;
3433  rc = OP_ATTACH_COLLAPSE;
3434  break;
3435  }
3436  CHECK_MODE(IsEmail(extra));
3437  mutt_view_attachments(extra->email);
3438  if (Context && extra->email->attach_del)
3439  Context->mailbox->changed = true;
3440  pager_menu->redraw = REDRAW_FULL;
3441  break;
3442 
3443  case OP_MAIL_KEY:
3444  {
3445  if (!(WithCrypto & APPLICATION_PGP))
3446  {
3447  ch = -1;
3448  break;
3449  }
3450  CHECK_MODE(IsEmail(extra));
3451  CHECK_ATTACH;
3452  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3453  emaillist_add_email(&el, extra->email);
3454  ci_send_message(SEND_KEY, NULL, NULL, extra->ctx, &el);
3455  emaillist_clear(&el);
3456  pager_menu->redraw = REDRAW_FULL;
3457  break;
3458  }
3459 
3460  case OP_EDIT_LABEL:
3461  {
3462  CHECK_MODE(IsEmail(extra));
3463 
3464  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3465  emaillist_add_email(&el, extra->email);
3466  rc = mutt_label_message(Context->mailbox, &el);
3467  emaillist_clear(&el);
3468 
3469  if (rc > 0)
3470  {
3471  Context->mailbox->changed = true;
3472  pager_menu->redraw = REDRAW_FULL;
3473  mutt_message(ngettext("%d label changed", "%d labels changed", rc), rc);
3474  }
3475  else
3476  {
3477  mutt_message(_("No labels changed"));
3478  }
3479  break;
3480  }
3481 
3482  case OP_FORGET_PASSPHRASE:
3484  break;
3485 
3486  case OP_EXTRACT_KEYS:
3487  {
3488  if (!WithCrypto)
3489  {
3490  ch = -1;
3491  break;
3492  }
3493  CHECK_MODE(IsEmail(extra));
3494  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3495  emaillist_add_email(&el, extra->email);
3497  emaillist_clear(&el);
3498  pager_menu->redraw = REDRAW_FULL;
3499  break;
3500  }
3501 
3502  case OP_WHAT_KEY:
3503  mutt_what_key();
3504  break;
3505 
3506  case OP_CHECK_STATS:
3507  mutt_check_stats();
3508  break;
3509 
3510 #ifdef USE_SIDEBAR
3511  case OP_SIDEBAR_NEXT:
3512  case OP_SIDEBAR_NEXT_NEW:
3513  case OP_SIDEBAR_PAGE_DOWN:
3514  case OP_SIDEBAR_PAGE_UP:
3515  case OP_SIDEBAR_PREV:
3516  case OP_SIDEBAR_PREV_NEW:
3518  break;
3519 
3520  case OP_SIDEBAR_TOGGLE_VISIBLE:
3521  bool_str_toggle(NeoMutt->sub, "sidebar_visible", NULL);
3523  break;
3524 #endif
3525 
3526  default:
3527  ch = -1;
3528  break;
3529  }
3530  }
3531 
3532  mutt_file_fclose(&rd.fp);
3533  if (IsEmail(extra))
3534  {
3535  if (Context)
3536  Context->msg_not_read_yet = -1;
3537  switch (rc)
3538  {
3539  case -1:
3540  case OP_DISPLAY_HEADERS:
3542  break;
3543  default:
3544  TopLine = rd.topline;
3545  OldEmail = extra->email;
3546  break;
3547  }
3548  }
3549 
3551 
3552  for (size_t i = 0; i < rd.max_line; i++)
3553  {
3554  FREE(&(rd.line_info[i].syntax));
3555  if (rd.search_compiled && rd.line_info[i].search)
3556  FREE(&(rd.line_info[i].search));
3557  }
3558  if (rd.search_compiled)
3559  {
3560  regfree(&rd.search_re);
3561  rd.search_compiled = false;
3562  }
3563  FREE(&rd.line_info);
3564  mutt_menu_pop_current(pager_menu);
3565  mutt_menu_free(&pager_menu);
3566  mutt_menu_free(&rd.menu);
3567 
3568  mutt_buffer_dealloc(&helpstr);
3569 
3570  if (rd.extra->win_index)
3571  {
3572  rd.extra->win_index->parent->state.visible = true;
3577  }
3578  rd.extra->win_pager->parent->state.visible = false;
3580 
3581  return (rc != -1) ? rc : 0;
3582 }
int km_dokey(enum MenuType menu)
Determine what a keypress should do.
Definition: keymap.c:619
struct Menu * menu
the Pager Index (PI)
Definition: pager.c:190
struct Email ** emails
Array of Emails.
Definition: mailbox.h:99
int mutt_save_message(struct Mailbox *m, struct EmailList *el, bool delete_original, bool decode, bool decrypt)
Save an email.
Definition: commands.c:1025
The "current" mailbox.
Definition: context.h:37
void mutt_window_move_abs(int row, int col)
Move the cursor to an absolute screen position.
Definition: mutt_window.c:447
FILE * fp
Source stream.
Definition: pager.h:70
#define MUTT_TYPES
Compute line&#39;s type.
Definition: pager.h:48
struct MuttWindow * win_index
Definition: pager.h:74
int mutt_thread_set_flag(struct Email *e, int flag, bool bf, bool subthread)
Set a flag on an entire thread.
Definition: flags.c:374
#define REDRAW_FULL
Redraw everything.
Definition: mutt_menu.h:47
enum MailboxType type
Mailbox type.
Definition: mailbox.h:105
bool mutt_mailbox_list(void)
List the mailboxes with new mail.
Definition: mutt_mailbox.c:230
#define NONULL(x)
Definition: string2.h:37
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:50
int msg_count
Total number of messages.
Definition: mailbox.h:91
#define mutt_set_flag(m, e, flag, bf)
Definition: protos.h:70
#define WithCrypto
Definition: lib.h:163
short C_PagerContext
Config: Number of lines of overlap when changing pages in the pager.
Definition: pager.c:87
#define SEND_TO_SENDER
Compose new email to sender.
Definition: send.h:100
const char * banner
Definition: pager.c:195
void mutt_pipe_message(struct Mailbox *m, struct EmailList *el)
Pipe a message.
Definition: commands.c:699
The envelope/body of an email.
Definition: email.h:37
#define MUTT_CLEAR
Clear input if printable character is pressed.
Definition: mutt.h:62
struct Email * mutt_get_virt_email(struct Mailbox *m, int vnum)
Get a virtual Email.
Definition: context.c:413
PagerFlags hide_quoted
Definition: pager.c:185
#define MIN(a, b)
Definition: memory.h:31
#define mutt_perror(...)
Definition: logging.h:85
GUI selectable list of items.
Definition: mutt_menu.h:82
WHERE bool C_BeepNew
Config: Make a noise when new mail arrives.
Definition: globals.h:206
int mx_mbox_check(struct Mailbox *m, int *index_hint)
Check for new mail - Wrapper for MxOps::mbox_check()
Definition: mx.c:1104
PagerFlags search_flag
Definition: pager.c:193
&#39;NNTP&#39; (Usenet) Mailbox type
Definition: mailbox.h:52
enum QuadOption query_quadoption(enum QuadOption opt, const char *prompt)
Ask the user a quad-question.
Definition: init.c:1099
#define mutt_message(...)
Definition: logging.h:83
int emaillist_add_email(struct EmailList *el, struct Email *e)
Add an Email to a list.
Definition: email.c:144
Keep track when the pager needs redrawing.
Definition: pager.c:171
static int up_n_lines(int nlines, struct Line *info, int cur, bool hiding)
Reposition the pager&#39;s view up by n lines.
Definition: pager.c:1908
User answered &#39;Yes&#39;, or assume &#39;Yes&#39;.
Definition: quad.h:40
WHERE unsigned char C_Quit
Config: Prompt before exiting NeoMutt.
Definition: globals.h:185
void mutt_display_address(struct Envelope *env)
Display the address of a message.
Definition: commands.c:908
#define MUTT_SHOWCOLOR
Show characters in color otherwise don&#39;t show characters.
Definition: pager.h:45
#define REDRAW_FLOW
Used by pager to reflow text.
Definition: mutt_menu.h:49
WHERE unsigned char C_FollowupToPoster
Config: (nntp) Reply to the poster if &#39;poster&#39; is in the &#39;Followup-To&#39; header.
Definition: globals.h:191
void mutt_view_attachments(struct Email *e)
Show the attachments in a Menu.
Definition: recvattach.c:1411
static int TopLine
Definition: pager.c:204
static void cleanup_quote(struct QClass **quote_list)
Free a quote list.
Definition: pager.c:562
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:651
bool attach_del
Has an attachment marked for deletion.
Definition: email.h:49
#define CHECK_ACL(aclbit, action)
Definition: pager.c:278
#define SEND_FORWARD
Forward email.
Definition: send.h:91
void mutt_resize_screen(void)
Update NeoMutt&#39;s opinion about the window size (CURSES)
Definition: resize.c:101
WHERE bool OptNeedResort
(pseudo) used to force a re-sort
Definition: options.h:44
void mutt_check_stats(void)
Forcibly update mailbox stats.
Definition: commands.c:1395
void crypt_forget_passphrase(void)
Forget a passphrase and display a message.
Definition: crypt.c:104
struct Buffer mutt_buffer_make(size_t size)
Make a new buffer on the stack.
Definition: buffer.c:61
#define IsMsgAttach(pager)
Definition: pager.c:248
void mutt_enter_command(void)
enter a neomutt command
Definition: commands.c:862
static void pager_custom_redraw(struct Menu *pager_menu)
Redraw the pager window - Implements Menu::custom_redraw()
Definition: pager.c:1932
String manipulation buffer.
Definition: buffer.h:33
Flagged messages.
Definition: mutt.h:100
#define _(a)
Definition: message.h:28
const char * helpstr
Definition: pager.c:196
WHERE bool C_WrapSearch
Config: Wrap around when the search hits the end.
Definition: globals.h:258
struct Line * line_info
Definition: pager.c:198
WHERE bool C_BrailleFriendly
Config: Move the cursor to the beginning of the line.
Definition: globals.h:207
void menu_status_line(char *buf, size_t buflen, struct Menu *menu, const char *p)
Create the status line.
Definition: status.c:409
struct Body * body
Current attachment.
Definition: pager.h:69
Messages to be purged (bypass trash)
Definition: mutt.h:98
PagerFlags flags
Definition: pager.c:173
static bool InHelp
Definition: pager.c:207
bool search_back
Definition: pager.c:165
bool search_compiled
Definition: pager.c:164
short type
Definition: pager.c:137
#define MUTT_PAGER_NOWRAP
Format for term width, ignore $wrap.
Definition: pager.h:56
uint16_t SendFlags
Flags for ci_send_message(), e.g. SEND_REPLY.
Definition: send.h:86
Pager: quoted text.
Definition: color.h:82
#define SEND_POSTPONED
Recall a postponed email.
Definition: send.h:92
Container for Accounts, Notifications.
Definition: neomutt.h:35
#define MUTT_ACL_DELETE
Delete a message.
Definition: mailbox.h:66
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:1626
#define mutt_get_field(field, buf, buflen, complete)
Definition: curs_lib.h:90
int vcount
The number of virtual messages.
Definition: mailbox.h:102
#define MUTT_PAGER_ATTACHMENT
Attachments may exist.
Definition: pager.h:55
LOFF_T last_pos
Definition: pager.c:188
void mutt_print_message(struct Mailbox *m, struct EmailList *el)
Print a message.
Definition: commands.c:721
#define SEND_NO_FLAGS
No flags are set.
Definition: send.h:87
void mutt_beep(bool force)
Irritate the user.
Definition: curs_lib.c:98
#define MAX(a, b)
Definition: memory.h:30
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
int line
Definition: pager.c:163
void mutt_attach_reply(FILE *fp, struct Email *e, struct AttachCtx *actx, struct Body *e_cur, SendFlags flags)
Attach a reply.
Definition: recvcmd.c:904
Pager pager (email viewer)
Definition: keymap.h:78
bool tagged
Email is tagged.
Definition: email.h:44
void * redraw_data
Definition: mutt_menu.h:155
bool read
Email is read.
Definition: email.h:51
void mutt_print_attachment_list(struct AttachCtx *actx, FILE *fp, bool tag, struct Body *top)
Print a list of Attachments.
Definition: recvattach.c:1026
void mutt_curses_set_cursor(enum MuttCursorState state)
Set the cursor state.
Definition: mutt_curses.c:76
struct Mailbox * mailbox
Definition: context.h:51
static int braille_line
Definition: pager.c:209
bool old
Email is seen, but unread.
Definition: email.h:50
int indexlen
Definition: pager.c:175
struct MuttWindow * win_ibar
Definition: mutt_menu.h:96
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:153
void mutt_what_key(void)
Ask the user to press a key.
Definition: keymap.c:1621
struct Envelope * env
Envelope information.
Definition: email.h:89
int has_types
Definition: pager.c:184
Display a normal cursor.
Definition: mutt_curses.h:81
FILE * fp
Definition: pager.c:199
#define REG_COMP(preg, regex, cflags)
Compile a regular expression.
Definition: regex3.h:52
bool mutt_mailbox_notify(struct Mailbox *m_cur)
Notify the user if there&#39;s new mail.
Definition: mutt_mailbox.c:217
short continuation
Definition: pager.c:138
void mutt_shell_escape(void)
invoke a command in a subshell
Definition: commands.c:834
void mutt_buffer_dealloc(struct Buffer *buf)
Release the memory allocated by a buffer.
Definition: buffer.c:294
WHERE SIG_ATOMIC_VOLATILE_T SigWinch
true after SIGWINCH is received
Definition: globals.h:80
WHERE unsigned char C_PostModerated
Config: (nntp) Allow posting to moderated newsgroups.
Definition: globals.h:190
#define MUTT_PAGER_NSKIP
Preserve whitespace with smartwrap.
Definition: pager.h:52
#define SEND_LIST_REPLY
Reply to mailing list.
Definition: send.h:90
static struct Mapping PagerNewsHelpExtra[]
Definition: pager.c:236
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:113
bool force_redraw
Definition: pager.c:183
void * mdata
Driver specific data.
Definition: mailbox.h:136
#define MUTT_ACL_WRITE
Write to a message (for flagging or linking threads)
Definition: mailbox.h:74
size_t mutt_buffer_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:225
#define SEND_KEY
Mail a PGP public key.
Definition: send.h:95
Window has a fixed size.
Definition: mutt_window.h:44
int msg_not_read_yet
Which msg "new" in pager, -1 if none.
Definition: context.h:45
struct MuttWindow * win_pager
Definition: pager.h:76
short cols
Number of columns, can be MUTT_WIN_SIZE_UNLIMITED.
Definition: mutt_window.h:58
#define mutt_b2s(buf)
Definition: buffer.h:41
struct Pager * extra
Definition: pager.c:174
struct Context * ctx
Current mailbox.
Definition: pager.h:67
void mutt_alias_create(struct Envelope *cur, struct AddressList *al)
Create a new Alias from an Envelope or an Address.
Definition: alias.c:375
void mutt_refresh(void)
Force a refresh of the screen.
Definition: curs_lib.c:107
Window size depends on its children.
Definition: mutt_window.h:46
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
short search_cnt
Definition: pager.c:140
struct TextSyntax * search
Definition: pager.c:142
struct WindowState state
Current state of the Window.
Definition: mutt_window.h:93
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: lib.h:137
WHERE bool OptAttachMsg
(pseudo) used by attach-message
Definition: options.h:31
#define REDRAW_STATUS
Redraw the status bar.
Definition: mutt_menu.h:46
bool visible
Window is visible.
Definition: mutt_window.h:56
bool search_compiled
Definition: pager.c:192
void km_error_key(enum MenuType menu)
Handle an unbound key sequence.
Definition: keymap.c:1095
#define CHECK_ATTACH
Definition: pager.c:270
Messages to be deleted.
Definition: mutt.h:96
A mailbox.
Definition: mailbox.h:81
#define MUTT_WIN_SIZE_UNLIMITED
Use as much space as possible.
Definition: mutt_window.h:49
short rows
Number of rows, can be MUTT_WIN_SIZE_UNLIMITED.
Definition: mutt_window.h:57
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:90
Nondestructive flags change (IMAP)
Definition: mx.h:77
WHERE bool C_Resolve
Config: Move to the next email whenever a command modifies an email.
Definition: globals.h:243
#define IS_HEADER(x)
Definition: pager.c:245
struct AttachCtx * actx
Attachment information.
Definition: pager.h:71
Tagged messages.
Definition: mutt.h:101
int bool_str_toggle(struct ConfigSubset *sub, const char *name, struct Buffer *err)
Toggle the value of a bool.
Definition: bool.c:239
int max_line
Definition: pager.c:179
WHERE char * C_NewMailCommand
Config: External command to run when new mail arrives.
Definition: globals.h:138
size_t mutt_str_strfcpy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:773
#define CHECK_READONLY
Definition: pager.c:262
A line of text in the pager.
Definition: pager.c:134
New messages.
Definition: mutt.h:91
Messages that have been read.
Definition: mutt.h:94
static const struct Mapping PagerHelp[]
Definition: pager.c:220
int last_line
Definition: pager.c:180
static const struct Mapping PagerHelpExtra[]
Definition: pager.c:227
bool quiet
Inhibit status messages?
Definition: mailbox.h:118
void(* custom_redraw)(struct Menu *menu)
Redraw the menu.
Definition: mutt_menu.h:153
#define SEND_NEWS
Reply to a news article.
Definition: send.h:102
int ci_send_message(SendFlags flags, struct Email *e_templ, const char *tempfile, struct Context *ctx, struct EmailList *el)
Send an email.
Definition: send.c:1893
WHERE bool OptSearchInvalid
(pseudo) used to invalidate the search pattern
Definition: options.h:53
enum MuttWindowSize size
Type of Window, e.g. MUTT_WIN_SIZE_FIXED.
Definition: mutt_window.h:97
#define MUTT_HIDE
Don&#39;t show quoted text.
Definition: pager.h:46
void update_index(struct Menu *menu, struct Context *ctx, int check, int oldcount, int index_hint)
Update the index.
Definition: index.c:614
int pagelen
Number of entries per screen.
Definition: mutt_menu.h:92
size_t mutt_buffer_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:240
SecurityFlags security
bit 0-10: flags, bit 11,12: application, bit 13: traditional pgp See: ncrypt/lib.h pgplib...
Definition: email.h:39
#define SEND_REPLY
Reply to sender.
Definition: send.h:88
NNTP-specific Mailbox data -.
Definition: lib.h:140
int mutt_window_move(struct MuttWindow *win, int row, int col)
Move the cursor in a Window.
Definition: mutt_window.c:278
void mutt_clear_pager_position(void)
Reset the pager&#39;s viewing position.
Definition: pager.c:1923
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:312
int max
Number of entries in the menu.
Definition: mutt_menu.h:88
struct MuttWindow * mutt_window_dialog(struct MuttWindow *win)
Find the parent Dialog of a Window.
Definition: mutt_window.c:560
WHERE bool C_DeleteUntag
Config: Untag messages when they are marked for deletion.
Definition: globals.h:211
bool C_PagerStop
Config: Don&#39;t automatically open the next message when at the end of a message.
Definition: pager.c:89
MuttRedrawFlags redraw
When to redraw the screen.
Definition: mutt_menu.h:89
void mutt_attach_forward(FILE *fp, struct Email *e, struct AttachCtx *actx, struct Body *cur, SendFlags flags)
Forward an Attachment.
Definition: recvcmd.c:756
struct QClass * quote_list
Definition: pager.c:187
#define IsEmail(pager)
Definition: pager.c:250
int indicator
the indicator line of the PI
Definition: pager.c:176
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:876
struct Email * email
Current message.
Definition: pager.h:68
Highlighting for a line of text.
Definition: pager.c:124
void ci_bounce_message(struct Mailbox *m, struct EmailList *el)
Bounce an email.
Definition: commands.c:408
#define MUTT_PAGER_RETWINCH
Need reformatting on SIGWINCH.
Definition: pager.h:54
#define SEND_GROUP_REPLY
Reply to all.
Definition: send.h:89
#define MUTT_SEARCH
Resolve search patterns.
Definition: pager.h:47
#define REDRAW_BODY
Redraw the pager.
Definition: mutt_menu.h:48
int mutt_label_message(struct Mailbox *m, struct EmailList *el)
Let the user label a message.
Definition: mutt_header.c:125
char * searchbuf
Definition: pager.c:197
bool flagged
Marked important?
Definition: email.h:43
void emaillist_clear(struct EmailList *el)
Drop a private list of Emails.
Definition: email.c:123
#define REDRAW_INDEX
Redraw the index.
Definition: mutt_menu.h:42
void mutt_help(enum MenuType menu, int wraplen)
Display the help menu.
Definition: help.c:444
bool deleted
Email is deleted.
Definition: email.h:45
void mutt_window_reflow(struct MuttWindow *win)
Resize a Window and its children.
Definition: mutt_window.c:345
struct MuttWindow * parent
Parent Window.
Definition: mutt_window.h:100
#define mutt_error(...)
Definition: logging.h:84
char * followup_to
List of &#39;followup-to&#39; fields.
Definition: envelope.h:77
int mutt_str_strcasecmp(const char *a, const char *b)
Compare two strings ignoring case, safely.
Definition: string.c:651
void mutt_timeout_hook(void)
Execute any timeout hooks.
Definition: hook.c:813
int mutt_select_sort(bool reverse)
Ask the user for a sort method.
Definition: commands.c:760
short C_SkipQuotedOffset
Config: Lines of context to show when skipping quoted text.
Definition: pager.c:91
int index
The absolute (unsorted) message number.
Definition: email.h:85
#define FREE(x)
Definition: memory.h:40
void crypt_extract_keys_from_messages(struct Mailbox *m, struct EmailList *el)
Extract keys from a message.
Definition: crypt.c:859
#define MUTT_ACL_SEEN
Change the &#39;seen&#39; status of a message.
Definition: mailbox.h:73
Hide the cursor.
Definition: mutt_curses.h:80
#define STAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:321
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:1074
short req_rows
Number of rows required.
Definition: mutt_window.h:90
struct TextSyntax * syntax
Definition: pager.c:141
void mutt_make_help(char *buf, size_t buflen, const char *txt, enum MenuType menu, int op)
Create one entry for the help bar.
Definition: help.c:93
#define PGP_TRADITIONAL_CHECKED
Email has a traditional (inline) signature.
Definition: lib.h:139
bool changed
Mailbox has been modified.
Definition: mailbox.h:114
int mutt_change_flag(struct Mailbox *m, struct EmailList *el, bool bf)
Change the flag on a Message.
Definition: flags.c:432
Keep track of screen resizing.
Definition: pager.c:161
void ctx_free(struct Context **ptr)
Free a Context.
Definition: context.c:48
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:38
New mail received in Mailbox.
Definition: mx.h:74
#define SEND_GROUP_CHAT_REPLY
Reply to all recipients preserving To/Cc.
Definition: send.h:101
struct stat sb
Definition: pager.c:200
#define IsAttach(pager)
Definition: pager.c:247
int current
Current entry.
Definition: mutt_menu.h:87
int el_add_tagged(struct EmailList *el, struct Context *ctx, struct Email *e, bool use_tagged)
Get a list of the tagged Emails.
Definition: context.c:365
struct Buffer pathbuf
Definition: mailbox.h:83
struct MuttWindow * win_index
Definition: mutt_menu.h:95
char * mutt_compile_help(char *buf, size_t buflen, enum MenuType menu, const struct Mapping *items)
Create the text for the help menu.
Definition: help.c:116
Window wants as much space as possible.
Definition: mutt_window.h:45
bool mutt_buffer_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:252
LOFF_T offset
Definition: pager.c:136
Mailbox was reopened.
Definition: mx.h:76
int mutt_resend_message(FILE *fp, struct Context *ctx, struct Email *e_cur)
Resend an email.
Definition: send.c:1504
short C_SearchContext
Config: Context to display around search matches.
Definition: pager.c:90
#define CHECK_MODE(test)
Definition: pager.c:254
bool mutt_mb_is_lower(const char *s)
Does a multi-byte string contain only lowercase characters?
Definition: mbyte.c:358
struct Email * email
header information for message/rfc822
Definition: body.h:55
#define MUTT_SHOWFLAT
Show characters (used for displaying help)
Definition: pager.h:44
void mutt_attach_resend(FILE *fp, struct AttachCtx *actx, struct Body *cur)
resend-message, from the attachment menu
Definition: recvcmd.c:291
int mutt_system(const char *cmd)
Run an external command.
Definition: system.c:51
static struct Email * OldEmail
Definition: pager.c:205
short C_PagerIndexLines
Config: Number of index lines to display above the pager.
Definition: pager.c:88
struct Email * last_tag
Last tagged msg (used to link threads)
Definition: context.h:42
regex_t search_re
Definition: pager.c:191
int msgno
Number displayed to the user.
Definition: email.h:86
const char * mutt_make_version(void)
Generate the NeoMutt version string.
Definition: muttlib.c:1549
bool search_back
Definition: pager.c:194
struct MuttWindow * win_pbar
Definition: pager.h:75
+ Here is the caller graph for this function:

Variable Documentation

◆ C_AllowAnsi

bool C_AllowAnsi

Config: Allow ANSI colour codes in rich text messages.

Definition at line 85 of file pager.c.

◆ C_HeaderColorPartial

bool C_HeaderColorPartial

Config: Only colour the part of the header matching the regex.

Definition at line 86 of file pager.c.

◆ C_PagerContext

short C_PagerContext

Config: Number of lines of overlap when changing pages in the pager.

Definition at line 87 of file pager.c.

◆ C_PagerIndexLines

short C_PagerIndexLines

Config: Number of index lines to display above the pager.

Definition at line 88 of file pager.c.

◆ C_PagerStop

bool C_PagerStop

Config: Don't automatically open the next message when at the end of a message.

Definition at line 89 of file pager.c.

◆ C_SearchContext

short C_SearchContext

Config: Context to display around search matches.

Definition at line 90 of file pager.c.

◆ C_SkipQuotedOffset

short C_SkipQuotedOffset

Config: Lines of context to show when skipping quoted text.

Definition at line 91 of file pager.c.

◆ C_SmartWrap

bool C_SmartWrap

Config: Wrap text at word boundaries.

Definition at line 92 of file pager.c.

◆ C_Smileys

struct Regex* C_Smileys

Config: Regex to match smileys to prevent mistakes when quoting text.

Definition at line 93 of file pager.c.

◆ C_Tilde

bool C_Tilde

Config: Character to pad blank lines in the pager.

Definition at line 94 of file pager.c.

◆ TopLine

int TopLine = 0
static

Definition at line 204 of file pager.c.

◆ OldEmail

struct Email* OldEmail = NULL
static

Definition at line 205 of file pager.c.

◆ InHelp

bool InHelp = false
static

Definition at line 207 of file pager.c.

◆ braille_line

int braille_line = -1
static

Definition at line 209 of file pager.c.

◆ braille_col

int braille_col = -1
static

Definition at line 210 of file pager.c.

◆ Resize

struct Resize* Resize = NULL
static

Definition at line 212 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")
#define N_(a)
Definition: message.h:32

Definition at line 214 of file pager.c.

◆ Mailbox_is_read_only

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

Definition at line 216 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")
#define N_(a)
Definition: message.h:32

Definition at line 217 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 },
{ NULL, 0 },
}
#define N_(a)
Definition: message.h:32

Definition at line 220 of file pager.c.

◆ PagerHelpExtra

const struct Mapping PagerHelpExtra[]
static
Initial value:
= {
{ N_("View Attachm."), OP_VIEW_ATTACHMENTS },
{ N_("Del"), OP_DELETE },
{ N_("Reply"), OP_REPLY },
{ N_("Next"), OP_MAIN_NEXT_UNDELETED },
{ NULL, 0 },
}
#define N_(a)
Definition: message.h:32

Definition at line 227 of file pager.c.

◆ PagerNewsHelpExtra

struct Mapping PagerNewsHelpExtra[]
static
Initial value:
= {
{ N_("Post"), OP_POST },
{ N_("Followup"), OP_FOLLOWUP },
{ N_("Del"), OP_DELETE },
{ N_("Next"), OP_MAIN_NEXT_UNDELETED },
{ NULL, 0 },
}
#define N_(a)
Definition: message.h:32

Definition at line 236 of file pager.c.