NeoMutt  2020-08-21-74-g346364
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 <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include <wchar.h>
#include "mutt/lib.h"
#include "config/lib.h"
#include "email/lib.h"
#include "core/lib.h"
#include "alias/lib.h"
#include "gui/lib.h"
#include "mutt.h"
#include "pager.h"
#include "ncrypt/lib.h"
#include "send/lib.h"
#include "commands.h"
#include "context.h"
#include "format_flags.h"
#include "hdrline.h"
#include "hook.h"
#include "index.h"
#include "init.h"
#include "keymap.h"
#include "mutt_attach.h"
#include "mutt_globals.h"
#include "mutt_header.h"
#include "mutt_logging.h"
#include "mutt_mailbox.h"
#include "mutt_menu.h"
#include "muttlib.h"
#include "mx.h"
#include "opcodes.h"
#include "options.h"
#include "protos.h"
#include "recvattach.h"
#include "recvcmd.h"
#include "status.h"
#include "sidebar/lib.h"
#include "nntp/lib.h"
#include <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 (const char *str)
 Is this an ANSI escape sequence? More...
 
static int grok_ansi (unsigned char *buf, int pos, struct AnsiAttr *a)
 Parse an ANSI escape sequence. More...
 
void mutt_buffer_strip_formatting (struct Buffer *dest, const char *src, bool strip_markers)
 Removes ANSI and backspace formatting. More...
 
static int fill_buffer (FILE *fp, LOFF_T *last_pos, LOFF_T offset, unsigned char **buf, unsigned char **fmt, size_t *blen, int *buf_ready)
 Fill a buffer from a file. More...
 
static int format_line (struct Line **line_info, int n, unsigned char *buf, PagerFlags flags, struct AnsiAttr *pa, int cnt, int *pspace, int *pvch, int *pcol, int *pspecial, int width)
 Display a line of text in the pager. More...
 
static int display_line (FILE *fp, LOFF_T *last_pos, struct Line **line_info, int n, int *last, int *max, PagerFlags flags, struct QClass **quote_list, int *q_level, bool *force_redraw, regex_t *search_re, struct MuttWindow *win_pager)
 Print a line on screen. More...
 
static int up_n_lines (int nlines, struct Line *info, int cur, bool hiding)
 Reposition the pager's view up by n lines. More...
 
void mutt_clear_pager_position (void)
 Reset the pager's viewing position. More...
 
static void pager_custom_redraw (struct Menu *pager_menu)
 Redraw the pager window - Implements Menu::custom_redraw() More...
 
int mutt_pager (const char *banner, const char *fname, PagerFlags flags, struct Pager *extra)
 Display a file, or help, in a window. More...
 

Variables

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 []
 Help Bar for the Pager's Help Page. More...
 
static const struct Mapping PagerHelpHelp []
 Help Bar for the Help Page itself. More...
 
static const struct Mapping PagerNormalHelp []
 Help Bar for the Pager of a normal Mailbox. More...
 
static const struct Mapping PagerNewsHelp []
 Help Bar for the Pager of an NNTP Mailbox. More...
 

Detailed Description

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

Authors
  • Michael R. Elkins

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 98 of file pager.c.

◆ ANSI_OFF

#define ANSI_OFF   (1 << 0)

Turn off colours and attributes.

Definition at line 99 of file pager.c.

◆ ANSI_BLINK

#define ANSI_BLINK   (1 << 1)

Blinking text.

Definition at line 100 of file pager.c.

◆ ANSI_BOLD

#define ANSI_BOLD   (1 << 2)

Bold text.

Definition at line 101 of file pager.c.

◆ ANSI_UNDERLINE

#define ANSI_UNDERLINE   (1 << 3)

Underlined text.

Definition at line 102 of file pager.c.

◆ ANSI_REVERSE

#define ANSI_REVERSE   (1 << 4)

Reverse video.

Definition at line 103 of file pager.c.

◆ ANSI_COLOR

#define ANSI_COLOR   (1 << 5)

Use colours.

Definition at line 104 of file pager.c.

◆ IS_HEADER

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

Definition at line 271 of file pager.c.

◆ IsAttach

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

Definition at line 273 of file pager.c.

◆ IsMsgAttach

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

Definition at line 274 of file pager.c.

◆ IsEmail

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

Definition at line 276 of file pager.c.

◆ NUM_SIG_LINES

#define NUM_SIG_LINES   4

Definition at line 278 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:212

Definition at line 280 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:38
#define _(a)
Definition: message.h:28
struct Mailbox * mailbox
Definition: context.h:50
bool readonly
Don&#39;t allow changes to the mailbox.
Definition: mailbox.h:119
static const char * Mailbox_is_read_only
Definition: pager.c:214

Definition at line 288 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:215

Definition at line 296 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:38
#define _(a)
Definition: message.h:28
struct Mailbox * mailbox
Definition: context.h:50
AclFlags rights
ACL bits, see AclFlags.
Definition: mailbox.h:121

Definition at line 304 of file pager.c.

Typedef Documentation

◆ AnsiFlags

typedef uint8_t AnsiFlags

Flags, e.g. ANSI_OFF.

Definition at line 97 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 321 of file pager.c.

322 {
323  int count = 0;
324 
325  while ((n > 0) && (count <= NUM_SIG_LINES))
326  {
327  if (info[n].type != MT_COLOR_SIGNATURE)
328  break;
329  count++;
330  n--;
331  }
332 
333  if (count == 0)
334  return -1;
335 
336  if (count > NUM_SIG_LINES)
337  {
338  /* check for a blank line */
339  while (*s)
340  {
341  if (!IS_SPACE(*s))
342  return 0;
343  s++;
344  }
345 
346  return -1;
347  }
348 
349  return 0;
350 }
enum MailboxType type
Mailbox type.
Definition: mailbox.h:105
Pager: signature lines.
Definition: color.h:93
#define NUM_SIG_LINES
Definition: pager.c:278
#define IS_SPACE(ch)
Definition: string2.h:38
+ 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 360 of file pager.c.

361 {
362  const int *cnt = (const int *) m1;
363  const struct TextSyntax *stx = (const struct TextSyntax *) m2;
364 
365  if (*cnt < stx->first)
366  return -1;
367  if (*cnt >= stx->last)
368  return 1;
369  return 0;
370 }
int last
Definition: pager.c:127
Highlighting for a line of text.
Definition: pager.c:123
int first
Definition: pager.c:126
+ 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 381 of file pager.c.

383 {
384  int def_color; /* color without syntax highlight */
385  int color; /* final color */
386  static int last_color; /* last color set */
387  bool search = false;
388  int m;
389  struct TextSyntax *matching_chunk = NULL;
390 
391  if (cnt == 0)
392  last_color = -1; /* force attrset() */
393 
394  if (line_info[n].continuation)
395  {
396  if (!cnt && C_Markers)
397  {
399  mutt_window_addch('+');
400  last_color = Colors->defs[MT_COLOR_MARKERS];
401  }
402  m = (line_info[n].syntax)[0].first;
403  cnt += (line_info[n].syntax)[0].last;
404  }
405  else
406  m = n;
407  if (flags & MUTT_PAGER_LOGS)
408  {
409  def_color = Colors->defs[(line_info[n].syntax)[0].color];
410  }
411  else if (!(flags & MUTT_SHOWCOLOR))
412  def_color = Colors->defs[MT_COLOR_NORMAL];
413  else if (line_info[m].type == MT_COLOR_HEADER)
414  def_color = (line_info[m].syntax)[0].color;
415  else
416  def_color = Colors->defs[line_info[m].type];
417 
418  if ((flags & MUTT_SHOWCOLOR) && (line_info[m].type == MT_COLOR_QUOTED))
419  {
420  struct QClass *qc = line_info[m].quote;
421 
422  if (qc)
423  {
424  def_color = qc->color;
425 
426  while (qc && (qc->length > cnt))
427  {
428  def_color = qc->color;
429  qc = qc->up;
430  }
431  }
432  }
433 
434  color = def_color;
435  if ((flags & MUTT_SHOWCOLOR) && line_info[m].chunks)
436  {
437  matching_chunk = bsearch(&cnt, line_info[m].syntax, line_info[m].chunks,
438  sizeof(struct TextSyntax), comp_syntax_t);
439  if (matching_chunk && (cnt >= matching_chunk->first) &&
440  (cnt < matching_chunk->last))
441  {
442  color = matching_chunk->color;
443  }
444  }
445 
446  if ((flags & MUTT_SEARCH) && line_info[m].search_cnt)
447  {
448  matching_chunk = bsearch(&cnt, line_info[m].search, line_info[m].search_cnt,
449  sizeof(struct TextSyntax), comp_syntax_t);
450  if (matching_chunk && (cnt >= matching_chunk->first) &&
451  (cnt < matching_chunk->last))
452  {
453  color = Colors->defs[MT_COLOR_SEARCH];
454  search = 1;
455  }
456  }
457 
458  /* handle "special" bold & underlined characters */
459  if (special || a->attr)
460  {
461 #ifdef HAVE_COLOR
462  if ((a->attr & ANSI_COLOR))
463  {
464  if (a->pair == -1)
465  a->pair = mutt_color_alloc(Colors, a->fg, a->bg);
466  color = a->pair;
467  if (a->attr & ANSI_BOLD)
468  color |= A_BOLD;
469  }
470  else
471 #endif
472  if ((special & A_BOLD) || (a->attr & ANSI_BOLD))
473  {
474  if (Colors->defs[MT_COLOR_BOLD] && !search)
475  color = Colors->defs[MT_COLOR_BOLD];
476  else
477  color ^= A_BOLD;
478  }
479  if ((special & A_UNDERLINE) || (a->attr & ANSI_UNDERLINE))
480  {
481  if (Colors->defs[MT_COLOR_UNDERLINE] && !search)
482  color = Colors->defs[MT_COLOR_UNDERLINE];
483  else
484  color ^= A_UNDERLINE;
485  }
486  else if (a->attr & ANSI_REVERSE)
487  {
488  color ^= A_REVERSE;
489  }
490  else if (a->attr & ANSI_BLINK)
491  {
492  color ^= A_BLINK;
493  }
494  else if (a->attr == ANSI_OFF)
495  {
496  a->attr = 0;
497  }
498  }
499 
500  if (color != last_color)
501  {
502  mutt_curses_set_attr(color);
503  last_color = color;
504  }
505 }
Bold text.
Definition: color.h:64
Underlined text.
Definition: color.h:97
#define ANSI_COLOR
Use colours.
Definition: pager.c:104
short chunks
Definition: pager.c:138
#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:57
size_t length
Definition: pager.c:112
int pair
Curses colour pair.
Definition: pager.c:154
int * defs
Array of all fixed colours, see enum ColorId.
Definition: color.h:131
int last
Definition: pager.c:127
short type
Definition: pager.c:136
Pager: quoted text.
Definition: color.h:81
#define ANSI_BOLD
Bold text.
Definition: pager.c:101
AnsiFlags attr
Attributes, e.g. underline, bold, etc.
Definition: pager.c:151
static int comp_syntax_t(const void *m1, const void *m2)
Search for a Syntax using bsearch.
Definition: pager.c:360
#define ANSI_BLINK
Blinking text.
Definition: pager.c:100
Message headers (takes a pattern)
Definition: color.h:72
Pager: markers, line continuation.
Definition: color.h:74
Plain text.
Definition: color.h:77
#define ANSI_REVERSE
Reverse video.
Definition: pager.c:103
struct QClass * quote
Definition: pager.c:142
int bg
Background colour.
Definition: pager.c:153
WHERE bool C_Markers
Config: Display a &#39;+&#39; at the beginning of wrapped lines in the pager.
Definition: mutt_globals.h:150
#define ANSI_UNDERLINE
Underlined text.
Definition: pager.c:102
Definition: color.h:129
#define MUTT_PAGER_LOGS
Logview mode.
Definition: pager.h:57
int fg
Foreground colour.
Definition: pager.c:152
Highlighting for a line of text.
Definition: pager.c:123
int mutt_window_addch(int ch)
Write one character to a Window.
Definition: mutt_window.c:502
#define MUTT_SEARCH
Resolve search patterns.
Definition: pager.h:47
int mutt_color_alloc(struct Colors *c, uint32_t fg, uint32_t bg)
Allocate a colour pair.
Definition: color.c:471
int color
Definition: pager.c:114
Pager: search matches.
Definition: color.h:82
struct TextSyntax * syntax
Definition: pager.c:140
int first
Definition: pager.c:126
void mutt_curses_set_attr(int attr)
Set the attributes for text.
Definition: mutt_curses.c:40
struct QClass * up
Definition: pager.c:117
Style of quoted text.
Definition: pager.c:110
int color
Definition: pager.c:125
#define ANSI_OFF
Turn off colours and attributes.
Definition: pager.c:99
+ 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 513 of file pager.c.

