NeoMutt  2021-02-05-666-ge300cd
Teaching an old dog new tricks
DOXYGEN
lib.h File Reference

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

#include "config.h"
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
+ Include dependency graph for lib.h:
+ This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  PagerData
 Data to be displayed by PagerView. More...
 
struct  PagerView
 Paged view into some data. More...
 

Macros

#define MUTT_PAGER_NO_FLAGS   0
 No flags are set. More...
 
#define MUTT_SHOWFLAT   (1 << 0)
 Show characters (used for displaying help) More...
 
#define MUTT_SHOWCOLOR   (1 << 1)
 Show characters in color otherwise don't show characters. More...
 
#define MUTT_HIDE   (1 << 2)
 Don't show quoted text. More...
 
#define MUTT_SEARCH   (1 << 3)
 Resolve search patterns. More...
 
#define MUTT_TYPES   (1 << 4)
 Compute line's type. More...
 
#define MUTT_SHOW   (MUTT_SHOWCOLOR | MUTT_SHOWFLAT)
 
#define MUTT_PAGER_NSKIP   (1 << 5)
 Preserve whitespace with smartwrap. More...
 
#define MUTT_PAGER_MARKER   (1 << 6)
 Use markers if option is set. More...
 
#define MUTT_PAGER_RETWINCH   (1 << 7)
 Need reformatting on SIGWINCH. More...
 
#define MUTT_PAGER_ATTACHMENT   (1 << 8)
 Attachments may exist. More...
 
#define MUTT_PAGER_NOWRAP   (1 << 9)
 Format for term width, ignore $wrap. More...
 
#define MUTT_PAGER_LOGS   (1 << 10)
 Logview mode. More...
 
#define MUTT_PAGER_BOTTOM   (1 << 11)
 Start at the bottom. More...
 
#define MUTT_PAGER_MESSAGE   (MUTT_SHOWCOLOR | MUTT_PAGER_MARKER)
 
#define MUTT_DISPLAYFLAGS   (MUTT_SHOW | MUTT_PAGER_NSKIP | MUTT_PAGER_MARKER | MUTT_PAGER_LOGS)
 
#define NT_PAGER_NO_FLAGS   0
 No flags are set. More...
 
#define NT_PAGER_CONFIG   (1 << 0)
 Config subset has changed. More...
 
#define NT_PAGER_CONTEXT   (1 << 1)
 Context has changed. More...
 
#define NT_PAGER_ACCOUNT   (1 << 2)
 Account has changed. More...
 
#define NT_PAGER_MAILBOX   (1 << 3)
 Mailbox has changed. More...
 
#define NT_PAGER_EMAIL   (1 << 4)
 Email has changed. More...
 
#define NT_PAGER_CLOSING   (1 << 5)
 The Pager is about to close. More...
 
#define NT_PAGER_SUBSET   (1 << 6)
 Config Subset has changed. More...
 

Typedefs

typedef uint16_t PagerFlags
 Flags for mutt_pager(), e.g. MUTT_SHOWFLAT. More...
 
typedef uint8_t NotifyPager
 Flags, e.g. NT_PAGER_ACCOUNT. More...
 

Enumerations

enum  PagerMode {
  PAGER_MODE_UNKNOWN = 0, PAGER_MODE_EMAIL, PAGER_MODE_ATTACH, PAGER_MODE_ATTACH_E,
  PAGER_MODE_HELP, PAGER_MODE_OTHER, PAGER_MODE_MAX
}
 Determine the behaviour of the Pager. More...
 

Functions

int mutt_pager (struct PagerView *pview)
 Display an email, attachment, or help, in a window. More...
 
int mutt_do_pager (struct PagerView *pview, struct Email *e)
 Display some page-able text to the user (help or attachment) More...
 
void mutt_buffer_strip_formatting (struct Buffer *dest, const char *src, bool strip_markers)
 Removes ANSI and backspace formatting. More...
 
struct MuttWindowppanel_new (bool status_on_top, struct IndexSharedData *shared)
 Create the Windows for the Pager panel. More...
 
struct MuttWindowpager_window_new (struct MuttWindow *parent, struct IndexSharedData *shared, struct PagerPrivateData *priv)
 Create a new Pager Window (list of Emails) More...
 
void mutt_clear_pager_position (void)
 Reset the pager's viewing position. More...
 

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 lib.h.

Macro Definition Documentation

◆ MUTT_PAGER_NO_FLAGS

#define MUTT_PAGER_NO_FLAGS   0

No flags are set.

Definition at line 54 of file lib.h.

◆ MUTT_SHOWFLAT

#define MUTT_SHOWFLAT   (1 << 0)

Show characters (used for displaying help)

Definition at line 55 of file lib.h.

◆ MUTT_SHOWCOLOR

#define MUTT_SHOWCOLOR   (1 << 1)

Show characters in color otherwise don't show characters.

Definition at line 56 of file lib.h.

◆ MUTT_HIDE

#define MUTT_HIDE   (1 << 2)

Don't show quoted text.

Definition at line 57 of file lib.h.

◆ MUTT_SEARCH

#define MUTT_SEARCH   (1 << 3)

Resolve search patterns.

Definition at line 58 of file lib.h.

◆ MUTT_TYPES

#define MUTT_TYPES   (1 << 4)

Compute line's type.

Definition at line 59 of file lib.h.

◆ MUTT_SHOW

#define MUTT_SHOW   (MUTT_SHOWCOLOR | MUTT_SHOWFLAT)

Definition at line 60 of file lib.h.

◆ MUTT_PAGER_NSKIP

#define MUTT_PAGER_NSKIP   (1 << 5)

Preserve whitespace with smartwrap.

Definition at line 63 of file lib.h.

◆ MUTT_PAGER_MARKER

#define MUTT_PAGER_MARKER   (1 << 6)

Use markers if option is set.

Definition at line 64 of file lib.h.

◆ MUTT_PAGER_RETWINCH

#define MUTT_PAGER_RETWINCH   (1 << 7)

Need reformatting on SIGWINCH.

Definition at line 65 of file lib.h.

◆ MUTT_PAGER_ATTACHMENT

#define MUTT_PAGER_ATTACHMENT   (1 << 8)

Attachments may exist.

Definition at line 66 of file lib.h.

◆ MUTT_PAGER_NOWRAP

#define MUTT_PAGER_NOWRAP   (1 << 9)

Format for term width, ignore $wrap.

Definition at line 67 of file lib.h.

◆ MUTT_PAGER_LOGS

#define MUTT_PAGER_LOGS   (1 << 10)

Logview mode.

Definition at line 68 of file lib.h.

◆ MUTT_PAGER_BOTTOM

#define MUTT_PAGER_BOTTOM   (1 << 11)

Start at the bottom.

Definition at line 69 of file lib.h.

◆ MUTT_PAGER_MESSAGE

#define MUTT_PAGER_MESSAGE   (MUTT_SHOWCOLOR | MUTT_PAGER_MARKER)

Definition at line 70 of file lib.h.

◆ MUTT_DISPLAYFLAGS

#define MUTT_DISPLAYFLAGS   (MUTT_SHOW | MUTT_PAGER_NSKIP | MUTT_PAGER_MARKER | MUTT_PAGER_LOGS)

Definition at line 72 of file lib.h.

◆ NT_PAGER_NO_FLAGS

#define NT_PAGER_NO_FLAGS   0

No flags are set.

Definition at line 168 of file lib.h.

◆ NT_PAGER_CONFIG

#define NT_PAGER_CONFIG   (1 << 0)

Config subset has changed.

Definition at line 169 of file lib.h.

◆ NT_PAGER_CONTEXT

#define NT_PAGER_CONTEXT   (1 << 1)

Context has changed.

Definition at line 170 of file lib.h.

◆ NT_PAGER_ACCOUNT

#define NT_PAGER_ACCOUNT   (1 << 2)

Account has changed.

Definition at line 171 of file lib.h.

◆ NT_PAGER_MAILBOX

#define NT_PAGER_MAILBOX   (1 << 3)

Mailbox has changed.

Definition at line 172 of file lib.h.

◆ NT_PAGER_EMAIL

#define NT_PAGER_EMAIL   (1 << 4)

Email has changed.

Definition at line 173 of file lib.h.

◆ NT_PAGER_CLOSING

#define NT_PAGER_CLOSING   (1 << 5)

The Pager is about to close.

Definition at line 174 of file lib.h.

◆ NT_PAGER_SUBSET

#define NT_PAGER_SUBSET   (1 << 6)

Config Subset has changed.

Definition at line 175 of file lib.h.

Typedef Documentation

◆ PagerFlags

typedef uint16_t PagerFlags

Flags for mutt_pager(), e.g. MUTT_SHOWFLAT.

Definition at line 51 of file lib.h.

◆ NotifyPager

typedef uint8_t NotifyPager

Flags, e.g. NT_PAGER_ACCOUNT.

Definition at line 167 of file lib.h.

Enumeration Type Documentation

◆ PagerMode

enum PagerMode

Determine the behaviour of the Pager.

Enumerator
PAGER_MODE_UNKNOWN 

A default and invalid mode, should never be used.

PAGER_MODE_EMAIL 

Pager is invoked via 1st path. The mime part is selected automatically.

PAGER_MODE_ATTACH 

Pager is invoked via 2nd path. A user-selected attachment (mime part or a nested email) will be shown.

PAGER_MODE_ATTACH_E 

A special case of PAGER_MODE_ATTACH - attachment is a full-blown email message.

PAGER_MODE_HELP 

Pager is invoked via 3rd path to show help.

PAGER_MODE_OTHER 

Pager is invoked via 3rd path. Non-email content is likely to be shown.

PAGER_MODE_MAX 

Another invalid mode, should never be used.

Definition at line 127 of file lib.h.

128 {
129  PAGER_MODE_UNKNOWN = 0,
130 
136 
138 };
A default and invalid mode, should never be used.
Definition: lib.h:129
A special case of PAGER_MODE_ATTACH - attachment is a full-blown email message.
Definition: lib.h:133
Pager is invoked via 3rd path to show help.
Definition: lib.h:134
Pager is invoked via 1st path. The mime part is selected automatically.
Definition: lib.h:131
Another invalid mode, should never be used.
Definition: lib.h:137
Pager is invoked via 2nd path. A user-selected attachment (mime part or a nested email) will be shown...
Definition: lib.h:132
Pager is invoked via 3rd path. Non-email content is likely to be shown.
Definition: lib.h:135

Function Documentation

◆ mutt_pager()

int mutt_pager ( struct PagerView pview)

Display an email, attachment, or help, in a window.

Parameters
pviewPager view settings
Return values
0Success
-1Error

This pager is actually not so simple as it once was. But it will be again. Currently it operates in 3 modes:

  • viewing messages. (PAGER_MODE_EMAIL)
  • viewing attachments. (PAGER_MODE_ATTACH)
  • viewing other stuff (e.g. help). (PAGER_MODE_OTHER) These can be distinguished by PagerMode in PagerView. Data is not yet polymorphic and is fused into a single struct (PagerData). Different elements of PagerData are expected to be present depending on the mode:
  • PAGER_MODE_EMAIL expects data->email and not expects data->body
  • PAGER_MODE_ATTACH expects data->email and data->body special sub-case of this mode is viewing attached email message it is recognized by presence of data->fp and data->body->email
  • PAGER_MODE_OTHER does not expect data->email or data->body

Definition at line 2360 of file dlg_pager.c.

