NeoMutt  2020-11-20
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:151
#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:492
#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 $quote_regex and doesn't match $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:477
WHERE bool C_Markers
Config: Display a &#39;+&#39; at the beginning of wrapped lines in the pager.
Definition: mutt_globals.h:151
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:550
int mutt_window_addch(int ch)
Write one character to a Window.
Definition: mutt_window.c:492
#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:244
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:492
#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  {
1996 
1997  if (IsEmail(rd->extra) && Context && Context->mailbox &&
1999  {
2000  rd->indexlen = Context->mailbox->vcount + 1;
2001  }
2002  else
2004 
2005  rd->indicator = rd->indexlen / 3;
2006 
2007  if (Resize)
2008  {
2010  if (rd->search_compiled)
2011  {
2012  int flags = mutt_mb_is_lower(rd->searchbuf) ? REG_ICASE : 0;
2013  const int err = REG_COMP(&rd->search_re, rd->searchbuf, REG_NEWLINE | flags);
2014  if (err == 0)
2015  {
2016  rd->search_flag = MUTT_SEARCH;
2018  }
2019  else
2020  {
2021  regerror(err, &rd->search_re, buf, sizeof(buf));
2022  mutt_error("%s", buf);
2023  rd->search_compiled = false;
2024  }
2025  }
2026  rd->lines = Resize->line;
2027  pager_menu->redraw |= REDRAW_FLOW;
2028 
2029  FREE(&Resize);
2030  }
2031 
2032  if (IsEmail(rd->extra) && (C_PagerIndexLines != 0))
2033  {
2034  if (!rd->menu)
2035  {
2036  /* only allocate the space if/when we need the index.
2037  * Initialise the menu as per the main index */
2038  rd->menu = mutt_menu_new(MENU_MAIN);
2040  rd->menu->color = index_color;
2041  rd->menu->max = Context ? Context->mailbox->vcount : 0;
2042  rd->menu->current = rd->extra->email->vnum;
2043  rd->menu->win_index = rd->extra->win_index;
2044  rd->menu->win_ibar = rd->extra->win_ibar;
2045  }
2046 
2048  rd->menu->pagelen = rd->extra->win_index->state.rows;
2049 
2050  /* some fudge to work out whereabouts the indicator should go */
2051  if (rd->menu->current - rd->indicator < 0)
2052  rd->menu->top = 0;
2053  else if (rd->menu->max - rd->menu->current < rd->menu->pagelen - rd->indicator)
2054  rd->menu->top = rd->menu->max - rd->menu->pagelen;
2055  else
2056  rd->menu->top = rd->menu->current - rd->indicator;
2057 
2058  menu_redraw_index(rd->menu);
2059  }
2060 
2061  pager_menu->redraw |= REDRAW_BODY | REDRAW_INDEX | REDRAW_STATUS;
2062  mutt_show_error();
2063  }
2064 
2065  if (pager_menu->redraw & REDRAW_FLOW)
2066  {
2067  if (!(rd->flags & MUTT_PAGER_RETWINCH))
2068  {
2069  rd->lines = -1;
2070  for (int i = 0; i <= rd->topline; i++)
2071  if (!rd->line_info[i].continuation)
2072  rd->lines++;
2073  for (int i = 0; i < rd->max_line; i++)
2074  {
2075  rd->line_info[i].offset = 0;
2076  rd->line_info[i].type = -1;
2077  rd->line_info[i].continuation = 0;
2078  rd->line_info[i].chunks = 0;
2079  rd->line_info[i].search_cnt = -1;
2080  rd->line_info[i].quote = NULL;
2081 
2082  mutt_mem_realloc(&(rd->line_info[i].syntax), sizeof(struct TextSyntax));
2083  if (rd->search_compiled && rd->line_info[i].search)
2084  FREE(&(rd->line_info[i].search));
2085  }
2086 
2087  rd->last_line = 0;
2088  rd->topline = 0;
2089  }
2090  int i = -1;
2091  int j = -1;
2092  while (display_line(rd->fp, &rd->last_pos, &rd->line_info, ++i, &rd->last_line,
2093  &rd->max_line, rd->has_types | rd->search_flag | (rd->flags & MUTT_PAGER_NOWRAP),
2094  &rd->quote_list, &rd->q_level, &rd->force_redraw,
2095  &rd->search_re, rd->extra->win_pager) == 0)
2096  {
2097  if (!rd->line_info[i].continuation && (++j == rd->lines))
2098  {
2099  rd->topline = i;
2100  if (!rd->search_flag)
2101  break;
2102  }
2103  }
2104  }
2105 
2106  if ((pager_menu->redraw & REDRAW_BODY) || (rd->topline != rd->oldtopline))
2107  {
2108  do
2109  {
2110  mutt_window_move(rd->extra->win_pager, 0, 0);
2111  rd->curline = rd->topline;
2112  rd->oldtopline = rd->topline;
2113  rd->lines = 0;
2114  rd->force_redraw = false;
2115 
2116  while ((rd->lines < rd->extra->win_pager->state.rows) &&
2117  (rd->line_info[rd->curline].offset <= rd->sb.st_size - 1))
2118  {
2119  if (display_line(rd->fp, &rd->last_pos, &rd->line_info, rd->curline,
2120  &rd->last_line, &rd->max_line,
2121  (rd->flags & MUTT_DISPLAYFLAGS) | rd->hide_quoted |
2122  rd->search_flag | (rd->flags & MUTT_PAGER_NOWRAP),
2123  &rd->quote_list, &rd->q_level, &rd->force_redraw,
2124  &rd->search_re, rd->extra->win_pager) > 0)
2125  {
2126  rd->lines++;
2127  }
2128  rd->curline++;
2129  mutt_window_move(rd->extra->win_pager, 0, rd->lines);
2130  }
2131  rd->last_offset = rd->line_info[rd->curline].offset;
2132  } while (rd->force_redraw);
2133 
2135  while (rd->lines < rd->extra->win_pager->state.rows)
2136  {
2138  if (C_Tilde)
2139  mutt_window_addch('~');
2140  rd->lines++;
2141  mutt_window_move(rd->extra->win_pager, 0, rd->lines);
2142  }
2144 
2145  /* We are going to update the pager status bar, so it isn't
2146  * necessary to reset to normal color now. */
2147 
2148  pager_menu->redraw |= REDRAW_STATUS; /* need to update the % seen */
2149  }
2150 
2151  struct Mailbox *m = Context ? Context->mailbox : NULL;
2152  if (pager_menu->redraw & REDRAW_STATUS)
2153  {
2154  struct HdrFormatInfo hfi;
2155  char pager_progress_str[65]; /* Lots of space for translations */
2156 
2157  hfi.mailbox = m;
2158  hfi.msg_in_pager = Context ? Context->msg_in_pager : -1;
2159  hfi.pager_progress = pager_progress_str;
2160 
2161  if (rd->last_pos < rd->sb.st_size - 1)
2162  {
2163  snprintf(pager_progress_str, sizeof(pager_progress_str), OFF_T_FMT "%%",
2164  (100 * rd->last_offset / rd->sb.st_size));
2165  }
2166  else
2167  {
2168  const char *msg = (rd->topline == 0) ?
2169  /* L10N: Status bar message: the entire email is visible in the pager */
2170  _("all") :
2171  /* L10N: Status bar message: the end of the email is visible in the pager */
2172  _("end");
2173  mutt_str_copy(pager_progress_str, msg, sizeof(pager_progress_str));
2174  }
2175 
2176  /* print out the pager status bar */
2177  mutt_window_move(rd->extra->win_pbar, 0, 0);
2179 
2180  if (IsEmail(rd->extra) || IsMsgAttach(rd->extra))
2181  {
2182  size_t l1 = rd->extra->win_pbar->state.cols * MB_LEN_MAX;
2183  size_t l2 = sizeof(buf);
2184  hfi.email = (IsEmail(rd->extra)) ? rd->extra->email : rd->extra->body->email;
2185  mutt_make_string_info(buf, (l1 < l2) ? l1 : l2, rd->extra->win_pbar->state.cols,
2187  mutt_draw_statusline(rd->extra->win_pbar->state.cols, buf, l2);
2188  }
2189  else
2190  {
2191  char bn[256];
2192  snprintf(bn, sizeof(bn), "%s (%s)", rd->banner, pager_progress_str);
2193  mutt_draw_statusline(rd->extra->win_pbar->state.cols, bn, sizeof(bn));
2194  }
2196  if (C_TsEnabled && TsSupported && rd->menu)
2197  {
2198  menu_status_line(buf, sizeof(buf), rd->menu, m, NONULL(C_TsStatusFormat));
2199  mutt_ts_status(buf);
2200  menu_status_line(buf, sizeof(buf), rd->menu, m, NONULL(C_TsIconFormat));
2201  mutt_ts_icon(buf);
2202  }
2203  }
2204 
2205  if ((pager_menu->redraw & REDRAW_INDEX) && rd->menu)
2206  {
2207  /* redraw the pager_index indicator, because the
2208  * flags for this message might have changed. */
2209  if (rd->extra->win_index->state.rows > 0)
2211 
2212  /* print out the index status bar */
2213  menu_status_line(buf, sizeof(buf), rd->menu, m, NONULL(C_StatusFormat));
2214 
2215  mutt_window_move(rd->extra->win_ibar, 0, 0);
2217  mutt_draw_statusline(rd->extra->win_ibar->state.cols, buf, sizeof(buf));
2219  }
2220 
2221  pager_menu->redraw = REDRAW_NO_FLAGS;
2222 }
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:244
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:859
#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:935
#define REG_COMP(preg, regex, cflags)
Compile a regular expression.
Definition: regex3.h:53
struct Body * body
Current attachment.
Definition: pager.h:69
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:382
int line
Definition: pager.c:162
void * redraw_data
Definition: mutt_menu.h:123
void mutt_window_clear(struct MuttWindow *win)
Clear a Window.
Definition: mutt_window.c:806
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
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:1438
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:167
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:492
#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:963
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 2239 of file pager.c.

