NeoMutt  2025-09-05-55-g97fc89
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
functions.c
Go to the documentation of this file.
1
22
28
29#include "config.h"
30#ifdef _MAKEDOC
31#include "docs/makedoc_defs.h"
32#else
33#include <inttypes.h>
34#include <stdbool.h>
35#include <stdio.h>
36#include <sys/stat.h>
37#include "mutt/lib.h"
38#include "config/lib.h"
39#include "email/lib.h"
40#include "core/lib.h"
41#include "gui/lib.h"
42#include "mutt.h"
43#include "lib.h"
44#include "attach/lib.h"
45#include "browser/lib.h"
46#include "color/lib.h"
47#include "editor/lib.h"
48#include "history/lib.h"
49#include "index/lib.h"
50#include "key/lib.h"
51#include "menu/lib.h"
52#include "pattern/lib.h"
53#include "display.h"
54#include "functions.h"
55#include "muttlib.h"
56#include "private_data.h"
57#include "protos.h"
58#endif
59
61static const char *Not_available_in_this_menu = N_("Not available in this menu");
62
63static int op_pager_search_next(struct IndexSharedData *shared,
64 struct PagerPrivateData *priv, int op);
65
66// clang-format off
70const struct MenuFuncOp OpPager[] = { /* map: pager */
71 { "bottom", OP_PAGER_BOTTOM },
72 { "bounce-message", OP_BOUNCE_MESSAGE },
73 { "break-thread", OP_MAIN_BREAK_THREAD },
74 { "change-folder", OP_MAIN_CHANGE_FOLDER },
75 { "change-folder-readonly", OP_MAIN_CHANGE_FOLDER_READONLY },
76 { "change-newsgroup", OP_MAIN_CHANGE_GROUP },
77 { "change-newsgroup-readonly", OP_MAIN_CHANGE_GROUP_READONLY },
78#ifdef USE_NOTMUCH
79 { "change-vfolder", OP_MAIN_CHANGE_VFOLDER },
80#endif
81 { "check-stats", OP_CHECK_STATS },
82 { "check-traditional-pgp", OP_CHECK_TRADITIONAL },
83 { "clear-flag", OP_MAIN_CLEAR_FLAG },
84 { "compose-to-sender", OP_COMPOSE_TO_SENDER },
85 { "copy-message", OP_COPY_MESSAGE },
86 { "create-alias", OP_CREATE_ALIAS },
87 { "decode-copy", OP_DECODE_COPY },
88 { "decode-save", OP_DECODE_SAVE },
89 { "decrypt-copy", OP_DECRYPT_COPY },
90 { "decrypt-save", OP_DECRYPT_SAVE },
91 { "delete-message", OP_DELETE },
92 { "delete-subthread", OP_DELETE_SUBTHREAD },
93 { "delete-thread", OP_DELETE_THREAD },
94 { "display-address", OP_DISPLAY_ADDRESS },
95 { "display-toggle-weed", OP_DISPLAY_HEADERS },
96 { "edit", OP_EDIT_RAW_MESSAGE },
97 { "edit-label", OP_EDIT_LABEL },
98 { "edit-or-view-raw-message", OP_EDIT_OR_VIEW_RAW_MESSAGE },
99 { "edit-raw-message", OP_EDIT_RAW_MESSAGE },
100 { "edit-type", OP_ATTACHMENT_EDIT_TYPE },
101 { "enter-command", OP_ENTER_COMMAND },
102#ifdef USE_NOTMUCH
103 { "entire-thread", OP_MAIN_ENTIRE_THREAD },
104#endif
105 { "exit", OP_EXIT },
106 { "extract-keys", OP_EXTRACT_KEYS },
107 { "flag-message", OP_FLAG_MESSAGE },
108 { "followup-message", OP_FOLLOWUP },
109 { "forget-passphrase", OP_FORGET_PASSPHRASE },
110 { "forward-message", OP_FORWARD_MESSAGE },
111 { "forward-to-group", OP_FORWARD_TO_GROUP },
112 { "group-chat-reply", OP_GROUP_CHAT_REPLY },
113 { "group-reply", OP_GROUP_REPLY },
114 { "half-down", OP_HALF_DOWN },
115 { "half-up", OP_HALF_UP },
116 { "help", OP_HELP },
117 { "imap-fetch-mail", OP_MAIN_IMAP_FETCH },
118 { "imap-logout-all", OP_MAIN_IMAP_LOGOUT_ALL },
119 { "jump", OP_JUMP },
120 { "jump", OP_JUMP_1 },
121 { "jump", OP_JUMP_2 },
122 { "jump", OP_JUMP_3 },
123 { "jump", OP_JUMP_4 },
124 { "jump", OP_JUMP_5 },
125 { "jump", OP_JUMP_6 },
126 { "jump", OP_JUMP_7 },
127 { "jump", OP_JUMP_8 },
128 { "jump", OP_JUMP_9 },
129 { "link-threads", OP_MAIN_LINK_THREADS },
130 { "list-reply", OP_LIST_REPLY },
131 { "list-subscribe", OP_LIST_SUBSCRIBE },
132 { "list-unsubscribe", OP_LIST_UNSUBSCRIBE },
133 { "mail", OP_MAIL },
134 { "mail-key", OP_MAIL_KEY },
135 { "mailbox-list", OP_MAILBOX_LIST },
136 { "mark-as-new", OP_TOGGLE_NEW },
137 { "modify-labels", OP_MAIN_MODIFY_TAGS },
138 { "modify-labels-then-hide", OP_MAIN_MODIFY_TAGS_THEN_HIDE },
139 { "modify-tags", OP_MAIN_MODIFY_TAGS },
140 { "modify-tags-then-hide", OP_MAIN_MODIFY_TAGS_THEN_HIDE },
141 { "next-entry", OP_NEXT_ENTRY },
142 { "next-line", OP_NEXT_LINE },
143 { "next-new", OP_MAIN_NEXT_NEW },
144 { "next-new-then-unread", OP_MAIN_NEXT_NEW_THEN_UNREAD },
145 { "next-page", OP_NEXT_PAGE },
146 { "next-subthread", OP_MAIN_NEXT_SUBTHREAD },
147 { "next-thread", OP_MAIN_NEXT_THREAD },
148 { "next-undeleted", OP_MAIN_NEXT_UNDELETED },
149 { "next-unread", OP_MAIN_NEXT_UNREAD },
150 { "next-unread-mailbox", OP_MAIN_NEXT_UNREAD_MAILBOX },
151 { "parent-message", OP_MAIN_PARENT_MESSAGE },
152 { "pipe-entry", OP_PIPE },
153 { "pipe-message", OP_PIPE },
154 { "post-message", OP_POST },
155 { "previous-entry", OP_PREV_ENTRY },
156 { "previous-line", OP_PREV_LINE },
157 { "previous-new", OP_MAIN_PREV_NEW },
158 { "previous-new-then-unread", OP_MAIN_PREV_NEW_THEN_UNREAD },
159 { "previous-page", OP_PREV_PAGE },
160 { "previous-subthread", OP_MAIN_PREV_SUBTHREAD },
161 { "previous-thread", OP_MAIN_PREV_THREAD },
162 { "previous-undeleted", OP_MAIN_PREV_UNDELETED },
163 { "previous-unread", OP_MAIN_PREV_UNREAD },
164 { "print-entry", OP_ATTACHMENT_PRINT },
165 { "print-message", OP_PRINT },
166 { "purge-message", OP_PURGE_MESSAGE },
167 { "purge-thread", OP_PURGE_THREAD },
168 { "quasi-delete", OP_MAIN_QUASI_DELETE },
169 { "quit", OP_QUIT },
170 { "read-subthread", OP_MAIN_READ_SUBTHREAD },
171 { "read-thread", OP_MAIN_READ_THREAD },
172 { "recall-message", OP_RECALL_MESSAGE },
173 { "reconstruct-thread", OP_RECONSTRUCT_THREAD },
174 { "redraw-screen", OP_REDRAW },
175 { "reply", OP_REPLY },
176 { "resend-message", OP_RESEND },
177 { "root-message", OP_MAIN_ROOT_MESSAGE },
178 { "save-entry", OP_ATTACHMENT_SAVE },
179 { "save-message", OP_SAVE },
180 { "search", OP_SEARCH },
181 { "search-next", OP_SEARCH_NEXT },
182 { "search-opposite", OP_SEARCH_OPPOSITE },
183 { "search-reverse", OP_SEARCH_REVERSE },
184 { "search-toggle", OP_SEARCH_TOGGLE },
185 { "set-flag", OP_MAIN_SET_FLAG },
186 { "shell-escape", OP_SHELL_ESCAPE },
187 { "show-log-messages", OP_SHOW_LOG_MESSAGES },
188 { "show-version", OP_VERSION },
189 { "sidebar-first", OP_SIDEBAR_FIRST },
190 { "sidebar-last", OP_SIDEBAR_LAST },
191 { "sidebar-next", OP_SIDEBAR_NEXT },
192 { "sidebar-next-new", OP_SIDEBAR_NEXT_NEW },
193 { "sidebar-open", OP_SIDEBAR_OPEN },
194 { "sidebar-page-down", OP_SIDEBAR_PAGE_DOWN },
195 { "sidebar-page-up", OP_SIDEBAR_PAGE_UP },
196 { "sidebar-prev", OP_SIDEBAR_PREV },
197 { "sidebar-prev-new", OP_SIDEBAR_PREV_NEW },
198 { "sidebar-toggle-virtual", OP_SIDEBAR_TOGGLE_VIRTUAL },
199 { "sidebar-toggle-visible", OP_SIDEBAR_TOGGLE_VISIBLE },
200 { "skip-headers", OP_PAGER_SKIP_HEADERS },
201 { "skip-quoted", OP_PAGER_SKIP_QUOTED },
202 { "sort-mailbox", OP_SORT },
203 { "sort-reverse", OP_SORT_REVERSE },
204 { "sync-mailbox", OP_MAIN_SYNC_FOLDER },
205 { "tag-message", OP_TAG },
206 { "toggle-quoted", OP_PAGER_HIDE_QUOTED },
207 { "toggle-write", OP_TOGGLE_WRITE },
208 { "top", OP_PAGER_TOP },
209 { "undelete-message", OP_UNDELETE },
210 { "undelete-subthread", OP_UNDELETE_SUBTHREAD },
211 { "undelete-thread", OP_UNDELETE_THREAD },
212#ifdef USE_NOTMUCH
213 { "vfolder-from-query", OP_MAIN_VFOLDER_FROM_QUERY },
214 { "vfolder-from-query-readonly", OP_MAIN_VFOLDER_FROM_QUERY_READONLY },
215#endif
216 { "view-attachments", OP_VIEW_ATTACHMENTS },
217 { "view-raw-message", OP_VIEW_RAW_MESSAGE },
218 { "what-key", OP_WHAT_KEY },
219 // Deprecated
220 { "buffy-list", OP_MAILBOX_LIST, OP_DEPRECATED },
221 { "error-history", OP_SHOW_LOG_MESSAGES, OP_DEPRECATED },
222 { NULL, 0 },
223};
224
228const struct MenuOpSeq PagerDefaultBindings[] = { /* map: pager */
229 { OP_ATTACHMENT_EDIT_TYPE, "\005" }, // <Ctrl-E>
230 { OP_BOUNCE_MESSAGE, "b" },
231 { OP_CHECK_TRADITIONAL, "\033P" }, // <Alt-P>
232 { OP_COPY_MESSAGE, "C" },
233 { OP_CREATE_ALIAS, "a" },
234 { OP_DECODE_COPY, "\033C" }, // <Alt-C>
235 { OP_DECODE_SAVE, "\033s" }, // <Alt-s>
236 { OP_DELETE, "d" },
237 { OP_DELETE_SUBTHREAD, "\033d" }, // <Alt-d>
238 { OP_DELETE_THREAD, "\004" }, // <Ctrl-D>
239 { OP_DISPLAY_ADDRESS, "@" },
240 { OP_DISPLAY_HEADERS, "h" },
241 { OP_EDIT_LABEL, "Y" },
242 { OP_EDIT_OR_VIEW_RAW_MESSAGE, "e" },
243 { OP_ENTER_COMMAND, ":" },
244 { OP_EXIT, "i" },
245 { OP_EXIT, "q" },
246 { OP_EXIT, "x" },
247 { OP_EXTRACT_KEYS, "\013" }, // <Ctrl-K>
248 { OP_FLAG_MESSAGE, "F" },
249 { OP_FORGET_PASSPHRASE, "\006" }, // <Ctrl-F>
250 { OP_FORWARD_MESSAGE, "f" },
251 { OP_GROUP_REPLY, "g" },
252 { OP_HELP, "?" },
253 { OP_JUMP_1, "1" },
254 { OP_JUMP_2, "2" },
255 { OP_JUMP_3, "3" },
256 { OP_JUMP_4, "4" },
257 { OP_JUMP_5, "5" },
258 { OP_JUMP_6, "6" },
259 { OP_JUMP_7, "7" },
260 { OP_JUMP_8, "8" },
261 { OP_JUMP_9, "9" },
262 { OP_LIST_REPLY, "L" },
263 { OP_MAIL, "m" },
264 { OP_MAILBOX_LIST, "." },
265 { OP_MAIL_KEY, "\033k" }, // <Alt-k>
266 { OP_MAIN_BREAK_THREAD, "#" },
267 { OP_MAIN_CHANGE_FOLDER, "c" },
268 { OP_MAIN_CHANGE_FOLDER_READONLY, "\033c" }, // <Alt-c>
269 { OP_MAIN_CLEAR_FLAG, "W" },
270 { OP_MAIN_LINK_THREADS, "&" },
271 { OP_MAIN_NEXT_NEW_THEN_UNREAD, "\t" }, // <Tab>
272 { OP_MAIN_NEXT_SUBTHREAD, "\033n" }, // <Alt-n>
273 { OP_MAIN_NEXT_THREAD, "\016" }, // <Ctrl-N>
274 { OP_MAIN_NEXT_UNDELETED, "<down>" },
275 { OP_MAIN_NEXT_UNDELETED, "<right>" },
276 { OP_MAIN_NEXT_UNDELETED, "j" },
277 { OP_MAIN_PARENT_MESSAGE, "P" },
278 { OP_MAIN_PREV_SUBTHREAD, "\033p" }, // <Alt-p>
279 { OP_MAIN_PREV_THREAD, "\020" }, // <Ctrl-P>
280 { OP_MAIN_PREV_UNDELETED, "<left>" },
281 { OP_MAIN_PREV_UNDELETED, "<up>" },
282 { OP_MAIN_PREV_UNDELETED, "k" },
283 { OP_MAIN_READ_SUBTHREAD, "\033r" }, // <Alt-r>
284 { OP_MAIN_READ_THREAD, "\022" }, // <Ctrl-R>
285 { OP_MAIN_SET_FLAG, "w" },
286 { OP_MAIN_SYNC_FOLDER, "$" },
287 { OP_NEXT_ENTRY, "J" },
288 { OP_NEXT_LINE, "<keypadenter>" },
289 { OP_NEXT_LINE, "\n" }, // <Enter>
290 { OP_NEXT_LINE, "\r" }, // <Return>
291 { OP_NEXT_PAGE, " " }, // <Space>
292 { OP_NEXT_PAGE, "<pagedown>" },
293 { OP_PAGER_BOTTOM, "<end>" },
294 { OP_PAGER_HIDE_QUOTED, "T" },
295 { OP_PAGER_SKIP_HEADERS, "H" },
296 { OP_PAGER_SKIP_QUOTED, "S" },
297 { OP_PAGER_TOP, "<home>" },
298 { OP_PAGER_TOP, "^" },
299 { OP_PIPE, "|" },
300 { OP_PREV_ENTRY, "K" },
301 { OP_PREV_LINE, "<backspace>" },
302 { OP_PREV_PAGE, "-" },
303 { OP_PREV_PAGE, "<pageup>" },
304 { OP_PRINT, "p" },
305 { OP_QUIT, "Q" },
306 { OP_RECALL_MESSAGE, "R" },
307 { OP_REDRAW, "\014" }, // <Ctrl-L>
308 { OP_REPLY, "r" },
309 { OP_RESEND, "\033e" }, // <Alt-e>
310 { OP_SAVE, "s" },
311 { OP_SEARCH, "/" },
312 { OP_SEARCH_NEXT, "n" },
313 { OP_SEARCH_REVERSE, "\033/" }, // <Alt-/>
314 { OP_SEARCH_TOGGLE, "\\" }, // <Backslash>
315 { OP_SHELL_ESCAPE, "!" },
316 { OP_SORT, "o" },
317 { OP_SORT_REVERSE, "O" },
318 { OP_TAG, "t" },
319 { OP_TOGGLE_NEW, "N" },
320 { OP_TOGGLE_WRITE, "%" },
321 { OP_UNDELETE, "u" },
322 { OP_UNDELETE_SUBTHREAD, "\033u" }, // <Alt-u>
323 { OP_UNDELETE_THREAD, "\025" }, // <Ctrl-U>
324 { OP_VERSION, "V" },
325 { OP_VIEW_ATTACHMENTS, "v" },
326 { 0, NULL },
327};
328// clang-format on
329
338static inline bool assert_pager_mode(bool test)
339{
340 if (test)
341 return true;
342
345 return false;
346}
347
356static int up_n_lines(int nlines, struct Line *info, int cur, bool hiding)
357{
358 while ((cur > 0) && (nlines > 0))
359 {
360 cur--;
361 if (!hiding || !COLOR_QUOTED(info[cur].cid))
362 nlines--;
363 }
364
365 return cur;
366}
367
375bool jump_to_bottom(struct PagerPrivateData *priv, struct PagerView *pview)
376{
377 if (!(priv->lines[priv->cur_line].offset < (priv->st.st_size - 1)))
378 {
379 return false;
380 }
381
382 int line_num = priv->cur_line;
383 /* make sure the types are defined to the end of file */
384 while (display_line(priv->fp, &priv->bytes_read, &priv->lines, line_num,
385 &priv->lines_used, &priv->lines_max,
386 priv->has_types | (pview->flags & MUTT_PAGER_NOWRAP),
387 &priv->quote_list, &priv->q_level, &priv->force_redraw,
388 &priv->search_re, priv->pview->win_pager, &priv->ansi_list) == 0)
389 {
390 line_num++;
391 }
392 priv->top_line = up_n_lines(priv->pview->win_pager->state.rows, priv->lines,
393 priv->lines_used, priv->hide_quoted);
395 return true;
396}
397
398// -----------------------------------------------------------------------------
399
403static int op_pager_bottom(struct IndexSharedData *shared,
404 struct PagerPrivateData *priv, int op)
405{
406 if (!jump_to_bottom(priv, priv->pview))
407 mutt_message(_("Bottom of message is shown"));
408
409 return FR_SUCCESS;
410}
411
415static int op_pager_half_down(struct IndexSharedData *shared,
416 struct PagerPrivateData *priv, int op)
417{
418 const bool c_pager_stop = cs_subset_bool(NeoMutt->sub, "pager_stop");
419 if (priv->lines[priv->cur_line].offset < (priv->st.st_size - 1))
420 {
421 priv->top_line = up_n_lines(priv->pview->win_pager->state.rows / 2,
422 priv->lines, priv->cur_line, priv->hide_quoted);
424 }
425 else if (c_pager_stop)
426 {
427 /* emulate "less -q" and don't go on to the next message. */
428 mutt_message(_("Bottom of message is shown"));
429 }
430 else
431 {
432 /* end of the current message, so display the next message. */
434 }
435 return FR_SUCCESS;
436}
437
441static int op_pager_half_up(struct IndexSharedData *shared,
442 struct PagerPrivateData *priv, int op)
443{
444 if (priv->top_line)
445 {
446 priv->top_line = up_n_lines(priv->pview->win_pager->state.rows / 2 +
447 (priv->pview->win_pager->state.rows % 2),
448 priv->lines, priv->top_line, priv->hide_quoted);
450 }
451 else
452 {
453 mutt_message(_("Top of message is shown"));
454 }
455 return FR_SUCCESS;
456}
457
461static int op_pager_hide_quoted(struct IndexSharedData *shared,
462 struct PagerPrivateData *priv, int op)
463{
464 if (!priv->has_types)
465 return FR_NO_ACTION;
466
467 priv->hide_quoted ^= MUTT_HIDE;
468 if (priv->hide_quoted && COLOR_QUOTED(priv->lines[priv->top_line].cid))
469 {
470 priv->top_line = up_n_lines(1, priv->lines, priv->top_line, priv->hide_quoted);
471 }
472 else
473 {
475 }
477 return FR_SUCCESS;
478}
479
483static int op_pager_next_line(struct IndexSharedData *shared,
484 struct PagerPrivateData *priv, int op)
485{
486 if (priv->lines[priv->cur_line].offset < (priv->st.st_size - 1))
487 {
488 priv->top_line++;
489 if (priv->hide_quoted)
490 {
491 while ((priv->top_line < priv->lines_used) &&
492 COLOR_QUOTED(priv->lines[priv->top_line].cid))
493 {
494 priv->top_line++;
495 }
496 }
498 }
499 else
500 {
501 mutt_message(_("Bottom of message is shown"));
502 }
503 return FR_SUCCESS;
504}
505
509static int op_pager_next_page(struct IndexSharedData *shared,
510 struct PagerPrivateData *priv, int op)
511{
512 const bool c_pager_stop = cs_subset_bool(NeoMutt->sub, "pager_stop");
513 if (priv->lines[priv->cur_line].offset < (priv->st.st_size - 1))
514 {
515 const short c_pager_context = cs_subset_number(NeoMutt->sub, "pager_context");
516 priv->top_line = up_n_lines(c_pager_context, priv->lines, priv->cur_line, priv->hide_quoted);
518 }
519 else if (c_pager_stop)
520 {
521 /* emulate "less -q" and don't go on to the next message. */
522 mutt_message(_("Bottom of message is shown"));
523 }
524 else
525 {
526 /* end of the current message, so display the next message. */
528 }
529 return FR_SUCCESS;
530}
531
535static int op_pager_prev_line(struct IndexSharedData *shared,
536 struct PagerPrivateData *priv, int op)
537{
538 if (priv->top_line)
539 {
540 priv->top_line = up_n_lines(1, priv->lines, priv->top_line, priv->hide_quoted);
542 }
543 else
544 {
545 mutt_message(_("Top of message is shown"));
546 }
547 return FR_SUCCESS;
548}
549
553static int op_pager_prev_page(struct IndexSharedData *shared,
554 struct PagerPrivateData *priv, int op)
555{
556 if (priv->top_line == 0)
557 {
558 mutt_message(_("Top of message is shown"));
559 }
560 else
561 {
562 const short c_pager_context = cs_subset_number(NeoMutt->sub, "pager_context");
563 priv->top_line = up_n_lines(priv->pview->win_pager->state.rows - c_pager_context,
564 priv->lines, priv->top_line, priv->hide_quoted);
566 }
567 return FR_SUCCESS;
568}
569
577static int op_pager_search(struct IndexSharedData *shared,
578 struct PagerPrivateData *priv, int op)
579{
580 struct PagerView *pview = priv->pview;
581
582 int rc = FR_NO_ACTION;
583 struct Buffer *buf = buf_pool_get();
584
585 buf_strcpy(buf, priv->search_str);
586 if (mw_get_field(((op == OP_SEARCH) || (op == OP_SEARCH_NEXT)) ? _("Search for: ") : _("Reverse search for: "),
588 {
589 goto done;
590 }
591
592 if (mutt_str_equal(buf_string(buf), priv->search_str))
593 {
594 if (priv->search_compiled)
595 {
596 /* do an implicit search-next */
597 if (op == OP_SEARCH)
598 op = OP_SEARCH_NEXT;
599 else
600 op = OP_SEARCH_OPPOSITE;
601
602 priv->wrapped = false;
603 op_pager_search_next(shared, priv, op);
604 }
605 }
606
607 if (buf_is_empty(buf))
608 goto done;
609
610 mutt_str_copy(priv->search_str, buf_string(buf), sizeof(priv->search_str));
611
612 /* leave search_back alone if op == OP_SEARCH_NEXT */
613 if (op == OP_SEARCH)
614 priv->search_back = false;
615 else if (op == OP_SEARCH_REVERSE)
616 priv->search_back = true;
617
618 if (priv->search_compiled)
619 {
620 regfree(&priv->search_re);
621 for (size_t i = 0; i < priv->lines_used; i++)
622 {
623 FREE(&(priv->lines[i].search));
624 priv->lines[i].search_arr_size = -1;
625 }
626 }
627
628 uint16_t rflags = mutt_mb_is_lower(priv->search_str) ? REG_ICASE : 0;
629 int err = REG_COMP(&priv->search_re, priv->search_str, REG_NEWLINE | rflags);
630 if (err != 0)
631 {
632 regerror(err, &priv->search_re, buf->data, buf->dsize);
633 mutt_error("%s", buf_string(buf));
634 for (size_t i = 0; i < priv->lines_max; i++)
635 {
636 /* cleanup */
637 FREE(&(priv->lines[i].search));
638 priv->lines[i].search_arr_size = -1;
639 }
640 priv->search_flag = 0;
641 priv->search_compiled = false;
642 }
643 else
644 {
645 priv->search_compiled = true;
646 /* update the search pointers */
647 int line_num = 0;
648 while (display_line(priv->fp, &priv->bytes_read, &priv->lines, line_num,
649 &priv->lines_used, &priv->lines_max,
650 MUTT_SEARCH | (pview->flags & MUTT_PAGER_NOWRAP) | priv->has_types,
651 &priv->quote_list, &priv->q_level, &priv->force_redraw,
652 &priv->search_re, priv->pview->win_pager, &priv->ansi_list) == 0)
653 {
654 line_num++;
655 }
656
657 if (priv->search_back)
658 {
659 /* searching backward */
660 int i;
661 for (i = priv->top_line; i >= 0; i--)
662 {
663 if ((!priv->hide_quoted || !COLOR_QUOTED(priv->lines[i].cid)) &&
664 !priv->lines[i].cont_line && (priv->lines[i].search_arr_size > 0))
665 {
666 break;
667 }
668 }
669
670 if (i >= 0)
671 priv->top_line = i;
672 }
673 else
674 {
675 /* searching forward */
676 int i;
677 for (i = priv->top_line; i < priv->lines_used; i++)
678 {
679 if ((!priv->hide_quoted || !COLOR_QUOTED(priv->lines[i].cid)) &&
680 !priv->lines[i].cont_line && (priv->lines[i].search_arr_size > 0))
681 {
682 break;
683 }
684 }
685
686 if (i < priv->lines_used)
687 priv->top_line = i;
688 }
689
690 if (priv->lines[priv->top_line].search_arr_size == 0)
691 {
692 priv->search_flag = 0;
693 mutt_error(_("Not found"));
694 }
695 else
696 {
697 const short c_search_context = cs_subset_number(NeoMutt->sub, "search_context");
698 priv->search_flag = MUTT_SEARCH;
699 /* give some context for search results */
700 if (c_search_context < priv->pview->win_pager->state.rows)
701 priv->searchctx = c_search_context;
702 else
703 priv->searchctx = 0;
704 if (priv->top_line - priv->searchctx > 0)
705 priv->top_line -= priv->searchctx;
706 }
707 }
710 rc = FR_SUCCESS;
711
712done:
713 buf_pool_release(&buf);
714 return rc;
715}
716
724static int op_pager_search_next(struct IndexSharedData *shared,
725 struct PagerPrivateData *priv, int op)
726{
727 if (priv->search_compiled)
728 {
729 const short c_search_context = cs_subset_number(NeoMutt->sub, "search_context");
730 priv->wrapped = false;
731
732 if (c_search_context < priv->pview->win_pager->state.rows)
733 priv->searchctx = c_search_context;
734 else
735 priv->searchctx = 0;
736
737 search_next:
738 if ((!priv->search_back && (op == OP_SEARCH_NEXT)) ||
739 (priv->search_back && (op == OP_SEARCH_OPPOSITE)))
740 {
741 /* searching forward */
742 int i;
743 for (i = priv->wrapped ? 0 : priv->top_line + priv->searchctx + 1;
744 i < priv->lines_used; i++)
745 {
746 if ((!priv->hide_quoted || !COLOR_QUOTED(priv->lines[i].cid)) &&
747 !priv->lines[i].cont_line && (priv->lines[i].search_arr_size > 0))
748 {
749 break;
750 }
751 }
752
753 const bool c_wrap_search = cs_subset_bool(NeoMutt->sub, "wrap_search");
754 if (i < priv->lines_used)
755 {
756 priv->top_line = i;
757 }
758 else if (priv->wrapped || !c_wrap_search)
759 {
760 mutt_error(_("Not found"));
761 }
762 else
763 {
764 mutt_message(_("Search wrapped to top"));
765 priv->wrapped = true;
766 goto search_next;
767 }
768 }
769 else
770 {
771 /* searching backward */
772 int i;
773 for (i = priv->wrapped ? priv->lines_used : priv->top_line + priv->searchctx - 1;
774 i >= 0; i--)
775 {
776 if ((!priv->hide_quoted ||
777 (priv->has_types && !COLOR_QUOTED(priv->lines[i].cid))) &&
778 !priv->lines[i].cont_line && (priv->lines[i].search_arr_size > 0))
779 {
780 break;
781 }
782 }
783
784 const bool c_wrap_search = cs_subset_bool(NeoMutt->sub, "wrap_search");
785 if (i >= 0)
786 {
787 priv->top_line = i;
788 }
789 else if (priv->wrapped || !c_wrap_search)
790 {
791 mutt_error(_("Not found"));
792 }
793 else
794 {
795 mutt_message(_("Search wrapped to bottom"));
796 priv->wrapped = true;
797 goto search_next;
798 }
799 }
800
801 if (priv->lines[priv->top_line].search_arr_size > 0)
802 {
803 priv->search_flag = MUTT_SEARCH;
804 /* give some context for search results */
805 if (priv->top_line - priv->searchctx > 0)
806 priv->top_line -= priv->searchctx;
807 }
808
810 return FR_SUCCESS;
811 }
812
813 /* no previous search pattern */
814 return op_pager_search(shared, priv, op);
815}
816
820static int op_pager_skip_headers(struct IndexSharedData *shared,
821 struct PagerPrivateData *priv, int op)
822{
823 struct PagerView *pview = priv->pview;
824
825 if (!priv->has_types)
826 return FR_NO_ACTION;
827
828 int rc = 0;
829 int new_topline = 0;
830
831 while (((new_topline < priv->lines_used) ||
832 (0 == (rc = display_line(priv->fp, &priv->bytes_read, &priv->lines,
833 new_topline, &priv->lines_used, &priv->lines_max,
834 MUTT_TYPES | (pview->flags & MUTT_PAGER_NOWRAP), &priv->quote_list,
835 &priv->q_level, &priv->force_redraw, &priv->search_re,
836 priv->pview->win_pager, &priv->ansi_list)))) &&
837 color_is_header(priv->lines[new_topline].cid))
838 {
839 new_topline++;
840 }
841
842 if (rc < 0)
843 {
844 /* L10N: Displayed if <skip-headers> is invoked in the pager, but
845 there is no text past the headers.
846 (I don't think this is actually possible in Mutt's code, but
847 display some kind of message in case it somehow occurs.) */
848 mutt_warning(_("No text past headers"));
849 return FR_NO_ACTION;
850 }
851 priv->top_line = new_topline;
853 return FR_SUCCESS;
854}
855
859static int op_pager_skip_quoted(struct IndexSharedData *shared,
860 struct PagerPrivateData *priv, int op)
861{
862 struct PagerView *pview = priv->pview;
863
864 if (!priv->has_types)
865 return FR_NO_ACTION;
866
867 const short c_pager_skip_quoted_context = cs_subset_number(NeoMutt->sub, "pager_skip_quoted_context");
868 int rc = 0;
869 int new_topline = priv->top_line;
870 int num_quoted = 0;
871
872 /* In a header? Skip all the email headers, and done */
873 if (color_is_header(priv->lines[new_topline].cid))
874 {
875 while (((new_topline < priv->lines_used) ||
876 (0 == (rc = display_line(priv->fp, &priv->bytes_read, &priv->lines,
877 new_topline, &priv->lines_used, &priv->lines_max,
878 MUTT_TYPES | (pview->flags & MUTT_PAGER_NOWRAP), &priv->quote_list,
879 &priv->q_level, &priv->force_redraw, &priv->search_re,
880 priv->pview->win_pager, &priv->ansi_list)))) &&
881 color_is_header(priv->lines[new_topline].cid))
882 {
883 new_topline++;
884 }
885 priv->top_line = new_topline;
887 return FR_SUCCESS;
888 }
889
890 /* Already in the body? Skip past previous "context" quoted lines */
891 if (c_pager_skip_quoted_context > 0)
892 {
893 while (((new_topline < priv->lines_used) ||
894 (0 == (rc = display_line(priv->fp, &priv->bytes_read, &priv->lines,
895 new_topline, &priv->lines_used, &priv->lines_max,
896 MUTT_TYPES | (pview->flags & MUTT_PAGER_NOWRAP), &priv->quote_list,
897 &priv->q_level, &priv->force_redraw, &priv->search_re,
898 priv->pview->win_pager, &priv->ansi_list)))) &&
899 COLOR_QUOTED(priv->lines[new_topline].cid))
900 {
901 new_topline++;
902 num_quoted++;
903 }
904
905 if (rc < 0)
906 {
907 mutt_error(_("No more unquoted text after quoted text"));
908 return FR_NO_ACTION;
909 }
910 }
911
912 if (num_quoted <= c_pager_skip_quoted_context)
913 {
914 num_quoted = 0;
915
916 while (((new_topline < priv->lines_used) ||
917 (0 == (rc = display_line(priv->fp, &priv->bytes_read, &priv->lines,
918 new_topline, &priv->lines_used, &priv->lines_max,
919 MUTT_TYPES | (pview->flags & MUTT_PAGER_NOWRAP), &priv->quote_list,
920 &priv->q_level, &priv->force_redraw, &priv->search_re,
921 priv->pview->win_pager, &priv->ansi_list)))) &&
922 !COLOR_QUOTED(priv->lines[new_topline].cid))
923 {
924 new_topline++;
925 }
926
927 if (rc < 0)
928 {
929 mutt_error(_("No more quoted text"));
930 return FR_NO_ACTION;
931 }
932
933 while (((new_topline < priv->lines_used) ||
934 (0 == (rc = display_line(priv->fp, &priv->bytes_read, &priv->lines,
935 new_topline, &priv->lines_used, &priv->lines_max,
936 MUTT_TYPES | (pview->flags & MUTT_PAGER_NOWRAP), &priv->quote_list,
937 &priv->q_level, &priv->force_redraw, &priv->search_re,
938 priv->pview->win_pager, &priv->ansi_list)))) &&
939 COLOR_QUOTED(priv->lines[new_topline].cid))
940 {
941 new_topline++;
942 num_quoted++;
943 }
944
945 if (rc < 0)
946 {
947 mutt_error(_("No more unquoted text after quoted text"));
948 return FR_NO_ACTION;
949 }
950 }
951 priv->top_line = new_topline - MIN(c_pager_skip_quoted_context, num_quoted);
953 return FR_SUCCESS;
954}
955
959static int op_pager_top(struct IndexSharedData *shared, struct PagerPrivateData *priv, int op)
960{
961 if (priv->top_line == 0)
962 {
963 mutt_message(_("Top of message is shown"));
964 }
965 else
966 {
967 priv->top_line = 0;
969 }
970
971 return FR_SUCCESS;
972}
973
974// -----------------------------------------------------------------------------
975
979static int op_exit(struct IndexSharedData *shared, struct PagerPrivateData *priv, int op)
980{
981 priv->rc = -1;
982 priv->loop = PAGER_LOOP_QUIT;
983 return FR_DONE;
984}
985
989static int op_help(struct IndexSharedData *shared, struct PagerPrivateData *priv, int op)
990{
991 if (priv->pview->mode == PAGER_MODE_HELP)
992 {
993 /* don't let the user enter the help-menu from the help screen! */
994 mutt_error(_("Help is currently being shown"));
995 return FR_ERROR;
996 }
999 return FR_SUCCESS;
1000}
1001
1005static int op_save(struct IndexSharedData *shared, struct PagerPrivateData *priv, int op)
1006{
1007 struct PagerView *pview = priv->pview;
1008 if (pview->mode != PAGER_MODE_OTHER)
1009 return FR_UNKNOWN;
1010
1011 if (!priv->fp)
1012 return FR_UNKNOWN;
1013
1014 int rc = FR_ERROR;
1015 FILE *fp_save = NULL;
1016 struct Buffer *buf = buf_pool_get();
1017
1018 // Save the current read position
1019 long pos = ftell(priv->fp);
1020 rewind(priv->fp);
1021
1022 struct FileCompletionData cdata = { false, NULL, NULL, NULL };
1023 if ((mw_get_field(_("Save to file: "), buf, MUTT_COMP_CLEAR, HC_FILE,
1024 &CompleteFileOps, &cdata) != 0) ||
1025 buf_is_empty(buf))
1026 {
1027 rc = FR_SUCCESS;
1028 goto done;
1029 }
1030
1031 buf_expand_path(buf);
1032 fp_save = mutt_file_fopen(buf_string(buf), "a+");
1033 if (!fp_save)
1034 {
1035 mutt_perror("%s", buf_string(buf));
1036 goto done;
1037 }
1038
1039 int bytes = mutt_file_copy_stream(priv->fp, fp_save);
1040 if (bytes == -1)
1041 {
1042 mutt_perror("%s", buf_string(buf));
1043 goto done;
1044 }
1045
1046 // Restore the read position
1047 if (pos >= 0)
1048 mutt_file_seek(priv->fp, pos, SEEK_CUR);
1049
1050 mutt_message(_("Saved to: %s"), buf_string(buf));
1051 rc = FR_SUCCESS;
1052
1053done:
1054 mutt_file_fclose(&fp_save);
1055 buf_pool_release(&buf);
1056
1057 return rc;
1058}
1059
1063static int op_search_toggle(struct IndexSharedData *shared,
1064 struct PagerPrivateData *priv, int op)
1065{
1066 if (priv->search_compiled)
1067 {
1068 priv->search_flag ^= MUTT_SEARCH;
1070 }
1071 return FR_SUCCESS;
1072}
1073
1077static int op_view_attachments(struct IndexSharedData *shared,
1078 struct PagerPrivateData *priv, int op)
1079{
1080 struct PagerView *pview = priv->pview;
1081
1082 // This needs to be delegated
1083 if (pview->flags & MUTT_PAGER_ATTACHMENT)
1084 return FR_UNKNOWN;
1085
1086 if (!assert_pager_mode(pview->mode == PAGER_MODE_EMAIL))
1087 return FR_NOT_IMPL;
1088 dlg_attachment(NeoMutt->sub, shared->mailbox_view, shared->email,
1089 pview->pdata->fp, shared->attach_msg);
1090 if (shared->email->attach_del)
1091 shared->mailbox->changed = true;
1093 return FR_SUCCESS;
1094}
1095
1096// -----------------------------------------------------------------------------
1097
1101static const struct PagerFunction PagerFunctions[] = {
1102 // clang-format off
1103 { OP_EXIT, op_exit },
1104 { OP_HALF_DOWN, op_pager_half_down },
1105 { OP_HALF_UP, op_pager_half_up },
1106 { OP_HELP, op_help },
1107 { OP_NEXT_LINE, op_pager_next_line },
1108 { OP_NEXT_PAGE, op_pager_next_page },
1109 { OP_PAGER_BOTTOM, op_pager_bottom },
1110 { OP_PAGER_HIDE_QUOTED, op_pager_hide_quoted },
1111 { OP_PAGER_SKIP_HEADERS, op_pager_skip_headers },
1112 { OP_PAGER_SKIP_QUOTED, op_pager_skip_quoted },
1113 { OP_PAGER_TOP, op_pager_top },
1114 { OP_PREV_LINE, op_pager_prev_line },
1115 { OP_PREV_PAGE, op_pager_prev_page },
1116 { OP_SAVE, op_save },
1117 { OP_SEARCH, op_pager_search },
1118 { OP_SEARCH_REVERSE, op_pager_search },
1119 { OP_SEARCH_NEXT, op_pager_search_next },
1120 { OP_SEARCH_OPPOSITE, op_pager_search_next },
1121 { OP_SEARCH_TOGGLE, op_search_toggle },
1122 { OP_VIEW_ATTACHMENTS, op_view_attachments },
1123 { 0, NULL },
1124 // clang-format on
1125};
1126
1131{
1132 if (!win)
1133 {
1135 return FR_ERROR;
1136 }
1137
1138 struct PagerPrivateData *priv = win->parent->wdata;
1139 if (!priv)
1140 return FR_ERROR;
1141
1142 struct MuttWindow *dlg = dialog_find(win);
1143 if (!dlg || !dlg->wdata)
1144 return FR_ERROR;
1145
1146 int rc = FR_UNKNOWN;
1147 for (size_t i = 0; PagerFunctions[i].op != OP_NULL; i++)
1148 {
1149 const struct PagerFunction *fn = &PagerFunctions[i];
1150 if (fn->op == op)
1151 {
1152 struct IndexSharedData *shared = dlg->wdata;
1153 rc = fn->function(shared, priv, op);
1154 break;
1155 }
1156 }
1157
1158 if (rc == FR_UNKNOWN) // Not our function
1159 return rc;
1160
1161 const char *result = dispatcher_get_retval_name(rc);
1162 mutt_debug(LL_DEBUG1, "Handled %s (%d) -> %s\n", opcodes_get_name(op), op, NONULL(result));
1163
1164 return rc;
1165}
GUI display the mailboxes in a side panel.
const struct CompleteOps CompleteFileOps
Auto-Completion of Files.
Definition complete.c:152
Select a Mailbox from a list.
bool buf_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition buffer.c:291
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition buffer.c:395
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition buffer.h:96
Color and attribute parsing.
short cs_subset_number(const struct ConfigSubset *sub, const char *name)
Get a number config item by name.
Definition helpers.c:143
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition helpers.c:47
Convenience wrapper for the config headers.
Convenience wrapper for the core headers.
struct MuttWindow * dialog_find(struct MuttWindow *win)
Find the parent Dialog of a Window.
Definition dialog.c:89
const char * dispatcher_get_retval_name(int rv)
Get the name of a return value.
Definition dispatcher.c:54
@ FR_SUCCESS
Valid function - successfully performed.
Definition dispatcher.h:39
@ FR_DONE
Exit the Dialog.
Definition dispatcher.h:35
@ FR_UNKNOWN
Unknown function.
Definition dispatcher.h:33
@ FR_ERROR
Valid function - error occurred.
Definition dispatcher.h:38
@ FR_NOT_IMPL
Invalid function - feature not enabled.
Definition dispatcher.h:36
@ FR_NO_ACTION
Valid function - no action performed.
Definition dispatcher.h:37
bool color_is_header(enum ColorId cid)
Colour is for an Email header.
Definition display.c:486
int display_line(FILE *fp, LOFF_T *bytes_read, struct Line **lines, int line_num, int *lines_used, int *lines_max, PagerFlags flags, struct QuoteStyle **quote_list, int *q_level, bool *force_redraw, regex_t *search_re, struct MuttWindow *win_pager, struct AttrColorList *ansi_list)
Print a line on screen.
Definition display.c:1051
Pager Display.
void pager_queue_redraw(struct PagerPrivateData *priv, PagerRedrawFlags redraw)
Queue a request for a redraw.
Definition dlg_pager.c:128
Edit a string.
Structs that make up an email.
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition file.c:225
bool mutt_file_seek(FILE *fp, LOFF_T offset, int whence)
Wrapper for fseeko with error handling.
Definition file.c:655
#define mutt_file_fclose(FP)
Definition file.h:139
#define mutt_file_fopen(PATH, MODE)
Definition file.h:138
void mutt_flushinp(void)
Empty all the keyboard buffers.
Definition get.c:58
static int op_exit(struct AliasMenuData *mdata, int op)
exit this menu - Implements alias_function_t -
Definition functions.c:200
int pager_function_dispatcher(struct MuttWindow *win, int op)
Perform a Pager function - Implements function_dispatcher_t -.
Definition functions.c:1130
static int op_help(struct EnterWindowData *wdata, int op)
Display Help - Implements enter_function_t -.
Definition functions.c:424
void dlg_attachment(struct ConfigSubset *sub, struct MailboxView *mv, struct Email *e, FILE *fp, bool attach_msg)
Show the attachments in a Menu -.
Definition dlg_attach.c:208
int mw_get_field(const char *prompt, struct Buffer *buf, CompletionFlags complete, enum HistoryClass hclass, const struct CompleteOps *comp_api, void *cdata)
Ask the user for a string -.
Definition window.c:272
static int op_view_attachments(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Show MIME attachments - Implements index_function_t -.
Definition functions.c:2483
static int op_save(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Make decrypted copy - Implements index_function_t -.
Definition functions.c:2217
#define mutt_warning(...)
Definition logging2.h:91
#define mutt_error(...)
Definition logging2.h:93
#define mutt_message(...)
Definition logging2.h:92
#define mutt_debug(LEVEL,...)
Definition logging2.h:90
#define mutt_perror(...)
Definition logging2.h:94
static int op_pager_skip_quoted(struct IndexSharedData *shared, struct PagerPrivateData *priv, int op)
Skip beyond quoted text - Implements pager_function_t -.
Definition functions.c:859
static int op_pager_skip_headers(struct IndexSharedData *shared, struct PagerPrivateData *priv, int op)
Jump to first line after headers - Implements pager_function_t -.
Definition functions.c:820
static int op_pager_half_up(struct IndexSharedData *shared, struct PagerPrivateData *priv, int op)
Scroll up 1/2 page - Implements pager_function_t -.
Definition functions.c:441
static int op_pager_next_line(struct IndexSharedData *shared, struct PagerPrivateData *priv, int op)
Scroll down one line - Implements pager_function_t -.
Definition functions.c:483
static int op_search_toggle(struct IndexSharedData *shared, struct PagerPrivateData *priv, int op)
Toggle search pattern coloring - Implements pager_function_t -.
Definition functions.c:1063
static int op_pager_top(struct IndexSharedData *shared, struct PagerPrivateData *priv, int op)
Jump to the top of the message - Implements pager_function_t -.
Definition functions.c:959
static int op_pager_hide_quoted(struct IndexSharedData *shared, struct PagerPrivateData *priv, int op)
Toggle display of quoted text - Implements pager_function_t -.
Definition functions.c:461
static int op_pager_next_page(struct IndexSharedData *shared, struct PagerPrivateData *priv, int op)
Move to the next page - Implements pager_function_t -.
Definition functions.c:509
static int op_pager_prev_page(struct IndexSharedData *shared, struct PagerPrivateData *priv, int op)
Move to the previous page - Implements pager_function_t -.
Definition functions.c:553
static int op_pager_bottom(struct IndexSharedData *shared, struct PagerPrivateData *priv, int op)
Jump to the bottom of the message - Implements pager_function_t -.
Definition functions.c:403
static int op_pager_half_down(struct IndexSharedData *shared, struct PagerPrivateData *priv, int op)
Scroll down 1/2 page - Implements pager_function_t -.
Definition functions.c:415
static int op_pager_search(struct IndexSharedData *shared, struct PagerPrivateData *priv, int op)
Search for a regular expression - Implements pager_function_t -.
Definition functions.c:577
static int op_pager_search_next(struct IndexSharedData *shared, struct PagerPrivateData *priv, int op)
Search for next match - Implements pager_function_t -.
Definition functions.c:724
static int op_pager_prev_line(struct IndexSharedData *shared, struct PagerPrivateData *priv, int op)
Scroll up one line - Implements pager_function_t -.
Definition functions.c:535
Convenience wrapper for the gui headers.
void mutt_help(enum MenuType menu)
Display the Help Page.
Definition help.c:148
Read/write command history from/to a file.
@ HC_FILE
Files.
Definition lib.h:57
@ HC_PATTERN
Patterns.
Definition lib.h:58
bool index_next_undeleted(struct MuttWindow *win_index)
Select the next undeleted Email (if possible)
Definition functions.c:390
GUI manage the main index (list of emails)
const struct MenuOpSeq PagerDefaultBindings[]
Key bindings for the Pager Menu.
Definition functions.c:228
const struct MenuFuncOp OpPager[]
Functions for the Pager Menu.
Definition functions.c:70
Manage keymappings.
#define OP_DEPRECATED
Convenience symbol.
Definition lib.h:109
@ LL_DEBUG1
Log at debug level 1.
Definition logging2.h:44
bool mutt_mb_is_lower(const char *s)
Does a multi-byte string contain only lowercase characters?
Definition mbyte.c:354
#define FREE(x)
Definition memory.h:62
#define MIN(a, b)
Definition memory.h:37
GUI present the user with a selectable list.
Convenience wrapper for the library headers.
#define N_(a)
Definition message.h:32
#define _(a)
Definition message.h:28
bool notify_send(struct Notify *notify, enum NotifyType event_type, int event_subtype, void *event_data)
Send out a notification message.
Definition notify.c:173
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition string.c:660
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:581
Many unsorted constants and some structs.
#define MUTT_COMP_CLEAR
Clear input if printable character is pressed.
Definition mutt.h:57
void buf_expand_path(struct Buffer *buf)
Create the canonical path.
Definition muttlib.c:314
Some miscellaneous functions.
@ NT_PAGER
Pager data has changed, NotifyPager, PagerPrivateData.
Definition notify_type.h:53
const char * opcodes_get_name(int op)
Get the name of an opcode.
Definition opcodes.c:48
static int up_n_lines(int nlines, struct Line *info, int cur, bool hiding)
Reposition the pager's view up by n lines.
Definition functions.c:356
static const char * Not_available_in_this_menu
Error message for unavailable functions.
Definition functions.c:61
bool jump_to_bottom(struct PagerPrivateData *priv, struct PagerView *pview)
Make sure the bottom line is displayed.
Definition functions.c:375
static bool assert_pager_mode(bool test)
Check that pager is in correct mode.
Definition functions.c:338
static const struct PagerFunction PagerFunctions[]
All the NeoMutt functions that the Pager supports.
Definition functions.c:1101
Pager functions.
GUI display a file/email/help in a viewport with paging.
@ PAGER_LOOP_QUIT
Quit the Pager.
Definition lib.h:151
#define NT_PAGER_VIEW
Pager View has changed.
Definition lib.h:185
#define MUTT_PAGER_NOWRAP
Format for term width, ignore $wrap.
Definition lib.h:71
#define MUTT_HIDE
Don't show quoted text.
Definition lib.h:63
#define MUTT_TYPES
Compute line's type.
Definition lib.h:65
#define MUTT_SEARCH
Resolve search patterns.
Definition lib.h:64
@ PAGER_MODE_OTHER
Pager is invoked via 3rd path. Non-email content is likely to be shown.
Definition lib.h:140
@ PAGER_MODE_HELP
Pager is invoked via 3rd path to show help.
Definition lib.h:139
@ PAGER_MODE_EMAIL
Pager is invoked via 1st path. The mime part is selected automatically.
Definition lib.h:136
#define PAGER_REDRAW_PAGER
Redraw the pager.
Definition lib.h:189
#define MUTT_PAGER_ATTACHMENT
Attachments may exist.
Definition lib.h:70
Private state data for the Pager.
const struct CompleteOps CompletePatternOps
Auto-Completion of Patterns.
Definition complete.c:82
Match patterns to emails.
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition pool.c:82
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition pool.c:96
Prototypes for many functions.
#define COLOR_QUOTED(cid)
Definition quoted.h:28
#define REG_COMP(preg, regex, cflags)
Compile a regular expression.
Definition regex3.h:50
#define NONULL(x)
Definition string2.h:43
String manipulation buffer.
Definition buffer.h:36
size_t dsize
Length of data.
Definition buffer.h:39
char * data
Pointer to data.
Definition buffer.h:37
bool attach_del
Has an attachment marked for deletion.
Definition email.h:99
Input for the file completion function.
Definition curs_lib.h:39
Data shared between Index, Pager and Sidebar.
Definition shared_data.h:37
struct Email * email
Currently selected Email.
Definition shared_data.h:42
struct Mailbox * mailbox
Current Mailbox.
Definition shared_data.h:41
bool attach_msg
Are we in "attach message" mode?
Definition shared_data.h:46
struct MailboxView * mailbox_view
Current Mailbox view.
Definition shared_data.h:40
A line of text in the pager.
Definition display.h:50
short search_arr_size
Number of items in search array.
Definition display.h:59
struct TextSyntax * search
Array of search text in the line.
Definition display.h:60
bool cont_line
Continuation of a previous line (wrapped by NeoMutt)
Definition display.h:53
short cid
Default line colour, e.g. MT_COLOR_SIGNATURE.
Definition display.h:52
LOFF_T offset
Offset into Email file (PagerPrivateData->fp)
Definition display.h:51
bool changed
Mailbox has been modified.
Definition mailbox.h:110
Mapping between a function and an operation.
Definition lib.h:115
Mapping between an operation and a key sequence.
Definition lib.h:125
int op
Operation, e.g. OP_DELETE.
Definition lib.h:126
struct WindowState state
Current state of the Window.
void * wdata
Private data.
struct MuttWindow * parent
Parent Window.
Container for Accounts, Notifications.
Definition neomutt.h:43
struct ConfigSubset * sub
Inherited config items.
Definition neomutt.h:47
FILE * fp
Source stream.
Definition lib.h:161
A NeoMutt function.
Definition functions.h:50
pager_function_t function
Function to call.
Definition functions.h:52
int op
Op code, e.g. OP_MAIN_LIMIT.
Definition functions.h:51
Private state data for the Pager.
PagerFlags hide_quoted
Set to MUTT_HIDE when quoted email is hidden <toggle-quoted>
int rc
Return code from functions.
int q_level
Number of unique quoting levels.
int cur_line
Current line (last line visible on screen)
bool wrapped
Has the search/next wrapped around?
int lines_used
Size of lines array (used entries)
char search_str[256]
Current search string.
int lines_max
Capacity of lines array (total entries)
bool force_redraw
Repaint is needed.
enum PagerLoopMode loop
What the Event Loop should do next, e.g. PAGER_LOOP_CONTINUE.
struct Line * lines
Array of text lines in pager.
int has_types
Set to MUTT_TYPES for PAGER_MODE_EMAIL or MUTT_SHOWCOLOR.
struct Notify * notify
Notifications: NotifyPager, PagerPrivateData.
LOFF_T bytes_read
Number of bytes read from file.
int top_line
First visible line on screen.
struct stat st
Stats about Email file.
bool search_back
Search backwards.
struct QuoteStyle * quote_list
Tree of quoting levels.
struct PagerView * pview
Object to view in the pager.
struct AttrColorList ansi_list
List of ANSI colours used in the Pager.
int searchctx
Space to show around search matches.
regex_t search_re
Compiled search string.
FILE * fp
File containing decrypted/decoded/weeded Email.
PagerFlags search_flag
Set to MUTT_SEARCH when search results are visible <search-toggle>
bool search_compiled
Search regex is in use.
Paged view into some data.
Definition lib.h:170
struct MuttWindow * win_index
Index Window.
Definition lib.h:176
struct PagerData * pdata
Data that pager displays. NOTNULL.
Definition lib.h:171
enum PagerMode mode
Pager mode.
Definition lib.h:172
PagerFlags flags
Additional settings to tweak pager's function.
Definition lib.h:173
struct MuttWindow * win_pager
Pager Window.
Definition lib.h:178
short rows
Number of rows, can be MUTT_WIN_SIZE_UNLIMITED.
Definition mutt_window.h:62
@ MENU_PAGER
Pager pager (email viewer)
Definition type.h:47