NeoMutt  2018-07-16 +1783-b00bd9
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 IS_HEADER(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 IS_HEADER (   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:785
#define _(a)
Definition: message.h:28
static const char * Not_available_in_this_menu
Definition: pager.c:104
static struct UrlTest test[]
Definition: url_parse.c:39
#define mutt_error(...)
Definition: logging.h:83

Definition at line 114 of file pager.c.

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

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:785
#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:83

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:38
void mutt_flushinp(void)
Empty all the keyboard buffers.
Definition: curs_lib.c:785
#define _(a)
Definition: message.h:28
struct Mailbox * mailbox
Definition: context.h:52
AclFlags rights
ACL bits, see AclFlags.
Definition: mailbox.h:121
#define mutt_error(...)
Definition: logging.h:83

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 (!IS_SPACE(*s))
251  return 0;
252  s++;
253  }
254 
255  return -1;
256  }
257 
258  return 0;
259 }
Pager: signature lines.
Definition: mutt_curses.h:127
#define NUM_SIG_LINES
Definition: pager.c:220
#define IS_SPACE(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 == 0)
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  ATTR_SET(color);
412  last_color = color;
413  }
414 }
int first
Definition: pager.c:166
#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:126
Bold text.
Definition: mutt_curses.h:141
int last
Definition: pager.c:167
Message headers (takes a pattern)
Definition: mutt_curses.h:136
Pager: search matches.
Definition: mutt_curses.h:140
Highlighting for a line of text.
Definition: pager.c:163
Pager: markers, line continuation.
Definition: mutt_curses.h:134
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:131
AnsiFlags attr
Attributes, e.g. underline, bold, etc.
Definition: pager.c:202
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:142
#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 ATTR_SET
Definition: mutt_curses.h:232
#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:53
#define SET_COLOR(X)
Definition: mutt_curses.h:224
#define MUTT_PAGER_LOGS
Logview mode.
Definition: pager.h:57
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:239
int mutt_alloc_color(uint32_t fg, uint32_t bg)
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:51
int ColorQuoteUsed
Number of colours for quoted email text.
Definition: color.c:52

+ 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:51
int ColorQuoteUsed
Number of colours for quoted email text.
Definition: color.c:52
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:51
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:52
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:645
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
struct Regex * C_Smileys
Config: Regex to match smileys to prevent mistakes when quoting text.
Definition: pager.c:94
const char * line
Definition: common.c:35
WHERE struct Regex * C_QuoteRegex
Config: Regex to match quoted text in a reply.
Definition: globals.h:177

+ 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) || IS_HEADER(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)) // Escape: 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:127
MIME attachments text (entire line)
Definition: mutt_curses.h:138
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:126
struct ColorLineHead ColorBodyList
List of colours applied to the email body.
Definition: color.c:55
Message headers (takes a pattern)
Definition: mutt_curses.h:136
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:669
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:131
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:121
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:192
struct Syntax * syntax
Definition: pager.c:180
#define IS_HEADER(x)
Definition: pager.c:97
struct ColorLineHead ColorHdrList
List of colours applied to the email headers.
Definition: color.c:56
#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:168
regex_t regex
Definition: mutt_curses.h:182
Header default colour.
Definition: mutt_curses.h:125
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:618
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:180
struct ColorLineHead ColorAttachList
List of colours applied to the attachment headers.
Definition: color.c:54

