NeoMutt  2019-11-11
Teaching an old dog new tricks
DOXYGEN
pager.c File Reference

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

#include "config.h"
#include <ctype.h>
#include <errno.h>
#include <inttypes.h>
#include <limits.h>
#include <regex.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include <wchar.h>
#include "mutt/mutt.h"
#include "config/lib.h"
#include "email/lib.h"
#include "core/lib.h"
#include "mutt.h"
#include "pager.h"
#include "alias.h"
#include "color.h"
#include "commands.h"
#include "context.h"
#include "curs_lib.h"
#include "format_flags.h"
#include "globals.h"
#include "hdrline.h"
#include "hook.h"
#include "index.h"
#include "keymap.h"
#include "mutt_attach.h"
#include "mutt_curses.h"
#include "mutt_header.h"
#include "mutt_logging.h"
#include "mutt_mailbox.h"
#include "mutt_menu.h"
#include "mutt_window.h"
#include "muttlib.h"
#include "mx.h"
#include "ncrypt/ncrypt.h"
#include "opcodes.h"
#include "options.h"
#include "protos.h"
#include "recvattach.h"
#include "recvcmd.h"
#include "send.h"
#include "status.h"
#include "terminal.h"
#include "sidebar.h"
#include "nntp/nntp.h"
#include <libintl.h>

Go to the source code of this file.

Data Structures

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

Macros

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

Typedefs

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

Functions

static int check_sig (const char *s, struct Line *info, int n)
 Check for an email signature. More...
 
static int comp_syntax_t (const void *m1, const void *m2)
 Search for a Syntax using bsearch. More...
 
static void resolve_color (struct Line *line_info, int n, int cnt, PagerFlags flags, int special, struct AnsiAttr *a)
 Set the colour for a line of text. More...
 
static void append_line (struct Line *line_info, int n, int cnt)
 Add a new Line to the array. More...
 
static void class_color_new (struct QClass *qc, int *q_level)
 Create a new quoting colour. More...
 
static void shift_class_colors (struct QClass *quote_list, struct QClass *new_class, int index, int *q_level)
 Insert a new quote colour class into a list. More...
 
static void cleanup_quote (struct QClass **quote_list)
 Free a quote list. More...
 
static struct QClassclassify_quote (struct QClass **quote_list, const char *qptr, size_t length, bool *force_redraw, int *q_level)
 Find a style for a string. More...
 
static int check_marker (const char *q, const char *p)
 Check that the unique marker is present. More...
 
static int check_attachment_marker (const char *p)
 Check that the unique marker is present. More...
 
static int check_protected_header_marker (const char *p)
 Check that the unique marker is present. More...
 
int mutt_is_quote_line (char *line, regmatch_t *pmatch)
 Is a line of message text a quote? More...
 
static void resolve_types (char *buf, char *raw, struct Line *line_info, int n, int last, struct QClass **quote_list, int *q_level, bool *force_redraw, bool q_classify)
 Determine the style for a line of text. More...
 
static bool is_ansi (unsigned char *buf)
 Is this an ANSI escape sequence? More...
 
static int grok_ansi (unsigned char *buf, int pos, struct AnsiAttr *a)
 Parse an ANSI escape sequence. More...
 
static int fill_buffer (FILE *fp, LOFF_T *last_pos, LOFF_T offset, unsigned char **buf, unsigned char **fmt, size_t *blen, int *buf_ready)
 Fill a buffer from a file. More...
 
static int format_line (struct Line **line_info, int n, unsigned char *buf, PagerFlags flags, struct AnsiAttr *pa, int cnt, int *pspace, int *pvch, int *pcol, int *pspecial, int width)
 Display a line of text in the pager. More...
 
static int display_line (FILE *fp, LOFF_T *last_pos, struct Line **line_info, int n, int *last, int *max, PagerFlags flags, struct QClass **quote_list, int *q_level, bool *force_redraw, regex_t *search_re, struct MuttWindow *pager_window)
 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::menu_custom_redraw() More...
 
int mutt_pager (const char *banner, const char *fname, PagerFlags flags, struct Pager *extra)
 Display a file, or help, in a window. More...
 

Variables

bool C_AllowAnsi
 Config: Allow ANSI colour codes in rich text messages. More...
 
bool C_HeaderColorPartial
 Config: Only colour the part of the header matching the regex. More...
 
short C_PagerContext
 Config: Number of lines of overlap when changing pages in the pager. More...
 
short C_PagerIndexLines
 Config: Number of index lines to display above the pager. More...
 
bool C_PagerStop
 Config: Don't automatically open the next message when at the end of a message. More...
 
