NeoMutt  2018-07-16 +2225-8687db
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 "core/lib.h"
#include "curs_lib.h"
#include "format_flags.h"
#include "globals.h"
#include "hdrline.h"
#include "hook.h"
#include "index.h"
#include "keymap.h"
#include "mutt_attach.h"
#include "mutt_curses.h"
#include "mutt_header.h"
#include "mutt_logging.h"
#include "mutt_mailbox.h"
#include "mutt_menu.h"
#include "mutt_window.h"
#include "muttlib.h"
#include "mx.h"
#include "ncrypt/ncrypt.h"
#include "opcodes.h"
#include "options.h"
#include "protos.h"
#include "recvattach.h"
#include "recvcmd.h"
#include "send.h"
#include "status.h"
#include "terminal.h"
#include "sidebar.h"
#include "nntp/nntp.h"
#include <libintl.h>

Go to the source code of this file.

Data Structures

struct  QClass
 Style of quoted text. More...
 
struct  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 *qc, int *q_level)
 Create a new quoting colour. More...
 
static void shift_class_colors (struct QClass *quote_list, struct QClass *new_class, int index, int *q_level)
 Insert a new quote colour class into a list. More...
 
static void cleanup_quote (struct QClass **quote_list)
 Free a quote list. More...
 
static struct QClassclassify_quote (struct QClass **quote_list, const char *qptr, size_t length, bool *force_redraw, int *q_level)
 Find a style for a string. More...
 
static int check_marker (const char *q, const char *p)
 Check that the unique marker is present. More...
 
static int check_attachment_marker (const char *p)
 Check that the unique marker is present. More...
 
static int check_protected_header_marker (const char *p)
 Check that the unique marker is present. More...
 
int mutt_is_quote_line (char *line, regmatch_t *pmatch)
 Is a line of message text a quote? More...
 
static void resolve_types (char *buf, char *raw, struct Line *line_info, int n, int last, struct QClass **quote_list, int *q_level, bool *force_redraw, bool q_classify)
 Determine the style for a line of text. More...
 
static bool is_ansi (unsigned char *buf)
 Is this an ANSI escape sequence? More...
 
static int grok_ansi (unsigned char *buf, int pos, struct AnsiAttr *a)
 Parse an ANSI escape sequence. More...
 
static int fill_buffer (FILE *fp, LOFF_T *last_pos, LOFF_T offset, unsigned char **buf, unsigned char **fmt, size_t *blen, int *buf_ready)
 Fill a buffer from a file. More...
 