514 {
515  int m;
516 
517  line_info[n + 1].type = line_info[n].type;
518  (line_info[n + 1].syntax)[0].color = (line_info[n].syntax)[0].color;
519  line_info[n + 1].continuation = 1;
520 
521  /* find the real start of the line */
522  for (m = n; m >= 0; m--)
523  if (line_info[m].continuation == 0)
524  break;
525 
526  (line_info[n + 1].syntax)[0].first = m;
527  (line_info[n + 1].syntax)[0].last =
528  (line_info[n].continuation) ? cnt + (line_info[n].syntax)[0].last : cnt;
529 }
short type
Definition: pager.c:136
short continuation
Definition: pager.c:137
int color
Definition: pager.c:114
struct TextSyntax * syntax
Definition: pager.c:140
+ 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 536 of file pager.c.

537 {
538  qc->index = (*q_level)++;
539  qc->color = Colors->quotes[qc->index % Colors->quotes_used];
540 }
Definition: color.h:129
int color
Definition: pager.c:114
int index
Definition: pager.c:113
int quotes_used
Number of colours for quoted email text.
Definition: color.h:144
int * quotes
Array of colours for quoted email text.
Definition: color.h:143
+ 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 549 of file pager.c.

551 {
552  struct QClass *q_list = quote_list;
553  new_class->index = -1;
554 
555  while (q_list)
556  {
557  if (q_list->index >= index)
558  {
559  q_list->index++;
560  q_list->color = Colors->quotes[q_list->index % Colors->quotes_used];
561  }
562  if (q_list->down)
563  q_list = q_list->down;
564  else if (q_list->next)
565  q_list = q_list->next;
566  else
567  {
568  while (!q_list->next)
569  {
570  q_list = q_list->up;
571  if (!q_list)
572  break;
573  }
574  if (q_list)
575  q_list = q_list->next;
576  }
577  }
578 
579  new_class->index = index;
580  new_class->color = Colors->quotes[index % Colors->quotes_used];
581  (*q_level)++;
582 }
struct QClass * down
Definition: pager.c:117
struct QClass * next
Definition: pager.c:116
Definition: color.h:129
int color
Definition: pager.c:114
int index
Definition: pager.c:113
int quotes_used
Number of colours for quoted email text.
Definition: color.h:144
struct QClass * up
Definition: pager.c:117
Style of quoted text.
Definition: pager.c:110
int * quotes
Array of colours for quoted email text.
Definition: color.h:143
+ 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 588 of file pager.c.

589 {
590  struct QClass *ptr = NULL;
591 
592  while (*quote_list)
593  {
594  if ((*quote_list)->down)
595  cleanup_quote(&((*quote_list)->down));
596  ptr = (*quote_list)->next;
597  FREE(&(*quote_list)->prefix);
598  FREE(quote_list);
599  *quote_list = ptr;
600  }
601 }
static void cleanup_quote(struct QClass **quote_list)
Free a quote list.
Definition: pager.c:588
struct QClass * next
Definition: pager.c:116
#define FREE(x)
Definition: memory.h:40
Style of quoted text.
Definition: pager.c:110
+ 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 612 of file pager.c.

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

925 {
926  for (; (p[0] == q[0]) && (q[0] != '\0') && (p[0] != '\0') && (q[0] != '\a') &&
927  (p[0] != '\a');
928  p++, q++)
929  {
930  }
931 
932  return (int) (*p - *q);
933 }
+ 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 940 of file pager.c.

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

951 {
953 }
WHERE char ProtectedHeaderMarker[256]
Unique ANSI string to mark protected headers in an email.
Definition: mutt_globals.h:47
static int check_marker(const char *q, const char *p)
Check that the unique marker is present.
Definition: pager.c:924
+ 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 964 of file pager.c.

965 {
966  bool is_quote = false;
967  regmatch_t pmatch_internal[1], smatch[1];
968 
969  if (!pmatch)
970  pmatch = pmatch_internal;
971 
972  if (mutt_regex_capture(C_QuoteRegex, line, 1, pmatch))
973  {
974  if (mutt_regex_capture(C_Smileys, line, 1, smatch))
975  {
976  if (smatch[0].rm_so > 0)
977  {
978  char c = line[smatch[0].rm_so];
979  line[smatch[0].rm_so] = 0;
980 
981  if (mutt_regex_capture(C_QuoteRegex, line, 1, pmatch))
982  is_quote = true;
983 
984  line[smatch[0].rm_so] = c;
985  }
986  }
987  else
988  is_quote = true;
989  }
990 
991  return is_quote;
992 }
struct Regex * C_Smileys
Config: Regex to match smileys to prevent mistakes when quoting text.
Definition: pager.c:92
WHERE struct Regex * C_QuoteRegex
Config: Regex to match quoted text in a reply.
Definition: mutt_globals.h:120
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:593
+ 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 1006 of file pager.c.