short C_SearchContext
 Config: Context to display around search matches. More...
 
short C_SkipQuotedOffset
 Config: Lines of context to show when skipping quoted text. More...
 
bool C_SmartWrap
 Config: Wrap text at word boundaries. More...
 
struct RegexC_Smileys
 Config: Regex to match smileys to prevent mistakes when quoting text. More...
 
bool C_Tilde
 Config: Character to pad blank lines in the pager. More...
 
static int TopLine = 0
 
static struct EmailOldEmail = NULL
 
static bool InHelp = false
 
static int braille_line = -1
 
static int braille_col = -1
 
static struct ResizeResize = NULL
 
static const char * Not_available_in_this_menu
 
static const char * Mailbox_is_read_only = N_("Mailbox is read-only")
 
static const char * Function_not_permitted_in_attach_message_mode
 
static const struct Mapping PagerHelp []
 
static const struct Mapping PagerHelpExtra []
 
static struct Mapping PagerNewsHelpExtra []
 

Detailed Description

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

Authors
  • Michael R. Elkins

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

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

Definition in file pager.c.

Macro Definition Documentation

◆ ANSI_NO_FLAGS

#define ANSI_NO_FLAGS   0

No flags are set.

Definition at line 102 of file pager.c.

◆ ANSI_OFF

#define ANSI_OFF   (1 << 0)

Turn off colours and attributes.

Definition at line 103 of file pager.c.

◆ ANSI_BLINK

#define ANSI_BLINK   (1 << 1)

Blinking text.

Definition at line 104 of file pager.c.

◆ ANSI_BOLD

#define ANSI_BOLD   (1 << 2)

Bold text.

Definition at line 105 of file pager.c.

◆ ANSI_UNDERLINE

#define ANSI_UNDERLINE   (1 << 3)

Underlined text.

Definition at line 106 of file pager.c.

◆ ANSI_REVERSE

#define ANSI_REVERSE   (1 << 4)

Reverse video.

Definition at line 107 of file pager.c.

◆ ANSI_COLOR

#define ANSI_COLOR   (1 << 5)

Use colours.

Definition at line 108 of file pager.c.

◆ IS_HEADER

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

Definition at line 252 of file pager.c.

◆ IsAttach

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

Definition at line 254 of file pager.c.

◆ IsMsgAttach

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

Definition at line 255 of file pager.c.

◆ IsEmail

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

Definition at line 257 of file pager.c.

◆ NUM_SIG_LINES

#define NUM_SIG_LINES   4

Definition at line 259 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:221
static struct UrlTest test[]
Definition: url_parse.c:40

Definition at line 261 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:36
#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:130
static const char * Mailbox_is_read_only
Definition: pager.c:223

Definition at line 269 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:224

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

Definition at line 285 of file pager.c.

Typedef Documentation

◆ AnsiFlags

typedef uint8_t AnsiFlags

Flags, e.g. ANSI_OFF.

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

303 {
304  int count = 0;
305 
306  while ((n > 0) && (count <= NUM_SIG_LINES))
307  {
308  if (info[n].type != MT_COLOR_SIGNATURE)
309  break;
310  count++;
311  n--;
312  }
313 
314  if (count == 0)
315  return -1;
316 
317  if (count > NUM_SIG_LINES)
318  {
319  /* check for a blank line */
320  while (*s)
321  {
322  if (!IS_SPACE(*s))
323  return 0;
324  s++;
325  }
326 
327  return -1;
328  }
329 
330  return 0;
331 }
Pager: signature lines.
Definition: color.h:94
#define NUM_SIG_LINES
Definition: pager.c:259
#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 341 of file pager.c.

342 {
343  const int *cnt = (const int *) m1;
344  const struct TextSyntax *stx = (const struct TextSyntax *) m2;
345 
346  if (*cnt < stx->first)
347  return -1;
348  if (*cnt >= stx->last)
349  return 1;
350  return 0;
351 }
int last
Definition: pager.c:131
Highlighting for a line of text.
Definition: pager.c:127
int first
Definition: pager.c:130
+ 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 362 of file pager.c.

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

495 {
496  int m;
497 
498  line_info[n + 1].type = line_info[n].type;
499  (line_info[n + 1].syntax)[0].color = (line_info[n].syntax)[0].color;
500  line_info[n + 1].continuation = 1;
501 
502  /* find the real start of the line */
503  for (m = n; m >= 0; m--)
504  if (line_info[m].continuation == 0)
505  break;
506 
507  (line_info[n + 1].syntax)[0].first = m;
508  (line_info[n + 1].syntax)[0].last =
509  (line_info[n].continuation) ? cnt + (line_info[n].syntax)[0].last : cnt;
510 }
short type
Definition: pager.c:140
short continuation
Definition: pager.c:141
int color
Definition: pager.c:118
struct TextSyntax * syntax
Definition: pager.c:144
+ 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 517 of file pager.c.

