NeoMutt  2018-07-16 +1360-3df4a2
Teaching an old dog new tricks
DOXYGEN
pager.c File Reference

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

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

Go to the source code of this file.

Data Structures

struct  QClass
 Style of quoted text. More...
 
struct  Syntax
 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 ISHEADER(x)   ((x) == MT_COLOR_HEADER || (x) == MT_COLOR_HDEFAULT)
 
#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 CHECK_MODE(test)
 
#define CHECK_READONLY
 
#define CHECK_ATTACH
 
#define CHECK_ACL(aclbit, action)
 
#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 NUM_SIG_LINES   4
 

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 new_class_color (struct QClass *class, 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, struct MuttWindow *pager_window)
 Display a line of text in the pager. More...
 
static int display_line (FILE *fp, LOFF_T *last_pos, struct Line **line_info, int n, int *last, int *max, PagerFlags flags, struct QClass **quote_list, int *q_level, bool *force_redraw, regex_t *search_re, struct MuttWindow *pager_window)
 Print a line on screen. More...
 
static int up_n_lines (int nlines, struct Line *info, int cur, bool hiding)
 Reposition the pager's view up by n lines. More...
 
void mutt_clear_pager_position (void)
 Reset the pager's viewing position. More...
 
static void pager_custom_redraw (struct Menu *pager_menu)
 Redraw the pager window - Implements Menu::menu_custom_redraw() More...
 
int mutt_pager (const char *banner, const char *fname, PagerFlags flags, struct Pager *extra)
 Display a file, or help, in a window. More...
 

Variables

bool C_AllowAnsi
 Config: Allow ANSI colour codes in rich text messages. More...
 
bool C_HeaderColorPartial
 Config: Only colour the part of the header matching the regex. More...
 
short C_PagerContext
 Config: Number of lines of overlap when changing pages in the pager. More...
 
short C_PagerIndexLines
 Config: Number of index lines to display above the pager. More...
 
bool C_PagerStop
 Config: Don't automatically open the next message when at the end of a message. More...
 
short C_SearchContext
 Config: Context to display around search matches. More...
 
short C_SkipQuotedOffset
 Config: Lines of context to show when skipping quoted text. More...
 
bool C_SmartWrap
 Config: Wrap text at word boundaries. More...
 
struct RegexC_Smileys
 Config: Regex to match smileys to prevent mistakes when quoting text. More...
 
bool C_Tilde
 Config: Character to pad blank lines in the pager. More...
 
static 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 int TopLine = 0
 
static struct EmailOldHdr = NULL
 
static short InHelp = 0
 
static struct ResizeResize = NULL
 
static int braille_line = -1
 
static int braille_col = -1
 
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

#define ISHEADER (   x)    ((x) == MT_COLOR_HEADER || (x) == MT_COLOR_HDEFAULT)

Definition at line 97 of file pager.c.

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

Definition at line 99 of file pager.c.

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

Definition at line 100 of file pager.c.

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

Definition at line 102 of file pager.c.

#define CHECK_MODE (   test)
Value:
if (!(test)) \
{ \
break; \
}
void mutt_flushinp(void)
Empty all the keyboard buffers.
Definition: curs_lib.c:753
#define _(a)
Definition: message.h:28
static const char * Not_available_in_this_menu
Definition: pager.c:104
#define mutt_error(...)
Definition: logging.h:88
static struct @5 test[]

Definition at line 114 of file pager.c.

#define CHECK_READONLY
Value:
{ \
break; \
}
The "current" mailbox.
Definition: context.h:37
void mutt_flushinp(void)
Empty all the keyboard buffers.
Definition: curs_lib.c:753
#define _(a)
Definition: message.h:28
struct Mailbox * mailbox
Definition: context.h:51
bool readonly
don&#39;t allow changes to the mailbox
Definition: mailbox.h:120
static const char * Mailbox_is_read_only
Definition: pager.c:106
#define mutt_error(...)
Definition: logging.h:88

Definition at line 122 of file pager.c.

#define CHECK_ATTACH
Value:
{ \
break; \
}
void mutt_flushinp(void)
Empty all the keyboard buffers.
Definition: curs_lib.c:753
#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:107
#define mutt_error(...)
Definition: logging.h:88

Definition at line 130 of file pager.c.

#define CHECK_ACL (   aclbit,
  action 
)
Value:
if (!Context || !(Context->mailbox->rights & aclbit)) \
{ \
/* 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
void mutt_flushinp(void)
Empty all the keyboard buffers.
Definition: curs_lib.c:753
#define _(a)
Definition: message.h:28
struct Mailbox * mailbox
Definition: context.h:51
AclFlags rights
ACL bits, see AclFlags.
Definition: mailbox.h:122
#define mutt_error(...)
Definition: logging.h:88

Definition at line 138 of file pager.c.

#define ANSI_NO_FLAGS   0

No flags are set.

Definition at line 188 of file pager.c.

#define ANSI_OFF   (1 << 0)

Turn off colours and attributes.

Definition at line 189 of file pager.c.

#define ANSI_BLINK   (1 << 1)

Blinking text.

Definition at line 190 of file pager.c.

#define ANSI_BOLD   (1 << 2)

Bold text.

Definition at line 191 of file pager.c.

#define ANSI_UNDERLINE   (1 << 3)

Underlined text.

Definition at line 192 of file pager.c.

#define ANSI_REVERSE   (1 << 4)

Reverse video.

Definition at line 193 of file pager.c.

#define ANSI_COLOR   (1 << 5)

Use colours.

Definition at line 194 of file pager.c.

#define NUM_SIG_LINES   4

Definition at line 220 of file pager.c.

Typedef Documentation

typedef uint8_t AnsiFlags

Flags, e.g. ANSI_OFF.

Definition at line 187 of file pager.c.

Function Documentation

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

231 {
232  int count = 0;
233 
234  while (n > 0 && count <= NUM_SIG_LINES)
235  {
236  if (info[n].type != MT_COLOR_SIGNATURE)
237  break;
238  count++;
239  n--;
240  }
241 
242  if (count == 0)
243  return -1;
244 
245  if (count > NUM_SIG_LINES)
246  {
247  /* check for a blank line */
248  while (*s)
249  {
250  if (!ISSPACE(*s))
251  return 0;
252  s++;
253  }
254 
255  return -1;
256  }
257 
258  return 0;
259 }
Pager: signature lines.
Definition: mutt_curses.h:126
#define NUM_SIG_LINES
Definition: pager.c:220
#define ISSPACE(ch)
Definition: string2.h:37

+ Here is the caller graph for this function:

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

270 {
271  const int *cnt = (const int *) m1;
272  const struct Syntax *stx = (const struct Syntax *) m2;
273 
274  if (*cnt < stx->first)
275  return -1;
276  if (*cnt >= stx->last)
277  return 1;
278  return 0;
279 }
int first
Definition: pager.c:166
int last
Definition: pager.c:167
Highlighting for a line of text.
Definition: pager.c:163

+ Here is the caller graph for this function:

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

292 {
293  int def_color; /* color without syntax highlight */
294  int color; /* final color */
295  static int last_color; /* last color set */
296  bool search = false;
297  int m;
298  struct Syntax *matching_chunk = NULL;
299 
300  if (!cnt)
301  last_color = -1; /* force attrset() */
302 
303  if (line_info[n].continuation)
304  {
305  if (!cnt && C_Markers)
306  {
308  addch('+');
309  last_color = ColorDefs[MT_COLOR_MARKERS];
310  }
311  m = (line_info[n].syntax)[0].first;
312  cnt += (line_info[n].syntax)[0].last;
313  }
314  else
315  m = n;
316  if (flags & MUTT_PAGER_LOGS)
317  {
318  def_color = ColorDefs[(line_info[n].syntax)[0].color];
319  }
320  else if (!(flags & MUTT_SHOWCOLOR))
321  def_color = ColorDefs[MT_COLOR_NORMAL];
322  else if (line_info[m].type == MT_COLOR_HEADER)
323  def_color = (line_info[m].syntax)[0].color;
324  else
325  def_color = ColorDefs[line_info[m].type];
326 
327  if ((flags & MUTT_SHOWCOLOR) && (line_info[m].type == MT_COLOR_QUOTED))
328  {
329  struct QClass *class = line_info[m].quote;
330 
331  if (class)
332  {
333  def_color = class->color;
334 
335  while (class && class->length > cnt)
336  {
337  def_color = class->color;
338  class = class->up;
339  }
340  }
341  }
342 
343  color = def_color;
344  if ((flags & MUTT_SHOWCOLOR) && line_info[m].chunks)
345  {
346  matching_chunk = bsearch(&cnt, line_info[m].syntax, line_info[m].chunks,
347  sizeof(struct Syntax), comp_syntax_t);
348  if (matching_chunk && (cnt >= matching_chunk->first) &&
349  (cnt < matching_chunk->last))
350  {
351  color = matching_chunk->color;
352  }
353  }
354 
355  if ((flags & MUTT_SEARCH) && line_info[m].search_cnt)
356  {
357  matching_chunk = bsearch(&cnt, line_info[m].search, line_info[m].search_cnt,
358  sizeof(struct Syntax), comp_syntax_t);
359  if (matching_chunk && (cnt >= matching_chunk->first) &&
360  (cnt < matching_chunk->last))
361  {
362  color = ColorDefs[MT_COLOR_SEARCH];
363  search = 1;
364  }
365  }
366 
367  /* handle "special" bold & underlined characters */
368  if (special || a->attr)
369  {
370 #ifdef HAVE_COLOR
371  if ((a->attr & ANSI_COLOR))
372  {
373  if (a->pair == -1)
374  a->pair = mutt_alloc_color(a->fg, a->bg);
375  color = a->pair;
376  if (a->attr & ANSI_BOLD)
377  color |= A_BOLD;
378  }
379  else
380 #endif
381  if ((special & A_BOLD) || (a->attr & ANSI_BOLD))
382  {
383  if (ColorDefs[MT_COLOR_BOLD] && !search)
384  color = ColorDefs[MT_COLOR_BOLD];
385  else
386  color ^= A_BOLD;
387  }
388  if ((special & A_UNDERLINE) || (a->attr & ANSI_UNDERLINE))
389  {
390  if (ColorDefs[MT_COLOR_UNDERLINE] && !search)
391  color = ColorDefs[MT_COLOR_UNDERLINE];
392  else
393  color ^= A_UNDERLINE;
394  }
395  else if (a->attr & ANSI_REVERSE)
396  {
397  color ^= A_REVERSE;
398  }
399  else if (a->attr & ANSI_BLINK)
400  {
401  color ^= A_BLINK;
402  }
403  else if (a->attr == ANSI_OFF)
404  {
405  a->attr = 0;
406  }
407  }
408 
409  if (color != last_color)
410  {
411  ATTRSET(color);
412  last_color = color;
413  }
414 }
int first
Definition: pager.c:166
int mutt_alloc_color(int fg, int bg)
#define ANSI_COLOR
Use colours.
Definition: pager.c:194
#define MUTT_SHOWCOLOR
Show characters in color otherwise don&#39;t show characters.
Definition: pager.h:45
int pair
Curses colour pair.
Definition: pager.c:205
Pager: quoted text.
Definition: mutt_curses.h:125
Bold text.
Definition: mutt_curses.h:140
int last
Definition: pager.c:167
Message headers (takes a pattern)
Definition: mutt_curses.h:135
Pager: search matches.
Definition: mutt_curses.h:139
Highlighting for a line of text.
Definition: pager.c:163
Pager: markers, line continuation.
Definition: mutt_curses.h:133
short type
Definition: pager.c:176
int color
Definition: pager.c:165
#define ANSI_BOLD
Bold text.
Definition: pager.c:191
Plain text.
Definition: mutt_curses.h:130
AnsiFlags attr
Attributes, e.g. underline, bold, etc.
Definition: pager.c:202
#define ATTRSET
Definition: mutt_curses.h:230
static int comp_syntax_t(const void *m1, const void *m2)
Search for a Syntax using bsearch.
Definition: pager.c:269
#define ANSI_BLINK
Blinking text.
Definition: pager.c:190
Underlined text.
Definition: mutt_curses.h:141
#define ANSI_REVERSE
Reverse video.
Definition: pager.c:193
int bg
Background colour.
Definition: pager.c:204
struct Syntax * syntax
Definition: pager.c:180
#define ANSI_UNDERLINE
Underlined text.
Definition: pager.c:192
int ColorDefs[MT_COLOR_MAX]
Array of all fixed colours, see enum ColorId.
Definition: color.c:52
#define MUTT_PAGER_LOGS
Logview mode.
Definition: pager.h:57
#define SETCOLOR(X)
Definition: mutt_curses.h:222
int fg
Foreground colour.
Definition: pager.c:203
#define MUTT_SEARCH
Resolve search patterns.
Definition: pager.h:47
int color
Definition: pager.c:154
WHERE bool C_Markers
Config: Display a &#39;+&#39; at the beginning of wrapped lines in the pager.
Definition: globals.h:247
Style of quoted text.
Definition: pager.c:150
#define ANSI_OFF
Turn off colours and attributes.
Definition: pager.c:189

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

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