1009 {
1010  struct ColorLine *color_line = NULL;
1011  struct ColorLineList *head = NULL;
1012  regmatch_t pmatch[1];
1013  bool found;
1014  bool null_rx;
1015  int offset, i = 0;
1016 
1017  if ((n == 0) || IS_HEADER(line_info[n - 1].type) ||
1018  (check_protected_header_marker(raw) == 0))
1019  {
1020  if (buf[0] == '\n') /* end of header */
1021  {
1022  line_info[n].type = MT_COLOR_NORMAL;
1023  getyx(stdscr, braille_line, braille_col);
1024  }
1025  else
1026  {
1027  /* if this is a continuation of the previous line, use the previous
1028  * line's color as default. */
1029  if ((n > 0) && ((buf[0] == ' ') || (buf[0] == '\t')))
1030  {
1031  line_info[n].type = line_info[n - 1].type; /* wrapped line */
1032  if (!C_HeaderColorPartial)
1033  {
1034  (line_info[n].syntax)[0].color = (line_info[n - 1].syntax)[0].color;
1035  line_info[n].is_cont_hdr = 1;
1036  }
1037  }
1038  else
1039  {
1040  line_info[n].type = MT_COLOR_HDRDEFAULT;
1041  }
1042 
1043  /* When this option is unset, we color the entire header the
1044  * same color. Otherwise, we handle the header patterns just
1045  * like body patterns (further below). */
1046  if (!C_HeaderColorPartial)
1047  {
1048  STAILQ_FOREACH(color_line, &Colors->hdr_list, entries)
1049  {
1050  if (regexec(&color_line->regex, buf, 0, NULL, 0) == 0)
1051  {
1052  line_info[n].type = MT_COLOR_HEADER;
1053  line_info[n].syntax[0].color = color_line->pair;
1054  if (line_info[n].is_cont_hdr)
1055  {
1056  /* adjust the previous continuation lines to reflect the color of this continuation line */
1057  int j;
1058  for (j = n - 1; j >= 0 && line_info[j].is_cont_hdr; --j)
1059  {
1060  line_info[j].type = line_info[n].type;
1061  line_info[j].syntax[0].color = line_info[n].syntax[0].color;
1062  }
1063  /* now adjust the first line of this header field */
1064  if (j >= 0)
1065  {
1066  line_info[j].type = line_info[n].type;
1067  line_info[j].syntax[0].color = line_info[n].syntax[0].color;
1068  }
1069  *force_redraw = true; /* the previous lines have already been drawn on the screen */
1070  }
1071  break;
1072  }
1073  }
1074  }
1075  }
1076  }
1077  else if (mutt_str_startswith(raw, "\033[0m")) // Escape: a little hack...
1078  line_info[n].type = MT_COLOR_NORMAL;
1079  else if (check_attachment_marker((char *) raw) == 0)
1080  line_info[n].type = MT_COLOR_ATTACHMENT;
1081  else if (mutt_str_equal("-- \n", buf) || mutt_str_equal("-- \r\n", buf))
1082  {
1083  i = n + 1;
1084 
1085  line_info[n].type = MT_COLOR_SIGNATURE;
1086  while ((i < last) && (check_sig(buf, line_info, i - 1) == 0) &&
1087  ((line_info[i].type == MT_COLOR_NORMAL) || (line_info[i].type == MT_COLOR_QUOTED) ||
1088  (line_info[i].type == MT_COLOR_HEADER)))
1089  {
1090  /* oops... */
1091  if (line_info[i].chunks)
1092  {
1093  line_info[i].chunks = 0;
1094  mutt_mem_realloc(&(line_info[n].syntax), sizeof(struct TextSyntax));
1095  }
1096  line_info[i++].type = MT_COLOR_SIGNATURE;
1097  }
1098  }
1099  else if (check_sig(buf, line_info, n - 1) == 0)
1100  line_info[n].type = MT_COLOR_SIGNATURE;
1101  else if (mutt_is_quote_line(buf, pmatch))
1102 
1103  {
1104  if (q_classify && (line_info[n].quote == NULL))
1105  {
1106  line_info[n].quote = classify_quote(quote_list, buf + pmatch[0].rm_so,
1107  pmatch[0].rm_eo - pmatch[0].rm_so,
1108  force_redraw, q_level);
1109  }
1110  line_info[n].type = MT_COLOR_QUOTED;
1111  }
1112  else
1113  line_info[n].type = MT_COLOR_NORMAL;
1114 
1115  /* body patterns */
1116  if ((line_info[n].type == MT_COLOR_NORMAL) || (line_info[n].type == MT_COLOR_QUOTED) ||
1117  ((line_info[n].type == MT_COLOR_HDRDEFAULT) && C_HeaderColorPartial))
1118  {
1119  size_t nl;
1120 
1121  /* don't consider line endings part of the buffer
1122  * for regex matching */
1123  nl = mutt_str_len(buf);
1124  if ((nl > 0) && (buf[nl - 1] == '\n'))
1125  buf[nl - 1] = '\0';
1126 
1127  i = 0;
1128  offset = 0;
1129  line_info[n].chunks = 0;
1130  if (line_info[n].type == MT_COLOR_HDRDEFAULT)
1131  head = &Colors->hdr_list;
1132  else
1133  head = &Colors->body_list;
1134  STAILQ_FOREACH(color_line, head, entries)
1135  {
1136  color_line->stop_matching = false;
1137  }
1138  do
1139  {
1140  if (!buf[offset])
1141  break;
1142 
1143  found = false;
1144  null_rx = false;
1145  STAILQ_FOREACH(color_line, head, entries)
1146  {
1147  if (!color_line->stop_matching &&
1148  (regexec(&color_line->regex, buf + offset, 1, pmatch,
1149  ((offset != 0) ? REG_NOTBOL : 0)) == 0))
1150  {
1151  if (pmatch[0].rm_eo != pmatch[0].rm_so)
1152  {
1153  if (!found)
1154  {
1155  /* Abort if we fill up chunks.
1156  * Yes, this really happened. */
1157  if (line_info[n].chunks == SHRT_MAX)
1158  {
1159  null_rx = false;
1160  break;
1161  }
1162  if (++(line_info[n].chunks) > 1)
1163  {
1164  mutt_mem_realloc(&(line_info[n].syntax),
1165  (line_info[n].chunks) * sizeof(struct TextSyntax));
1166  }
1167  }
1168  i = line_info[n].chunks - 1;
1169  pmatch[0].rm_so += offset;
1170  pmatch[0].rm_eo += offset;
1171  if (!found || (pmatch[0].rm_so < (line_info[n].syntax)[i].first) ||
1172  ((pmatch[0].rm_so == (line_info[n].syntax)[i].first) &&
1173  (pmatch[0].rm_eo > (line_info[n].syntax)[i].last)))
1174  {
1175  (line_info[n].syntax)[i].color = color_line->pair;
1176  (line_info[n].syntax)[i].first = pmatch[0].rm_so;
1177  (line_info[n].syntax)[i].last = pmatch[0].rm_eo;
1178  }
1179  found = true;
1180  null_rx = false;
1181  }
1182  else
1183  null_rx = true; /* empty regex; don't add it, but keep looking */
1184  }
1185  else
1186  {
1187  /* Once a regexp fails to match, don't try matching it again.
1188  * On very long lines this can cause a performance issue if there
1189  * are other regexps that have many matches. */
1190  color_line->stop_matching = true;
1191  }
1192  }
1193 
1194  if (null_rx)
1195  offset++; /* avoid degenerate cases */
1196  else
1197  offset = (line_info[n].syntax)[i].last;
1198  } while (found || null_rx);
1199  if (nl > 0)
1200  buf[nl] = '\n';
1201  }
1202 
1203  /* attachment patterns */
1204  if (line_info[n].type == MT_COLOR_ATTACHMENT)
1205  {
1206  size_t nl;
1207 
1208  /* don't consider line endings part of the buffer for regex matching */
1209  nl = mutt_str_len(buf);
1210  if ((nl > 0) && (buf[nl - 1] == '\n'))
1211  buf[nl - 1] = '\0';
1212 
1213  i = 0;
1214  offset = 0;
1215  line_info[n].chunks = 0;
1216  do
1217  {
1218  if (!buf[offset])
1219  break;
1220 
1221  found = false;
1222  null_rx = false;
1223  STAILQ_FOREACH(color_line, &Colors->attach_list, entries)
1224  {
1225  if (regexec(&color_line->regex, buf + offset, 1, pmatch,
1226  ((offset != 0) ? REG_NOTBOL : 0)) == 0)
1227  {
1228  if (pmatch[0].rm_eo != pmatch[0].rm_so)
1229  {
1230  if (!found)
1231  {
1232  if (++(line_info[n].chunks) > 1)
1233  {
1234  mutt_mem_realloc(&(line_info[n].syntax),
1235  (line_info[n].chunks) * sizeof(struct TextSyntax));
1236  }
1237  }
1238  i = line_info[n].chunks - 1;
1239  pmatch[0].rm_so += offset;
1240  pmatch[0].rm_eo += offset;
1241  if (!found || (pmatch[0].rm_so < (line_info[n].syntax)[i].first) ||
1242  ((pmatch[0].rm_so == (line_info[n].syntax)[i].first) &&
1243  (pmatch[0].rm_eo > (line_info[n].syntax)[i].last)))
1244  {
1245  (line_info[n].syntax)[i].color = color_line->pair;
1246  (line_info[n].syntax)[i].first = pmatch[0].rm_so;
1247  (line_info[n].syntax)[i].last = pmatch[0].rm_eo;
1248  }
1249  found = 1;
1250  null_rx = 0;
1251  }
1252  else
1253  null_rx = 1; /* empty regex; don't add it, but keep looking */
1254  }
1255  }
1256 
1257  if (null_rx)
1258  offset++; /* avoid degenerate cases */
1259  else
1260  offset = (line_info[n].syntax)[i].last;
1261  } while (found || null_rx);
1262  if (nl > 0)
1263  buf[nl] = '\n';
1264  }
1265 }
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:871
Header default colour.
Definition: color.h:71
static int check_protected_header_marker(const char *p)
Check that the unique marker is present.
Definition: pager.c:950
struct ColorLineList body_list
List of colours applied to the email body.
Definition: color.h:134
short chunks
Definition: pager.c:138
int pair
Colour pair index.
Definition: color.h:43
Pager: signature lines.
Definition: color.h:93
short type
Definition: pager.c:136
Pager: quoted text.
Definition: color.h:81
static int braille_line
Definition: pager.c:207
Message headers (takes a pattern)
Definition: color.h:72
struct ColorLineList hdr_list
List of colours applied to the email headers.
Definition: color.h:135
Plain text.
Definition: color.h:77
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:142
static int braille_col
Definition: pager.c:208
size_t mutt_str_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix.
Definition: string.c:160
bool stop_matching
Used by the pager for body patterns, to prevent the color from being retried once it fails...
Definition: color.h:45
#define IS_HEADER(x)
Definition: pager.c:271
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:349
Definition: color.h:129
regex_t regex
Compiled regex.
Definition: color.h:37
Highlighting for a line of text.
Definition: pager.c:123
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:631
MIME attachments text (entire line)
Definition: color.h:61
bool C_HeaderColorPartial
Config: Only colour the part of the header matching the regex.
Definition: pager.c:85
struct TextSyntax * syntax
Definition: pager.c:140
struct ColorLineList attach_list
List of colours applied to the attachment headers.
Definition: color.h:133
int mutt_is_quote_line(char *line, regmatch_t *pmatch)
Is a line of message text a quote?
Definition: pager.c:964
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:612
static int check_attachment_marker(const char *p)
Check that the unique marker is present.
Definition: pager.c:940
static int check_sig(const char *s, struct Line *info, int n)
Check for an email signature.
Definition: pager.c:321
unsigned int is_cont_hdr
this line is a continuation of the previous header line
Definition: pager.c:143
A regular expression and a color to highlight a line.
Definition: color.h:35
int color
Definition: pager.c:125
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ is_ansi()