518 {
519  qc->index = (*q_level)++;
520  qc->color = Colors->quotes[qc->index % Colors->quotes_used];
521 }
Definition: color.h:130
int color
Definition: pager.c:118
int index
Definition: pager.c:117
int quotes_used
Number of colours for quoted email text.
Definition: color.h:145
int * quotes
Array of colours for quoted email text.
Definition: color.h:144
+ Here is the caller graph for this function:

◆ shift_class_colors()

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

Insert a new quote colour class into a list.

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

Definition at line 530 of file pager.c.

532 {
533  struct QClass *q_list = quote_list;
534  new_class->index = -1;
535 
536  while (q_list)
537  {
538  if (q_list->index >= index)
539  {
540  q_list->index++;
541  q_list->color = Colors->quotes[q_list->index % Colors->quotes_used];
542  }
543  if (q_list->down)
544  q_list = q_list->down;
545  else if (q_list->next)
546  q_list = q_list->next;
547  else
548  {
549  while (!q_list->next)
550  {
551  q_list = q_list->up;
552  if (!q_list)
553  break;
554  }
555  if (q_list)
556  q_list = q_list->next;
557  }
558  }
559 
560  new_class->index = index;
561  new_class->color = Colors->quotes[index % Colors->quotes_used];
562  (*q_level)++;
563 }
struct QClass * down
Definition: pager.c:121
struct QClass * next
Definition: pager.c:120
Definition: color.h:130
int color
Definition: pager.c:118
int index
Definition: pager.c:117
int quotes_used
Number of colours for quoted email text.
Definition: color.h:145
struct QClass * up
Definition: pager.c:121
Style of quoted text.
Definition: pager.c:114
int * quotes
Array of colours for quoted email text.
Definition: color.h:144
+ Here is the caller graph for this function:

◆ cleanup_quote()

static void cleanup_quote ( struct QClass **  quote_list)
static

Free a quote list.

Parameters
[out]quote_listQuote list to free

Definition at line 569 of file pager.c.

570 {
571  struct QClass *ptr = NULL;
572 
573  while (*quote_list)
574  {
575  if ((*quote_list)->down)
576  cleanup_quote(&((*quote_list)->down));
577  ptr = (*quote_list)->next;
578  FREE(&(*quote_list)->prefix);
579  FREE(quote_list);
580  *quote_list = ptr;
581  }
582 }
static void cleanup_quote(struct QClass **quote_list)
Free a quote list.
Definition: pager.c:569
struct QClass * next
Definition: pager.c:120
#define FREE(x)
Definition: memory.h:40
Style of quoted text.
Definition: pager.c:114
+ 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 593 of file pager.c.

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

◆ check_marker()

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

Check that the unique marker is present.

Parameters
qMarker string
pString to check
Return values
numOffset of marker

Definition at line 905 of file pager.c.

906 {
907  for (; (p[0] == q[0]) && (q[0] != '\0') && (p[0] != '\0') && (q[0] != '\a') &&
908  (p[0] != '\a');
909  p++, q++)
910  {
911  }
912 
913  return (int) (*p - *q);
914 }
+ 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 921 of file pager.c.

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

932 {
934 }
static int check_marker(const char *q, const char *p)
Check that the unique marker is present.
Definition: pager.c:905
WHERE char ProtectedHeaderMarker[256]
Unique ANSI string to mark protected headers in an email.
Definition: globals.h:49
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_is_quote_line()

int mutt_is_quote_line ( char *  line,
regmatch_t *  pmatch 
)

Is a line of message text a quote?

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

Checks if line matches the C_QuoteRegex and doesn't match C_Smileys. This is used by the pager for calling classify_quote.

Definition at line 945 of file pager.c.