2361 {
2362  //===========================================================================
2363  // ACT 1 - Ensure sanity of the caller and determine the mode
2364  //===========================================================================
2365  assert(pview);
2366  assert((pview->mode > PAGER_MODE_UNKNOWN) && (pview->mode < PAGER_MODE_MAX));
2367  assert(pview->pdata); // view can't exist in a vacuum
2368  assert(pview->win_pager);
2369  assert(pview->win_pbar);
2370 
2371  struct MuttWindow *dlg = dialog_find(pview->win_pager);
2372  struct IndexSharedData *shared = dlg->wdata;
2373 
2374  switch (pview->mode)
2375  {
2376  case PAGER_MODE_EMAIL:
2377  // This case was previously identified by IsEmail macro
2378  // we expect data to contain email and not contain body
2379  // We also expect email to always belong to some mailbox
2380  assert(shared->ctx);
2381  assert(shared->mailbox);
2382  assert(shared->email);
2383  assert(!pview->pdata->body);
2384  break;
2385 
2386  case PAGER_MODE_ATTACH:
2387  // this case was previously identified by IsAttach and IsMsgAttach
2388  // macros, we expect data to contain:
2389  // - body (viewing regular attachment)
2390  // - email
2391  // - fp and body->email in special case of viewing an attached email.
2392  assert(shared->email); // This should point to the top level email
2393  assert(pview->pdata->body);
2394  if (pview->pdata->fp && pview->pdata->body->email)
2395  {
2396  // Special case: attachment is a full-blown email message.
2397  // Yes, emails can contain other emails.
2398  pview->mode = PAGER_MODE_ATTACH_E;
2399  }
2400  break;
2401 
2402  case PAGER_MODE_HELP:
2403  case PAGER_MODE_OTHER:
2404  assert(!shared->ctx);
2405  assert(!shared->email);
2406  assert(!pview->pdata->body);
2407  break;
2408 
2409  case PAGER_MODE_UNKNOWN:
2410  case PAGER_MODE_MAX:
2411  default:
2412  // Unexpected mode. Catch fire and explode.
2413  // This *should* happen if mode is PAGER_MODE_ATTACH_E, since
2414  // we do not expect any caller to pass it to us.
2415  assert(false);
2416  break;
2417  }
2418 
2419  //===========================================================================
2420  // ACT 2 - Declare, initialize local variables, read config, etc.
2421  //===========================================================================
2422 
2423  //---------- reading config values needed now--------------------------------
2424  const short c_pager_index_lines =
2425  cs_subset_number(NeoMutt->sub, "pager_index_lines");
2426  const short c_pager_read_delay =
2427  cs_subset_number(NeoMutt->sub, "pager_read_delay");
2428 
2429  //---------- local variables ------------------------------------------------
2430  char buf[1024] = { 0 };
2431  int op = 0;
2432  int rc = -1;
2433  int searchctx = 0;
2434  int index_space = shared->mailbox ? MIN(c_pager_index_lines, shared->mailbox->vcount) :
2435  c_pager_index_lines;
2436  bool first = true;
2437  bool wrapped = false;
2438  enum MailboxType mailbox_type = shared->mailbox ? shared->mailbox->type : MUTT_UNKNOWN;
2439  uint64_t delay_read_timestamp = 0;
2440 
2441  struct PagerPrivateData *priv = pview->win_pager->parent->wdata;
2442  {
2443  // Wipe any previous state info
2444  struct Menu *menu = priv->menu;
2445  memset(priv, 0, sizeof(*priv));
2446  priv->menu = menu;
2447  priv->win_pbar = pview->win_pbar;
2448  }
2449 
2450  //---------- setup flags ----------------------------------------------------
2451  if (!(pview->flags & MUTT_SHOWCOLOR))
2452  pview->flags |= MUTT_SHOWFLAT;
2453 
2454  if (pview->mode == PAGER_MODE_EMAIL && !shared->email->read)
2455  {
2456  shared->ctx->msg_in_pager = shared->email->msgno;
2457  priv->win_pbar->actions |= WA_RECALC;
2458  if (c_pager_read_delay == 0)
2459  {
2460  mutt_set_flag(shared->mailbox, shared->email, MUTT_READ, true);
2461  }
2462  else
2463  {
2464  delay_read_timestamp = mutt_date_epoch_ms() + (1000 * c_pager_read_delay);
2465  }
2466  }
2467  //---------- setup help menu ------------------------------------------------
2468  pview->win_pager->help_data = pager_resolve_help_mapping(pview->mode, mailbox_type);
2469  pview->win_pager->help_menu = MENU_PAGER;
2470 
2471  //---------- initialize redraw pdata -----------------------------------------
2473  priv->pview = pview;
2474  priv->indexlen = c_pager_index_lines;
2475  priv->indicator = priv->indexlen / 3;
2476  priv->max_line = LINES; // number of lines on screen, from curses
2477  priv->line_info = mutt_mem_calloc(priv->max_line, sizeof(struct Line));
2478  priv->fp = fopen(pview->pdata->fname, "r");
2479  priv->has_types =
2480  ((pview->mode == PAGER_MODE_EMAIL) || (pview->flags & MUTT_SHOWCOLOR)) ?
2481  MUTT_TYPES :
2482  0; // main message or rfc822 attachment
2483 
2484  for (size_t i = 0; i < priv->max_line; i++)
2485  {
2486  priv->line_info[i].type = -1;
2487  priv->line_info[i].search_cnt = -1;
2488  priv->line_info[i].syntax = mutt_mem_malloc(sizeof(struct TextSyntax));
2489  (priv->line_info[i].syntax)[0].first = -1;
2490  (priv->line_info[i].syntax)[0].last = -1;
2491  }
2492 
2493  // ---------- try to open the pdata file -------------------------------------
2494  if (!priv->fp)
2495  {
2496  mutt_perror(pview->pdata->fname);
2497  return -1;
2498  }
2499 
2500  if (stat(pview->pdata->fname, &priv->sb) != 0)
2501  {
2502  mutt_perror(pview->pdata->fname);
2503  mutt_file_fclose(&priv->fp);
2504  return -1;
2505  }
2506  unlink(pview->pdata->fname);
2507 
2508  //---------- restore global state if needed ---------------------------------
2509  while ((pview->mode == PAGER_MODE_EMAIL) && (OldEmail == shared->email) && // are we "resuming" to the same Email?
2510  (TopLine != priv->topline) && // is saved offset different?
2511  (priv->line_info[priv->curline].offset < (priv->sb.st_size - 1)))
2512  {
2514  pager_custom_redraw(priv);
2515  // trick user, as if nothing happened
2516  // scroll down to previosly saved offset
2517  priv->topline =
2518  ((TopLine - priv->topline) > priv->lines) ? priv->topline + priv->lines : TopLine;
2519  }
2520 
2521  TopLine = 0;
2522  OldEmail = NULL;
2523 
2524  //---------- show windows, set focus and visibility --------------------------
2525  if (priv->pview->win_index)
2526  {
2527  priv->menu = priv->pview->win_index->wdata;
2529  priv->pview->win_index->req_rows = index_space;
2531  window_set_visible(priv->pview->win_index->parent, (index_space > 0));
2532  }
2533  window_set_visible(priv->pview->win_pager->parent, true);
2534  mutt_window_reflow(dlg);
2535  window_set_focus(pview->win_pager);
2536 
2537  //---------- jump to the bottom if requested ------------------------------
2538  if (pview->flags & MUTT_PAGER_BOTTOM)
2539  {
2540  jump_to_bottom(priv, pview);
2541  }
2542 
2543  //-------------------------------------------------------------------------
2544  // ACT 3: Read user input and decide what to do with it
2545  // ...but also do a whole lot of other things.
2546  //-------------------------------------------------------------------------
2547  while (op != -1)
2548  {
2549  if (check_read_delay(&delay_read_timestamp))
2550  {
2551  mutt_set_flag(shared->mailbox, shared->email, MUTT_READ, true);
2552  }
2554 
2556  window_redraw(NULL);
2557  pager_custom_redraw(priv);
2558 
2559  const bool c_braille_friendly =
2560  cs_subset_bool(NeoMutt->sub, "braille_friendly");
2561  if (c_braille_friendly)
2562  {
2563  if (braille_row != -1)
2564  {
2566  braille_row = -1;
2567  }
2568  }
2569  else
2570  mutt_window_move(priv->pview->win_pbar, priv->pview->win_pager->state.cols - 1, 0);
2571 
2572  // force redraw of the screen at every iteration of the event loop
2573  mutt_refresh();
2574 
2575  //-------------------------------------------------------------------------
2576  // Check if information in the status bar needs an update
2577  // This is done because pager is a single-threaded application, which
2578  // tries to emulate concurrency.
2579  //-------------------------------------------------------------------------
2580  bool do_new_mail = false;
2581  if (shared->mailbox && !OptAttachMsg)
2582  {
2583  int oldcount = shared->mailbox->msg_count;
2584  /* check for new mail */
2585  enum MxStatus check = mx_mbox_check(shared->mailbox);
2586  if (check == MX_STATUS_ERROR)
2587  {
2588  if (!shared->mailbox || mutt_buffer_is_empty(&shared->mailbox->pathbuf))
2589  {
2590  /* fatal error occurred */
2592  break;
2593  }
2594  }
2595  else if ((check == MX_STATUS_NEW_MAIL) || (check == MX_STATUS_REOPENED) ||
2596  (check == MX_STATUS_FLAGS))
2597  {
2598  /* notify user of newly arrived mail */
2599  if (check == MX_STATUS_NEW_MAIL)
2600  {
2601  for (size_t i = oldcount; i < shared->mailbox->msg_count; i++)
2602  {
2603  struct Email *e = shared->mailbox->emails[i];
2604 
2605  if (e && !e->read)
2606  {
2607  mutt_message(_("New mail in this mailbox"));
2608  do_new_mail = true;
2609  break;
2610  }
2611  }
2612  }
2613 
2614  if ((check == MX_STATUS_NEW_MAIL) || (check == MX_STATUS_REOPENED))
2615  {
2616  if (priv->menu && shared->mailbox)
2617  {
2618  /* After the mailbox has been updated, selection might be invalid */
2619  int index = menu_get_index(priv->menu);
2620  menu_set_index(priv->menu, MIN(index, MAX(shared->mailbox->msg_count - 1, 0)));
2621  index = menu_get_index(priv->menu);
2622  struct Email *e = mutt_get_virt_email(shared->mailbox, index);
2623  if (!e)
2624  continue;
2625 
2626  bool verbose = shared->mailbox->verbose;
2627  shared->mailbox->verbose = false;
2628  mutt_update_index(priv->menu, shared->ctx, check, oldcount, shared);
2629  shared->mailbox->verbose = verbose;
2630 
2631  priv->menu->max = shared->mailbox->vcount;
2632 
2633  /* If these header pointers don't match, then our email may have
2634  * been deleted. Make the pointer safe, then leave the pager.
2635  * This have a unpleasant behaviour to close the pager even the
2636  * deleted message is not the opened one, but at least it's safe. */
2637  e = mutt_get_virt_email(shared->mailbox, index);
2638  if (shared->email != e)
2639  {
2640  shared->email = e;
2641  break;
2642  }
2643  }
2644 
2646  OptSearchInvalid = true;
2647  }
2648  }
2649 
2650  if (mutt_mailbox_notify(shared->mailbox) || do_new_mail)
2651  {
2652  const bool c_beep_new = cs_subset_bool(NeoMutt->sub, "beep_new");
2653  if (c_beep_new)
2654  mutt_beep(true);
2655  const char *const c_new_mail_command =
2656  cs_subset_string(NeoMutt->sub, "new_mail_command");
2657  if (c_new_mail_command)
2658  {
2659  char cmd[1024];
2660  menu_status_line(cmd, sizeof(cmd), shared, priv->menu, sizeof(cmd),
2661  NONULL(c_new_mail_command));
2662  if (mutt_system(cmd) != 0)
2663  mutt_error(_("Error running \"%s\""), cmd);
2664  }
2665  }
2666  }
2667  //-------------------------------------------------------------------------
2668 
2669  if (SigWinch)
2670  {
2671  SigWinch = false;
2673  clearok(stdscr, true); /* force complete redraw */
2675 
2676  if (pview->flags & MUTT_PAGER_RETWINCH)
2677  {
2678  /* Store current position. */
2679  priv->lines = -1;
2680  for (size_t i = 0; i <= priv->topline; i++)
2681  if (!priv->line_info[i].continuation)
2682  priv->lines++;
2683 
2684  Resize = mutt_mem_malloc(sizeof(struct Resize));
2685 
2686  Resize->line = priv->lines;
2688  Resize->search_back = priv->search_back;
2689 
2690  op = -1;
2691  rc = OP_REFORMAT_WINCH;
2692  }
2693  else
2694  {
2695  /* note: mutt_resize_screen() -> mutt_window_reflow() sets
2696  * MENU_REDRAW_FULL and MENU_REDRAW_FLOW */
2697  op = 0;
2698  }
2699  continue;
2700  }
2701  //-------------------------------------------------------------------------
2702  // Finally, read user's key press
2703  //-------------------------------------------------------------------------
2704  // km_dokey() reads not only user's key strokes, but also a MacroBuffer
2705  // MacroBuffer may contain OP codes of the operations.
2706  // MacroBuffer is global
2707  // OP codes inserted into the MacroBuffer by various functions.
2708  // One of such functions is `mutt_enter_command()`
2709  // Some OP codes are not handled by pager, they cause pager to quit returning
2710  // OP code to index. Index handles the operation and then restarts pager
2711  op = km_dokey(MENU_PAGER);
2712 
2713  if (op >= 0)
2714  {
2715  mutt_clear_error();
2716  mutt_debug(LL_DEBUG1, "Got op %s (%d)\n", OpStrings[op][0], op);
2717  }
2719 
2720  if (op < 0)
2721  {
2722  op = 0;
2724  continue;
2725  }
2726 
2727  rc = op;
2728 
2729  switch (op)
2730  {
2731  //=======================================================================
2732 
2733  case OP_EXIT:
2734  rc = -1;
2735  op = -1;
2736  break;
2737 
2738  //=======================================================================
2739 
2740  case OP_QUIT:
2741  {
2742  const enum QuadOption c_quit = cs_subset_quad(NeoMutt->sub, "quit");
2743  if (query_quadoption(c_quit, _("Quit NeoMutt?")) == MUTT_YES)
2744  {
2745  /* avoid prompting again in the index menu */
2746  cs_subset_str_native_set(NeoMutt->sub, "quit", MUTT_YES, NULL);
2747  op = -1;
2748  }
2749  break;
2750  }
2751 
2752  //=======================================================================
2753 
2754  case OP_NEXT_PAGE:
2755  {
2756  const bool c_pager_stop = cs_subset_bool(NeoMutt->sub, "pager_stop");
2757  if (priv->line_info[priv->curline].offset < (priv->sb.st_size - 1))
2758  {
2759  const short c_pager_context =
2760  cs_subset_number(NeoMutt->sub, "pager_context");
2761  priv->topline = up_n_lines(c_pager_context, priv->line_info,
2762  priv->curline, priv->hide_quoted);
2763  }
2764  else if (c_pager_stop)
2765  {
2766  /* emulate "less -q" and don't go on to the next message. */
2767  mutt_message(_("Bottom of message is shown"));
2768  }
2769  else
2770  {
2771  /* end of the current message, so display the next message. */
2772  rc = OP_MAIN_NEXT_UNDELETED;
2773  op = -1;
2774  }
2775  break;
2776  }
2777 
2778  //=======================================================================
2779 
2780  case OP_PREV_PAGE:
2781  if (priv->topline == 0)
2782  {
2783  mutt_message(_("Top of message is shown"));
2784  }
2785  else
2786  {
2787  const short c_pager_context =
2788  cs_subset_number(NeoMutt->sub, "pager_context");
2789  priv->topline =
2790  up_n_lines(priv->pview->win_pager->state.rows - c_pager_context,
2791  priv->line_info, priv->topline, priv->hide_quoted);
2792  }
2793  break;
2794 
2795  //=======================================================================
2796 
2797  case OP_NEXT_LINE:
2798  if (priv->line_info[priv->curline].offset < (priv->sb.st_size - 1))
2799  {
2800  priv->topline++;
2801  if (priv->hide_quoted)
2802  {
2803  while ((priv->line_info[priv->topline].type == MT_COLOR_QUOTED) &&
2804  (priv->topline < priv->last_line))
2805  {
2806  priv->topline++;
2807  }
2808  }
2809  }
2810  else
2811  mutt_message(_("Bottom of message is shown"));
2812  break;
2813 
2814  //=======================================================================
2815 
2816  case OP_PREV_LINE:
2817  if (priv->topline)
2818  priv->topline = up_n_lines(1, priv->line_info, priv->topline, priv->hide_quoted);
2819  else
2820  mutt_message(_("Top of message is shown"));
2821  break;
2822 
2823  //=======================================================================
2824 
2825  case OP_PAGER_TOP:
2826  if (priv->topline)
2827  priv->topline = 0;
2828  else
2829  mutt_message(_("Top of message is shown"));
2830  break;
2831 
2832  //=======================================================================
2833 
2834  case OP_HALF_UP:
2835  if (priv->topline)
2836  {
2837  priv->topline = up_n_lines(priv->pview->win_pager->state.rows / 2 +
2838  (priv->pview->win_pager->state.rows % 2),
2839  priv->line_info, priv->topline, priv->hide_quoted);
2840  }
2841  else
2842  mutt_message(_("Top of message is shown"));
2843  break;
2844 
2845  //=======================================================================
2846 
2847  case OP_HALF_DOWN:
2848  {
2849  const bool c_pager_stop = cs_subset_bool(NeoMutt->sub, "pager_stop");
2850  if (priv->line_info[priv->curline].offset < (priv->sb.st_size - 1))
2851  {
2852  priv->topline = up_n_lines(priv->pview->win_pager->state.rows / 2,
2853  priv->line_info, priv->curline, priv->hide_quoted);
2854  }
2855  else if (c_pager_stop)
2856  {
2857  /* emulate "less -q" and don't go on to the next message. */
2858  mutt_message(_("Bottom of message is shown"));
2859  }
2860  else
2861  {
2862  /* end of the current message, so display the next message. */
2863  rc = OP_MAIN_NEXT_UNDELETED;
2864  op = -1;
2865  }
2866  break;
2867  }
2868 
2869  //=======================================================================
2870 
2871  case OP_SEARCH_NEXT:
2872  case OP_SEARCH_OPPOSITE:
2873  if (priv->search_compiled)
2874  {
2875  const short c_search_context =
2876  cs_subset_number(NeoMutt->sub, "search_context");
2877  wrapped = false;
2878 
2879  if (c_search_context < priv->pview->win_pager->state.rows)
2880  searchctx = c_search_context;
2881  else
2882  searchctx = 0;
2883 
2884  search_next:
2885  if ((!priv->search_back && (op == OP_SEARCH_NEXT)) ||
2886  (priv->search_back && (op == OP_SEARCH_OPPOSITE)))
2887  {
2888  /* searching forward */
2889  int i;
2890  for (i = wrapped ? 0 : priv->topline + searchctx + 1; i < priv->last_line; i++)
2891  {
2892  if ((!priv->hide_quoted || (priv->line_info[i].type != MT_COLOR_QUOTED)) &&
2893  !priv->line_info[i].continuation && (priv->line_info[i].search_cnt > 0))
2894  {
2895  break;
2896  }
2897  }
2898 
2899  const bool c_wrap_search =
2900  cs_subset_bool(NeoMutt->sub, "wrap_search");
2901  if (i < priv->last_line)
2902  priv->topline = i;
2903  else if (wrapped || !c_wrap_search)
2904  mutt_error(_("Not found"));
2905  else
2906  {
2907  mutt_message(_("Search wrapped to top"));
2908  wrapped = true;
2909  goto search_next;
2910  }
2911  }
2912  else
2913  {
2914  /* searching backward */
2915  int i;
2916  for (i = wrapped ? priv->last_line : priv->topline + searchctx - 1; i >= 0; i--)
2917  {
2918  if ((!priv->hide_quoted ||
2919  (priv->has_types && (priv->line_info[i].type != MT_COLOR_QUOTED))) &&
2920  !priv->line_info[i].continuation && (priv->line_info[i].search_cnt > 0))
2921  {
2922  break;
2923  }
2924  }
2925 
2926  const bool c_wrap_search =
2927  cs_subset_bool(NeoMutt->sub, "wrap_search");
2928  if (i >= 0)
2929  priv->topline = i;
2930  else if (wrapped || !c_wrap_search)
2931  mutt_error(_("Not found"));
2932  else
2933  {
2934  mutt_message(_("Search wrapped to bottom"));
2935  wrapped = true;
2936  goto search_next;
2937  }
2938  }
2939 
2940  if (priv->line_info[priv->topline].search_cnt > 0)
2941  {
2942  priv->search_flag = MUTT_SEARCH;
2943  /* give some context for search results */
2944  if (priv->topline - searchctx > 0)
2945  priv->topline -= searchctx;
2946  }
2947 
2948  break;
2949  }
2950  /* no previous search pattern */
2951  /* fallthrough */
2952  //=======================================================================
2953 
2954  case OP_SEARCH:
2955  case OP_SEARCH_REVERSE:
2956  mutt_str_copy(buf, priv->searchbuf, sizeof(buf));
2957  if (mutt_get_field(((op == OP_SEARCH) || (op == OP_SEARCH_NEXT)) ?
2958  _("Search for: ") :
2959  _("Reverse search for: "),
2960  buf, sizeof(buf), MUTT_CLEAR | MUTT_PATTERN, false,
2961  NULL, NULL) != 0)
2962  {
2963  break;
2964  }
2965 
2966  if (strcmp(buf, priv->searchbuf) == 0)
2967  {
2968  if (priv->search_compiled)
2969  {
2970  /* do an implicit search-next */
2971  if (op == OP_SEARCH)
2972  op = OP_SEARCH_NEXT;
2973  else
2974  op = OP_SEARCH_OPPOSITE;
2975 
2976  wrapped = false;
2977  goto search_next;
2978  }
2979  }
2980 
2981  if (buf[0] == '\0')
2982  break;
2983 
2984  mutt_str_copy(priv->searchbuf, buf, sizeof(priv->searchbuf));
2985 
2986  /* leave search_back alone if op == OP_SEARCH_NEXT */
2987  if (op == OP_SEARCH)
2988  priv->search_back = false;
2989  else if (op == OP_SEARCH_REVERSE)
2990  priv->search_back = true;
2991 
2992  if (priv->search_compiled)
2993  {
2994  regfree(&priv->search_re);
2995  for (size_t i = 0; i < priv->last_line; i++)
2996  {
2997  FREE(&(priv->line_info[i].search));
2998  priv->line_info[i].search_cnt = -1;
2999  }
3000  }
3001 
3002  uint16_t rflags = mutt_mb_is_lower(priv->searchbuf) ? REG_ICASE : 0;
3003  int err = REG_COMP(&priv->search_re, priv->searchbuf, REG_NEWLINE | rflags);
3004  if (err != 0)
3005  {
3006  regerror(err, &priv->search_re, buf, sizeof(buf));
3007  mutt_error("%s", buf);
3008  for (size_t i = 0; i < priv->max_line; i++)
3009  {
3010  /* cleanup */
3011  FREE(&(priv->line_info[i].search));
3012  priv->line_info[i].search_cnt = -1;
3013  }
3014  priv->search_flag = 0;
3015  priv->search_compiled = false;
3016  }
3017  else
3018  {
3019  priv->search_compiled = true;
3020  /* update the search pointers */
3021  int line_num = 0;
3022  while (display_line(priv->fp, &priv->last_pos, &priv->line_info,
3023  line_num, &priv->last_line, &priv->max_line,
3024  MUTT_SEARCH | (pview->flags & MUTT_PAGER_NSKIP) |
3025  (pview->flags & MUTT_PAGER_NOWRAP),
3026  &priv->quote_list, &priv->q_level, &priv->force_redraw,
3027  &priv->search_re, priv->pview->win_pager) == 0)
3028  {
3029  line_num++;
3030  }
3031 
3032  if (!priv->search_back)
3033  {
3034  /* searching forward */
3035  int i;
3036  for (i = priv->topline; i < priv->last_line; i++)
3037  {
3038  if ((!priv->hide_quoted || (priv->line_info[i].type != MT_COLOR_QUOTED)) &&
3039  !priv->line_info[i].continuation && (priv->line_info[i].search_cnt > 0))
3040  {
3041  break;
3042  }
3043  }
3044 
3045  if (i < priv->last_line)
3046  priv->topline = i;
3047  }
3048  else
3049  {
3050  /* searching backward */
3051  int i;
3052  for (i = priv->topline; i >= 0; i--)
3053  {
3054  if ((!priv->hide_quoted || (priv->line_info[i].type != MT_COLOR_QUOTED)) &&
3055  !priv->line_info[i].continuation && (priv->line_info[i].search_cnt > 0))
3056  {
3057  break;
3058  }
3059  }
3060 
3061  if (i >= 0)
3062  priv->topline = i;
3063  }
3064 
3065  if (priv->line_info[priv->topline].search_cnt == 0)
3066  {
3067  priv->search_flag = 0;
3068  mutt_error(_("Not found"));
3069  }
3070  else
3071  {
3072  const short c_search_context =
3073  cs_subset_number(NeoMutt->sub, "search_context");
3074  priv->search_flag = MUTT_SEARCH;
3075  /* give some context for search results */
3076  if (c_search_context < priv->pview->win_pager->state.rows)
3077  searchctx = c_search_context;
3078  else
3079  searchctx = 0;
3080  if (priv->topline - searchctx > 0)
3081  priv->topline -= searchctx;
3082  }
3083  }
3085  break;
3086 
3087  //=======================================================================
3088 
3089  case OP_SEARCH_TOGGLE:
3090  if (priv->search_compiled)
3091  {
3092  priv->search_flag ^= MUTT_SEARCH;
3094  }
3095  break;
3096 
3097  //=======================================================================
3098 
3099  case OP_SORT:
3100  case OP_SORT_REVERSE:
3101  if (!assert_pager_mode(pview->mode == PAGER_MODE_EMAIL))
3102  break;
3103  if (mutt_select_sort(op == OP_SORT_REVERSE))
3104  {
3105  OptNeedResort = true;
3106  op = -1;
3107  rc = OP_DISPLAY_MESSAGE;
3108  }
3109  break;
3110 
3111  //=======================================================================
3112 
3113  case OP_HELP:
3114  if (pview->mode == PAGER_MODE_HELP)
3115  {
3116  /* don't let the user enter the help-menu from the help screen! */
3117  mutt_error(_("Help is currently being shown"));
3118  break;
3119  }
3122  break;
3123 
3124  //=======================================================================
3125 
3126  case OP_PAGER_HIDE_QUOTED:
3127  if (!priv->has_types)
3128  break;
3129 
3130  priv->hide_quoted ^= MUTT_HIDE;
3131  if (priv->hide_quoted && (priv->line_info[priv->topline].type == MT_COLOR_QUOTED))
3132  priv->topline = up_n_lines(1, priv->line_info, priv->topline, priv->hide_quoted);
3133  else
3135  break;
3136 
3137  //=======================================================================
3138 
3139  case OP_PAGER_SKIP_QUOTED:
3140  {
3141  if (!priv->has_types)
3142  break;
3143 
3144  const short c_skip_quoted_context =
3145  cs_subset_number(NeoMutt->sub, "pager_skip_quoted_context");
3146  int dretval = 0;
3147  int new_topline = priv->topline;
3148  int num_quoted = 0;
3149 
3150  /* In a header? Skip all the email headers, and done */
3151  if (mutt_color_is_header(priv->line_info[new_topline].type))
3152  {
3153  while (((new_topline < priv->last_line) ||
3154  (0 == (dretval = display_line(
3155  priv->fp, &priv->last_pos, &priv->line_info,
3156  new_topline, &priv->last_line, &priv->max_line,
3157  MUTT_TYPES | (pview->flags & MUTT_PAGER_NOWRAP),
3158  &priv->quote_list, &priv->q_level, &priv->force_redraw,
3159  &priv->search_re, priv->pview->win_pager)))) &&
3160  mutt_color_is_header(priv->line_info[new_topline].type))
3161  {
3162  new_topline++;
3163  }
3164  priv->topline = new_topline;
3165  break;
3166  }
3167 
3168  /* Already in the body? Skip past previous "context" quoted lines */
3169  if (c_skip_quoted_context > 0)
3170  {
3171  while (((new_topline < priv->last_line) ||
3172  (0 == (dretval = display_line(
3173  priv->fp, &priv->last_pos, &priv->line_info,
3174  new_topline, &priv->last_line, &priv->max_line,
3175  MUTT_TYPES | (pview->flags & MUTT_PAGER_NOWRAP),
3176  &priv->quote_list, &priv->q_level, &priv->force_redraw,
3177  &priv->search_re, priv->pview->win_pager)))) &&
3178  (priv->line_info[new_topline].type == MT_COLOR_QUOTED))
3179  {
3180  new_topline++;
3181  num_quoted++;
3182  }
3183 
3184  if (dretval < 0)
3185  {
3186  mutt_error(_("No more unquoted text after quoted text"));
3187  break;
3188  }
3189  }
3190 
3191  if (num_quoted <= c_skip_quoted_context)
3192  {
3193  num_quoted = 0;
3194 
3195  while (((new_topline < priv->last_line) ||
3196  (0 == (dretval = display_line(
3197  priv->fp, &priv->last_pos, &priv->line_info,
3198  new_topline, &priv->last_line, &priv->max_line,
3199  MUTT_TYPES | (pview->flags & MUTT_PAGER_NOWRAP),
3200  &priv->quote_list, &priv->q_level, &priv->force_redraw,
3201  &priv->search_re, priv->pview->win_pager)))) &&
3202  (priv->line_info[new_topline].type != MT_COLOR_QUOTED))
3203  {
3204  new_topline++;
3205  }
3206 
3207  if (dretval < 0)
3208  {
3209  mutt_error(_("No more quoted text"));
3210  break;
3211  }
3212 
3213  while (((new_topline < priv->last_line) ||
3214  (0 == (dretval = display_line(
3215  priv->fp, &priv->last_pos, &priv->line_info,
3216  new_topline, &priv->last_line, &priv->max_line,
3217  MUTT_TYPES | (pview->flags & MUTT_PAGER_NOWRAP),
3218  &priv->quote_list, &priv->q_level, &priv->force_redraw,
3219  &priv->search_re, priv->pview->win_pager)))) &&
3220  (priv->line_info[new_topline].type == MT_COLOR_QUOTED))
3221  {
3222  new_topline++;
3223  num_quoted++;
3224  }
3225 
3226  if (dretval < 0)
3227  {
3228  mutt_error(_("No more unquoted text after quoted text"));
3229  break;
3230  }
3231  }
3232  priv->topline = new_topline - MIN(c_skip_quoted_context, num_quoted);
3233  break;
3234  }
3235 
3236  //=======================================================================
3237 
3238  case OP_PAGER_SKIP_HEADERS:
3239  {
3240  if (!priv->has_types)
3241  break;
3242 
3243  int dretval = 0;
3244  int new_topline = 0;
3245 
3246  while (((new_topline < priv->last_line) ||
3247  (0 == (dretval = display_line(
3248  priv->fp, &priv->last_pos, &priv->line_info, new_topline, &priv->last_line,
3249  &priv->max_line, MUTT_TYPES | (pview->flags & MUTT_PAGER_NOWRAP),
3250  &priv->quote_list, &priv->q_level, &priv->force_redraw,
3251  &priv->search_re, priv->pview->win_pager)))) &&
3252  mutt_color_is_header(priv->line_info[new_topline].type))
3253  {
3254  new_topline++;
3255  }
3256 
3257  if (dretval < 0)
3258  {
3259  /* L10N: Displayed if <skip-headers> is invoked in the pager, but
3260  there is no text past the headers.
3261  (I don't think this is actually possible in Mutt's code, but
3262  display some kind of message in case it somehow occurs.) */
3263  mutt_warning(_("No text past headers"));
3264  break;
3265  }
3266  priv->topline = new_topline;
3267  break;
3268  }
3269 
3270  //=======================================================================
3271 
3272  case OP_PAGER_BOTTOM: /* move to the end of the file */
3273  if (!jump_to_bottom(priv, pview))
3274  {
3275  mutt_message(_("Bottom of message is shown"));
3276  }
3277  break;
3278 
3279  //=======================================================================
3280 
3281  case OP_REDRAW:
3282  mutt_window_reflow(NULL);
3283  clearok(stdscr, true);
3285  break;
3286 
3287  //=======================================================================
3288 
3289  case OP_NULL:
3291  break;
3292 
3293  //=======================================================================
3294  // The following are operations on the current message rather than
3295  // adjusting the view of the message.
3296  //=======================================================================
3297  case OP_BOUNCE_MESSAGE:
3298  {
3299  if (!assert_pager_mode((pview->mode == PAGER_MODE_EMAIL) ||
3300  (pview->mode == PAGER_MODE_ATTACH_E)))
3301  {
3302  break;
3303  }
3305  break;
3306  if (pview->mode == PAGER_MODE_ATTACH_E)
3307  {
3308  mutt_attach_bounce(shared->mailbox, pview->pdata->fp,
3309  pview->pdata->actx, pview->pdata->body);
3310  }
3311  else
3312  {
3313  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3314  emaillist_add_email(&el, shared->email);
3315  ci_bounce_message(shared->mailbox, &el);
3316  emaillist_clear(&el);
3317  }
3318  break;
3319  }
3320 
3321  //=======================================================================
3322 
3323  case OP_RESEND:
3324  if (!assert_pager_mode((pview->mode == PAGER_MODE_EMAIL) ||
3325  (pview->mode == PAGER_MODE_ATTACH_E)))
3326  {
3327  break;
3328  }
3330  break;
3331  if (pview->mode == PAGER_MODE_ATTACH_E)
3332  {
3333  mutt_attach_resend(pview->pdata->fp, ctx_mailbox(shared->ctx),
3334  pview->pdata->actx, pview->pdata->body);
3335  }
3336  else
3337  {
3338  mutt_resend_message(NULL, ctx_mailbox(shared->ctx), shared->email,
3339  NeoMutt->sub);
3340  }
3342  break;
3343 
3344  //=======================================================================
3345 
3346  case OP_COMPOSE_TO_SENDER:
3347  if (!assert_pager_mode((pview->mode == PAGER_MODE_EMAIL) ||
3348  (pview->mode == PAGER_MODE_ATTACH_E)))
3349  {
3350  break;
3351  }
3353  break;
3354  if (pview->mode == PAGER_MODE_ATTACH_E)
3355  {
3356  mutt_attach_mail_sender(pview->pdata->fp, shared->email,
3357  pview->pdata->actx, pview->pdata->body);
3358  }
3359  else
3360  {
3361  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3362  emaillist_add_email(&el, shared->email);
3363 
3364  mutt_send_message(SEND_TO_SENDER, NULL, NULL,
3365  ctx_mailbox(shared->ctx), &el, NeoMutt->sub);
3366  emaillist_clear(&el);
3367  }
3369  break;
3370 
3371  //=======================================================================
3372 
3373  case OP_CHECK_TRADITIONAL:
3374  if (!assert_pager_mode(pview->mode == PAGER_MODE_EMAIL))
3375  break;
3376  if (!(WithCrypto & APPLICATION_PGP))
3377  break;
3378  if (!(shared->email->security & PGP_TRADITIONAL_CHECKED))
3379  {
3380  op = -1;
3381  rc = OP_CHECK_TRADITIONAL;
3382  }
3383  break;
3384 
3385  //=======================================================================
3386 
3387  case OP_CREATE_ALIAS:
3388  if (!assert_pager_mode((pview->mode == PAGER_MODE_EMAIL) ||
3389  (pview->mode == PAGER_MODE_ATTACH_E)))
3390  {
3391  break;
3392  }
3393  struct AddressList *al = NULL;
3394  if (pview->mode == PAGER_MODE_ATTACH_E)
3395  al = mutt_get_address(pview->pdata->body->email->env, NULL);
3396  else
3397  al = mutt_get_address(shared->email->env, NULL);
3398  alias_create(al, NeoMutt->sub);
3399  break;
3400 
3401  //=======================================================================
3402 
3403  case OP_PURGE_MESSAGE:
3404  case OP_DELETE:
3405  {
3406  if (!assert_pager_mode(pview->mode == PAGER_MODE_EMAIL))
3407  break;
3408  if (!assert_mailbox_writable(shared->mailbox))
3409  break;
3410  /* L10N: CHECK_ACL */
3412  _("Can't delete message")))
3413  {
3414  break;
3415  }
3416 
3417  mutt_set_flag(shared->mailbox, shared->email, MUTT_DELETE, true);
3418  mutt_set_flag(shared->mailbox, shared->email, MUTT_PURGE, (op == OP_PURGE_MESSAGE));
3419  const bool c_delete_untag =
3420  cs_subset_bool(NeoMutt->sub, "delete_untag");
3421  if (c_delete_untag)
3422  mutt_set_flag(shared->mailbox, shared->email, MUTT_TAG, false);
3424  const bool c_resolve = cs_subset_bool(NeoMutt->sub, "resolve");
3425  if (c_resolve)
3426  {
3427  op = -1;
3428  rc = OP_MAIN_NEXT_UNDELETED;
3429  }
3430  break;
3431  }
3432 
3433  //=======================================================================
3434 
3435  case OP_MAIN_SET_FLAG:
3436  case OP_MAIN_CLEAR_FLAG:
3437  {
3438  if (!assert_pager_mode(pview->mode == PAGER_MODE_EMAIL))
3439  break;
3440  if (!assert_mailbox_writable(shared->mailbox))
3441  break;
3442 
3443  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3444  emaillist_add_email(&el, shared->email);
3445 
3446  if (mutt_change_flag(shared->mailbox, &el, (op == OP_MAIN_SET_FLAG)) == 0)
3448  const bool c_resolve = cs_subset_bool(NeoMutt->sub, "resolve");
3449  if (shared->email->deleted && c_resolve)
3450  {
3451  op = -1;
3452  rc = OP_MAIN_NEXT_UNDELETED;
3453  }
3454  emaillist_clear(&el);
3455  break;
3456  }
3457 
3458  //=======================================================================
3459 
3460  case OP_DELETE_THREAD:
3461  case OP_DELETE_SUBTHREAD:
3462  case OP_PURGE_THREAD:
3463  {
3464  if (!assert_pager_mode(pview->mode == PAGER_MODE_EMAIL))
3465  break;
3466  if (!assert_mailbox_writable(shared->mailbox))
3467  break;
3468  /* L10N: CHECK_ACL */
3469  /* L10N: Due to the implementation details we do not know whether we
3470  delete zero, 1, 12, ... messages. So in English we use
3471  "messages". Your language might have other means to express this. */
3473  _("Can't delete messages")))
3474  {
3475  break;
3476  }
3477 
3478  int subthread = (op == OP_DELETE_SUBTHREAD);
3479  int r = mutt_thread_set_flag(shared->mailbox, shared->email, MUTT_DELETE, 1, subthread);
3480  if (r == -1)
3481  break;
3482  if (op == OP_PURGE_THREAD)
3483  {
3484  r = mutt_thread_set_flag(shared->mailbox, shared->email, MUTT_PURGE, true, subthread);
3485  if (r == -1)
3486  break;
3487  }
3488 
3489  const bool c_delete_untag =
3490  cs_subset_bool(NeoMutt->sub, "delete_untag");
3491  if (c_delete_untag)
3492  mutt_thread_set_flag(shared->mailbox, shared->email, MUTT_TAG, 0, subthread);
3493  const bool c_resolve = cs_subset_bool(NeoMutt->sub, "resolve");
3494  if (c_resolve)
3495  {
3496  rc = OP_MAIN_NEXT_UNDELETED;
3497  op = -1;
3498  }
3499 
3500  if (!c_resolve &&
3501  (cs_subset_number(NeoMutt->sub, "pager_index_lines") != 0))
3503  else
3505 
3506  break;
3507  }
3508 
3509  //=======================================================================
3510 
3511  case OP_DISPLAY_ADDRESS:
3512  if (!assert_pager_mode((pview->mode == PAGER_MODE_EMAIL) ||
3513  (pview->mode == PAGER_MODE_ATTACH_E)))
3514  {
3515  break;
3516  }
3517  if (pview->mode == PAGER_MODE_ATTACH_E)
3519  else
3520  mutt_display_address(shared->email->env);
3521  break;
3522 
3523  //=======================================================================
3524 
3525  case OP_ENTER_COMMAND:
3528 
3529  if (OptNeedResort)
3530  {
3531  OptNeedResort = false;
3532  if (!assert_pager_mode(pview->mode == PAGER_MODE_EMAIL))
3533  break;
3534  OptNeedResort = true;
3535  }
3536 
3537  if ((priv->redraw & MENU_REDRAW_FLOW) && (pview->flags & MUTT_PAGER_RETWINCH))
3538  {
3539  op = -1;
3540  rc = OP_REFORMAT_WINCH;
3541  continue;
3542  }
3543 
3544  op = 0;
3545  break;
3546 
3547  //=======================================================================
3548 
3549  case OP_FLAG_MESSAGE:
3550  {
3551  if (!assert_pager_mode(pview->mode == PAGER_MODE_EMAIL))
3552  break;
3553  if (!assert_mailbox_writable(shared->mailbox))
3554  break;
3555  /* L10N: CHECK_ACL */
3556  if (!assert_mailbox_permissions(shared->mailbox, MUTT_ACL_WRITE, "Can't flag message"))
3557  break;
3558 
3559  mutt_set_flag(shared->mailbox, shared->email, MUTT_FLAG, !shared->email->flagged);
3561  const bool c_resolve = cs_subset_bool(NeoMutt->sub, "resolve");
3562  if (c_resolve)
3563  {
3564  op = -1;
3565  rc = OP_MAIN_NEXT_UNDELETED;
3566  }
3567  break;
3568  }
3569 
3570  //=======================================================================
3571 
3572  case OP_PIPE:
3573  if (!assert_pager_mode((pview->mode == PAGER_MODE_EMAIL) ||
3574  (pview->mode == PAGER_MODE_ATTACH)))
3575  {
3576  break;
3577  }
3578  if (pview->mode == PAGER_MODE_ATTACH)
3579  {
3580  mutt_pipe_attachment_list(pview->pdata->actx, pview->pdata->fp, false,
3581  pview->pdata->body, false);
3582  }
3583  else
3584  {
3585  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3586  el_add_tagged(&el, shared->ctx, shared->email, false);
3587  mutt_pipe_message(shared->mailbox, &el);
3588  emaillist_clear(&el);
3589  }
3590  break;
3591 
3592  //=======================================================================
3593 
3594  case OP_PRINT:
3595  if (!assert_pager_mode((pview->mode == PAGER_MODE_EMAIL) ||
3596  (pview->mode == PAGER_MODE_ATTACH)))
3597  {
3598  break;
3599  }
3600  if (pview->mode == PAGER_MODE_ATTACH)
3601  {
3602  mutt_print_attachment_list(pview->pdata->actx, pview->pdata->fp,
3603  false, pview->pdata->body);
3604  }
3605  else
3606  {
3607  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3608  el_add_tagged(&el, shared->ctx, shared->email, false);
3609  mutt_print_message(shared->mailbox, &el);
3610  emaillist_clear(&el);
3611  }
3612  break;
3613 
3614  //=======================================================================
3615 
3616  case OP_MAIL:
3617  if (!assert_pager_mode(pview->mode == PAGER_MODE_EMAIL))
3618  break;
3620  break;
3621 
3622  mutt_send_message(SEND_NO_FLAGS, NULL, NULL, ctx_mailbox(shared->ctx),
3623  NULL, NeoMutt->sub);
3625  break;
3626 
3627  //=======================================================================
3628 
3629 #ifdef USE_NNTP
3630  case OP_POST:
3631  {
3632  if (!assert_pager_mode(pview->mode == PAGER_MODE_EMAIL))
3633  break;
3635  break;
3636  const enum QuadOption c_post_moderated =
3637  cs_subset_quad(NeoMutt->sub, "post_moderated");
3638  if ((shared->mailbox->type == MUTT_NNTP) &&
3639  !((struct NntpMboxData *) shared->mailbox->mdata)->allowed && (query_quadoption(c_post_moderated, _("Posting to this group not allowed, may be moderated. Continue?")) != MUTT_YES))
3640  {
3641  break;
3642  }
3643 
3644  mutt_send_message(SEND_NEWS, NULL, NULL, ctx_mailbox(shared->ctx), NULL,
3645  NeoMutt->sub);
3647  break;
3648  }
3649 
3650  //=======================================================================
3651 
3652  case OP_FORWARD_TO_GROUP:
3653  {
3654  if (!assert_pager_mode((pview->mode == PAGER_MODE_EMAIL) ||
3655  (pview->mode == PAGER_MODE_ATTACH_E)))
3656  {
3657  break;
3658  }
3660  break;
3661  const enum QuadOption c_post_moderated =
3662  cs_subset_quad(NeoMutt->sub, "post_moderated");
3663  if ((shared->mailbox->type == MUTT_NNTP) &&
3664  !((struct NntpMboxData *) shared->mailbox->mdata)->allowed && (query_quadoption(c_post_moderated, _("Posting to this group not allowed, may be moderated. Continue?")) != MUTT_YES))
3665  {
3666  break;
3667  }
3668  if (pview->mode == PAGER_MODE_ATTACH_E)
3669  {
3670  mutt_attach_forward(pview->pdata->fp, shared->email,
3671  pview->pdata->actx, pview->pdata->body, SEND_NEWS);
3672  }
3673  else
3674  {
3675  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3676  emaillist_add_email(&el, shared->email);
3677 
3679  ctx_mailbox(shared->ctx), &el, NeoMutt->sub);
3680  emaillist_clear(&el);
3681  }
3683  break;
3684  }
3685 
3686  //=======================================================================
3687 
3688  case OP_FOLLOWUP:
3689  if (!assert_pager_mode((pview->mode == PAGER_MODE_EMAIL) ||
3690  (pview->mode == PAGER_MODE_ATTACH_E)))
3691  {
3692  break;
3693  }
3695  break;
3696 
3697  char *followup_to = NULL;
3698  if (pview->mode == PAGER_MODE_ATTACH_E)
3699  followup_to = pview->pdata->body->email->env->followup_to;
3700  else
3701  followup_to = shared->email->env->followup_to;
3702 
3703  const enum QuadOption c_followup_to_poster =
3704  cs_subset_quad(NeoMutt->sub, "followup_to_poster");
3705  if (!followup_to || !mutt_istr_equal(followup_to, "poster") ||
3706  (query_quadoption(c_followup_to_poster,
3707  _("Reply by mail as poster prefers?")) != MUTT_YES))
3708  {
3709  const enum QuadOption c_post_moderated =
3710  cs_subset_quad(NeoMutt->sub, "post_moderated");
3711  if ((shared->mailbox->type == MUTT_NNTP) &&
3712  !((struct NntpMboxData *) shared->mailbox->mdata)->allowed && (query_quadoption(c_post_moderated, _("Posting to this group not allowed, may be moderated. Continue?")) != MUTT_YES))
3713  {
3714  break;
3715  }
3716  if (pview->mode == PAGER_MODE_ATTACH_E)
3717  {
3718  mutt_attach_reply(pview->pdata->fp, shared->mailbox, shared->email,
3719  pview->pdata->actx, pview->pdata->body, SEND_NEWS | SEND_REPLY);
3720  }
3721  else
3722  {
3723  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3724  emaillist_add_email(&el, shared->email);
3725  mutt_send_message(SEND_NEWS | SEND_REPLY, NULL, NULL,
3726  ctx_mailbox(shared->ctx), &el, NeoMutt->sub);
3727  emaillist_clear(&el);
3728  }
3730  break;
3731  }
3732 
3733  //=======================================================================
3734 
3735 #endif
3736  /* fallthrough */
3737  case OP_REPLY:
3738  case OP_GROUP_REPLY:
3739  case OP_GROUP_CHAT_REPLY:
3740  case OP_LIST_REPLY:
3741  {
3742  if (!assert_pager_mode((pview->mode == PAGER_MODE_EMAIL) ||
3743  (pview->mode == PAGER_MODE_ATTACH_E)))
3744  {
3745  break;
3746  }
3748  break;
3749 
3750  SendFlags replyflags = SEND_REPLY;
3751  if (op == OP_GROUP_REPLY)
3752  replyflags |= SEND_GROUP_REPLY;
3753  else if (op == OP_GROUP_CHAT_REPLY)
3754  replyflags |= SEND_GROUP_CHAT_REPLY;
3755  else if (op == OP_LIST_REPLY)
3756  replyflags |= SEND_LIST_REPLY;
3757 
3758  if (pview->mode == PAGER_MODE_ATTACH_E)
3759  {
3760  mutt_attach_reply(pview->pdata->fp, shared->mailbox, shared->email,
3761  pview->pdata->actx, pview->pdata->body, replyflags);
3762  }
3763  else
3764  {
3765  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3766  emaillist_add_email(&el, shared->email);
3767  mutt_send_message(replyflags, NULL, NULL, ctx_mailbox(shared->ctx),
3768  &el, NeoMutt->sub);
3769  emaillist_clear(&el);
3770  }
3772  break;
3773  }
3774 
3775  //=======================================================================
3776 
3777  case OP_RECALL_MESSAGE:
3778  {
3779  if (!assert_pager_mode(pview->mode == PAGER_MODE_EMAIL))
3780  break;
3782  break;
3783  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3784  emaillist_add_email(&el, shared->email);
3785 
3786  mutt_send_message(SEND_POSTPONED, NULL, NULL, ctx_mailbox(shared->ctx),
3787  &el, NeoMutt->sub);
3788  emaillist_clear(&el);
3790  break;
3791  }
3792 
3793  //=======================================================================
3794 
3795  case OP_FORWARD_MESSAGE:
3796  if (!assert_pager_mode((pview->mode == PAGER_MODE_EMAIL) ||
3797  (pview->mode == PAGER_MODE_ATTACH_E)))
3798  {
3799  break;
3800  }
3802  break;
3803  if (pview->mode == PAGER_MODE_ATTACH_E)
3804  {
3805  mutt_attach_forward(pview->pdata->fp, shared->email, pview->pdata->actx,
3806  pview->pdata->body, SEND_NO_FLAGS);
3807  }
3808  else
3809  {
3810  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3811  emaillist_add_email(&el, shared->email);
3812 
3813  mutt_send_message(SEND_FORWARD, NULL, NULL, ctx_mailbox(shared->ctx),
3814  &el, NeoMutt->sub);
3815  emaillist_clear(&el);
3816  }
3818  break;
3819 
3820  //=======================================================================
3821 
3822  case OP_DECRYPT_SAVE:
3823  if (!WithCrypto)
3824  {
3825  op = -1;
3826  break;
3827  }
3828  /* fallthrough */
3829  //=======================================================================
3830 
3831  case OP_SAVE:
3832  if (pview->mode == PAGER_MODE_ATTACH)
3833  {
3834  mutt_save_attachment_list(pview->pdata->actx, pview->pdata->fp, false,
3835  pview->pdata->body, shared->email, NULL);
3836  break;
3837  }
3838  /* fallthrough */
3839  //=======================================================================
3840 
3841  case OP_COPY_MESSAGE:
3842  case OP_DECODE_SAVE:
3843  case OP_DECODE_COPY:
3844  case OP_DECRYPT_COPY:
3845  {
3846  if (!(WithCrypto != 0) && (op == OP_DECRYPT_COPY))
3847  {
3848  op = -1;
3849  break;
3850  }
3851  if (!assert_pager_mode(pview->mode == PAGER_MODE_EMAIL))
3852  break;
3853  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3854  emaillist_add_email(&el, shared->email);
3855 
3856  const enum MessageSaveOpt save_opt =
3857  ((op == OP_SAVE) || (op == OP_DECODE_SAVE) || (op == OP_DECRYPT_SAVE)) ?
3858  SAVE_MOVE :
3859  SAVE_COPY;
3860 
3861  enum MessageTransformOpt transform_opt =
3862  ((op == OP_DECODE_SAVE) || (op == OP_DECODE_COPY)) ? TRANSFORM_DECODE :
3863  ((op == OP_DECRYPT_SAVE) || (op == OP_DECRYPT_COPY)) ? TRANSFORM_DECRYPT :
3865 
3866  const int rc2 = mutt_save_message(shared->mailbox, &el, save_opt, transform_opt);
3867  if ((rc2 == 0) && (save_opt == SAVE_MOVE))
3868  {
3869  const bool c_resolve = cs_subset_bool(NeoMutt->sub, "resolve");
3870  if (c_resolve)
3871  {
3872  op = -1;
3873  rc = OP_MAIN_NEXT_UNDELETED;
3874  }
3875  else
3877  }
3878  emaillist_clear(&el);
3879  break;
3880  }
3881 
3882  //=======================================================================
3883 
3884  case OP_SHELL_ESCAPE:
3885  if (mutt_shell_escape())
3886  {
3888  }
3889  break;
3890 
3891  //=======================================================================
3892 
3893  case OP_TAG:
3894  {
3895  if (!assert_pager_mode(pview->mode == PAGER_MODE_EMAIL))
3896  break;
3897  mutt_set_flag(shared->mailbox, shared->email, MUTT_TAG, !shared->email->tagged);
3898 
3900  const bool c_resolve = cs_subset_bool(NeoMutt->sub, "resolve");
3901  if (c_resolve)
3902  {
3903  op = -1;
3904  rc = OP_NEXT_ENTRY;
3905  }
3906  break;
3907  }
3908 
3909  //=======================================================================
3910 
3911  case OP_TOGGLE_NEW:
3912  {
3913  if (!assert_pager_mode(pview->mode == PAGER_MODE_EMAIL))
3914  break;
3915  if (!assert_mailbox_writable(shared->mailbox))
3916  break;
3917  /* L10N: CHECK_ACL */
3918  if (!assert_mailbox_permissions(shared->mailbox, MUTT_ACL_SEEN, _("Can't toggle new")))
3919  break;
3920 
3921  if (shared->email->read || shared->email->old)
3922  mutt_set_flag(shared->mailbox, shared->email, MUTT_NEW, true);
3923  else if (!first || (delay_read_timestamp != 0))
3924  mutt_set_flag(shared->mailbox, shared->email, MUTT_READ, true);
3925  delay_read_timestamp = 0;
3926  first = false;
3927  shared->ctx->msg_in_pager = -1;
3928  priv->win_pbar->actions |= WA_RECALC;
3930  const bool c_resolve = cs_subset_bool(NeoMutt->sub, "resolve");
3931  if (c_resolve)
3932  {
3933  op = -1;
3934  rc = OP_MAIN_NEXT_UNDELETED;
3935  }
3936  break;
3937  }
3938 
3939  //=======================================================================
3940 
3941  case OP_UNDELETE:
3942  {
3943  if (!assert_pager_mode(pview->mode == PAGER_MODE_EMAIL))
3944  break;
3945  if (!assert_mailbox_writable(shared->mailbox))
3946  break;
3947  /* L10N: CHECK_ACL */
3949  _("Can't undelete message")))
3950  {
3951  break;
3952  }
3953 
3954  mutt_set_flag(shared->mailbox, shared->email, MUTT_DELETE, false);
3955  mutt_set_flag(shared->mailbox, shared->email, MUTT_PURGE, false);
3957  const bool c_resolve = cs_subset_bool(NeoMutt->sub, "resolve");
3958  if (c_resolve)
3959  {
3960  op = -1;
3961  rc = OP_NEXT_ENTRY;
3962  }
3963  break;
3964  }
3965 
3966  //=======================================================================
3967 
3968  case OP_UNDELETE_THREAD:
3969  case OP_UNDELETE_SUBTHREAD:
3970  {
3971  if (!assert_pager_mode(pview->mode == PAGER_MODE_EMAIL))
3972  break;
3973  if (!assert_mailbox_writable(shared->mailbox))
3974  break;
3975  /* L10N: CHECK_ACL */
3976  /* L10N: Due to the implementation details we do not know whether we
3977  undelete zero, 1, 12, ... messages. So in English we use
3978  "messages". Your language might have other means to express this. */
3980  _("Can't undelete messages")))
3981  {
3982  break;
3983  }
3984 
3985  int r = mutt_thread_set_flag(shared->mailbox, shared->email, MUTT_DELETE,
3986  false, (op != OP_UNDELETE_THREAD));
3987  if (r != -1)
3988  {
3989  r = mutt_thread_set_flag(shared->mailbox, shared->email, MUTT_PURGE,
3990  false, (op != OP_UNDELETE_THREAD));
3991  }
3992  if (r != -1)
3993  {
3994  const bool c_resolve = cs_subset_bool(NeoMutt->sub, "resolve");
3995  if (c_resolve)
3996  {
3997  rc = (op == OP_DELETE_THREAD) ? OP_MAIN_NEXT_THREAD : OP_MAIN_NEXT_SUBTHREAD;
3998  op = -1;
3999  }
4000 
4001  if (!c_resolve &&
4002  (cs_subset_number(NeoMutt->sub, "pager_index_lines") != 0))
4004  else
4006  }
4007  break;
4008  }
4009 
4010  //=======================================================================
4011 
4012  case OP_VERSION:
4014  break;
4015 
4016  //=======================================================================
4017 
4018  case OP_MAILBOX_LIST:
4020  break;
4021 
4022  //=======================================================================
4023 
4024  case OP_VIEW_ATTACHMENTS:
4025  if (pview->flags & MUTT_PAGER_ATTACHMENT)
4026  {
4027  op = -1;
4028  rc = OP_ATTACH_COLLAPSE;
4029  break;
4030  }
4031  if (!assert_pager_mode(pview->mode == PAGER_MODE_EMAIL))
4032  break;
4034  pview->pdata->fp);
4035  if (shared->email->attach_del)
4036  shared->mailbox->changed = true;
4038  break;
4039 
4040  //=======================================================================
4041 
4042  case OP_MAIL_KEY:
4043  {
4044  if (!(WithCrypto & APPLICATION_PGP))
4045  {
4046  op = -1;
4047  break;
4048  }
4049  if (!assert_pager_mode(pview->mode == PAGER_MODE_EMAIL))
4050  break;
4052  break;
4053  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
4054  emaillist_add_email(&el, shared->email);
4055 
4056  mutt_send_message(SEND_KEY, NULL, NULL, ctx_mailbox(shared->ctx), &el,
4057  NeoMutt->sub);
4058  emaillist_clear(&el);
4060  break;
4061  }
4062 
4063  //=======================================================================
4064 
4065  case OP_EDIT_LABEL:
4066  {
4067  if (!assert_pager_mode(pview->mode == PAGER_MODE_EMAIL))
4068  break;
4069 
4070  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
4071  emaillist_add_email(&el, shared->email);
4072  rc = mutt_label_message(shared->mailbox, &el);
4073  emaillist_clear(&el);
4074 
4075  if (rc > 0)
4076  {
4077  shared->mailbox->changed = true;
4079  mutt_message(ngettext("%d label changed", "%d labels changed", rc), rc);
4080  }
4081  else
4082  {
4083  mutt_message(_("No labels changed"));
4084  }
4085  break;
4086  }
4087 
4088  //=======================================================================
4089 
4090  case OP_FORGET_PASSPHRASE:
4092  break;
4093 
4094  //=======================================================================
4095 
4096  case OP_EXTRACT_KEYS:
4097  {
4098  if (!WithCrypto)
4099  {
4100  op = -1;
4101  break;
4102  }
4103  if (!assert_pager_mode(pview->mode == PAGER_MODE_EMAIL))
4104  break;
4105  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
4106  emaillist_add_email(&el, shared->email);
4108  emaillist_clear(&el);
4110  break;
4111  }
4112 
4113  //=======================================================================
4114 
4115  case OP_WHAT_KEY:
4116  mutt_what_key();
4117  break;
4118 
4119  //=======================================================================
4120 
4121  case OP_CHECK_STATS:
4122  mutt_check_stats(shared->mailbox);
4123  break;
4124 
4125  //=======================================================================
4126 
4127 #ifdef USE_SIDEBAR
4128  case OP_SIDEBAR_FIRST:
4129  case OP_SIDEBAR_LAST:
4130  case OP_SIDEBAR_NEXT:
4131  case OP_SIDEBAR_NEXT_NEW:
4132  case OP_SIDEBAR_PAGE_DOWN:
4133  case OP_SIDEBAR_PAGE_UP:
4134  case OP_SIDEBAR_PREV:
4135  case OP_SIDEBAR_PREV_NEW:
4136  {
4137  struct MuttWindow *win_sidebar = window_find_child(dlg, WT_SIDEBAR);
4138  if (!win_sidebar)
4139  break;
4140  sb_change_mailbox(win_sidebar, op);
4141  break;
4142  }
4143 
4144  //=======================================================================
4145 
4146  case OP_SIDEBAR_TOGGLE_VISIBLE:
4147  bool_str_toggle(NeoMutt->sub, "sidebar_visible", NULL);
4148  mutt_window_reflow(dlg);
4149  break;
4150 
4151  //=======================================================================
4152 #endif
4153 
4154  default:
4155  op = -1;
4156  break;
4157  }
4158  }
4159  //-------------------------------------------------------------------------
4160  // END OF ACT 3: Read user input loop - while (op != -1)
4161  //-------------------------------------------------------------------------
4162 
4163  if (check_read_delay(&delay_read_timestamp))
4164  {
4165  mutt_set_flag(shared->mailbox, shared->email, MUTT_READ, true);
4166  }
4167  mutt_file_fclose(&priv->fp);
4168  if (pview->mode == PAGER_MODE_EMAIL)
4169  {
4170  shared->ctx->msg_in_pager = -1;
4171  priv->win_pbar->actions |= WA_RECALC;
4172  switch (rc)
4173  {
4174  case -1:
4175  case OP_DISPLAY_HEADERS:
4177  break;
4178  default:
4179  TopLine = priv->topline;
4180  OldEmail = shared->email;
4181  break;
4182  }
4183  }
4184 
4185  cleanup_quote(&priv->quote_list);
4186 
4187  for (size_t i = 0; i < priv->max_line; i++)
4188  {
4189  FREE(&(priv->line_info[i].syntax));
4190  if (priv->search_compiled && priv->line_info[i].search)
4191  FREE(&(priv->line_info[i].search));
4192  }
4193  if (priv->search_compiled)
4194  {
4195  regfree(&priv->search_re);
4196  priv->search_compiled = false;
4197  }
4198  FREE(&priv->line_info);
4199 
4200  if (priv->pview->win_index)
4201  {
4206  window_set_visible(priv->pview->win_index->parent, true);
4207  }
4208  window_set_visible(priv->pview->win_pager->parent, false);
4209  mutt_window_reflow(dlg);
4210 
4211  return (rc != -1) ? rc : 0;
4212 }
struct Email ** emails
Array of Emails.
Definition: mailbox.h:99
static bool assert_pager_mode(bool test)
Check that pager is in correct mode.
Definition: dlg_pager.c:241
The "current" mailbox.
Definition: context.h:37
struct MuttWindow * window_find_child(struct MuttWindow *win, enum WindowType type)
Recursively find a child Window of a given type.
Definition: mutt_window.c:550
struct PagerData * pdata
Data that pager displays. NOTNULL.
Definition: lib.h:156
#define MUTT_PAGER_RETWINCH
Need reformatting on SIGWINCH.
Definition: lib.h:65
enum MailboxType type
Mailbox type.
Definition: mailbox.h:105
Decrypt message.
Definition: commands.h:42
bool mutt_mailbox_list(void)
List the mailboxes with new mail.
Definition: mutt_mailbox.c:222
#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:91
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: dlg_pager.c:1980
#define mutt_set_flag(m, e, flag, bf)
Definition: protos.h:66
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
uint64_t mutt_date_epoch_ms(void)
Return the number of milliseconds since the Unix epoch.
Definition: date.c:436
#define WithCrypto
Definition: lib.h:113
#define SEND_TO_SENDER
Compose new email to sender.
Definition: send.h:51
int msg_in_pager
Message currently shown in the pager.
Definition: context.h:43
void mutt_pipe_message(struct Mailbox *m, struct EmailList *el)
Pipe a message.
Definition: commands.c:760
struct stat sb
Definition: private_data.h:67
A default and invalid mode, should never be used.
Definition: lib.h:129
The envelope/body of an email.
Definition: email.h:37
#define MUTT_CLEAR
Clear input if printable character is pressed.
Definition: mutt.h:58
struct Email * mutt_get_virt_email(struct Mailbox *m, int vnum)
Get a virtual Email.
Definition: context.c:412
#define MIN(a, b)
Definition: memory.h:31
Definition: lib.h:67
#define MUTT_PAGER_NSKIP
Preserve whitespace with smartwrap.
Definition: lib.h:63
static void cleanup_quote(struct QClass **quote_list)
Free a quote list.
Definition: dlg_pager.c:592
struct Mailbox * ctx_mailbox(struct Context *ctx)
wrapper to get the mailbox in a Context, or NULL
Definition: context.c:444
void mutt_clear_pager_position(void)
Reset the pager&#39;s viewing position.
Definition: dlg_pager.c:1995
&#39;NNTP&#39; (Usenet) Mailbox type
Definition: mailbox.h:52
struct Email * email
Currently selected Email.
Definition: shared_data.h:42
#define mutt_error(...)
Definition: logging.h:88
static int braille_col
Definition: dlg_pager.c:170
bool mutt_color_is_header(enum ColorId color_id)
Colour is for an Email header.
Definition: color.c:1560
int help_menu
Menu for key bindings, e.g. MENU_PAGER.
Definition: mutt_window.h:141
int mutt_get_field(const char *field, char *buf, size_t buflen, CompletionFlags complete, bool multiple, char ***files, int *numfiles)
Ask the user for a string.
Definition: curs_lib.c:335
void mutt_display_address(struct Envelope *env)
Display the address of a message.
Definition: commands.c:1026
bool mutt_shell_escape(void)
invoke a command in a subshell
Definition: commands.c:943
void mutt_update_index(struct Menu *menu, struct Context *ctx, enum MxStatus check, int oldcount, struct IndexSharedData *shared)
Update the index.
Definition: dlg_index.c:541
PagerFlags hide_quoted
Definition: private_data.h:55
struct Body * body
Current attachment.
Definition: lib.h:145
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:788
bool attach_del
Has an attachment marked for deletion.
Definition: email.h:49
#define SEND_FORWARD
Forward email.
Definition: send.h:43
void mutt_resize_screen(void)
Update NeoMutt&#39;s opinion about the window size (CURSES)
Definition: resize.c:101
WHERE bool OptNeedResort
(pseudo) used to force a re-sort
Definition: options.h:42
void crypt_forget_passphrase(void)
Forget a passphrase and display a message.
Definition: crypt.c:93
No transformation.
Definition: commands.h:41
void mutt_enter_command(void)
enter a neomutt command
Definition: commands.c:978
Nondestructive flags change (IMAP)
Definition: mxapi.h:82
#define MUTT_HIDE
Don&#39;t show quoted text.
Definition: lib.h:57
New mail received in Mailbox.
Definition: mxapi.h:79
struct MuttWindow * window_set_focus(struct MuttWindow *win)
Set the Window focus.
Definition: mutt_window.c:680
Flagged messages.
Definition: mutt.h:98
#define MUTT_SHOWFLAT
Show characters (used for displaying help)
Definition: lib.h:55
#define _(a)
Definition: message.h:28
Mailbox wasn&#39;t recognised.
Definition: mailbox.h:47
static struct Email * OldEmail
Definition: dlg_pager.c:167
#define REG_COMP(preg, regex, cflags)
Compile a regular expression.
Definition: regex3.h:54
void window_redraw(struct MuttWindow *win)
Reflow, recalc and repaint a tree of Windows.
Definition: mutt_window.c:632
Data shared between Index, Pager and Sidebar.
Definition: shared_data.h:36
Messages to be purged (bypass trash)
Definition: mutt.h:96
static int braille_row
Definition: dlg_pager.c:169
void emaillist_clear(struct EmailList *el)
Drop a private list of Emails.
Definition: email.c:138
static bool assert_mailbox_permissions(struct Mailbox *m, AclFlags acl, char *action)
checks that mailbox is has requested acl flags set
Definition: dlg_pager.c:300
bool search_back
Definition: dlg_pager.c:162
Copy message, making a duplicate in another mailbox.
Definition: commands.h:51
int indicator
the indicator line of the PI
Definition: private_data.h:46
bool search_compiled
Definition: dlg_pager.c:161
short type
Definition: dlg_pager.c:134
struct QClass * quote_list
Definition: private_data.h:57
uint16_t SendFlags
Flags for mutt_send_message(), e.g. SEND_REPLY.
Definition: send.h:36
static int display_line(FILE *fp, LOFF_T *last_pos, struct Line **line_info, int n, int *last, int *max, PagerFlags flags, struct QClass **quote_list, int *q_level, bool *force_redraw, regex_t *search_re, struct MuttWindow *win_pager)
Print a line on screen.
Definition: dlg_pager.c:1692
Pager: quoted text.
Definition: color.h:62
A special case of PAGER_MODE_ATTACH - attachment is a full-blown email message.
Definition: lib.h:133
short cs_subset_number(const struct ConfigSubset *sub, const char *name)
Get a number config item by name.
Definition: helpers.c:169
#define SEND_POSTPONED
Recall a postponed email.
Definition: send.h:44
void mutt_help(enum MenuType menu)
Display the help menu.
Definition: help.c:389
void msgwin_clear_text(void)
Clear the text in the Message Window.
Definition: msgwin.c:242
#define mutt_perror(...)
Definition: logging.h:89
struct MuttWindow * win_index
Definition: lib.h:162
Container for Accounts, Notifications.
Definition: neomutt.h:36
#define MUTT_PATTERN
Pattern mode - only used for history classes.
Definition: mutt.h:60
#define MUTT_SEARCH
Resolve search patterns.
Definition: lib.h:58
#define MUTT_ACL_DELETE
Delete a message.
Definition: mailbox.h:66
int vcount
The number of virtual messages.
Definition: mailbox.h:102
Mailbox was reopened.
Definition: mxapi.h:81
QuadOption
Possible values for a quad-option.
Definition: quad.h:35
int mutt_window_move(struct MuttWindow *win, int col, int row)
Move the cursor in a Window.
Definition: mutt_window.c:310
void mutt_print_message(struct Mailbox *m, struct EmailList *el)
Print a message.
Definition: commands.c:791
static bool check_read_delay(uint64_t *timestamp)
Is it time to mark the message read?
Definition: dlg_pager.c:2329
#define SEND_NO_FLAGS
No flags are set.
Definition: send.h:39
Private state data for the Pager.
Definition: private_data.h:39
void mutt_beep(bool force)
Irritate the user.
Definition: curs_lib.c:105
#define MAX(a, b)
Definition: memory.h:30
int cs_subset_str_native_set(const struct ConfigSubset *sub, const char *name, intptr_t value, struct Buffer *err)
Natively set the value of a string config item.
Definition: subset.c:305
int line
Definition: dlg_pager.c:160
enum MxStatus mx_mbox_check(struct Mailbox *m)
Check for new mail - Wrapper for MxOps::mbox_check()
Definition: mx.c:1119
WindowActionFlags actions
Actions to be performed, e.g. WA_RECALC.
Definition: mutt_window.h:132
Pager pager (email viewer)
Definition: type.h:54
bool tagged
Email is tagged.
Definition: email.h:44
bool read
Email is read.
Definition: email.h:51
void mutt_print_attachment_list(struct AttachCtx *actx, FILE *fp, bool tag, struct Body *top)
Print a list of Attachments.
Definition: recvattach.c:1240
void mutt_curses_set_cursor(enum MuttCursorState state)
Set the cursor state.
Definition: mutt_curses.c:71
#define MUTT_PAGER_BOTTOM
Start at the bottom.
Definition: lib.h:69
bool old
Email is seen, but unread.
Definition: email.h:50
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:153
void mutt_what_key(void)
Ask the user to press a key.
Definition: keymap.c:1718
struct Envelope * env
Envelope information.
Definition: email.h:90
Display a normal cursor.
Definition: mutt_curses.h:81
void km_error_key(enum MenuType mtype)
Handle an unbound key sequence.
Definition: keymap.c:1144
struct Menu * menu
Definition: private_data.h:41
void alias_create(struct AddressList *al, const struct ConfigSubset *sub)
Create a new Alias from an Address.
Definition: alias.c:372
bool mutt_mailbox_notify(struct Mailbox *m_cur)
Notify the user if there&#39;s new mail.
Definition: mutt_mailbox.c:209
short continuation
Definition: dlg_pager.c:135
int mutt_send_message(SendFlags flags, struct Email *e_templ, const char *tempfile, struct Mailbox *m, struct EmailList *el, struct ConfigSubset *sub)
Send an email.
Definition: send.c:2125
void pager_queue_redraw(struct PagerPrivateData *priv, MenuRedrawFlags redraw)
Queue a request for a redraw.
Definition: dlg_pager.c:2006
int bool_str_toggle(struct ConfigSubset *sub, const char *name, struct Buffer *err)
Toggle the value of a bool.
Definition: bool.c:214
enum QuadOption query_quadoption(enum QuadOption opt, const char *prompt)
Ask the user a quad-question.
Definition: question.c:347
#define SEND_LIST_REPLY
Reply to mailing list.
Definition: send.h:42
MessageTransformOpt
Message transformation option.
Definition: commands.h:39
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:112
static bool assert_mailbox_writable(struct Mailbox *mailbox)
checks that mailbox is writable
Definition: dlg_pager.c:259
const char * OpStrings[][2]
Definition: opcodes.c:34
void * mdata
Driver specific data.
Definition: mailbox.h:136
#define MUTT_ACL_WRITE
Write to a message (for flagging or linking threads)
Definition: mailbox.h:74
#define mutt_warning(...)
Definition: logging.h:86
static bool jump_to_bottom(struct PagerPrivateData *priv, struct PagerView *pview)
make sure the bottom line is displayed
Definition: dlg_pager.c:2301
Pager is invoked via 3rd path to show help.
Definition: lib.h:134
#define SEND_KEY
Mail a PGP public key.
Definition: send.h:46
Window has a fixed size.
Definition: mutt_window.h:47
bool mutt_select_sort(bool reverse)
Ask the user for a sort method.
Definition: commands.c:835
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:916
struct Context * ctx
Current Mailbox view.
Definition: shared_data.h:39
enum PagerMode mode
Pager mode.
Definition: lib.h:157
short cols
Number of columns, can be MUTT_WIN_SIZE_UNLIMITED.
Definition: mutt_window.h:60
int mutt_save_message(struct Mailbox *m, struct EmailList *el, enum MessageSaveOpt save_opt, enum MessageTransformOpt transform_opt)
Save an email.
Definition: commands.c:1144
void mutt_refresh(void)
Force a refresh of the screen.
Definition: curs_lib.c:115
Side panel containing Accounts or groups of data.
Definition: mutt_window.h:101
Pager is invoked via 1st path. The mime part is selected automatically.
Definition: lib.h:131
Window size depends on its children.
Definition: mutt_window.h:49
void mutt_attach_bounce(struct Mailbox *m, FILE *fp, struct AttachCtx *actx, struct Body *cur)
Bounce function, from the attachment menu.
Definition: recvcmd.c:161
short search_cnt
Definition: dlg_pager.c:137
struct TextSyntax * search
Definition: dlg_pager.c:139
struct WindowState state
Current state of the Window.
Definition: mutt_window.h:127
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: lib.h:87
WHERE bool OptAttachMsg
(pseudo) used by attach-message
Definition: options.h:31
struct AddressList * mutt_get_address(struct Envelope *env, const char **prefix)
Get an Address from an Envelope.
Definition: alias.c:332
void dlg_select_attachment(struct ConfigSubset *sub, struct Mailbox *m, struct Email *e, FILE *fp)
Show the attachments in a Menu.
Definition: recvattach.c:1713
void mutt_attach_reply(FILE *fp, struct Mailbox *m, struct Email *e, struct AttachCtx *actx, struct Body *e_cur, SendFlags flags)
Attach a reply.
Definition: recvcmd.c:938
Messages to be deleted.
Definition: mutt.h:94
int mutt_mailbox_check(struct Mailbox *m_cur, int force)
Check all all Mailboxes for new mail.
Definition: mutt_mailbox.c:137
#define MUTT_PAGER_ATTACHMENT
Attachments may exist.
Definition: lib.h:66
#define MUTT_WIN_SIZE_UNLIMITED
Use as much space as possible.
Definition: mutt_window.h:52
short rows
Number of rows, can be MUTT_WIN_SIZE_UNLIMITED.
Definition: mutt_window.h:61
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:90
struct Line * line_info
Definition: private_data.h:65
const struct Mapping * help_data
Data for the Help Bar.
Definition: mutt_window.h:142
Tagged messages.
Definition: mutt.h:99
A line of text in the pager.
Definition: dlg_pager.c:131
New messages.
Definition: mutt.h:89
Messages that have been read.
Definition: mutt.h:92
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
#define MUTT_SHOWCOLOR
Show characters in color otherwise don&#39;t show characters.
Definition: lib.h:56
static int TopLine
Definition: dlg_pager.c:166
bool verbose
Display status messages?
Definition: mailbox.h:118
struct MuttWindow * win_pbar
Definition: private_data.h:42
static bool assert_attach_msg_mode(bool attach_msg)
Check that attach message mode is on.
Definition: dlg_pager.c:279
#define SEND_NEWS
Reply to a news article.
Definition: send.h:53
WHERE bool OptSearchInvalid
(pseudo) used to invalidate the search pattern
Definition: options.h:51
enum MuttWindowSize size
Type of Window, e.g. MUTT_WIN_SIZE_FIXED.
Definition: mutt_window.h:131
PagerFlags flags
Additional settings to tweak pager&#39;s function.
Definition: lib.h:158
void menu_status_line(char *buf, size_t buflen, struct IndexSharedData *shared, struct Menu *menu, int cols, const char *fmt)
Create the status line.
Definition: status.c:445
struct PagerView * pview
Definition: private_data.h:44
#define mutt_debug(LEVEL,...)
Definition: logging.h:85
#define MUTT_TYPES
Compute line&#39;s type.
Definition: lib.h:59
SecurityFlags security
bit 0-10: flags, bit 11,12: application, bit 13: traditional pgp See: ncrypt/lib.h pgplib...
Definition: email.h:39
int emaillist_add_email(struct EmailList *el, struct Email *e)
Add an Email to a list.
Definition: email.c:159
#define SEND_REPLY
Reply to sender.
Definition: send.h:40
NNTP-specific Mailbox data -.
Definition: mdata.h:32
enum QuadOption cs_subset_quad(const struct ConfigSubset *sub, const char *name)
Get a quad-value config item by name.
Definition: helpers.c:218
#define MUTT_MAILBOX_CHECK_FORCE
Definition: mutt_mailbox.h:32
int max
Number of entries in the menu.
Definition: lib.h:71
void mutt_attach_resend(FILE *fp, struct Mailbox *m, struct AttachCtx *actx, struct Body *cur)
resend-message, from the attachment menu
Definition: recvcmd.c:294
struct AttachCtx * actx
Attachment information.
Definition: lib.h:147
void mutt_attach_forward(FILE *fp, struct Email *e, struct AttachCtx *actx, struct Body *cur, SendFlags flags)
Forward an Attachment.
Definition: recvcmd.c:784
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:1081
Highlighting for a line of text.
Definition: dlg_pager.c:121
void ci_bounce_message(struct Mailbox *m, struct EmailList *el)
Bounce an email.
Definition: commands.c:434
#define SEND_GROUP_REPLY
Reply to all.
Definition: send.h:41
MailboxType
Supported mailbox formats.
Definition: mailbox.h:43
int mutt_label_message(struct Mailbox *m, struct EmailList *el)
Let the user label a message.
Definition: mutt_header.c:124
Move message to another mailbox, removing the original.
Definition: commands.h:52
Log at debug level 1.
Definition: logging.h:40
bool flagged
Marked important?
Definition: email.h:43
size_t mutt_str_copy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:749
FILE * fp
Source stream.
Definition: lib.h:146
void window_set_visible(struct MuttWindow *win, bool visible)
Set a Window visible or hidden.
Definition: mutt_window.c:163
bool deleted
Email is deleted.
Definition: email.h:45
void mutt_window_reflow(struct MuttWindow *win)
Resize a Window and its children.
Definition: mutt_window.c:361
struct MuttWindow * parent
Parent Window.
Definition: mutt_window.h:135
Another invalid mode, should never be used.
Definition: lib.h:137
char * followup_to
List of &#39;followup-to&#39; fields.
Definition: envelope.h:77
void mutt_timeout_hook(void)
Execute any timeout hooks.
Definition: hook.c:827
Pager is invoked via 2nd path. A user-selected attachment (mime part or a nested email) will be shown...
Definition: lib.h:132
MessageSaveOpt
Message save option.
Definition: commands.h:49
void mutt_check_stats(struct Mailbox *m)
Forcibly update mailbox stats.
Definition: commands.c:1590
int index
The absolute (unsorted) message number.
Definition: email.h:86
#define mutt_message(...)
Definition: logging.h:87
#define FREE(x)
Definition: memory.h:40
static void pager_custom_redraw(struct PagerPrivateData *priv)
Redraw the pager window.
Definition: dlg_pager.c:2016
void crypt_extract_keys_from_messages(struct Mailbox *m, struct EmailList *el)
Extract keys from a message.
Definition: crypt.c:858
#define MUTT_ACL_SEEN
Change the &#39;seen&#39; status of a message.
Definition: mailbox.h:73
Hide the cursor.
Definition: mutt_curses.h:80
#define STAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:324
Decode message.
Definition: commands.h:43
struct MuttWindow * win_pager
Definition: lib.h:164
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:1115
short req_rows
Number of rows required.
Definition: mutt_window.h:125
struct MuttWindow * win_pbar
Definition: lib.h:163
struct TextSyntax * syntax
Definition: dlg_pager.c:138
#define MUTT_PAGER_NOWRAP
Format for term width, ignore $wrap.
Definition: lib.h:67
#define PGP_TRADITIONAL_CHECKED
Email has a traditional (inline) signature.
Definition: lib.h:89
bool changed
Mailbox has been modified.
Definition: mailbox.h:114
int mutt_change_flag(struct Mailbox *m, struct EmailList *el, bool bf)
Change the flag on a Message.
Definition: flags.c:434
Keep track of screen resizing.
Definition: dlg_pager.c:158
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
int mutt_resend_message(FILE *fp, struct Mailbox *m, struct Email *e_cur, struct ConfigSubset *sub)
Resend an email.
Definition: send.c:1632
PagerFlags search_flag
Definition: private_data.h:62
const char * fname
Name of the file to read.
Definition: lib.h:148
#define SEND_GROUP_CHAT_REPLY
Reply to all recipients preserving To/Cc.
Definition: send.h:52
struct Mailbox * mailbox
Current Mailbox.
Definition: shared_data.h:41
int km_dokey(enum MenuType mtype)
Determine what a keypress should do.
Definition: keymap.c:635
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:364
struct Buffer pathbuf
Definition: mailbox.h:83
Window wants as much space as possible.
Definition: mutt_window.h:48
bool mutt_buffer_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:252
LOFF_T offset
Definition: dlg_pager.c:133
Pager is invoked via 3rd path. Non-email content is likely to be shown.
Definition: lib.h:135
void * wdata
Private data.
Definition: mutt_window.h:145
static const struct Mapping * pager_resolve_help_mapping(enum PagerMode mode, enum MailboxType type)
determine help mapping based on pager mode and mailbox type
Definition: dlg_pager.c:2263
bool mutt_mb_is_lower(const char *s)
Does a multi-byte string contain only lowercase characters?
Definition: mbyte.c:357
WHERE SIG_ATOMIC_VOLATILE_T SigWinch
true after SIGWINCH is received
Definition: mutt_globals.h:68
struct Email * email
header information for message/rfc822
Definition: body.h:55
struct MuttWindow * dialog_find(struct MuttWindow *win)
Find the parent Dialog of a Window.
Definition: dialog.c:85
MxStatus
Return values from mbox_check(), mbox_check_stats(), mbox_snc(), and mbox_close() ...
Definition: mxapi.h:75
int mutt_system(const char *cmd)
Run an external command.
Definition: system.c:51
int mutt_thread_set_flag(struct Mailbox *m, struct Email *e, enum MessageType flag, bool bf, bool subthread)
Set a flag on an entire thread.
Definition: flags.c:375
MenuRedrawFlags redraw
When to redraw the screen.
Definition: private_data.h:69
char searchbuf[256]
Definition: private_data.h:64
int msgno
Number displayed to the user.
Definition: email.h:87
const char * mutt_make_version(void)
Generate the NeoMutt version string.
Definition: muttlib.c:1476
User answered &#39;Yes&#39;, or assume &#39;Yes&#39;.
Definition: quad.h:39
An error occurred.
Definition: mxapi.h:77
#define WA_RECALC
Recalculate the contents of the Window.
Definition: mutt_window.h:110
+ Here is the caller graph for this function:

◆ mutt_do_pager()

int mutt_do_pager ( struct PagerView pview,
struct Email e 
)

Display some page-able text to the user (help or attachment)

Parameters
pviewPagerView to construct Pager object
eEmail to use
Return values
0Success
-1Error

Definition at line 120 of file do_pager.c.

121 {
122  assert(pview);
123  assert(pview->pdata);
124  assert(pview->pdata->fname);
125  assert((pview->mode == PAGER_MODE_ATTACH) ||
126  (pview->mode == PAGER_MODE_HELP) || (pview->mode == PAGER_MODE_OTHER));
127 
128  struct MuttWindow *dlg =
131 
132  struct IndexSharedData *shared = index_shared_data_new();
133  shared->email = e;
134 
135  notify_set_parent(shared->notify, dlg->notify);
136 
137  dlg->wdata = shared;
139 
140  const bool c_status_on_top = cs_subset_bool(NeoMutt->sub, "status_on_top");
141  struct MuttWindow *panel_pager = ppanel_new(c_status_on_top, shared);
142  dlg->focus = panel_pager;
143  mutt_window_add_child(dlg, panel_pager);
144 
147  dialog_push(dlg);
148 
149  pview->win_ibar = NULL;
150  pview->win_index = NULL;
151  pview->win_pbar = window_find_child(panel_pager, WT_STATUS_BAR);
152  pview->win_pager = window_find_child(panel_pager, WT_CUSTOM);
153 
154  int rc;
155 
156  const char *const c_pager = cs_subset_string(NeoMutt->sub, "pager");
157  if (!c_pager || mutt_str_equal(c_pager, "builtin"))
158  {
159  rc = mutt_pager(pview);
160  }
161  else
162  {
163  struct Buffer *cmd = mutt_buffer_pool_get();
164 
165  mutt_endwin();
166  mutt_buffer_file_expand_fmt_quote(cmd, c_pager, pview->pdata->fname);
167  if (mutt_system(mutt_buffer_string(cmd)) == -1)
168  {
169  mutt_error(_("Error running \"%s\""), mutt_buffer_string(cmd));
170  rc = -1;
171  }
172  else
173  rc = 0;
174  mutt_file_unlink(pview->pdata->fname);
176  }
177 
178  dialog_pop();
179  mutt_window_free(&dlg);
180  return rc;
181 }
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:904
struct MuttWindow * window_find_child(struct MuttWindow *win, enum WindowType type)
Recursively find a child Window of a given type.
Definition: mutt_window.c:550
struct PagerData * pdata
Data that pager displays. NOTNULL.
Definition: lib.h:156
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
void(* wdata_free)(struct MuttWindow *win, void **ptr)
Definition: mutt_window.h:160
struct Email * email
Currently selected Email.
Definition: shared_data.h:42
#define mutt_error(...)
Definition: logging.h:88
static int dopager_window_observer(struct NotifyCallback *nc)
Notification that a Window has changed - Implements observer_t.
Definition: do_pager.c:93
Window uses all available vertical space.
Definition: mutt_window.h:38
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
void mutt_file_unlink(const char *s)
Delete a file, carefully.
Definition: file.c:195
String manipulation buffer.
Definition: buffer.h:33
#define _(a)
Definition: message.h:28
Data shared between Index, Pager and Sidebar.
Definition: shared_data.h:36
void index_shared_data_free(struct MuttWindow *win, void **ptr)
Free Index Data.
Definition: shared_data.c:273
struct MuttWindow * win_index
Definition: lib.h:162
Container for Accounts, Notifications.
Definition: neomutt.h:36
MuttWindow has changed, NotifyWindow, EventWindow.
Definition: notify_type.h:53
struct Notify * notify
Notifications: NotifyIndex, IndexSharedData.
Definition: shared_data.h:44
Status Bar containing extra info about the Index/Pager/etc.
Definition: mutt_window.h:102
void mutt_window_free(struct MuttWindow **ptr)
Free a Window and its children.
Definition: mutt_window.c:200
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:77
struct MuttWindow * ppanel_new(bool status_on_top, struct IndexSharedData *shared)
Create the Windows for the Pager panel.
Definition: ppanel.c:121
int mutt_pager(struct PagerView *pview)
Display an email, attachment, or help, in a window.
Definition: dlg_pager.c:2360
struct MuttWindow * focus
Focussed Window.
Definition: mutt_window.h:140
struct Notify * notify
Notifications: NotifyWindow, EventWindow.
Definition: mutt_window.h:138
static int dopager_config_observer(struct NotifyCallback *nc)
Notification that a Config Variable has changed - Implements observer_t.
Definition: do_pager.c:75
void dialog_push(struct MuttWindow *dlg)
Display a Window to the user.
Definition: dialog.c:105
Window with a custom drawing function.
Definition: mutt_window.h:95
bool notify_observer_add(struct Notify *notify, enum NotifyType type, observer_t callback, void *global_data)
Add an observer to an object.
Definition: notify.c:189
Pager is invoked via 3rd path to show help.
Definition: lib.h:134
enum PagerMode mode
Pager mode.
Definition: lib.h:157
void mutt_endwin(void)
Shutdown curses/slang.
Definition: curs_lib.c:422
#define MUTT_WIN_SIZE_UNLIMITED
Use as much space as possible.
Definition: mutt_window.h:52
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
Pager Dialog, mutt_do_pager()
Definition: mutt_window.h:84
struct Notify * notify
Notifications handler.
Definition: neomutt.h:38
void mutt_window_add_child(struct MuttWindow *parent, struct MuttWindow *child)
Add a child to Window.
Definition: mutt_window.c:468
Config has changed, NotifyConfig, EventConfig.
Definition: notify_type.h:42
void dialog_pop(void)
Hide a Window from the user.
Definition: dialog.c:139
void mutt_buffer_file_expand_fmt_quote(struct Buffer *dest, const char *fmt, const char *src)
Replace s in a string with a filename.
Definition: file.c:1435
Pager is invoked via 2nd path. A user-selected attachment (mime part or a nested email) will be shown...
Definition: lib.h:132
struct MuttWindow * win_pager
Definition: lib.h:164
struct MuttWindow * win_pbar
Definition: lib.h:163
void notify_set_parent(struct Notify *notify, struct Notify *parent)
Set the parent notification handler.
Definition: notify.c:93
struct IndexSharedData * index_shared_data_new(void)
Create new Index Data.
Definition: shared_data.c:300
struct MuttWindow * win_ibar
Definition: lib.h:161
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
const char * fname
Name of the file to read.
Definition: lib.h:148
struct MuttWindow * mutt_window_new(enum WindowType type, enum MuttWindowOrientation orient, enum MuttWindowSize size, int cols, int rows)
Create a new Window.
Definition: mutt_window.c:180
Window wants as much space as possible.
Definition: mutt_window.h:48
void * wdata
Private data.
Definition: mutt_window.h:145
Pager is invoked via 3rd path. Non-email content is likely to be shown.
Definition: lib.h:135
int mutt_system(const char *cmd)
Run an external command.
Definition: system.c:51
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_buffer_strip_formatting()