+ 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
void mutt_free_color(uint32_t fg, uint32_t bg)
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
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] = NULL;
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)) // Ctrl-H (backspace)
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)) // Escape
1334  {
1335  while (*p++ != 'm') /* skip ANSI sequence */
1336  ;
1337  }
1338  else if ((*p == '\033') && (*(p + 1) == ']') && // Escape
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:657
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:121
#define MUTT_EOL
don&#39;t strip \n / \r\n
Definition: file.h:38
#define mutt_debug(LEVEL,...)
Definition: logging.h:80
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] == '[') && // Escape
1392  is_ansi(buf + ch + 2))
1393  ch = grok_ansi(buf, ch + 2, pa) + 1;
1394 
1395  while ((cnt - ch >= 2) && (buf[ch] == '\033') && (buf[ch + 1] == ']') && // Escape
1396  ((check_attachment_marker((char *) buf + ch) == 0) ||
1397  (check_protected_header_marker((char *) buf + ch) == 0)))
1398  {
1399  while (buf[ch++] != '\a')
1400  if (ch >= cnt)
1401  break;
1402  }
1403 
1404  /* is anything left to do? */
1405  if (ch >= cnt)
1406  break;
1407 
1408  k = mbrtowc(&wc, (char *) buf + ch, cnt - ch, &mbstate);
1409  if ((k == (size_t)(-2)) || (k == (size_t)(-1)))
1410  {
1411  if (k == (size_t)(-1))
1412  memset(&mbstate, 0, sizeof(mbstate));
1413  mutt_debug(LL_DEBUG1, "mbrtowc returned %lu; errno = %d\n", k, errno);
1414  if (col + 4 > wrap_cols)
1415  break;
1416  col += 4;
1417  if (pa)
1418  printw("\\%03o", buf[ch]);
1419  k = 1;
1420  continue;
1421  }
1422  if (k == 0)
1423  k = 1;
1424 
1425  if (CharsetIsUtf8)
1426  {
1427  /* zero width space, zero width no-break space */
1428  if ((wc == 0x200B) || (wc == 0xFEFF))
1429  {
1430  mutt_debug(LL_DEBUG3, "skip zero-width character U+%04X\n", (unsigned short) wc);
1431  continue;
1432  }
1434  {
1435  mutt_debug(LL_DEBUG3, "filtered U+%04X\n", (unsigned short) wc);
1436  continue;
1437  }
1438  }
1439 
1440  /* Handle backspace */
1441  special = 0;
1442  if (IsWPrint(wc))
1443  {
1444  wchar_t wc1;
1445  mbstate_t mbstate1 = mbstate;
1446  size_t k1 = mbrtowc(&wc1, (char *) buf + ch + k, cnt - ch - k, &mbstate1);
1447  while ((k1 != (size_t)(-2)) && (k1 != (size_t)(-1)) && (k1 > 0) && (wc1 == '\b'))
1448  {
1449  const size_t k2 =
1450  mbrtowc(&wc1, (char *) buf + ch + k + k1, cnt - ch - k - k1, &mbstate1);
1451  if ((k2 == (size_t)(-2)) || (k2 == (size_t)(-1)) || (k2 == 0) || (!IsWPrint(wc1)))
1452  break;
1453 
1454  if (wc == wc1)
1455  {
1456  special |= ((wc == '_') && (special & A_UNDERLINE)) ? A_UNDERLINE : A_BOLD;
1457  }
1458  else if ((wc == '_') || (wc1 == '_'))
1459  {
1460  special |= A_UNDERLINE;
1461  wc = (wc1 == '_') ? wc : wc1;
1462  }
1463  else
1464  {
1465  /* special = 0; / * overstrike: nothing to do! */
1466  wc = wc1;
1467  }
1468 
1469  ch += k + k1;
1470  k = k2;
1471  mbstate = mbstate1;
1472  k1 = mbrtowc(&wc1, (char *) buf + ch + k, cnt - ch - k, &mbstate1);
1473  }
1474  }
1475 
1476  if (pa && ((flags & (MUTT_SHOWCOLOR | MUTT_SEARCH | MUTT_PAGER_MARKER)) ||
1477  special || last_special || pa->attr))
1478  {
1479  resolve_color(*line_info, n, vch, flags, special, pa);
1480  last_special = special;
1481  }
1482 
1483  /* no-break space, narrow no-break space */
1484  if (IsWPrint(wc) || (CharsetIsUtf8 && ((wc == 0x00A0) || (wc == 0x202F))))
1485  {
1486  if (wc == ' ')
1487  {
1488  space = ch;
1489  }
1490  t = wcwidth(wc);
1491  if (col + t > wrap_cols)
1492  break;
1493  col += t;
1494  if (pa)
1495  mutt_addwch(wc);
1496  }
1497  else if (wc == '\n')
1498  break;
1499  else if (wc == '\t')
1500  {
1501  space = ch;
1502  t = (col & ~7) + 8;
1503  if (t > wrap_cols)
1504  break;
1505  if (pa)
1506  for (; col < t; col++)
1507  addch(' ');
1508  else
1509  col = t;
1510  }
1511  else if ((wc < 0x20) || (wc == 0x7f))
1512  {
1513  if (col + 2 > wrap_cols)
1514  break;
1515  col += 2;
1516  if (pa)
1517  printw("^%c", ('@' + wc) & 0x7f);
1518  }
1519  else if (wc < 0x100)
1520  {
1521  if (col + 4 > wrap_cols)
1522  break;
1523  col += 4;
1524  if (pa)
1525  printw("\\%03o", wc);
1526  }
1527  else
1528  {
1529  if (col + 1 > wrap_cols)
1530  break;
1531  col += k;
1532  if (pa)
1533  addch(ReplacementChar);
1534  }
1535  }
1536  *pspace = space;
1537  *pcol = col;
1538  *pvch = vch;
1539  *pspecial = special;
1540  return ch;
1541 }
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:390
#define IsWPrint(wc)
Definition: mbyte.h:39
#define MUTT_SHOWCOLOR
Show characters in color otherwise don&#39;t show characters.
Definition: pager.h:45
WHERE short C_Wrap
Config: Width to wrap text in the pager.
Definition: globals.h:151
#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:80
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:239
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:939
int mutt_window_wrap_cols(struct MuttWindow *win, short wrap)
Calculate the wrap column for a Window.
Definition: mutt_window.c:324

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

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

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