946 {
947  bool is_quote = false;
948  regmatch_t pmatch_internal[1], smatch[1];
949 
950  if (!pmatch)
951  pmatch = pmatch_internal;
952 
953  if (mutt_regex_capture(C_QuoteRegex, line, 1, pmatch))
954  {
955  if (mutt_regex_capture(C_Smileys, line, 1, smatch))
956  {
957  if (smatch[0].rm_so > 0)
958  {
959  char c = line[smatch[0].rm_so];
960  line[smatch[0].rm_so] = 0;
961 
962  if (mutt_regex_capture(C_QuoteRegex, line, 1, pmatch))
963  is_quote = true;
964 
965  line[smatch[0].rm_so] = c;
966  }
967  }
968  else
969  is_quote = true;
970  }
971 
972  return is_quote;
973 }
struct Regex * C_Smileys
Config: Regex to match smileys to prevent mistakes when quoting text.
Definition: pager.c:96
const char * line
Definition: common.c:36
WHERE struct Regex * C_QuoteRegex
Config: Regex to match quoted text in a reply.
Definition: globals.h:179
bool mutt_regex_capture(const struct Regex *regex, const char *str, size_t nmatch, regmatch_t matches[])
match a regex against a string, with provided options
Definition: regex.c:594
+ 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 987 of file pager.c.

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

◆ is_ansi()

static bool is_ansi ( unsigned char *  buf)
static

Is this an ANSI escape sequence?

Parameters
bufString to check
Return values
trueIf it is

Definition at line 1253 of file pager.c.

1254 {
1255  while ((*buf != '\0') && (isdigit(*buf) || (*buf == ';')))
1256  buf++;
1257  return *buf == 'm';
1258 }
+ 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 1267 of file pager.c.

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

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

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

Definition at line 1633 of file pager.c.

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

1916 {
1917  while ((cur > 0) && (nlines > 0))
1918  {
1919  cur--;
1920  if (!hiding || (info[cur].type != MT_COLOR_QUOTED))
1921  nlines--;
1922  }
1923 
1924  return cur;
1925 }
short type
Definition: pager.c:140
Pager: quoted text.
Definition: color.h:82
+ Here is the caller graph for this function:

◆ mutt_clear_pager_position()

void mutt_clear_pager_position ( void  )

Reset the pager's viewing position.

Definition at line 1930 of file pager.c.

1931 {
1932  TopLine = 0;
1933  OldEmail = NULL;
1934 }
static int TopLine
Definition: pager.c:211
static struct Email * OldEmail
Definition: pager.c:212
+ 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::menu_custom_redraw()

Definition at line 1939 of file pager.c.