static int format_line (struct Line **line_info, int n, unsigned char *buf, PagerFlags flags, struct AnsiAttr *pa, int cnt, int *pspace, int *pvch, int *pcol, int *pspecial, 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 EmailOldEmail = 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 98 of file pager.c.

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

Definition at line 100 of file pager.c.

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

Definition at line 101 of file pager.c.

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

Definition at line 103 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:800
#define _(a)
Definition: message.h:28
static const char * Not_available_in_this_menu
Definition: pager.c:105
static struct UrlTest test[]
Definition: url_parse.c:40
#define mutt_error(...)
Definition: logging.h:84

Definition at line 115 of file pager.c.

#define CHECK_READONLY
Value:
{ \
break; \
}
The "current" mailbox.
Definition: context.h:39
void mutt_flushinp(void)
Empty all the keyboard buffers.
Definition: curs_lib.c:800
#define _(a)
Definition: message.h:28
struct Mailbox * mailbox
Definition: context.h:53
bool readonly
Don&#39;t allow changes to the mailbox.
Definition: mailbox.h:131
static const char * Mailbox_is_read_only
Definition: pager.c:107
#define mutt_error(...)
Definition: logging.h:84

Definition at line 123 of file pager.c.

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

Definition at line 131 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:39
void mutt_flushinp(void)
Empty all the keyboard buffers.
Definition: curs_lib.c:800
#define _(a)
Definition: message.h:28
struct Mailbox * mailbox
Definition: context.h:53
AclFlags rights
ACL bits, see AclFlags.
Definition: mailbox.h:133
#define mutt_error(...)
Definition: logging.h:84

Definition at line 139 of file pager.c.

#define ANSI_NO_FLAGS   0

No flags are set.

Definition at line 189 of file pager.c.

#define ANSI_OFF   (1 << 0)

Turn off colours and attributes.

Definition at line 190 of file pager.c.

#define ANSI_BLINK   (1 << 1)

Blinking text.

Definition at line 191 of file pager.c.

#define ANSI_BOLD   (1 << 2)

Bold text.

Definition at line 192 of file pager.c.

#define ANSI_UNDERLINE   (1 << 3)

Underlined text.

Definition at line 193 of file pager.c.

#define ANSI_REVERSE   (1 << 4)

Reverse video.

Definition at line 194 of file pager.c.

#define ANSI_COLOR   (1 << 5)

Use colours.

Definition at line 195 of file pager.c.

#define NUM_SIG_LINES   4

Definition at line 221 of file pager.c.

Typedef Documentation

typedef uint8_t AnsiFlags

Flags, e.g. ANSI_OFF.

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

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

271 {
272  const int *cnt = (const int *) m1;
273  const struct Syntax *stx = (const struct Syntax *) m2;
274 
275  if (*cnt < stx->first)
276  return -1;
277  if (*cnt >= stx->last)
278  return 1;
279  return 0;
280 }
int first
Definition: pager.c:167
int last
Definition: pager.c:168
Highlighting for a line of text.
Definition: pager.c:164
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 291 of file pager.c.

293 {
294  int def_color; /* color without syntax highlight */
295  int color; /* final color */
296  static int last_color; /* last color set */
297  bool search = false;
298  int m;
299  struct Syntax *matching_chunk = NULL;
300 
301  if (cnt == 0)
302  last_color = -1; /* force attrset() */
303 
304  if (line_info[n].continuation)
305  {
306  if (!cnt && C_Markers)
307  {
309  addch('+');
310  last_color = ColorDefs[MT_COLOR_MARKERS];
311  }
312  m = (line_info[n].syntax)[0].first;
313  cnt += (line_info[n].syntax)[0].last;
314  }
315  else
316  m = n;
317  if (flags & MUTT_PAGER_LOGS)
318  {
319  def_color = ColorDefs[(line_info[n].syntax)[0].color];
320  }
321  else if (!(flags & MUTT_SHOWCOLOR))
322  def_color = ColorDefs[MT_COLOR_NORMAL];
323  else if (line_info[m].type == MT_COLOR_HEADER)
324  def_color = (line_info[m].syntax)[0].color;
325  else
326  def_color = ColorDefs[line_info[m].type];
327 
328  if ((flags & MUTT_SHOWCOLOR) && (line_info[m].type == MT_COLOR_QUOTED))
329  {
330  struct QClass *qc = line_info[m].quote;
331 
332  if (qc)
333  {
334  def_color = qc->color;
335 
336  while (qc && (qc->length > cnt))
337  {
338  def_color = qc->color;
339  qc = qc->up;
340  }
341  }
342  }
343 
344  color = def_color;
345  if ((flags & MUTT_SHOWCOLOR) && line_info[m].chunks)
346  {
347  matching_chunk = bsearch(&cnt, line_info[m].syntax, line_info[m].chunks,
348  sizeof(struct Syntax), comp_syntax_t);
349  if (matching_chunk && (cnt >= matching_chunk->first) &&
350  (cnt < matching_chunk->last))
351  {
352  color = matching_chunk->color;
353  }
354  }
355 
356  if ((flags & MUTT_SEARCH) && line_info[m].search_cnt)
357  {
358  matching_chunk = bsearch(&cnt, line_info[m].search, line_info[m].search_cnt,
359  sizeof(struct Syntax), comp_syntax_t);
360  if (matching_chunk && (cnt >= matching_chunk->first) &&
361  (cnt < matching_chunk->last))
362  {
363  color = ColorDefs[MT_COLOR_SEARCH];
364  search = 1;
365  }
366  }
367 
368  /* handle "special" bold & underlined characters */
369  if (special || a->attr)
370  {
371 #ifdef HAVE_COLOR
372  if ((a->attr & ANSI_COLOR))
373  {
374  if (a->pair == -1)
375  a->pair = mutt_alloc_color(a->fg, a->bg);
376  color = a->pair;
377  if (a->attr & ANSI_BOLD)
378  color |= A_BOLD;
379  }
380  else
381 #endif
382  if ((special & A_BOLD) || (a->attr & ANSI_BOLD))
383  {
384  if (ColorDefs[MT_COLOR_BOLD] && !search)
385  color = ColorDefs[MT_COLOR_BOLD];
386  else
387  color ^= A_BOLD;
388  }
389  if ((special & A_UNDERLINE) || (a->attr & ANSI_UNDERLINE))
390  {
391  if (ColorDefs[MT_COLOR_UNDERLINE] && !search)
392  color = ColorDefs[MT_COLOR_UNDERLINE];
393  else
394  color ^= A_UNDERLINE;
395  }
396  else if (a->attr & ANSI_REVERSE)
397  {
398  color ^= A_REVERSE;
399  }
400  else if (a->attr & ANSI_BLINK)
401  {
402  color ^= A_BLINK;
403  }
404  else if (a->attr == ANSI_OFF)
405  {
406  a->attr = 0;
407  }
408  }
409 
410  if (color != last_color)
411  {
412  ATTR_SET(color);
413  last_color = color;
414  }
415 }
int first
Definition: pager.c:167
#define ANSI_COLOR
Use colours.
Definition: pager.c:195
#define MUTT_SHOWCOLOR
Show characters in color otherwise don&#39;t show characters.
Definition: pager.h:45
size_t length
Definition: pager.c:153
int pair
Curses colour pair.
Definition: pager.c:206
Pager: quoted text.
Definition: mutt_curses.h:126
Bold text.
Definition: mutt_curses.h:141
int last
Definition: pager.c:168
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:164
Pager: markers, line continuation.
Definition: mutt_curses.h:134
short type
Definition: pager.c:177
int color
Definition: pager.c:166
#define ANSI_BOLD
Bold text.
Definition: pager.c:192
Plain text.
Definition: mutt_curses.h:131
AnsiFlags attr
Attributes, e.g. underline, bold, etc.
Definition: pager.c:203
static int comp_syntax_t(const void *m1, const void *m2)
Search for a Syntax using bsearch.
Definition: pager.c:270
#define ANSI_BLINK
Blinking text.
Definition: pager.c:191
Underlined text.
Definition: mutt_curses.h:142
#define ANSI_REVERSE
Reverse video.
Definition: pager.c:194
int bg
Background colour.
Definition: pager.c:205
struct Syntax * syntax
Definition: pager.c:181
#define ATTR_SET
Definition: mutt_curses.h:232
#define ANSI_UNDERLINE
Underlined text.
Definition: pager.c:193
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:204
#define MUTT_SEARCH
Resolve search patterns.
Definition: pager.h:47
int color
Definition: pager.c:155
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)
struct QClass * up
Definition: pager.c:158
Style of quoted text.
Definition: pager.c:151
#define ANSI_OFF
Turn off colours and attributes.
Definition: pager.c:190
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 423 of file pager.c.

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

Create a new quoting colour.

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

Definition at line 446 of file pager.c.

447 {
448  qc->index = (*q_level)++;
449  qc->color = ColorQuote[qc->index % ColorQuoteUsed];
450 }
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
int color
Definition: pager.c:155
int index
Definition: pager.c:154
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 459 of file pager.c.

461 {
462  struct QClass *q_list = quote_list;
463  new_class->index = -1;
464 
465  while (q_list)
466  {
467  if (q_list->index >= index)
468  {
469  q_list->index++;
470  q_list->color = ColorQuote[q_list->index % ColorQuoteUsed];
471  }
472  if (q_list->down)
473  q_list = q_list->down;
474  else if (q_list->next)
475  q_list = q_list->next;
476  else
477  {
478  while (!q_list->next)
479  {
480  q_list = q_list->up;
481  if (!q_list)
482  break;
483  }
484  if (q_list)
485  q_list = q_list->next;
486  }
487  }
488 
489  new_class->index = index;
490  new_class->color = ColorQuote[index % ColorQuoteUsed];
491  (*q_level)++;
492 }
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:158
struct QClass * next
Definition: pager.c:157
int color
Definition: pager.c:155
int index
Definition: pager.c:154
struct QClass * up
Definition: pager.c:158
Style of quoted text.
Definition: pager.c:151
static void cleanup_quote ( struct QClass **  quote_list)
static

Free a quote list.

Parameters
[out]quote_listQuote list to free

