NeoMutt  2019-12-07-60-g0cfa53
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 "gui/lib.h"
#include "mutt.h"
#include "pager.h"
#include "alias.h"
#include "commands.h"
#include "context.h"
#include "format_flags.h"
#include "globals.h"
#include "hdrline.h"
#include "hook.h"
#include "index.h"
#include "keymap.h"
#include "mutt_attach.h"
#include "mutt_header.h"
#include "mutt_logging.h"
#include "mutt_mailbox.h"
#include "mutt_menu.h"
#include "muttlib.h"
#include "mx.h"
#include "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 "sidebar.h"
#include "nntp/nntp.h"
#include <libintl.h>
+ Include dependency graph for pager.c:

Go to the source code of this file.

Data Structures

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

Macros

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

Typedefs

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

Functions

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

◆ ANSI_OFF

#define ANSI_OFF   (1 << 0)

Turn off colours and attributes.

Definition at line 99 of file pager.c.

◆ ANSI_BLINK

#define ANSI_BLINK   (1 << 1)

Blinking text.

Definition at line 100 of file pager.c.

◆ ANSI_BOLD

#define ANSI_BOLD   (1 << 2)

Bold text.

Definition at line 101 of file pager.c.

◆ ANSI_UNDERLINE

#define ANSI_UNDERLINE   (1 << 3)

Underlined text.

Definition at line 102 of file pager.c.

◆ ANSI_REVERSE

#define ANSI_REVERSE   (1 << 4)

Reverse video.

Definition at line 103 of file pager.c.

◆ ANSI_COLOR

#define ANSI_COLOR   (1 << 5)

Use colours.

Definition at line 104 of file pager.c.

◆ IS_HEADER

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

Definition at line 244 of file pager.c.

◆ IsAttach

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

Definition at line 246 of file pager.c.

◆ IsMsgAttach

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

Definition at line 247 of file pager.c.

◆ IsEmail

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

Definition at line 249 of file pager.c.

◆ NUM_SIG_LINES

#define NUM_SIG_LINES   4

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

Definition at line 253 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:118
static const char * Mailbox_is_read_only
Definition: pager.c:215

Definition at line 261 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:216

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

Definition at line 277 of file pager.c.

Typedef Documentation

◆ AnsiFlags

typedef uint8_t AnsiFlags

Flags, e.g. ANSI_OFF.

Definition at line 97 of file pager.c.

Function Documentation

◆ check_sig()

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

Check for an email signature.

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

Definition at line 294 of file pager.c.

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

334 {
335  const int *cnt = (const int *) m1;
336  const struct TextSyntax *stx = (const struct TextSyntax *) m2;
337 
338  if (*cnt < stx->first)
339  return -1;
340  if (*cnt >= stx->last)
341  return 1;
342  return 0;
343 }
int last
Definition: pager.c:127
Highlighting for a line of text.
Definition: pager.c:123
int first
Definition: pager.c:126
+ Here is the caller graph for this function:

◆ resolve_color()

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

Set the colour for a line of text.

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

Definition at line 354 of file pager.c.

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

◆ append_line()

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

Add a new Line to the array.

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

Definition at line 486 of file pager.c.

487 {
488  int m;
489 
490  line_info[n + 1].type = line_info[n].type;
491  (line_info[n + 1].syntax)[0].color = (line_info[n].syntax)[0].color;
492  line_info[n + 1].continuation = 1;
493 
494  /* find the real start of the line */
495  for (m = n; m >= 0; m--)
496  if (line_info[m].continuation == 0)
497  break;
498 
499  (line_info[n + 1].syntax)[0].first = m;
500  (line_info[n + 1].syntax)[0].last =
501  (line_info[n].continuation) ? cnt + (line_info[n].syntax)[0].last : cnt;
502 }
short type
Definition: pager.c:136
short continuation
Definition: pager.c:137
int color
Definition: pager.c:114
struct TextSyntax * syntax
Definition: pager.c:140
+ Here is the caller graph for this function:

◆ class_color_new()

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

Create a new quoting colour.

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

Definition at line 509 of file pager.c.

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

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

562 {
563  struct QClass *ptr = NULL;
564 
565  while (*quote_list)
566  {
567  if ((*quote_list)->down)
568  cleanup_quote(&((*quote_list)->down));
569  ptr = (*quote_list)->next;
570  FREE(&(*quote_list)->prefix);
571  FREE(quote_list);
572  *quote_list = ptr;
573  }
574 }
static void cleanup_quote(struct QClass **quote_list)
Free a quote list.
Definition: pager.c:561
struct QClass * next
Definition: pager.c:116
#define FREE(x)
Definition: memory.h:40
Style of quoted text.
Definition: pager.c:110
+ Here is the caller graph for this function:

◆ classify_quote()

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

Find a style for a string.

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

Definition at line 585 of file pager.c.

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

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

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

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

◆ mutt_is_quote_line()

int mutt_is_quote_line ( char *  line,
regmatch_t *  pmatch 
)

Is a line of message text a quote?

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

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

Definition at line 937 of file pager.c.

938 {
939  bool is_quote = false;
940  regmatch_t pmatch_internal[1], smatch[1];
941 
942  if (!pmatch)
943  pmatch = pmatch_internal;
944 
945  if (mutt_regex_capture(C_QuoteRegex, line, 1, pmatch))
946  {
947  if (mutt_regex_capture(C_Smileys, line, 1, smatch))
948  {
949  if (smatch[0].rm_so > 0)
950  {
951  char c = line[smatch[0].rm_so];
952  line[smatch[0].rm_so] = 0;
953 
954  if (mutt_regex_capture(C_QuoteRegex, line, 1, pmatch))
955  is_quote = true;
956 
957  line[smatch[0].rm_so] = c;
958  }
959  }
960  else
961  is_quote = true;
962  }
963 
964  return is_quote;
965 }
struct Regex * C_Smileys
Config: Regex to match smileys to prevent mistakes when quoting text.
Definition: pager.c:92
const char * line
Definition: common.c:36
WHERE struct Regex * C_QuoteRegex
Config: Regex to match quoted text in a reply.
Definition: globals.h:174
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 979 of file pager.c.

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

◆ is_ansi()

static bool is_ansi ( unsigned char *  buf)
static

Is this an ANSI escape sequence?

Parameters
bufString to check
Return values
trueIf it is

Definition at line 1245 of file pager.c.

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

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

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

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

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

◆ display_line()

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

Print a line on screen.

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

Definition at line 1625 of file pager.c.

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

◆ up_n_lines()

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

Reposition the pager's view up by n lines.

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

Definition at line 1907 of file pager.c.

1908 {
1909  while ((cur > 0) && (nlines > 0))
1910  {
1911  cur--;
1912  if (!hiding || (info[cur].type != MT_COLOR_QUOTED))
1913  nlines--;
1914  }
1915 
1916  return cur;
1917 }
short type
Definition: pager.c:136
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 1922 of file pager.c.

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

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

◆ mutt_pager()

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

Display a file, or help, in a window.

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

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

Definition at line 2205 of file pager.c.

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

Variable Documentation

◆ C_AllowAnsi

bool C_AllowAnsi

Config: Allow ANSI colour codes in rich text messages.

Definition at line 84 of file pager.c.

◆ C_HeaderColorPartial

bool C_HeaderColorPartial

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

Definition at line 85 of file pager.c.

◆ C_PagerContext

short C_PagerContext

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

Definition at line 86 of file pager.c.

◆ C_PagerIndexLines

short C_PagerIndexLines

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

Definition at line 87 of file pager.c.

◆ C_PagerStop

bool C_PagerStop

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

Definition at line 88 of file pager.c.

◆ C_SearchContext

short C_SearchContext

Config: Context to display around search matches.

Definition at line 89 of file pager.c.

◆ C_SkipQuotedOffset

short C_SkipQuotedOffset

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

Definition at line 90 of file pager.c.

◆ C_SmartWrap

bool C_SmartWrap

Config: Wrap text at word boundaries.

Definition at line 91 of file pager.c.

◆ C_Smileys

struct Regex* C_Smileys

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

Definition at line 92 of file pager.c.

◆ C_Tilde

bool C_Tilde

Config: Character to pad blank lines in the pager.

Definition at line 93 of file pager.c.

◆ TopLine

int TopLine = 0
static

Definition at line 203 of file pager.c.

◆ OldEmail

struct Email* OldEmail = NULL
static

Definition at line 204 of file pager.c.

◆ InHelp

bool InHelp = false
static

Definition at line 206 of file pager.c.

◆ braille_line

int braille_line = -1
static

Definition at line 208 of file pager.c.

◆ braille_col

int braille_col = -1
static

Definition at line 209 of file pager.c.

◆ Resize

struct Resize* Resize = NULL
static

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

◆ Mailbox_is_read_only

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

Definition at line 215 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 216 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 219 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 226 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 235 of file pager.c.