1940 {
1941  struct PagerRedrawData *rd = pager_menu->redraw_data;
1942  char buf[1024];
1943 
1944  if (!rd)
1945  return;
1946 
1947  if (pager_menu->redraw & REDRAW_FULL)
1948  {
1951 
1952  if (IsEmail(rd->extra) && Context && ((Context->mailbox->vcount + 1) < C_PagerIndexLines))
1953  rd->indexlen = Context->mailbox->vcount + 1;
1954  else
1956 
1957  rd->indicator = rd->indexlen / 3;
1958 
1961  rd->index_status_window->rows = 0;
1962  rd->index_window->rows = 0;
1963 
1964  if (IsEmail(rd->extra) && (C_PagerIndexLines != 0))
1965  {
1967  rd->index_window->rows = (rd->indexlen > 0) ? rd->indexlen - 1 : 0;
1968 
1969  if (C_StatusOnTop)
1970  {
1972 
1974  rd->pager_status_window->rows = 1;
1976 
1977  rd->pager_window->rows -=
1979  rd->pager_window->row_offset +=
1981  }
1982  else
1983  {
1985  rd->index_status_window->rows = 1;
1987 
1988  rd->pager_window->rows -=
1990  rd->pager_window->row_offset +=
1992  }
1993  }
1994 
1995  if (C_Help)
1996  {
2001  }
2002 
2003  if (Resize)
2004  {
2006  if (rd->search_compiled)
2007  {
2008  int flags = mutt_mb_is_lower(rd->searchbuf) ? REG_ICASE : 0;
2009  const int err = REG_COMP(&rd->search_re, rd->searchbuf, REG_NEWLINE | flags);
2010  if (err == 0)
2011  {
2012  rd->search_flag = MUTT_SEARCH;
2014  }
2015  else
2016  {
2017  regerror(err, &rd->search_re, buf, sizeof(buf));
2018  mutt_error("%s", buf);
2019  rd->search_compiled = false;
2020  }
2021  }
2022  rd->lines = Resize->line;
2023  pager_menu->redraw |= REDRAW_FLOW;
2024 
2025  FREE(&Resize);
2026  }
2027 
2028  if (IsEmail(rd->extra) && (C_PagerIndexLines != 0))
2029  {
2030  if (!rd->menu)
2031  {
2032  /* only allocate the space if/when we need the index.
2033  * Initialise the menu as per the main index */
2034  rd->menu = mutt_menu_new(MENU_MAIN);
2036  rd->menu->menu_color = index_color;
2037  rd->menu->max = Context ? Context->mailbox->vcount : 0;
2038  rd->menu->current = rd->extra->email->vnum;
2039  rd->menu->indexwin = rd->index_window;
2040  rd->menu->statuswin = rd->index_status_window;
2041  }
2042 
2044  rd->menu->pagelen = rd->index_window->rows;
2045 
2046  /* some fudge to work out whereabouts the indicator should go */
2047  if (rd->menu->current - rd->indicator < 0)
2048  rd->menu->top = 0;
2049  else if (rd->menu->max - rd->menu->current < rd->menu->pagelen - rd->indicator)
2050  rd->menu->top = rd->menu->max - rd->menu->pagelen;
2051  else
2052  rd->menu->top = rd->menu->current - rd->indicator;
2053 
2054  menu_redraw_index(rd->menu);
2055  }
2056 
2057  pager_menu->redraw |= REDRAW_BODY | REDRAW_INDEX | REDRAW_STATUS;
2058 #ifdef USE_SIDEBAR
2059  pager_menu->redraw |= REDRAW_SIDEBAR;
2060 #endif
2061  mutt_show_error();
2062  }
2063 
2064  if (pager_menu->redraw & REDRAW_FLOW)
2065  {
2066  if (!(rd->flags & MUTT_PAGER_RETWINCH))
2067  {
2068  rd->lines = -1;
2069  for (int i = 0; i <= rd->topline; i++)
2070  if (!rd->line_info[i].continuation)
2071  rd->lines++;
2072  for (int i = 0; i < rd->max_line; i++)
2073  {
2074  rd->line_info[i].offset = 0;
2075  rd->line_info[i].type = -1;
2076  rd->line_info[i].continuation = 0;
2077  rd->line_info[i].chunks = 0;
2078  rd->line_info[i].search_cnt = -1;
2079  rd->line_info[i].quote = NULL;
2080 
2081  mutt_mem_realloc(&(rd->line_info[i].syntax), sizeof(struct TextSyntax));
2082  if (rd->search_compiled && rd->line_info[i].search)
2083  FREE(&(rd->line_info[i].search));
2084  }
2085 
2086  rd->last_line = 0;
2087  rd->topline = 0;
2088  }
2089  int i = -1;
2090  int j = -1;
2091  while (display_line(rd->fp, &rd->last_pos, &rd->line_info, ++i, &rd->last_line,
2092  &rd->max_line, rd->has_types | rd->search_flag | (rd->flags & MUTT_PAGER_NOWRAP),
2093  &rd->quote_list, &rd->q_level, &rd->force_redraw,
2094  &rd->search_re, rd->pager_window) == 0)
2095  {
2096  if (!rd->line_info[i].continuation && (++j == rd->lines))
2097  {
2098  rd->topline = i;
2099  if (!rd->search_flag)
2100  break;
2101  }
2102  }
2103  }
2104 
2105 #ifdef USE_SIDEBAR
2106  if (pager_menu->redraw & REDRAW_SIDEBAR)
2107  {
2108  menu_redraw_sidebar(pager_menu);
2109  }
2110 #endif
2111 
2112  if ((pager_menu->redraw & REDRAW_BODY) || (rd->topline != rd->oldtopline))
2113  {
2114  do
2115  {
2116  mutt_window_move(rd->pager_window, 0, 0);
2117  rd->curline = rd->topline;
2118  rd->oldtopline = rd->topline;
2119  rd->lines = 0;
2120  rd->force_redraw = false;
2121 
2122  while ((rd->lines < rd->pager_window->rows) &&
2123  (rd->line_info[rd->curline].offset <= rd->sb.st_size - 1))
2124  {
2125  if (display_line(rd->fp, &rd->last_pos, &rd->line_info, rd->curline,
2126  &rd->last_line, &rd->max_line,
2127  (rd->flags & MUTT_DISPLAYFLAGS) | rd->hide_quoted |
2128  rd->search_flag | (rd->flags & MUTT_PAGER_NOWRAP),
2129  &rd->quote_list, &rd->q_level, &rd->force_redraw,
2130  &rd->search_re, rd->pager_window) > 0)
2131  {
2132  rd->lines++;
2133  }
2134  rd->curline++;
2135  mutt_window_move(rd->pager_window, rd->lines, 0);
2136  }
2137  rd->last_offset = rd->line_info[rd->curline].offset;
2138  } while (rd->force_redraw);
2139 
2141  while (rd->lines < rd->pager_window->rows)
2142  {
2144  if (C_Tilde)
2145  mutt_window_addch('~');
2146  rd->lines++;
2147  mutt_window_move(rd->pager_window, rd->lines, 0);
2148  }
2150 
2151  /* We are going to update the pager status bar, so it isn't
2152  * necessary to reset to normal color now. */
2153 
2154  pager_menu->redraw |= REDRAW_STATUS; /* need to update the % seen */
2155  }
2156 
2157  if (pager_menu->redraw & REDRAW_STATUS)
2158  {
2159  struct HdrFormatInfo hfi;
2160  char pager_progress_str[65]; /* Lots of space for translations */
2161 
2162  hfi.ctx = Context;
2163  hfi.mailbox = Context ? Context->mailbox : NULL;
2164  hfi.pager_progress = pager_progress_str;
2165 
2166  if (rd->last_pos < rd->sb.st_size - 1)
2167  {
2168  snprintf(pager_progress_str, sizeof(pager_progress_str), OFF_T_FMT "%%",
2169  (100 * rd->last_offset / rd->sb.st_size));
2170  }
2171  else
2172  {
2173  const char *msg = (rd->topline == 0) ?
2174  /* L10N: Status bar message: the entire email is visible in the pager */
2175  _("all") :
2176  /* L10N: Status bar message: the end of the email is visible in the pager */
2177  _("end");
2178  mutt_str_strfcpy(pager_progress_str, msg, sizeof(pager_progress_str));
2179  }
2180 
2181  /* print out the pager status bar */
2184 
2185  if (IsEmail(rd->extra) || IsMsgAttach(rd->extra))
2186  {
2187  size_t l1 = rd->pager_status_window->cols * MB_LEN_MAX;
2188  size_t l2 = sizeof(buf);
2189  hfi.email = (IsEmail(rd->extra)) ? rd->extra->email : rd->extra->body->email;
2190  mutt_make_string_info(buf, (l1 < l2) ? l1 : l2, rd->pager_status_window->cols,
2193  }
2194  else
2195  {
2196  char bn[256];
2197  snprintf(bn, sizeof(bn), "%s (%s)", rd->banner, pager_progress_str);
2198  mutt_draw_statusline(rd->pager_status_window->cols, bn, sizeof(bn));
2199  }
2201  if (C_TsEnabled && TsSupported && rd->menu)
2202  {
2203  menu_status_line(buf, sizeof(buf), rd->menu, NONULL(C_TsStatusFormat));
2204  mutt_ts_status(buf);
2205  menu_status_line(buf, sizeof(buf), rd->menu, NONULL(C_TsIconFormat));
2206  mutt_ts_icon(buf);
2207  }
2208  }
2209 
2210  if ((pager_menu->redraw & REDRAW_INDEX) && rd->menu)
2211  {
2212  /* redraw the pager_index indicator, because the
2213  * flags for this message might have changed. */
2214  if (rd->index_window->rows > 0)
2216 
2217  /* print out the index status bar */
2218  menu_status_line(buf, sizeof(buf), rd->menu, NONULL(C_StatusFormat));
2219 
2222  mutt_draw_statusline(rd->index_status_window->cols, buf, sizeof(buf));
2224  }
2225 
2226  pager_menu->redraw = REDRAW_NO_FLAGS;
2227 }
struct Menu * menu
the Pager Index (PI)
Definition: pager.c:197
struct Context * ctx
Definition: hdrline.h:47
The "current" mailbox.
Definition: context.h:36
WHERE bool C_StatusOnTop
Config: Display the status bar at the top.
Definition: globals.h:264
WHERE char * C_TsIconFormat
Config: printf-like format string for the terminal&#39;s icon title.
Definition: globals.h:149
#define REDRAW_FULL
Redraw everything.
Definition: mutt_menu.h:47
#define NONULL(x)
Definition: string2.h:37
const char * banner
Definition: pager.c:202
PagerFlags hide_quoted
Definition: pager.c:188
struct MuttWindow * MuttStatusWindow
Status Window.
Definition: mutt_window.c:41
PagerFlags search_flag
Definition: pager.c:200
#define MUTT_DISPLAYFLAGS
Definition: pager.h:60
short chunks
Definition: pager.c:142
Keep track when the pager needs redrawing.
Definition: pager.c:174
void mutt_curses_set_color(enum ColorId color)
Set the current colour for text.
Definition: mutt_curses.c:49
#define REDRAW_FLOW
Used by pager to reflow text.
Definition: mutt_menu.h:49
struct MuttWindow * pager_status_window
Definition: pager.c:195
void mutt_window_clrtoeol(struct MuttWindow *win)
Clear to the end of the line.
Definition: mutt_window.c:117
WHERE bool C_Help
Config: Display a help line with common key bindings.
Definition: globals.h:225
void index_make_entry(char *buf, size_t buflen, struct Menu *menu, int line)
Format a menu item for the index list - Implements Menu::menu_make_entry()
Definition: index.c:781
#define IsMsgAttach(pager)
Definition: pager.c:255
#define _(a)
Definition: message.h:28
const char * helpstr
Definition: pager.c:203
struct Line * line_info
Definition: pager.c:205
int index_color(int line)
Calculate the colour for a line of the index - Implements Menu::menu_color()
Definition: index.c:855
void menu_status_line(char *buf, size_t buflen, struct Menu *menu, const char *p)
Create the status line.
Definition: status.c:408
struct MuttWindow * MuttHelpWindow
Help Window.
Definition: mutt_window.c:39
struct Body * body
Current attachment.
Definition: pager.h:69
PagerFlags flags
Definition: pager.c:176
Index panel (list of emails)
Definition: keymap.h:77
bool search_back
Definition: pager.c:168
WHERE char * C_StatusFormat
Config: printf-like format string for the index&#39;s status line.
Definition: globals.h:147
bool search_compiled
Definition: pager.c:167
short type
Definition: pager.c:140
#define MUTT_PAGER_NOWRAP
Format for term width, ignore $wrap.
Definition: pager.h:56
WHERE bool C_TsEnabled
Config: Allow NeoMutt to set the terminal status line and icon.
Definition: globals.h:267
void(* menu_make_entry)(char *buf, size_t buflen, struct Menu *menu, int line)
Format a item for a menu.
Definition: mutt_menu.h:120
#define MUTT_FORMAT_NO_FLAGS
No flags are set.
Definition: format_flags.h:30
int vcount
The number of virtual messages.
Definition: mailbox.h:113
#define REDRAW_SIDEBAR
Redraw the sidebar.
Definition: mutt_menu.h:51
void mutt_paddstr(int n, const char *s)
Display a string on screen, padded if necessary.
Definition: curs_lib.c:1194
LOFF_T last_pos
Definition: pager.c:191
struct MuttWindow * index_status_window
Definition: pager.c:193
int line
Definition: pager.c:166
void * redraw_data
Definition: mutt_menu.h:150
void mutt_window_clear_screen(void)
Clear the entire screen.
Definition: mutt_window.c:437
Pager: empty lines after message.
Definition: color.h:96
struct Mailbox * mailbox
Definition: context.h:50
Data passed to index_format_str()
Definition: hdrline.h:45
void mutt_window_copy_size(const struct MuttWindow *win_src, struct MuttWindow *win_dst)
Copy the size of one Window to another.
Definition: mutt_window.c:250
int indexlen
Definition: pager.c:178
LOFF_T last_offset
Definition: pager.c:192
int has_types
Definition: pager.c:187
FILE * fp
Definition: pager.c:206
#define REG_COMP(preg, regex, cflags)
Compile a regular expression.
Definition: regex3.h:52
short continuation
Definition: pager.c:141
bool force_redraw
Definition: pager.c:186
Plain text.
Definition: color.h:78
void mutt_mem_realloc(void *ptr, size_t size)
Resize a block of memory on the heap.
Definition: memory.c:114
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:1521
int oldtopline
Definition: pager.c:180
struct Pager * extra
Definition: pager.c:177
struct QClass * quote
Definition: pager.c:146
short search_cnt
Definition: pager.c:143
struct MuttWindow * statuswin
Definition: mutt_menu.h:96
WHERE struct Context * Context
Definition: globals.h:44
struct TextSyntax * search
Definition: pager.c:145
#define REDRAW_STATUS
Redraw the status bar.
Definition: mutt_menu.h:46
bool search_compiled
Definition: pager.c:199
Status bar (takes a pattern)
Definition: color.h:95
struct MuttWindow * pager_window
Definition: pager.c:196
struct MuttWindow * MuttIndexWindow
Index Window.
Definition: mutt_window.c:40
struct MuttWindow * indexwin
Definition: mutt_menu.h:95
struct MuttWindow * index_window
Definition: pager.c:194
int top
Entry that is the top of the current page.
Definition: mutt_menu.h:108
int max_line
Definition: pager.c:182
size_t mutt_str_strfcpy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:750
int last_line
Definition: pager.c:183
int vnum
Virtual message number.
Definition: email.h:87
int pagelen
Number of entries per screen.
Definition: mutt_menu.h:92
bool TsSupported
Terminal Setting is supported.
Definition: terminal.c:42
int mutt_window_move(struct MuttWindow *win, int row, int col)
Move the cursor in a Window.
Definition: mutt_window.c:198
WHERE char * C_TsStatusFormat
Config: printf-like format string for the terminal&#39;s status (window title)
Definition: globals.h:148
int(* menu_color)(int line)
Calculate the colour for a line of the menu.
Definition: mutt_menu.h:144
int max
Number of entries in the menu.
Definition: mutt_menu.h:88
MuttRedrawFlags redraw
When to redraw the screen.
Definition: mutt_menu.h:89
struct QClass * quote_list
Definition: pager.c:190
#define IsEmail(pager)
Definition: pager.c:257
int indicator
the indicator line of the PI
Definition: pager.c:179
struct Email * email
Current message.
Definition: pager.h:68
Highlighting for a line of text.
Definition: pager.c:127
int mutt_window_addch(int ch)
Write one character to a Window.
Definition: mutt_window.c:366
#define MUTT_PAGER_RETWINCH
Need reformatting on SIGWINCH.
Definition: pager.h:54
#define MUTT_SEARCH
Resolve search patterns.
Definition: pager.h:47
#define REDRAW_BODY
Redraw the pager.
Definition: mutt_menu.h:48
char * searchbuf
Definition: pager.c:204
#define REDRAW_INDEX
Redraw the index.
Definition: mutt_menu.h:42
#define mutt_error(...)
Definition: logging.h:84
int row_offset
Definition: mutt_window.h:37
#define FREE(x)
Definition: memory.h:40
void mutt_ts_icon(char *str)
Set the icon in the terminal title bar.
Definition: terminal.c:117
bool C_Tilde
Config: Character to pad blank lines in the pager.
Definition: pager.c:97
struct TextSyntax * syntax
Definition: pager.c:144
void mutt_show_error(void)
Show the user an error message.
Definition: curs_lib.c:530
Keep track of screen resizing.
Definition: pager.c:164
void mutt_ts_status(char *str)
Set the text of the terminal title bar.
Definition: terminal.c:103
struct stat sb
Definition: pager.c:207
int current
Current entry.
Definition: mutt_menu.h:87
#define REDRAW_NO_FLAGS
No flags are set.
Definition: mutt_menu.h:41
LOFF_T offset
Definition: pager.c:139
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
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 *pager_window)
Print a line on screen.
Definition: pager.c:1633
void mutt_draw_statusline(int cols, const char *buf, size_t buflen)
Draw a highlighted status bar.
Definition: index.c:884
short C_PagerIndexLines
Config: Number of index lines to display above the pager.
Definition: pager.c:91
WHERE char * C_PagerFormat
Config: printf-like format string for the pager&#39;s status bar.
Definition: globals.h:135
regex_t search_re
Definition: pager.c:198
bool search_back
Definition: pager.c:201
+ 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 2244 of file pager.c.

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