423 {
424  int m;
425 
426  line_info[n + 1].type = line_info[n].type;
427  (line_info[n + 1].syntax)[0].color = (line_info[n].syntax)[0].color;
428  line_info[n + 1].continuation = 1;
429 
430  /* find the real start of the line */
431  for (m = n; m >= 0; m--)
432  if (line_info[m].continuation == 0)
433  break;
434 
435  (line_info[n + 1].syntax)[0].first = m;
436  (line_info[n + 1].syntax)[0].last =
437  (line_info[n].continuation) ? cnt + (line_info[n].syntax)[0].last : cnt;
438 }
short type
Definition: pager.c:176
short continuation
Definition: pager.c:177
struct Syntax * syntax
Definition: pager.c:180

+ Here is the caller graph for this function:

static void new_class_color ( struct QClass class,
int *  q_level 
)
static

Create a new quoting colour.

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

Definition at line 445 of file pager.c.

446 {
447  class->index = (*q_level)++;
448  class->color = ColorQuote[class->index % ColorQuoteUsed];
449 }
int * ColorQuote
Array of colours for quoted email text.
Definition: color.c:50
int ColorQuoteUsed
Number of colours for quoted email text.
Definition: color.c:51

+ Here is the caller graph for this function:

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

460 {
461  struct QClass *q_list = quote_list;
462  new_class->index = -1;
463 
464  while (q_list)
465  {
466  if (q_list->index >= index)
467  {
468  q_list->index++;
469  q_list->color = ColorQuote[q_list->index % ColorQuoteUsed];
470  }
471  if (q_list->down)
472  q_list = q_list->down;
473  else if (q_list->next)
474  q_list = q_list->next;
475  else
476  {
477  while (!q_list->next)
478  {
479  q_list = q_list->up;
480  if (!q_list)
481  break;
482  }
483  if (q_list)
484  q_list = q_list->next;
485  }
486  }
487 
488  new_class->index = index;
489  new_class->color = ColorQuote[index % ColorQuoteUsed];
490  (*q_level)++;
491 }
int * ColorQuote
Array of colours for quoted email text.
Definition: color.c:50
int ColorQuoteUsed
Number of colours for quoted email text.
Definition: color.c:51
struct QClass * down
Definition: pager.c:157
struct QClass * next
Definition: pager.c:156
int color
Definition: pager.c:154
int index
Definition: pager.c:153
struct QClass * up
Definition: pager.c:157
Style of quoted text.
Definition: pager.c:150

+ Here is the caller graph for this function:

static void cleanup_quote ( struct QClass **  quote_list)
static

Free a quote list.

Parameters
[out]quote_listQuote list to free

Definition at line 497 of file pager.c.

498 {
499  struct QClass *ptr = NULL;
500 
501  while (*quote_list)
502  {
503  if ((*quote_list)->down)
504  cleanup_quote(&((*quote_list)->down));
505  ptr = (*quote_list)->next;
506  if ((*quote_list)->prefix)
507  FREE(&(*quote_list)->prefix);
508  FREE(quote_list);
509  *quote_list = ptr;
510  }
511 }
static void cleanup_quote(struct QClass **quote_list)
Free a quote list.
Definition: pager.c:497
struct QClass * next
Definition: pager.c:156
#define FREE(x)
Definition: memory.h:40
Style of quoted text.
Definition: pager.c:150

+ Here is the caller graph for this function:

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

524 {
525  struct QClass *q_list = *quote_list;
526  struct QClass *class = NULL, *tmp = NULL, *ptr = NULL, *save = NULL;
527  char *tail_qptr = NULL;
528  int offset, tail_lng;
529  int index = -1;
530 
531  if (ColorQuoteUsed <= 1)
532  {
533  /* not much point in classifying quotes... */
534 
535  if (!*quote_list)
536  {
537  class = mutt_mem_calloc(1, sizeof(struct QClass));
538  class->color = ColorQuote[0];
539  *quote_list = class;
540  }
541  return *quote_list;
542  }
543 
544  /* classify quoting prefix */
545  while (q_list)
546  {
547  if (length <= q_list->length)
548  {
549  /* case 1: check the top level nodes */
550 
551  if (mutt_str_strncmp(qptr, q_list->prefix, length) == 0)
552  {
553  if (length == q_list->length)
554  return q_list; /* same prefix: return the current class */
555 
556  /* found shorter prefix */
557  if (!tmp)
558  {
559  /* add a node above q_list */
560  tmp = mutt_mem_calloc(1, sizeof(struct QClass));
561  tmp->prefix = mutt_mem_calloc(1, length + 1);
562  strncpy(tmp->prefix, qptr, length);
563  tmp->length = length;
564 
565  /* replace q_list by tmp in the top level list */
566  if (q_list->next)
567  {
568  tmp->next = q_list->next;
569  q_list->next->prev = tmp;
570  }
571  if (q_list->prev)
572  {
573  tmp->prev = q_list->prev;
574  q_list->prev->next = tmp;
575  }
576 
577  /* make q_list a child of tmp */
578  tmp->down = q_list;
579  q_list->up = tmp;
580 
581  /* q_list has no siblings for now */
582  q_list->next = NULL;
583  q_list->prev = NULL;
584 
585  /* update the root if necessary */
586  if (q_list == *quote_list)
587  *quote_list = tmp;
588 
589  index = q_list->index;
590 
591  /* tmp should be the return class too */
592  class = tmp;
593 
594  /* next class to test; if tmp is a shorter prefix for another
595  * node, that node can only be in the top level list, so don't
596  * go down after this point */
597  q_list = tmp->next;
598  }
599  else
600  {
601  /* found another branch for which tmp is a shorter prefix */
602 
603  /* save the next sibling for later */
604  save = q_list->next;
605 
606  /* unlink q_list from the top level list */
607  if (q_list->next)
608  q_list->next->prev = q_list->prev;
609  if (q_list->prev)
610  q_list->prev->next = q_list->next;
611 
612  /* at this point, we have a tmp->down; link q_list to it */
613  ptr = tmp->down;
614  /* sibling order is important here, q_list should be linked last */
615  while (ptr->next)
616  ptr = ptr->next;
617  ptr->next = q_list;
618  q_list->next = NULL;
619  q_list->prev = ptr;
620  q_list->up = tmp;
621 
622  index = q_list->index;
623 
624  /* next class to test; as above, we shouldn't go down */
625  q_list = save;
626  }
627 
628  /* we found a shorter prefix, so certain quotes have changed classes */
629  *force_redraw = true;
630  continue;
631  }
632  else
633  {
634  /* shorter, but not a substring of the current class: try next */
635  q_list = q_list->next;
636  continue;
637  }
638  }
639  else
640  {
641  /* case 2: try subclassing the current top level node */
642 
643  /* tmp != NULL means we already found a shorter prefix at case 1 */
644  if (!tmp && (mutt_str_strncmp(qptr, q_list->prefix, q_list->length) == 0))
645  {
646  /* ok, it's a subclass somewhere on this branch */
647 
648  ptr = q_list;
649  offset = q_list->length;
650 
651  q_list = q_list->down;
652  tail_lng = length - offset;
653  tail_qptr = (char *) qptr + offset;
654 
655  while (q_list)
656  {
657  if (length <= q_list->length)
658  {
659  if (mutt_str_strncmp(tail_qptr, (q_list->prefix) + offset, tail_lng) == 0)
660  {
661  /* same prefix: return the current class */
662  if (length == q_list->length)
663  return q_list;
664 
665  /* found shorter common prefix */
666  if (!tmp)
667  {
668  /* add a node above q_list */
669  tmp = mutt_mem_calloc(1, sizeof(struct QClass));
670  tmp->prefix = mutt_mem_calloc(1, length + 1);
671  strncpy(tmp->prefix, qptr, length);
672  tmp->length = length;
673 
674  /* replace q_list by tmp */
675  if (q_list->next)
676  {
677  tmp->next = q_list->next;
678  q_list->next->prev = tmp;
679  }
680  if (q_list->prev)
681  {
682  tmp->prev = q_list->prev;
683  q_list->prev->next = tmp;
684  }
685 
686  /* make q_list a child of tmp */
687  tmp->down = q_list;
688  tmp->up = q_list->up;
689  q_list->up = tmp;
690  if (tmp->up->down == q_list)
691  tmp->up->down = tmp;
692 
693  /* q_list has no siblings */
694  q_list->next = NULL;
695  q_list->prev = NULL;
696 
697  index = q_list->index;
698 
699  /* tmp should be the return class too */
700  class = tmp;
701 
702  /* next class to test */
703  q_list = tmp->next;
704  }
705  else
706  {
707  /* found another branch for which tmp is a shorter prefix */
708 
709  /* save the next sibling for later */
710  save = q_list->next;
711 
712  /* unlink q_list from the top level list */
713  if (q_list->next)
714  q_list->next->prev = q_list->prev;
715  if (q_list->prev)
716  q_list->prev->next = q_list->next;
717 
718  /* at this point, we have a tmp->down; link q_list to it */
719  ptr = tmp->down;
720  while (ptr->next)
721  ptr = ptr->next;
722  ptr->next = q_list;
723  q_list->next = NULL;
724  q_list->prev = ptr;
725  q_list->up = tmp;
726 
727  index = q_list->index;
728 
729  /* next class to test */
730  q_list = save;
731  }
732 
733  /* we found a shorter prefix, so we need a redraw */
734  *force_redraw = true;
735  continue;
736  }
737  else
738  {
739  q_list = q_list->next;
740  continue;
741  }
742  }
743  else
744  {
745  /* longer than the current prefix: try subclassing it */
746  if (!tmp && (mutt_str_strncmp(tail_qptr, (q_list->prefix) + offset,
747  q_list->length - offset) == 0))
748  {
749  /* still a subclass: go down one level */
750  ptr = q_list;
751  offset = q_list->length;
752 
753  q_list = q_list->down;
754  tail_lng = length - offset;
755  tail_qptr = (char *) qptr + offset;
756 
757  continue;
758  }
759  else
760  {
761  /* nope, try the next prefix */
762  q_list = q_list->next;
763  continue;
764  }
765  }
766  }
767 
768  /* still not found so far: add it as a sibling to the current node */
769  if (!class)
770  {
771  tmp = mutt_mem_calloc(1, sizeof(struct QClass));
772  tmp->prefix = mutt_mem_calloc(1, length + 1);
773  strncpy(tmp->prefix, qptr, length);
774  tmp->length = length;
775 
776  if (ptr->down)
777  {
778  tmp->next = ptr->down;
779  ptr->down->prev = tmp;
780  }
781  ptr->down = tmp;
782  tmp->up = ptr;
783 
784  new_class_color(tmp, q_level);
785 
786  return tmp;
787  }
788  else
789  {
790  if (index != -1)
791  shift_class_colors(*quote_list, tmp, index, q_level);
792 
793  return class;
794  }
795  }
796  else
797  {
798  /* nope, try the next prefix */
799  q_list = q_list->next;
800  continue;
801  }
802  }
803  }
804 
805  if (!class)
806  {
807  /* not found so far: add it as a top level class */
808  class = mutt_mem_calloc(1, sizeof(struct QClass));
809  class->prefix = mutt_mem_calloc(1, length + 1);
810  strncpy(class->prefix, qptr, length);
811  class->length = length;
812  new_class_color(class, q_level);
813 
814  if (*quote_list)
815  {
816  class->next = *quote_list;
817  (*quote_list)->prev = class;
818  }
819  *quote_list = class;
820  }
821 
822  if (index != -1)
823  shift_class_colors(*quote_list, tmp, index, q_level);
824 
825  return class;
826 }
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:51
int * ColorQuote
Array of colours for quoted email text.
Definition: color.c:50
static void new_class_color(struct QClass *class, int *q_level)
Create a new quoting colour.
Definition: pager.c:445
size_t length
Definition: pager.c:152
int ColorQuoteUsed
Number of colours for quoted email text.
Definition: color.c:51
struct QClass * down
Definition: pager.c:157
char * prefix
Definition: pager.c:155
struct QClass * next
Definition: pager.c:156
int mutt_str_strncmp(const char *a, const char *b, size_t l)
Compare two strings (to a maximum), safely.
Definition: string.c:638
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:458
int index
Definition: pager.c:153
struct QClass * prev
Definition: pager.c:156
struct QClass * up
Definition: pager.c:157
Style of quoted text.
Definition: pager.c:150

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

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