Definition at line 498 of file pager.c.

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

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

839 {
840  for (; (p[0] == q[0]) && (q[0] != '\0') && (p[0] != '\0') && (q[0] != '\a') &&
841  (p[0] != '\a');
842  p++, q++)
843  {
844  }
845 
846  return (int) (*p - *q);
847 }
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 854 of file pager.c.

855 {
856  return check_marker(AttachmentMarker, p);
857 }
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:838
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 864 of file pager.c.

865 {
867 }
static int check_marker(const char *q, const char *p)
Check that the unique marker is present.
Definition: pager.c:838
WHERE char ProtectedHeaderMarker[256]
Unique ANSI string to mark protected headers in an email.
Definition: globals.h:46
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 878 of file pager.c.

879 {
880  bool is_quote = false;
881  regmatch_t pmatch_internal[1], smatch[1];
882 
883  if (!pmatch)
884  pmatch = pmatch_internal;
885 
886  if (C_QuoteRegex && C_QuoteRegex->regex &&
887  (regexec(C_QuoteRegex->regex, line, 1, pmatch, 0) == 0))
888  {
889  if (C_Smileys && C_Smileys->regex &&
890  (regexec(C_Smileys->regex, line, 1, smatch, 0) == 0))
891  {
892  if (smatch[0].rm_so > 0)
893  {
894  char c = line[smatch[0].rm_so];
895  line[smatch[0].rm_so] = 0;
896 
897  if (regexec(C_QuoteRegex->regex, line, 1, pmatch, 0) == 0)
898  is_quote = true;
899 
900  line[smatch[0].rm_so] = c;
901  }
902  }
903  else
904  is_quote = true;
905  }
906 
907  return is_quote;
908 }
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:95
const char * line
Definition: common.c:36
WHERE struct Regex * C_QuoteRegex
Config: Regex to match quoted text in a reply.
Definition: globals.h:177
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 922 of file pager.c.