static bool is_ansi ( const char *  str)
static

Is this an ANSI escape sequence?

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

Definition at line 1272 of file pager.c.

1273 {
1274  while (*str && (isdigit(*str) || *str == ';'))
1275  str++;
1276  return (*str == 'm');
1277 }
+ 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 1286 of file pager.c.

1287 {
1288  int x = pos;
1289 
1290  while (isdigit(buf[x]) || (buf[x] == ';'))
1291  x++;
1292 
1293  /* Character Attributes */
1294  if (C_AllowAnsi && a && (buf[x] == 'm'))
1295  {
1296  if (pos == x)
1297  {
1298 #ifdef HAVE_COLOR
1299  if (a->pair != -1)
1300  mutt_color_free(Colors, a->fg, a->bg);
1301 #endif
1302  a->attr = ANSI_OFF;
1303  a->pair = -1;
1304  }
1305  while (pos < x)
1306  {
1307  if ((buf[pos] == '1') && ((pos + 1 == x) || (buf[pos + 1] == ';')))
1308  {
1309  a->attr |= ANSI_BOLD;
1310  pos += 2;
1311  }
1312  else if ((buf[pos] == '4') && ((pos + 1 == x) || (buf[pos + 1] == ';')))
1313  {
1314  a->attr |= ANSI_UNDERLINE;
1315  pos += 2;
1316  }
1317  else if ((buf[pos] == '5') && ((pos + 1 == x) || (buf[pos + 1] == ';')))
1318  {
1319  a->attr |= ANSI_BLINK;
1320  pos += 2;
1321  }
1322  else if ((buf[pos] == '7') && ((pos + 1 == x) || (buf[pos + 1] == ';')))
1323  {
1324  a->attr |= ANSI_REVERSE;
1325  pos += 2;
1326  }
1327  else if ((buf[pos] == '0') && ((pos + 1 == x) || (buf[pos + 1] == ';')))
1328  {
1329 #ifdef HAVE_COLOR
1330  if (a->pair != -1)
1331  mutt_color_free(Colors, a->fg, a->bg);
1332 #endif
1333  a->attr = ANSI_OFF;
1334  a->pair = -1;
1335  pos += 2;
1336  }
1337  else if ((buf[pos] == '3') && isdigit(buf[pos + 1]))
1338  {
1339 #ifdef HAVE_COLOR
1340  if (a->pair != -1)
1341  mutt_color_free(Colors, a->fg, a->bg);
1342 #endif
1343  a->pair = -1;
1344  a->attr |= ANSI_COLOR;
1345  a->fg = buf[pos + 1] - '0';
1346  pos += 3;
1347  }
1348  else if ((buf[pos] == '4') && isdigit(buf[pos + 1]))
1349  {
1350 #ifdef HAVE_COLOR
1351  if (a->pair != -1)
1352  mutt_color_free(Colors, a->fg, a->bg);
1353 #endif
1354  a->pair = -1;
1355  a->attr |= ANSI_COLOR;
1356  a->bg = buf[pos + 1] - '0';
1357  pos += 3;
1358  }
1359  else
1360  {
1361  while ((pos < x) && (buf[pos] != ';'))
1362  pos++;
1363  pos++;
1364  }
1365  }
1366  }
1367  pos = x;
1368  return pos;
1369 }
bool C_AllowAnsi
Config: Allow ANSI colour codes in rich text messages.
Definition: pager.c:84
#define ANSI_COLOR
Use colours.
Definition: pager.c:104
void mutt_color_free(struct Colors *c, uint32_t fg, uint32_t bg)
Free a colour.
Definition: color.c:251
int pair
Curses colour pair.
Definition: pager.c:154
#define ANSI_BOLD
Bold text.
Definition: pager.c:101
AnsiFlags attr
Attributes, e.g. underline, bold, etc.
Definition: pager.c:151
#define ANSI_BLINK
Blinking text.
Definition: pager.c:100
#define ANSI_REVERSE
Reverse video.
Definition: pager.c:103
int bg
Background colour.
Definition: pager.c:153
#define ANSI_UNDERLINE
Underlined text.
Definition: pager.c:102
Definition: color.h:129
int fg
Foreground colour.
Definition: pager.c:152
#define ANSI_OFF
Turn off colours and attributes.
Definition: pager.c:99
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_buffer_strip_formatting()

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

Removes ANSI and backspace formatting.

Parameters
destBuffer for the result
srcString to strip
strip_markersRemove

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

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

Definition at line 1384 of file pager.c.

1385 {
1386  const char *s = src;
1387 
1388  mutt_buffer_reset(dest);
1389 
1390  if (!s)
1391  return;
1392 
1393  while (s[0] != '\0')
1394  {
1395  if ((s[0] == '\010') && (s > src))
1396  {
1397  if (s[1] == '_') /* underline */
1398  s += 2;
1399  else if (s[1] && mutt_buffer_len(dest)) /* bold or overstrike */
1400  {
1401  dest->dptr--;
1402  mutt_buffer_addch(dest, s[1]);
1403  s += 2;
1404  }
1405  else /* ^H */
1406  mutt_buffer_addch(dest, *s++);
1407  }
1408  else if ((s[0] == '\033') && (s[1] == '[') && is_ansi(s + 2))
1409  {
1410  while (*s++ != 'm')
1411  ; /* skip ANSI sequence */
1412  }
1413  else if (strip_markers && (s[0] == '\033') && (s[1] == ']') &&
1414  ((check_attachment_marker(s) == 0) || (check_protected_header_marker(s) == 0)))
1415  {
1416  mutt_debug(LL_DEBUG2, "Seen attachment marker\n");
1417  while (*s++ != '\a')
1418  ; /* skip pseudo-ANSI sequence */
1419  }
1420  else
1421  mutt_buffer_addch(dest, *s++);
1422  }
1423 }
void mutt_buffer_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:79
static int check_protected_header_marker(const char *p)
Check that the unique marker is present.
Definition: pager.c:950
static bool is_ansi(const char *str)
Is this an ANSI escape sequence?
Definition: pager.c:1272
Log at debug level 2.
Definition: logging.h:41
size_t mutt_buffer_len(const struct Buffer *buf)
Calculate the length of a Buffer.
Definition: buffer.c:356
char * dptr
Current read/write position.
Definition: buffer.h:36
size_t mutt_buffer_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:240
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
static int check_attachment_marker(const char *p)
Check that the unique marker is present.
Definition: pager.c:940
+ 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 1437 of file pager.c.

1439 {
1440  static int b_read;
1441  struct Buffer stripped;
1442 
1443  if (*buf_ready == 0)
1444  {
1445  if (offset != *last_pos)
1446  fseeko(fp, offset, SEEK_SET);
1447 
1448  *buf = (unsigned char *) mutt_file_read_line((char *) *buf, blen, fp, NULL, MUTT_EOL);
1449  if (!*buf)
1450  {
1451  fmt[0] = NULL;
1452  return -1;
1453  }
1454 
1455  *last_pos = ftello(fp);
1456  b_read = (int) (*last_pos - offset);
1457  *buf_ready = 1;
1458 
1459  mutt_buffer_init(&stripped);
1460  mutt_buffer_alloc(&stripped, *blen);
1461  mutt_buffer_strip_formatting(&stripped, (const char *) *buf, 1);
1462  /* This should be a noop, because *fmt should be NULL */
1463  FREE(fmt);
1464  *fmt = (unsigned char *) stripped.data;
1465  }
1466 
1467  return b_read;
1468 }
String manipulation buffer.
Definition: buffer.h:33
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
void mutt_buffer_strip_formatting(struct Buffer *dest, const char *src, bool strip_markers)
Removes ANSI and backspace formatting.
Definition: pager.c:1384
#define FREE(x)
Definition: memory.h:40
#define MUTT_EOL
don&#39;t strip \n / \r\n
Definition: file.h:38
struct Buffer * mutt_buffer_init(struct Buffer *buf)
Initialise a new Buffer.
Definition: buffer.c:46
void mutt_buffer_alloc(struct Buffer *buf, size_t new_size)
Make sure a buffer can store at least new_size bytes.
Definition: buffer.c:265
+ 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 1485 of file pager.c.

