NeoMutt  2018-07-16 +2388-bcedc8
Teaching an old dog new tricks
DOXYGEN
pager.c File Reference

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

#include "config.h"
#include <ctype.h>
#include <errno.h>
#include <inttypes.h>
#include <limits.h>
#include <regex.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include <wchar.h>
#include "mutt/mutt.h"
#include "config/lib.h"
#include "email/lib.h"
#include "core/lib.h"
#include "mutt.h"
#include "pager.h"
#include "alias.h"
#include "color.h"
#include "commands.h"
#include "context.h"
#include "curs_lib.h"
#include "format_flags.h"
#include "globals.h"
#include "hdrline.h"
#include "hook.h"
#include "index.h"
#include "keymap.h"
#include "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 ANSI_NO_FLAGS   0
 No flags are set. More...
 
#define ANSI_OFF   (1 << 0)
 Turn off colours and attributes. More...
 
#define ANSI_BLINK   (1 << 1)
 Blinking text. More...
 
#define ANSI_BOLD   (1 << 2)
 Bold text. More...
 
#define ANSI_UNDERLINE   (1 << 3)
 Underlined text. More...
 
#define ANSI_REVERSE   (1 << 4)
 Reverse video. More...
 
#define ANSI_COLOR   (1 << 5)
 Use colours. More...
 
#define IS_HEADER(x)   ((x) == MT_COLOR_HEADER || (x) == MT_COLOR_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 NUM_SIG_LINES   4
 
#define CHECK_MODE(test)
 
#define CHECK_READONLY
 
#define CHECK_ATTACH
 
#define CHECK_ACL(aclbit, action)
 

Typedefs

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

Functions

static int check_sig (const char *s, struct Line *info, int n)
 Check for an email signature. More...
 
static int comp_syntax_t (const void *m1, const void *m2)
 Search for a Syntax using bsearch. More...
 
static void resolve_color (struct Line *line_info, int n, int cnt, PagerFlags flags, int special, struct AnsiAttr *a)
 Set the colour for a line of text. More...
 
static void append_line (struct Line *line_info, int n, int cnt)
 Add a new Line to the array. More...
 
static void 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, int width)
 Display a line of text in the pager. More...
 