925 {
926  struct ColorLine *color_line = NULL;
927  struct ColorLineHead *head = NULL;
928  regmatch_t pmatch[1];
929  bool found;
930  bool null_rx;
931  int offset, i = 0;
932 
933  if ((n == 0) || IS_HEADER(line_info[n - 1].type) ||
934  (check_protected_header_marker(raw) == 0))
935  {
936  if (buf[0] == '\n') /* end of header */
937  {
938  line_info[n].type = MT_COLOR_NORMAL;
939  getyx(stdscr, braille_line, braille_col);
940  }
941  else
942  {
943  /* if this is a continuation of the previous line, use the previous
944  * line's color as default. */
945  if ((n > 0) && ((buf[0] == ' ') || (buf[0] == '\t')))
946  {
947  line_info[n].type = line_info[n - 1].type; /* wrapped line */
949  {
950  (line_info[n].syntax)[0].color = (line_info[n - 1].syntax)[0].color;
951  line_info[n].is_cont_hdr = 1;
952  }
953  }
954  else
955  {
956  line_info[n].type = MT_COLOR_HDEFAULT;
957  }
958 
959  /* When this option is unset, we color the entire header the
960  * same color. Otherwise, we handle the header patterns just
961  * like body patterns (further below). */
963  {
964  STAILQ_FOREACH(color_line, &ColorHdrList, entries)
965  {
966  if (regexec(&color_line->regex, buf, 0, NULL, 0) == 0)
967  {
968  line_info[n].type = MT_COLOR_HEADER;
969  line_info[n].syntax[0].color = color_line->pair;
970  if (line_info[n].is_cont_hdr)
971  {
972  /* adjust the previous continuation lines to reflect the color of this continuation line */
973  int j;
974  for (j = n - 1; j >= 0 && line_info[j].is_cont_hdr; --j)
975  {
976  line_info[j].type = line_info[n].type;
977  line_info[j].syntax[0].color = line_info[n].syntax[0].color;
978  }
979  /* now adjust the first line of this header field */
980  if (j >= 0)
981  {
982  line_info[j].type = line_info[n].type;
983  line_info[j].syntax[0].color = line_info[n].syntax[0].color;
984  }
985  *force_redraw = true; /* the previous lines have already been drawn on the screen */
986  }
987  break;
988  }
989  }
990  }
991  }
992  }
993  else if (mutt_str_startswith(raw, "\033[0m", CASE_MATCH)) // Escape: a little hack...
994  line_info[n].type = MT_COLOR_NORMAL;
995  else if (check_attachment_marker((char *) raw) == 0)
996  line_info[n].type = MT_COLOR_ATTACHMENT;
997  else if ((mutt_str_strcmp("-- \n", buf) == 0) || (mutt_str_strcmp("-- \r\n", buf) == 0))
998  {
999  i = n + 1;
1000 
1001  line_info[n].type = MT_COLOR_SIGNATURE;
1002  while ((i < last) && (check_sig(buf, line_info, i - 1) == 0) &&
1003  ((line_info[i].type == MT_COLOR_NORMAL) || (line_info[i].type == MT_COLOR_QUOTED) ||
1004  (line_info[i].type == MT_COLOR_HEADER)))
1005  {
1006  /* oops... */
1007  if (line_info[i].chunks)
1008  {
1009  line_info[i].chunks = 0;
1010  mutt_mem_realloc(&(line_info[n].syntax), sizeof(struct Syntax));
1011  }
1012  line_info[i++].type = MT_COLOR_SIGNATURE;
1013  }
1014  }
1015  else if (check_sig(buf, line_info, n - 1) == 0)
1016  line_info[n].type = MT_COLOR_SIGNATURE;
1017  else if (mutt_is_quote_line(buf, pmatch))
1018 
1019  {
1020  if (q_classify && (line_info[n].quote == NULL))
1021  {
1022  line_info[n].quote = classify_quote(quote_list, buf + pmatch[0].rm_so,
1023  pmatch[0].rm_eo - pmatch[0].rm_so,
1024  force_redraw, q_level);
1025  }
1026  line_info[n].type = MT_COLOR_QUOTED;
1027  }
1028  else
1029  line_info[n].type = MT_COLOR_NORMAL;
1030 
1031  /* body patterns */
1032  if ((line_info[n].type == MT_COLOR_NORMAL) || (line_info[n].type == MT_COLOR_QUOTED) ||
1033  ((line_info[n].type == MT_COLOR_HDEFAULT) && C_HeaderColorPartial))
1034  {
1035  size_t nl;
1036 
1037  /* don't consider line endings part of the buffer
1038  * for regex matching */
1039  nl = mutt_str_strlen(buf);
1040  if ((nl > 0) && (buf[nl - 1] == '\n'))
1041  buf[nl - 1] = '\0';
1042 
1043  i = 0;
1044  offset = 0;
1045  line_info[n].chunks = 0;
1046  if (line_info[n].type == MT_COLOR_HDEFAULT)
1047  head = &ColorHdrList;
1048  else
1049  head = &ColorBodyList;
1050  STAILQ_FOREACH(color_line, head, entries)
1051  {
1052  color_line->stop_matching = false;
1053  }
1054  do
1055  {
1056  if (!buf[offset])
1057  break;
1058 
1059  found = false;
1060  null_rx = false;
1061  STAILQ_FOREACH(color_line, head, entries)
1062  {
1063  if (!color_line->stop_matching &&
1064  (regexec(&color_line->regex, buf + offset, 1, pmatch,
1065  ((offset != 0) ? REG_NOTBOL : 0)) == 0))
1066  {
1067  if (pmatch[0].rm_eo != pmatch[0].rm_so)
1068  {
1069  if (!found)
1070  {
1071  /* Abort if we fill up chunks.
1072  * Yes, this really happened. See #3888 */
1073  if (line_info[n].chunks == SHRT_MAX)
1074  {
1075  null_rx = false;
1076  break;
1077  }
1078  if (++(line_info[n].chunks) > 1)
1079  {
1080  mutt_mem_realloc(&(line_info[n].syntax),
1081  (line_info[n].chunks) * sizeof(struct Syntax));
1082  }
1083  }
1084  i = line_info[n].chunks - 1;
1085  pmatch[0].rm_so += offset;
1086  pmatch[0].rm_eo += offset;
1087  if (!found || (pmatch[0].rm_so < (line_info[n].syntax)[i].first) ||
1088  ((pmatch[0].rm_so == (line_info[n].syntax)[i].first) &&
1089  (pmatch[0].rm_eo > (line_info[n].syntax)[i].last)))
1090  {
1091  (line_info[n].syntax)[i].color = color_line->pair;
1092  (line_info[n].syntax)[i].first = pmatch[0].rm_so;
1093  (line_info[n].syntax)[i].last = pmatch[0].rm_eo;
1094  }
1095  found = true;
1096  null_rx = false;
1097  }
1098  else
1099  null_rx = true; /* empty regex; don't add it, but keep looking */
1100  }
1101  else
1102  {
1103  /* Once a regexp fails to match, don't try matching it again.
1104  * On very long lines this can cause a performance issue if there
1105  * are other regexps that have many matches. */
1106  color_line->stop_matching = true;
1107  }
1108  }
1109 
1110  if (null_rx)
1111  offset++; /* avoid degenerate cases */
1112  else
1113  offset = (line_info[n].syntax)[i].last;
1114  } while (found || null_rx);
1115  if (nl > 0)
1116  buf[nl] = '\n';
1117  }
1118 
1119  /* attachment patterns */
1120  if (line_info[n].type == MT_COLOR_ATTACHMENT)
1121  {
1122  size_t nl;
1123 
1124  /* don't consider line endings part of the buffer for regex matching */
1125  nl = mutt_str_strlen(buf);
1126  if ((nl > 0) && (buf[nl - 1] == '\n'))
1127  buf[nl - 1] = '\0';
1128 
1129  i = 0;
1130  offset = 0;
1131  line_info[n].chunks = 0;
1132  do
1133  {
1134  if (!buf[offset])
1135  break;
1136 
1137  found = false;
1138  null_rx = false;
1139  STAILQ_FOREACH(color_line, &ColorAttachList, entries)
1140  {
1141  if (regexec(&color_line->regex, buf + offset, 1, pmatch,
1142  ((offset != 0) ? REG_NOTBOL : 0)) == 0)
1143  {
1144  if (pmatch[0].rm_eo != pmatch[0].rm_so)
1145  {
1146  if (!found)
1147  {
1148  if (++(line_info[n].chunks) > 1)
1149  {
1150  mutt_mem_realloc(&(line_info[n].syntax),
1151  (line_info[n].chunks) * sizeof(struct Syntax));
1152  }
1153  }
1154  i = line_info[n].chunks - 1;
1155  pmatch[0].rm_so += offset;
1156  pmatch[0].rm_eo += offset;
1157  if (!found || (pmatch[0].rm_so < (line_info[n].syntax)[i].first) ||
1158  ((pmatch[0].rm_so == (line_info[n].syntax)[i].first) &&
1159  (pmatch[0].rm_eo > (line_info[n].syntax)[i].last)))
1160  {
1161  (line_info[n].syntax)[i].color = color_line->pair;
1162  (line_info[n].syntax)[i].first = pmatch[0].rm_so;
1163  (line_info[n].syntax)[i].last = pmatch[0].rm_eo;
1164  }
1165  found = 1;
1166  null_rx = 0;
1167  }
1168  else
1169  null_rx = 1; /* empty regex; don't add it, but keep looking */
1170  }
1171  }
1172 
1173  if (null_rx)
1174  offset++; /* avoid degenerate cases */
1175  else
1176  offset = (line_info[n].syntax)[i].last;
1177  } while (found || null_rx);
1178  if (nl > 0)
1179  buf[nl] = '\n';
1180  }
1181 }
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:864
short chunks
Definition: pager.c:179
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:67
size_t mutt_str_strlen(const char *a)
Calculate the length of a string, safely.
Definition: string.c:666
Highlighting for a line of text.
Definition: pager.c:164
short type
Definition: pager.c:177
int color
Definition: pager.c:166
Plain text.
Definition: mutt_curses.h:131
static int braille_line
Definition: pager.c:829
void mutt_mem_realloc(void *ptr, size_t size)
Resize a block of memory on the heap.
Definition: memory.c:114
struct QClass * quote
Definition: pager.c:183
static int braille_col
Definition: pager.c:830
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:181
#define IS_HEADER(x)
Definition: pager.c:98
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:88
int mutt_is_quote_line(char *line, regmatch_t *pmatch)
Is a line of message text a quote?
Definition: pager.c:878
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:523
static int check_attachment_marker(const char *p)
Check that the unique marker is present.
Definition: pager.c:854
static int check_sig(const char *s, struct Line *info, int n)
Check for an email signature.
Definition: pager.c:231
int mutt_str_strcmp(const char *a, const char *b)
Compare two strings, safely.
Definition: string.c:615
unsigned int is_cont_hdr
this line is a continuation of the previous header line
Definition: pager.c:184
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
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 1188 of file pager.c.

