NeoMutt  2020-06-26-30-g76c339
Teaching an old dog new tricks
DOXYGEN
pager.c File Reference

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

#include "config.h"
#include <ctype.h>
#include <errno.h>
#include <inttypes.h>
#include <limits.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include <wchar.h>
#include "mutt/lib.h"
#include "config/lib.h"
#include "email/lib.h"
#include "core/lib.h"
#include "alias/lib.h"
#include "gui/lib.h"
#include "mutt.h"
#include "pager.h"
#include "commands.h"
#include "context.h"
#include "format_flags.h"
#include "globals.h"
#include "hdrline.h"
#include "hook.h"
#include "index.h"
#include "init.h"
#include "keymap.h"
#include "mutt_attach.h"
#include "mutt_header.h"
#include "mutt_logging.h"
#include "mutt_mailbox.h"
#include "mutt_menu.h"
#include "muttlib.h"
#include "mx.h"
#include "opcodes.h"
#include "options.h"
#include "protos.h"
#include "recvattach.h"
#include "recvcmd.h"
#include "send.h"
#include "status.h"
#include "ncrypt/lib.h"
#include "sidebar.h"
#include "nntp/lib.h"
#include <libintl.h>
+ Include dependency graph for pager.c:

Go to the source code of this file.

Data Structures

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

Macros

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

Typedefs

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

Functions

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

Variables

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

Detailed Description

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

Authors
  • Michael R. Elkins

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

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

Definition in file pager.c.

Macro Definition Documentation

◆ ANSI_NO_FLAGS

#define ANSI_NO_FLAGS   0

No flags are set.

Definition at line 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
struct TestData test[]

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:37
#define _(a)
Definition: message.h:28
struct Mailbox * mailbox
Definition: context.h:50
bool readonly
Don&#39;t allow changes to the mailbox.
Definition: mailbox.h:119
static const char * Mailbox_is_read_only
Definition: pager.c: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:37
#define _(a)
Definition: message.h:28
struct Mailbox * mailbox
Definition: context.h:50
AclFlags rights
ACL bits, see AclFlags.
Definition: mailbox.h:121

Definition at line 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 }
enum MailboxType type
Mailbox type.
Definition: mailbox.h:105
Pager: signature lines.
Definition: color.h:93
#define NUM_SIG_LINES
Definition: pager.c:251
#define IS_SPACE(ch)
Definition: string2.h:38
int n
Definition: acutest.h:492
+ 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:64
Underlined text.
Definition: color.h:97
if(!test_colorize_)
Definition: acutest.h:499
#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:131
int last
Definition: pager.c:127
short type
Definition: pager.c:136
Pager: quoted text.
Definition: color.h:81
#define ANSI_BOLD
Bold text.
Definition: pager.c:101
AnsiFlags attr
Attributes, e.g. underline, bold, etc.
Definition: pager.c:151
static int comp_syntax_t(const void *m1, const void *m2)
Search for a Syntax using bsearch.
Definition: pager.c:333
#define ANSI_BLINK
Blinking text.
Definition: pager.c:100
Message headers (takes a pattern)
Definition: color.h:72
Pager: markers, line continuation.
Definition: color.h:74
Plain text.
Definition: color.h:77
#define ANSI_REVERSE
Reverse video.
Definition: pager.c:103
struct QClass * quote
Definition: pager.c:142
int bg
Background colour.
Definition: pager.c:153
#define ANSI_UNDERLINE
Underlined text.
Definition: pager.c:102
Definition: color.h:129
#define MUTT_PAGER_LOGS
Logview mode.
Definition: pager.h:57
int fg
Foreground colour.
Definition: pager.c:152
Highlighting for a line of text.
Definition: pager.c:123
int mutt_window_addch(int ch)
Write one character to a Window.
Definition: mutt_window.c:491
#define MUTT_SEARCH
Resolve search patterns.
Definition: pager.h:47
int n
Definition: acutest.h:492
int mutt_color_alloc(struct Colors *c, uint32_t fg, uint32_t bg)
Allocate a colour pair.
Definition: color.c:471
int color
Definition: pager.c:114
Pager: search matches.
Definition: color.h:82
struct TextSyntax * syntax
Definition: pager.c:140
int first
Definition: pager.c:126
void mutt_curses_set_attr(int attr)
Set the attributes for text.
Definition: mutt_curses.c:40
WHERE bool C_Markers
Config: Display a &#39;+&#39; at the beginning of wrapped lines in the pager.
Definition: globals.h:233
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 n
Definition: acutest.h:492
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:129
int color
Definition: pager.c:114
int index
Definition: pager.c:113
int quotes_used
Number of colours for quoted email text.
Definition: color.h:144
int * quotes
Array of colours for quoted email text.
Definition: color.h:143
+ Here is the caller graph for this function:

◆ shift_class_colors()

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

Insert a new quote colour class into a list.

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

Definition at line 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:129
int color
Definition: pager.c:114
int index
Definition: pager.c:113
int quotes_used
Number of colours for quoted email text.
Definition: color.h:144
struct QClass * up
Definition: pager.c:117
Style of quoted text.
Definition: pager.c:110
int * quotes
Array of colours for quoted email text.
Definition: color.h:143
+ Here is the caller graph for this function:

◆ cleanup_quote()

static void cleanup_quote ( struct QClass **  quote_list)
static

Free a quote list.

Parameters
[out]quote_listQuote list to free

Definition at line 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_strn_equal(qptr, q_list->prefix, length))
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_strn_equal(qptr, q_list->prefix, q_list->length))
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_strn_equal(tail_qptr, (q_list->prefix) + offset, tail_lng))
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_strn_equal(tail_qptr, (q_list->prefix) + offset,
810  q_list->length - offset))
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:129
bool mutt_strn_equal(const char *a, const char *b, size_t l)
Check for equality of two strings (to a maximum), safely.
Definition: string.c:601
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:144
struct QClass * up
Definition: pager.c:117
Style of quoted text.
Definition: pager.c:110
int * quotes
Array of colours for quoted email text.
Definition: color.h:143
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ check_marker()

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

Check that the unique marker is present.

Parameters
qMarker string
pString to check
Return values
numOffset of marker