void mutt_buffer_strip_formatting ( struct Buffer dest,
const char *  src,
bool  strip_markers 
)

Removes ANSI and backspace formatting.

Parameters
destBuffer for the result
srcString to strip
strip_markersRemove

Removes ANSI and backspace formatting, and optionally markers. This is separated out so that it can be used both by the pager and the autoview handler.

This logic is pulled from the pager fill_buffer() function, for use in stripping reply-quoted autoview output of ansi sequences.

Definition at line 1395 of file dlg_pager.c.

1396 {
1397  const char *s = src;
1398 
1399  mutt_buffer_reset(dest);
1400 
1401  if (!s)
1402  return;
1403 
1404  while (s[0] != '\0')
1405  {
1406  if ((s[0] == '\010') && (s > src))
1407  {
1408  if (s[1] == '_') /* underline */
1409  s += 2;
1410  else if (s[1] && mutt_buffer_len(dest)) /* bold or overstrike */
1411  {
1412  dest->dptr--;
1413  mutt_buffer_addch(dest, s[1]);
1414  s += 2;
1415  }
1416  else /* ^H */
1417  mutt_buffer_addch(dest, *s++);
1418  }
1419  else if ((s[0] == '\033') && (s[1] == '[') && is_ansi(s + 2))
1420  {
1421  while (*s++ != 'm')
1422  ; /* skip ANSI sequence */
1423  }
1424  else if (strip_markers && (s[0] == '\033') && (s[1] == ']') &&
1425  ((check_attachment_marker(s) == 0) || (check_protected_header_marker(s) == 0)))
1426  {
1427  mutt_debug(LL_DEBUG2, "Seen attachment marker\n");
1428  while (*s++ != '\a')
1429  ; /* skip pseudo-ANSI sequence */
1430  }
1431  else
1432  mutt_buffer_addch(dest, *s++);
1433  }
1434 }
void mutt_buffer_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:79
static bool is_ansi(const char *str)
Is this an ANSI escape sequence?
Definition: dlg_pager.c:1282
Log at debug level 2.
Definition: logging.h:41
size_t mutt_buffer_len(const struct Buffer *buf)
Calculate the length of a Buffer.
Definition: buffer.c:356
char * dptr
Current read/write position.
Definition: buffer.h:36
size_t mutt_buffer_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:240
#define mutt_debug(LEVEL,...)
Definition: logging.h:85
static int check_attachment_marker(const char *p)
Check that the unique marker is present.
Definition: dlg_pager.c:944
static int check_protected_header_marker(const char *p)
Check that the unique marker is present.
Definition: dlg_pager.c:954
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ ppanel_new()