1189 {
1190  while ((*buf != '\0') && (isdigit(*buf) || (*buf == ';')))
1191  buf++;
1192  return *buf == 'm';
1193 }
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 1202 of file pager.c.

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

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

1378 {
1379  int space = -1; /* index of the last space or TAB */
1380  int col = C_Markers ? (*line_info)[n].continuation : 0;
1381  size_t k;
1382  int ch, vch, last_special = -1, special = 0, t;
1383  wchar_t wc;
1384  mbstate_t mbstate;
1385  int wrap_cols =
1386  mutt_window_wrap_cols(pager_window, (flags & MUTT_PAGER_NOWRAP) ? 0 : C_Wrap);
1387 
1388  if (check_attachment_marker((char *) buf) == 0)
1389  wrap_cols = pager_window->cols;
1390 
1391  /* FIXME: this should come from line_info */
1392  memset(&mbstate, 0, sizeof(mbstate));
1393 
1394  for (ch = 0, vch = 0; ch < cnt; ch += k, vch += k)
1395  {
1396  /* Handle ANSI sequences */
1397  while ((cnt - ch >= 2) && (buf[ch] == '\033') && (buf[ch + 1] == '[') && // Escape
1398  is_ansi(buf + ch + 2))
1399  ch = grok_ansi(buf, ch + 2, pa) + 1;
1400 
1401  while ((cnt - ch >= 2) && (buf[ch] == '\033') && (buf[ch + 1] == ']') && // Escape
1402  ((check_attachment_marker((char *) buf + ch) == 0) ||
1403  (check_protected_header_marker((char *) buf + ch) == 0)))
1404  {
1405  while (buf[ch++] != '\a')
1406  if (ch >= cnt)
1407  break;
1408  }
1409 
1410  /* is anything left to do? */
1411  if (ch >= cnt)
1412  break;
1413 
1414  k = mbrtowc(&wc, (char *) buf + ch, cnt - ch, &mbstate);
1415  if ((k == (size_t)(-2)) || (k == (size_t)(-1)))
1416  {
1417  if (k == (size_t)(-1))
1418  memset(&mbstate, 0, sizeof(mbstate));
1419  mutt_debug(LL_DEBUG1, "mbrtowc returned %lu; errno = %d\n", k, errno);
1420  if (col + 4 > wrap_cols)
1421  break;
1422  col += 4;
1423  if (pa)
1424  printw("\\%03o", buf[ch]);
1425  k = 1;
1426  continue;
1427  }
1428  if (k == 0)
1429  k = 1;
1430 
1431  if (CharsetIsUtf8)
1432  {
1433  /* zero width space, zero width no-break space */
1434  if ((wc == 0x200B) || (wc == 0xFEFF))
1435  {
1436  mutt_debug(LL_DEBUG3, "skip zero-width character U+%04X\n", (unsigned short) wc);
1437  continue;
1438  }
1440  {
1441  mutt_debug(LL_DEBUG3, "filtered U+%04X\n", (unsigned short) wc);
1442  continue;
1443  }
1444  }
1445 
1446  /* Handle backspace */
1447  special = 0;
1448  if (IsWPrint(wc))
1449  {
1450  wchar_t wc1;
1451  mbstate_t mbstate1 = mbstate;
1452  size_t k1 = mbrtowc(&wc1, (char *) buf + ch + k, cnt - ch - k, &mbstate1);
1453  while ((k1 != (size_t)(-2)) && (k1 != (size_t)(-1)) && (k1 > 0) && (wc1 == '\b'))
1454  {
1455  const size_t k2 =
1456  mbrtowc(&wc1, (char *) buf + ch + k + k1, cnt - ch - k - k1, &mbstate1);
1457  if ((k2 == (size_t)(-2)) || (k2 == (size_t)(-1)) || (k2 == 0) || (!IsWPrint(wc1)))
1458  break;
1459 
1460  if (wc == wc1)
1461  {
1462  special |= ((wc == '_') && (special & A_UNDERLINE)) ? A_UNDERLINE : A_BOLD;
1463  }
1464  else if ((wc == '_') || (wc1 == '_'))
1465  {
1466  special |= A_UNDERLINE;
1467  wc = (wc1 == '_') ? wc : wc1;
1468  }
1469  else
1470  {
1471  /* special = 0; / * overstrike: nothing to do! */
1472  wc = wc1;
1473  }
1474 
1475  ch += k + k1;
1476  k = k2;
1477  mbstate = mbstate1;
1478  k1 = mbrtowc(&wc1, (char *) buf + ch + k, cnt - ch - k, &mbstate1);
1479  }
1480  }
1481 
1482  if (pa && ((flags & (MUTT_SHOWCOLOR | MUTT_SEARCH | MUTT_PAGER_MARKER)) ||
1483  special || last_special || pa->attr))
1484  {
1485  resolve_color(*line_info, n, vch, flags, special, pa);
1486  last_special = special;
1487  }
1488 
1489  /* no-break space, narrow no-break space */
1490  if (IsWPrint(wc) || (CharsetIsUtf8 && ((wc == 0x00A0) || (wc == 0x202F))))
1491  {
1492  if (wc == ' ')
1493  {
1494  space = ch;
1495  }
1496  t = wcwidth(wc);
1497  if (col + t > wrap_cols)
1498  break;
1499  col += t;
1500  if (pa)
1501  mutt_addwch(wc);
1502  }
1503  else if (wc == '\n')
1504  break;
1505  else if (wc == '\t')
1506  {
1507  space = ch;
1508  t = (col & ~7) + 8;
1509  if (t > wrap_cols)
1510  break;
1511  if (pa)
1512  for (; col < t; col++)
1513  addch(' ');
1514  else
1515  col = t;
1516  }
1517  else if ((wc < 0x20) || (wc == 0x7f))
1518  {
1519  if (col + 2 > wrap_cols)
1520  break;
1521  col += 2;
1522  if (pa)
1523  printw("^%c", ('@' + wc) & 0x7f);
1524  }
1525  else if (wc < 0x100)
1526  {
1527  if (col + 4 > wrap_cols)
1528  break;
1529  col += 4;
1530  if (pa)
1531  printw("\\%03o", wc);
1532  }
1533  else
1534  {
1535  if (col + 1 > wrap_cols)
1536  break;
1537  col += k;
1538  if (pa)
1539  addch(ReplacementChar);
1540  }
1541  }
1542  *pspace = space;
1543  *pcol = col;
1544  *pvch = vch;
1545  *pspecial = special;
1546  return ch;
1547 }
static int check_protected_header_marker(const char *p)
Check that the unique marker is present.
Definition: pager.c:864
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:203
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:1202
Log at debug level 1.
Definition: logging.h:56
#define MUTT_PAGER_MARKER
Use markers if option is set.
Definition: pager.h:53
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
static bool is_ansi(unsigned char *buf)
Is this an ANSI escape sequence?
Definition: pager.c:1188
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:291
static int check_attachment_marker(const char *p)
Check that the unique marker is present.
Definition: pager.c:854
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:954
int mutt_window_wrap_cols(struct MuttWindow *win, short wrap)
Calculate the wrap column for a Window.
Definition: mutt_window.c:324
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 1567 of file pager.c.

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