838 {
839  for (; *p == *q && *q && *p && *q != '\a' && *p != '\a'; p++, q++)
840  ;
841  return (int) (*p - *q);
842 }

+ Here is the caller graph for this function:

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

850 {
851  return check_marker(AttachmentMarker, p);
852 }
WHERE char AttachmentMarker[256]
Unique ANSI string to mark PGP messages in an email.
Definition: globals.h:45
static int check_marker(const char *q, const char *p)
Check that the unique marker is present.
Definition: pager.c:837

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

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

860 {
862 }
static int check_marker(const char *q, const char *p)
Check that the unique marker is present.
Definition: pager.c:837
WHERE char ProtectedHeaderMarker[256]
Unique ANSI string to mark protected headers in an email.
Definition: globals.h:46

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

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

874 {
875  bool is_quote = false;
876  regmatch_t pmatch_internal[1], smatch[1];
877 
878  if (!pmatch)
879  pmatch = pmatch_internal;
880 
881  if (C_QuoteRegex && C_QuoteRegex->regex &&
882  (regexec(C_QuoteRegex->regex, line, 1, pmatch, 0) == 0))
883  {
884  if (C_Smileys && C_Smileys->regex &&
885  (regexec(C_Smileys->regex, line, 1, smatch, 0) == 0))
886  {
887  if (smatch[0].rm_so > 0)
888  {
889  char c = line[smatch[0].rm_so];
890  line[smatch[0].rm_so] = 0;
891 
892  if (regexec(C_QuoteRegex->regex, line, 1, pmatch, 0) == 0)
893  is_quote = true;
894 
895  line[smatch[0].rm_so] = c;
896  }
897  }
898  else
899  is_quote = true;
900  }
901 
902  return is_quote;
903 }
regex_t * regex
compiled expression
Definition: regex3.h:60
const char * line
Definition: common.c:35
struct Regex * C_Smileys
Config: Regex to match smileys to prevent mistakes when quoting text.
Definition: pager.c:94
WHERE struct Regex * C_QuoteRegex
Config: Regex to match quoted text in a reply.
Definition: globals.h:185

+ Here is the caller graph for this function:

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