Definition at line 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:47
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:48
+ 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
WHERE struct Regex * C_QuoteRegex
Config: Regex to match quoted text in a reply.
Definition: globals.h:170
bool mutt_regex_capture(const struct Regex *regex, const char *str, size_t nmatch, regmatch_t matches[])
match a regex against a string, with provided options
Definition: regex.c:593
int const char int line
Definition: acutest.h:617
+ 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")) // 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_equal("-- \n", buf) || mutt_str_equal("-- \r\n", buf))
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_len(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_len(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 }
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:879
Header default colour.
Definition: color.h:71
static int check_protected_header_marker(const char *p)
Check that the unique marker is present.
Definition: pager.c:923
struct ColorLineList body_list
List of colours applied to the email body.
Definition: color.h:134
short chunks
Definition: pager.c:138
int pair
Colour pair index.
Definition: color.h:43
Pager: signature lines.
Definition: color.h:93
short type
Definition: pager.c:136
Pager: quoted text.
Definition: color.h:81
static int braille_line
Definition: pager.c:208
Message headers (takes a pattern)
Definition: color.h:72
struct ColorLineList hdr_list
List of colours applied to the email headers.
Definition: color.h:135
Plain text.
Definition: color.h:77
void mutt_mem_realloc(void *ptr, size_t size)
Resize a block of memory on the heap.
Definition: memory.c:114
struct QClass * quote
Definition: pager.c:142
static int braille_col
Definition: pager.c:209
size_t mutt_str_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix.
Definition: string.c:165
bool stop_matching
Used by the pager for body patterns, to prevent the color from being retried once it fails...
Definition: color.h:45
#define IS_HEADER(x)
Definition: pager.c:244
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:349
Definition: color.h:129
regex_t regex
Compiled regex.
Definition: color.h:37
Highlighting for a line of text.
Definition: pager.c:123
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:639
int n
Definition: acutest.h:492
MIME attachments text (entire line)
Definition: color.h:61
bool C_HeaderColorPartial
Config: Only colour the part of the header matching the regex.
Definition: pager.c:85
struct TextSyntax * syntax
Definition: pager.c:140
struct ColorLineList attach_list
List of colours applied to the attachment headers.
Definition: color.h:133
int mutt_is_quote_line(char *line, regmatch_t *pmatch)
Is a line of message text a quote?
Definition: pager.c: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
unsigned int is_cont_hdr
this line is a continuation of the previous header line
Definition: pager.c:143
A regular expression and a color to highlight a line.
Definition: color.h:35
int color
Definition: pager.c:125
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ is_ansi()

static bool is_ansi ( 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:129
int fg
Foreground colour.
Definition: pager.c:152
#define ANSI_OFF
Turn off colours and attributes.
Definition: pager.c:99
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

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

1434 {
1435  int space = -1; /* index of the last space or TAB */
1436  int col = C_Markers ? (*line_info)[n].continuation : 0;
1437  size_t k;
1438  int ch, vch, last_special = -1, special = 0, t;
1439  wchar_t wc;
1440  mbstate_t mbstate;
1441  int wrap_cols = mutt_window_wrap_cols(width, (flags & MUTT_PAGER_NOWRAP) ? 0 : C_Wrap);
1442 
1443  if (check_attachment_marker((char *) buf) == 0)
1444  wrap_cols = width;
1445 
1446  /* FIXME: this should come from line_info */
1447  memset(&mbstate, 0, sizeof(mbstate));
1448 
1449  for (ch = 0, vch = 0; ch < cnt; ch += k, vch += k)
1450  {
1451  /* Handle ANSI sequences */
1452  while ((cnt - ch >= 2) && (buf[ch] == '\033') && (buf[ch + 1] == '[') && // Escape
1453  is_ansi(buf + ch + 2))
1454  {
1455  ch = grok_ansi(buf, ch + 2, pa) + 1;
1456  }
1457 
1458  while ((cnt - ch >= 2) && (buf[ch] == '\033') && (buf[ch + 1] == ']') && // Escape
1459  ((check_attachment_marker((char *) buf + ch) == 0) ||
1460  (check_protected_header_marker((char *) buf + ch) == 0)))
1461  {
1462  while (buf[ch++] != '\a')
1463  if (ch >= cnt)
1464  break;
1465  }
1466 
1467  /* is anything left to do? */
1468  if (ch >= cnt)
1469  break;
1470 
1471  k = mbrtowc(&wc, (char *) buf + ch, cnt - ch, &mbstate);
1472  if ((k == (size_t)(-2)) || (k == (size_t)(-1)))
1473  {
1474  if (k == (size_t)(-1))
1475  memset(&mbstate, 0, sizeof(mbstate));
1476  mutt_debug(LL_DEBUG1, "mbrtowc returned %lu; errno = %d\n", k, errno);
1477  if (col + 4 > wrap_cols)
1478  break;
1479  col += 4;
1480  if (pa)
1481  mutt_window_printf("\\%03o", buf[ch]);
1482  k = 1;
1483  continue;
1484  }
1485  if (k == 0)
1486  k = 1;
1487 
1488  if (CharsetIsUtf8)
1489  {
1490  /* zero width space, zero width no-break space */
1491  if ((wc == 0x200B) || (wc == 0xFEFF))
1492  {
1493  mutt_debug(LL_DEBUG3, "skip zero-width character U+%04X\n", (unsigned short) wc);
1494  continue;
1495  }
1497  {
1498  mutt_debug(LL_DEBUG3, "filtered U+%04X\n", (unsigned short) wc);
1499  continue;
1500  }
1501  }
1502 
1503  /* Handle backspace */
1504  special = 0;
1505  if (IsWPrint(wc))
1506  {
1507  wchar_t wc1;
1508  mbstate_t mbstate1 = mbstate;
1509  size_t k1 = mbrtowc(&wc1, (char *) buf + ch + k, cnt - ch - k, &mbstate1);
1510  while ((k1 != (size_t)(-2)) && (k1 != (size_t)(-1)) && (k1 > 0) && (wc1 == '\b'))
1511  {
1512  const size_t k2 =
1513  mbrtowc(&wc1, (char *) buf + ch + k + k1, cnt - ch - k - k1, &mbstate1);
1514  if ((k2 == (size_t)(-2)) || (k2 == (size_t)(-1)) || (k2 == 0) || (!IsWPrint(wc1)))
1515  break;
1516 
1517  if (wc == wc1)
1518  {
1519  special |= ((wc == '_') && (special & A_UNDERLINE)) ? A_UNDERLINE : A_BOLD;
1520  }
1521  else if ((wc == '_') || (wc1 == '_'))
1522  {
1523  special |= A_UNDERLINE;
1524  wc = (wc1 == '_') ? wc : wc1;
1525  }
1526  else
1527  {
1528  /* special = 0; / * overstrike: nothing to do! */
1529  wc = wc1;
1530  }
1531 
1532  ch += k + k1;
1533  k = k2;
1534  mbstate = mbstate1;
1535  k1 = mbrtowc(&wc1, (char *) buf + ch + k, cnt - ch - k, &mbstate1);
1536  }
1537  }
1538 
1539  if (pa && ((flags & (MUTT_SHOWCOLOR | MUTT_SEARCH | MUTT_PAGER_MARKER)) ||
1540  special || last_special || pa->attr))
1541  {
1542  resolve_color(*line_info, n, vch, flags, special, pa);
1543  last_special = special;
1544  }
1545 
1546  /* no-break space, narrow no-break space */
1547  if (IsWPrint(wc) || (CharsetIsUtf8 && ((wc == 0x00A0) || (wc == 0x202F))))
1548  {
1549  if (wc == ' ')
1550  {
1551  space = ch;
1552  }
1553  t = wcwidth(wc);
1554  if (col + t > wrap_cols)
1555  break;
1556  col += t;
1557  if (pa)
1558  mutt_addwch(wc);
1559  }
1560  else if (wc == '\n')
1561  break;
1562  else if (wc == '\t')
1563  {
1564  space = ch;
1565  t = (col & ~7) + 8;
1566  if (t > wrap_cols)
1567  break;
1568  if (pa)
1569  for (; col < t; col++)
1570  mutt_window_addch(' ');
1571  else
1572  col = t;
1573  }
1574  else if ((wc < 0x20) || (wc == 0x7f))
1575  {
1576  if (col + 2 > wrap_cols)
1577  break;
1578  col += 2;
1579  if (pa)
1580  mutt_window_printf("^%c", ('@' + wc) & 0x7f);
1581  }
1582  else if (wc < 0x100)
1583  {
1584  if (col + 4 > wrap_cols)
1585  break;
1586  col += 4;
1587  if (pa)
1588  mutt_window_printf("\\%03o", wc);
1589  }
1590  else
1591  {
1592  if (col + 1 > wrap_cols)
1593  break;
1594  col += k;
1595  if (pa)
1597  }
1598  }
1599  *pspace = space;
1600  *pcol = col;
1601  *pvch = vch;
1602  *pspecial = special;
1603  return ch;
1604 }
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:148
#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:58
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:476
int mutt_window_printf(const char *fmt,...)
Write a formatted string to a Window.
Definition: mutt_window.c:549
int mutt_window_addch(int ch)
Write one character to a Window.
Definition: mutt_window.c:491
bool CharsetIsUtf8
Is the user&#39;s current character set utf-8?
Definition: charset.c:63
#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
int n
Definition: acutest.h:492
#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:233
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:1038
+ 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 1624 of file pager.c.

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

◆ up_n_lines()

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

Reposition the pager's view up by n lines.

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

Definition at line 1906 of file pager.c.

1907 {
1908  while ((cur > 0) && (nlines > 0))
1909  {
1910  cur--;
1911  if (!hiding || (info[cur].type != MT_COLOR_QUOTED))
1912  nlines--;
1913  }
1914 
1915  return cur;
1916 }
short type
Definition: pager.c:136
Pager: quoted text.
Definition: color.h:81
+ Here is the caller graph for this function:

◆ mutt_clear_pager_position()

void mutt_clear_pager_position ( void  )

Reset the pager's viewing position.

Definition at line 1921 of file pager.c.

1922 {
1923  TopLine = 0;
1924  OldEmail = NULL;
1925 }
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::custom_redraw()

Definition at line 1930 of file pager.c.

1931 {
1932  struct PagerRedrawData *rd = pager_menu->redraw_data;
1933  char buf[1024];
1934 
1935  if (!rd)
1936  return;
1937 
1938  if (pager_menu->redraw & REDRAW_FULL)
1939  {
1941  /* clear() doesn't optimize screen redraws */
1942  mutt_window_move_abs(0, 0);
1944 
1945  if (IsEmail(rd->extra) && Context && Context->mailbox &&
1947  {
1948  rd->indexlen = Context->mailbox->vcount + 1;
1949  }
1950  else
1952 
1953  rd->indicator = rd->indexlen / 3;
1954 
1955  if (C_Help)
1956  {
1961  }
1962 
1963  if (Resize)
1964  {
1966  if (rd->search_compiled)
1967  {
1968  int flags = mutt_mb_is_lower(rd->searchbuf) ? REG_ICASE : 0;
1969  const int err = REG_COMP(&rd->search_re, rd->searchbuf, REG_NEWLINE | flags);
1970  if (err == 0)
1971  {
1972  rd->search_flag = MUTT_SEARCH;
1974  }
1975  else
1976  {
1977  regerror(err, &rd->search_re, buf, sizeof(buf));
1978  mutt_error("%s", buf);
1979  rd->search_compiled = false;
1980  }
1981  }
1982  rd->lines = Resize->line;
1983  pager_menu->redraw |= REDRAW_FLOW;
1984 
1985  FREE(&Resize);
1986  }
1987 
1988  if (IsEmail(rd->extra) && (C_PagerIndexLines != 0))
1989  {
1990  if (!rd->menu)
1991  {
1992  /* only allocate the space if/when we need the index.
1993  * Initialise the menu as per the main index */
1994  rd->menu = mutt_menu_new(MENU_MAIN);
1996  rd->menu->color = index_color;
1997  rd->menu->max = Context ? Context->mailbox->vcount : 0;
1998  rd->menu->current = rd->extra->email->vnum;
1999  rd->menu->win_index = rd->extra->win_index;
2000  rd->menu->win_ibar = rd->extra->win_ibar;
2001  }
2002 
2004  rd->menu->pagelen = rd->extra->win_index->state.rows;
2005 
2006  /* some fudge to work out whereabouts the indicator should go */
2007  if (rd->menu->current - rd->indicator < 0)
2008  rd->menu->top = 0;
2009  else if (rd->menu->max - rd->menu->current < rd->menu->pagelen - rd->indicator)
2010  rd->menu->top = rd->menu->max - rd->menu->pagelen;
2011  else
2012  rd->menu->top = rd->menu->current - rd->indicator;
2013 
2014  menu_redraw_index(rd->menu);
2015  }
2016 
2017  pager_menu->redraw |= REDRAW_BODY | REDRAW_INDEX | REDRAW_STATUS;
2018 #ifdef USE_SIDEBAR
2019  pager_menu->redraw |= REDRAW_SIDEBAR;
2020 #endif
2021  mutt_show_error();
2022  }
2023 
2024  if (pager_menu->redraw & REDRAW_FLOW)
2025  {
2026  if (!(rd->flags & MUTT_PAGER_RETWINCH))
2027  {
2028  rd->lines = -1;
2029  for (int i = 0; i <= rd->topline; i++)
2030  if (!rd->line_info[i].continuation)
2031  rd->lines++;
2032  for (int i = 0; i < rd->max_line; i++)
2033  {
2034  rd->line_info[i].offset = 0;
2035  rd->line_info[i].type = -1;
2036  rd->line_info[i].continuation = 0;
2037  rd->line_info[i].chunks = 0;
2038  rd->line_info[i].search_cnt = -1;
2039  rd->line_info[i].quote = NULL;
2040 
2041  mutt_mem_realloc(&(rd->line_info[i].syntax), sizeof(struct TextSyntax));
2042  if (rd->search_compiled && rd->line_info[i].search)
2043  FREE(&(rd->line_info[i].search));
2044  }
2045 
2046  rd->last_line = 0;
2047  rd->topline = 0;
2048  }
2049  int i = -1;
2050  int j = -1;
2051  while (display_line(rd->fp, &rd->last_pos, &rd->line_info, ++i, &rd->last_line,
2052  &rd->max_line, rd->has_types | rd->search_flag | (rd->flags & MUTT_PAGER_NOWRAP),
2053  &rd->quote_list, &rd->q_level, &rd->force_redraw,
2054  &rd->search_re, rd->extra->win_pager) == 0)
2055  {
2056  if (!rd->line_info[i].continuation && (++j == rd->lines))
2057  {
2058  rd->topline = i;
2059  if (!rd->search_flag)
2060  break;
2061  }
2062  }
2063  }
2064 
2065 #ifdef USE_SIDEBAR
2066  if (pager_menu->redraw & REDRAW_SIDEBAR)
2067  {
2068  menu_redraw_sidebar(pager_menu);
2069  }
2070 #endif
2071 
2072  if ((pager_menu->redraw & REDRAW_BODY) || (rd->topline != rd->oldtopline))
2073  {
2074  do
2075  {
2076  mutt_window_move(rd->extra->win_pager, 0, 0);
2077  rd->curline = rd->topline;
2078  rd->oldtopline = rd->topline;
2079  rd->lines = 0;
2080  rd->force_redraw = false;
2081 
2082  while ((rd->lines < rd->extra->win_pager->state.rows) &&
2083  (rd->line_info[rd->curline].offset <= rd->sb.st_size - 1))
2084  {
2085  if (display_line(rd->fp, &rd->last_pos, &rd->line_info, rd->curline,
2086  &rd->last_line, &rd->max_line,
2087  (rd->flags & MUTT_DISPLAYFLAGS) | rd->hide_quoted |
2088  rd->search_flag | (rd->flags & MUTT_PAGER_NOWRAP),
2089  &rd->quote_list, &rd->q_level, &rd->force_redraw,
2090  &rd->search_re, rd->extra->win_pager) > 0)
2091  {
2092  rd->lines++;
2093  }
2094  rd->curline++;
2095  mutt_window_move(rd->extra->win_pager, 0, rd->lines);
2096  }
2097  rd->last_offset = rd->line_info[rd->curline].offset;
2098  } while (rd->force_redraw);
2099 
2101  while (rd->lines < rd->extra->win_pager->state.rows)
2102  {
2104  if (C_Tilde)
2105  mutt_window_addch('~');
2106  rd->lines++;
2107  mutt_window_move(rd->extra->win_pager, 0, rd->lines);
2108  }
2110 
2111  /* We are going to update the pager status bar, so it isn't
2112  * necessary to reset to normal color now. */
2113 
2114  pager_menu->redraw |= REDRAW_STATUS; /* need to update the % seen */
2115  }
2116 
2117  if (pager_menu->redraw & REDRAW_STATUS)
2118  {
2119  struct HdrFormatInfo hfi;
2120  char pager_progress_str[65]; /* Lots of space for translations */
2121 
2122  hfi.ctx = Context;
2123  hfi.mailbox = Context ? Context->mailbox : NULL;
2124  hfi.pager_progress = pager_progress_str;
2125 
2126  if (rd->last_pos < rd->sb.st_size - 1)
2127  {
2128  snprintf(pager_progress_str, sizeof(pager_progress_str), OFF_T_FMT "%%",
2129  (100 * rd->last_offset / rd->sb.st_size));
2130  }
2131  else
2132  {
2133  const char *msg = (rd->topline == 0) ?
2134  /* L10N: Status bar message: the entire email is visible in the pager */
2135  _("all") :
2136  /* L10N: Status bar message: the end of the email is visible in the pager */
2137  _("end");
2138  mutt_str_copy(pager_progress_str, msg, sizeof(pager_progress_str));
2139  }
2140 
2141  /* print out the pager status bar */
2142  mutt_window_move(rd->extra->win_pbar, 0, 0);
2144 
2145  if (IsEmail(rd->extra) || IsMsgAttach(rd->extra))
2146  {
2147  size_t l1 = rd->extra->win_pbar->state.cols * MB_LEN_MAX;
2148  size_t l2 = sizeof(buf);
2149  hfi.email = (IsEmail(rd->extra)) ? rd->extra->email : rd->extra->body->email;
2150  mutt_make_string_info(buf, (l1 < l2) ? l1 : l2, rd->extra->win_pbar->state.cols,
2152  mutt_draw_statusline(rd->extra->win_pbar->state.cols, buf, l2);
2153  }
2154  else
2155  {
2156  char bn[256];
2157  snprintf(bn, sizeof(bn), "%s (%s)", rd->banner, pager_progress_str);
2158  mutt_draw_statusline(rd->extra->win_pbar->state.cols, bn, sizeof(bn));
2159  }
2161  if (C_TsEnabled && TsSupported && rd->menu)
2162  {
2163  menu_status_line(buf, sizeof(buf), rd->menu, NONULL(C_TsStatusFormat));
2164  mutt_ts_status(buf);
2165  menu_status_line(buf, sizeof(buf), rd->menu, NONULL(C_TsIconFormat));
2166  mutt_ts_icon(buf);
2167  }
2168  }
2169 
2170  if ((pager_menu->redraw & REDRAW_INDEX) && rd->menu)
2171  {
2172  /* redraw the pager_index indicator, because the
2173  * flags for this message might have changed. */
2174  if (rd->extra->win_index->state.rows > 0)
2176 
2177  /* print out the index status bar */
2178  menu_status_line(buf, sizeof(buf), rd->menu, NONULL(C_StatusFormat));
2179 
2180  mutt_window_move(rd->extra->win_ibar, 0, 0);
2182  mutt_draw_statusline(rd->extra->win_ibar->state.cols, buf, sizeof(buf));
2184  }
2185 
2186  pager_menu->redraw = REDRAW_NO_FLAGS;
2187 }
struct Menu * menu
the Pager Index (PI)
Definition: pager.c:189
struct Context * ctx
Definition: hdrline.h:47
The "current" mailbox.
Definition: context.h:37
WHERE char * C_TsIconFormat
Config: printf-like format string for the terminal&#39;s icon title.
Definition: globals.h:143
struct MuttWindow * win_index
Definition: pager.h:74
#define REDRAW_FULL
Redraw everything.
Definition: mutt_menu.h:45
#define NONULL(x)
Definition: string2.h:37
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:47
void mutt_window_clrtoeol(struct MuttWindow *win)
Clear to the end of the line.
Definition: mutt_window.c:212
WHERE bool C_Help
Config: Display a help line with common key bindings.
Definition: globals.h:212
void index_make_entry(char *buf, size_t buflen, struct Menu *menu, int line)
Format a menu item for the index list - Implements Menu::make_entry()
Definition: index.c:850
#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::color()
Definition: index.c:926
void menu_status_line(char *buf, size_t buflen, struct Menu *menu, const char *p)
Create the status line.
Definition: status.c:410
struct MuttWindow * MuttHelpWindow
Help Window.
Definition: mutt_window.c:45
struct Body * body
Current attachment.
Definition: pager.h:69
void mutt_window_move_abs(int col, int row)
Move the cursor to an absolute screen position.
Definition: mutt_window.c:538
PagerFlags flags
Definition: pager.c:172
Index panel (list of emails)
Definition: keymap.h:78
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:141
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:250
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:1624
#define MUTT_FORMAT_NO_FLAGS
No flags are set.
Definition: format_flags.h:30
int vcount
The number of virtual messages.
Definition: mailbox.h:102
#define REDRAW_SIDEBAR
Redraw the sidebar.
Definition: mutt_menu.h:49
void mutt_paddstr(int n, const char *s)
Display a string on screen, padded if necessary.
Definition: curs_lib.c:1245
LOFF_T last_pos
Definition: pager.c:187
int mutt_window_move(struct MuttWindow *win, int col, int row)
Move the cursor in a Window.
Definition: mutt_window.c:365
int line
Definition: pager.c:162
void * redraw_data
Definition: mutt_menu.h:152
Pager: empty lines after message.
Definition: color.h:95
struct Mailbox * mailbox
Definition: context.h:50
Data passed to index_format_str()
Definition: hdrline.h:45
int indexlen
Definition: pager.c:174
struct MuttWindow * win_ibar
Definition: mutt_menu.h:93
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:53
short continuation
Definition: pager.c:137
void mutt_window_clrtobot(void)
Clear to the bottom of the Window.
Definition: mutt_window.c:201
bool force_redraw
Definition: pager.c:182
Plain text.
Definition: color.h:77
void mutt_mem_realloc(void *ptr, size_t size)
Resize a block of memory on the heap.
Definition: memory.c:114
struct MuttWindow * win_pager
Definition: pager.h:76
short cols
Number of columns, can be MUTT_WIN_SIZE_UNLIMITED.
Definition: mutt_window.h:57
void mutt_make_string_info(char *buf, size_t buflen, int cols, const char *s, struct HdrFormatInfo *hfi, MuttFormatFlags flags)
Create pager status bar string.
Definition: hdrline.c:1430
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:43
struct TextSyntax * search
Definition: pager.c:141
struct WindowState state
Current state of the Window.
Definition: mutt_window.h:113
#define REDRAW_STATUS
Redraw the status bar.
Definition: mutt_menu.h:44
bool search_compiled
Definition: pager.c:191
int(* color)(int line)
Calculate the colour for a line of the menu.
Definition: mutt_menu.h:144
Status bar (takes a pattern)
Definition: color.h:94
short rows
Number of rows, can be MUTT_WIN_SIZE_UNLIMITED.
Definition: mutt_window.h:58
int top
Entry that is the top of the current page.
Definition: mutt_menu.h:105
int max_line
Definition: pager.c:178
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:89
bool TsSupported
Terminal Setting is supported.
Definition: terminal.c:43
WHERE char * C_TsStatusFormat
Config: printf-like format string for the terminal&#39;s status (window title)
Definition: globals.h:142
int max
Number of entries in the menu.
Definition: mutt_menu.h:86
MuttRedrawFlags redraw
When to redraw the screen.
Definition: mutt_menu.h:87
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:491
#define MUTT_PAGER_RETWINCH
Need reformatting on SIGWINCH.
Definition: pager.h:54
#define MUTT_SEARCH
Resolve search patterns.
Definition: pager.h:47
#define REDRAW_BODY
Redraw the pager.
Definition: mutt_menu.h:46
char * searchbuf
Definition: pager.c:196
size_t mutt_str_copy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:724
#define REDRAW_INDEX
Redraw the index.
Definition: mutt_menu.h:40
#define mutt_error(...)
Definition: logging.h:84
#define FREE(x)
Definition: memory.h:40
void mutt_ts_icon(char *str)
Set the icon in the terminal title bar.
Definition: terminal.c:118
bool C_Tilde
Config: Character to pad blank lines in the pager.
Definition: pager.c:93
struct TextSyntax * syntax
Definition: pager.c:140
void mutt_show_error(void)
Show the user an error message.
Definition: curs_lib.c:532
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:85
struct MuttWindow * win_index
Definition: mutt_menu.h:92
#define REDRAW_NO_FLAGS
No flags are set.
Definition: mutt_menu.h:39
LOFF_T offset
Definition: pager.c:135
bool mutt_mb_is_lower(const char *s)
Does a multi-byte string contain only lowercase characters?
Definition: mbyte.c:358
struct Email * email
header information for message/rfc822
Definition: body.h:55
void(* make_entry)(char *buf, size_t buflen, struct Menu *menu, int line)
Format a item for a menu.
Definition: mutt_menu.h:117
void mutt_draw_statusline(int cols, const char *buf, size_t buflen)
Draw a highlighted status bar.
Definition: index.c:954
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:129
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 2204 of file pager.c.

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