1844 {
1845  while ((cur > 0) && (nlines > 0))
1846  {
1847  cur--;
1848  if (!hiding || (info[cur].type != MT_COLOR_QUOTED))
1849  nlines--;
1850  }
1851 
1852  return cur;
1853 }
Pager: quoted text.
Definition: mutt_curses.h:126
void mutt_clear_pager_position ( void  )

Reset the pager's viewing position.

Definition at line 1883 of file pager.c.

1884 {
1885  TopLine = 0;
1886  OldEmail = NULL;
1887 }
static int TopLine
Definition: pager.c:112
static struct Email * OldEmail
Definition: pager.c:113
static void pager_custom_redraw ( struct Menu pager_menu)
static

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

Definition at line 1931 of file pager.c.

1932 {
1933  struct PagerRedrawData *rd = pager_menu->redraw_data;
1934  char buf[1024];
1935 
1936  if (!rd)
1937  return;
1938 
1939  if (pager_menu->redraw & REDRAW_FULL)
1940  {
1942  NORMAL_COLOR;
1943  /* clear() doesn't optimize screen redraws */
1944  move(0, 0);
1945  clrtobot();
1946 
1947  if (IsEmail(rd->extra) && Context && ((Context->mailbox->vcount + 1) < C_PagerIndexLines))
1948  rd->indexlen = Context->mailbox->vcount + 1;
1949  else
1951 
1952  rd->indicator = rd->indexlen / 3;
1953 
1954  memcpy(rd->pager_window, MuttIndexWindow, sizeof(struct MuttWindow));
1955  memcpy(rd->pager_status_window, MuttStatusWindow, sizeof(struct MuttWindow));
1956  rd->index_status_window->rows = 0;
1957  rd->index_window->rows = 0;
1958 
1959  if (IsEmail(rd->extra) && C_PagerIndexLines)
1960  {
1961  memcpy(rd->index_window, MuttIndexWindow, sizeof(struct MuttWindow));
1962  rd->index_window->rows = (rd->indexlen > 0) ? rd->indexlen - 1 : 0;
1963 
1964  if (C_StatusOnTop)
1965  {
1966  memcpy(rd->index_status_window, MuttStatusWindow, sizeof(struct MuttWindow));
1967 
1968  memcpy(rd->pager_status_window, MuttIndexWindow, sizeof(struct MuttWindow));
1969  rd->pager_status_window->rows = 1;
1971 
1972  rd->pager_window->rows -=
1974  rd->pager_window->row_offset +=
1976  }
1977  else
1978  {
1979  memcpy(rd->index_status_window, MuttIndexWindow, sizeof(struct MuttWindow));
1980  rd->index_status_window->rows = 1;
1982 
1983  rd->pager_window->rows -=
1985  rd->pager_window->row_offset +=
1987  }
1988  }
1989 
1990  if (C_Help)
1991  {
1995  NORMAL_COLOR;
1996  }
1997 
1998  if (Resize)
1999  {
2001  if (rd->search_compiled)
2002  {
2003  int flags = mutt_mb_is_lower(rd->searchbuf) ? REG_ICASE : 0;
2004  const int err = REG_COMP(&rd->search_re, rd->searchbuf, REG_NEWLINE | flags);
2005  if (err != 0)
2006  {
2007  regerror(err, &rd->search_re, buf, sizeof(buf));
2008  mutt_error("%s", buf);
2009  rd->search_compiled = false;
2010  }
2011  else
2012  {
2013  rd->search_flag = MUTT_SEARCH;
2015  }
2016  }
2017  rd->lines = Resize->line;
2018  pager_menu->redraw |= REDRAW_FLOW;
2019 
2020  FREE(&Resize);
2021  }
2022 
2023  if (IsEmail(rd->extra) && C_PagerIndexLines)
2024  {
2025  if (!rd->index)
2026  {
2027  /* only allocate the space if/when we need the index.
2028  * Initialise the menu as per the main index */
2029  rd->index = mutt_menu_new(MENU_MAIN);
2031  rd->index->menu_color = index_color;
2032  rd->index->max = Context ? Context->mailbox->vcount : 0;
2033  rd->index->current = rd->extra->email->vnum;
2034  rd->index->indexwin = rd->index_window;
2035  rd->index->statuswin = rd->index_status_window;
2036  }
2037 
2038  NORMAL_COLOR;
2039  rd->index->pagelen = rd->index_window->rows;
2040 
2041  /* some fudge to work out whereabouts the indicator should go */
2042  if (rd->index->current - rd->indicator < 0)
2043  rd->index->top = 0;
2044  else if (rd->index->max - rd->index->current < rd->index->pagelen - rd->indicator)
2045  rd->index->top = rd->index->max - rd->index->pagelen;
2046  else
2047  rd->index->top = rd->index->current - rd->indicator;
2048 
2049  menu_redraw_index(rd->index);
2050  }
2051 
2052  pager_menu->redraw |= REDRAW_BODY | REDRAW_INDEX | REDRAW_STATUS;
2053 #ifdef USE_SIDEBAR
2054  pager_menu->redraw |= REDRAW_SIDEBAR;
2055 #endif
2056  mutt_show_error();
2057  }
2058 
2059  if (pager_menu->redraw & REDRAW_FLOW)
2060  {
2061  if (!(rd->flags & MUTT_PAGER_RETWINCH))
2062  {
2063  rd->lines = -1;
2064  for (int i = 0; i <= rd->topline; i++)
2065  if (!rd->line_info[i].continuation)
2066  rd->lines++;
2067  for (int i = 0; i < rd->max_line; i++)
2068  {
2069  rd->line_info[i].offset = 0;
2070  rd->line_info[i].type = -1;
2071  rd->line_info[i].continuation = 0;
2072  rd->line_info[i].chunks = 0;
2073  rd->line_info[i].search_cnt = -1;
2074  rd->line_info[i].quote = NULL;
2075 
2076  mutt_mem_realloc(&(rd->line_info[i].syntax), sizeof(struct Syntax));
2077  if (rd->search_compiled && rd->line_info[i].search)
2078  FREE(&(rd->line_info[i].search));
2079  }
2080 
2081  rd->last_line = 0;
2082  rd->topline = 0;
2083  }
2084  int i = -1;
2085  int j = -1;
2086  while (display_line(rd->fp, &rd->last_pos, &rd->line_info, ++i, &rd->last_line,
2087  &rd->max_line, rd->has_types | rd->search_flag | (rd->flags & MUTT_PAGER_NOWRAP),
2088  &rd->quote_list, &rd->q_level, &rd->force_redraw,
2089  &rd->search_re, rd->pager_window) == 0)
2090  {
2091  if (!rd->line_info[i].continuation && (++j == rd->lines))
2092  {
2093  rd->topline = i;
2094  if (!rd->search_flag)
2095  break;
2096  }
2097  }
2098  }
2099 
2100 #ifdef USE_SIDEBAR
2101  if (pager_menu->redraw & REDRAW_SIDEBAR)
2102  {
2103  menu_redraw_sidebar(pager_menu);
2104  }
2105 #endif
2106 
2107  if ((pager_menu->redraw & REDRAW_BODY) || (rd->topline != rd->oldtopline))
2108  {
2109  do
2110  {
2111  mutt_window_move(rd->pager_window, 0, 0);
2112  rd->curline = rd->topline;
2113  rd->oldtopline = rd->topline;
2114  rd->lines = 0;
2115  rd->force_redraw = false;
2116 
2117  while ((rd->lines < rd->pager_window->rows) &&
2118  (rd->line_info[rd->curline].offset <= rd->sb.st_size - 1))
2119  {
2120  if (display_line(rd->fp, &rd->last_pos, &rd->line_info, rd->curline,
2121  &rd->last_line, &rd->max_line,
2122  (rd->flags & MUTT_DISPLAYFLAGS) | rd->hide_quoted |
2123  rd->search_flag | (rd->flags & MUTT_PAGER_NOWRAP),
2124  &rd->quote_list, &rd->q_level, &rd->force_redraw,
2125  &rd->search_re, rd->pager_window) > 0)
2126  {
2127  rd->lines++;
2128  }
2129  rd->curline++;
2130  mutt_window_move(rd->pager_window, rd->lines, 0);
2131  }
2132  rd->last_offset = rd->line_info[rd->curline].offset;
2133  } while (rd->force_redraw);
2134 
2136  while (rd->lines < rd->pager_window->rows)
2137  {
2139  if (C_Tilde)
2140  addch('~');
2141  rd->lines++;
2142  mutt_window_move(rd->pager_window, rd->lines, 0);
2143  }
2144  NORMAL_COLOR;
2145 
2146  /* We are going to update the pager status bar, so it isn't
2147  * necessary to reset to normal color now. */
2148 
2149  pager_menu->redraw |= REDRAW_STATUS; /* need to update the % seen */
2150  }
2151 
2152  if (pager_menu->redraw & REDRAW_STATUS)
2153  {
2154  struct HdrFormatInfo hfi;
2155  char pager_progress_str[65]; /* Lots of space for translations */
2156 
2157  hfi.ctx = Context;
2158  hfi.mailbox = Context ? Context->mailbox : NULL;
2159  hfi.pager_progress = pager_progress_str;
2160 
2161  if (rd->last_pos < rd->sb.st_size - 1)
2162  {
2163  snprintf(pager_progress_str, sizeof(pager_progress_str), OFF_T_FMT "%%",
2164  (100 * rd->last_offset / rd->sb.st_size));
2165  }
2166  else
2167  {
2168  const char *msg = (rd->topline == 0) ?
2169  /* L10N: Status bar message: the entire email is visible in the pager */
2170  _("all") :
2171  /* L10N: Status bar message: the end of the email is visible in the pager */
2172  _("end");
2173  mutt_str_strfcpy(pager_progress_str, msg, sizeof(pager_progress_str));
2174  }
2175 
2176  /* print out the pager status bar */
2179 
2180  if (IsEmail(rd->extra) || IsMsgAttach(rd->extra))
2181  {
2182  size_t l1 = rd->pager_status_window->cols * MB_LEN_MAX;
2183  size_t l2 = sizeof(buf);
2184  hfi.email = (IsEmail(rd->extra)) ? rd->extra->email : rd->extra->body->email;
2185  mutt_make_string_info(buf, (l1 < l2) ? l1 : l2, rd->pager_status_window->cols,
2188  }
2189  else
2190  {
2191  char bn[256];
2192  snprintf(bn, sizeof(bn), "%s (%s)", rd->banner, pager_progress_str);
2193  mutt_draw_statusline(rd->pager_status_window->cols, bn, sizeof(bn));
2194  }
2195  NORMAL_COLOR;
2196  if (C_TsEnabled && TsSupported && rd->index)
2197  {
2198  menu_status_line(buf, sizeof(buf), rd->index, NONULL(C_TsStatusFormat));
2199  mutt_ts_status(buf);
2200  menu_status_line(buf, sizeof(buf), rd->index, NONULL(C_TsIconFormat));
2201  mutt_ts_icon(buf);
2202  }
2203  }
2204 
2205  if ((pager_menu->redraw & REDRAW_INDEX) && rd->index)
2206  {
2207  /* redraw the pager_index indicator, because the
2208  * flags for this message might have changed. */
2209  if (rd->index_window->rows > 0)
2211 
2212  /* print out the index status bar */
2213  menu_status_line(buf, sizeof(buf), rd->index, NONULL(C_StatusFormat));
2214 
2217  mutt_draw_statusline(rd->index_status_window->cols, buf, sizeof(buf));
2218  NORMAL_COLOR;
2219  }
2220 
2221  pager_menu->redraw = 0;
2222 }
struct Context * ctx
Definition: hdrline.h:46
The "current" mailbox.
Definition: context.h:39
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:37
const char * banner
Definition: pager.c:1920
PagerFlags hide_quoted
Definition: pager.c:1906
struct MuttWindow * MuttStatusWindow
Status Window.
Definition: mutt_window.c:40
PagerFlags search_flag
Definition: pager.c:1918
#define MUTT_DISPLAYFLAGS
Definition: pager.h:60
short chunks
Definition: pager.c:179
Keep track when the pager needs redrawing.
Definition: pager.c:1892
#define NORMAL_COLOR
Definition: mutt_curses.h:239
Pager: empty lines after message.
Definition: mutt_curses.h:133
#define REDRAW_FLOW
Used by pager to reflow text.
Definition: mutt_menu.h:49
struct MuttWindow * pager_status_window
Definition: pager.c:1913
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:736
#define IsMsgAttach(pager)
Definition: pager.c:101
#define _(a)
Definition: message.h:28
const char * helpstr
Definition: pager.c:1921
struct Line * line_info
Definition: pager.c:1923
int index_color(int line)
Calculate the colour for a line of the index - Implements Menu::menu_color()
Definition: index.c:809
void menu_status_line(char *buf, size_t buflen, struct Menu *menu, const char *p)
Create the status line.
Definition: status.c:394
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:1894
Index panel (list of emails)
Definition: keymap.h:76
bool search_back
Definition: pager.c:218
Highlighting for a line of text.
Definition: pager.c:164
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:217
short type
Definition: pager.c:177
#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:114
#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:1161
LOFF_T last_pos
Definition: pager.c:1909
struct MuttWindow * index_status_window
Definition: pager.c:1911
int line
Definition: pager.c:216
void * redraw_data
Definition: mutt_menu.h:152
struct Mailbox * mailbox
Definition: context.h:53
Data passed to index_format_str()
Definition: hdrline.h:44
LOFF_T last_offset
Definition: pager.c:1910
FILE * fp
Definition: pager.c:1924
#define REG_COMP(preg, regex, cflags)
Compile a regular expression.
Definition: regex3.h:52
short continuation
Definition: pager.c:178
bool force_redraw
Definition: pager.c:1904
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:114
void mutt_make_string_info(char *buf, size_t buflen, int cols, const char *s, struct HdrFormatInfo *hfi, MuttFormatFlags flags)
Create pager status bar string.
Definition: hdrline.c:1524
int oldtopline
Definition: pager.c:1898
struct Pager * extra
Definition: pager.c:1895
struct QClass * quote
Definition: pager.c:183
short search_cnt
Definition: pager.c:180
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:1917
struct Syntax * syntax
Definition: pager.c:181
struct MuttWindow * MuttIndexWindow
Index Window.
Definition: mutt_window.c:39
struct MuttWindow * pager_window
Definition: pager.c:1914
struct MuttWindow * indexwin
Definition: mutt_menu.h:95
struct MuttWindow * index_window
Definition: pager.c:1912
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:750
int vnum
Virtual message number.
Definition: email.h:87
int pagelen
number of entries per screen
Definition: mutt_menu.h:92
bool TsSupported
Terminal Setting is supported.
Definition: terminal.c:43
#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:1915
struct QClass * quote_list
Definition: pager.c:1908
#define IsEmail(pager)
Definition: pager.c:103
int indicator
the indicator line of the PI
Definition: pager.c:1897
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:1922
#define REDRAW_INDEX
Redraw the index.
Definition: mutt_menu.h:42
#define mutt_error(...)
Definition: logging.h:84
int row_offset
Definition: mutt_window.h:37
#define FREE(x)
Definition: memory.h:40
Status bar.
Definition: mutt_curses.h:129
struct Syntax * search
Definition: pager.c:182
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:96
void mutt_show_error(void)
Show the user an error message.
Definition: curs_lib.c:485
Keep track of screen resizing.
Definition: pager.c:214
void mutt_ts_status(char *str)
Set the text of the terminal title bar.
Definition: terminal.c:104
struct stat sb
Definition: pager.c:1925
int current
current entry
Definition: mutt_menu.h:87
LOFF_T offset
Definition: pager.c:176
bool mutt_mb_is_lower(const char *s)
Does a multi-byte string contain only lowercase characters?
Definition: mbyte.c:358
struct Email * email
header information for message/rfc822
Definition: body.h:55
static int display_line(FILE *fp, LOFF_T *last_pos, struct Line **line_info, int n, int *last, int *max, PagerFlags flags, struct QClass **quote_list, int *q_level, bool *force_redraw, regex_t *search_re, struct MuttWindow *pager_window)
Print a line on screen.
Definition: pager.c:1567
void mutt_draw_statusline(int cols, const char *buf, size_t buflen)
Draw a highlighted status bar.
Definition: index.c:838
short C_PagerIndexLines
Config: Number of index lines to display above the pager.
Definition: pager.c:90
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:1916
bool search_back
Definition: pager.c:1919
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 2239 of file pager.c.

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

Variable Documentation

bool C_AllowAnsi

Config: Allow ANSI colour codes in rich text messages.

Definition at line 87 of file pager.c.

bool C_HeaderColorPartial

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

Definition at line 88 of file pager.c.

short C_PagerContext

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

Definition at line 89 of file pager.c.

short C_PagerIndexLines

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

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

short C_SearchContext

Config: Context to display around search matches.

Definition at line 92 of file pager.c.

short C_SkipQuotedOffset

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

Definition at line 93 of file pager.c.

bool C_SmartWrap

Config: Wrap text at word boundaries.

Definition at line 94 of file pager.c.

struct Regex* C_Smileys

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

Definition at line 95 of file pager.c.

bool C_Tilde

Config: Character to pad blank lines in the pager.

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

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

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

int TopLine = 0
static

Definition at line 112 of file pager.c.

struct Email* OldEmail = NULL
static

Definition at line 113 of file pager.c.

short InHelp = 0
static

Definition at line 209 of file pager.c.

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

Definition at line 829 of file pager.c.

int braille_col = -1
static

Definition at line 830 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 1855 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 1862 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 1871 of file pager.c.