920 {
921  struct ColorLine *color_line = NULL;
922  struct ColorLineHead *head = NULL;
923  regmatch_t pmatch[1];
924  bool found;
925  bool null_rx;
926  int offset, i = 0;
927 
928  if ((n == 0) || ISHEADER(line_info[n - 1].type) ||
929  (check_protected_header_marker(raw) == 0))
930  {
931  if (buf[0] == '\n') /* end of header */
932  {
933  line_info[n].type = MT_COLOR_NORMAL;
934  getyx(stdscr, braille_line, braille_col);
935  }
936  else
937  {
938  /* if this is a continuation of the previous line, use the previous
939  * line's color as default. */
940  if ((n > 0) && ((buf[0] == ' ') || (buf[0] == '\t')))
941  {
942  line_info[n].type = line_info[n - 1].type; /* wrapped line */
944  {
945  (line_info[n].syntax)[0].color = (line_info[n - 1].syntax)[0].color;
946  line_info[n].is_cont_hdr = 1;
947  }
948  }
949  else
950  {
951  line_info[n].type = MT_COLOR_HDEFAULT;
952  }
953 
954  /* When this option is unset, we color the entire header the
955  * same color. Otherwise, we handle the header patterns just
956  * like body patterns (further below). */
958  {
959  STAILQ_FOREACH(color_line, &ColorHdrList, entries)
960  {
961  if (regexec(&color_line->regex, buf, 0, NULL, 0) == 0)
962  {
963  line_info[n].type = MT_COLOR_HEADER;
964  line_info[n].syntax[0].color = color_line->pair;
965  if (line_info[n].is_cont_hdr)
966  {
967  /* adjust the previous continuation lines to reflect the color of this continuation line */
968  int j;
969  for (j = n - 1; j >= 0 && line_info[j].is_cont_hdr; --j)
970  {
971  line_info[j].type = line_info[n].type;
972  line_info[j].syntax[0].color = line_info[n].syntax[0].color;
973  }
974  /* now adjust the first line of this header field */
975  if (j >= 0)
976  {
977  line_info[j].type = line_info[n].type;
978  line_info[j].syntax[0].color = line_info[n].syntax[0].color;
979  }
980  *force_redraw = true; /* the previous lines have already been drawn on the screen */
981  }
982  break;
983  }
984  }
985  }
986  }
987  }
988  else if (mutt_str_startswith(raw, "\033[0m", CASE_MATCH)) /* a little hack... */
989  line_info[n].type = MT_COLOR_NORMAL;
990  else if (check_attachment_marker((char *) raw) == 0)
991  line_info[n].type = MT_COLOR_ATTACHMENT;
992  else if ((mutt_str_strcmp("-- \n", buf) == 0) || (mutt_str_strcmp("-- \r\n", buf) == 0))
993  {
994  i = n + 1;
995 
996  line_info[n].type = MT_COLOR_SIGNATURE;
997  while (i < last && check_sig(buf, line_info, i - 1) == 0 &&
998  (line_info[i].type == MT_COLOR_NORMAL || line_info[i].type == MT_COLOR_QUOTED ||
999  line_info[i].type == MT_COLOR_HEADER))
1000  {
1001  /* oops... */
1002  if (line_info[i].chunks)
1003  {
1004  line_info[i].chunks = 0;
1005  mutt_mem_realloc(&(line_info[n].syntax), sizeof(struct Syntax));
1006  }
1007  line_info[i++].type = MT_COLOR_SIGNATURE;
1008  }
1009  }
1010  else if (check_sig(buf, line_info, n - 1) == 0)
1011  line_info[n].type = MT_COLOR_SIGNATURE;
1012  else if (mutt_is_quote_line(buf, pmatch))
1013 
1014  {
1015  if (q_classify && (line_info[n].quote == NULL))
1016  {
1017  line_info[n].quote = classify_quote(quote_list, buf + pmatch[0].rm_so,
1018  pmatch[0].rm_eo - pmatch[0].rm_so,
1019  force_redraw, q_level);
1020  }
1021  line_info[n].type = MT_COLOR_QUOTED;
1022  }
1023  else
1024  line_info[n].type = MT_COLOR_NORMAL;
1025 
1026  /* body patterns */
1027  if ((line_info[n].type == MT_COLOR_NORMAL) || (line_info[n].type == MT_COLOR_QUOTED) ||
1028  ((line_info[n].type == MT_COLOR_HDEFAULT) && C_HeaderColorPartial))
1029  {
1030  size_t nl;
1031 
1032  /* don't consider line endings part of the buffer
1033  * for regex matching */
1034  nl = mutt_str_strlen(buf);
1035  if ((nl > 0) && (buf[nl - 1] == '\n'))
1036  buf[nl - 1] = '\0';
1037 
1038  i = 0;
1039  offset = 0;
1040  line_info[n].chunks = 0;
1041  if (line_info[n].type == MT_COLOR_HDEFAULT)
1042  head = &ColorHdrList;
1043  else
1044  head = &ColorBodyList;
1045  STAILQ_FOREACH(color_line, head, entries)
1046  {
1047  color_line->stop_matching = false;
1048  }
1049  do
1050  {
1051  if (!buf[offset])
1052  break;
1053 
1054  found = false;
1055  null_rx = false;
1056  STAILQ_FOREACH(color_line, head, entries)
1057  {
1058  if (!color_line->stop_matching && (regexec(&color_line->regex, buf + offset, 1, pmatch,
1059  (offset ? REG_NOTBOL : 0)) == 0))
1060  {
1061  if (pmatch[0].rm_eo != pmatch[0].rm_so)
1062  {
1063  if (!found)
1064  {
1065  /* Abort if we fill up chunks.
1066  * Yes, this really happened. See #3888 */
1067  if (line_info[n].chunks == SHRT_MAX)
1068  {
1069  null_rx = false;
1070  break;
1071  }
1072  if (++(line_info[n].chunks) > 1)
1073  {
1074  mutt_mem_realloc(&(line_info[n].syntax),
1075  (line_info[n].chunks) * sizeof(struct Syntax));
1076  }
1077  }
1078  i = line_info[n].chunks - 1;
1079  pmatch[0].rm_so += offset;
1080  pmatch[0].rm_eo += offset;
1081  if (!found || (pmatch[0].rm_so < (line_info[n].syntax)[i].first) ||
1082  ((pmatch[0].rm_so == (line_info[n].syntax)[i].first) &&
1083  (pmatch[0].rm_eo > (line_info[n].syntax)[i].last)))
1084  {
1085  (line_info[n].syntax)[i].color = color_line->pair;
1086  (line_info[n].syntax)[i].first = pmatch[0].rm_so;
1087  (line_info[n].syntax)[i].last = pmatch[0].rm_eo;
1088  }
1089  found = true;
1090  null_rx = false;
1091  }
1092  else
1093  null_rx = true; /* empty regex; don't add it, but keep looking */
1094  }
1095  else
1096  {
1097  /* Once a regexp fails to match, don't try matching it again.
1098  * On very long lines this can cause a performance issue if there
1099  * are other regexps that have many matches. */
1100  color_line->stop_matching = true;
1101  }
1102  }
1103 
1104  if (null_rx)
1105  offset++; /* avoid degenerate cases */
1106  else
1107  offset = (line_info[n].syntax)[i].last;
1108  } while (found || null_rx);
1109  if (nl > 0)
1110  buf[nl] = '\n';
1111  }
1112 
1113  /* attachment patterns */
1114  if (line_info[n].type == MT_COLOR_ATTACHMENT)
1115  {
1116  size_t nl;
1117 
1118  /* don't consider line endings part of the buffer for regex matching */
1119  nl = mutt_str_strlen(buf);
1120  if ((nl > 0) && (buf[nl - 1] == '\n'))
1121  buf[nl - 1] = '\0';
1122 
1123  i = 0;
1124  offset = 0;
1125  line_info[n].chunks = 0;
1126  do
1127  {
1128  if (!buf[offset])
1129  break;
1130 
1131  found = false;
1132  null_rx = false;
1133  STAILQ_FOREACH(color_line, &ColorAttachList, entries)
1134  {
1135  if (regexec(&color_line->regex, buf + offset, 1, pmatch,
1136  (offset ? REG_NOTBOL : 0)) == 0)
1137  {
1138  if (pmatch[0].rm_eo != pmatch[0].rm_so)
1139  {
1140  if (!found)
1141  {
1142  if (++(line_info[n].chunks) > 1)
1143  {
1144  mutt_mem_realloc(&(line_info[n].syntax),
1145  (line_info[n].chunks) * sizeof(struct Syntax));
1146  }
1147  }
1148  i = line_info[n].chunks - 1;
1149  pmatch[0].rm_so += offset;
1150  pmatch[0].rm_eo += offset;
1151  if (!found || (pmatch[0].rm_so < (line_info[n].syntax)[i].first) ||
1152  ((pmatch[0].rm_so == (line_info[n].syntax)[i].first) &&
1153  (pmatch[0].rm_eo > (line_info[n].syntax)[i].last)))
1154  {
1155  (line_info[n].syntax)[i].color = color_line->pair;
1156  (line_info[n].syntax)[i].first = pmatch[0].rm_so;
1157  (line_info[n].syntax)[i].last = pmatch[0].rm_eo;
1158  }
1159  found = 1;
1160  null_rx = 0;
1161  }
1162  else
1163  null_rx = 1; /* empty regex; don't add it, but keep looking */
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 }
Pager: signature lines.
Definition: mutt_curses.h:126
MIME attachments text (entire line)
Definition: mutt_curses.h:137
static int check_protected_header_marker(const char *p)
Check that the unique marker is present.
Definition: pager.c:859
short chunks
Definition: pager.c:178
Pager: quoted text.
Definition: mutt_curses.h:125
#define ISHEADER(x)
Definition: pager.c:97
struct ColorLineHead ColorBodyList
List of colours applied to the email body.
Definition: color.c:54
Message headers (takes a pattern)
Definition: mutt_curses.h:135
Match case when comparing strings.
Definition: string2.h:66
size_t mutt_str_strlen(const char *a)
Calculate the length of a string, safely.
Definition: string.c:662
Highlighting for a line of text.
Definition: pager.c:163
short type
Definition: pager.c:176
int color
Definition: pager.c:165
Plain text.
Definition: mutt_curses.h:130
static int braille_line
Definition: pager.c:828
void mutt_mem_realloc(void *ptr, size_t size)
Resize a block of memory on the heap.
Definition: memory.c:124
struct QClass * quote
Definition: pager.c:182
static int braille_col
Definition: pager.c:829
bool stop_matching
used by the pager for body patterns, to prevent the color from being retried once it fails ...
Definition: mutt_curses.h:190
struct Syntax * syntax
Definition: pager.c:180
struct ColorLineHead ColorHdrList
List of colours applied to the email headers.
Definition: color.c:55
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:350
size_t mutt_str_startswith(const char *str, const char *prefix, enum CaseSensitivity cs)
Check whether a string starts with a prefix.
Definition: string.c:165
regex_t regex
Definition: mutt_curses.h:180
Header default colour.
Definition: mutt_curses.h:124
bool C_HeaderColorPartial
Config: Only colour the part of the header matching the regex.
Definition: pager.c:87
int mutt_is_quote_line(char *line, regmatch_t *pmatch)
Is a line of message text a quote?
Definition: pager.c:873
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:522
static int check_attachment_marker(const char *p)
Check that the unique marker is present.
Definition: pager.c:849
static int check_sig(const char *s, struct Line *info, int n)
Check for an email signature.
Definition: pager.c:230
int mutt_str_strcmp(const char *a, const char *b)
Compare two strings, safely.
Definition: string.c:611
unsigned int is_cont_hdr
this line is a continuation of the previous header line
Definition: pager.c:183
A regular expression and a color to highlight a line.
Definition: mutt_curses.h:178
struct ColorLineHead ColorAttachList
List of colours applied to the attachment headers.
Definition: color.c:53

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

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

1183 {
1184  while ((*buf != '\0') && (isdigit(*buf) || *buf == ';'))
1185  buf++;
1186  return *buf == 'm';
1187 }

+ Here is the caller graph for this function:

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

1197 {
1198  int x = pos;
1199 
1200  while (isdigit(buf[x]) || buf[x] == ';')
1201  x++;
1202 
1203  /* Character Attributes */
1204  if (C_AllowAnsi && a && (buf[x] == 'm'))
1205  {
1206  if (pos == x)
1207  {
1208 #ifdef HAVE_COLOR
1209  if (a->pair != -1)
1210  mutt_free_color(a->fg, a->bg);
1211 #endif
1212  a->attr = ANSI_OFF;
1213  a->pair = -1;
1214  }
1215  while (pos < x)
1216  {
1217  if ((buf[pos] == '1') && ((pos + 1 == x) || (buf[pos + 1] == ';')))
1218  {
1219  a->attr |= ANSI_BOLD;
1220  pos += 2;
1221  }
1222  else if ((buf[pos] == '4') && ((pos + 1 == x) || (buf[pos + 1] == ';')))
1223  {
1224  a->attr |= ANSI_UNDERLINE;
1225  pos += 2;
1226  }
1227  else if ((buf[pos] == '5') && ((pos + 1 == x) || (buf[pos + 1] == ';')))
1228  {
1229  a->attr |= ANSI_BLINK;
1230  pos += 2;
1231  }
1232  else if ((buf[pos] == '7') && ((pos + 1 == x) || (buf[pos + 1] == ';')))
1233  {
1234  a->attr |= ANSI_REVERSE;
1235  pos += 2;
1236  }
1237  else if ((buf[pos] == '0') && ((pos + 1 == x) || (buf[pos + 1] == ';')))
1238  {
1239 #ifdef HAVE_COLOR
1240  if (a->pair != -1)
1241  mutt_free_color(a->fg, a->bg);
1242 #endif
1243  a->attr = ANSI_OFF;
1244  a->pair = -1;
1245  pos += 2;
1246  }
1247  else if ((buf[pos] == '3') && isdigit(buf[pos + 1]))
1248  {
1249 #ifdef HAVE_COLOR
1250  if (a->pair != -1)
1251  mutt_free_color(a->fg, a->bg);
1252 #endif
1253  a->pair = -1;
1254  a->attr |= ANSI_COLOR;
1255  a->fg = buf[pos + 1] - '0';
1256  pos += 3;
1257  }
1258  else if ((buf[pos] == '4') && isdigit(buf[pos + 1]))
1259  {
1260 #ifdef HAVE_COLOR
1261  if (a->pair != -1)
1262  mutt_free_color(a->fg, a->bg);
1263 #endif
1264  a->pair = -1;
1265  a->attr |= ANSI_COLOR;
1266  a->bg = buf[pos + 1] - '0';
1267  pos += 3;
1268  }
1269  else
1270  {
1271  while (pos < x && buf[pos] != ';')
1272  pos++;
1273  pos++;
1274  }
1275  }
1276  }
1277  pos = x;
1278  return pos;
1279 }
bool C_AllowAnsi
Config: Allow ANSI colour codes in rich text messages.
Definition: pager.c:86
#define ANSI_COLOR
Use colours.
Definition: pager.c:194
int pair
Curses colour pair.
Definition: pager.c:205
#define ANSI_BOLD
Bold text.
Definition: pager.c:191
AnsiFlags attr
Attributes, e.g. underline, bold, etc.
Definition: pager.c:202
#define ANSI_BLINK
Blinking text.
Definition: pager.c:190
#define ANSI_REVERSE
Reverse video.
Definition: pager.c:193
int bg
Background colour.
Definition: pager.c:204
#define ANSI_UNDERLINE
Underlined text.
Definition: pager.c:192
void mutt_free_color(int fg, int bg)
int fg
Foreground colour.
Definition: pager.c:203
#define ANSI_OFF
Turn off colours and attributes.
Definition: pager.c:189

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

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

1295 {
1296  unsigned char *p = NULL, *q = NULL;
1297  static int b_read;
1298  int l = 0;
1299 
1300  if (*buf_ready == 0)
1301  {
1302  if (offset != *last_pos)
1303  fseeko(fp, offset, SEEK_SET);
1304  *buf = (unsigned char *) mutt_file_read_line((char *) *buf, blen, fp, &l, MUTT_EOL);
1305  if (!*buf)
1306  {
1307  fmt[0] = '\0';
1308  return -1;
1309  }
1310  *last_pos = ftello(fp);
1311  b_read = (int) (*last_pos - offset);
1312  *buf_ready = 1;
1313 
1314  mutt_mem_realloc(fmt, *blen);
1315 
1316  /* copy "buf" to "fmt", but without bold and underline controls */
1317  p = *buf;
1318  q = *fmt;
1319  while (*p)
1320  {
1321  if ((*p == '\010') && (p > *buf))
1322  {
1323  if (*(p + 1) == '_') /* underline */
1324  p += 2;
1325  else if (*(p + 1) && (q > *fmt)) /* bold or overstrike */
1326  {
1327  *(q - 1) = *(p + 1);
1328  p += 2;
1329  }
1330  else /* ^H */
1331  *q++ = *p++;
1332  }
1333  else if ((*p == '\033') && (*(p + 1) == '[') && is_ansi(p + 2))
1334  {
1335  while (*p++ != 'm') /* skip ANSI sequence */
1336  ;
1337  }
1338  else if ((*p == '\033') && (*(p + 1) == ']') &&
1339  ((check_attachment_marker((char *) p) == 0) ||
1340  (check_protected_header_marker((char *) p) == 0)))
1341  {
1342  mutt_debug(LL_DEBUG2, "Seen attachment marker.\n");
1343  while (*p++ != '\a') /* skip pseudo-ANSI sequence */
1344  ;
1345  }
1346  else
1347  *q++ = *p++;
1348  }
1349  *q = '\0';
1350  }
1351  return b_read;
1352 }
static int check_protected_header_marker(const char *p)
Check that the unique marker is present.
Definition: pager.c:859
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:630
Log at debug level 2.
Definition: logging.h:57
void mutt_mem_realloc(void *ptr, size_t size)
Resize a block of memory on the heap.
Definition: memory.c:124
#define MUTT_EOL
don&#39;t strip \n / \r\n
Definition: file.h:37
#define mutt_debug(LEVEL,...)
Definition: logging.h:85
static bool is_ansi(unsigned char *buf)
Is this an ANSI escape sequence?
Definition: pager.c:1182
static int check_attachment_marker(const char *p)
Check that the unique marker is present.
Definition: pager.c:849

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

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,
struct MuttWindow pager_window 
)
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]pager_windowWindow to write to
Return values
numNumber of characters displayed

Definition at line 1369 of file pager.c.

1372 {
1373  int space = -1; /* index of the last space or TAB */
1374  int col = C_Markers ? (*line_info)[n].continuation : 0;
1375  size_t k;
1376  int ch, vch, last_special = -1, special = 0, t;
1377  wchar_t wc;
1378  mbstate_t mbstate;
1379  int wrap_cols =
1380  mutt_window_wrap_cols(pager_window, (flags & MUTT_PAGER_NOWRAP) ? 0 : C_Wrap);
1381 
1382  if (check_attachment_marker((char *) buf) == 0)
1383  wrap_cols = pager_window->cols;
1384 
1385  /* FIXME: this should come from line_info */
1386  memset(&mbstate, 0, sizeof(mbstate));
1387 
1388  for (ch = 0, vch = 0; ch < cnt; ch += k, vch += k)
1389  {
1390  /* Handle ANSI sequences */
1391  while (cnt - ch >= 2 && buf[ch] == '\033' && buf[ch + 1] == '[' && is_ansi(buf + ch + 2))
1392  ch = grok_ansi(buf, ch + 2, pa) + 1;
1393 
1394  while (cnt - ch >= 2 && buf[ch] == '\033' && buf[ch + 1] == ']' &&
1395  ((check_attachment_marker((char *) buf + ch) == 0) ||
1396  (check_protected_header_marker((char *) buf + ch) == 0)))
1397  {
1398  while (buf[ch++] != '\a')
1399  if (ch >= cnt)
1400  break;
1401  }
1402 
1403  /* is anything left to do? */
1404  if (ch >= cnt)
1405  break;
1406 
1407  k = mbrtowc(&wc, (char *) buf + ch, cnt - ch, &mbstate);
1408  if ((k == (size_t)(-2)) || (k == (size_t)(-1)))
1409  {
1410  if (k == (size_t)(-1))
1411  memset(&mbstate, 0, sizeof(mbstate));
1412  mutt_debug(LL_DEBUG1, "mbrtowc returned %lu; errno = %d.\n", k, errno);
1413  if (col + 4 > wrap_cols)
1414  break;
1415  col += 4;
1416  if (pa)
1417  printw("\\%03o", buf[ch]);
1418  k = 1;
1419  continue;
1420  }
1421  if (k == 0)
1422  k = 1;
1423 
1424  if (CharsetIsUtf8)
1425  {
1426  /* zero width space, zero width no-break space */
1427  if ((wc == 0x200B) || (wc == 0xFEFF))
1428  {
1429  mutt_debug(LL_DEBUG3, "skip zero-width character U+%04X\n", (unsigned short) wc);
1430  continue;
1431  }
1433  {
1434  mutt_debug(LL_DEBUG3, "filtered U+%04X\n", (unsigned short) wc);
1435  continue;
1436  }
1437  }
1438 
1439  /* Handle backspace */
1440  special = 0;
1441  if (IsWPrint(wc))
1442  {
1443  wchar_t wc1;
1444  mbstate_t mbstate1 = mbstate;
1445  size_t k1 = mbrtowc(&wc1, (char *) buf + ch + k, cnt - ch - k, &mbstate1);
1446  while ((k1 != (size_t)(-2)) && (k1 != (size_t)(-1)) && (k1 > 0) && (wc1 == '\b'))
1447  {
1448  const size_t k2 =
1449  mbrtowc(&wc1, (char *) buf + ch + k + k1, cnt - ch - k - k1, &mbstate1);
1450  if ((k2 == (size_t)(-2)) || (k2 == (size_t)(-1)) || (k2 == 0) || (!IsWPrint(wc1)))
1451  break;
1452 
1453  if (wc == wc1)
1454  {
1455  special |= (wc == '_' && special & A_UNDERLINE) ? A_UNDERLINE : A_BOLD;
1456  }
1457  else if ((wc == '_') || (wc1 == '_'))
1458  {
1459  special |= A_UNDERLINE;
1460  wc = (wc1 == '_') ? wc : wc1;
1461  }
1462  else
1463  {
1464  /* special = 0; / * overstrike: nothing to do! */
1465  wc = wc1;
1466  }
1467 
1468  ch += k + k1;
1469  k = k2;
1470  mbstate = mbstate1;
1471  k1 = mbrtowc(&wc1, (char *) buf + ch + k, cnt - ch - k, &mbstate1);
1472  }
1473  }
1474 
1475  if (pa && ((flags & (MUTT_SHOWCOLOR | MUTT_SEARCH | MUTT_PAGER_MARKER)) ||
1476  special || last_special || pa->attr))
1477  {
1478  resolve_color(*line_info, n, vch, flags, special, pa);
1479  last_special = special;
1480  }
1481 
1482  /* no-break space, narrow no-break space */
1483  if (IsWPrint(wc) || (CharsetIsUtf8 && ((wc == 0x00A0) || (wc == 0x202F))))
1484  {
1485  if (wc == ' ')
1486  {
1487  space = ch;
1488  }
1489  t = wcwidth(wc);
1490  if (col + t > wrap_cols)
1491  break;
1492  col += t;
1493  if (pa)
1494  mutt_addwch(wc);
1495  }
1496  else if (wc == '\n')
1497  break;
1498  else if (wc == '\t')
1499  {
1500  space = ch;
1501  t = (col & ~7) + 8;
1502  if (t > wrap_cols)
1503  break;
1504  if (pa)
1505  for (; col < t; col++)
1506  addch(' ');
1507  else
1508  col = t;
1509  }
1510  else if ((wc < 0x20) || (wc == 0x7f))
1511  {
1512  if (col + 2 > wrap_cols)
1513  break;
1514  col += 2;
1515  if (pa)
1516  printw("^%c", ('@' + wc) & 0x7f);
1517  }
1518  else if (wc < 0x100)
1519  {
1520  if (col + 4 > wrap_cols)
1521  break;
1522  col += 4;
1523  if (pa)
1524  printw("\\%03o", wc);
1525  }
1526  else
1527  {
1528  if (col + 1 > wrap_cols)
1529  break;
1530  col += k;
1531  if (pa)
1532  addch(ReplacementChar);
1533  }
1534  }
1535  *pspace = space;
1536  *pcol = col;
1537  *pvch = vch;
1538  *pspecial = special;
1539  return ch;
1540 }
static int check_protected_header_marker(const char *p)
Check that the unique marker is present.
Definition: pager.c:859
bool mutt_mb_is_display_corrupting_utf8(wchar_t wc)
Will this character corrupt the display?
Definition: mbyte.c:375
#define IsWPrint(wc)
Definition: mbyte.h:39
#define MUTT_SHOWCOLOR
Show characters in color otherwise don&#39;t show characters.
Definition: pager.h:45
WHERE short C_Wrap
Config: Width to wrap text in the pager.
Definition: globals.h:159
#define MUTT_PAGER_NOWRAP
Format for term width, ignore $wrap.
Definition: pager.h:56
wchar_t ReplacementChar
When a Unicode character can&#39;t be displayed, use this instead.
Definition: charset.c:59
AnsiFlags attr
Attributes, e.g. underline, bold, etc.
Definition: pager.c:202
bool CharsetIsUtf8
Is the user&#39;s current character set utf-8?
Definition: charset.c:64
#define MUTT_SEARCH
Resolve search patterns.
Definition: pager.h:47
static int grok_ansi(unsigned char *buf, int pos, struct AnsiAttr *a)
Parse an ANSI escape sequence.
Definition: pager.c:1196
Log at debug level 1.
Definition: logging.h:56
#define MUTT_PAGER_MARKER
Use markers if option is set.
Definition: pager.h:53
#define mutt_debug(LEVEL,...)
Definition: logging.h:85
static bool is_ansi(unsigned char *buf)
Is this an ANSI escape sequence?
Definition: pager.c:1182
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:290
static int check_attachment_marker(const char *p)
Check that the unique marker is present.
Definition: pager.c:849
WHERE bool C_Markers
Config: Display a &#39;+&#39; at the beginning of wrapped lines in the pager.
Definition: globals.h:247
Log at debug level 3.
Definition: logging.h:58
int mutt_addwch(wchar_t wc)
addwch would be provided by an up-to-date curses library
Definition: curs_lib.c:877
int mutt_window_wrap_cols(struct MuttWindow *win, short wrap)
Calculate the wrap column for a Window.
Definition: mutt_window.c:309

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

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

Print a line on screen.

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

Definition at line 1560 of file pager.c.

1564 {
1565  unsigned char *buf = NULL, *fmt = NULL;
1566  size_t buflen = 0;
1567  unsigned char *buf_ptr = NULL;
1568  int ch, vch, col, cnt, b_read;
1569  int buf_ready = 0;
1570  bool change_last = false;
1571  int special;
1572  int offset;
1573  int def_color;
1574  int m;
1575  int rc = -1;
1576  struct AnsiAttr a = { 0, 0, 0, -1 };
1577  regmatch_t pmatch[1];
1578 
1579  if (n == *last)
1580  {
1581  (*last)++;
1582  change_last = true;
1583  }
1584 
1585  if (*last == *max)
1586  {
1587  mutt_mem_realloc(line_info, sizeof(struct Line) * (*max += LINES));
1588  for (ch = *last; ch < *max; ch++)
1589  {
1590  memset(&((*line_info)[ch]), 0, sizeof(struct Line));
1591  (*line_info)[ch].type = -1;
1592  (*line_info)[ch].search_cnt = -1;
1593  (*line_info)[ch].syntax = mutt_mem_malloc(sizeof(struct Syntax));
1594  ((*line_info)[ch].syntax)[0].first = -1;
1595  ((*line_info)[ch].syntax)[0].last = -1;
1596  }
1597  }
1598 
1599  if (flags & MUTT_PAGER_LOGS)
1600  {
1601  /* determine the line class */
1602  if (fill_buffer(fp, last_pos, (*line_info)[n].offset, &buf, &fmt, &buflen, &buf_ready) < 0)
1603  {
1604  if (change_last)
1605  (*last)--;
1606  goto out;
1607  }
1608 
1609  (*line_info)[n].type = MT_COLOR_MESSAGE_LOG;
1610  if (buf[11] == 'M')
1611  (*line_info)[n].syntax[0].color = MT_COLOR_MESSAGE;
1612  else if (buf[11] == 'E')
1613  (*line_info)[n].syntax[0].color = MT_COLOR_ERROR;
1614  else
1615  (*line_info)[n].syntax[0].color = MT_COLOR_NORMAL;
1616  }
1617 
1618  /* only do color highlighting if we are viewing a message */
1619  if (flags & (MUTT_SHOWCOLOR | MUTT_TYPES))
1620  {
1621  if ((*line_info)[n].type == -1)
1622  {
1623  /* determine the line class */
1624  if (fill_buffer(fp, last_pos, (*line_info)[n].offset, &buf, &fmt, &buflen, &buf_ready) < 0)
1625  {
1626  if (change_last)
1627  (*last)--;
1628  goto out;
1629  }
1630 
1631  resolve_types((char *) fmt, (char *) buf, *line_info, n, *last,
1632  quote_list, q_level, force_redraw, flags & MUTT_SHOWCOLOR);
1633 
1634  /* avoid race condition for continuation lines when scrolling up */
1635  for (m = n + 1; m < *last && (*line_info)[m].offset && (*line_info)[m].continuation; m++)
1636  (*line_info)[m].type = (*line_info)[n].type;
1637  }
1638 
1639  /* this also prevents searching through the hidden lines */
1640  if ((flags & MUTT_HIDE) && ((*line_info)[n].type == MT_COLOR_QUOTED))
1641  flags = 0; /* MUTT_NOSHOW */
1642  }
1643 
1644  /* At this point, (*line_info[n]).quote may still be undefined. We
1645  * don't want to compute it every time MUTT_TYPES is set, since this
1646  * would slow down the "bottom" function unacceptably. A compromise
1647  * solution is hence to call regexec() again, just to find out the
1648  * length of the quote prefix. */
1649  if ((flags & MUTT_SHOWCOLOR) && !(*line_info)[n].continuation &&
1650  ((*line_info)[n].type == MT_COLOR_QUOTED) && !(*line_info)[n].quote)
1651  {
1652  if (fill_buffer(fp, last_pos, (*line_info)[n].offset, &buf, &fmt, &buflen, &buf_ready) < 0)
1653  {
1654  if (change_last)
1655  (*last)--;
1656  goto out;
1657  }
1658  if (C_QuoteRegex && C_QuoteRegex->regex &&
1659  (regexec(C_QuoteRegex->regex, (char *) fmt, 1, pmatch, 0) == 0))
1660  {
1661  (*line_info)[n].quote =
1662  classify_quote(quote_list, (char *) fmt + pmatch[0].rm_so,
1663  pmatch[0].rm_eo - pmatch[0].rm_so, force_redraw, q_level);
1664  }
1665  else
1666  {
1667  goto out;
1668  }
1669  }
1670 
1671  if ((flags & MUTT_SEARCH) && !(*line_info)[n].continuation &&
1672  ((*line_info)[n].search_cnt == -1))
1673  {
1674  if (fill_buffer(fp, last_pos, (*line_info)[n].offset, &buf, &fmt, &buflen, &buf_ready) < 0)
1675  {
1676  if (change_last)
1677  (*last)--;
1678  goto out;
1679  }
1680 
1681  offset = 0;
1682  (*line_info)[n].search_cnt = 0;
1683  while (regexec(search_re, (char *) fmt + offset, 1, pmatch,
1684  (offset ? REG_NOTBOL : 0)) == 0)
1685  {
1686  if (++((*line_info)[n].search_cnt) > 1)
1687  {
1688  mutt_mem_realloc(&((*line_info)[n].search),
1689  ((*line_info)[n].search_cnt) * sizeof(struct Syntax));
1690  }
1691  else
1692  (*line_info)[n].search = mutt_mem_malloc(sizeof(struct Syntax));
1693  pmatch[0].rm_so += offset;
1694  pmatch[0].rm_eo += offset;
1695  ((*line_info)[n].search)[(*line_info)[n].search_cnt - 1].first = pmatch[0].rm_so;
1696  ((*line_info)[n].search)[(*line_info)[n].search_cnt - 1].last = pmatch[0].rm_eo;
1697 
1698  if (pmatch[0].rm_eo == pmatch[0].rm_so)
1699  offset++; /* avoid degenerate cases */
1700  else
1701  offset = pmatch[0].rm_eo;
1702  if (!fmt[offset])
1703  break;
1704  }
1705  }
1706 
1707  if (!(flags & MUTT_SHOW) && ((*line_info)[n + 1].offset > 0))
1708  {
1709  /* we've already scanned this line, so just exit */
1710  rc = 0;
1711  goto out;
1712  }
1713  if ((flags & MUTT_SHOWCOLOR) && *force_redraw && ((*line_info)[n + 1].offset > 0))
1714  {
1715  /* no need to try to display this line... */
1716  rc = 1;
1717  goto out; /* fake display */
1718  }
1719 
1720  b_read = fill_buffer(fp, last_pos, (*line_info)[n].offset, &buf, &fmt, &buflen, &buf_ready);
1721  if (b_read < 0)
1722  {
1723  if (change_last)
1724  (*last)--;
1725  goto out;
1726  }
1727 
1728  /* now chose a good place to break the line */
1729  cnt = format_line(line_info, n, buf, flags, 0, b_read, &ch, &vch, &col, &special, pager_window);
1730  buf_ptr = buf + cnt;
1731 
1732  /* move the break point only if smart_wrap is set */
1733  if (C_SmartWrap)
1734  {
1735  if ((cnt < b_read) && (ch != -1) && !ISHEADER((*line_info)[n].type) &&
1736  !ISSPACE(buf[cnt]))
1737  {
1738  buf_ptr = buf + ch;
1739  /* skip trailing blanks */
1740  while (ch && (buf[ch] == ' ' || buf[ch] == '\t' || buf[ch] == '\r'))
1741  ch--;
1742  /* A very long word with leading spaces causes infinite
1743  * wrapping when MUTT_PAGER_NSKIP is set. A folded header
1744  * with a single long word shouldn't be smartwrapped
1745  * either. So just disable smart_wrap if it would wrap at the
1746  * beginning of the line. */
1747  if (!ch)
1748  buf_ptr = buf + cnt;
1749  else
1750  cnt = ch + 1;
1751  }
1752  if (!(flags & MUTT_PAGER_NSKIP))
1753  {
1754  /* skip leading blanks on the next line too */
1755  while (*buf_ptr == ' ' || *buf_ptr == '\t')
1756  buf_ptr++;
1757  }
1758  }
1759 
1760  if (*buf_ptr == '\r')
1761  buf_ptr++;
1762  if (*buf_ptr == '\n')
1763  buf_ptr++;
1764 
1765  if (((int) (buf_ptr - buf) < b_read) && !(*line_info)[n + 1].continuation)
1766  append_line(*line_info, n, (int) (buf_ptr - buf));
1767  (*line_info)[n + 1].offset = (*line_info)[n].offset + (long) (buf_ptr - buf);
1768 
1769  /* if we don't need to display the line we are done */
1770  if (!(flags & MUTT_SHOW))
1771  {
1772  rc = 0;
1773  goto out;
1774  }
1775 
1776  /* display the line */
1777  format_line(line_info, n, buf, flags, &a, cnt, &ch, &vch, &col, &special, pager_window);
1778 
1779 /* avoid a bug in ncurses... */
1780 #ifndef USE_SLANG_CURSES
1781  if (col == 0)
1782  {
1783  NORMAL_COLOR;
1784  addch(' ');
1785  }
1786 #endif
1787 
1788  /* end the last color pattern (needed by S-Lang) */
1789  if (special || ((col != pager_window->cols) && (flags & (MUTT_SHOWCOLOR | MUTT_SEARCH))))
1790  resolve_color(*line_info, n, vch, flags, 0, &a);
1791 
1792  /* Fill the blank space at the end of the line with the prevailing color.
1793  * ncurses does an implicit clrtoeol() when you do addch('\n') so we have
1794  * to make sure to reset the color *after* that */
1795  if (flags & MUTT_SHOWCOLOR)
1796  {
1797  m = ((*line_info)[n].continuation) ? ((*line_info)[n].syntax)[0].first : n;
1798  if ((*line_info)[m].type == MT_COLOR_HEADER)
1799  def_color = ((*line_info)[m].syntax)[0].color;
1800  else
1801  def_color = ColorDefs[(*line_info)[m].type];
1802 
1803  ATTRSET(def_color);
1804  }
1805 
1806  if (col < pager_window->cols)
1807  mutt_window_clrtoeol(pager_window);
1808 
1809  /* reset the color back to normal. This *must* come after the
1810  * clrtoeol, otherwise the color for this line will not be
1811  * filled to the right margin. */
1812  if (flags & MUTT_SHOWCOLOR)
1813  NORMAL_COLOR;
1814 
1815  /* build a return code */
1816  if (!(flags & MUTT_SHOW))
1817  flags = 0;
1818 
1819  rc = flags;
1820 
1821 out:
1822  FREE(&buf);
1823  FREE(&fmt);
1824  return rc;
1825 }
#define MUTT_TYPES
Compute line&#39;s type.
Definition: pager.h:48
#define NORMAL_COLOR
Definition: mutt_curses.h:237
#define MUTT_SHOWCOLOR
Show characters in color otherwise don&#39;t show characters.
Definition: pager.h:45
Pager: quoted text.
Definition: mutt_curses.h:125
void mutt_window_clrtoeol(struct MuttWindow *win)
Clear to the end of the line.
Definition: mutt_window.c:81
regex_t * regex
compiled expression
Definition: regex3.h:60
#define ISHEADER(x)
Definition: pager.c:97
Message headers (takes a pattern)
Definition: mutt_curses.h:135
An ANSI escape sequence.
Definition: pager.c:200
Highlighting for a line of text.
Definition: pager.c:163
Plain text.
Definition: mutt_curses.h:130
#define ATTRSET
Definition: mutt_curses.h:230
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:917
#define MUTT_PAGER_NSKIP
Preserve whitespace with smartwrap.
Definition: pager.h:52
#define MUTT_SHOW
Definition: pager.h:49
void mutt_mem_realloc(void *ptr, size_t size)
Resize a block of memory on the heap.
Definition: memory.c:124
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, struct MuttWindow *pager_window)
Display a line of text in the pager.
Definition: pager.c:1369
Informational message.
Definition: mutt_curses.h:136
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:99
WHERE struct Regex * C_QuoteRegex
Config: Regex to match quoted text in a reply.
Definition: globals.h:185
A line of text in the pager.
Definition: pager.c:173
#define MUTT_HIDE
Don&#39;t show quoted text.
Definition: pager.h:46
int ColorDefs[MT_COLOR_MAX]
Array of all fixed colours, see enum ColorId.
Definition: color.c:52
#define MUTT_PAGER_LOGS
Logview mode.
Definition: pager.h:57
#define ISSPACE(ch)
Definition: string2.h:37
bool C_SmartWrap
Config: Wrap text at word boundaries.
Definition: pager.c:93
Menu showing log messages.
Definition: mutt_curses.h:153
#define MUTT_SEARCH
Resolve search patterns.
Definition: pager.h:47
#define FREE(x)
Definition: memory.h:40
Error message.
Definition: mutt_curses.h:131
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:1293
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:522
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:290
static void append_line(struct Line *line_info, int n, int cnt)
Add a new Line to the array.
Definition: pager.c:422

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

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

1836 {
1837  while (cur > 0 && nlines > 0)
1838  {
1839  cur--;
1840  if (!hiding || (info[cur].type != MT_COLOR_QUOTED))
1841  nlines--;
1842  }
1843 
1844  return cur;
1845 }
Pager: quoted text.
Definition: mutt_curses.h:125

+ Here is the caller graph for this function:

void mutt_clear_pager_position ( void  )

Reset the pager's viewing position.

Definition at line 1875 of file pager.c.

1876 {
1877  TopLine = 0;
1878  OldHdr = NULL;
1879 }
static int TopLine
Definition: pager.c:111
static struct Email * OldHdr
Definition: pager.c:112

+ Here is the caller graph for this function:

static void pager_custom_redraw ( struct Menu pager_menu)
static

Redraw the pager window - Implements Menu::menu_custom_redraw()

Definition at line 1923 of file pager.c.

1924 {
1925  struct PagerRedrawData *rd = pager_menu->redraw_data;
1926  char buf[1024];
1927 
1928  if (!rd)
1929  return;
1930 
1931  if (pager_menu->redraw & REDRAW_FULL)
1932  {
1934  NORMAL_COLOR;
1935  /* clear() doesn't optimize screen redraws */
1936  move(0, 0);
1937  clrtobot();
1938 
1939  if (IsEmail(rd->extra) && Context && ((Context->mailbox->vcount + 1) < C_PagerIndexLines))
1940  rd->indexlen = Context->mailbox->vcount + 1;
1941  else
1943 
1944  rd->indicator = rd->indexlen / 3;
1945 
1946  memcpy(rd->pager_window, MuttIndexWindow, sizeof(struct MuttWindow));
1947  memcpy(rd->pager_status_window, MuttStatusWindow, sizeof(struct MuttWindow));
1948  rd->index_status_window->rows = 0;
1949  rd->index_window->rows = 0;
1950 
1951  if (IsEmail(rd->extra) && C_PagerIndexLines)
1952  {
1953  memcpy(rd->index_window, MuttIndexWindow, sizeof(struct MuttWindow));
1954  rd->index_window->rows = rd->indexlen > 0 ? rd->indexlen - 1 : 0;
1955 
1956  if (C_StatusOnTop)
1957  {
1958  memcpy(rd->index_status_window, MuttStatusWindow, sizeof(struct MuttWindow));
1959 
1960  memcpy(rd->pager_status_window, MuttIndexWindow, sizeof(struct MuttWindow));
1961  rd->pager_status_window->rows = 1;
1963 
1964  rd->pager_window->rows -=
1966  rd->pager_window->row_offset +=
1968  }
1969  else
1970  {
1971  memcpy(rd->index_status_window, MuttIndexWindow, sizeof(struct MuttWindow));
1972  rd->index_status_window->rows = 1;
1974 
1975  rd->pager_window->rows -=
1977  rd->pager_window->row_offset +=
1979  }
1980  }
1981 
1982  if (C_Help)
1983  {
1987  NORMAL_COLOR;
1988  }
1989 
1990  if (Resize)
1991  {
1993  if (rd->search_compiled)
1994  {
1995  int flags = mutt_mb_is_lower(rd->searchbuf) ? REG_ICASE : 0;
1996  const int err = REGCOMP(&rd->search_re, rd->searchbuf, REG_NEWLINE | flags);
1997  if (err != 0)
1998  {
1999  regerror(err, &rd->search_re, buf, sizeof(buf));
2000  mutt_error("%s", buf);
2001  rd->search_compiled = false;
2002  }
2003  else
2004  {
2005  rd->search_flag = MUTT_SEARCH;
2007  }
2008  }
2009  rd->lines = Resize->line;
2010  pager_menu->redraw |= REDRAW_FLOW;
2011 
2012  FREE(&Resize);
2013  }
2014 
2015  if (IsEmail(rd->extra) && C_PagerIndexLines)
2016  {
2017  if (!rd->index)
2018  {
2019  /* only allocate the space if/when we need the index.
2020  * Initialise the menu as per the main index */
2021  rd->index = mutt_menu_new(MENU_MAIN);
2023  rd->index->menu_color = index_color;
2024  rd->index->max = Context ? Context->mailbox->vcount : 0;
2025  rd->index->current = rd->extra->email->virtual;
2026  rd->index->indexwin = rd->index_window;
2027  rd->index->statuswin = rd->index_status_window;
2028  }
2029 
2030  NORMAL_COLOR;
2031  rd->index->pagelen = rd->index_window->rows;
2032 
2033  /* some fudge to work out whereabouts the indicator should go */
2034  if (rd->index->current - rd->indicator < 0)
2035  rd->index->top = 0;
2036  else if (rd->index->max - rd->index->current < rd->index->pagelen - rd->indicator)
2037  rd->index->top = rd->index->max - rd->index->pagelen;
2038  else
2039  rd->index->top = rd->index->current - rd->indicator;
2040 
2041  menu_redraw_index(rd->index);
2042  }
2043 
2044  pager_menu->redraw |= REDRAW_BODY | REDRAW_INDEX | REDRAW_STATUS;
2045 #ifdef USE_SIDEBAR
2046  pager_menu->redraw |= REDRAW_SIDEBAR;
2047 #endif
2048  mutt_show_error();
2049  }
2050 
2051  if (pager_menu->redraw & REDRAW_FLOW)
2052  {
2053  if (!(rd->flags & MUTT_PAGER_RETWINCH))
2054  {
2055  rd->lines = -1;
2056  for (int i = 0; i <= rd->topline; i++)
2057  if (!rd->line_info[i].continuation)
2058  rd->lines++;
2059  for (int i = 0; i < rd->max_line; i++)
2060  {
2061  rd->line_info[i].offset = 0;
2062  rd->line_info[i].type = -1;
2063  rd->line_info[i].continuation = 0;
2064  rd->line_info[i].chunks = 0;
2065  rd->line_info[i].search_cnt = -1;
2066  rd->line_info[i].quote = NULL;
2067 
2068  mutt_mem_realloc(&(rd->line_info[i].syntax), sizeof(struct Syntax));
2069  if (rd->search_compiled && rd->line_info[i].search)
2070  FREE(&(rd->line_info[i].search));
2071  }
2072 
2073  rd->last_line = 0;
2074  rd->topline = 0;
2075  }
2076  int i = -1;
2077  int j = -1;
2078  while (display_line(rd->fp, &rd->last_pos, &rd->line_info, ++i, &rd->last_line,
2079  &rd->max_line, rd->has_types | rd->search_flag | (rd->flags & MUTT_PAGER_NOWRAP),
2080  &rd->quote_list, &rd->q_level, &rd->force_redraw,
2081  &rd->search_re, rd->pager_window) == 0)
2082  {
2083  if (!rd->line_info[i].continuation && (++j == rd->lines))
2084  {
2085  rd->topline = i;
2086  if (!rd->search_flag)
2087  break;
2088  }
2089  }
2090  }
2091 
2092 #ifdef USE_SIDEBAR
2093  if (pager_menu->redraw & REDRAW_SIDEBAR)
2094  {
2095  menu_redraw_sidebar(pager_menu);
2096  }
2097 #endif
2098 
2099  if ((pager_menu->redraw & REDRAW_BODY) || (rd->topline != rd->oldtopline))
2100  {
2101  do
2102  {
2103  mutt_window_move(rd->pager_window, 0, 0);
2104  rd->curline = rd->topline;
2105  rd->oldtopline = rd->topline;
2106  rd->lines = 0;
2107  rd->force_redraw = false;
2108 
2109  while (rd->lines < rd->pager_window->rows &&
2110  rd->line_info[rd->curline].offset <= rd->sb.st_size - 1)
2111  {
2112  if (display_line(rd->fp, &rd->last_pos, &rd->line_info, rd->curline,
2113  &rd->last_line, &rd->max_line,
2114  (rd->flags & MUTT_DISPLAYFLAGS) | rd->hide_quoted |
2115  rd->search_flag | (rd->flags & MUTT_PAGER_NOWRAP),
2116  &rd->quote_list, &rd->q_level, &rd->force_redraw,
2117  &rd->search_re, rd->pager_window) > 0)
2118  {
2119  rd->lines++;
2120  }
2121  rd->curline++;
2122  mutt_window_move(rd->pager_window, rd->lines, 0);
2123  }
2124  rd->last_offset = rd->line_info[rd->curline].offset;
2125  } while (rd->force_redraw);
2126 
2128  while (rd->lines < rd->pager_window->rows)
2129  {
2131  if (C_Tilde)
2132  addch('~');
2133  rd->lines++;
2134  mutt_window_move(rd->pager_window, rd->lines, 0);
2135  }
2136  NORMAL_COLOR;
2137 
2138  /* We are going to update the pager status bar, so it isn't
2139  * necessary to reset to normal color now. */
2140 
2141  pager_menu->redraw |= REDRAW_STATUS; /* need to update the % seen */
2142  }
2143 
2144  if (pager_menu->redraw & REDRAW_STATUS)
2145  {
2146  struct HdrFormatInfo hfi;
2147  char pager_progress_str[65]; /* Lots of space for translations */
2148 
2149  hfi.ctx = Context;
2150  hfi.mailbox = Context ? Context->mailbox : NULL;
2151  hfi.pager_progress = pager_progress_str;
2152 
2153  if (rd->last_pos < rd->sb.st_size - 1)
2154  {
2155  snprintf(pager_progress_str, sizeof(pager_progress_str), OFF_T_FMT "%%",
2156  (100 * rd->last_offset / rd->sb.st_size));
2157  }
2158  else
2159  {
2160  const char *msg = (rd->topline == 0) ?
2161  /* L10N: Status bar message: the entire email is visible in the pager */
2162  _("all") :
2163  /* L10N: Status bar message: the end of the email is visible in the pager */
2164  _("end");
2165  mutt_str_strfcpy(pager_progress_str, msg, sizeof(pager_progress_str));
2166  }
2167 
2168  /* print out the pager status bar */
2171 
2172  if (IsEmail(rd->extra) || IsMsgAttach(rd->extra))
2173  {
2174  size_t l1 = rd->pager_status_window->cols * MB_LEN_MAX;
2175  size_t l2 = sizeof(buf);
2176  hfi.email = (IsEmail(rd->extra)) ? rd->extra->email : rd->extra->body->email;
2177  mutt_make_string_info(buf, l1 < l2 ? l1 : l2, rd->pager_status_window->cols,
2178  NONULL(C_PagerFormat), &hfi, 0);
2180  }
2181  else
2182  {
2183  char bn[256];
2184  snprintf(bn, sizeof(bn), "%s (%s)", rd->banner, pager_progress_str);
2185  mutt_draw_statusline(rd->pager_status_window->cols, bn, sizeof(bn));
2186  }
2187  NORMAL_COLOR;
2188  if (C_TsEnabled && TsSupported && rd->index)
2189  {
2190  menu_status_line(buf, sizeof(buf), rd->index, NONULL(C_TsStatusFormat));
2191  mutt_ts_status(buf);
2192  menu_status_line(buf, sizeof(buf), rd->index, NONULL(C_TsIconFormat));
2193  mutt_ts_icon(buf);
2194  }
2195  }
2196 
2197  if ((pager_menu->redraw & REDRAW_INDEX) && rd->index)
2198  {
2199  /* redraw the pager_index indicator, because the
2200  * flags for this message might have changed. */
2201  if (rd->index_window->rows > 0)
2203 
2204  /* print out the index status bar */
2205  menu_status_line(buf, sizeof(buf), rd->index, NONULL(C_StatusFormat));
2206 
2209  mutt_draw_statusline(rd->index_status_window->cols, buf, sizeof(buf));
2210  NORMAL_COLOR;
2211  }
2212 
2213  pager_menu->redraw = 0;
2214 }
struct Context * ctx
Definition: hdrline.h:45
The "current" mailbox.
Definition: context.h:37
WHERE bool C_StatusOnTop
Config: Display the status bar at the top.
Definition: globals.h:261
WHERE char * C_TsIconFormat
Config: printf-like format string for the terminal&#39;s icon title.
Definition: globals.h:153
#define REDRAW_FULL
Redraw everything.
Definition: mutt_menu.h:47
#define NONULL(x)
Definition: string2.h:36
const char * banner
Definition: pager.c:1912
PagerFlags hide_quoted
Definition: pager.c:1898
struct MuttWindow * MuttStatusWindow
Status Window.
Definition: mutt_window.c:40
PagerFlags search_flag
Definition: pager.c:1910
#define MUTT_DISPLAYFLAGS
Definition: pager.h:60
short chunks
Definition: pager.c:178
Keep track when the pager needs redrawing.
Definition: pager.c:1884
#define NORMAL_COLOR
Definition: mutt_curses.h:237
Pager: empty lines after message.
Definition: mutt_curses.h:132
int virtual
virtual message number
Definition: email.h:90
#define REDRAW_FLOW
Used by pager to reflow text.
Definition: mutt_menu.h:49
struct MuttWindow * pager_status_window
Definition: pager.c:1905
void mutt_window_clrtoeol(struct MuttWindow *win)
Clear to the end of the line.
Definition: mutt_window.c:81
WHERE bool C_Help
Config: Display a help line with common key bindings.
Definition: globals.h:226
void index_make_entry(char *buf, size_t buflen, struct Menu *menu, int line)
Format a menu item for the index list - Implements Menu::menu_make_entry()
Definition: index.c:733
#define IsMsgAttach(pager)
Definition: pager.c:100
#define _(a)
Definition: message.h:28
struct Line * line_info
Definition: pager.c:1915
int index_color(int line)
Calculate the colour for a line of the index - Implements Menu::menu_color()
Definition: index.c:806
void menu_status_line(char *buf, size_t buflen, struct Menu *menu, const char *p)
Create the status line.
Definition: status.c:393
struct MuttWindow * MuttHelpWindow
Help Window.
Definition: mutt_window.c:38
struct Body * body
current attachment
Definition: pager.h:69
A division of the screen.
Definition: mutt_window.h:33
PagerFlags flags
Definition: pager.c:1886
Index panel (list of emails)
Definition: keymap.h:74
bool search_back
Definition: pager.c:217
Highlighting for a line of text.
Definition: pager.c:163
WHERE char * C_StatusFormat
Config: printf-like format string for the index&#39;s status line.
Definition: globals.h:151
bool search_compiled
Definition: pager.c:216
short type
Definition: pager.c:176
#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:264
void(* menu_make_entry)(char *buf, size_t buflen, struct Menu *menu, int line)
Format a item for a menu.
Definition: mutt_menu.h:121
int vcount
the number of virtual messages
Definition: mailbox.h:103
#define REDRAW_SIDEBAR
Redraw the sidebar.
Definition: mutt_menu.h:51
void mutt_paddstr(int n, const char *s)
Display a string on screen, padded if necessary.
Definition: curs_lib.c:1083
LOFF_T last_pos
Definition: pager.c:1901
struct MuttWindow * index_status_window
Definition: pager.c:1903
int line
Definition: pager.c:215
void * redraw_data
Definition: mutt_menu.h:151
struct Mailbox * mailbox
Definition: context.h:51
Data passed to index_format_str()
Definition: hdrline.h:43
LOFF_T last_offset
Definition: pager.c:1902
FILE * fp
Definition: pager.c:1916
short continuation
Definition: pager.c:177
bool force_redraw
Definition: pager.c:1896
void mutt_window_reflow(void)
Resize the Windows to fit the screen.
Definition: mutt_window.c:222
void mutt_mem_realloc(void *ptr, size_t size)
Resize a block of memory on the heap.
Definition: memory.c:124
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:1489
int oldtopline
Definition: pager.c:1890
struct Pager * extra
Definition: pager.c:1887
struct QClass * quote
Definition: pager.c:182
short search_cnt
Definition: pager.c:179
struct MuttWindow * statuswin
Definition: mutt_menu.h:96
WHERE struct Context * Context
Definition: globals.h:41
#define REDRAW_STATUS
Redraw the status bar.
Definition: mutt_menu.h:46
bool search_compiled
Definition: pager.c:1909
struct Syntax * syntax
Definition: pager.c:180
struct MuttWindow * MuttIndexWindow
Index Window.
Definition: mutt_window.c:39
struct MuttWindow * pager_window
Definition: pager.c:1906
struct MuttWindow * indexwin
Definition: mutt_menu.h:95
struct MuttWindow * index_window
Definition: pager.c:1904
int top
entry that is the top of the current page
Definition: mutt_menu.h:109
size_t mutt_str_strfcpy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:741
int pagelen
number of entries per screen
Definition: mutt_menu.h:92
bool TsSupported
Terminal Setting is supported.
Definition: terminal.c:43
int mutt_window_move(struct MuttWindow *win, int row, int col)
Move the cursor in a Window.
Definition: mutt_window.c:162
WHERE char * C_TsStatusFormat
Config: printf-like format string for the terminal&#39;s status (window title)
Definition: globals.h:152
int(* menu_color)(int line)
Calculate the colour for a line of the menu.
Definition: mutt_menu.h:145
#define SETCOLOR(X)
Definition: mutt_curses.h:222
int max
the number of entries in the menu
Definition: mutt_menu.h:88
MuttRedrawFlags redraw
when to redraw the screen
Definition: mutt_menu.h:89
struct Menu * index
the Pager Index (PI)
Definition: pager.c:1907
struct QClass * quote_list
Definition: pager.c:1900
#define IsEmail(pager)
Definition: pager.c:102
int indicator
the indicator line of the PI
Definition: pager.c:1889
struct Email * email
current message
Definition: pager.h:68
#define MUTT_PAGER_RETWINCH
Need reformatting on SIGWINCH.
Definition: pager.h:54
#define MUTT_SEARCH
Resolve search patterns.
Definition: pager.h:47
#define REDRAW_BODY
Redraw the pager.
Definition: mutt_menu.h:48
char * searchbuf
Definition: pager.c:1914
#define REDRAW_INDEX
Redraw the index.
Definition: mutt_menu.h:42
#define mutt_error(...)
Definition: logging.h:88
int row_offset
Definition: mutt_window.h:37
#define FREE(x)
Definition: memory.h:40
Status bar.
Definition: mutt_curses.h:128
struct Syntax * search
Definition: pager.c:181
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:95
void mutt_show_error(void)
Show the user an error message.
Definition: curs_lib.c:483
Keep track of screen resizing.
Definition: pager.c:213
#define REGCOMP(preg, regex, cflags)
Compile a regular expression.
Definition: regex3.h:52
void mutt_ts_status(char *str)
Set the text of the terminal title bar.
Definition: terminal.c:104
struct stat sb
Definition: pager.c:1917
int current
current entry
Definition: mutt_menu.h:87
char * helpstr
Definition: pager.c:1913
LOFF_T offset
Definition: pager.c:175
bool mutt_mb_is_lower(const char *s)
Does a multi-byte string contain only lowercase characters?
Definition: mbyte.c:346
struct Email * email
header information for message/rfc822
Definition: body.h:60
static int display_line(FILE *fp, LOFF_T *last_pos, struct Line **line_info, int n, int *last, int *max, PagerFlags flags, struct QClass **quote_list, int *q_level, bool *force_redraw, regex_t *search_re, struct MuttWindow *pager_window)
Print a line on screen.
Definition: pager.c:1560
void mutt_draw_statusline(int cols, const char *buf, size_t buflen)
Draw a highlighted status bar.
Definition: index.c:835
short C_PagerIndexLines
Config: Number of index lines to display above the pager.
Definition: pager.c:89
WHERE char * C_PagerFormat
Config: printf-like format string for the pager&#39;s status bar.
Definition: globals.h:139
regex_t search_re
Definition: pager.c:1908
bool search_back
Definition: pager.c:1911

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

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 "hdr" is NULL. The "hdr" 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 2231 of file pager.c.

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

+ Here is the caller graph for this function:

Variable Documentation

bool C_AllowAnsi

Config: Allow ANSI colour codes in rich text messages.

Definition at line 86 of file pager.c.

bool C_HeaderColorPartial

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

Definition at line 87 of file pager.c.

short C_PagerContext

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

Definition at line 88 of file pager.c.

short C_PagerIndexLines

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

Definition at line 89 of file pager.c.

bool C_PagerStop

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

Definition at line 90 of file pager.c.

short C_SearchContext

Config: Context to display around search matches.

Definition at line 91 of file pager.c.

short C_SkipQuotedOffset

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

Definition at line 92 of file pager.c.

bool C_SmartWrap

Config: Wrap text at word boundaries.

Definition at line 93 of file pager.c.

struct Regex* C_Smileys

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

Definition at line 94 of file pager.c.

bool C_Tilde

Config: Character to pad blank lines in the pager.

Definition at line 95 of file pager.c.

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

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

Definition at line 106 of file pager.c.

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

int TopLine = 0
static

Definition at line 111 of file pager.c.

struct Email* OldHdr = NULL
static

Definition at line 112 of file pager.c.

short InHelp = 0
static

Definition at line 208 of file pager.c.

struct Resize * Resize = NULL
static
int braille_line = -1
static

Definition at line 828 of file pager.c.

int braille_col = -1
static

Definition at line 829 of file pager.c.

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

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

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