2240 {
2241  static char searchbuf[256] = { 0 };
2242  char buf[1024];
2243  int ch = 0, rc = -1;
2244  bool first = true;
2245  int searchctx = 0;
2246  bool wrapped = false;
2247 
2248  struct Menu *pager_menu = NULL;
2249  int old_PagerIndexLines; /* some people want to resize it while inside the pager */
2250 #ifdef USE_NNTP
2251  char *followup_to = NULL;
2252 #endif
2253 
2254  struct Mailbox *m = Context ? Context->mailbox : NULL;
2255 
2256  if (!(flags & MUTT_SHOWCOLOR))
2257  flags |= MUTT_SHOWFLAT;
2258 
2259  int index_space = C_PagerIndexLines;
2260  if (extra->ctx && extra->ctx->mailbox)
2261  index_space = MIN(index_space, extra->ctx->mailbox->vcount);
2262 
2263  struct PagerRedrawData rd = { 0 };
2264  rd.banner = banner;
2265  rd.flags = flags;
2266  rd.extra = extra;
2267  rd.indexlen = index_space;
2268  rd.indicator = rd.indexlen / 3;
2269  rd.searchbuf = searchbuf;
2270  rd.has_types = (IsEmail(extra) || (flags & MUTT_SHOWCOLOR)) ? MUTT_TYPES : 0; /* main message or rfc822 attachment */
2271 
2272  rd.fp = fopen(fname, "r");
2273  if (!rd.fp)
2274  {
2275  mutt_perror(fname);
2276  return -1;
2277  }
2278 
2279  if (stat(fname, &rd.sb) != 0)
2280  {
2281  mutt_perror(fname);
2282  mutt_file_fclose(&rd.fp);
2283  return -1;
2284  }
2285  unlink(fname);
2286 
2287  if (rd.extra->win_index)
2288  {
2290  rd.extra->win_index->req_rows = index_space;
2292  window_set_visible(rd.extra->win_index->parent, (index_space > 0));
2293  }
2297 
2298  /* Initialize variables */
2299 
2300  if (Context && IsEmail(extra) && !extra->email->read)
2301  {
2302  Context->msg_in_pager = extra->email->msgno;
2303  mutt_set_flag(m, extra->email, MUTT_READ, true);
2304  }
2305 
2306  rd.max_line = LINES; /* number of lines on screen, from curses */
2307  rd.line_info = mutt_mem_calloc(rd.max_line, sizeof(struct Line));
2308  for (size_t i = 0; i < rd.max_line; i++)
2309  {
2310  rd.line_info[i].type = -1;
2311  rd.line_info[i].search_cnt = -1;
2312  rd.line_info[i].syntax = mutt_mem_malloc(sizeof(struct TextSyntax));
2313  (rd.line_info[i].syntax)[0].first = -1;
2314  (rd.line_info[i].syntax)[0].last = -1;
2315  }
2316 
2317  pager_menu = mutt_menu_new(MENU_PAGER);
2318  pager_menu->pagelen = extra->win_pager->state.rows;
2319  pager_menu->win_index = extra->win_pager;
2320  pager_menu->win_ibar = extra->win_pbar;
2321 
2322  pager_menu->custom_redraw = pager_custom_redraw;
2323  pager_menu->redraw_data = &rd;
2324  mutt_menu_push_current(pager_menu);
2325 
2326  if (IsEmail(extra))
2327  {
2328  // Viewing a Mailbox
2329 #ifdef USE_NNTP
2330  if (m && (m->type == MUTT_NNTP))
2331  extra->win_pager->help_data = PagerNewsHelp;
2332  else
2333 #endif
2335  }
2336  else
2337  {
2338  // Viewing Help
2339  if (InHelp)
2340  extra->win_pager->help_data = PagerHelpHelp;
2341  else
2342  extra->win_pager->help_data = PagerHelp;
2343  }
2344  extra->win_pager->help_menu = MENU_PAGER;
2345  window_set_focus(extra->win_pager);
2346 
2347  while (ch != -1)
2348  {
2350 
2351  pager_custom_redraw(pager_menu);
2352  window_redraw(RootWindow, true);
2353 
2354  if (C_BrailleFriendly)
2355  {
2356  if (braille_line != -1)
2357  {
2359  braille_line = -1;
2360  }
2361  }
2362  else
2364 
2365  mutt_refresh();
2366 
2367  if (IsEmail(extra) && (OldEmail == extra->email) && (TopLine != rd.topline) &&
2368  (rd.line_info[rd.curline].offset < (rd.sb.st_size - 1)))
2369  {
2370  if ((TopLine - rd.topline) > rd.lines)
2371  rd.topline += rd.lines;
2372  else
2373  rd.topline = TopLine;
2374  continue;
2375  }
2376  else
2377  OldEmail = NULL;
2378 
2379  ch = km_dokey(MENU_PAGER);
2380  if (ch >= 0)
2381  {
2382  mutt_clear_error();
2383  mutt_debug(LL_DEBUG1, "Got op %s (%d)\n", OpStrings[ch][0], ch);
2384  }
2386 
2387  bool do_new_mail = false;
2388 
2389  if (m && !OptAttachMsg)
2390  {
2391  int oldcount = m->msg_count;
2392  /* check for new mail */
2393  int check = mx_mbox_check(m);
2394  if (check < 0)
2395  {
2396  if (!m || mutt_buffer_is_empty(&m->pathbuf))
2397  {
2398  /* fatal error occurred */
2399  ctx_free(&Context);
2400  pager_menu->redraw = REDRAW_FULL;
2401  break;
2402  }
2403  }
2404  else if ((check == MUTT_NEW_MAIL) || (check == MUTT_REOPENED) || (check == MUTT_FLAGS))
2405  {
2406  /* notify user of newly arrived mail */
2407  if (check == MUTT_NEW_MAIL)
2408  {
2409  for (size_t i = oldcount; i < m->msg_count; i++)
2410  {
2411  struct Email *e = m->emails[i];
2412 
2413  if (e && !e->read)
2414  {
2415  mutt_message(_("New mail in this mailbox"));
2416  do_new_mail = true;
2417  break;
2418  }
2419  }
2420  }
2421 
2422  if ((check == MUTT_NEW_MAIL) || (check == MUTT_REOPENED))
2423  {
2424  if (rd.menu && m)
2425  {
2426  /* After the mailbox has been updated,
2427  * rd.menu->current might be invalid */
2428  rd.menu->current = MIN(rd.menu->current, MAX(m->msg_count - 1, 0));
2429  struct Email *e = mutt_get_virt_email(m, rd.menu->current);
2430  if (!e)
2431  continue;
2432 
2433  bool verbose = m->verbose;
2434  m->verbose = false;
2435  mutt_update_index(rd.menu, Context, check, oldcount, e);
2436  m->verbose = verbose;
2437 
2438  rd.menu->max = m->vcount;
2439 
2440  /* If these header pointers don't match, then our email may have
2441  * been deleted. Make the pointer safe, then leave the pager.
2442  * This have a unpleasant behaviour to close the pager even the
2443  * deleted message is not the opened one, but at least it's safe. */
2444  e = mutt_get_virt_email(m, rd.menu->current);
2445  if (extra->email != e)
2446  {
2447  extra->email = e;
2448  break;
2449  }
2450  }
2451 
2452  pager_menu->redraw = REDRAW_FULL;
2453  OptSearchInvalid = true;
2454  }
2455  }
2456 
2457  if (mutt_mailbox_notify(m) || do_new_mail)
2458  {
2459  if (C_BeepNew)
2460  mutt_beep(true);
2461  if (C_NewMailCommand)
2462  {
2463  char cmd[1024];
2464  menu_status_line(cmd, sizeof(cmd), rd.menu, m, NONULL(C_NewMailCommand));
2465  if (mutt_system(cmd) != 0)
2466  mutt_error(_("Error running \"%s\""), cmd);
2467  }
2468  }
2469  }
2470 
2471  if (SigWinch)
2472  {
2473  SigWinch = 0;
2475  clearok(stdscr, true); /* force complete redraw */
2476 
2477  if (flags & MUTT_PAGER_RETWINCH)
2478  {
2479  /* Store current position. */
2480  rd.lines = -1;
2481  for (size_t i = 0; i <= rd.topline; i++)
2482  if (!rd.line_info[i].continuation)
2483  rd.lines++;
2484 
2485  Resize = mutt_mem_malloc(sizeof(struct Resize));
2486 
2487  Resize->line = rd.lines;
2490 
2491  ch = -1;
2492  rc = OP_REFORMAT_WINCH;
2493  }
2494  else
2495  {
2496  /* note: mutt_resize_screen() -> mutt_window_reflow() sets
2497  * REDRAW_FULL and REDRAW_FLOW */
2498  ch = 0;
2499  }
2500  continue;
2501  }
2502 
2503  if (ch < 0)
2504  {
2505  ch = 0;
2507  continue;
2508  }
2509 
2510  rc = ch;
2511 
2512  switch (ch)
2513  {
2514  case OP_EXIT:
2515  rc = -1;
2516  ch = -1;
2517  break;
2518 
2519  case OP_QUIT:
2520  if (query_quadoption(C_Quit, _("Quit NeoMutt?")) == MUTT_YES)
2521  {
2522  /* avoid prompting again in the index menu */
2523  cs_subset_str_native_set(NeoMutt->sub, "quit", MUTT_YES, NULL);
2524  ch = -1;
2525  }
2526  break;
2527 
2528  case OP_NEXT_PAGE:
2529  if (rd.line_info[rd.curline].offset < (rd.sb.st_size - 1))
2530  {
2532  }
2533  else if (C_PagerStop)
2534  {
2535  /* emulate "less -q" and don't go on to the next message. */
2536  mutt_error(_("Bottom of message is shown"));
2537  }
2538  else
2539  {
2540  /* end of the current message, so display the next message. */
2541  rc = OP_MAIN_NEXT_UNDELETED;
2542  ch = -1;
2543  }
2544  break;
2545 
2546  case OP_PREV_PAGE:
2547  if (rd.topline == 0)
2548  {
2549  mutt_message(_("Top of message is shown"));
2550  }
2551  else
2552  {
2554  rd.line_info, rd.topline, rd.hide_quoted);
2555  }
2556  break;
2557 
2558  case OP_NEXT_LINE:
2559  if (rd.line_info[rd.curline].offset < (rd.sb.st_size - 1))
2560  {
2561  rd.topline++;
2562  if (rd.hide_quoted)
2563  {
2564  while ((rd.line_info[rd.topline].type == MT_COLOR_QUOTED) &&
2565  (rd.topline < rd.last_line))
2566  {
2567  rd.topline++;
2568  }
2569  }
2570  }
2571  else
2572  mutt_message(_("Bottom of message is shown"));
2573  break;
2574 
2575  case OP_PREV_LINE:
2576  if (rd.topline)
2577  rd.topline = up_n_lines(1, rd.line_info, rd.topline, rd.hide_quoted);
2578  else
2579  mutt_error(_("Top of message is shown"));
2580  break;
2581 
2582  case OP_PAGER_TOP:
2583  if (rd.topline)
2584  rd.topline = 0;
2585  else
2586  mutt_error(_("Top of message is shown"));
2587  break;
2588 
2589  case OP_HALF_UP:
2590  if (rd.topline)
2591  {
2592  rd.topline = up_n_lines(rd.extra->win_pager->state.rows / 2 +
2593  (rd.extra->win_pager->state.rows % 2),
2594  rd.line_info, rd.topline, rd.hide_quoted);
2595  }
2596  else
2597  mutt_error(_("Top of message is shown"));
2598  break;
2599 
2600  case OP_HALF_DOWN:
2601  if (rd.line_info[rd.curline].offset < (rd.sb.st_size - 1))
2602  {
2603  rd.topline = up_n_lines(rd.extra->win_pager->state.rows / 2,
2604  rd.line_info, rd.curline, rd.hide_quoted);
2605  }
2606  else if (C_PagerStop)
2607  {
2608  /* emulate "less -q" and don't go on to the next message. */
2609  mutt_error(_("Bottom of message is shown"));
2610  }
2611  else
2612  {
2613  /* end of the current message, so display the next message. */
2614  rc = OP_MAIN_NEXT_UNDELETED;
2615  ch = -1;
2616  }
2617  break;
2618 
2619  case OP_SEARCH_NEXT:
2620  case OP_SEARCH_OPPOSITE:
2621  if (rd.search_compiled)
2622  {
2623  wrapped = false;
2624 
2625  if (C_SearchContext < rd.extra->win_pager->state.rows)
2626  searchctx = C_SearchContext;
2627  else
2628  searchctx = 0;
2629 
2630  search_next:
2631  if ((!rd.search_back && (ch == OP_SEARCH_NEXT)) ||
2632  (rd.search_back && (ch == OP_SEARCH_OPPOSITE)))
2633  {
2634  /* searching forward */
2635  int i;
2636  for (i = wrapped ? 0 : rd.topline + searchctx + 1; i < rd.last_line; i++)
2637  {
2638  if ((!rd.hide_quoted || (rd.line_info[i].type != MT_COLOR_QUOTED)) &&
2639  !rd.line_info[i].continuation && (rd.line_info[i].search_cnt > 0))
2640  {
2641  break;
2642  }
2643  }
2644 
2645  if (i < rd.last_line)
2646  rd.topline = i;
2647  else if (wrapped || !C_WrapSearch)
2648  mutt_error(_("Not found"));
2649  else
2650  {
2651  mutt_message(_("Search wrapped to top"));
2652  wrapped = true;
2653  goto search_next;
2654  }
2655  }
2656  else
2657  {
2658  /* searching backward */
2659  int i;
2660  for (i = wrapped ? rd.last_line : rd.topline + searchctx - 1; i >= 0; i--)
2661  {
2662  if ((!rd.hide_quoted ||
2663  (rd.has_types && (rd.line_info[i].type != MT_COLOR_QUOTED))) &&
2664  !rd.line_info[i].continuation && (rd.line_info[i].search_cnt > 0))
2665  {
2666  break;
2667  }
2668  }
2669 
2670  if (i >= 0)
2671  rd.topline = i;
2672  else if (wrapped || !C_WrapSearch)
2673  mutt_error(_("Not found"));
2674  else
2675  {
2676  mutt_message(_("Search wrapped to bottom"));
2677  wrapped = true;
2678  goto search_next;
2679  }
2680  }
2681 
2682  if (rd.line_info[rd.topline].search_cnt > 0)
2683  {
2684  rd.search_flag = MUTT_SEARCH;
2685  /* give some context for search results */
2686  if (rd.topline - searchctx > 0)
2687  rd.topline -= searchctx;
2688  }
2689 
2690  break;
2691  }
2692  /* no previous search pattern */
2693  /* fallthrough */
2694 
2695  case OP_SEARCH:
2696  case OP_SEARCH_REVERSE:
2697  mutt_str_copy(buf, searchbuf, sizeof(buf));
2698  if (mutt_get_field(((ch == OP_SEARCH) || (ch == OP_SEARCH_NEXT)) ?
2699  _("Search for: ") :
2700  _("Reverse search for: "),
2701  buf, sizeof(buf), MUTT_CLEAR | MUTT_PATTERN) != 0)
2702  {
2703  break;
2704  }
2705 
2706  if (strcmp(buf, searchbuf) == 0)
2707  {
2708  if (rd.search_compiled)
2709  {
2710  /* do an implicit search-next */
2711  if (ch == OP_SEARCH)
2712  ch = OP_SEARCH_NEXT;
2713  else
2714  ch = OP_SEARCH_OPPOSITE;
2715 
2716  wrapped = false;
2717  goto search_next;
2718  }
2719  }
2720 
2721  if (buf[0] == '\0')
2722  break;
2723 
2724  mutt_str_copy(searchbuf, buf, sizeof(searchbuf));
2725 
2726  /* leave search_back alone if ch == OP_SEARCH_NEXT */
2727  if (ch == OP_SEARCH)
2728  rd.search_back = false;
2729  else if (ch == OP_SEARCH_REVERSE)
2730  rd.search_back = true;
2731 
2732  if (rd.search_compiled)
2733  {
2734  regfree(&rd.search_re);
2735  for (size_t i = 0; i < rd.last_line; i++)
2736  {
2737  FREE(&(rd.line_info[i].search));
2738  rd.line_info[i].search_cnt = -1;
2739  }
2740  }
2741 
2742  int rflags = mutt_mb_is_lower(searchbuf) ? REG_ICASE : 0;
2743  int err = REG_COMP(&rd.search_re, searchbuf, REG_NEWLINE | rflags);
2744  if (err != 0)
2745  {
2746  regerror(err, &rd.search_re, buf, sizeof(buf));
2747  mutt_error("%s", buf);
2748  for (size_t i = 0; i < rd.max_line; i++)
2749  {
2750  /* cleanup */
2751  FREE(&(rd.line_info[i].search));
2752  rd.line_info[i].search_cnt = -1;
2753  }
2754  rd.search_flag = 0;
2755  rd.search_compiled = false;
2756  }
2757  else
2758  {
2759  rd.search_compiled = true;
2760  /* update the search pointers */
2761  int line_num = 0;
2762  while (display_line(rd.fp, &rd.last_pos, &rd.line_info, line_num,
2763  &rd.last_line, &rd.max_line,
2764  MUTT_SEARCH | (flags & MUTT_PAGER_NSKIP) | (flags & MUTT_PAGER_NOWRAP),
2765  &rd.quote_list, &rd.q_level, &rd.force_redraw,
2766  &rd.search_re, rd.extra->win_pager) == 0)
2767  {
2768  line_num++;
2769  }
2770 
2771  if (!rd.search_back)
2772  {
2773  /* searching forward */
2774  int i;
2775  for (i = rd.topline; i < rd.last_line; i++)
2776  {
2777  if ((!rd.hide_quoted || (rd.line_info[i].type != MT_COLOR_QUOTED)) &&
2778  !rd.line_info[i].continuation && (rd.line_info[i].search_cnt > 0))
2779  {
2780  break;
2781  }
2782  }
2783 
2784  if (i < rd.last_line)
2785  rd.topline = i;
2786  }
2787  else
2788  {
2789  /* searching backward */
2790  int i;
2791  for (i = rd.topline; i >= 0; i--)
2792  {
2793  if ((!rd.hide_quoted || (rd.line_info[i].type != MT_COLOR_QUOTED)) &&
2794  !rd.line_info[i].continuation && (rd.line_info[i].search_cnt > 0))
2795  {
2796  break;
2797  }
2798  }
2799 
2800  if (i >= 0)
2801  rd.topline = i;
2802  }
2803 
2804  if (rd.line_info[rd.topline].search_cnt == 0)
2805  {
2806  rd.search_flag = 0;
2807  mutt_error(_("Not found"));
2808  }
2809  else
2810  {
2811  rd.search_flag = MUTT_SEARCH;
2812  /* give some context for search results */
2813  if (C_SearchContext < rd.extra->win_pager->state.rows)
2814  searchctx = C_SearchContext;
2815  else
2816  searchctx = 0;
2817  if (rd.topline - searchctx > 0)
2818  rd.topline -= searchctx;
2819  }
2820  }
2821  pager_menu->redraw = REDRAW_BODY;
2822  break;
2823 
2824  case OP_SEARCH_TOGGLE:
2825  if (rd.search_compiled)
2826  {
2827  rd.search_flag ^= MUTT_SEARCH;
2828  pager_menu->redraw = REDRAW_BODY;
2829  }
2830  break;
2831 
2832  case OP_SORT:
2833  case OP_SORT_REVERSE:
2834  CHECK_MODE(IsEmail(extra))
2835  if (mutt_select_sort((ch == OP_SORT_REVERSE)) == 0)
2836  {
2837  OptNeedResort = true;
2838  ch = -1;
2839  rc = OP_DISPLAY_MESSAGE;
2840  }
2841  break;
2842 
2843  case OP_HELP:
2844  if (InHelp)
2845  {
2846  /* don't let the user enter the help-menu from the help screen! */
2847  mutt_error(_("Help is currently being shown"));
2848  break;
2849  }
2850 
2851  InHelp = true;
2852  mutt_help(MENU_PAGER, pager_menu->win_index->state.cols);
2853  pager_menu->redraw = REDRAW_FULL;
2854  InHelp = false;
2855  break;
2856 
2857  case OP_PAGER_HIDE_QUOTED:
2858  if (!rd.has_types)
2859  break;
2860 
2861  rd.hide_quoted ^= MUTT_HIDE;
2862  if (rd.hide_quoted && (rd.line_info[rd.topline].type == MT_COLOR_QUOTED))
2863  rd.topline = up_n_lines(1, rd.line_info, rd.topline, rd.hide_quoted);
2864  else
2865  pager_menu->redraw = REDRAW_BODY;
2866  break;
2867 
2868  case OP_PAGER_SKIP_QUOTED:
2869  if (!rd.has_types)
2870  break;
2871 
2872  int dretval = 0;
2873  int new_topline = rd.topline;
2874 
2875  /* Skip all the email headers */
2876  if (IS_HEADER(rd.line_info[new_topline].type))
2877  {
2878  while (((new_topline < rd.last_line) ||
2879  (0 == (dretval = display_line(
2880  rd.fp, &rd.last_pos, &rd.line_info, new_topline, &rd.last_line,
2881  &rd.max_line, MUTT_TYPES | (flags & MUTT_PAGER_NOWRAP),
2882  &rd.quote_list, &rd.q_level, &rd.force_redraw,
2883  &rd.search_re, rd.extra->win_pager)))) &&
2884  IS_HEADER(rd.line_info[new_topline].type))
2885  {
2886  new_topline++;
2887  }
2888  rd.topline = new_topline;
2889  break;
2890  }
2891 
2892  while ((((new_topline + C_SkipQuotedOffset) < rd.last_line) ||
2893  (0 == (dretval = display_line(
2894  rd.fp, &rd.last_pos, &rd.line_info, new_topline, &rd.last_line,
2895  &rd.max_line, MUTT_TYPES | (flags & MUTT_PAGER_NOWRAP),
2896  &rd.quote_list, &rd.q_level, &rd.force_redraw,
2897  &rd.search_re, rd.extra->win_pager)))) &&
2898  (rd.line_info[new_topline + C_SkipQuotedOffset].type != MT_COLOR_QUOTED))
2899  {
2900  new_topline++;
2901  }
2902 
2903  if (dretval < 0)
2904  {
2905  mutt_error(_("No more quoted text"));
2906  break;
2907  }
2908 
2909  while ((((new_topline + C_SkipQuotedOffset) < rd.last_line) ||
2910  (0 == (dretval = display_line(
2911  rd.fp, &rd.last_pos, &rd.line_info, new_topline, &rd.last_line,
2912  &rd.max_line, MUTT_TYPES | (flags & MUTT_PAGER_NOWRAP),
2913  &rd.quote_list, &rd.q_level, &rd.force_redraw,
2914  &rd.search_re, rd.extra->win_pager)))) &&
2915  (rd.line_info[new_topline + C_SkipQuotedOffset].type == MT_COLOR_QUOTED))
2916  {
2917  new_topline++;
2918  }
2919 
2920  if (dretval < 0)
2921  {
2922  mutt_error(_("No more unquoted text after quoted text"));
2923  break;
2924  }
2925  rd.topline = new_topline;
2926  break;
2927 
2928  case OP_PAGER_BOTTOM: /* move to the end of the file */
2929  if (rd.line_info[rd.curline].offset < (rd.sb.st_size - 1))
2930  {
2931  int line_num = rd.curline;
2932  /* make sure the types are defined to the end of file */
2933  while (display_line(rd.fp, &rd.last_pos, &rd.line_info, line_num, &rd.last_line,
2934  &rd.max_line, rd.has_types | (flags & MUTT_PAGER_NOWRAP),
2935  &rd.quote_list, &rd.q_level, &rd.force_redraw,
2936  &rd.search_re, rd.extra->win_pager) == 0)
2937  {
2938  line_num++;
2939  }
2941  rd.last_line, rd.hide_quoted);
2942  }
2943  else
2944  mutt_error(_("Bottom of message is shown"));
2945  break;
2946 
2947  case OP_REDRAW:
2948  mutt_window_reflow(NULL);
2949  clearok(stdscr, true);
2950  pager_menu->redraw = REDRAW_FULL;
2951  break;
2952 
2953  case OP_NULL:
2955  break;
2956 
2957  /* --------------------------------------------------------------------
2958  * The following are operations on the current message rather than
2959  * adjusting the view of the message. */
2960 
2961  case OP_BOUNCE_MESSAGE:
2962  {
2963  CHECK_MODE(IsEmail(extra) || IsMsgAttach(extra))
2964  CHECK_ATTACH;
2965  if (IsMsgAttach(extra))
2966  mutt_attach_bounce(m, extra->fp, extra->actx, extra->body);
2967  else
2968  {
2969  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
2970  emaillist_add_email(&el, extra->email);
2971  ci_bounce_message(m, &el);
2972  emaillist_clear(&el);
2973  }
2974  break;
2975  }
2976 
2977  case OP_RESEND:
2978  CHECK_MODE(IsEmail(extra) || IsMsgAttach(extra))
2979  CHECK_ATTACH;
2980  if (IsMsgAttach(extra))
2981  mutt_attach_resend(extra->fp, extra->actx, extra->body);
2982  else
2983  mutt_resend_message(NULL, extra->ctx, extra->email, NeoMutt->sub);
2984  pager_menu->redraw = REDRAW_FULL;
2985  break;
2986 
2987  case OP_COMPOSE_TO_SENDER:
2988  CHECK_MODE(IsEmail(extra) || IsMsgAttach(extra));
2989  CHECK_ATTACH;
2990  if (IsMsgAttach(extra))
2991  mutt_attach_mail_sender(extra->fp, extra->email, extra->actx, extra->body);
2992  else
2993  {
2994  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
2995  emaillist_add_email(&el, extra->email);
2996  mutt_send_message(SEND_TO_SENDER, NULL, NULL, extra->ctx, &el, NeoMutt->sub);
2997  emaillist_clear(&el);
2998  }
2999  pager_menu->redraw = REDRAW_FULL;
3000  break;
3001 
3002  case OP_CHECK_TRADITIONAL:
3003  CHECK_MODE(IsEmail(extra));
3004  if (!(WithCrypto & APPLICATION_PGP))
3005  break;
3006  if (!(extra->email->security & PGP_TRADITIONAL_CHECKED))
3007  {
3008  ch = -1;
3009  rc = OP_CHECK_TRADITIONAL;
3010  }
3011  break;
3012 
3013  case OP_CREATE_ALIAS:
3014  CHECK_MODE(IsEmail(extra) || IsMsgAttach(extra));
3015  struct AddressList *al = NULL;
3016  if (IsMsgAttach(extra))
3017  al = mutt_get_address(extra->body->email->env, NULL);
3018  else
3019  al = mutt_get_address(extra->email->env, NULL);
3020  alias_create(al, NeoMutt->sub);
3021  break;
3022 
3023  case OP_PURGE_MESSAGE:
3024  case OP_DELETE:
3025  CHECK_MODE(IsEmail(extra));
3027  /* L10N: CHECK_ACL */
3028  CHECK_ACL(MUTT_ACL_DELETE, _("Can't delete message"));
3029 
3030  mutt_set_flag(Context->mailbox, extra->email, MUTT_DELETE, true);
3031  mutt_set_flag(Context->mailbox, extra->email, MUTT_PURGE, (ch == OP_PURGE_MESSAGE));
3032  if (C_DeleteUntag)
3033  mutt_set_flag(Context->mailbox, extra->email, MUTT_TAG, false);
3034  pager_menu->redraw |= REDRAW_STATUS | REDRAW_INDEX;
3035  if (C_Resolve)
3036  {
3037  ch = -1;
3038  rc = OP_MAIN_NEXT_UNDELETED;
3039  }
3040  break;
3041 
3042  case OP_MAIN_SET_FLAG:
3043  case OP_MAIN_CLEAR_FLAG:
3044  {
3045  CHECK_MODE(IsEmail(extra));
3047 
3048  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3049  emaillist_add_email(&el, extra->email);
3050 
3051  if (mutt_change_flag(Context->mailbox, &el, (ch == OP_MAIN_SET_FLAG)) == 0)
3052  pager_menu->redraw |= REDRAW_STATUS | REDRAW_INDEX;
3053  if (extra->email->deleted && C_Resolve)
3054  {
3055  ch = -1;
3056  rc = OP_MAIN_NEXT_UNDELETED;
3057  }
3058  emaillist_clear(&el);
3059  break;
3060  }
3061 
3062  case OP_DELETE_THREAD:
3063  case OP_DELETE_SUBTHREAD:
3064  case OP_PURGE_THREAD:
3065  {
3066  CHECK_MODE(IsEmail(extra));
3068  /* L10N: CHECK_ACL */
3069  /* L10N: Due to the implementation details we do not know whether we
3070  delete zero, 1, 12, ... messages. So in English we use
3071  "messages". Your language might have other means to express this. */
3072  CHECK_ACL(MUTT_ACL_DELETE, _("Can't delete messages"));
3073 
3074  int subthread = (ch == OP_DELETE_SUBTHREAD);
3075  int r = mutt_thread_set_flag(extra->email, MUTT_DELETE, 1, subthread);
3076  if (r == -1)
3077  break;
3078  if (ch == OP_PURGE_THREAD)
3079  {
3080  r = mutt_thread_set_flag(extra->email, MUTT_PURGE, true, subthread);
3081  if (r == -1)
3082  break;
3083  }
3084 
3085  if (C_DeleteUntag)
3086  mutt_thread_set_flag(extra->email, MUTT_TAG, 0, subthread);
3087  if (C_Resolve)
3088  {
3089  rc = OP_MAIN_NEXT_UNDELETED;
3090  ch = -1;
3091  }
3092 
3093  if (!C_Resolve && (C_PagerIndexLines != 0))
3094  pager_menu->redraw = REDRAW_FULL;
3095  else
3096  pager_menu->redraw |= REDRAW_STATUS | REDRAW_INDEX;
3097 
3098  break;
3099  }
3100 
3101  case OP_DISPLAY_ADDRESS:
3102  CHECK_MODE(IsEmail(extra) || IsMsgAttach(extra));
3103  if (IsMsgAttach(extra))
3104  mutt_display_address(extra->body->email->env);
3105  else
3106  mutt_display_address(extra->email->env);
3107  break;
3108 
3109  case OP_ENTER_COMMAND:
3110  old_PagerIndexLines = C_PagerIndexLines;
3111 
3114  pager_menu->redraw = REDRAW_FULL;
3115 
3116  if (OptNeedResort)
3117  {
3118  OptNeedResort = false;
3119  CHECK_MODE(IsEmail(extra));
3120  OptNeedResort = true;
3121  }
3122 
3123  if (old_PagerIndexLines != C_PagerIndexLines)
3124  {
3125  mutt_menu_free(&rd.menu);
3126  }
3127 
3128  if ((pager_menu->redraw & REDRAW_FLOW) && (flags & MUTT_PAGER_RETWINCH))
3129  {
3130  ch = -1;
3131  rc = OP_REFORMAT_WINCH;
3132  continue;
3133  }
3134 
3135  ch = 0;
3136  break;
3137 
3138  case OP_FLAG_MESSAGE:
3139  CHECK_MODE(IsEmail(extra));
3141  /* L10N: CHECK_ACL */
3142  CHECK_ACL(MUTT_ACL_WRITE, "Can't flag message");
3143 
3144  mutt_set_flag(Context->mailbox, extra->email, MUTT_FLAG, !extra->email->flagged);
3145  pager_menu->redraw |= REDRAW_STATUS | REDRAW_INDEX;
3146  if (C_Resolve)
3147  {
3148  ch = -1;
3149  rc = OP_MAIN_NEXT_UNDELETED;
3150  }
3151  break;
3152 
3153  case OP_PIPE:
3154  CHECK_MODE(IsEmail(extra) || IsAttach(extra));
3155  if (IsAttach(extra))
3156  mutt_pipe_attachment_list(extra->actx, extra->fp, false, extra->body, false);
3157  else
3158  {
3159  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3160  el_add_tagged(&el, extra->ctx, extra->email, false);
3161  mutt_pipe_message(extra->ctx->mailbox, &el);
3162  emaillist_clear(&el);
3163  }
3164  break;
3165 
3166  case OP_PRINT:
3167  CHECK_MODE(IsEmail(extra) || IsAttach(extra));
3168  if (IsAttach(extra))
3169  mutt_print_attachment_list(extra->actx, extra->fp, false, extra->body);
3170  else
3171  {
3172  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3173  el_add_tagged(&el, extra->ctx, extra->email, false);
3174  mutt_print_message(extra->ctx->mailbox, &el);
3175  emaillist_clear(&el);
3176  }
3177  break;
3178 
3179  case OP_MAIL:
3180  CHECK_MODE(IsEmail(extra) && !IsAttach(extra));
3181  CHECK_ATTACH;
3182  mutt_send_message(SEND_NO_FLAGS, NULL, NULL, extra->ctx, NULL, NeoMutt->sub);
3183  pager_menu->redraw = REDRAW_FULL;
3184  break;
3185 
3186 #ifdef USE_NNTP
3187  case OP_POST:
3188  CHECK_MODE(IsEmail(extra) && !IsAttach(extra));
3189  CHECK_ATTACH;
3190  if (extra->ctx && (extra->ctx->mailbox->type == MUTT_NNTP) &&
3191  !((struct NntpMboxData *) extra->ctx->mailbox->mdata)->allowed && (query_quadoption(C_PostModerated, _("Posting to this group not allowed, may be moderated. Continue?")) != MUTT_YES))
3192  {
3193  break;
3194  }
3195  mutt_send_message(SEND_NEWS, NULL, NULL, extra->ctx, NULL, NeoMutt->sub);
3196  pager_menu->redraw = REDRAW_FULL;
3197  break;
3198 
3199  case OP_FORWARD_TO_GROUP:
3200  CHECK_MODE(IsEmail(extra) || IsMsgAttach(extra));
3201  CHECK_ATTACH;
3202  if (extra->ctx && (extra->ctx->mailbox->type == MUTT_NNTP) &&
3203  !((struct NntpMboxData *) extra->ctx->mailbox->mdata)->allowed && (query_quadoption(C_PostModerated, _("Posting to this group not allowed, may be moderated. Continue?")) != MUTT_YES))
3204  {
3205  break;
3206  }
3207  if (IsMsgAttach(extra))
3208  mutt_attach_forward(extra->fp, extra->email, extra->actx, extra->body, SEND_NEWS);
3209  else
3210  {
3211  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3212  emaillist_add_email(&el, extra->email);
3213  mutt_send_message(SEND_NEWS | SEND_FORWARD, NULL, NULL, extra->ctx,
3214  &el, NeoMutt->sub);
3215  emaillist_clear(&el);
3216  }
3217  pager_menu->redraw = REDRAW_FULL;
3218  break;
3219 
3220  case OP_FOLLOWUP:
3221  CHECK_MODE(IsEmail(extra) || IsMsgAttach(extra));
3222  CHECK_ATTACH;
3223 
3224  if (IsMsgAttach(extra))
3225  followup_to = extra->body->email->env->followup_to;
3226  else
3227  followup_to = extra->email->env->followup_to;
3228 
3229  if (!followup_to || !mutt_istr_equal(followup_to, "poster") ||
3231  _("Reply by mail as poster prefers?")) != MUTT_YES))
3232  {
3233  if (extra->ctx && (extra->ctx->mailbox->type == MUTT_NNTP) &&
3234  !((struct NntpMboxData *) extra->ctx->mailbox->mdata)->allowed && (query_quadoption(C_PostModerated, _("Posting to this group not allowed, may be moderated. Continue?")) != MUTT_YES))
3235  {
3236  break;
3237  }
3238  if (IsMsgAttach(extra))
3239  {
3240  mutt_attach_reply(extra->fp, extra->email, extra->actx, extra->body,
3241  SEND_NEWS | SEND_REPLY);
3242  }
3243  else
3244  {
3245  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3246  emaillist_add_email(&el, extra->email);
3247  mutt_send_message(SEND_NEWS | SEND_REPLY, NULL, NULL, extra->ctx,
3248  &el, NeoMutt->sub);
3249  emaillist_clear(&el);
3250  }
3251  pager_menu->redraw = REDRAW_FULL;
3252  break;
3253  }
3254 #endif
3255  /* fallthrough */
3256  case OP_REPLY:
3257  case OP_GROUP_REPLY:
3258  case OP_GROUP_CHAT_REPLY:
3259  case OP_LIST_REPLY:
3260  {
3261  CHECK_MODE(IsEmail(extra) || IsMsgAttach(extra));
3262  CHECK_ATTACH;
3263 
3264  SendFlags replyflags = SEND_REPLY;
3265  if (ch == OP_GROUP_REPLY)
3266  replyflags |= SEND_GROUP_REPLY;
3267  else if (ch == OP_GROUP_CHAT_REPLY)
3268  replyflags |= SEND_GROUP_CHAT_REPLY;
3269  else if (ch == OP_LIST_REPLY)
3270  replyflags |= SEND_LIST_REPLY;
3271 
3272  if (IsMsgAttach(extra))
3273  mutt_attach_reply(extra->fp, extra->email, extra->actx, extra->body, replyflags);
3274  else
3275  {
3276  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3277  emaillist_add_email(&el, extra->email);
3278  mutt_send_message(replyflags, NULL, NULL, extra->ctx, &el, NeoMutt->sub);
3279  emaillist_clear(&el);
3280  }
3281  pager_menu->redraw = REDRAW_FULL;
3282  break;
3283  }
3284 
3285  case OP_RECALL_MESSAGE:
3286  {
3287  CHECK_MODE(IsEmail(extra) && !IsAttach(extra));
3288  CHECK_ATTACH;
3289  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3290  emaillist_add_email(&el, extra->email);
3291  mutt_send_message(SEND_POSTPONED, NULL, NULL, extra->ctx, &el, NeoMutt->sub);
3292  emaillist_clear(&el);
3293  pager_menu->redraw = REDRAW_FULL;
3294  break;
3295  }
3296 
3297  case OP_FORWARD_MESSAGE:
3298  CHECK_MODE(IsEmail(extra) || IsMsgAttach(extra));
3299  CHECK_ATTACH;
3300  if (IsMsgAttach(extra))
3301  mutt_attach_forward(extra->fp, extra->email, extra->actx, extra->body, SEND_NO_FLAGS);
3302  else
3303  {
3304  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3305  emaillist_add_email(&el, extra->email);
3306  mutt_send_message(SEND_FORWARD, NULL, NULL, extra->ctx, &el, NeoMutt->sub);
3307  emaillist_clear(&el);
3308  }
3309  pager_menu->redraw = REDRAW_FULL;
3310  break;
3311 
3312  case OP_DECRYPT_SAVE:
3313  if (!WithCrypto)
3314  {
3315  ch = -1;
3316  break;
3317  }
3318  /* fallthrough */
3319  case OP_SAVE:
3320  if (IsAttach(extra))
3321  {
3322  mutt_save_attachment_list(extra->actx, extra->fp, false, extra->body,
3323  extra->email, NULL);
3324  break;
3325  }
3326  /* fallthrough */
3327  case OP_COPY_MESSAGE:
3328  case OP_DECODE_SAVE:
3329  case OP_DECODE_COPY:
3330  case OP_DECRYPT_COPY:
3331  {
3332  if (!(WithCrypto != 0) && (ch == OP_DECRYPT_COPY))
3333  {
3334  ch = -1;
3335  break;
3336  }
3337  CHECK_MODE(IsEmail(extra));
3338  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3339  emaillist_add_email(&el, extra->email);
3340 
3341  const bool delete_original =
3342  (ch == OP_SAVE) || (ch == OP_DECODE_SAVE) || (ch == OP_DECRYPT_SAVE);
3343  const bool decode = (ch == OP_DECODE_SAVE) || (ch == OP_DECODE_COPY);
3344  const bool decrypt = (ch == OP_DECRYPT_SAVE) || (ch == OP_DECRYPT_COPY);
3345 
3346  if ((mutt_save_message(Context->mailbox, &el, delete_original, decode, decrypt) == 0) &&
3347  delete_original)
3348  {
3349  if (C_Resolve)
3350  {
3351  ch = -1;
3352  rc = OP_MAIN_NEXT_UNDELETED;
3353  }
3354  else
3355  pager_menu->redraw |= REDRAW_STATUS | REDRAW_INDEX;
3356  }
3357  emaillist_clear(&el);
3358  break;
3359  }
3360 
3361  case OP_SHELL_ESCAPE:
3363  break;
3364 
3365  case OP_TAG:
3366  CHECK_MODE(IsEmail(extra));
3367  if (Context)
3368  {
3369  mutt_set_flag(Context->mailbox, extra->email, MUTT_TAG, !extra->email->tagged);
3370  }
3371 
3372  pager_menu->redraw |= REDRAW_STATUS | REDRAW_INDEX;
3373  if (C_Resolve)
3374  {
3375  ch = -1;
3376  rc = OP_NEXT_ENTRY;
3377  }
3378  break;
3379 
3380  case OP_TOGGLE_NEW:
3381  CHECK_MODE(IsEmail(extra));
3383  /* L10N: CHECK_ACL */
3384  CHECK_ACL(MUTT_ACL_SEEN, _("Can't toggle new"));
3385 
3386  if (extra->email->read || extra->email->old)
3387  mutt_set_flag(Context->mailbox, extra->email, MUTT_NEW, true);
3388  else if (!first)
3389  mutt_set_flag(Context->mailbox, extra->email, MUTT_READ, true);
3390  first = false;
3391  Context->msg_in_pager = -1;
3392  pager_menu->redraw |= REDRAW_STATUS | REDRAW_INDEX;
3393  if (C_Resolve)
3394  {
3395  ch = -1;
3396  rc = OP_MAIN_NEXT_UNDELETED;
3397  }
3398  break;
3399 
3400  case OP_UNDELETE:
3401  CHECK_MODE(IsEmail(extra));
3403  /* L10N: CHECK_ACL */
3404  CHECK_ACL(MUTT_ACL_DELETE, _("Can't undelete message"));
3405 
3406  mutt_set_flag(Context->mailbox, extra->email, MUTT_DELETE, false);
3407  mutt_set_flag(Context->mailbox, extra->email, MUTT_PURGE, false);
3408  pager_menu->redraw |= REDRAW_STATUS | REDRAW_INDEX;
3409  if (C_Resolve)
3410  {
3411  ch = -1;
3412  rc = OP_NEXT_ENTRY;
3413  }
3414  break;
3415 
3416  case OP_UNDELETE_THREAD:
3417  case OP_UNDELETE_SUBTHREAD:
3418  {
3419  CHECK_MODE(IsEmail(extra));
3421  /* L10N: CHECK_ACL */
3422  /* L10N: Due to the implementation details we do not know whether we
3423  undelete zero, 1, 12, ... messages. So in English we use
3424  "messages". Your language might have other means to express this. */
3425  CHECK_ACL(MUTT_ACL_DELETE, _("Can't undelete messages"));
3426 
3427  int r = mutt_thread_set_flag(extra->email, MUTT_DELETE, false,
3428  (ch != OP_UNDELETE_THREAD));
3429  if (r != -1)
3430  {
3431  r = mutt_thread_set_flag(extra->email, MUTT_PURGE, false,
3432  (ch != OP_UNDELETE_THREAD));
3433  }
3434  if (r != -1)
3435  {
3436  if (C_Resolve)
3437  {
3438  rc = (ch == OP_DELETE_THREAD) ? OP_MAIN_NEXT_THREAD : OP_MAIN_NEXT_SUBTHREAD;
3439  ch = -1;
3440  }
3441 
3442  if (!C_Resolve && (C_PagerIndexLines != 0))
3443  pager_menu->redraw = REDRAW_FULL;
3444  else
3445  pager_menu->redraw |= REDRAW_STATUS | REDRAW_INDEX;
3446  }
3447  break;
3448  }
3449 
3450  case OP_VERSION:
3452  break;
3453 
3454  case OP_MAILBOX_LIST:
3456  break;
3457 
3458  case OP_VIEW_ATTACHMENTS:
3459  if (flags & MUTT_PAGER_ATTACHMENT)
3460  {
3461  ch = -1;
3462  rc = OP_ATTACH_COLLAPSE;
3463  break;
3464  }
3465  CHECK_MODE(IsEmail(extra));
3466  dlg_select_attachment(extra->email);
3467  if (Context && extra->email->attach_del)
3468  Context->mailbox->changed = true;
3469  pager_menu->redraw = REDRAW_FULL;
3470  break;
3471 
3472  case OP_MAIL_KEY:
3473  {
3474  if (!(WithCrypto & APPLICATION_PGP))
3475  {
3476  ch = -1;
3477  break;
3478  }
3479  CHECK_MODE(IsEmail(extra));
3480  CHECK_ATTACH;
3481  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3482  emaillist_add_email(&el, extra->email);
3483  mutt_send_message(SEND_KEY, NULL, NULL, extra->ctx, &el, NeoMutt->sub);
3484  emaillist_clear(&el);
3485  pager_menu->redraw = REDRAW_FULL;
3486  break;
3487  }
3488 
3489  case OP_EDIT_LABEL:
3490  {
3491  CHECK_MODE(IsEmail(extra));
3492 
3493  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3494  emaillist_add_email(&el, extra->email);
3495  rc = mutt_label_message(Context->mailbox, &el);
3496  emaillist_clear(&el);
3497 
3498  if (rc > 0)
3499  {
3500  Context->mailbox->changed = true;
3501  pager_menu->redraw = REDRAW_FULL;
3502  mutt_message(ngettext("%d label changed", "%d labels changed", rc), rc);
3503  }
3504  else
3505  {
3506  mutt_message(_("No labels changed"));
3507  }
3508  break;
3509  }
3510 
3511  case OP_FORGET_PASSPHRASE:
3513  break;
3514 
3515  case OP_EXTRACT_KEYS:
3516  {
3517  if (!WithCrypto)
3518  {
3519  ch = -1;
3520  break;
3521  }
3522  CHECK_MODE(IsEmail(extra));
3523  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3524  emaillist_add_email(&el, extra->email);
3526  emaillist_clear(&el);
3527  pager_menu->redraw = REDRAW_FULL;
3528  break;
3529  }
3530 
3531  case OP_WHAT_KEY:
3532  mutt_what_key();
3533  break;
3534 
3535  case OP_CHECK_STATS:
3536  mutt_check_stats();
3537  break;
3538 
3539 #ifdef USE_SIDEBAR
3540  case OP_SIDEBAR_FIRST:
3541  case OP_SIDEBAR_LAST:
3542  case OP_SIDEBAR_NEXT:
3543  case OP_SIDEBAR_NEXT_NEW:
3544  case OP_SIDEBAR_PAGE_DOWN:
3545  case OP_SIDEBAR_PAGE_UP:
3546  case OP_SIDEBAR_PREV:
3547  case OP_SIDEBAR_PREV_NEW:
3548  {
3549  struct MuttWindow *win_sidebar =
3551  if (!win_sidebar)
3552  break;
3553  sb_change_mailbox(win_sidebar, ch);
3554  break;
3555  }
3556 
3557  case OP_SIDEBAR_TOGGLE_VISIBLE:
3558  bool_str_toggle(NeoMutt->sub, "sidebar_visible", NULL);
3560  break;
3561 #endif
3562 
3563  default:
3564  ch = -1;
3565  break;
3566  }
3567  }
3568 
3569  mutt_file_fclose(&rd.fp);
3570  if (IsEmail(extra))
3571  {
3572  if (Context)
3573  Context->msg_in_pager = -1;
3574  switch (rc)
3575  {
3576  case -1:
3577  case OP_DISPLAY_HEADERS:
3579  break;
3580  default:
3581  TopLine = rd.topline;
3582  OldEmail = extra->email;
3583  break;
3584  }
3585  }
3586 
3588 
3589  for (size_t i = 0; i < rd.max_line; i++)
3590  {
3591  FREE(&(rd.line_info[i].syntax));
3592  if (rd.search_compiled && rd.line_info[i].search)
3593  FREE(&(rd.line_info[i].search));
3594  }
3595  if (rd.search_compiled)
3596  {
3597  regfree(&rd.search_re);
3598  rd.search_compiled = false;
3599  }
3600  FREE(&rd.line_info);
3601  mutt_menu_pop_current(pager_menu);
3602  mutt_menu_free(&pager_menu);
3603  mutt_menu_free(&rd.menu);
3604 
3605  if (rd.extra->win_index)
3606  {
3612  }
3615 
3616  return (rc != -1) ? rc : 0;
3617 }
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:651
#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 * 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:145
struct Email * mutt_get_virt_email(struct Mailbox *m, int vnum)
Get a virtual Email.
Definition: context.c:396
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:763
&#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:678
#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:539
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:382
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
void alias_create(struct AddressList *al, const struct ConfigSubset *sub)
Create a new Alias from an Address.
Definition: alias.c:366
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:170
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:1508
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:433
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:1995
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:747
#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:348
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:155
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.