static int display_line (FILE *fp, LOFF_T *last_pos, struct Line **line_info, int n, int *last, int *max, PagerFlags flags, struct QClass **quote_list, int *q_level, bool *force_redraw, regex_t *search_re, struct MuttWindow *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 int TopLine = 0
 
static struct EmailOldEmail = NULL
 
static bool InHelp = false
 
static int braille_line = -1
 
static int braille_col = -1
 
static struct ResizeResize = NULL
 
static const char * Not_available_in_this_menu
 
static const char * Mailbox_is_read_only = N_("Mailbox is read-only")
 
static const char * Function_not_permitted_in_attach_message_mode
 
static const struct Mapping PagerHelp []
 
static const struct Mapping PagerHelpExtra []
 
static struct Mapping PagerNewsHelpExtra []
 

Detailed Description

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

Authors
  • Michael R. Elkins

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

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

Definition in file pager.c.

Macro Definition Documentation

#define ANSI_NO_FLAGS   0

No flags are set.

Definition at line 102 of file pager.c.

#define ANSI_OFF   (1 << 0)

Turn off colours and attributes.

Definition at line 103 of file pager.c.

#define ANSI_BLINK   (1 << 1)

Blinking text.

Definition at line 104 of file pager.c.

#define ANSI_BOLD   (1 << 2)

Bold text.

Definition at line 105 of file pager.c.

#define ANSI_UNDERLINE   (1 << 3)

Underlined text.

Definition at line 106 of file pager.c.

#define ANSI_REVERSE   (1 << 4)

Reverse video.

Definition at line 107 of file pager.c.

#define ANSI_COLOR   (1 << 5)

Use colours.

Definition at line 108 of file pager.c.

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

Definition at line 252 of file pager.c.

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

Definition at line 254 of file pager.c.

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

Definition at line 255 of file pager.c.

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

Definition at line 257 of file pager.c.

#define NUM_SIG_LINES   4

Definition at line 259 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:221
static struct UrlTest test[]
Definition: url_parse.c:40
#define mutt_error(...)
Definition: logging.h:84

Definition at line 261 of file pager.c.

#define CHECK_READONLY
Value:
{ \
break; \
}
The "current" mailbox.
Definition: context.h:36
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:50
bool readonly
Don&#39;t allow changes to the mailbox.
Definition: mailbox.h:130
static const char * Mailbox_is_read_only
Definition: pager.c:223
#define mutt_error(...)
Definition: logging.h:84

Definition at line 269 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:224
#define mutt_error(...)
Definition: logging.h:84

Definition at line 277 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:36
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:50
AclFlags rights
ACL bits, see AclFlags.
Definition: mailbox.h:132
#define mutt_error(...)
Definition: logging.h:84

Definition at line 285 of file pager.c.

Typedef Documentation

typedef uint8_t AnsiFlags

Flags, e.g. ANSI_OFF.

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

303 {
304  int count = 0;
305 
306  while ((n > 0) && (count <= NUM_SIG_LINES))
307  {
308  if (info[n].type != MT_COLOR_SIGNATURE)
309  break;
310  count++;
311  n--;
312  }
313 
314  if (count == 0)
315  return -1;
316 
317  if (count > NUM_SIG_LINES)
318  {
319  /* check for a blank line */
320  while (*s)
321  {
322  if (!IS_SPACE(*s))
323  return 0;
324  s++;
325  }
326 
327  return -1;
328  }
329 
330  return 0;
331 }
Pager: signature lines.
Definition: mutt_curses.h:127
#define NUM_SIG_LINES
Definition: pager.c:259
#define IS_SPACE(ch)
Definition: string2.h:38

+ Here is the caller graph for this function:

static int comp_syntax_t ( const void *  m1,
const void *  m2 
)
static

Search for a Syntax using bsearch.

Parameters
m1Search key
m2Array member
Return values
-1m1 precedes m2
0m1 matches m2
1m2 precedes m1

Definition at line 341 of file pager.c.

342 {
343  const int *cnt = (const int *) m1;
344  const struct Syntax *stx = (const struct Syntax *) m2;
345 
346  if (*cnt < stx->first)
347  return -1;
348  if (*cnt >= stx->last)
349  return 1;
350  return 0;
351 }
int first
Definition: pager.c:130
int last
Definition: pager.c:131
Highlighting for a line of text.
Definition: pager.c:127

+ Here is the caller graph for this function:

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

Set the colour for a line of text.

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

Definition at line 362 of file pager.c.

364 {
365  int def_color; /* color without syntax highlight */
366  int color; /* final color */
367  static int last_color; /* last color set */
368  bool search = false;
369  int m;
370  struct Syntax *matching_chunk = NULL;
371 
372  if (cnt == 0)
373  last_color = -1; /* force attrset() */
374 
375  if (line_info[n].continuation)
376  {
377  if (!cnt && C_Markers)
378  {
380  addch('+');
381  last_color = ColorDefs[MT_COLOR_MARKERS];
382  }
383  m = (line_info[n].syntax)[0].first;
384  cnt += (line_info[n].syntax)[0].last;
385  }
386  else
387  m = n;
388  if (flags & MUTT_PAGER_LOGS)
389  {
390  def_color = ColorDefs[(line_info[n].syntax)[0].color];
391  }
392  else if (!(flags & MUTT_SHOWCOLOR))
393  def_color = ColorDefs[MT_COLOR_NORMAL];
394  else if (line_info[m].type == MT_COLOR_HEADER)
395  def_color = (line_info[m].syntax)[0].color;
396  else
397  def_color = ColorDefs[line_info[m].type];
398 
399  if ((flags & MUTT_SHOWCOLOR) && (line_info[m].type == MT_COLOR_QUOTED))
400  {
401  struct QClass *qc = line_info[m].quote;
402 
403  if (qc)
404  {
405  def_color = qc->color;
406 
407  while (qc && (qc->length > cnt))
408  {
409  def_color = qc->color;
410  qc = qc->up;
411  }
412  }
413  }
414 
415  color = def_color;
416  if ((flags & MUTT_SHOWCOLOR) && line_info[m].chunks)
417  {
418  matching_chunk = bsearch(&cnt, line_info[m].syntax, line_info[m].chunks,
419  sizeof(struct Syntax), comp_syntax_t);
420  if (matching_chunk && (cnt >= matching_chunk->first) &&
421  (cnt < matching_chunk->last))
422  {
423  color = matching_chunk->color;
424  }
425  }
426 
427  if ((flags & MUTT_SEARCH) && line_info[m].search_cnt)
428  {
429  matching_chunk = bsearch(&cnt, line_info[m].search, line_info[m].search_cnt,
430  sizeof(struct Syntax), comp_syntax_t);
431  if (matching_chunk && (cnt >= matching_chunk->first) &&
432  (cnt < matching_chunk->last))
433  {
434  color = ColorDefs[MT_COLOR_SEARCH];
435  search = 1;
436  }
437  }
438 
439  /* handle "special" bold & underlined characters */
440  if (special || a->attr)
441  {
442 #ifdef HAVE_COLOR
443  if ((a->attr & ANSI_COLOR))
444  {
445  if (a->pair == -1)
446  a->pair = mutt_alloc_color(a->fg, a->bg);
447  color = a->pair;
448  if (a->attr & ANSI_BOLD)
449  color |= A_BOLD;
450  }
451  else
452 #endif
453  if ((special & A_BOLD) || (a->attr & ANSI_BOLD))
454  {
455  if (ColorDefs[MT_COLOR_BOLD] && !search)
456  color = ColorDefs[MT_COLOR_BOLD];
457  else
458  color ^= A_BOLD;
459  }
460  if ((special & A_UNDERLINE) || (a->attr & ANSI_UNDERLINE))
461  {
462  if (ColorDefs[MT_COLOR_UNDERLINE] && !search)
463  color = ColorDefs[MT_COLOR_UNDERLINE];
464  else
465  color ^= A_UNDERLINE;
466  }
467  else if (a->attr & ANSI_REVERSE)
468  {
469  color ^= A_REVERSE;
470  }
471  else if (a->attr & ANSI_BLINK)
472  {
473  color ^= A_BLINK;
474  }
475  else if (a->attr == ANSI_OFF)
476  {
477  a->attr = 0;
478  }
479  }
480 
481  if (color != last_color)
482  {
483  ATTR_SET(color);
484  last_color = color;
485  }
486 }
int first
Definition: pager.c:130
#define ANSI_COLOR
Use colours.
Definition: pager.c:108
#define MUTT_SHOWCOLOR
Show characters in color otherwise don&#39;t show characters.
Definition: pager.h:45
size_t length
Definition: pager.c:116
int pair
Curses colour pair.
Definition: pager.c:158
Pager: quoted text.
Definition: mutt_curses.h:126
Bold text.
Definition: mutt_curses.h:141
int last
Definition: pager.c:131
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:127
Pager: markers, line continuation.
Definition: mutt_curses.h:134
short type
Definition: pager.c:140
int color
Definition: pager.c:129
#define ANSI_BOLD
Bold text.
Definition: pager.c:105
Plain text.
Definition: mutt_curses.h:131
AnsiFlags attr
Attributes, e.g. underline, bold, etc.
Definition: pager.c:155
static int comp_syntax_t(const void *m1, const void *m2)
Search for a Syntax using bsearch.
Definition: pager.c:341
#define ANSI_BLINK
Blinking text.
Definition: pager.c:104
Underlined text.
Definition: mutt_curses.h:142
#define ANSI_REVERSE
Reverse video.
Definition: pager.c:107
int bg
Background colour.
Definition: pager.c:157
struct Syntax * syntax
Definition: pager.c:144
#define ATTR_SET
Definition: mutt_curses.h:232
#define ANSI_UNDERLINE
Underlined text.
Definition: pager.c:106
int ColorDefs[MT_COLOR_MAX]
Array of all fixed colours, see enum ColorId.
Definition: color.c:55
#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:156
#define MUTT_SEARCH
Resolve search patterns.
Definition: pager.h:47
int color
Definition: pager.c:118
WHERE bool C_Markers
Config: Display a &#39;+&#39; at the beginning of wrapped lines in the pager.
Definition: globals.h:252
int mutt_alloc_color(uint32_t fg, uint32_t bg)
struct QClass * up
Definition: pager.c:121
Style of quoted text.
Definition: pager.c:114
#define ANSI_OFF
Turn off colours and attributes.
Definition: pager.c:103

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

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

Add a new Line to the array.

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

Definition at line 494 of file pager.c.

495 {
496  int m;
497 
498  line_info[n + 1].type = line_info[n].type;
499  (line_info[n + 1].syntax)[0].color = (line_info[n].syntax)[0].color;
500  line_info[n + 1].continuation = 1;
501 
502  /* find the real start of the line */
503  for (m = n; m >= 0; m--)
504  if (line_info[m].continuation == 0)
505  break;
506 
507  (line_info[n + 1].syntax)[0].first = m;
508  (line_info[n + 1].syntax)[0].last =
509  (line_info[n].continuation) ? cnt + (line_info[n].syntax)[0].last : cnt;
510 }
short type
Definition: pager.c:140
short continuation
Definition: pager.c:141
struct Syntax * syntax
Definition: pager.c:144
int color
Definition: pager.c:118

+ Here is the caller graph for this function:

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

518 {
519  qc->index = (*q_level)++;
520  qc->color = ColorQuote[qc->index % ColorQuoteUsed];
521 }
int * ColorQuote
Array of colours for quoted email text.
Definition: color.c:53
int ColorQuoteUsed
Number of colours for quoted email text.
Definition: color.c:54
int color
Definition: pager.c:118
int index
Definition: pager.c:117

+ Here is the caller graph for this function:

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

Insert a new quote colour class into a list.

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

Definition at line 530 of file pager.c.

532 {
533  struct QClass *q_list = quote_list;
534  new_class->index = -1;
535 
536  while (q_list)
537  {
538  if (q_list->index >= index)
539  {
540  q_list->index++;
541  q_list->color = ColorQuote[q_list->index % ColorQuoteUsed];
542  }
543  if (q_list->down)
544  q_list = q_list->down;
545  else if (q_list->next)
546  q_list = q_list->next;
547  else
548  {
549  while (!q_list->next)
550  {
551  q_list = q_list->up;
552  if (!q_list)
553  break;
554  }
555  if (q_list)
556  q_list = q_list->next;
557  }
558  }
559 
560  new_class->index = index;
561  new_class->color = ColorQuote[index % ColorQuoteUsed];
562  (*q_level)++;
563 }
int * ColorQuote
Array of colours for quoted email text.
Definition: color.c:53
int ColorQuoteUsed
Number of colours for quoted email text.
Definition: color.c:54
struct QClass * down
Definition: pager.c:121
struct QClass * next
Definition: pager.c:120
int color
Definition: pager.c:118
int index
Definition: pager.c:117
struct QClass * up
Definition: pager.c:121
Style of quoted text.
Definition: pager.c:114

+ Here is the caller graph for this function:

static void cleanup_quote ( struct QClass **  quote_list)
static

Free a quote list.

Parameters
[out]quote_listQuote list to free

Definition at line 569 of file pager.c.

570 {
571  struct QClass *ptr = NULL;
572 
573  while (*quote_list)
574  {
575  if ((*quote_list)->down)
576  cleanup_quote(&((*quote_list)->down));
577  ptr = (*quote_list)->next;
578  if ((*quote_list)->prefix)
579  FREE(&(*quote_list)->prefix);
580  FREE(quote_list);
581  *quote_list = ptr;
582  }
583 }
static void cleanup_quote(struct QClass **quote_list)
Free a quote list.
Definition: pager.c:569
struct QClass * next
Definition: pager.c:120
#define FREE(x)
Definition: memory.h:40
Style of quoted text.
Definition: pager.c:114

+ Here is the caller graph for this function:

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

Find a style for a string.

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

Definition at line 594 of file pager.c.

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

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

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

Check that the unique marker is present.

Parameters
qMarker string
pString to check
Return values
numOffset of marker

Definition at line 906 of file pager.c.

907 {
908  for (; (p[0] == q[0]) && (q[0] != '\0') && (p[0] != '\0') && (q[0] != '\a') &&
909  (p[0] != '\a');
910  p++, q++)
911  {
912  }
913 
914  return (int) (*p - *q);
915 }

+ Here is the caller graph for this function:

static int check_attachment_marker ( const char *  p)
static

Check that the unique marker is present.

Parameters
pString to check
Return values
numOffset of marker

Definition at line 922 of file pager.c.

923 {
924  return check_marker(AttachmentMarker, p);
925 }
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:906

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static int check_protected_header_marker ( const char *  p)
static

Check that the unique marker is present.

Parameters
pString to check
Return values
numOffset of marker

Definition at line 932 of file pager.c.

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

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

int mutt_is_quote_line ( char *  line,
regmatch_t *  pmatch 
)

Is a line of message text a quote?

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

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

Definition at line 946 of file pager.c.

947 {
948  bool is_quote = false;
949  regmatch_t pmatch_internal[1], smatch[1];
950 
951  if (!pmatch)
952  pmatch = pmatch_internal;
953 
954  if (mutt_regex_capture(C_QuoteRegex, line, 1, pmatch))
955  {
956  if (mutt_regex_capture(C_Smileys, line, 1, smatch))
957  {
958  if (smatch[0].rm_so > 0)
959  {
960  char c = line[smatch[0].rm_so];
961  line[smatch[0].rm_so] = 0;
962 
963  if (mutt_regex_capture(C_QuoteRegex, line, 1, pmatch))
964  is_quote = true;
965 
966  line[smatch[0].rm_so] = c;
967  }
968  }
969  else
970  is_quote = true;
971  }
972 
973  return is_quote;
974 }
struct Regex * C_Smileys
Config: Regex to match smileys to prevent mistakes when quoting text.
Definition: pager.c:96
const char * line
Definition: common.c:36
WHERE struct Regex * C_QuoteRegex
Config: Regex to match quoted text in a reply.
Definition: globals.h:186
bool mutt_regex_capture(const struct Regex *regex, const char *str, size_t nmatch, regmatch_t matches[])
match a regex against a string, with provided options
Definition: regex.c:594

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

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

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

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static bool is_ansi ( unsigned char *  buf)
static

Is this an ANSI escape sequence?

Parameters
bufString to check
Return values
trueIf it is

Definition at line 1254 of file pager.c.

1255 {
1256  while ((*buf != '\0') && (isdigit(*buf) || (*buf == ';')))
1257  buf++;
1258  return *buf == 'm';
1259 }

+ Here is the caller graph for this function:

static int grok_ansi ( unsigned char *  buf,
int  pos,
struct AnsiAttr a 
)
static

Parse an ANSI escape sequence.

Parameters
bufString to parse
posStarting position in string
aAnsiAttr for the result
Return values
numIndex of first character after the escape sequence

Definition at line 1268 of file pager.c.

1269 {
1270  int x = pos;
1271 
1272  while (isdigit(buf[x]) || (buf[x] == ';'))
1273  x++;
1274 
1275  /* Character Attributes */
1276  if (C_AllowAnsi && a && (buf[x] == 'm'))
1277  {
1278  if (pos == x)
1279  {
1280 #ifdef HAVE_COLOR
1281  if (a->pair != -1)
1282  mutt_free_color(a->fg, a->bg);
1283 #endif
1284  a->attr = ANSI_OFF;
1285  a->pair = -1;
1286  }
1287  while (pos < x)
1288  {
1289  if ((buf[pos] == '1') && ((pos + 1 == x) || (buf[pos + 1] == ';')))
1290  {
1291  a->attr |= ANSI_BOLD;
1292  pos += 2;
1293  }
1294  else if ((buf[pos] == '4') && ((pos + 1 == x) || (buf[pos + 1] == ';')))
1295  {
1296  a->attr |= ANSI_UNDERLINE;
1297  pos += 2;
1298  }
1299  else if ((buf[pos] == '5') && ((pos + 1 == x) || (buf[pos + 1] == ';')))
1300  {
1301  a->attr |= ANSI_BLINK;
1302  pos += 2;
1303  }
1304  else if ((buf[pos] == '7') && ((pos + 1 == x) || (buf[pos + 1] == ';')))
1305  {
1306  a->attr |= ANSI_REVERSE;
1307  pos += 2;
1308  }
1309  else if ((buf[pos] == '0') && ((pos + 1 == x) || (buf[pos + 1] == ';')))
1310  {
1311 #ifdef HAVE_COLOR
1312  if (a->pair != -1)
1313  mutt_free_color(a->fg, a->bg);
1314 #endif
1315  a->attr = ANSI_OFF;
1316  a->pair = -1;
1317  pos += 2;
1318  }
1319  else if ((buf[pos] == '3') && isdigit(buf[pos + 1]))
1320  {
1321 #ifdef HAVE_COLOR
1322  if (a->pair != -1)
1323  mutt_free_color(a->fg, a->bg);
1324 #endif
1325  a->pair = -1;
1326  a->attr |= ANSI_COLOR;
1327  a->fg = buf[pos + 1] - '0';
1328  pos += 3;
1329  }
1330  else if ((buf[pos] == '4') && isdigit(buf[pos + 1]))
1331  {
1332 #ifdef HAVE_COLOR
1333  if (a->pair != -1)
1334  mutt_free_color(a->fg, a->bg);
1335 #endif
1336  a->pair = -1;
1337  a->attr |= ANSI_COLOR;
1338  a->bg = buf[pos + 1] - '0';
1339  pos += 3;
1340  }
1341  else
1342  {
1343  while ((pos < x) && (buf[pos] != ';'))
1344  pos++;
1345  pos++;
1346  }
1347  }
1348  }
1349  pos = x;
1350  return pos;
1351 }
bool C_AllowAnsi
Config: Allow ANSI colour codes in rich text messages.
Definition: pager.c:88
#define ANSI_COLOR
Use colours.
Definition: pager.c:108
int pair
Curses colour pair.
Definition: pager.c:158
#define ANSI_BOLD
Bold text.
Definition: pager.c:105
void mutt_free_color(uint32_t fg, uint32_t bg)
AnsiFlags attr
Attributes, e.g. underline, bold, etc.
Definition: pager.c:155
#define ANSI_BLINK
Blinking text.
Definition: pager.c:104
#define ANSI_REVERSE
Reverse video.
Definition: pager.c:107
int bg
Background colour.
Definition: pager.c:157
#define ANSI_UNDERLINE
Underlined text.
Definition: pager.c:106
int fg
Foreground colour.
Definition: pager.c:156
#define ANSI_OFF
Turn off colours and attributes.
Definition: pager.c:103

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static int fill_buffer ( FILE *  fp,
LOFF_T *  last_pos,
LOFF_T  offset,
unsigned char **  buf,
unsigned char **  fmt,
size_t *  blen,
int *  buf_ready 
)
static

Fill a buffer from a file.

Parameters
[in]fpFile to read from
[in,out]last_posEnd of last read
[in]offsetPosition start reading from
[out]bufBuffer to fill
[out]fmtCopy of buffer, stripped of attributes
[out]blenLength of the buffer
[in,out]buf_readytrue if the buffer already has data in it
Return values
>=0Bytes read
-1Error

Definition at line 1365 of file pager.c.

1367 {
1368  unsigned char *p = NULL, *q = NULL;
1369  static int b_read;
1370  int l = 0;
1371 
1372  if (*buf_ready == 0)
1373  {
1374  if (offset != *last_pos)
1375  fseeko(fp, offset, SEEK_SET);
1376  *buf = (unsigned char *) mutt_file_read_line((char *) *buf, blen, fp, &l, MUTT_EOL);
1377  if (!*buf)
1378  {
1379  fmt[0] = NULL;
1380  return -1;
1381  }
1382  *last_pos = ftello(fp);
1383  b_read = (int) (*last_pos - offset);
1384  *buf_ready = 1;
1385 
1386  mutt_mem_realloc(fmt, *blen);
1387 
1388  /* copy "buf" to "fmt", but without bold and underline controls */
1389  p = *buf;
1390  q = *fmt;
1391  while (*p)
1392  {
1393  if ((p[0] == '\010') && (p > *buf)) // Ctrl-H (backspace)
1394  {
1395  if (p[1] == '_') /* underline */
1396  p += 2;
1397  else if ((p[1] != '\0') && (q > *fmt)) /* bold or overstrike */
1398  {
1399  q[-1] = p[1];
1400  p += 2;
1401  }
1402  else /* ^H */
1403  *q++ = *p++;
1404  }
1405  else if ((p[0] == '\033') && (p[1] == '[') && is_ansi(p + 2)) // Escape
1406  {
1407  while (*p++ != 'm') /* skip ANSI sequence */
1408  ;
1409  }
1410  else if ((p[0] == '\033') && (p[1] == ']') && // Escape
1411  ((check_attachment_marker((char *) p) == 0) ||
1412  (check_protected_header_marker((char *) p) == 0)))
1413  {
1414  mutt_debug(LL_DEBUG2, "Seen attachment marker\n");
1415  while (*p++ != '\a') /* skip pseudo-ANSI sequence */
1416  ;
1417  }
1418  else
1419  *q++ = *p++;
1420  }
1421  *q = '\0';
1422  }
1423  return b_read;
1424 }
static int check_protected_header_marker(const char *p)
Check that the unique marker is present.
Definition: pager.c:932
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:1254
static int check_attachment_marker(const char *p)
Check that the unique marker is present.
Definition: pager.c:922

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static int format_line ( struct Line **  line_info,
int  n,
unsigned char *  buf,
PagerFlags  flags,
struct AnsiAttr pa,
int  cnt,
int *  pspace,
int *  pvch,
int *  pcol,
int *  pspecial,
int  width 
)
static

Display a line of text in the pager.

Parameters
[out]line_infoLine info
[in]nLine number (index into line_info)
[in]bufText to display
[in]flagsFlags, see PagerFlags
[out]paANSI attributes used
[in]cntLength of text buffer
[out]pspaceIndex of last whitespace character
[out]pvchNumber of bytes read
[out]pcolNumber of columns used
[out]pspecialAttribute flags, e.g. A_UNDERLINE
[in]widthWidth of screen (to wrap to)
Return values
numNumber of characters displayed

Definition at line 1441 of file pager.c.

1444 {
1445  int space = -1; /* index of the last space or TAB */
1446  int col = C_Markers ? (*line_info)[n].continuation : 0;
1447  size_t k;
1448  int ch, vch, last_special = -1, special = 0, t;
1449  wchar_t wc;
1450  mbstate_t mbstate;
1451  int wrap_cols = mutt_window_wrap_cols(width, (flags & MUTT_PAGER_NOWRAP) ? 0 : C_Wrap);
1452 
1453  if (check_attachment_marker((char *) buf) == 0)
1454  wrap_cols = width;
1455 
1456  /* FIXME: this should come from line_info */
1457  memset(&mbstate, 0, sizeof(mbstate));
1458 
1459  for (ch = 0, vch = 0; ch < cnt; ch += k, vch += k)
1460  {
1461  /* Handle ANSI sequences */
1462  while ((cnt - ch >= 2) && (buf[ch] == '\033') && (buf[ch + 1] == '[') && // Escape
1463  is_ansi(buf + ch + 2))
1464  {
1465  ch = grok_ansi(buf, ch + 2, pa) + 1;
1466  }
1467 
1468  while ((cnt - ch >= 2) && (buf[ch] == '\033') && (buf[ch + 1] == ']') && // Escape
1469  ((check_attachment_marker((char *) buf + ch) == 0) ||
1470  (check_protected_header_marker((char *) buf + ch) == 0)))
1471  {
1472  while (buf[ch++] != '\a')
1473  if (ch >= cnt)
1474  break;
1475  }
1476 
1477  /* is anything left to do? */
1478  if (ch >= cnt)
1479  break;
1480 
1481  k = mbrtowc(&wc, (char *) buf + ch, cnt - ch, &mbstate);
1482  if ((k == (size_t)(-2)) || (k == (size_t)(-1)))
1483  {
1484  if (k == (size_t)(-1))
1485  memset(&mbstate, 0, sizeof(mbstate));
1486  mutt_debug(LL_DEBUG1, "mbrtowc returned %lu; errno = %d\n", k, errno);
1487  if (col + 4 > wrap_cols)
1488  break;
1489  col += 4;
1490  if (pa)
1491  printw("\\%03o", buf[ch]);
1492  k = 1;
1493  continue;
1494  }
1495  if (k == 0)
1496  k = 1;
1497 
1498  if (CharsetIsUtf8)
1499  {
1500  /* zero width space, zero width no-break space */
1501  if ((wc == 0x200B) || (wc == 0xFEFF))
1502  {
1503  mutt_debug(LL_DEBUG3, "skip zero-width character U+%04X\n", (unsigned short) wc);
1504  continue;
1505  }
1507  {
1508  mutt_debug(LL_DEBUG3, "filtered U+%04X\n", (unsigned short) wc);
1509  continue;
1510  }
1511  }
1512 
1513  /* Handle backspace */
1514  special = 0;
1515  if (IsWPrint(wc))
1516  {
1517  wchar_t wc1;
1518  mbstate_t mbstate1 = mbstate;
1519  size_t k1 = mbrtowc(&wc1, (char *) buf + ch + k, cnt - ch - k, &mbstate1);
1520  while ((k1 != (size_t)(-2)) && (k1 != (size_t)(-1)) && (k1 > 0) && (wc1 == '\b'))
1521  {
1522  const size_t k2 =
1523  mbrtowc(&wc1, (char *) buf + ch + k + k1, cnt - ch - k - k1, &mbstate1);
1524  if ((k2 == (size_t)(-2)) || (k2 == (size_t)(-1)) || (k2 == 0) || (!IsWPrint(wc1)))
1525  break;
1526 
1527  if (wc == wc1)
1528  {
1529  special |= ((wc == '_') && (special & A_UNDERLINE)) ? A_UNDERLINE : A_BOLD;
1530  }
1531  else if ((wc == '_') || (wc1 == '_'))
1532  {
1533  special |= A_UNDERLINE;
1534  wc = (wc1 == '_') ? wc : wc1;
1535  }
1536  else
1537  {
1538  /* special = 0; / * overstrike: nothing to do! */
1539  wc = wc1;
1540  }
1541 
1542  ch += k + k1;
1543  k = k2;
1544  mbstate = mbstate1;
1545  k1 = mbrtowc(&wc1, (char *) buf + ch + k, cnt - ch - k, &mbstate1);
1546  }
1547  }
1548 
1549  if (pa && ((flags & (MUTT_SHOWCOLOR | MUTT_SEARCH | MUTT_PAGER_MARKER)) ||
1550  special || last_special || pa->attr))
1551  {
1552  resolve_color(*line_info, n, vch, flags, special, pa);
1553  last_special = special;
1554  }
1555 
1556  /* no-break space, narrow no-break space */
1557  if (IsWPrint(wc) || (CharsetIsUtf8 && ((wc == 0x00A0) || (wc == 0x202F))))
1558  {
1559  if (wc == ' ')
1560  {
1561  space = ch;
1562  }
1563  t = wcwidth(wc);
1564  if (col + t > wrap_cols)
1565  break;
1566  col += t;
1567  if (pa)
1568  mutt_addwch(wc);
1569  }
1570  else if (wc == '\n')
1571  break;
1572  else if (wc == '\t')
1573  {
1574  space = ch;
1575  t = (col & ~7) + 8;
1576  if (t > wrap_cols)
1577  break;
1578  if (pa)
1579  for (; col < t; col++)
1580  addch(' ');
1581  else
1582  col = t;
1583  }
1584  else if ((wc < 0x20) || (wc == 0x7f))
1585  {
1586  if (col + 2 > wrap_cols)
1587  break;
1588  col += 2;
1589  if (pa)
1590  printw("^%c", ('@' + wc) & 0x7f);
1591  }
1592  else if (wc < 0x100)
1593  {
1594  if (col + 4 > wrap_cols)
1595  break;
1596  col += 4;
1597  if (pa)
1598  printw("\\%03o", wc);
1599  }
1600  else
1601  {
1602  if (col + 1 > wrap_cols)
1603  break;
1604  col += k;
1605  if (pa)
1606  addch(ReplacementChar);
1607  }
1608  }
1609  *pspace = space;
1610  *pcol = col;
1611  *pvch = vch;
1612  *pspecial = special;
1613  return ch;
1614 }
static int check_protected_header_marker(const char *p)
Check that the unique marker is present.
Definition: pager.c:932
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:160
#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:155
int mutt_window_wrap_cols(int width, short wrap)
Calculate the wrap column for a given screen width.
Definition: mutt_window.c:321
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:1268
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:1254
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:362
static int check_attachment_marker(const char *p)
Check that the unique marker is present.
Definition: pager.c:922
WHERE bool C_Markers
Config: Display a &#39;+&#39; at the beginning of wrapped lines in the pager.
Definition: globals.h:252
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:962

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

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

Print a line on screen.

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

Definition at line 1634 of file pager.c.

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

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

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

Reposition the pager's view up by n lines.

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

Definition at line 1911 of file pager.c.

1912 {
1913  while ((cur > 0) && (nlines > 0))
1914  {
1915  cur--;
1916  if (!hiding || (info[cur].type != MT_COLOR_QUOTED))
1917  nlines--;
1918  }
1919 
1920  return cur;
1921 }
Pager: quoted text.
Definition: mutt_curses.h:126

+ Here is the caller graph for this function:

void mutt_clear_pager_position ( void  )

Reset the pager's viewing position.

Definition at line 1926 of file pager.c.

1927 {
1928  TopLine = 0;
1929  OldEmail = NULL;
1930 }
static int TopLine
Definition: pager.c:211
static struct Email * OldEmail
Definition: pager.c:212

+ Here is the caller graph for this function:

static void pager_custom_redraw ( struct Menu pager_menu)
static

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

Definition at line 1935 of file pager.c.

1936 {
1937  struct PagerRedrawData *rd = pager_menu->redraw_data;
1938  char buf[1024];
1939 
1940  if (!rd)
1941  return;
1942 
1943  if (pager_menu->redraw & REDRAW_FULL)
1944  {
1945  NORMAL_COLOR;
1946  /* clear() doesn't optimize screen redraws */
1947  move(0, 0);
1948  clrtobot();
1949 
1950  if (IsEmail(rd->extra) && Context && ((Context->mailbox->vcount + 1) < C_PagerIndexLines))
1951  rd->indexlen = Context->mailbox->vcount + 1;
1952  else
1954 
1955  rd->indicator = rd->indexlen / 3;
1956 
1957  memcpy(rd->pager_window, MuttIndexWindow, sizeof(struct MuttWindow));
1958  memcpy(rd->pager_status_window, MuttStatusWindow, sizeof(struct MuttWindow));
1959  rd->index_status_window->rows = 0;
1960  rd->index_window->rows = 0;
1961 
1962  if (IsEmail(rd->extra) && (C_PagerIndexLines != 0))
1963  {
1964  memcpy(rd->index_window, MuttIndexWindow, sizeof(struct MuttWindow));
1965  rd->index_window->rows = (rd->indexlen > 0) ? rd->indexlen - 1 : 0;
1966 
1967  if (C_StatusOnTop)
1968  {
1969  memcpy(rd->index_status_window, MuttStatusWindow, sizeof(struct MuttWindow));
1970 
1971  memcpy(rd->pager_status_window, MuttIndexWindow, sizeof(struct MuttWindow));
1972  rd->pager_status_window->rows = 1;
1974 
1975  rd->pager_window->rows -=
1977  rd->pager_window->row_offset +=
1979  }
1980  else
1981  {
1982  memcpy(rd->index_status_window, MuttIndexWindow, sizeof(struct MuttWindow));
1983  rd->index_status_window->rows = 1;
1985 
1986  rd->pager_window->rows -=
1988  rd->pager_window->row_offset +=
1990  }
1991  }
1992 
1993  if (C_Help)
1994  {
1998  NORMAL_COLOR;
1999  }
2000 
2001  if (Resize)
2002  {
2004  if (rd->search_compiled)
2005  {
2006  int flags = mutt_mb_is_lower(rd->searchbuf) ? REG_ICASE : 0;
2007  const int err = REG_COMP(&rd->search_re, rd->searchbuf, REG_NEWLINE | flags);
2008  if (err != 0)
2009  {
2010  regerror(err, &rd->search_re, buf, sizeof(buf));
2011  mutt_error("%s", buf);
2012  rd->search_compiled = false;
2013  }
2014  else
2015  {
2016  rd->search_flag = MUTT_SEARCH;
2018  }
2019  }
2020  rd->lines = Resize->line;
2021  pager_menu->redraw |= REDRAW_FLOW;
2022 
2023  FREE(&Resize);
2024  }
2025 
2026  if (IsEmail(rd->extra) && (C_PagerIndexLines != 0))
2027  {
2028  if (!rd->index)
2029  {
2030  /* only allocate the space if/when we need the index.
2031  * Initialise the menu as per the main index */
2032  rd->index = mutt_menu_new(MENU_MAIN);
2034  rd->index->menu_color = index_color;
2035  rd->index->max = Context ? Context->mailbox->vcount : 0;
2036  rd->index->current = rd->extra->email->vnum;
2037  rd->index->indexwin = rd->index_window;
2038  rd->index->statuswin = rd->index_status_window;
2039  }
2040 
2041  NORMAL_COLOR;
2042  rd->index->pagelen = rd->index_window->rows;
2043 
2044  /* some fudge to work out whereabouts the indicator should go */
2045  if (rd->index->current - rd->indicator < 0)
2046  rd->index->top = 0;
2047  else if (rd->index->max - rd->index->current < rd->index->pagelen - rd->indicator)
2048  rd->index->top = rd->index->max - rd->index->pagelen;
2049  else
2050  rd->index->top = rd->index->current - rd->indicator;
2051 
2052  menu_redraw_index(rd->index);
2053  }
2054 
2055  pager_menu->redraw |= REDRAW_BODY | REDRAW_INDEX | REDRAW_STATUS;
2056 #ifdef USE_SIDEBAR
2057  pager_menu->redraw |= REDRAW_SIDEBAR;
2058 #endif
2059  mutt_show_error();
2060  }
2061 
2062  if (pager_menu->redraw & REDRAW_FLOW)
2063  {
2064  if (!(rd->flags & MUTT_PAGER_RETWINCH))
2065  {
2066  rd->lines = -1;
2067  for (int i = 0; i <= rd->topline; i++)
2068  if (!rd->line_info[i].continuation)
2069  rd->lines++;
2070  for (int i = 0; i < rd->max_line; i++)
2071  {
2072  rd->line_info[i].offset = 0;
2073  rd->line_info[i].type = -1;
2074  rd->line_info[i].continuation = 0;
2075  rd->line_info[i].chunks = 0;
2076  rd->line_info[i].search_cnt = -1;
2077  rd->line_info[i].quote = NULL;
2078 
2079  mutt_mem_realloc(&(rd->line_info[i].syntax), sizeof(struct Syntax));
2080  if (rd->search_compiled && rd->line_info[i].search)
2081  FREE(&(rd->line_info[i].search));
2082  }
2083 
2084  rd->last_line = 0;
2085  rd->topline = 0;
2086  }
2087  int i = -1;
2088  int j = -1;
2089  while (display_line(rd->fp, &rd->last_pos, &rd->line_info, ++i, &rd->last_line,
2090  &rd->max_line, rd->has_types | rd->search_flag | (rd->flags & MUTT_PAGER_NOWRAP),
2091  &rd->quote_list, &rd->q_level, &rd->force_redraw,
2092  &rd->search_re, rd->pager_window) == 0)
2093  {
2094  if (!rd->line_info[i].continuation && (++j == rd->lines))
2095  {
2096  rd->topline = i;
2097  if (!rd->search_flag)
2098  break;
2099  }
2100  }
2101  }
2102 
2103 #ifdef USE_SIDEBAR
2104  if (pager_menu->redraw & REDRAW_SIDEBAR)
2105  {
2106  menu_redraw_sidebar(pager_menu);
2107  }
2108 #endif
2109 
2110  if ((pager_menu->redraw & REDRAW_BODY) || (rd->topline != rd->oldtopline))
2111  {
2112  do
2113  {
2114  mutt_window_move(rd->pager_window, 0, 0);
2115  rd->curline = rd->topline;
2116  rd->oldtopline = rd->topline;
2117  rd->lines = 0;
2118  rd->force_redraw = false;
2119 
2120  while ((rd->lines < rd->pager_window->rows) &&
2121  (rd->line_info[rd->curline].offset <= rd->sb.st_size - 1))
2122  {
2123  if (display_line(rd->fp, &rd->last_pos, &rd->line_info, rd->curline,
2124  &rd->last_line, &rd->max_line,
2125  (rd->flags & MUTT_DISPLAYFLAGS) | rd->hide_quoted |
2126  rd->search_flag | (rd->flags & MUTT_PAGER_NOWRAP),
2127  &rd->quote_list, &rd->q_level, &rd->force_redraw,
2128  &rd->search_re, rd->pager_window) > 0)
2129  {
2130  rd->lines++;
2131  }
2132  rd->curline++;
2133  mutt_window_move(rd->pager_window, rd->lines, 0);
2134  }
2135  rd->last_offset = rd->line_info[rd->curline].offset;
2136  } while (rd->force_redraw);
2137 
2139  while (rd->lines < rd->pager_window->rows)
2140  {
2142  if (C_Tilde)
2143  addch('~');
2144  rd->lines++;
2145  mutt_window_move(rd->pager_window, rd->lines, 0);
2146  }
2147  NORMAL_COLOR;
2148 
2149  /* We are going to update the pager status bar, so it isn't
2150  * necessary to reset to normal color now. */
2151 
2152  pager_menu->redraw |= REDRAW_STATUS; /* need to update the % seen */
2153  }
2154 
2155  if (pager_menu->redraw & REDRAW_STATUS)
2156  {
2157  struct HdrFormatInfo hfi;
2158  char pager_progress_str[65]; /* Lots of space for translations */
2159 
2160  hfi.ctx = Context;
2161  hfi.mailbox = Context ? Context->mailbox : NULL;
2162  hfi.pager_progress = pager_progress_str;
2163 
2164  if (rd->last_pos < rd->sb.st_size - 1)
2165  {
2166  snprintf(pager_progress_str, sizeof(pager_progress_str), OFF_T_FMT "%%",
2167  (100 * rd->last_offset / rd->sb.st_size));
2168  }
2169  else
2170  {
2171  const char *msg = (rd->topline == 0) ?
2172  /* L10N: Status bar message: the entire email is visible in the pager */
2173  _("all") :
2174  /* L10N: Status bar message: the end of the email is visible in the pager */
2175  _("end");
2176  mutt_str_strfcpy(pager_progress_str, msg, sizeof(pager_progress_str));
2177  }
2178 
2179  /* print out the pager status bar */
2182 
2183  if (IsEmail(rd->extra) || IsMsgAttach(rd->extra))
2184  {
2185  size_t l1 = rd->pager_status_window->cols * MB_LEN_MAX;
2186  size_t l2 = sizeof(buf);
2187  hfi.email = (IsEmail(rd->extra)) ? rd->extra->email : rd->extra->body->email;
2188  mutt_make_string_info(buf, (l1 < l2) ? l1 : l2, rd->pager_status_window->cols,
2191  }
2192  else
2193  {
2194  char bn[256];
2195  snprintf(bn, sizeof(bn), "%s (%s)", rd->banner, pager_progress_str);
2196  mutt_draw_statusline(rd->pager_status_window->cols, bn, sizeof(bn));
2197  }
2198  NORMAL_COLOR;
2199  if (C_TsEnabled && TsSupported && rd->index)
2200  {
2201  menu_status_line(buf, sizeof(buf), rd->index, NONULL(C_TsStatusFormat));
2202  mutt_ts_status(buf);
2203  menu_status_line(buf, sizeof(buf), rd->index, NONULL(C_TsIconFormat));
2204  mutt_ts_icon(buf);
2205  }
2206  }
2207 
2208  if ((pager_menu->redraw & REDRAW_INDEX) && rd->index)
2209  {
2210  /* redraw the pager_index indicator, because the
2211  * flags for this message might have changed. */
2212  if (rd->index_window->rows > 0)
2214 
2215  /* print out the index status bar */
2216  menu_status_line(buf, sizeof(buf), rd->index, NONULL(C_StatusFormat));
2217 
2220  mutt_draw_statusline(rd->index_status_window->cols, buf, sizeof(buf));
2221  NORMAL_COLOR;
2222  }
2223 
2224  pager_menu->redraw = 0;
2225 }
struct Context * ctx
Definition: hdrline.h:47
The "current" mailbox.
Definition: context.h:36
WHERE bool C_StatusOnTop
Config: Display the status bar at the top.
Definition: globals.h:270
WHERE char * C_TsIconFormat
Config: printf-like format string for the terminal&#39;s icon title.
Definition: globals.h:154
#define REDRAW_FULL
Redraw everything.
Definition: mutt_menu.h:47
#define NONULL(x)
Definition: string2.h:37
const char * banner
Definition: pager.c:202
PagerFlags hide_quoted
Definition: pager.c:188
struct MuttWindow * MuttStatusWindow
Status Window.
Definition: mutt_window.c:41
PagerFlags search_flag
Definition: pager.c:200
#define MUTT_DISPLAYFLAGS
Definition: pager.h:60
short chunks
Definition: pager.c:142
Keep track when the pager needs redrawing.
Definition: pager.c:174
#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:195
void mutt_window_clrtoeol(struct MuttWindow *win)
Clear to the end of the line.
Definition: mutt_window.c:107
WHERE bool C_Help
Config: Display a help line with common key bindings.
Definition: globals.h:231
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:748
#define IsMsgAttach(pager)
Definition: pager.c:255
#define _(a)
Definition: message.h:28
const char * helpstr
Definition: pager.c:203
struct Line * line_info
Definition: pager.c:205
int index_color(int line)
Calculate the colour for a line of the index - Implements Menu::menu_color()
Definition: index.c:822
void menu_status_line(char *buf, size_t buflen, struct Menu *menu, const char *p)
Create the status line.
Definition: status.c:408
struct MuttWindow * MuttHelpWindow
Help Window.
Definition: mutt_window.c:39
struct Body * body
Current attachment.
Definition: pager.h:69
A division of the screen.
Definition: mutt_window.h:35
PagerFlags flags
Definition: pager.c:176
Index panel (list of emails)
Definition: keymap.h:77
bool search_back
Definition: pager.c:168
Highlighting for a line of text.
Definition: pager.c:127
WHERE char * C_StatusFormat
Config: printf-like format string for the index&#39;s status line.
Definition: globals.h:152
bool search_compiled
Definition: pager.c:167
short type
Definition: pager.c:140
#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:273
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:113
#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:1169
LOFF_T last_pos
Definition: pager.c:191
struct MuttWindow * index_status_window
Definition: pager.c:193
int line
Definition: pager.c:166
void * redraw_data
Definition: mutt_menu.h:152
struct Mailbox * mailbox
Definition: context.h:50
Data passed to index_format_str()
Definition: hdrline.h:45
int indexlen
Definition: pager.c:178
LOFF_T last_offset
Definition: pager.c:192
int has_types
Definition: pager.c:187
FILE * fp
Definition: pager.c:206
#define REG_COMP(preg, regex, cflags)
Compile a regular expression.
Definition: regex3.h:52
short continuation
Definition: pager.c:141
bool force_redraw
Definition: pager.c:186
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:1523
int oldtopline
Definition: pager.c:180
struct Pager * extra
Definition: pager.c:177
struct QClass * quote
Definition: pager.c:146
short search_cnt
Definition: pager.c:143
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:199
struct Syntax * syntax
Definition: pager.c:144
struct MuttWindow * MuttIndexWindow
Index Window.
Definition: mutt_window.c:40
struct MuttWindow * pager_window
Definition: pager.c:196
struct MuttWindow * indexwin
Definition: mutt_menu.h:95
struct MuttWindow * index_window
Definition: pager.c:194
int top
entry that is the top of the current page
Definition: mutt_menu.h:110
int max_line
Definition: pager.c:182
size_t mutt_str_strfcpy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:750
int last_line
Definition: pager.c:183
int vnum
Virtual message number.
Definition: email.h:89
int pagelen
number of entries per screen
Definition: mutt_menu.h:92
bool TsSupported
Terminal Setting is supported.
Definition: terminal.c:42
#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:188
WHERE char * C_TsStatusFormat
Config: printf-like format string for the terminal&#39;s status (window title)
Definition: globals.h:153
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:197
struct QClass * quote_list
Definition: pager.c:190
#define IsEmail(pager)
Definition: pager.c:257
int indicator
the indicator line of the PI
Definition: pager.c:179
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:204
#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:39
#define FREE(x)
Definition: memory.h:40
Status bar.
Definition: mutt_curses.h:129
struct Syntax * search
Definition: pager.c:145
void mutt_ts_icon(char *str)
Set the icon in the terminal title bar.
Definition: terminal.c:117
bool C_Tilde
Config: Character to pad blank lines in the pager.
Definition: pager.c:97
void mutt_show_error(void)
Show the user an error message.
Definition: curs_lib.c:485
Keep track of screen resizing.
Definition: pager.c:164
void mutt_ts_status(char *str)
Set the text of the terminal title bar.
Definition: terminal.c:103
struct stat sb
Definition: pager.c:207
int current
current entry
Definition: mutt_menu.h:87
LOFF_T offset
Definition: pager.c:139
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:1634
void mutt_draw_statusline(int cols, const char *buf, size_t buflen)
Draw a highlighted status bar.
Definition: index.c:851
short C_PagerIndexLines
Config: Number of index lines to display above the pager.
Definition: pager.c:91
WHERE char * C_PagerFormat
Config: printf-like format string for the pager&#39;s status bar.
Definition: globals.h:140
regex_t search_re
Definition: pager.c:198
bool search_back
Definition: pager.c:201

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

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

Display a file, or help, in a window.

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

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

Definition at line 2242 of file pager.c.

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

+ Here is the caller graph for this function:

Variable Documentation

bool C_AllowAnsi

Config: Allow ANSI colour codes in rich text messages.

Definition at line 88 of file pager.c.

bool C_HeaderColorPartial

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

Definition at line 89 of file pager.c.

short C_PagerContext

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

Definition at line 90 of file pager.c.

short C_PagerIndexLines

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

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

short C_SearchContext

Config: Context to display around search matches.

Definition at line 93 of file pager.c.

short C_SkipQuotedOffset

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

Definition at line 94 of file pager.c.

bool C_SmartWrap

Config: Wrap text at word boundaries.

Definition at line 95 of file pager.c.

struct Regex* C_Smileys

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

Definition at line 96 of file pager.c.

bool C_Tilde

Config: Character to pad blank lines in the pager.

Definition at line 97 of file pager.c.

int TopLine = 0
static

Definition at line 211 of file pager.c.

struct Email* OldEmail = NULL
static

Definition at line 212 of file pager.c.

bool InHelp = false
static

Definition at line 214 of file pager.c.

int braille_line = -1
static

Definition at line 216 of file pager.c.

int braille_col = -1
static

Definition at line 217 of file pager.c.

struct Resize* Resize = NULL
static

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

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

Definition at line 223 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 224 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 227 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 234 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 243 of file pager.c.