struct MuttWindow* ppanel_new ( bool  status_on_top,
struct IndexSharedData shared 
)

Create the Windows for the Pager panel.

Parameters
status_on_toptrue, if the Pager bar should be on top
sharedShared Index data
Return values
ptrNew Pager Panel

Definition at line 121 of file ppanel.c.

122 {
123  struct MuttWindow *panel_pager =
126  panel_pager->state.visible = false; // The Pager and Pager Bar are initially hidden
127 
128  struct PagerPrivateData *priv = pager_private_data_new();
129  panel_pager->wdata = priv;
130  panel_pager->wdata_free = pager_private_data_free;
131 
132  struct MuttWindow *win_pager = pager_window_new(panel_pager, shared, priv);
133  panel_pager->focus = win_pager;
134 
135  struct MuttWindow *win_pbar = pbar_new(panel_pager, shared, priv);
136  if (status_on_top)
137  {
138  mutt_window_add_child(panel_pager, win_pbar);
139  mutt_window_add_child(panel_pager, win_pager);
140  }
141  else
142  {
143  mutt_window_add_child(panel_pager, win_pager);
144  mutt_window_add_child(panel_pager, win_pbar);
145  }
146 
148  notify_observer_add(panel_pager->notify, NT_WINDOW, ppanel_window_observer, panel_pager);
149 
150  return panel_pager;
151 }
void(* wdata_free)(struct MuttWindow *win, void **ptr)
Definition: mutt_window.h:160
Window uses all available vertical space.
Definition: mutt_window.h:38
struct MuttWindow * pager_window_new(struct MuttWindow *parent, struct IndexSharedData *shared, struct PagerPrivateData *priv)
Create a new Pager Window (list of Emails)
Definition: pager.c:241
Container for Accounts, Notifications.
Definition: neomutt.h:36
MuttWindow has changed, NotifyWindow, EventWindow.
Definition: notify_type.h:53
Private state data for the Pager.
Definition: private_data.h:39
struct MuttWindow * focus
Focussed Window.
Definition: mutt_window.h:140
struct Notify * notify
Notifications: NotifyWindow, EventWindow.
Definition: mutt_window.h:138
bool notify_observer_add(struct Notify *notify, enum NotifyType type, observer_t callback, void *global_data)
Add an observer to an object.
Definition: notify.c:189
struct PagerPrivateData * pager_private_data_new(void)
Create new Pager Data.
Definition: private_data.c:52
struct WindowState state
Current state of the Window.
Definition: mutt_window.h:127
bool visible
Window is visible.
Definition: mutt_window.h:59
#define MUTT_WIN_SIZE_UNLIMITED
Use as much space as possible.
Definition: mutt_window.h:52
static int ppanel_window_observer(struct NotifyCallback *nc)
Notification that a Window has changed - Implements observer_t.
Definition: ppanel.c:95
struct Notify * notify
Notifications handler.
Definition: neomutt.h:38
void mutt_window_add_child(struct MuttWindow *parent, struct MuttWindow *child)
Add a child to Window.
Definition: mutt_window.c:468
Config has changed, NotifyConfig, EventConfig.
Definition: notify_type.h:42
A panel containing the Pager Window.
Definition: mutt_window.h:100
static int ppanel_config_observer(struct NotifyCallback *nc)
Notification that a Config Variable has changed - Implements observer_t.
Definition: ppanel.c:75
struct MuttWindow * pbar_new(struct MuttWindow *parent, struct IndexSharedData *shared, struct PagerPrivateData *priv)
Create the Pager Bar.
Definition: pbar.c:337
void pager_private_data_free(struct MuttWindow *win, void **ptr)
Free Pager Data.
Definition: private_data.c:38
struct MuttWindow * mutt_window_new(enum WindowType type, enum MuttWindowOrientation orient, enum MuttWindowSize size, int cols, int rows)
Create a new Window.
Definition: mutt_window.c:180
Window wants as much space as possible.
Definition: mutt_window.h:48
void * wdata
Private data.
Definition: mutt_window.h:145
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ pager_window_new()