◆ C_HeaderColorPartial

bool C_HeaderColorPartial

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

Definition at line 89 of file pager.c.

◆ C_PagerContext

short C_PagerContext

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

Definition at line 90 of file pager.c.

◆ C_PagerIndexLines

short C_PagerIndexLines

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

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

◆ C_SearchContext

short C_SearchContext

Config: Context to display around search matches.

Definition at line 93 of file pager.c.

◆ C_SkipQuotedOffset

short C_SkipQuotedOffset

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

Definition at line 94 of file pager.c.

◆ C_SmartWrap

bool C_SmartWrap

Config: Wrap text at word boundaries.

Definition at line 95 of file pager.c.

◆ C_Smileys

struct Regex* C_Smileys

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

Definition at line 96 of file pager.c.

◆ C_Tilde

bool C_Tilde

Config: Character to pad blank lines in the pager.

Definition at line 97 of file pager.c.

◆ TopLine

int TopLine = 0
static

Definition at line 211 of file pager.c.

◆ OldEmail

struct Email* OldEmail = NULL
static

Definition at line 212 of file pager.c.

◆ InHelp

bool InHelp = false
static

Definition at line 214 of file pager.c.

◆ braille_line

int braille_line = -1
static

Definition at line 216 of file pager.c.

◆ braille_col

int braille_col = -1
static

Definition at line 217 of file pager.c.

◆ Resize

struct Resize* Resize = NULL
static

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

◆ Mailbox_is_read_only

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

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

◆ PagerHelp

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

Definition at line 227 of file pager.c.

◆ PagerHelpExtra

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

Definition at line 234 of file pager.c.

◆ PagerNewsHelpExtra

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

Definition at line 243 of file pager.c.