+ Here is the caller graph for this function:

void mutt_clear_pager_position ( void  )

Reset the pager's viewing position.

Definition at line 1877 of file pager.c.

1878 {
1879  TopLine = 0;
1880  OldHdr = NULL;
1881 }
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 1925 of file pager.c.

1926 {
1927  struct PagerRedrawData *rd = pager_menu->redraw_data;
1928  char buf[1024];
1929 
1930  if (!rd)
1931  return;
1932 
1933  if (pager_menu->redraw & REDRAW_FULL)
1934  {
1936  NORMAL_COLOR;
1937  /* clear() doesn't optimize screen redraws */
1938  move(0, 0);
1939  clrtobot();
1940 
1941  if (IsEmail(rd->extra) && Context && ((Context->mailbox->vcount + 1) < C_PagerIndexLines))
1942  rd->indexlen = Context->mailbox->vcount + 1;
1943  else
1945 
1946  rd->indicator = rd->indexlen / 3;
1947 
1948  memcpy(rd->pager_window, MuttIndexWindow, sizeof(struct MuttWindow));
1949  memcpy(rd->pager_status_window, MuttStatusWindow, sizeof(struct MuttWindow));
1950  rd->index_status_window->rows = 0;
1951  rd->index_window->rows = 0;
1952 
1953  if (IsEmail(rd->extra) && C_PagerIndexLines)
1954  {
1955  memcpy(rd->index_window, MuttIndexWindow, sizeof(struct MuttWindow));
1956  rd->index_window->rows = (rd->indexlen > 0) ? rd->indexlen - 1 : 0;
1957 
1958  if (C_StatusOnTop)
1959  {
1960  memcpy(rd->index_status_window, MuttStatusWindow, sizeof(struct MuttWindow));
1961 
1962  memcpy(rd->pager_status_window, MuttIndexWindow, sizeof(struct MuttWindow));
1963  rd->pager_status_window->rows = 1;
1965 
1966  rd->pager_window->rows -=
1968  rd->pager_window->row_offset +=
1970  }
1971  else
1972  {
1973  memcpy(rd->index_status_window, MuttIndexWindow, sizeof(struct MuttWindow));
1974  rd->index_status_window->rows = 1;
1976 
1977  rd->pager_window->rows -=
1979  rd->pager_window->row_offset +=
1981  }
1982  }
1983 
1984  if (C_Help)
1985  {
1989  NORMAL_COLOR;
1990  }
1991 
1992  if (Resize)
1993  {
1995  if (rd->search_compiled)
1996  {
1997  int flags = mutt_mb_is_lower(rd->searchbuf) ? REG_ICASE : 0;
1998  const int err = REG_COMP(&rd->search_re, rd->searchbuf, REG_NEWLINE | flags);
1999  if (err != 0)
2000  {
2001  regerror(err, &rd->search_re, buf, sizeof(buf));
2002  mutt_error("%s", buf);
2003  rd->search_compiled = false;
2004  }
2005  else
2006  {
2007  rd->search_flag = MUTT_SEARCH;
2009  }
2010  }
2011  rd->lines = Resize->line;
2012  pager_menu->redraw |= REDRAW_FLOW;
2013 
2014  FREE(&Resize);
2015  }
2016 
2017  if (IsEmail(rd->extra) && C_PagerIndexLines)
2018  {
2019  if (!rd->index)
2020  {
2021  /* only allocate the space if/when we need the index.
2022  * Initialise the menu as per the main index */
2023  rd->index = mutt_menu_new(MENU_MAIN);
2025  rd->index->menu_color = index_color;
2026  rd->index->max = Context ? Context->mailbox->vcount : 0;
2027  rd->index->current = rd->extra->email->virtual;
2028  rd->index->indexwin = rd->index_window;
2029  rd->index->statuswin = rd->index_status_window;
2030  }
2031 
2032  NORMAL_COLOR;
2033  rd->index->pagelen = rd->index_window->rows;
2034 
2035  /* some fudge to work out whereabouts the indicator should go */
2036  if (rd->index->current - rd->indicator < 0)
2037  rd->index->top = 0;
2038  else if (rd->index->max - rd->index->current < rd->index->pagelen - rd->indicator)
2039  rd->index->top = rd->index->max - rd->index->pagelen;
2040  else
2041  rd->index->top = rd->index->current - rd->indicator;
2042 
2043  menu_redraw_index(rd->index);
2044  }
2045 
2046  pager_menu->redraw |= REDRAW_BODY | REDRAW_INDEX | REDRAW_STATUS;
2047 #ifdef USE_SIDEBAR
2048  pager_menu->redraw |= REDRAW_SIDEBAR;
2049 #endif
2050  mutt_show_error();
2051  }
2052 
2053  if (pager_menu->redraw & REDRAW_FLOW)
2054  {
2055  if (!(rd->flags & MUTT_PAGER_RETWINCH))
2056  {
2057  rd->lines = -1;
2058  for (int i = 0; i <= rd->topline; i++)
2059  if (!rd->line_info[i].continuation)
2060  rd->lines++;
2061  for (int i = 0; i < rd->max_line; i++)
2062  {
2063  rd->line_info[i].offset = 0;
2064  rd->line_info[i].type = -1;
2065  rd->line_info[i].continuation = 0;
2066  rd->line_info[i].chunks = 0;
2067  rd->line_info[i].search_cnt = -1;
2068  rd->line_info[i].quote = NULL;
2069 
2070  mutt_mem_realloc(&(rd->line_info[i].syntax), sizeof(struct Syntax));
2071  if (rd->search_compiled && rd->line_info[i].search)
2072  FREE(&(rd->line_info[i].search));
2073  }
2074 
2075  rd->last_line = 0;
2076  rd->topline = 0;
2077  }
2078  int i = -1;
2079  int j = -1;
2080  while (display_line(rd->fp, &rd->last_pos, &rd->line_info, ++i, &rd->last_line,
2081  &rd->max_line, rd->has_types | rd->search_flag | (rd->flags & MUTT_PAGER_NOWRAP),
2082  &rd->quote_list, &rd->q_level, &rd->force_redraw,
2083  &rd->search_re, rd->pager_window) == 0)
2084  {
2085  if (!rd->line_info[i].continuation && (++j == rd->lines))
2086  {
2087  rd->topline = i;
2088  if (!rd->search_flag)
2089  break;
2090  }
2091  }
2092  }
2093 
2094 #ifdef USE_SIDEBAR
2095  if (pager_menu->redraw & REDRAW_SIDEBAR)
2096  {
2097  menu_redraw_sidebar(pager_menu);
2098  }
2099 #endif
2100 
2101  if ((pager_menu->redraw & REDRAW_BODY) || (rd->topline != rd->oldtopline))
2102  {
2103  do
2104  {
2105  mutt_window_move(rd->pager_window, 0, 0);
2106  rd->curline = rd->topline;
2107  rd->oldtopline = rd->topline;
2108  rd->lines = 0;
2109  rd->force_redraw = false;
2110 
2111  while ((rd->lines < rd->pager_window->rows) &&
2112  (rd->line_info[rd->curline].offset <= rd->sb.st_size - 1))
2113  {
2114  if (display_line(rd->fp, &rd->last_pos, &rd->line_info, rd->curline,
2115  &rd->last_line, &rd->max_line,
2116  (rd->flags & MUTT_DISPLAYFLAGS) | rd->hide_quoted |
2117  rd->search_flag | (rd->flags & MUTT_PAGER_NOWRAP),
2118  &rd->quote_list, &rd->q_level, &rd->force_redraw,
2119  &rd->search_re, rd->pager_window) > 0)
2120  {
2121  rd->lines++;
2122  }
2123  rd->curline++;
2124  mutt_window_move(rd->pager_window, rd->lines, 0);
2125  }
2126  rd->last_offset = rd->line_info[rd->curline].offset;
2127  } while (rd->force_redraw);
2128 
2130  while (rd->lines < rd->pager_window->rows)
2131  {
2133  if (C_Tilde)
2134  addch('~');
2135  rd->lines++;
2136  mutt_window_move(rd->pager_window, rd->lines, 0);
2137  }
2138  NORMAL_COLOR;
2139 
2140  /* We are going to update the pager status bar, so it isn't
2141  * necessary to reset to normal color now. */
2142 
2143  pager_menu->redraw |= REDRAW_STATUS; /* need to update the % seen */
2144  }
2145 
2146  if (pager_menu->redraw & REDRAW_STATUS)
2147  {
2148  struct HdrFormatInfo hfi;
2149  char pager_progress_str[65]; /* Lots of space for translations */
2150 
2151  hfi.ctx = Context;
2152  hfi.mailbox = Context ? Context->mailbox : NULL;
2153  hfi.pager_progress = pager_progress_str;
2154 
2155  if (rd->last_pos < rd->sb.st_size - 1)
2156  {
2157  snprintf(pager_progress_str, sizeof(pager_progress_str), OFF_T_FMT "%%",
2158  (100 * rd->last_offset / rd->sb.st_size));
2159  }
2160  else
2161  {
2162  const char *msg = (rd->topline == 0) ?
2163  /* L10N: Status bar message: the entire email is visible in the pager */
2164  _("all") :
2165  /* L10N: Status bar message: the end of the email is visible in the pager */
2166  _("end");
2167  mutt_str_strfcpy(pager_progress_str, msg, sizeof(pager_progress_str));
2168  }
2169 
2170  /* print out the pager status bar */
2173 
2174  if (IsEmail(rd->extra) || IsMsgAttach(rd->extra))
2175  {
2176  size_t l1 = rd->pager_status_window->cols * MB_LEN_MAX;
2177  size_t l2 = sizeof(buf);
2178  hfi.email = (IsEmail(rd->extra)) ? rd->extra->email : rd->extra->body->email;
2179  mutt_make_string_info(buf, (l1 < l2) ? l1 : l2, rd->pager_status_window->cols,
2182  }
2183  else
2184  {
2185  char bn[256];
2186  snprintf(bn, sizeof(bn), "%s (%s)", rd->banner, pager_progress_str);
2187  mutt_draw_statusline(rd->pager_status_window->cols, bn, sizeof(bn));
2188  }
2189  NORMAL_COLOR;
2190  if (C_TsEnabled && TsSupported && rd->index)
2191  {
2192  menu_status_line(buf, sizeof(buf), rd->index, NONULL(C_TsStatusFormat));
2193  mutt_ts_status(buf);
2194  menu_status_line(buf, sizeof(buf), rd->index, NONULL(C_TsIconFormat));
2195  mutt_ts_icon(buf);
2196  }
2197  }
2198 
2199  if ((pager_menu->redraw & REDRAW_INDEX) && rd->index)
2200  {
2201  /* redraw the pager_index indicator, because the
2202  * flags for this message might have changed. */
2203  if (rd->index_window->rows > 0)
2205 
2206  /* print out the index status bar */
2207  menu_status_line(buf, sizeof(buf), rd->index, NONULL(C_StatusFormat));
2208 
2211  mutt_draw_statusline(rd->index_status_window->cols, buf, sizeof(buf));
2212  NORMAL_COLOR;
2213  }
2214 
2215  pager_menu->redraw = 0;
2216 }
struct Context * ctx
Definition: hdrline.h:45
The "current" mailbox.
Definition: context.h:38
WHERE bool C_StatusOnTop
Config: Display the status bar at the top.
Definition: globals.h:253
WHERE char * C_TsIconFormat
Config: printf-like format string for the terminal&#39;s icon title.
Definition: globals.h:145
#define REDRAW_FULL
Redraw everything.
Definition: mutt_menu.h:47
#define NONULL(x)
Definition: string2.h:36
const char * banner
Definition: pager.c:1914
PagerFlags hide_quoted
Definition: pager.c:1900
struct MuttWindow * MuttStatusWindow
Status Window.
Definition: mutt_window.c:40
PagerFlags search_flag
Definition: pager.c:1912
#define MUTT_DISPLAYFLAGS
Definition: pager.h:60
short chunks
Definition: pager.c:178
Keep track when the pager needs redrawing.
Definition: pager.c:1886
#define NORMAL_COLOR
Definition: mutt_curses.h:239
Pager: empty lines after message.
Definition: mutt_curses.h:133
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:1907
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:218
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:737
#define IsMsgAttach(pager)
Definition: pager.c:100
#define _(a)
Definition: message.h:28
const char * helpstr
Definition: pager.c:1915
struct Line * line_info
Definition: pager.c:1917
int index_color(int line)
Calculate the colour for a line of the index - Implements Menu::menu_color()
Definition: index.c:810
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:1888
Index panel (list of emails)
Definition: keymap.h:76
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:143
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:256
void(* menu_make_entry)(char *buf, size_t buflen, struct Menu *menu, int line)
Format a item for a menu.
Definition: mutt_menu.h:122
#define MUTT_FORMAT_NO_FLAGS
No flags are set.
Definition: format_flags.h:30
int vcount
the number of virtual messages
Definition: mailbox.h:102
#define REDRAW_SIDEBAR
Redraw the sidebar.
Definition: mutt_menu.h:51
void mutt_paddstr(int n, const char *s)
Display a string on screen, padded if necessary.
Definition: curs_lib.c:1146
LOFF_T last_pos
Definition: pager.c:1903
struct MuttWindow * index_status_window
Definition: pager.c:1905
int line
Definition: pager.c:215
void * redraw_data
Definition: mutt_menu.h:152
struct Mailbox * mailbox
Definition: context.h:52
Data passed to index_format_str()
Definition: hdrline.h:43
LOFF_T last_offset
Definition: pager.c:1904
FILE * fp
Definition: pager.c:1918
#define REG_COMP(preg, regex, cflags)
Compile a regular expression.
Definition: regex3.h:52
short continuation
Definition: pager.c:177
bool force_redraw
Definition: pager.c:1898
void mutt_window_reflow(void)
Resize the Windows to fit the screen.
Definition: mutt_window.c:237
void mutt_mem_realloc(void *ptr, size_t size)
Resize a block of memory on the heap.
Definition: memory.c:121
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:1514
int oldtopline
Definition: pager.c:1892
struct Pager * extra
Definition: pager.c:1889
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:1911
struct Syntax * syntax
Definition: pager.c:180
struct MuttWindow * MuttIndexWindow
Index Window.
Definition: mutt_window.c:39
struct MuttWindow * pager_window
Definition: pager.c:1908
struct MuttWindow * indexwin
Definition: mutt_menu.h:95
struct MuttWindow * index_window
Definition: pager.c:1906
int top
entry that is the top of the current page
Definition: mutt_menu.h:110
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:753
int pagelen
number of entries per screen
Definition: mutt_menu.h:92
bool TsSupported
Terminal Setting is supported.
Definition: terminal.c:43
#define SET_COLOR(X)
Definition: mutt_curses.h:224
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:144
int(* menu_color)(int line)
Calculate the colour for a line of the menu.
Definition: mutt_menu.h:146
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:1909
struct QClass * quote_list
Definition: pager.c:1902
#define IsEmail(pager)
Definition: pager.c:102
int indicator
the indicator line of the PI
Definition: pager.c:1891
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:1916
#define REDRAW_INDEX
Redraw the index.
Definition: mutt_menu.h:42
#define mutt_error(...)
Definition: logging.h:83
int row_offset
Definition: mutt_window.h:37
#define FREE(x)
Definition: memory.h:40
Status bar.
Definition: mutt_curses.h:129
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:485
Keep track of screen resizing.
Definition: pager.c:213
void mutt_ts_status(char *str)
Set the text of the terminal title bar.
Definition: terminal.c:104
struct stat sb
Definition: pager.c:1919
int current
current entry
Definition: mutt_menu.h:87
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:358
struct Email * email
header information for message/rfc822
Definition: body.h:62
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:1561
void mutt_draw_statusline(int cols, const char *buf, size_t buflen)
Draw a highlighted status bar.
Definition: index.c:839
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:131
regex_t search_re
Definition: pager.c:1910
bool search_back
Definition: pager.c:1913

+ 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 "email" is NULL. The "email" arg is there so that we can do operations on the current message without the need to pop back out to the main-menu.

Definition at line 2233 of file pager.c.

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

+ 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 1849 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 1856 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 1865 of file pager.c.