1488 {
1489  int space = -1; /* index of the last space or TAB */
1490  int col = C_Markers ? (*line_info)[n].continuation : 0;
1491  size_t k;
1492  int ch, vch, last_special = -1, special = 0, t;
1493  wchar_t wc;
1494  mbstate_t mbstate;
1495  int wrap_cols = mutt_window_wrap_cols(width, (flags & MUTT_PAGER_NOWRAP) ? 0 : C_Wrap);
1496 
1497  if (check_attachment_marker((char *) buf) == 0)
1498  wrap_cols = width;
1499 
1500  /* FIXME: this should come from line_info */
1501  memset(&mbstate, 0, sizeof(mbstate));
1502 
1503  for (ch = 0, vch = 0; ch < cnt; ch += k, vch += k)
1504  {
1505  /* Handle ANSI sequences */
1506  while ((cnt - ch >= 2) && (buf[ch] == '\033') && (buf[ch + 1] == '[') && // Escape
1507  is_ansi((char *) buf + ch + 2))
1508  {
1509  ch = grok_ansi(buf, ch + 2, pa) + 1;
1510  }
1511 
1512  while ((cnt - ch >= 2) && (buf[ch] == '\033') && (buf[ch + 1] == ']') && // Escape
1513  ((check_attachment_marker((char *) buf + ch) == 0) ||
1514  (check_protected_header_marker((char *) buf + ch) == 0)))
1515  {
1516  while (buf[ch++] != '\a')
1517  if (ch >= cnt)
1518  break;
1519  }
1520 
1521  /* is anything left to do? */
1522  if (ch >= cnt)
1523  break;
1524 
1525  k = mbrtowc(&wc, (char *) buf + ch, cnt - ch, &mbstate);
1526  if ((k == (size_t)(-2)) || (k == (size_t)(-1)))
1527  {
1528  if (k == (size_t)(-1))
1529  memset(&mbstate, 0, sizeof(mbstate));
1530  mutt_debug(LL_DEBUG1, "mbrtowc returned %lu; errno = %d\n", k, errno);
1531  if (col + 4 > wrap_cols)
1532  break;
1533  col += 4;
1534  if (pa)
1535  mutt_window_printf("\\%03o", buf[ch]);
1536  k = 1;
1537  continue;
1538  }
1539  if (k == 0)
1540  k = 1;
1541 
1542  if (CharsetIsUtf8)
1543  {
1544  /* zero width space, zero width no-break space */
1545  if ((wc == 0x200B) || (wc == 0xFEFF))
1546  {
1547  mutt_debug(LL_DEBUG3, "skip zero-width character U+%04X\n", (unsigned short) wc);
1548  continue;
1549  }
1551  {
1552  mutt_debug(LL_DEBUG3, "filtered U+%04X\n", (unsigned short) wc);
1553  continue;
1554  }
1555  }
1556 
1557  /* Handle backspace */
1558  special = 0;
1559  if (IsWPrint(wc))
1560  {
1561  wchar_t wc1;
1562  mbstate_t mbstate1 = mbstate;
1563  size_t k1 = mbrtowc(&wc1, (char *) buf + ch + k, cnt - ch - k, &mbstate1);
1564  while ((k1 != (size_t)(-2)) && (k1 != (size_t)(-1)) && (k1 > 0) && (wc1 == '\b'))
1565  {
1566  const size_t k2 =
1567  mbrtowc(&wc1, (char *) buf + ch + k + k1, cnt - ch - k - k1, &mbstate1);
1568  if ((k2 == (size_t)(-2)) || (k2 == (size_t)(-1)) || (k2 == 0) || (!IsWPrint(wc1)))
1569  break;
1570 
1571  if (wc == wc1)
1572  {
1573  special |= ((wc == '_') && (special & A_UNDERLINE)) ? A_UNDERLINE : A_BOLD;
1574  }
1575  else if ((wc == '_') || (wc1 == '_'))
1576  {
1577  special |= A_UNDERLINE;
1578  wc = (wc1 == '_') ? wc : wc1;
1579  }
1580  else
1581  {
1582  /* special = 0; / * overstrike: nothing to do! */
1583  wc = wc1;
1584  }
1585 
1586  ch += k + k1;
1587  k = k2;
1588  mbstate = mbstate1;
1589  k1 = mbrtowc(&wc1, (char *) buf + ch + k, cnt - ch - k, &mbstate1);
1590  }
1591  }
1592 
1593  if (pa && ((flags & (MUTT_SHOWCOLOR | MUTT_SEARCH | MUTT_PAGER_MARKER)) ||
1594  special || last_special || pa->attr))
1595  {
1596  resolve_color(*line_info, n, vch, flags, special, pa);
1597  last_special = special;
1598  }
1599 
1600  /* no-break space, narrow no-break space */
1601  if (IsWPrint(wc) || (CharsetIsUtf8 && ((wc == 0x00A0) || (wc == 0x202F))))
1602  {
1603  if (wc == ' ')
1604  {
1605  space = ch;
1606  }
1607  t = wcwidth(wc);
1608  if (col + t > wrap_cols)
1609  break;
1610  col += t;
1611  if (pa)
1612  mutt_addwch(wc);
1613  }
1614  else if (wc == '\n')
1615  break;
1616  else if (wc == '\t')
1617  {
1618  space = ch;
1619  t = (col & ~7) + 8;
1620  if (t > wrap_cols)
1621  break;
1622  if (pa)
1623  for (; col < t; col++)
1624  mutt_window_addch(' ');
1625  else
1626  col = t;
1627  }
1628  else if ((wc < 0x20) || (wc == 0x7f))
1629  {
1630  if (col + 2 > wrap_cols)
1631  break;
1632  col += 2;
1633  if (pa)
1634  mutt_window_printf("^%c", ('@' + wc) & 0x7f);
1635  }
1636  else if (wc < 0x100)
1637  {
1638  if (col + 4 > wrap_cols)
1639  break;
1640  col += 4;
1641  if (pa)
1642  mutt_window_printf("\\%03o", wc);
1643  }
1644  else
1645  {
1646  if (col + 1 > wrap_cols)
1647  break;
1648  col += k;
1649  if (pa)
1651  }
1652  }
1653  *pspace = space;
1654  *pcol = col;
1655  *pvch = vch;
1656  *pspecial = special;
1657  return ch;
1658 }
static int check_protected_header_marker(const char *p)
Check that the unique marker is present.
Definition: pager.c:950
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
static bool is_ansi(const char *str)
Is this an ANSI escape sequence?
Definition: pager.c:1272
#define MUTT_PAGER_NOWRAP
Format for term width, ignore $wrap.
Definition: pager.h:56
AnsiFlags attr
Attributes, e.g. underline, bold, etc.
Definition: pager.c:151
WHERE short C_Wrap
Config: Width to wrap text in the pager.
Definition: mutt_globals.h:116
wchar_t ReplacementChar
When a Unicode character can&#39;t be displayed, use this instead.
Definition: charset.c:58
int mutt_window_wrap_cols(int width, short wrap)
Calculate the wrap column for a given screen width.
Definition: mutt_window.c:487
WHERE bool C_Markers
Config: Display a &#39;+&#39; at the beginning of wrapped lines in the pager.
Definition: mutt_globals.h:150
bool CharsetIsUtf8
Is the user&#39;s current character set utf-8?
Definition: charset.c:63
int mutt_window_printf(const char *fmt,...)
Write a formatted string to a Window.
Definition: mutt_window.c:560
int mutt_window_addch(int ch)
Write one character to a Window.
Definition: mutt_window.c:502
#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:1286
Log at debug level 1.
Definition: logging.h:40
#define MUTT_PAGER_MARKER
Use markers if option is set.
Definition: pager.h:53
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
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:381
static int check_attachment_marker(const char *p)
Check that the unique marker is present.
Definition: pager.c:940
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:1059
+ 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 1678 of file pager.c.

1682 {
1683  unsigned char *buf = NULL, *fmt = NULL;
1684  size_t buflen = 0;
1685  unsigned char *buf_ptr = NULL;
1686  int ch, vch, col, cnt, b_read;
1687  int buf_ready = 0;
1688  bool change_last = false;
1689  int special;
1690  int offset;
1691  int def_color;
1692  int m;
1693  int rc = -1;
1694  struct AnsiAttr a = { 0, 0, 0, -1 };
1695  regmatch_t pmatch[1];
1696 
1697  if (n == *last)
1698  {
1699  (*last)++;
1700  change_last = true;
1701  }
1702 
1703  if (*last == *max)
1704  {
1705  mutt_mem_realloc(line_info, sizeof(struct Line) * (*max += LINES));
1706  for (ch = *last; ch < *max; ch++)
1707  {
1708  memset(&((*line_info)[ch]), 0, sizeof(struct Line));
1709  (*line_info)[ch].type = -1;
1710  (*line_info)[ch].search_cnt = -1;
1711  (*line_info)[ch].syntax = mutt_mem_malloc(sizeof(struct TextSyntax));
1712  ((*line_info)[ch].syntax)[0].first = -1;
1713  ((*line_info)[ch].syntax)[0].last = -1;
1714  }
1715  }
1716 
1717  struct Line *const curr_line = &(*line_info)[n];
1718 
1719  if (flags & MUTT_PAGER_LOGS)
1720  {
1721  /* determine the line class */
1722  if (fill_buffer(fp, last_pos, curr_line->offset, &buf, &fmt, &buflen, &buf_ready) < 0)
1723  {
1724  if (change_last)
1725  (*last)--;
1726  goto out;
1727  }
1728 
1729  curr_line->type = MT_COLOR_MESSAGE_LOG;
1730  if (buf[11] == 'M')
1731  curr_line->syntax[0].color = MT_COLOR_MESSAGE;
1732  else if (buf[11] == 'W')
1733  curr_line->syntax[0].color = MT_COLOR_WARNING;
1734  else if (buf[11] == 'E')
1735  curr_line->syntax[0].color = MT_COLOR_ERROR;
1736  else
1737  curr_line->syntax[0].color = MT_COLOR_NORMAL;
1738  }
1739 
1740  /* only do color highlighting if we are viewing a message */
1741  if (flags & (MUTT_SHOWCOLOR | MUTT_TYPES))
1742  {
1743  if (curr_line->type == -1)
1744  {
1745  /* determine the line class */
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  resolve_types((char *) fmt, (char *) buf, *line_info, n, *last,
1754  quote_list, q_level, force_redraw, flags & MUTT_SHOWCOLOR);
1755 
1756  /* avoid race condition for continuation lines when scrolling up */
1757  for (m = n + 1; m < *last && (*line_info)[m].offset && (*line_info)[m].continuation; m++)
1758  (*line_info)[m].type = curr_line->type;
1759  }
1760 
1761  /* this also prevents searching through the hidden lines */
1762  if ((flags & MUTT_HIDE) && (curr_line->type == MT_COLOR_QUOTED) &&
1763  ((curr_line->quote == NULL) || (curr_line->quote->index >= C_ToggleQuotedShowLevels)))
1764  {
1765  flags = 0; /* MUTT_NOSHOW */
1766  }
1767  }
1768 
1769  /* At this point, (*line_info[n]).quote may still be undefined. We
1770  * don't want to compute it every time MUTT_TYPES is set, since this
1771  * would slow down the "bottom" function unacceptably. A compromise
1772  * solution is hence to call regexec() again, just to find out the
1773  * length of the quote prefix. */
1774  if ((flags & MUTT_SHOWCOLOR) && !curr_line->continuation &&
1775  (curr_line->type == MT_COLOR_QUOTED) && !curr_line->quote)
1776  {
1777  if (fill_buffer(fp, last_pos, curr_line->offset, &buf, &fmt, &buflen, &buf_ready) < 0)
1778  {
1779  if (change_last)
1780  (*last)--;
1781  goto out;
1782  }
1783 
1784  if (mutt_regex_capture(C_QuoteRegex, (char *) fmt, 1, pmatch))
1785  {
1786  curr_line->quote =
1787  classify_quote(quote_list, (char *) fmt + pmatch[0].rm_so,
1788  pmatch[0].rm_eo - pmatch[0].rm_so, force_redraw, q_level);
1789  }
1790  else
1791  {
1792  goto out;
1793  }
1794  }
1795 
1796  if ((flags & MUTT_SEARCH) && !curr_line->continuation && (curr_line->search_cnt == -1))
1797  {
1798  if (fill_buffer(fp, last_pos, curr_line->offset, &buf, &fmt, &buflen, &buf_ready) < 0)
1799  {
1800  if (change_last)
1801  (*last)--;
1802  goto out;
1803  }
1804 
1805  offset = 0;
1806  curr_line->search_cnt = 0;
1807  while (regexec(search_re, (char *) fmt + offset, 1, pmatch,
1808  (offset ? REG_NOTBOL : 0)) == 0)
1809  {
1810  if (++(curr_line->search_cnt) > 1)
1811  {
1812  mutt_mem_realloc(&(curr_line->search),
1813  (curr_line->search_cnt) * sizeof(struct TextSyntax));
1814  }
1815  else
1816  curr_line->search = mutt_mem_malloc(sizeof(struct TextSyntax));
1817  pmatch[0].rm_so += offset;
1818  pmatch[0].rm_eo += offset;
1819  (curr_line->search)[curr_line->search_cnt - 1].first = pmatch[0].rm_so;
1820  (curr_line->search)[curr_line->search_cnt - 1].last = pmatch[0].rm_eo;
1821 
1822  if (pmatch[0].rm_eo == pmatch[0].rm_so)
1823  offset++; /* avoid degenerate cases */
1824  else
1825  offset = pmatch[0].rm_eo;
1826  if (!fmt[offset])
1827  break;
1828  }
1829  }
1830 
1831  if (!(flags & MUTT_SHOW) && ((*line_info)[n + 1].offset > 0))
1832  {
1833  /* we've already scanned this line, so just exit */
1834  rc = 0;
1835  goto out;
1836  }
1837  if ((flags & MUTT_SHOWCOLOR) && *force_redraw && ((*line_info)[n + 1].offset > 0))
1838  {
1839  /* no need to try to display this line... */
1840  rc = 1;
1841  goto out; /* fake display */
1842  }
1843 
1844  b_read = fill_buffer(fp, last_pos, curr_line->offset, &buf, &fmt, &buflen, &buf_ready);
1845  if (b_read < 0)
1846  {
1847  if (change_last)
1848  (*last)--;
1849  goto out;
1850  }
1851 
1852  /* now chose a good place to break the line */
1853  cnt = format_line(line_info, n, buf, flags, NULL, b_read, &ch, &vch, &col,
1854  &special, win_pager->state.cols);
1855  buf_ptr = buf + cnt;
1856 
1857  /* move the break point only if smart_wrap is set */
1858  if (C_SmartWrap)
1859  {
1860  if ((cnt < b_read) && (ch != -1) && !IS_HEADER(curr_line->type) && !IS_SPACE(buf[cnt]))
1861  {
1862  buf_ptr = buf + ch;
1863  /* skip trailing blanks */
1864  while (ch && ((buf[ch] == ' ') || (buf[ch] == '\t') || (buf[ch] == '\r')))
1865  ch--;
1866  /* A very long word with leading spaces causes infinite
1867  * wrapping when MUTT_PAGER_NSKIP is set. A folded header
1868  * with a single long word shouldn't be smartwrapped
1869  * either. So just disable smart_wrap if it would wrap at the
1870  * beginning of the line. */
1871  if (ch == 0)
1872  buf_ptr = buf + cnt;
1873  else
1874  cnt = ch + 1;
1875  }
1876  if (!(flags & MUTT_PAGER_NSKIP))
1877  {
1878  /* skip leading blanks on the next line too */
1879  while ((*buf_ptr == ' ') || (*buf_ptr == '\t'))
1880  buf_ptr++;
1881  }
1882  }
1883 
1884  if (*buf_ptr == '\r')
1885  buf_ptr++;
1886  if (*buf_ptr == '\n')
1887  buf_ptr++;
1888 
1889  if (((int) (buf_ptr - buf) < b_read) && !(*line_info)[n + 1].continuation)
1890  append_line(*line_info, n, (int) (buf_ptr - buf));
1891  (*line_info)[n + 1].offset = curr_line->offset + (long) (buf_ptr - buf);
1892 
1893  /* if we don't need to display the line we are done */
1894  if (!(flags & MUTT_SHOW))
1895  {
1896  rc = 0;
1897  goto out;
1898  }
1899 
1900  /* display the line */
1901  format_line(line_info, n, buf, flags, &a, cnt, &ch, &vch, &col, &special,
1902  win_pager->state.cols);
1903 
1904 /* avoid a bug in ncurses... */
1905 #ifndef USE_SLANG_CURSES
1906  if (col == 0)
1907  {
1909  mutt_window_addch(' ');
1910  }
1911 #endif
1912 
1913  /* end the last color pattern (needed by S-Lang) */
1914  if (special || ((col != win_pager->state.cols) && (flags & (MUTT_SHOWCOLOR | MUTT_SEARCH))))
1915  resolve_color(*line_info, n, vch, flags, 0, &a);
1916 
1917  /* Fill the blank space at the end of the line with the prevailing color.
1918  * ncurses does an implicit clrtoeol() when you do mutt_window_addch('\n') so we have
1919  * to make sure to reset the color *after* that */
1920  if (flags & MUTT_SHOWCOLOR)
1921  {
1922  m = (curr_line->continuation) ? (curr_line->syntax)[0].first : n;
1923  if ((*line_info)[m].type == MT_COLOR_HEADER)
1924  def_color = ((*line_info)[m].syntax)[0].color;
1925  else
1926  def_color = Colors->defs[(*line_info)[m].type];
1927 
1928  mutt_curses_set_attr(def_color);
1929  }
1930 
1931  if (col < win_pager->state.cols)
1932  mutt_window_clrtoeol(win_pager);
1933 
1934  /* reset the color back to normal. This *must* come after the
1935  * clrtoeol, otherwise the color for this line will not be
1936  * filled to the right margin. */
1937  if (flags & MUTT_SHOWCOLOR)
1939 
1940  /* build a return code */
1941  if (!(flags & MUTT_SHOW))
1942  flags = 0;
1943 
1944  rc = flags;
1945 
1946 out:
1947  FREE(&buf);
1948  FREE(&fmt);
1949  return rc;
1950 }
#define MUTT_TYPES
Compute line&#39;s type.
Definition: pager.h:48
Informational message.
Definition: color.h:75
#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:57
int * defs
Array of all fixed colours, see enum ColorId.
Definition: color.h:131
void mutt_window_clrtoeol(struct MuttWindow *win)
Clear to the end of the line.
Definition: mutt_window.c:254
An ANSI escape sequence.
Definition: pager.c:149
short type
Definition: pager.c:136
Pager: quoted text.
Definition: color.h:81
Menu showing log messages.
Definition: color.h:76
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:1006
Message headers (takes a pattern)
Definition: color.h:72
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:1485
short continuation
Definition: pager.c:137
#define MUTT_PAGER_NSKIP
Preserve whitespace with smartwrap.
Definition: pager.h:52
#define MUTT_SHOW
Definition: pager.h:49
Plain text.
Definition: color.h:77
WHERE int C_ToggleQuotedShowLevels
Config: Number of quote levels to show with toggle-quoted.
Definition: mutt_globals.h:121
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:57
struct QClass * quote
Definition: pager.c:142
short search_cnt
Definition: pager.c:139
struct TextSyntax * search
Definition: pager.c:141
struct WindowState state
Current state of the Window.
Definition: mutt_window.h:120
WHERE struct Regex * C_QuoteRegex
Config: Regex to match quoted text in a reply.
Definition: mutt_globals.h:120
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:90
#define IS_HEADER(x)
Definition: pager.c:271
A line of text in the pager.
Definition: pager.c:133
#define MUTT_HIDE
Don&#39;t show quoted text.
Definition: pager.h:46
Definition: color.h:129
#define MUTT_PAGER_LOGS
Logview mode.
Definition: pager.h:57
bool C_SmartWrap
Config: Wrap text at word boundaries.
Definition: pager.c:91
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:593
#define IS_SPACE(ch)
Definition: string2.h:38
Highlighting for a line of text.
Definition: pager.c:123
int mutt_window_addch(int ch)
Write one character to a Window.
Definition: mutt_window.c:502
#define MUTT_SEARCH
Resolve search patterns.
Definition: pager.h:47
Error message.
Definition: color.h:70
#define FREE(x)
Definition: memory.h:40
int index
Definition: pager.c:113
struct TextSyntax * syntax
Definition: pager.c:140
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:1437
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:612
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:381
LOFF_T offset
Definition: pager.c:135
static void append_line(struct Line *line_info, int n, int cnt)
Add a new Line to the array.
Definition: pager.c:513
Warning messages.
Definition: color.h:98
int color
Definition: pager.c:125
+ 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 1960 of file pager.c.

1961 {
1962  while ((cur > 0) && (nlines > 0))
1963  {
1964  cur--;
1965  if (!hiding || (info[cur].type != MT_COLOR_QUOTED))
1966  nlines--;
1967  }
1968 
1969  return cur;
1970 }
short type
Definition: pager.c:136
Pager: quoted text.
Definition: color.h:81
+ 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 1975 of file pager.c.

1976 {
1977  TopLine = 0;
1978  OldEmail = NULL;
1979 }
static int TopLine
Definition: pager.c:202
static struct Email * OldEmail
Definition: pager.c:203
+ 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 1984 of file pager.c.

1985 {
1986  struct PagerRedrawData *rd = pager_menu->redraw_data;
1987  char buf[1024];
1988 
1989  if (!rd)
1990  return;
1991 
1992  if (pager_menu->redraw & REDRAW_FULL)
1993  {
1995  /* clear() doesn't optimize screen redraws */
1996  mutt_window_move_abs(0, 0);
1998 
1999  if (IsEmail(rd->extra) && Context && Context->mailbox &&
2001  {
2002  rd->indexlen = Context->mailbox->vcount + 1;
2003  }
2004  else
2006 
2007  rd->indicator = rd->indexlen / 3;
2008 
2009  if (Resize)
2010  {
2012  if (rd->search_compiled)
2013  {
2014  int flags = mutt_mb_is_lower(rd->searchbuf) ? REG_ICASE : 0;
2015  const int err = REG_COMP(&rd->search_re, rd->searchbuf, REG_NEWLINE | flags);
2016  if (err == 0)
2017  {
2018  rd->search_flag = MUTT_SEARCH;
2020  }
2021  else
2022  {
2023  regerror(err, &rd->search_re, buf, sizeof(buf));
2024  mutt_error("%s", buf);
2025  rd->search_compiled = false;
2026  }
2027  }
2028  rd->lines = Resize->line;
2029  pager_menu->redraw |= REDRAW_FLOW;
2030 
2031  FREE(&Resize);
2032  }
2033 
2034  if (IsEmail(rd->extra) && (C_PagerIndexLines != 0))
2035  {
2036  if (!rd->menu)
2037  {
2038  /* only allocate the space if/when we need the index.
2039  * Initialise the menu as per the main index */
2040  rd->menu = mutt_menu_new(MENU_MAIN);
2042  rd->menu->color = index_color;
2043  rd->menu->max = Context ? Context->mailbox->vcount : 0;
2044  rd->menu->current = rd->extra->email->vnum;
2045  rd->menu->win_index = rd->extra->win_index;
2046  rd->menu->win_ibar = rd->extra->win_ibar;
2047  }
2048 
2050  rd->menu->pagelen = rd->extra->win_index->state.rows;
2051 
2052  /* some fudge to work out whereabouts the indicator should go */
2053  if (rd->menu->current - rd->indicator < 0)
2054  rd->menu->top = 0;
2055  else if (rd->menu->max - rd->menu->current < rd->menu->pagelen - rd->indicator)
2056  rd->menu->top = rd->menu->max - rd->menu->pagelen;
2057  else
2058  rd->menu->top = rd->menu->current - rd->indicator;
2059 
2060  menu_redraw_index(rd->menu);
2061  }
2062 
2063  pager_menu->redraw |= REDRAW_BODY | REDRAW_INDEX | REDRAW_STATUS;
2064  mutt_show_error();
2065  }
2066 
2067  if (pager_menu->redraw & REDRAW_FLOW)
2068  {
2069  if (!(rd->flags & MUTT_PAGER_RETWINCH))
2070  {
2071  rd->lines = -1;
2072  for (int i = 0; i <= rd->topline; i++)
2073  if (!rd->line_info[i].continuation)
2074  rd->lines++;
2075  for (int i = 0; i < rd->max_line; i++)
2076  {
2077  rd->line_info[i].offset = 0;
2078  rd->line_info[i].type = -1;
2079  rd->line_info[i].continuation = 0;
2080  rd->line_info[i].chunks = 0;
2081  rd->line_info[i].search_cnt = -1;
2082  rd->line_info[i].quote = NULL;
2083 
2084  mutt_mem_realloc(&(rd->line_info[i].syntax), sizeof(struct TextSyntax));
2085  if (rd->search_compiled && rd->line_info[i].search)
2086  FREE(&(rd->line_info[i].search));
2087  }
2088 
2089  rd->last_line = 0;
2090  rd->topline = 0;
2091  }
2092  int i = -1;
2093  int j = -1;
2094  while (display_line(rd->fp, &rd->last_pos, &rd->line_info, ++i, &rd->last_line,
2095  &rd->max_line, rd->has_types | rd->search_flag | (rd->flags & MUTT_PAGER_NOWRAP),
2096  &rd->quote_list, &rd->q_level, &rd->force_redraw,
2097  &rd->search_re, rd->extra->win_pager) == 0)
2098  {
2099  if (!rd->line_info[i].continuation && (++j == rd->lines))
2100  {
2101  rd->topline = i;
2102  if (!rd->search_flag)
2103  break;
2104  }
2105  }
2106  }
2107 
2108  if ((pager_menu->redraw & REDRAW_BODY) || (rd->topline != rd->oldtopline))
2109  {
2110  do
2111  {
2112  mutt_window_move(rd->extra->win_pager, 0, 0);
2113  rd->curline = rd->topline;
2114  rd->oldtopline = rd->topline;
2115  rd->lines = 0;
2116  rd->force_redraw = false;
2117 
2118  while ((rd->lines < rd->extra->win_pager->state.rows) &&
2119  (rd->line_info[rd->curline].offset <= rd->sb.st_size - 1))
2120  {
2121  if (display_line(rd->fp, &rd->last_pos, &rd->line_info, rd->curline,
2122  &rd->last_line, &rd->max_line,
2123  (rd->flags & MUTT_DISPLAYFLAGS) | rd->hide_quoted |
2124  rd->search_flag | (rd->flags & MUTT_PAGER_NOWRAP),
2125  &rd->quote_list, &rd->q_level, &rd->force_redraw,
2126  &rd->search_re, rd->extra->win_pager) > 0)
2127  {
2128  rd->lines++;
2129  }
2130  rd->curline++;
2131  mutt_window_move(rd->extra->win_pager, 0, rd->lines);
2132  }
2133  rd->last_offset = rd->line_info[rd->curline].offset;
2134  } while (rd->force_redraw);
2135 
2137  while (rd->lines < rd->extra->win_pager->state.rows)
2138  {
2140  if (C_Tilde)
2141  mutt_window_addch('~');
2142  rd->lines++;
2143  mutt_window_move(rd->extra->win_pager, 0, rd->lines);
2144  }
2146 
2147  /* We are going to update the pager status bar, so it isn't
2148  * necessary to reset to normal color now. */
2149 
2150  pager_menu->redraw |= REDRAW_STATUS; /* need to update the % seen */
2151  }
2152 
2153  struct Mailbox *m = Context ? Context->mailbox : NULL;
2154  if (pager_menu->redraw & REDRAW_STATUS)
2155  {
2156  struct HdrFormatInfo hfi;
2157  char pager_progress_str[65]; /* Lots of space for translations */
2158 
2159  hfi.mailbox = m;
2160  hfi.msg_in_pager = Context ? Context->msg_in_pager : -1;
2161  hfi.pager_progress = pager_progress_str;
2162 
2163  if (rd->last_pos < rd->sb.st_size - 1)
2164  {
2165  snprintf(pager_progress_str, sizeof(pager_progress_str), OFF_T_FMT "%%",
2166  (100 * rd->last_offset / rd->sb.st_size));
2167  }
2168  else
2169  {
2170  const char *msg = (rd->topline == 0) ?
2171  /* L10N: Status bar message: the entire email is visible in the pager */
2172  _("all") :
2173  /* L10N: Status bar message: the end of the email is visible in the pager */
2174  _("end");
2175  mutt_str_copy(pager_progress_str, msg, sizeof(pager_progress_str));
2176  }
2177 
2178  /* print out the pager status bar */
2179  mutt_window_move(rd->extra->win_pbar, 0, 0);
2181 
2182  if (IsEmail(rd->extra) || IsMsgAttach(rd->extra))
2183  {
2184  size_t l1 = rd->extra->win_pbar->state.cols * MB_LEN_MAX;
2185  size_t l2 = sizeof(buf);
2186  hfi.email = (IsEmail(rd->extra)) ? rd->extra->email : rd->extra->body->email;
2187  mutt_make_string_info(buf, (l1 < l2) ? l1 : l2, rd->extra->win_pbar->state.cols,
2189  mutt_draw_statusline(rd->extra->win_pbar->state.cols, buf, l2);
2190  }
2191  else
2192  {
2193  char bn[256];
2194  snprintf(bn, sizeof(bn), "%s (%s)", rd->banner, pager_progress_str);
2195  mutt_draw_statusline(rd->extra->win_pbar->state.cols, bn, sizeof(bn));
2196  }
2198  if (C_TsEnabled && TsSupported && rd->menu)
2199  {
2200  menu_status_line(buf, sizeof(buf), rd->menu, m, NONULL(C_TsStatusFormat));
2201  mutt_ts_status(buf);
2202  menu_status_line(buf, sizeof(buf), rd->menu, m, NONULL(C_TsIconFormat));
2203  mutt_ts_icon(buf);
2204  }
2205  }
2206 
2207  if ((pager_menu->redraw & REDRAW_INDEX) && rd->menu)
2208  {
2209  /* redraw the pager_index indicator, because the
2210  * flags for this message might have changed. */
2211  if (rd->extra->win_index->state.rows > 0)
2213 
2214  /* print out the index status bar */
2215  menu_status_line(buf, sizeof(buf), rd->menu, m, NONULL(C_StatusFormat));
2216 
2217  mutt_window_move(rd->extra->win_ibar, 0, 0);
2219  mutt_draw_statusline(rd->extra->win_ibar->state.cols, buf, sizeof(buf));
2221  }
2222 
2223  pager_menu->redraw = REDRAW_NO_FLAGS;
2224 }
struct Menu * menu
the Pager Index (PI)
Definition: pager.c:189
The "current" mailbox.
Definition: context.h:38
struct MuttWindow * win_index
Definition: pager.h:74
#define REDRAW_FULL
Redraw everything.
Definition: mutt_menu.h:45
#define NONULL(x)
Definition: string2.h:37
int msg_in_pager
Message currently shown in the pager.
Definition: context.h:44
const char * banner
Definition: pager.c:194
PagerFlags hide_quoted
Definition: pager.c:184
PagerFlags search_flag
Definition: pager.c:192
#define MUTT_DISPLAYFLAGS
Definition: pager.h:60
short chunks
Definition: pager.c:138
Keep track when the pager needs redrawing.
Definition: pager.c:170
WHERE char * C_TsIconFormat
Config: printf-like format string for the terminal&#39;s icon title.
Definition: mutt_globals.h:111
void mutt_curses_set_color(enum ColorId color)
Set the current colour for text.
Definition: mutt_curses.c:57
#define REDRAW_FLOW
Used by pager to reflow text.
Definition: mutt_menu.h:47
void mutt_window_clrtoeol(struct MuttWindow *win)
Clear to the end of the line.
Definition: mutt_window.c:254
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:856
#define IsMsgAttach(pager)
Definition: pager.c:274
#define _(a)
Definition: message.h:28
struct Line * line_info
Definition: pager.c:196
int index_color(int line)
Calculate the colour for a line of the index - Implements Menu::color()
Definition: index.c:932
#define REG_COMP(preg, regex, cflags)
Compile a regular expression.
Definition: regex3.h:53
struct Body * body
Current attachment.
Definition: pager.h:69
void mutt_window_move_abs(int col, int row)
Move the cursor to an absolute screen position.
Definition: mutt_window.c:549
PagerFlags flags
Definition: pager.c:172
Index panel (list of emails)
Definition: keymap.h:80
bool search_back
Definition: pager.c:164
bool search_compiled
Definition: pager.c:163
short type
Definition: pager.c:136
#define MUTT_PAGER_NOWRAP
Format for term width, ignore $wrap.
Definition: pager.h:56
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:1678
#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
LOFF_T last_pos
Definition: pager.c:187
int mutt_window_move(struct MuttWindow *win, int col, int row)
Move the cursor in a Window.
Definition: mutt_window.c:392
int line
Definition: pager.c:162
void * redraw_data
Definition: mutt_menu.h:123
Pager: empty lines after message.
Definition: color.h:95
struct Mailbox * mailbox
Definition: context.h:50
Data passed to index_format_str()
Definition: hdrline.h:44
int indexlen
Definition: pager.c:174
struct MuttWindow * win_ibar
Definition: mutt_menu.h:64
LOFF_T last_offset
Definition: pager.c:188
int has_types
Definition: pager.c:183
FILE * fp
Definition: pager.c:197
struct Mailbox * mailbox
Definition: hdrline.h:46
short continuation
Definition: pager.c:137
WHERE char * C_StatusFormat
Config: printf-like format string for the index&#39;s status line.
Definition: mutt_globals.h:109
void mutt_window_clrtobot(void)
Clear to the bottom of the Window.
Definition: mutt_window.c:243
bool force_redraw
Definition: pager.c:182
Plain text.
Definition: color.h:77
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
void menu_status_line(char *buf, size_t buflen, struct Menu *menu, struct Mailbox *m, const char *p)
Create the status line.
Definition: status.c:421
short cols
Number of columns, can be MUTT_WIN_SIZE_UNLIMITED.
Definition: mutt_window.h:57
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:1426
int oldtopline
Definition: pager.c:176
struct Pager * extra
Definition: pager.c:173
struct QClass * quote
Definition: pager.c:142
short search_cnt
Definition: pager.c:139
struct TextSyntax * search
Definition: pager.c:141
struct WindowState state
Current state of the Window.
Definition: mutt_window.h:120
#define REDRAW_STATUS
Redraw the status bar.
Definition: mutt_menu.h:44
bool search_compiled
Definition: pager.c:191
int(* color)(int line)
Calculate the colour for a line of the menu.
Definition: mutt_menu.h:115
Status bar (takes a pattern)
Definition: color.h:94
A mailbox.
Definition: mailbox.h:81
WHERE bool C_TsEnabled
Config: Allow NeoMutt to set the terminal status line and icon.
Definition: mutt_globals.h:166
short rows
Number of rows, can be MUTT_WIN_SIZE_UNLIMITED.
Definition: mutt_window.h:58
int top
Entry that is the top of the current page.
Definition: mutt_menu.h:75
int max_line
Definition: pager.c:178
int last_line
Definition: pager.c:179
int vnum
Virtual message number.
Definition: email.h:88
int pagelen
Number of entries per screen.
Definition: mutt_menu.h:60
bool TsSupported
Terminal Setting is supported.
Definition: terminal.c:43
WHERE char * C_TsStatusFormat
Config: printf-like format string for the terminal&#39;s status (window title)
Definition: mutt_globals.h:110
int max
Number of entries in the menu.
Definition: mutt_menu.h:57
MuttRedrawFlags redraw
When to redraw the screen.
Definition: mutt_menu.h:58
struct QClass * quote_list
Definition: pager.c:186
#define IsEmail(pager)
Definition: pager.c:276
int indicator
the indicator line of the PI
Definition: pager.c:175
struct Email * email
Current message.
Definition: pager.h:68
Highlighting for a line of text.
Definition: pager.c:123
int mutt_window_addch(int ch)
Write one character to a Window.
Definition: mutt_window.c:502
#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:46
char * searchbuf
Definition: pager.c:195
size_t mutt_str_copy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:716
#define REDRAW_INDEX
Redraw the index.
Definition: mutt_menu.h:40
#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:93
struct TextSyntax * syntax
Definition: pager.c:140
void mutt_show_error(void)
Show the user an error message.
Definition: curs_lib.c:557
struct MuttWindow * win_ibar
Definition: pager.h:73
Keep track of screen resizing.
Definition: pager.c:160
void mutt_ts_status(char *str)
Set the text of the terminal title bar.
Definition: terminal.c:104
struct stat sb
Definition: pager.c:198
int current
Current entry.
Definition: mutt_menu.h:56
struct MuttWindow * win_index
Definition: mutt_menu.h:63
WHERE char * C_PagerFormat
Config: printf-like format string for the pager&#39;s status bar.
Definition: mutt_globals.h:100
#define REDRAW_NO_FLAGS
No flags are set.
Definition: mutt_menu.h:39
LOFF_T offset
Definition: pager.c:135
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:88
void mutt_draw_statusline(int cols, const char *buf, size_t buflen)
Draw a highlighted status bar.
Definition: index.c:960
short C_PagerIndexLines
Config: Number of index lines to display above the pager.
Definition: pager.c:87
regex_t search_re
Definition: pager.c:190
bool search_back
Definition: pager.c:193
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 2241 of file pager.c.

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

◆ C_HeaderColorPartial

bool C_HeaderColorPartial

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

Definition at line 85 of file pager.c.

◆ C_PagerContext

short C_PagerContext

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

Definition at line 86 of file pager.c.

◆ C_PagerIndexLines

short C_PagerIndexLines

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

Definition at line 87 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 88 of file pager.c.

◆ C_SearchContext

short C_SearchContext

Config: Context to display around search matches.

Definition at line 89 of file pager.c.

◆ C_SkipQuotedOffset

short C_SkipQuotedOffset

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

Definition at line 90 of file pager.c.

◆ C_SmartWrap

bool C_SmartWrap

Config: Wrap text at word boundaries.

Definition at line 91 of file pager.c.

◆ C_Smileys

struct Regex* C_Smileys

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

Definition at line 92 of file pager.c.

◆ C_Tilde

bool C_Tilde

Config: Character to pad blank lines in the pager.

Definition at line 93 of file pager.c.

◆ TopLine

int TopLine = 0
static

Definition at line 202 of file pager.c.

◆ OldEmail

struct Email* OldEmail = NULL
static

Definition at line 203 of file pager.c.

◆ InHelp

bool InHelp = false
static

Definition at line 205 of file pager.c.

◆ braille_line

int braille_line = -1
static

Definition at line 207 of file pager.c.

◆ braille_col

int braille_col = -1
static

Definition at line 208 of file pager.c.

◆ Resize

struct Resize* Resize = NULL
static

Definition at line 210 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 212 of file pager.c.

◆ Mailbox_is_read_only

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

Definition at line 214 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 215 of file pager.c.

◆ PagerHelp

const struct Mapping PagerHelp[]
static
Initial value:
= {
{ N_("Exit"), OP_EXIT },
{ N_("PrevPg"), OP_PREV_PAGE },
{ N_("NextPg"), OP_NEXT_PAGE },
{ N_("Help"), OP_HELP },
{ NULL, 0 },
}
#define N_(a)
Definition: message.h:32

Help Bar for the Pager's Help Page.

Definition at line 219 of file pager.c.

◆ PagerHelpHelp

const struct Mapping PagerHelpHelp[]
static
Initial value:
= {
{ N_("Exit"), OP_EXIT },
{ N_("PrevPg"), OP_PREV_PAGE },
{ N_("NextPg"), OP_NEXT_PAGE },
{ NULL, 0 },
}
#define N_(a)
Definition: message.h:32

Help Bar for the Help Page itself.

Definition at line 230 of file pager.c.

◆ PagerNormalHelp

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

Help Bar for the Pager of a normal Mailbox.

Definition at line 240 of file pager.c.

◆ PagerNewsHelp

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

Help Bar for the Pager of an NNTP Mailbox.

Definition at line 256 of file pager.c.