struct MuttWindow* pager_window_new ( struct MuttWindow parent,
struct IndexSharedData shared,
struct PagerPrivateData priv 
)

Create a new Pager Window (list of Emails)

Parameters
parentParent Window
sharedShared Index Data
privPrivate Pager Data
Return values
ptrNew Window

Definition at line 241 of file pager.c.

243 {
244  struct MuttWindow *win =
247  win->wdata = priv;
248 
254 
255  return win;
256 }
static int pager_pager_observer(struct NotifyCallback *nc)
Notification that the Pager has changed - Implements observer_t.
Definition: pager.c:192
static int pager_window_observer(struct NotifyCallback *nc)
Notification that a Window has changed - Implements observer_t.
Definition: pager.c:204
Window uses all available vertical space.
Definition: mutt_window.h:38
static int pager_index_observer(struct NotifyCallback *nc)
Notification that the Index has changed - Implements observer_t.
Definition: pager.c:155
Container for Accounts, Notifications.
Definition: neomutt.h:36
MuttWindow has changed, NotifyWindow, EventWindow.
Definition: notify_type.h:53
struct Notify * notify
Notifications: NotifyIndex, IndexSharedData.
Definition: shared_data.h:44
Index data has changed, NotifyIndex, IndexSharedData.
Definition: notify_type.h:47
struct Notify * notify
Notifications: NotifyWindow, EventWindow.
Definition: mutt_window.h:138
Window with a custom drawing function.
Definition: mutt_window.h:95
bool notify_observer_add(struct Notify *notify, enum NotifyType type, observer_t callback, void *global_data)
Add an observer to an object.
Definition: notify.c:189
static int pager_config_observer(struct NotifyCallback *nc)
Notification that a Config Variable has changed - Implements observer_t.
Definition: pager.c:135
Colour has changed, NotifyColor, EventColor.
Definition: notify_type.h:39
#define MUTT_WIN_SIZE_UNLIMITED
Use as much space as possible.
Definition: mutt_window.h:52
Pager data has changed, NotifyPager, IndexSharedData.
Definition: notify_type.h:50
struct Notify * notify
Notifications handler.
Definition: neomutt.h:38
static int pager_color_observer(struct NotifyCallback *nc)
Notification that a Color has changed - Implements observer_t.
Definition: pager.c:123
Config has changed, NotifyConfig, EventConfig.
Definition: notify_type.h:42
struct MuttWindow * mutt_window_new(enum WindowType type, enum MuttWindowOrientation orient, enum MuttWindowSize size, int cols, int rows)
Create a new Window.
Definition: mutt_window.c:180
Window wants as much space as possible.
Definition: mutt_window.h:48
void * wdata
Private data.
Definition: mutt_window.h:145
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_clear_pager_position()

void mutt_clear_pager_position ( void  )

Reset the pager's viewing position.

Definition at line 1995 of file dlg_pager.c.

1996 {
1997  TopLine = 0;
1998  OldEmail = NULL;
1999 }
static struct Email * OldEmail
Definition: dlg_pager.c:167
static int TopLine
Definition: dlg_pager.c:166
+ Here is the caller graph for this function: