NeoMutt  2025-12-11-694-ga89709
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
functions.c
Go to the documentation of this file.
1
24
30
31#include "config.h"
32#include <limits.h>
33#include <stdbool.h>
34#include <stdio.h>
35#include "mutt/lib.h"
36#include "config/lib.h"
37#include "email/lib.h"
38#include "core/lib.h"
39#include "alias/lib.h"
40#include "gui/lib.h"
41#include "mutt.h"
42#include "functions.h"
43#include "lib.h"
44#include "attach/lib.h"
45#include "browser/lib.h"
46#include "editor/lib.h"
47#include "history/lib.h"
48#include "hooks/lib.h"
49#include "imap/lib.h"
50#include "key/lib.h"
51#include "menu/lib.h"
52#include "ncrypt/lib.h"
53#include "nntp/lib.h"
54#include "pager/lib.h"
55#include "pattern/lib.h"
56#include "pop/lib.h"
57#include "progress/lib.h"
58#include "question/lib.h"
59#include "send/lib.h"
60#include "sidebar/lib.h"
61#include "external.h"
62#include "globals.h"
63#include "mutt_mailbox.h"
64#include "muttlib.h"
65#include "mx.h"
66#include "nntp/mdata.h"
67#include "private_data.h"
68#include "shared_data.h"
69#ifdef USE_AUTOCRYPT
70#include "autocrypt/lib.h"
71#endif
72#ifdef USE_NOTMUCH
73#include "notmuch/lib.h"
74#endif
75#ifdef ENABLE_NLS
76#include <libintl.h>
77#endif
78
80struct MenuDefinition *MdIndex = NULL;
81
82// clang-format off
86static const struct MenuFuncOp OpIndex[] = { /* map: index */
87 { "alias-dialog", OP_ALIAS_DIALOG },
88#ifdef USE_AUTOCRYPT
89 { "autocrypt-acct-menu", OP_AUTOCRYPT_ACCT_MENU },
90#endif
91 { "bounce-message", OP_BOUNCE_MESSAGE },
92 { "break-thread", OP_MAIN_BREAK_THREAD },
93 { "catchup", OP_CATCHUP },
94 { "change-folder", OP_MAIN_CHANGE_FOLDER },
95 { "change-folder-readonly", OP_MAIN_CHANGE_FOLDER_READONLY },
96 { "change-newsgroup", OP_MAIN_CHANGE_GROUP },
97 { "change-newsgroup-readonly", OP_MAIN_CHANGE_GROUP_READONLY },
98#ifdef USE_NOTMUCH
99 { "change-vfolder", OP_MAIN_CHANGE_VFOLDER },
100#endif
101 { "check-traditional-pgp", OP_CHECK_TRADITIONAL },
102 { "clear-flag", OP_MAIN_CLEAR_FLAG },
103 { "close-all-threads", OP_MAIN_CLOSE_ALL_THREADS },
104 { "close-thread", OP_MAIN_CLOSE_THREAD },
105 { "collapse-all", OP_MAIN_COLLAPSE_ALL },
106 { "collapse-thread", OP_MAIN_COLLAPSE_THREAD },
107 { "compose-to-sender", OP_COMPOSE_TO_SENDER },
108 { "copy-message", OP_COPY_MESSAGE },
109 { "create-alias", OP_CREATE_ALIAS },
110 { "decode-copy", OP_DECODE_COPY },
111 { "decode-save", OP_DECODE_SAVE },
112 { "decrypt-copy", OP_DECRYPT_COPY },
113 { "decrypt-save", OP_DECRYPT_SAVE },
114 { "delete-message", OP_DELETE },
115 { "delete-pattern", OP_MAIN_DELETE_PATTERN },
116 { "delete-subthread", OP_DELETE_SUBTHREAD },
117 { "delete-thread", OP_DELETE_THREAD },
118 { "display-address", OP_DISPLAY_ADDRESS },
119 { "display-message", OP_DISPLAY_MESSAGE },
120 { "display-toggle-weed", OP_DISPLAY_HEADERS },
121 { "edit", OP_EDIT_RAW_MESSAGE },
122 { "edit-label", OP_EDIT_LABEL },
123 { "edit-or-view-raw-message", OP_EDIT_OR_VIEW_RAW_MESSAGE },
124 { "edit-raw-message", OP_EDIT_RAW_MESSAGE },
125 { "edit-type", OP_ATTACH_EDIT_TYPE },
126#ifdef USE_NOTMUCH
127 { "entire-thread", OP_MAIN_ENTIRE_THREAD },
128#endif
129 { "exit", OP_EXIT },
130 { "extract-keys", OP_EXTRACT_KEYS },
131 { "fetch-mail", OP_MAIN_FETCH_MAIL },
132 { "flag-message", OP_FLAG_MESSAGE },
133 { "followup-message", OP_FOLLOWUP },
134 { "forget-passphrase", OP_FORGET_PASSPHRASE },
135 { "forward-message", OP_FORWARD_MESSAGE },
136 { "forward-to-group", OP_FORWARD_TO_GROUP },
137 { "get-children", OP_GET_CHILDREN },
138 { "get-message", OP_GET_MESSAGE },
139 { "get-parent", OP_GET_PARENT },
140 { "group-chat-reply", OP_GROUP_CHAT_REPLY },
141 { "group-reply", OP_GROUP_REPLY },
142 { "imap-fetch-mail", OP_MAIN_IMAP_FETCH },
143 { "imap-logout-all", OP_MAIN_IMAP_LOGOUT_ALL },
144 { "limit", OP_MAIN_LIMIT },
145 { "limit-current-thread", OP_LIMIT_CURRENT_THREAD },
146 { "link-threads", OP_MAIN_LINK_THREADS },
147 { "list-reply", OP_LIST_REPLY },
148 { "list-subscribe", OP_LIST_SUBSCRIBE },
149 { "list-unsubscribe", OP_LIST_UNSUBSCRIBE },
150 { "mail", OP_MAIL },
151 { "mail-key", OP_MAIL_KEY },
152 { "mailbox-list", OP_MAILBOX_LIST },
153 { "mark-message", OP_MARK_MSG },
154 { "modify-labels", OP_MAIN_MODIFY_TAGS },
155 { "modify-labels-then-hide", OP_MAIN_MODIFY_TAGS_THEN_HIDE },
156 { "modify-tags", OP_MAIN_MODIFY_TAGS },
157 { "modify-tags-then-hide", OP_MAIN_MODIFY_TAGS_THEN_HIDE },
158 { "next-new", OP_MAIN_NEXT_NEW },
159 { "next-new-then-unread", OP_MAIN_NEXT_NEW_THEN_UNREAD },
160 { "next-subthread", OP_MAIN_NEXT_SUBTHREAD },
161 { "next-thread", OP_MAIN_NEXT_THREAD },
162 { "next-undeleted", OP_MAIN_NEXT_UNDELETED },
163 { "next-unread", OP_MAIN_NEXT_UNREAD },
164 { "next-unread-mailbox", OP_MAIN_NEXT_UNREAD_MAILBOX },
165 { "open-all-threads", OP_MAIN_OPEN_ALL_THREADS },
166 { "open-thread", OP_MAIN_OPEN_THREAD },
167 { "parent-message", OP_MAIN_PARENT_MESSAGE },
168 { "pipe-entry", OP_PIPE },
169 { "pipe-message", OP_PIPE },
170 { "post-message", OP_POST },
171 { "previous-new", OP_MAIN_PREV_NEW },
172 { "previous-new-then-unread", OP_MAIN_PREV_NEW_THEN_UNREAD },
173 { "previous-subthread", OP_MAIN_PREV_SUBTHREAD },
174 { "previous-thread", OP_MAIN_PREV_THREAD },
175 { "previous-undeleted", OP_MAIN_PREV_UNDELETED },
176 { "previous-unread", OP_MAIN_PREV_UNREAD },
177 { "print-message", OP_PRINT },
178 { "purge-message", OP_PURGE_MESSAGE },
179 { "purge-thread", OP_PURGE_THREAD },
180 { "quasi-delete", OP_MAIN_QUASI_DELETE },
181 { "query", OP_QUERY },
182 { "quit", OP_QUIT },
183 { "read-subthread", OP_MAIN_READ_SUBTHREAD },
184 { "read-thread", OP_MAIN_READ_THREAD },
185 { "recall-message", OP_RECALL_MESSAGE },
186 { "reconstruct-thread", OP_RECONSTRUCT_THREAD },
187 { "reply", OP_REPLY },
188 { "resend-message", OP_RESEND },
189 { "root-message", OP_MAIN_ROOT_MESSAGE },
190 { "save-message", OP_SAVE },
191 { "set-flag", OP_MAIN_SET_FLAG },
192 { "show-limit", OP_MAIN_SHOW_LIMIT },
193 { "sort-mailbox", OP_SORT },
194 { "sort-reverse", OP_SORT_REVERSE },
195 { "sync-mailbox", OP_MAIN_SYNC_FOLDER },
196 { "tag-pattern", OP_MAIN_TAG_PATTERN },
197 { "tag-subthread", OP_TAG_SUBTHREAD },
198 { "tag-thread", OP_TAG_THREAD },
199 { "toggle-new", OP_TOGGLE_NEW },
200 { "toggle-read", OP_TOGGLE_READ },
201 { "toggle-write", OP_TOGGLE_WRITE },
202 { "undelete-message", OP_UNDELETE },
203 { "undelete-pattern", OP_MAIN_UNDELETE_PATTERN },
204 { "undelete-subthread", OP_UNDELETE_SUBTHREAD },
205 { "undelete-thread", OP_UNDELETE_THREAD },
206 { "untag-pattern", OP_MAIN_UNTAG_PATTERN },
207#ifdef USE_NOTMUCH
208 { "vfolder-from-query", OP_MAIN_VFOLDER_FROM_QUERY },
209 { "vfolder-from-query-readonly", OP_MAIN_VFOLDER_FROM_QUERY_READONLY },
210 { "vfolder-window-backward", OP_MAIN_WINDOWED_VFOLDER_BACKWARD },
211 { "vfolder-window-forward", OP_MAIN_WINDOWED_VFOLDER_FORWARD },
212 { "vfolder-window-reset", OP_MAIN_WINDOWED_VFOLDER_RESET },
213#endif
214 { "view-attachments", OP_VIEW_ATTACHMENTS },
215 { "view-raw-message", OP_VIEW_RAW_MESSAGE },
216 // Deprecated
217 { "buffy-list", OP_MAILBOX_LIST, MFF_DEPRECATED },
218 { NULL, 0 },
219};
220
224static const struct MenuOpSeq IndexDefaultBindings[] = { /* map: index */
225 { OP_ATTACH_EDIT_TYPE, "\005" }, // <Ctrl-E>
226#ifdef USE_AUTOCRYPT
227 { OP_AUTOCRYPT_ACCT_MENU, "A" },
228#endif
229 { OP_BOUNCE_MESSAGE, "b" },
230 { OP_CHECK_TRADITIONAL, "\033P" }, // <Alt-P>
231 { OP_COPY_MESSAGE, "C" },
232 { OP_CREATE_ALIAS, "a" },
233 { OP_DECODE_COPY, "\033C" }, // <Alt-C>
234 { OP_DECODE_SAVE, "\033s" }, // <Alt-s>
235 { OP_DELETE, "d" },
236 { OP_DELETE_SUBTHREAD, "\033d" }, // <Alt-d>
237 { OP_DELETE_THREAD, "\004" }, // <Ctrl-D>
238 { OP_DISPLAY_ADDRESS, "@" },
239 { OP_DISPLAY_HEADERS, "h" },
240 { OP_DISPLAY_MESSAGE, " " }, // <Space>
241 { OP_DISPLAY_MESSAGE, "<keypadenter>" },
242 { OP_DISPLAY_MESSAGE, "\n" }, // <Enter>
243 { OP_DISPLAY_MESSAGE, "\r" }, // <Return>
244 { OP_EDIT_LABEL, "Y" },
245 { OP_EDIT_OR_VIEW_RAW_MESSAGE, "e" },
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_LIST_REPLY, "L" },
253 { OP_MAIL, "m" },
254 { OP_MAILBOX_LIST, "." },
255 { OP_MAIL_KEY, "\033k" }, // <Alt-k>
256 { OP_MAIN_BREAK_THREAD, "#" },
257 { OP_MAIN_CHANGE_FOLDER, "c" },
258 { OP_MAIN_CHANGE_FOLDER_READONLY, "\033c" }, // <Alt-c>
259 { OP_MAIN_CHANGE_GROUP, "i" },
260 { OP_MAIN_CHANGE_GROUP_READONLY, "\033i" }, // <Alt-i>
261 { OP_MAIN_CLEAR_FLAG, "W" },
262 { OP_MAIN_COLLAPSE_ALL, "\033V" }, // <Alt-V>
263 { OP_MAIN_COLLAPSE_THREAD, "\033v" }, // <Alt-v>
264 { OP_MAIN_DELETE_PATTERN, "D" },
265 { OP_MAIN_FETCH_MAIL, "G" },
266 { OP_MAIN_LIMIT, "l" },
267 { OP_MAIN_LINK_THREADS, "&" },
268 { OP_MAIN_NEXT_NEW_THEN_UNREAD, "\t" }, // <Tab>
269 { OP_MAIN_NEXT_SUBTHREAD, "\033n" }, // <Alt-n>
270 { OP_MAIN_NEXT_THREAD, "\016" }, // <Ctrl-N>
271 { OP_MAIN_NEXT_UNDELETED, "<down>" },
272 { OP_MAIN_NEXT_UNDELETED, "j" },
273 { OP_MAIN_PARENT_MESSAGE, "P" },
274 { OP_MAIN_PREV_NEW_THEN_UNREAD, "\033\t" }, // <Alt-Tab>
275 { OP_MAIN_PREV_SUBTHREAD, "\033p" }, // <Alt-p>
276 { OP_MAIN_PREV_THREAD, "\020" }, // <Ctrl-P>
277 { OP_MAIN_PREV_UNDELETED, "<up>" },
278 { OP_MAIN_PREV_UNDELETED, "k" },
279 { OP_MAIN_READ_SUBTHREAD, "\033r" }, // <Alt-r>
280 { OP_MAIN_READ_THREAD, "\022" }, // <Ctrl-R>
281 { OP_MAIN_SET_FLAG, "w" },
282 { OP_MAIN_SHOW_LIMIT, "\033l" }, // <Alt-l>
283 { OP_MAIN_SYNC_FOLDER, "$" },
284 { OP_MAIN_TAG_PATTERN, "T" },
285 { OP_MAIN_UNDELETE_PATTERN, "U" },
286 { OP_MAIN_UNTAG_PATTERN, "\024" }, // <Ctrl-T>
287 { OP_MARK_MSG, "~" },
288 { OP_NEXT_ENTRY, "J" },
289 { OP_PIPE, "|" },
290 { OP_PREV_ENTRY, "K" },
291 { OP_PRINT, "p" },
292 { OP_QUERY, "Q" },
293 { OP_QUIT, "q" },
294 { OP_RECALL_MESSAGE, "R" },
295 { OP_REPLY, "r" },
296 { OP_RESEND, "\033e" }, // <Alt-e>
297 { OP_SAVE, "s" },
298 { OP_SHOW_LOG_MESSAGES, "M" },
299 { OP_SORT, "o" },
300 { OP_SORT_REVERSE, "O" },
301 { OP_TAG_THREAD, "\033t" }, // <Alt-t>
302 { OP_TOGGLE_NEW, "N" },
303 { OP_TOGGLE_WRITE, "%" },
304 { OP_UNDELETE, "u" },
305 { OP_UNDELETE_SUBTHREAD, "\033u" }, // <Alt-u>
306 { OP_UNDELETE_THREAD, "\025" }, // <Ctrl-U>
307 { OP_VIEW_ATTACHMENTS, "v" },
308 { 0, NULL },
309};
310// clang-format on
311
322
326void index_init_keys(struct SubMenu *sm_generic)
327{
328 struct MenuDefinition *md = NULL;
329 struct SubMenu *sm_index = NULL;
330 struct SubMenu *sm_sidebar = sidebar_get_submenu();
331
332 sm_index = km_register_submenu(OpIndex);
333 md = km_register_menu(MENU_INDEX, "index");
334 km_menu_add_submenu(md, sm_index);
335 km_menu_add_submenu(md, sm_sidebar);
336 km_menu_add_submenu(md, sm_generic);
338
339 MdIndex = md;
340}
341
349static bool resolve_email(struct IndexPrivateData *priv,
350 struct IndexSharedData *shared, enum ResolveMethod rm)
351{
352 if (!priv || !priv->menu || !shared || !shared->mailbox || !shared->email)
353 return false;
354
355 const bool c_resolve = cs_subset_bool(shared->sub, "resolve");
356 if (!c_resolve)
357 return false;
358
359 int index = -1;
360 switch (rm)
361 {
363 index = menu_get_index(priv->menu) + 1;
364 break;
365
367 {
368 const bool uncollapse = mutt_using_threads() && !window_is_focused(priv->win_index);
369 index = find_next_undeleted(shared->mailbox_view, menu_get_index(priv->menu), uncollapse);
370 break;
371 }
372
374 index = mutt_next_thread(shared->email);
375 break;
376
378 index = mutt_next_subthread(shared->email);
379 break;
380 }
381
382 if ((index < 0) || (index >= shared->mailbox->vcount))
383 {
384 // Resolve failed
385 notify_send(shared->notify, NT_INDEX, NT_INDEX_EMAIL, NULL);
386 return false;
387 }
388
389 menu_set_index(priv->menu, index);
390 return true;
391}
392
398bool index_next_undeleted(struct MuttWindow *win_index)
399{
400 struct MuttWindow *dlg = dialog_find(win_index);
401 if (!dlg)
402 return false;
403
404 struct Menu *menu = win_index->wdata;
405 struct IndexSharedData *shared = dlg->wdata;
406 if (!shared)
407 return false;
408
409 struct IndexPrivateData *priv = win_index->parent->wdata;
410 const bool uncollapse = mutt_using_threads() && !window_is_focused(priv->win_index);
411
412 int index = find_next_undeleted(shared->mailbox_view, menu_get_index(menu), uncollapse);
413 if ((index < 0) || (index >= shared->mailbox->vcount))
414 {
415 // Selection failed
417 return false;
418 }
419
420 menu_set_index(menu, index);
421 return true;
422}
423
424// -----------------------------------------------------------------------------
425
430 struct IndexPrivateData *priv, const struct KeyEvent *event)
431{
433 return FR_SUCCESS;
434}
435
440 struct IndexPrivateData *priv, const struct KeyEvent *event)
441{
442 if (!shared->email)
443 return FR_NO_ACTION;
445
447 return FR_SUCCESS;
448}
449
454 struct IndexPrivateData *priv, const struct KeyEvent *event)
455{
456 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
457 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
458 index_bounce_message(shared->mailbox, &ea);
459 ARRAY_FREE(&ea);
460
461 return FR_SUCCESS;
462}
463
467static int op_check_traditional(struct IndexSharedData *shared,
468 struct IndexPrivateData *priv, const struct KeyEvent *event)
469{
471 return FR_NOT_IMPL;
472 if (!shared->email)
473 return FR_NO_ACTION;
474
475 if (priv->tag_prefix || !(shared->email->security & PGP_TRADITIONAL_CHECKED))
476 {
477 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
478 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
479 if (mutt_check_traditional_pgp(shared->mailbox, &ea))
481 ARRAY_FREE(&ea);
482 }
483
484 return FR_SUCCESS;
485}
486
490static int op_compose_to_sender(struct IndexSharedData *shared,
491 struct IndexPrivateData *priv, const struct KeyEvent *event)
492{
493 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
494 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
495 int rc = mutt_send_message(SEND_TO_SENDER, NULL, NULL, shared->mailbox, &ea,
496 shared->sub);
497 ARRAY_FREE(&ea);
499
500 return (rc == -1) ? FR_ERROR : FR_SUCCESS;
501}
502
506static int op_create_alias(struct IndexSharedData *shared,
507 struct IndexPrivateData *priv, const struct KeyEvent *event)
508{
509 struct AddressList *al = NULL;
510 if (shared->email && shared->email->env)
511 al = mutt_get_address(shared->email->env, NULL);
512 alias_create(al, shared->sub);
514
515 return FR_SUCCESS;
516}
517
525static int op_delete(struct IndexSharedData *shared,
526 struct IndexPrivateData *priv, const struct KeyEvent *event)
527{
528 /* L10N: CHECK_ACL */
529 if (!check_acl(shared->mailbox, MUTT_ACL_DELETE, _("Can't delete message")))
530 return FR_ERROR;
531
532 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
533 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
534
535 mutt_emails_set_flag(shared->mailbox, &ea, MUTT_DELETE, true);
536 mutt_emails_set_flag(shared->mailbox, &ea, MUTT_PURGE, (event->op == OP_PURGE_MESSAGE));
537 const bool c_delete_untag = cs_subset_bool(shared->sub, "delete_untag");
538 if (c_delete_untag)
539 mutt_emails_set_flag(shared->mailbox, &ea, MUTT_TAG, false);
540 ARRAY_FREE(&ea);
541
542 if (priv->tag_prefix)
543 {
545 }
546 else
547 {
549 }
550
551 return FR_SUCCESS;
552}
553
562static int op_delete_thread(struct IndexSharedData *shared,
563 struct IndexPrivateData *priv, const struct KeyEvent *event)
564{
565 /* L10N: CHECK_ACL */
566 /* L10N: Due to the implementation details we do not know whether we
567 delete zero, 1, 12, ... messages. So in English we use
568 "messages". Your language might have other means to express this. */
569 if (!check_acl(shared->mailbox, MUTT_ACL_DELETE, _("Can't delete messages")))
570 return FR_ERROR;
571 if (!shared->email)
572 return FR_NO_ACTION;
573
574 const int op = event->op;
575 int subthread = (op == OP_DELETE_SUBTHREAD);
576 int rc = mutt_thread_set_flag(shared->mailbox, shared->email, MUTT_DELETE, true, subthread);
577 if (rc == -1)
578 return FR_ERROR;
579 if (op == OP_PURGE_THREAD)
580 {
581 rc = mutt_thread_set_flag(shared->mailbox, shared->email, MUTT_PURGE, true, subthread);
582 if (rc == -1)
583 return FR_ERROR;
584 }
585
586 const bool c_delete_untag = cs_subset_bool(shared->sub, "delete_untag");
587 if (c_delete_untag)
588 mutt_thread_set_flag(shared->mailbox, shared->email, MUTT_TAG, false, subthread);
589
592 return FR_SUCCESS;
593}
594
598static int op_display_address(struct IndexSharedData *shared,
599 struct IndexPrivateData *priv, const struct KeyEvent *event)
600{
601 if (!shared->email)
602 return FR_NO_ACTION;
604
605 return FR_SUCCESS;
606}
607
615static int op_display_message(struct IndexSharedData *shared,
616 struct IndexPrivateData *priv, const struct KeyEvent *event)
617{
618 if (!shared->email)
619 return FR_NO_ACTION;
620
622
623 int op = event->op;
624 /* toggle the weeding of headers so that a user can press the key
625 * again while reading the message. */
626 if (op == OP_DISPLAY_HEADERS)
627 {
628 bool_str_toggle(shared->sub, "weed", NULL);
629 notify_send(shared->notify, NT_INDEX, NT_INDEX_EMAIL, shared);
630 if (!window_is_focused(priv->win_index))
631 return FR_SUCCESS;
632 }
633
634 OptNeedResort = false;
635
636 if (mutt_using_threads() && shared->email->collapsed)
637 {
639 mutt_set_vnum(shared->mailbox);
640 const bool c_uncollapse_jump = cs_subset_bool(shared->sub, "uncollapse_jump");
641 if (c_uncollapse_jump)
643 }
644
645 const bool c_pgp_auto_decode = cs_subset_bool(shared->sub, "pgp_auto_decode");
646 if (c_pgp_auto_decode &&
647 (priv->tag_prefix || !(shared->email->security & PGP_TRADITIONAL_CHECKED)))
648 {
649 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
650 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
651 if (mutt_check_traditional_pgp(shared->mailbox, &ea))
653 ARRAY_FREE(&ea);
654 }
655 const int index = menu_get_index(priv->menu);
657
658 const char *const c_pager = pager_get_pager(NeoMutt->sub);
659 if (c_pager)
660 {
661 op = external_pager(shared->mailbox_view, shared->email, c_pager);
662 }
663 else
664 {
665 op = mutt_display_message(priv->win_index, shared);
666 }
667
669 if (op < OP_NULL)
670 {
671 OptNeedResort = false;
672 return FR_ERROR;
673 }
674
675 if (shared->mailbox)
676 {
678 shared->mailbox->msg_count, shared);
679 }
680
681 return op;
682}
683
687static int op_edit_label(struct IndexSharedData *shared,
688 struct IndexPrivateData *priv, const struct KeyEvent *event)
689{
690 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
691 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
692 int num_changed = mutt_label_message(shared->mailbox_view, &ea);
693 ARRAY_FREE(&ea);
694
695 if (num_changed > 0)
696 {
697 shared->mailbox->changed = true;
699 /* L10N: This is displayed when the x-label on one or more
700 messages is edited. */
701 mutt_message(ngettext("%d label changed", "%d labels changed", num_changed), num_changed);
702
703 if (!priv->tag_prefix)
705 return FR_SUCCESS;
706 }
707
708 /* L10N: This is displayed when editing an x-label, but no messages
709 were updated. Possibly due to canceling at the prompt or if the new
710 label is the same as the old label. */
711 mutt_message(_("No labels changed"));
712 return FR_NO_ACTION;
713}
714
723static int op_edit_raw_message(struct IndexSharedData *shared,
724 struct IndexPrivateData *priv, const struct KeyEvent *event)
725{
726 /* TODO split this into 3 cases? */
727 bool edit;
728 const int op = event->op;
729 if (op == OP_EDIT_RAW_MESSAGE)
730 {
731 /* L10N: CHECK_ACL */
732 if (!check_acl(shared->mailbox, MUTT_ACL_INSERT, _("Can't edit message")))
733 return FR_ERROR;
734 edit = true;
735 }
736 else if (op == OP_EDIT_OR_VIEW_RAW_MESSAGE)
737 {
738 edit = !shared->mailbox->readonly && (shared->mailbox->rights & MUTT_ACL_INSERT);
739 }
740 else
741 {
742 edit = false;
743 }
744
745 if (!shared->email)
746 return FR_NO_ACTION;
747 const bool c_pgp_auto_decode = cs_subset_bool(shared->sub, "pgp_auto_decode");
748 if (c_pgp_auto_decode &&
749 (priv->tag_prefix || !(shared->email->security & PGP_TRADITIONAL_CHECKED)))
750 {
751 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
752 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
753 if (mutt_check_traditional_pgp(shared->mailbox, &ea))
755 ARRAY_FREE(&ea);
756 }
757 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
758 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
759 mutt_ev_message(shared->mailbox, &ea, edit ? EVM_EDIT : EVM_VIEW);
760 ARRAY_FREE(&ea);
762
763 return FR_SUCCESS;
764}
765
769static int op_end_cond(struct IndexSharedData *shared,
770 struct IndexPrivateData *priv, const struct KeyEvent *event)
771{
772 return FR_SUCCESS;
773}
774
778static int op_exit(struct IndexSharedData *shared,
779 struct IndexPrivateData *priv, const struct KeyEvent *event)
780{
781 if (shared->attach_msg)
782 return FR_DONE;
783
784 if (query_quadoption(_("Exit NeoMutt without saving?"), shared->sub, "quit") == MUTT_YES)
785 {
786 if (shared->mailbox_view)
787 {
788 mx_fastclose_mailbox(shared->mailbox, false);
789 mview_free(&shared->mailbox_view);
790 }
791 return FR_DONE;
792 }
793
794 return FR_NO_ACTION;
795}
796
800static int op_extract_keys(struct IndexSharedData *shared,
801 struct IndexPrivateData *priv, const struct KeyEvent *event)
802{
803 if (!WithCrypto)
804 return FR_NOT_IMPL;
805 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
806 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
808 ARRAY_FREE(&ea);
810
811 return FR_SUCCESS;
812}
813
817static int op_flag_message(struct IndexSharedData *shared,
818 struct IndexPrivateData *priv, const struct KeyEvent *event)
819{
820 /* L10N: CHECK_ACL */
821 if (!check_acl(shared->mailbox, MUTT_ACL_WRITE, _("Can't flag message")))
822 return FR_ERROR;
823
824 struct Mailbox *m = shared->mailbox;
825 if (priv->tag_prefix)
826 {
827 for (size_t i = 0; i < m->msg_count; i++)
828 {
829 struct Email *e = m->emails[i];
830 if (!e)
831 break;
832 if (message_is_tagged(e))
833 mutt_set_flag(m, e, MUTT_FLAG, !e->flagged, true);
834 }
835
837 }
838 else
839 {
840 if (!shared->email)
841 return FR_NO_ACTION;
842 mutt_set_flag(m, shared->email, MUTT_FLAG, !shared->email->flagged, true);
843
845 }
846
847 return FR_SUCCESS;
848}
849
853static int op_forget_passphrase(struct IndexSharedData *shared,
854 struct IndexPrivateData *priv, const struct KeyEvent *event)
855{
857 return FR_SUCCESS;
858}
859
863static int op_forward_message(struct IndexSharedData *shared,
864 struct IndexPrivateData *priv, const struct KeyEvent *event)
865{
866 if (!shared->email)
867 return FR_NO_ACTION;
868 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
869 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
870 const bool c_pgp_auto_decode = cs_subset_bool(shared->sub, "pgp_auto_decode");
871 if (c_pgp_auto_decode &&
872 (priv->tag_prefix || !(shared->email->security & PGP_TRADITIONAL_CHECKED)))
873 {
874 if (mutt_check_traditional_pgp(shared->mailbox, &ea))
876 }
877 int rc = mutt_send_message(SEND_FORWARD, NULL, NULL, shared->mailbox, &ea,
878 shared->sub);
879 ARRAY_FREE(&ea);
881
882 return (rc == -1) ? FR_ERROR : FR_SUCCESS;
883}
884
892static int op_group_reply(struct IndexSharedData *shared,
893 struct IndexPrivateData *priv, const struct KeyEvent *event)
894{
895 SendFlags replyflags = SEND_REPLY;
896 if (event->op == OP_GROUP_REPLY)
897 replyflags |= SEND_GROUP_REPLY;
898 else
899 replyflags |= SEND_GROUP_CHAT_REPLY;
900 if (!shared->email)
901 return FR_NO_ACTION;
902 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
903 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
904 const bool c_pgp_auto_decode = cs_subset_bool(shared->sub, "pgp_auto_decode");
905 if (c_pgp_auto_decode &&
906 (priv->tag_prefix || !(shared->email->security & PGP_TRADITIONAL_CHECKED)))
907 {
908 if (mutt_check_traditional_pgp(shared->mailbox, &ea))
910 }
911 int rc = mutt_send_message(replyflags, NULL, NULL, shared->mailbox, &ea,
912 shared->sub);
913 ARRAY_FREE(&ea);
915
916 return (rc == -1) ? FR_ERROR : FR_SUCCESS;
917}
918
922static int op_jump(struct IndexSharedData *shared,
923 struct IndexPrivateData *priv, const struct KeyEvent *event)
924{
925 int rc = FR_ERROR;
926 struct Buffer *buf = buf_pool_get();
927
928 const int digit = event->op - OP_JUMP;
929 if ((digit > 0) && (digit < 10))
930 {
931 mutt_unget_ch('0' + digit);
932 }
933
934 int msg_num = 0;
935 if ((mw_get_field(_("Jump to message: "), buf, MUTT_COMP_NO_FLAGS, HC_OTHER, NULL, NULL) != 0) ||
936 buf_is_empty(buf))
937 {
938 mutt_message(_("Nothing to do"));
939 rc = FR_NO_ACTION;
940 }
941 else if (!mutt_str_atoi_full(buf_string(buf), &msg_num))
942 {
943 mutt_warning(_("Argument must be a message number"));
944 }
945 else if ((msg_num < 1) || (msg_num > shared->mailbox->msg_count))
946 {
947 mutt_warning(_("Invalid message number"));
948 }
949 else if (!shared->mailbox->emails[msg_num - 1] ||
950 !shared->mailbox->emails[msg_num - 1]->visible)
951 {
952 mutt_warning(_("That message is not visible"));
953 }
954 else
955 {
956 struct Email *e = shared->mailbox->emails[msg_num - 1];
957
958 if (mutt_messages_in_thread(shared->mailbox, e, MIT_POSITION) > 1)
959 {
961 mutt_set_vnum(shared->mailbox);
962 }
963 menu_set_index(priv->menu, e->vnum);
964 rc = FR_SUCCESS;
965 }
966
967 buf_pool_release(&buf);
968 return rc;
969}
970
974static int op_list_reply(struct IndexSharedData *shared,
975 struct IndexPrivateData *priv, const struct KeyEvent *event)
976{
977 if (!shared->email)
978 return FR_NO_ACTION;
979 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
980 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
981 const bool c_pgp_auto_decode = cs_subset_bool(shared->sub, "pgp_auto_decode");
982 if (c_pgp_auto_decode &&
983 (priv->tag_prefix || !(shared->email->security & PGP_TRADITIONAL_CHECKED)))
984 {
985 if (mutt_check_traditional_pgp(shared->mailbox, &ea))
987 }
988 int rc = mutt_send_message(SEND_REPLY | SEND_LIST_REPLY, NULL, NULL,
989 shared->mailbox, &ea, shared->sub);
990 ARRAY_FREE(&ea);
992
993 return (rc == -1) ? FR_ERROR : FR_SUCCESS;
994}
995
999static int op_list_subscribe(struct IndexSharedData *shared,
1000 struct IndexPrivateData *priv, const struct KeyEvent *event)
1001{
1002 return mutt_send_list_subscribe(shared->mailbox, shared->email) ? FR_SUCCESS : FR_NO_ACTION;
1003}
1004
1008static int op_list_unsubscribe(struct IndexSharedData *shared,
1009 struct IndexPrivateData *priv, const struct KeyEvent *event)
1010{
1011 return mutt_send_list_unsubscribe(shared->mailbox, shared->email) ? FR_SUCCESS : FR_NO_ACTION;
1012}
1013
1017static int op_mail(struct IndexSharedData *shared,
1018 struct IndexPrivateData *priv, const struct KeyEvent *event)
1019{
1020 int rc = mutt_send_message(SEND_NO_FLAGS, NULL, NULL, shared->mailbox, NULL,
1021 shared->sub);
1023 return (rc == -1) ? FR_ERROR : FR_SUCCESS;
1024}
1025
1029static int op_mailbox_list(struct IndexSharedData *shared,
1030 struct IndexPrivateData *priv, const struct KeyEvent *event)
1031{
1033 return FR_SUCCESS;
1034}
1035
1039static int op_mail_key(struct IndexSharedData *shared,
1040 struct IndexPrivateData *priv, const struct KeyEvent *event)
1041{
1042 if (!(WithCrypto & APPLICATION_PGP))
1043 return FR_NOT_IMPL;
1044 int rc = mutt_send_message(SEND_KEY, NULL, NULL, NULL, NULL, shared->sub);
1046
1047 return (rc == -1) ? FR_ERROR : FR_SUCCESS;
1048}
1049
1053static int op_main_break_thread(struct IndexSharedData *shared,
1054 struct IndexPrivateData *priv, const struct KeyEvent *event)
1055{
1056 struct Mailbox *m = shared->mailbox;
1057 /* L10N: CHECK_ACL */
1058 if (!check_acl(m, MUTT_ACL_WRITE, _("Can't break thread")))
1059 return FR_ERROR;
1060
1061 struct Email *e = shared->email;
1062 if (!e)
1063 return FR_NO_ACTION;
1064
1065 if (!mutt_using_threads())
1066 {
1067 mutt_warning(_("Threading is not enabled"));
1068 return FR_NO_ACTION;
1069 }
1070
1071 struct MailboxView *mv = shared->mailbox_view;
1073 {
1074 {
1076 mutt_sort_headers(mv, true);
1077 menu_set_index(priv->menu, e->vnum);
1078 }
1079
1080 m->changed = true;
1081 mutt_message(_("Thread broken"));
1082
1084 }
1085 else
1086 {
1087 mutt_error(_("Thread can't be broken, message is not part of a thread"));
1088 }
1089
1090 return FR_SUCCESS;
1091}
1092
1101static int op_main_change_folder(struct IndexSharedData *shared,
1102 struct IndexPrivateData *priv, const struct KeyEvent *event)
1103{
1104 struct Buffer *folderbuf = buf_pool_get();
1105 buf_alloc(folderbuf, PATH_MAX);
1106
1107 char *cp = NULL;
1108 bool read_only;
1109 const bool c_read_only = cs_subset_bool(shared->sub, "read_only");
1110 const int op = event->op;
1111 if (shared->attach_msg || c_read_only || (op == OP_MAIN_CHANGE_FOLDER_READONLY))
1112 {
1113 cp = _("Open mailbox in read-only mode");
1114 read_only = true;
1115 }
1116 else
1117 {
1118 cp = _("Open mailbox");
1119 read_only = false;
1120 }
1121
1122 const bool c_change_folder_next = cs_subset_bool(shared->sub, "change_folder_next");
1123 if (c_change_folder_next && shared->mailbox && !buf_is_empty(&shared->mailbox->pathbuf))
1124 {
1125 buf_strcpy(folderbuf, mailbox_path(shared->mailbox));
1126 pretty_mailbox(folderbuf);
1127 }
1128 /* By default, fill buf with the next mailbox that contains unread mail */
1129 mutt_mailbox_next(shared->mailbox_view ? shared->mailbox : NULL, folderbuf);
1130
1131 if (mw_enter_fname(cp, folderbuf, true, shared->mailbox, false, NULL, NULL,
1132 MUTT_SEL_NO_FLAGS) == -1)
1133 {
1134 goto changefoldercleanup;
1135 }
1136
1137 /* Selected directory is okay, let's save it. */
1139
1140 if (buf_is_empty(folderbuf))
1141 {
1142 msgwin_clear_text(NULL);
1143 goto changefoldercleanup;
1144 }
1145
1146 struct Mailbox *m = mx_mbox_find2(buf_string(folderbuf));
1147 if (m)
1148 {
1149 change_folder_mailbox(priv->menu, m, &priv->oldcount, shared, read_only);
1150 }
1151 else
1152 {
1153 change_folder_string(priv->menu, folderbuf, &priv->oldcount, shared, read_only);
1154 }
1155
1156changefoldercleanup:
1157 buf_pool_release(&folderbuf);
1159
1160 return FR_SUCCESS;
1161}
1162
1166static int op_main_collapse_all(struct IndexSharedData *shared,
1167 struct IndexPrivateData *priv, const struct KeyEvent *event)
1168{
1169 if (!mutt_using_threads())
1170 {
1171 mutt_warning(_("Threading is not enabled"));
1172 return FR_NO_ACTION;
1173 }
1175 notify_send(shared->notify, NT_INDEX, NT_INDEX_EMAIL, NULL);
1176
1177 return FR_SUCCESS;
1178}
1179
1184 struct IndexPrivateData *priv,
1185 const struct KeyEvent *event)
1186{
1187 if (!mutt_using_threads())
1188 {
1189 mutt_warning(_("Threading is not enabled"));
1190 return FR_NO_ACTION;
1191 }
1192
1193 if (!shared->mailbox_view || shared->mailbox_view->collapsed)
1194 return FR_NO_ACTION;
1195
1197 notify_send(shared->notify, NT_INDEX, NT_INDEX_EMAIL, NULL);
1198
1199 return FR_SUCCESS;
1200}
1201
1205static int op_main_close_thread(struct IndexSharedData *shared,
1206 struct IndexPrivateData *priv, const struct KeyEvent *event)
1207{
1208 if (!mutt_using_threads())
1209 {
1210 mutt_warning(_("Threading is not enabled"));
1211 return FR_NO_ACTION;
1212 }
1213
1214 if (!shared->email || shared->email->collapsed)
1215 return FR_NO_ACTION;
1216
1217 if (!mutt_thread_can_collapse(shared->email))
1218 {
1219 mutt_warning(_("Thread contains unread or flagged messages"));
1220 return FR_ERROR;
1221 }
1222
1224 mutt_set_vnum(shared->mailbox);
1226 notify_send(shared->notify, NT_INDEX, NT_INDEX_EMAIL, NULL);
1227 return FR_SUCCESS;
1228}
1229
1234 struct IndexPrivateData *priv,
1235 const struct KeyEvent *event)
1236{
1237 if (!mutt_using_threads())
1238 {
1239 mutt_warning(_("Threading is not enabled"));
1240 return FR_NO_ACTION;
1241 }
1242
1243 if (!shared->email)
1244 return FR_NO_ACTION;
1245
1246 if (shared->email->collapsed)
1247 {
1248 int index = mutt_uncollapse_thread(shared->email);
1249 mutt_set_vnum(shared->mailbox);
1250 const bool c_uncollapse_jump = cs_subset_bool(shared->sub, "uncollapse_jump");
1251 if (c_uncollapse_jump)
1252 index = mutt_thread_next_unread(shared->email);
1253 menu_set_index(priv->menu, index);
1254 }
1255 else if (mutt_thread_can_collapse(shared->email))
1256 {
1258 mutt_set_vnum(shared->mailbox);
1259 }
1260 else
1261 {
1262 mutt_error(_("Thread contains unread or flagged messages"));
1263 return FR_ERROR;
1264 }
1265
1267 notify_send(shared->notify, NT_INDEX, NT_INDEX_EMAIL, NULL);
1268
1269 return FR_SUCCESS;
1270}
1271
1276 struct IndexPrivateData *priv,
1277 const struct KeyEvent *event)
1278{
1279 if (!mutt_using_threads())
1280 {
1281 mutt_warning(_("Threading is not enabled"));
1282 return FR_NO_ACTION;
1283 }
1284
1285 if (!shared->mailbox_view || !shared->mailbox_view->collapsed)
1286 return FR_NO_ACTION;
1287
1289 notify_send(shared->notify, NT_INDEX, NT_INDEX_EMAIL, NULL);
1290
1291 return FR_SUCCESS;
1292}
1293
1297static int op_main_open_thread(struct IndexSharedData *shared,
1298 struct IndexPrivateData *priv, const struct KeyEvent *event)
1299{
1300 if (!mutt_using_threads())
1301 {
1302 mutt_warning(_("Threading is not enabled"));
1303 return FR_NO_ACTION;
1304 }
1305
1306 if (!shared->email || !shared->email->collapsed)
1307 return FR_NO_ACTION;
1308
1309 int index = mutt_uncollapse_thread(shared->email);
1310 mutt_set_vnum(shared->mailbox);
1311 const bool c_uncollapse_jump = cs_subset_bool(shared->sub, "uncollapse_jump");
1312 if (c_uncollapse_jump)
1313 index = mutt_thread_next_unread(shared->email);
1314 menu_set_index(priv->menu, index);
1316 notify_send(shared->notify, NT_INDEX, NT_INDEX_EMAIL, NULL);
1317
1318 return FR_SUCCESS;
1319}
1320
1324static int op_main_delete_pattern(struct IndexSharedData *shared,
1325 struct IndexPrivateData *priv, const struct KeyEvent *event)
1326{
1327 /* L10N: CHECK_ACL */
1328 /* L10N: Due to the implementation details we do not know whether we
1329 delete zero, 1, 12, ... messages. So in English we use
1330 "messages". Your language might have other means to express this. */
1331 if (!check_acl(shared->mailbox, MUTT_ACL_DELETE, _("Can't delete messages")))
1332 return FR_ERROR;
1333
1334 mutt_pattern_func(shared->mailbox_view, MUTT_DELETE, _("Delete messages matching: "));
1336
1337 return FR_SUCCESS;
1338}
1339
1348static int op_main_limit(struct IndexSharedData *shared,
1349 struct IndexPrivateData *priv, const struct KeyEvent *event)
1350{
1351 const bool lmt = mview_has_limit(shared->mailbox_view);
1352 int old_index = shared->email ? shared->email->index : -1;
1353 const int op = event->op;
1354 if (op == OP_TOGGLE_READ)
1355 {
1356 struct Buffer *buf2 = buf_pool_get();
1357
1358 if (!lmt || !mutt_strn_equal(shared->mailbox_view->pattern, "!~R!~D~s", 8))
1359 {
1360 buf_printf(buf2, "!~R!~D~s%s", lmt ? shared->mailbox_view->pattern : ".*");
1361 }
1362 else
1363 {
1364 const char *pat = shared->mailbox_view->pattern + 8;
1365 if ((*pat == '\0') || mutt_strn_equal(pat, ".*", 2))
1366 buf_strcpy(buf2, "~A");
1367 else
1368 buf_strcpy(buf2, pat);
1369 }
1371 buf_pool_release(&buf2);
1373 }
1374
1375 if (((op == OP_LIMIT_CURRENT_THREAD) &&
1376 mutt_limit_current_thread(shared->mailbox_view, shared->email)) ||
1377 (op == OP_TOGGLE_READ) ||
1378 ((op == OP_MAIN_LIMIT) && (mutt_pattern_func(shared->mailbox_view, MUTT_LIMIT,
1379 _("Limit to messages matching: ")) == 0)))
1380 {
1381 priv->menu->max = shared->mailbox->vcount;
1382 menu_set_index(priv->menu, 0);
1383 if (old_index >= 0)
1384 {
1385 /* try to find what used to be the current message */
1386 for (size_t i = 0; i < shared->mailbox->vcount; i++)
1387 {
1388 struct Email *e = mutt_get_virt_email(shared->mailbox, i);
1389 if (!e)
1390 continue;
1391 if (e->index == old_index)
1392 {
1393 menu_set_index(priv->menu, i);
1394 break;
1395 }
1396 }
1397 }
1398
1399 if ((shared->mailbox->msg_count != 0) && mutt_using_threads())
1400 {
1401 const bool c_collapse_all = cs_subset_bool(shared->sub, "collapse_all");
1402 if (c_collapse_all)
1405 }
1406 notify_send(shared->notify, NT_INDEX, NT_INDEX_EMAIL, NULL);
1408 }
1409 if (lmt)
1410 mutt_message(_("To view all messages, limit to \"all\""));
1411
1412 return FR_SUCCESS;
1413}
1414
1418static int op_main_link_threads(struct IndexSharedData *shared,
1419 struct IndexPrivateData *priv, const struct KeyEvent *event)
1420{
1421 struct Mailbox *m = shared->mailbox;
1422 /* L10N: CHECK_ACL */
1423 if (!check_acl(m, MUTT_ACL_WRITE, _("Can't link threads")))
1424 return FR_ERROR;
1425
1426 struct Email *e = shared->email;
1427 if (!e)
1428 return FR_NO_ACTION;
1429
1430 enum FunctionRetval rc = FR_ERROR;
1431
1432 if (!mutt_using_threads())
1433 {
1434 mutt_warning(_("Threading is not enabled"));
1435 rc = FR_NO_ACTION;
1436 }
1437 else if (!e->env->message_id)
1438 {
1439 mutt_error(_("No Message-ID: header available to link thread"));
1440 }
1441 else
1442 {
1443 struct MailboxView *mv = shared->mailbox_view;
1444 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
1445 ea_add_tagged(&ea, mv, NULL, true);
1446
1447 if (mutt_link_threads(e, &ea, m))
1448 {
1449 mutt_sort_headers(mv, true);
1450 menu_set_index(priv->menu, e->vnum);
1451
1452 m->changed = true;
1453 mutt_message(_("Threads linked"));
1454 rc = FR_SUCCESS;
1455 }
1456 else
1457 {
1458 mutt_error(_("No thread linked"));
1459 rc = FR_NO_ACTION;
1460 }
1461
1462 ARRAY_FREE(&ea);
1463 }
1464
1466 return rc;
1467}
1468
1476static int op_main_modify_tags(struct IndexSharedData *shared,
1477 struct IndexPrivateData *priv, const struct KeyEvent *event)
1478{
1479 int rc = FR_ERROR;
1480 struct Buffer *buf = NULL;
1481
1482 if (!shared->mailbox)
1483 goto done;
1484 struct Mailbox *m = shared->mailbox;
1485 if (!mx_tags_is_supported(m))
1486 {
1487 mutt_message(_("Folder doesn't support tagging, aborting"));
1488 goto done;
1489 }
1490 if (!shared->email)
1491 {
1492 rc = FR_NO_ACTION;
1493 goto done;
1494 }
1495
1496 const int op = event->op;
1497 struct Buffer *tags = buf_pool_get();
1498 if (!priv->tag_prefix)
1499 driver_tags_get_with_hidden(&shared->email->tags, tags);
1500 /* Prompt the user to edit the tag string */
1501 buf = buf_pool_get();
1502 int rc2 = mx_tags_edit(m, buf_string(tags), buf);
1503 buf_pool_release(&tags);
1504 if (rc2 < 0)
1505 {
1506 goto done;
1507 }
1508 else if (rc2 == 0)
1509 {
1510 mutt_message(_("No tag specified, aborting"));
1511 goto done;
1512 }
1513
1514 if (priv->tag_prefix)
1515 {
1516 /* Batch mode: apply the tag change to all tagged messages */
1517 struct Progress *progress = NULL;
1518
1519 if (m->verbose)
1520 {
1522 progress_set_message(progress, _("Update tags..."));
1523 }
1524
1525#ifdef USE_NOTMUCH
1526 if (m->type == MUTT_NOTMUCH)
1527 nm_db_longrun_init(m, true);
1528#endif
1529 for (int px = 0, i = 0; i < m->msg_count; i++)
1530 {
1531 struct Email *e = m->emails[i];
1532 if (!e)
1533 break;
1534 if (!message_is_tagged(e))
1535 continue;
1536
1537 progress_update(progress, ++px, -1);
1538 mx_tags_commit(m, e, buf_string(buf));
1539 e->attr_color = NULL;
1540 if (op == OP_MAIN_MODIFY_TAGS_THEN_HIDE)
1541 {
1542 bool still_queried = false;
1543#ifdef USE_NOTMUCH
1544 if (m->type == MUTT_NOTMUCH)
1545 still_queried = nm_message_is_still_queried(m, e);
1546#endif
1547 e->quasi_deleted = !still_queried;
1548 m->changed = true;
1549 }
1550 }
1551 progress_free(&progress);
1552#ifdef USE_NOTMUCH
1553 if (m->type == MUTT_NOTMUCH)
1555#endif
1557 }
1558 else
1559 {
1560 /* Single message mode: apply tag change to the current message only */
1561 if (mx_tags_commit(m, shared->email, buf_string(buf)))
1562 {
1563 mutt_message(_("Failed to modify tags, aborting"));
1564 goto done;
1565 }
1566 shared->email->attr_color = NULL;
1567 if (op == OP_MAIN_MODIFY_TAGS_THEN_HIDE)
1568 {
1569 bool still_queried = false;
1570#ifdef USE_NOTMUCH
1571 if (m->type == MUTT_NOTMUCH)
1572 still_queried = nm_message_is_still_queried(m, shared->email);
1573#endif
1574 shared->email->quasi_deleted = !still_queried;
1575 m->changed = true;
1576 }
1577
1579 }
1580 rc = FR_SUCCESS;
1581
1582done:
1583 buf_pool_release(&buf);
1584 return rc;
1585}
1586
1598static int op_main_next_new(struct IndexSharedData *shared,
1599 struct IndexPrivateData *priv, const struct KeyEvent *event)
1600{
1601 int first_unread = -1;
1602 int first_new = -1;
1603
1604 const int saved_current = menu_get_index(priv->menu);
1605 int mcur = saved_current;
1606 int index = -1;
1607 const bool threaded = mutt_using_threads();
1608 const int op = event->op;
1609 /* Scan through all virtual messages in the mailbox, wrapping around.
1610 * Track the first new and first unread message found. */
1611 for (size_t i = 0; i != shared->mailbox->vcount; i++)
1612 {
1613 if ((op == OP_MAIN_NEXT_NEW) || (op == OP_MAIN_NEXT_UNREAD) ||
1614 (op == OP_MAIN_NEXT_NEW_THEN_UNREAD))
1615 {
1616 mcur++;
1617 if (mcur > (shared->mailbox->vcount - 1))
1618 {
1619 mcur = 0;
1620 }
1621 }
1622 else
1623 {
1624 mcur--;
1625 if (mcur < 0)
1626 {
1627 mcur = shared->mailbox->vcount - 1;
1628 }
1629 }
1630
1631 struct Email *e = mutt_get_virt_email(shared->mailbox, mcur);
1632 if (!e)
1633 break;
1634 if (e->collapsed && threaded)
1635 {
1636 int unread = mutt_thread_contains_unread(e);
1637 if ((unread != 0) && (first_unread == -1))
1638 first_unread = mcur;
1639 if ((unread == 1) && (first_new == -1))
1640 first_new = mcur;
1641 }
1642 else if (!e->deleted && !e->read)
1643 {
1644 if (first_unread == -1)
1645 first_unread = mcur;
1646 if (!e->old && (first_new == -1))
1647 first_new = mcur;
1648 }
1649
1650 if (((op == OP_MAIN_NEXT_UNREAD) || (op == OP_MAIN_PREV_UNREAD)) && (first_unread != -1))
1651 {
1652 break;
1653 }
1654 if (((op == OP_MAIN_NEXT_NEW) || (op == OP_MAIN_PREV_NEW) ||
1655 (op == OP_MAIN_NEXT_NEW_THEN_UNREAD) || (op == OP_MAIN_PREV_NEW_THEN_UNREAD)) &&
1656 (first_new != -1))
1657 {
1658 break;
1659 }
1660 }
1661 /* Select the best match based on the operation: prefer "new" for *_NEW ops,
1662 * fall back to "unread" for *_THEN_UNREAD ops */
1663 if (((op == OP_MAIN_NEXT_NEW) || (op == OP_MAIN_PREV_NEW) ||
1664 (op == OP_MAIN_NEXT_NEW_THEN_UNREAD) || (op == OP_MAIN_PREV_NEW_THEN_UNREAD)) &&
1665 (first_new != -1))
1666 {
1667 index = first_new;
1668 }
1669 else if (((op == OP_MAIN_NEXT_UNREAD) || (op == OP_MAIN_PREV_UNREAD) ||
1670 (op == OP_MAIN_NEXT_NEW_THEN_UNREAD) || (op == OP_MAIN_PREV_NEW_THEN_UNREAD)) &&
1671 (first_unread != -1))
1672 {
1673 index = first_unread;
1674 }
1675
1676 if (index == -1)
1677 {
1678 menu_set_index(priv->menu, saved_current);
1679 if ((op == OP_MAIN_NEXT_NEW) || (op == OP_MAIN_PREV_NEW))
1680 {
1681 if (mview_has_limit(shared->mailbox_view))
1682 mutt_error(_("No new messages in this limited view"));
1683 else
1684 mutt_error(_("No new messages"));
1685 }
1686 else
1687 {
1688 if (mview_has_limit(shared->mailbox_view))
1689 mutt_error(_("No unread messages in this limited view"));
1690 else
1691 mutt_error(_("No unread messages"));
1692 }
1693 notify_send(shared->notify, NT_INDEX, NT_INDEX_EMAIL, NULL);
1694 return FR_ERROR;
1695 }
1696 else
1697 {
1698 menu_set_index(priv->menu, index);
1699 }
1700
1701 index = menu_get_index(priv->menu);
1702 if ((op == OP_MAIN_NEXT_NEW) || (op == OP_MAIN_NEXT_UNREAD) ||
1703 (op == OP_MAIN_NEXT_NEW_THEN_UNREAD))
1704 {
1705 if (saved_current > index)
1706 {
1707 mutt_message(_("Search wrapped to top"));
1708 }
1709 }
1710 else if (saved_current < index)
1711 {
1712 mutt_message(_("Search wrapped to bottom"));
1713 }
1714
1715 return FR_SUCCESS;
1716}
1717
1727static int op_main_next_thread(struct IndexSharedData *shared,
1728 struct IndexPrivateData *priv, const struct KeyEvent *event)
1729{
1730 int index = -1;
1731 const int op = event->op;
1732 switch (op)
1733 {
1734 case OP_MAIN_NEXT_THREAD:
1735 index = mutt_next_thread(shared->email);
1736 break;
1737
1738 case OP_MAIN_NEXT_SUBTHREAD:
1739 index = mutt_next_subthread(shared->email);
1740 break;
1741
1742 case OP_MAIN_PREV_THREAD:
1743 index = mutt_previous_thread(shared->email);
1744 break;
1745
1746 case OP_MAIN_PREV_SUBTHREAD:
1748 break;
1749 }
1750
1751 if (index != -1)
1752 menu_set_index(priv->menu, index);
1753
1754 if (index < 0)
1755 {
1756 if ((op == OP_MAIN_NEXT_THREAD) || (op == OP_MAIN_NEXT_SUBTHREAD))
1757 mutt_error(_("No more threads"));
1758 else
1759 mutt_error(_("You are on the first thread"));
1760
1761 notify_send(shared->notify, NT_INDEX, NT_INDEX_EMAIL, NULL);
1762 }
1763
1764 return FR_SUCCESS;
1765}
1766
1770static int op_main_next_undeleted(struct IndexSharedData *shared,
1771 struct IndexPrivateData *priv, const struct KeyEvent *event)
1772{
1773 int index = menu_get_index(priv->menu);
1774 if (index >= (shared->mailbox->vcount - 1))
1775 {
1776 notify_send(shared->notify, NT_INDEX, NT_INDEX_EMAIL, NULL);
1777 mutt_message(_("You are on the last message"));
1778 return FR_ERROR;
1779 }
1780
1781 const bool uncollapse = mutt_using_threads() && !window_is_focused(priv->win_index);
1782
1783 index = find_next_undeleted(shared->mailbox_view, index, uncollapse);
1784 if (index != -1)
1785 {
1786 menu_set_index(priv->menu, index);
1787 if (uncollapse)
1789 }
1790
1791 if (index == -1)
1792 {
1793 notify_send(shared->notify, NT_INDEX, NT_INDEX_EMAIL, NULL);
1794 mutt_error(_("No undeleted messages"));
1795 }
1796
1797 return FR_SUCCESS;
1798}
1799
1804 struct IndexPrivateData *priv,
1805 const struct KeyEvent *event)
1806{
1807 struct Mailbox *m = shared->mailbox;
1808
1809 struct Buffer *folderbuf = buf_pool_get();
1810 buf_strcpy(folderbuf, mailbox_path(m));
1811 m = mutt_mailbox_next_unread(m, folderbuf);
1812 buf_pool_release(&folderbuf);
1813
1814 if (!m)
1815 {
1816 mutt_error(_("No mailboxes have new mail"));
1817 return FR_ERROR;
1818 }
1819
1820 change_folder_mailbox(priv->menu, m, &priv->oldcount, shared, false);
1821 return FR_SUCCESS;
1822}
1823
1827static int op_main_prev_undeleted(struct IndexSharedData *shared,
1828 struct IndexPrivateData *priv, const struct KeyEvent *event)
1829{
1830 int index = menu_get_index(priv->menu);
1831 if (index < 1)
1832 {
1833 notify_send(shared->notify, NT_INDEX, NT_INDEX_EMAIL, NULL);
1834 mutt_message(_("You are on the first message"));
1835 return FR_ERROR;
1836 }
1837
1838 const bool uncollapse = mutt_using_threads() && !window_is_focused(priv->win_index);
1839
1840 index = find_previous_undeleted(shared->mailbox_view, index, uncollapse);
1841 if (index != -1)
1842 {
1843 menu_set_index(priv->menu, index);
1844 if (uncollapse)
1846 }
1847
1848 if (index == -1)
1849 {
1850 mutt_error(_("No undeleted messages"));
1851 notify_send(shared->notify, NT_INDEX, NT_INDEX_EMAIL, NULL);
1852 }
1853
1854 return FR_SUCCESS;
1855}
1856
1860static int op_main_quasi_delete(struct IndexSharedData *shared,
1861 struct IndexPrivateData *priv, const struct KeyEvent *event)
1862{
1863 if (priv->tag_prefix)
1864 {
1865 struct Mailbox *m = shared->mailbox;
1866 for (size_t i = 0; i < m->msg_count; i++)
1867 {
1868 struct Email *e = m->emails[i];
1869 if (!e)
1870 break;
1871 if (message_is_tagged(e))
1872 {
1873 e->quasi_deleted = true;
1874 m->changed = true;
1875 }
1876 }
1877 }
1878 else
1879 {
1880 if (!shared->email)
1881 return FR_NO_ACTION;
1882 shared->email->quasi_deleted = true;
1883 shared->mailbox->changed = true;
1884 }
1885
1886 return FR_SUCCESS;
1887}
1888
1896static int op_main_read_thread(struct IndexSharedData *shared,
1897 struct IndexPrivateData *priv, const struct KeyEvent *event)
1898{
1899 /* L10N: CHECK_ACL */
1900 /* L10N: Due to the implementation details we do not know whether we
1901 mark zero, 1, 12, ... messages as read. So in English we use
1902 "messages". Your language might have other means to express this. */
1903 if (!check_acl(shared->mailbox, MUTT_ACL_SEEN, _("Can't mark messages as read")))
1904 return FR_ERROR;
1905
1906 const int op = event->op;
1907 int rc = mutt_thread_set_flag(shared->mailbox, shared->email, MUTT_READ, true,
1908 (op != OP_MAIN_READ_THREAD));
1909 if (rc != -1)
1910 {
1911 const enum ResolveMethod rm = (op == OP_MAIN_READ_THREAD) ? RESOLVE_NEXT_THREAD :
1913 resolve_email(priv, shared, rm);
1915 }
1916
1917 return FR_SUCCESS;
1918}
1919
1927static int op_main_root_message(struct IndexSharedData *shared,
1928 struct IndexPrivateData *priv, const struct KeyEvent *event)
1929{
1930 int index = mutt_parent_message(shared->email, event->op == OP_MAIN_ROOT_MESSAGE);
1931 if (index != -1)
1932 menu_set_index(priv->menu, index);
1933
1934 return FR_SUCCESS;
1935}
1936
1944static int op_main_set_flag(struct IndexSharedData *shared,
1945 struct IndexPrivateData *priv, const struct KeyEvent *event)
1946{
1947 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
1948 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
1949
1950 if (mw_change_flag(shared->mailbox, &ea, (event->op == OP_MAIN_SET_FLAG)) == 0)
1951 {
1952 if (priv->tag_prefix)
1953 {
1955 }
1956 else
1957 {
1959 }
1960 }
1961 ARRAY_FREE(&ea);
1962
1963 return FR_SUCCESS;
1964}
1965
1969static int op_main_show_limit(struct IndexSharedData *shared,
1970 struct IndexPrivateData *priv, const struct KeyEvent *event)
1971{
1972 if (mview_has_limit(shared->mailbox_view))
1973 {
1974 struct Buffer *buf = buf_pool_get();
1975 /* L10N: ask for a limit to apply */
1976 buf_printf(buf, _("Limit: %s"), shared->mailbox_view->pattern);
1977 mutt_message("%s", buf_string(buf));
1978 buf_pool_release(&buf);
1979 }
1980 else
1981 {
1982 mutt_message(_("No limit pattern is in effect"));
1983 }
1984
1985 return FR_SUCCESS;
1986}
1987
1991static int op_main_sync_folder(struct IndexSharedData *shared,
1992 struct IndexPrivateData *priv, const struct KeyEvent *event)
1993{
1994 if (!shared->mailbox || (shared->mailbox->msg_count == 0) || shared->mailbox->readonly)
1995 return FR_NO_ACTION;
1996
1997 int ovc = shared->mailbox->vcount;
1998 int oc = shared->mailbox->msg_count;
1999 struct Email *e = NULL;
2000
2001 /* don't attempt to move the cursor if there are no visible messages in the current limit */
2002 int index = menu_get_index(priv->menu);
2003 if (index < shared->mailbox->vcount)
2004 {
2005 /* threads may be reordered, so figure out what header the cursor
2006 * should be on. */
2007 int newidx = index;
2008 if (!shared->email)
2009 return FR_NO_ACTION;
2010 if (shared->email->deleted)
2011 newidx = find_next_undeleted(shared->mailbox_view, index, false);
2012 if (newidx < 0)
2013 newidx = find_previous_undeleted(shared->mailbox_view, index, false);
2014 if (newidx >= 0)
2015 e = mutt_get_virt_email(shared->mailbox, newidx);
2016 }
2017
2018 enum MxStatus check = mx_mbox_sync(shared->mailbox);
2019 if (check == MX_STATUS_OK)
2020 {
2021 if (e && (shared->mailbox->vcount != ovc))
2022 {
2023 for (size_t i = 0; i < shared->mailbox->vcount; i++)
2024 {
2025 struct Email *e2 = mutt_get_virt_email(shared->mailbox, i);
2026 if (e2 == e)
2027 {
2028 menu_set_index(priv->menu, i);
2029 break;
2030 }
2031 }
2032 }
2034 }
2035 else if ((check == MX_STATUS_NEW_MAIL) || (check == MX_STATUS_REOPENED))
2036 {
2037 update_index(priv->menu, shared->mailbox_view, check, oc, shared);
2038 }
2039
2040 /* do a sanity check even if mx_mbox_sync failed. */
2041
2042 index = menu_get_index(priv->menu);
2043 if ((index < 0) || (shared->mailbox && (index >= shared->mailbox->vcount)))
2044 {
2046 }
2047
2048 /* check for a fatal error, or all messages deleted */
2049 if (shared->mailbox && buf_is_empty(&shared->mailbox->pathbuf))
2050 {
2051 mview_free(&shared->mailbox_view);
2052 }
2053
2054 if (shared->mailbox)
2055 {
2056 priv->menu->max = shared->mailbox->vcount;
2058
2059 struct EventMailbox ev_m = { shared->mailbox };
2061 }
2062 else
2063 {
2064 priv->menu->max = 0;
2066 }
2067
2068 return FR_SUCCESS;
2069}
2070
2074static int op_main_tag_pattern(struct IndexSharedData *shared,
2075 struct IndexPrivateData *priv, const struct KeyEvent *event)
2076{
2077 mutt_pattern_func(shared->mailbox_view, MUTT_TAG, _("Tag messages matching: "));
2079
2080 return FR_SUCCESS;
2081}
2082
2087 struct IndexPrivateData *priv,
2088 const struct KeyEvent *event)
2089{
2090 /* L10N: CHECK_ACL */
2091 /* L10N: Due to the implementation details we do not know whether we
2092 undelete zero, 1, 12, ... messages. So in English we use
2093 "messages". Your language might have other means to express this. */
2094 if (!check_acl(shared->mailbox, MUTT_ACL_DELETE, _("Can't undelete messages")))
2095 return FR_ERROR;
2096
2098 _("Undelete messages matching: ")) == 0)
2099 {
2101 }
2102
2103 return FR_SUCCESS;
2104}
2105
2109static int op_main_untag_pattern(struct IndexSharedData *shared,
2110 struct IndexPrivateData *priv, const struct KeyEvent *event)
2111{
2112 if (mutt_pattern_func(shared->mailbox_view, MUTT_UNTAG, _("Untag messages matching: ")) == 0)
2114
2115 return FR_SUCCESS;
2116}
2117
2121static int op_mark_msg(struct IndexSharedData *shared,
2122 struct IndexPrivateData *priv, const struct KeyEvent *event)
2123{
2124 if (!shared->email)
2125 return FR_NO_ACTION;
2126
2127 int rc = FR_SUCCESS;
2128
2129 if (shared->email->env->message_id)
2130 {
2131 struct Buffer *buf = buf_pool_get();
2132
2133 /* L10N: This is the prompt for <mark-message>. Whatever they
2134 enter will be prefixed by $mark_macro_prefix and will become
2135 a macro hotkey to jump to the currently selected message. */
2136 if ((mw_get_field(_("Enter macro stroke: "), buf, MUTT_COMP_NO_FLAGS,
2137 HC_OTHER, NULL, NULL) == 0) &&
2138 !buf_is_empty(buf))
2139 {
2140 const char *const c_mark_macro_prefix = cs_subset_string(shared->sub, "mark_macro_prefix");
2141 char str[256] = { 0 };
2142 snprintf(str, sizeof(str), "%s%s", c_mark_macro_prefix, buf_string(buf));
2143
2144 struct Buffer *msg_id = buf_pool_get();
2145 mutt_file_sanitize_regex(msg_id, shared->email->env->message_id);
2146 char macro[256] = { 0 };
2147 snprintf(macro, sizeof(macro), "<search>~i '%s'\n", buf_string(msg_id));
2148 buf_pool_release(&msg_id);
2149
2150 /* L10N: "message hotkey" is the key bindings menu description of a
2151 macro created by <mark-message>. */
2152 km_bind(MdIndex, str, OP_MACRO, macro, _("message hotkey"), NULL);
2153
2154 /* L10N: This is echoed after <mark-message> creates a new hotkey
2155 macro. %s is the hotkey string ($mark_macro_prefix followed
2156 by whatever they typed at the prompt.) */
2157 buf_printf(buf, _("Message bound to %s"), str);
2158 mutt_message("%s", buf_string(buf));
2159 mutt_debug(LL_DEBUG1, "Mark: %s => %s\n", str, macro);
2160 }
2161 buf_pool_release(&buf);
2162 }
2163 else
2164 {
2165 /* L10N: This error is printed if <mark-message> can't find a
2166 Message-ID for the currently selected message in the index. */
2167 mutt_error(_("No message ID to macro"));
2168 rc = FR_ERROR;
2169 }
2170
2171 return rc;
2172}
2173
2177static int op_next_entry(struct IndexSharedData *shared,
2178 struct IndexPrivateData *priv, const struct KeyEvent *event)
2179{
2180 const int index = menu_get_index(priv->menu) + 1;
2181 if (index >= shared->mailbox->vcount)
2182 {
2183 mutt_message(_("You are on the last message"));
2184 notify_send(shared->notify, NT_INDEX, NT_INDEX_EMAIL, NULL);
2185 return FR_ERROR;
2186 }
2187 menu_set_index(priv->menu, index);
2188 return FR_SUCCESS;
2189}
2190
2194static int op_pipe(struct IndexSharedData *shared,
2195 struct IndexPrivateData *priv, const struct KeyEvent *event)
2196{
2197 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
2198 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
2199 mutt_pipe_message(shared->mailbox, &ea);
2200 ARRAY_FREE(&ea);
2201
2202 /* in an IMAP folder index with imap_peek=no, piping could change
2203 * new or old messages status to read. Redraw what's needed. */
2204 const bool c_imap_peek = cs_subset_bool(shared->sub, "imap_peek");
2205 if ((shared->mailbox->type == MUTT_IMAP) && !c_imap_peek)
2206 {
2208 }
2209
2210 return FR_SUCCESS;
2211}
2212
2216static int op_prev_entry(struct IndexSharedData *shared,
2217 struct IndexPrivateData *priv, const struct KeyEvent *event)
2218{
2219 int index = menu_get_index(priv->menu);
2220 if (index < 1)
2221 {
2222 notify_send(shared->notify, NT_INDEX, NT_INDEX_EMAIL, NULL);
2223 mutt_message(_("You are on the first message"));
2224 return FR_ERROR;
2225 }
2226 menu_set_index(priv->menu, index - 1);
2227 return FR_SUCCESS;
2228}
2229
2233static int op_print(struct IndexSharedData *shared,
2234 struct IndexPrivateData *priv, const struct KeyEvent *event)
2235{
2236 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
2237 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
2238 mutt_print_message(shared->mailbox, &ea);
2239 ARRAY_FREE(&ea);
2240
2241 /* in an IMAP folder index with imap_peek=no, printing could change
2242 * new or old messages status to read. Redraw what's needed. */
2243 const bool c_imap_peek = cs_subset_bool(shared->sub, "imap_peek");
2244 if ((shared->mailbox->type == MUTT_IMAP) && !c_imap_peek)
2245 {
2247 }
2248
2249 return FR_SUCCESS;
2250}
2251
2255static int op_query(struct IndexSharedData *shared,
2256 struct IndexPrivateData *priv, const struct KeyEvent *event)
2257{
2258 query_index(shared->mailbox, shared->sub);
2259 return FR_SUCCESS;
2260}
2261
2265static int op_quit(struct IndexSharedData *shared,
2266 struct IndexPrivateData *priv, const struct KeyEvent *event)
2267{
2268 if (shared->attach_msg)
2269 return FR_DONE;
2270
2271 if (query_quadoption(_("Quit NeoMutt?"), shared->sub, "quit") == MUTT_YES)
2272 {
2273 priv->oldcount = shared->mailbox ? shared->mailbox->msg_count : 0;
2274
2276 mutt_debug(LL_NOTIFY, "NT_GLOBAL_SHUTDOWN\n");
2278
2279 enum MxStatus check = MX_STATUS_OK;
2280 if (!shared->mailbox_view || ((check = mx_mbox_close(shared->mailbox)) == MX_STATUS_OK))
2281 {
2282 mview_free(&shared->mailbox_view);
2283 mailbox_free(&shared->mailbox);
2284 return FR_DONE;
2285 }
2286
2287 if ((check == MX_STATUS_NEW_MAIL) || (check == MX_STATUS_REOPENED))
2288 {
2289 update_index(priv->menu, shared->mailbox_view, check, priv->oldcount, shared);
2290 }
2291
2292 menu_queue_redraw(priv->menu, MENU_REDRAW_FULL); /* new mail arrived? */
2294 }
2295
2296 return FR_NO_ACTION;
2297}
2298
2302static int op_recall_message(struct IndexSharedData *shared,
2303 struct IndexPrivateData *priv, const struct KeyEvent *event)
2304{
2305 int rc = mutt_send_message(SEND_POSTPONED, NULL, NULL, shared->mailbox, NULL,
2306 shared->sub);
2308 return (rc == -1) ? FR_ERROR : FR_SUCCESS;
2309}
2310
2314static int op_reply(struct IndexSharedData *shared,
2315 struct IndexPrivateData *priv, const struct KeyEvent *event)
2316{
2317 if (!shared->email)
2318 return FR_NO_ACTION;
2319 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
2320 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
2321 const bool c_pgp_auto_decode = cs_subset_bool(shared->sub, "pgp_auto_decode");
2322 if (c_pgp_auto_decode &&
2323 (priv->tag_prefix || !(shared->email->security & PGP_TRADITIONAL_CHECKED)))
2324 {
2325 if (mutt_check_traditional_pgp(shared->mailbox, &ea))
2327 }
2328 int rc = mutt_send_message(SEND_REPLY, NULL, NULL, shared->mailbox, &ea,
2329 shared->sub);
2330 ARRAY_FREE(&ea);
2332
2333 return (rc == -1) ? FR_ERROR : FR_SUCCESS;
2334}
2335
2339static int op_resend(struct IndexSharedData *shared,
2340 struct IndexPrivateData *priv, const struct KeyEvent *event)
2341{
2342 int rc = -1;
2343 if (priv->tag_prefix)
2344 {
2345 struct Mailbox *m = shared->mailbox;
2346 for (size_t i = 0; i < m->msg_count; i++)
2347 {
2348 struct Email *e = m->emails[i];
2349 if (!e)
2350 break;
2351 if (message_is_tagged(e))
2352 rc = mutt_resend_message(NULL, shared->mailbox, e, shared->sub);
2353 }
2354 }
2355 else
2356 {
2357 rc = mutt_resend_message(NULL, shared->mailbox, shared->email, shared->sub);
2358 }
2359
2361 return (rc == -1) ? FR_ERROR : FR_SUCCESS;
2362}
2363
2375static int op_save(struct IndexSharedData *shared,
2376 struct IndexPrivateData *priv, const struct KeyEvent *event)
2377{
2378 const int op = event->op;
2379 if (((op == OP_DECRYPT_COPY) || (op == OP_DECRYPT_SAVE)) && !WithCrypto)
2380 return FR_NOT_IMPL;
2381
2382 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
2383 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
2384
2385 const enum MessageSaveOpt save_opt = ((op == OP_SAVE) || (op == OP_DECODE_SAVE) ||
2386 (op == OP_DECRYPT_SAVE)) ?
2387 SAVE_MOVE :
2388 SAVE_COPY;
2389
2390 enum MessageTransformOpt transform_opt =
2391 ((op == OP_DECODE_SAVE) || (op == OP_DECODE_COPY)) ? TRANSFORM_DECODE :
2392 ((op == OP_DECRYPT_SAVE) || (op == OP_DECRYPT_COPY)) ? TRANSFORM_DECRYPT :
2394
2395 const int rc = mutt_save_message(shared->mailbox, &ea, save_opt, transform_opt);
2396 if ((rc == 0) && (save_opt == SAVE_MOVE) && !priv->tag_prefix)
2397 {
2399 }
2400 ARRAY_FREE(&ea);
2401
2402 if (priv->tag_prefix)
2404
2405 return (rc == -1) ? FR_ERROR : FR_SUCCESS;
2406}
2407
2417static int op_search(struct IndexSharedData *shared,
2418 struct IndexPrivateData *priv, const struct KeyEvent *event)
2419{
2421 switch (event->op)
2422 {
2423 case OP_SEARCH:
2424 flags |= SEARCH_PROMPT;
2425 shared->search_state->reverse = false;
2426 break;
2427 case OP_SEARCH_REVERSE:
2428 flags |= SEARCH_PROMPT;
2429 shared->search_state->reverse = true;
2430 break;
2431 case OP_SEARCH_NEXT:
2432 break;
2433 case OP_SEARCH_OPPOSITE:
2434 flags |= SEARCH_OPPOSITE;
2435 break;
2436 }
2437
2438 // Initiating a search can happen on an empty mailbox, but
2439 // searching for next/previous/... needs to be on a message and
2440 // thus a non-empty mailbox
2441 int index = menu_get_index(priv->menu);
2442 index = mutt_search_command(shared->mailbox_view, priv->menu, index,
2443 shared->search_state, flags);
2444 if (index != -1)
2445 menu_set_index(priv->menu, index);
2446
2447 return FR_SUCCESS;
2448}
2449
2457static int op_sort(struct IndexSharedData *shared,
2458 struct IndexPrivateData *priv, const struct KeyEvent *event)
2459{
2460 if (!mutt_select_sort(event->op == OP_SORT_REVERSE))
2461 return FR_ERROR;
2462
2463 if (shared->mailbox && (shared->mailbox->msg_count != 0))
2464 {
2465 resort_index(shared->mailbox_view, priv->menu);
2467 }
2468
2469 return FR_SUCCESS;
2470}
2471
2475static int op_tag(struct IndexSharedData *shared, struct IndexPrivateData *priv,
2476 const struct KeyEvent *event)
2477{
2478 const bool c_auto_tag = cs_subset_bool(shared->sub, "auto_tag");
2479 if (priv->tag_prefix && !c_auto_tag)
2480 {
2481 struct Mailbox *m = shared->mailbox;
2482 for (size_t i = 0; i < m->msg_count; i++)
2483 {
2484 struct Email *e = m->emails[i];
2485 if (!e)
2486 break;
2487 if (e->visible)
2488 mutt_set_flag(m, e, MUTT_TAG, false, true);
2489 }
2491 return FR_SUCCESS;
2492 }
2493
2494 if (!shared->email)
2495 return FR_NO_ACTION;
2496
2497 mutt_set_flag(shared->mailbox, shared->email, MUTT_TAG, !shared->email->tagged, true);
2498
2499 resolve_email(priv, shared, RESOLVE_NEXT_EMAIL);
2500 return FR_SUCCESS;
2501}
2502
2510static int op_tag_thread(struct IndexSharedData *shared,
2511 struct IndexPrivateData *priv, const struct KeyEvent *event)
2512{
2513 if (!shared->email)
2514 return FR_NO_ACTION;
2515
2516 const int op = event->op;
2517 int rc = mutt_thread_set_flag(shared->mailbox, shared->email, MUTT_TAG,
2518 !shared->email->tagged, (op != OP_TAG_THREAD));
2519 if (rc != -1)
2520 {
2521 const enum ResolveMethod rm = (op == OP_TAG_THREAD) ? RESOLVE_NEXT_THREAD :
2523 resolve_email(priv, shared, rm);
2525 }
2526
2527 return FR_SUCCESS;
2528}
2529
2533static int op_toggle_new(struct IndexSharedData *shared,
2534 struct IndexPrivateData *priv, const struct KeyEvent *event)
2535{
2536 /* L10N: CHECK_ACL */
2537 if (!check_acl(shared->mailbox, MUTT_ACL_SEEN, _("Can't toggle new")))
2538 return FR_ERROR;
2539
2540 struct Mailbox *m = shared->mailbox;
2541 if (priv->tag_prefix)
2542 {
2543 for (size_t i = 0; i < m->msg_count; i++)
2544 {
2545 struct Email *e = m->emails[i];
2546 if (!e)
2547 break;
2548 if (!message_is_tagged(e))
2549 continue;
2550
2551 if (e->read || e->old)
2552 mutt_set_flag(m, e, MUTT_NEW, true, true);
2553 else
2554 mutt_set_flag(m, e, MUTT_READ, true, true);
2555 }
2557 }
2558 else
2559 {
2560 if (!shared->email)
2561 return FR_NO_ACTION;
2562 if (shared->email->read || shared->email->old)
2563 mutt_set_flag(m, shared->email, MUTT_NEW, true, true);
2564 else
2565 mutt_set_flag(m, shared->email, MUTT_READ, true, true);
2566
2568 }
2569
2570 return FR_SUCCESS;
2571}
2572
2576static int op_toggle_write(struct IndexSharedData *shared,
2577 struct IndexPrivateData *priv, const struct KeyEvent *event)
2578{
2579 mx_toggle_write(shared->mailbox);
2580 return FR_SUCCESS;
2581}
2582
2586static int op_undelete(struct IndexSharedData *shared,
2587 struct IndexPrivateData *priv, const struct KeyEvent *event)
2588{
2589 /* L10N: CHECK_ACL */
2590 if (!check_acl(shared->mailbox, MUTT_ACL_DELETE, _("Can't undelete message")))
2591 return FR_ERROR;
2592
2593 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
2594 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
2595
2596 mutt_emails_set_flag(shared->mailbox, &ea, MUTT_DELETE, false);
2597 mutt_emails_set_flag(shared->mailbox, &ea, MUTT_PURGE, false);
2598 ARRAY_FREE(&ea);
2599
2600 if (priv->tag_prefix)
2601 {
2603 }
2604 else
2605 {
2606 resolve_email(priv, shared, RESOLVE_NEXT_EMAIL);
2607 }
2608
2609 return FR_SUCCESS;
2610}
2611
2619static int op_undelete_thread(struct IndexSharedData *shared,
2620 struct IndexPrivateData *priv, const struct KeyEvent *event)
2621{
2622 /* L10N: CHECK_ACL */
2623 /* L10N: Due to the implementation details we do not know whether we
2624 undelete zero, 1, 12, ... messages. So in English we use
2625 "messages". Your language might have other means to express this. */
2626 if (!check_acl(shared->mailbox, MUTT_ACL_DELETE, _("Can't undelete messages")))
2627 return FR_ERROR;
2628
2629 const int op = event->op;
2630 int rc = mutt_thread_set_flag(shared->mailbox, shared->email, MUTT_DELETE,
2631 false, (op != OP_UNDELETE_THREAD));
2632 if (rc != -1)
2633 {
2634 rc = mutt_thread_set_flag(shared->mailbox, shared->email, MUTT_PURGE, false,
2635 (op != OP_UNDELETE_THREAD));
2636 }
2637 if (rc != -1)
2638 {
2639 const enum ResolveMethod rm = (op == OP_UNDELETE_THREAD) ? RESOLVE_NEXT_THREAD :
2641 resolve_email(priv, shared, rm);
2643 }
2644
2645 return FR_SUCCESS;
2646}
2647
2651static int op_view_attachments(struct IndexSharedData *shared,
2652 struct IndexPrivateData *priv, const struct KeyEvent *event)
2653{
2654 if (!shared->email)
2655 return FR_NO_ACTION;
2656
2657 enum FunctionRetval rc = FR_ERROR;
2658 struct Message *msg = mx_msg_open(shared->mailbox, shared->email);
2659 if (msg)
2660 {
2661 dlg_attach(NeoMutt->sub, shared->mailbox_view, shared->email, msg->fp,
2662 shared->attach_msg);
2663 if (shared->email->attach_del)
2664 {
2665 shared->mailbox->changed = true;
2666 }
2667 mx_msg_close(shared->mailbox, &msg);
2668 rc = FR_SUCCESS;
2669 }
2671 return rc;
2672}
2673
2674// -----------------------------------------------------------------------------
2675
2676#ifdef USE_AUTOCRYPT
2680static int op_autocrypt_acct_menu(struct IndexSharedData *shared,
2681 struct IndexPrivateData *priv, const struct KeyEvent *event)
2682{
2683 dlg_autocrypt();
2684 return FR_SUCCESS;
2685}
2686#endif
2687
2691static int op_main_imap_fetch(struct IndexSharedData *shared,
2692 struct IndexPrivateData *priv, const struct KeyEvent *event)
2693{
2694 if (!shared->mailbox || (shared->mailbox->type != MUTT_IMAP))
2695 return FR_NO_ACTION;
2696
2697 imap_check_mailbox(shared->mailbox, true);
2698 return FR_SUCCESS;
2699}
2700
2705 struct IndexPrivateData *priv,
2706 const struct KeyEvent *event)
2707{
2708 if (shared->mailbox && (shared->mailbox->type == MUTT_IMAP))
2709 {
2710 const enum MxStatus check = mx_mbox_close(shared->mailbox);
2711 if (check == MX_STATUS_OK)
2712 {
2713 mview_free(&shared->mailbox_view);
2714 }
2715 else
2716 {
2717 if ((check == MX_STATUS_NEW_MAIL) || (check == MX_STATUS_REOPENED))
2718 {
2719 update_index(priv->menu, shared->mailbox_view, check, priv->oldcount, shared);
2720 }
2723 return FR_ERROR;
2724 }
2725 }
2727 mutt_message(_("Logged out of IMAP servers"));
2730
2731 return FR_SUCCESS;
2732}
2733
2737static int op_catchup(struct IndexSharedData *shared,
2738 struct IndexPrivateData *priv, const struct KeyEvent *event)
2739{
2740 struct Mailbox *m = shared->mailbox;
2741 if (!m || (m->type != MUTT_NNTP))
2742 return FR_NO_ACTION;
2743
2744 struct NntpMboxData *mdata = m->mdata;
2745 if (mutt_newsgroup_catchup(m, mdata->adata, mdata->group))
2747
2748 return FR_SUCCESS;
2749}
2750
2758static int op_get_children(struct IndexSharedData *shared,
2759 struct IndexPrivateData *priv, const struct KeyEvent *event)
2760{
2761 struct Mailbox *m = shared->mailbox;
2762 if (m->type != MUTT_NNTP)
2763 return FR_ERROR;
2764
2765 struct Email *e = shared->email;
2766 if (!e)
2767 return FR_NO_ACTION;
2768
2769 char buf[PATH_MAX] = { 0 };
2770 int oldmsgcount = m->msg_count;
2771 int oldindex = e->index;
2772 int rc = 0;
2773
2774 if (!e->env->message_id)
2775 {
2776 mutt_error(_("No Message-ID. Unable to perform operation."));
2777 return FR_ERROR;
2778 }
2779
2780 mutt_message(_("Fetching message headers..."));
2781 if (!m->id_hash)
2782 m->id_hash = mutt_make_id_hash(m);
2783 mutt_str_copy(buf, e->env->message_id, sizeof(buf));
2784
2785 const int op = event->op;
2786 /* trying to find msgid of the root message */
2787 if (op == OP_RECONSTRUCT_THREAD)
2788 {
2789 struct ListNode *ref = NULL;
2790 STAILQ_FOREACH(ref, &e->env->references, entries)
2791 {
2792 if (!mutt_hash_find(m->id_hash, ref->data))
2793 {
2794 rc = nntp_check_msgid(m, ref->data);
2795 if (rc < 0)
2796 return FR_ERROR;
2797 }
2798
2799 /* the last msgid in References is the root message */
2800 if (!STAILQ_NEXT(ref, entries))
2801 mutt_str_copy(buf, ref->data, sizeof(buf));
2802 }
2803 }
2804
2805 /* fetching all child messages */
2806 rc = nntp_check_children(m, buf);
2807
2808 /* at least one message has been loaded */
2809 if (m->msg_count > oldmsgcount)
2810 {
2811 bool verbose = m->verbose;
2812
2813 if (rc < 0)
2814 m->verbose = false;
2815
2816 struct MailboxView *mv = shared->mailbox_view;
2817 mutt_sort_headers(mv, (op == OP_RECONSTRUCT_THREAD));
2818 m->verbose = verbose;
2819
2820 /* if the root message was retrieved, move to it */
2821 struct Email *e2 = mutt_hash_find(m->id_hash, buf);
2822 if (e2)
2823 {
2824 menu_set_index(priv->menu, e2->vnum);
2825 }
2826 else
2827 {
2828 /* try to restore old position */
2829 for (int i = 0; i < m->msg_count; i++)
2830 {
2831 e2 = m->emails[i];
2832 if (!e2)
2833 break;
2834 if (e2->index == oldindex)
2835 {
2836 menu_set_index(priv->menu, e2->vnum);
2837 /* as an added courtesy, recenter the menu
2838 * with the current entry at the middle of the screen */
2840 }
2841 }
2842 }
2844 }
2845 else if (rc >= 0)
2846 {
2847 mutt_error(_("No deleted messages found in the thread"));
2848 }
2849
2850 return FR_SUCCESS;
2851}
2852
2860static int op_get_message(struct IndexSharedData *shared,
2861 struct IndexPrivateData *priv, const struct KeyEvent *event)
2862{
2863 struct Mailbox *m = shared->mailbox;
2864 if (m->type != MUTT_NNTP)
2865 return FR_SUCCESS;
2866
2867 int rc = FR_ERROR;
2868 struct Buffer *buf = buf_pool_get();
2869
2870 const int op = event->op;
2871 if (op == OP_GET_MESSAGE)
2872 {
2873 if ((mw_get_field(_("Enter Message-ID: "), buf, MUTT_COMP_NO_FLAGS,
2874 HC_OTHER, NULL, NULL) != 0) ||
2875 buf_is_empty(buf))
2876 {
2877 goto done;
2878 }
2879 }
2880 else
2881 {
2882 struct Email *e = shared->email;
2883 if (!e || STAILQ_EMPTY(&e->env->references))
2884 {
2885 mutt_error(_("Article has no parent reference"));
2886 goto done;
2887 }
2889 }
2890
2891 if (!m->id_hash)
2892 m->id_hash = mutt_make_id_hash(m);
2893 struct Email *e = mutt_hash_find(m->id_hash, buf_string(buf));
2894 if (e)
2895 {
2896 if (e->vnum != -1)
2897 {
2898 menu_set_index(priv->menu, e->vnum);
2899 }
2900 else if (e->collapsed)
2901 {
2903 mutt_set_vnum(m);
2904 menu_set_index(priv->menu, e->vnum);
2905 }
2906 else
2907 {
2908 mutt_error(_("Message is not visible in limited view"));
2909 }
2910 }
2911 else
2912 {
2913 mutt_message(_("Fetching %s from server..."), buf_string(buf));
2914 int rc2 = nntp_check_msgid(m, buf_string(buf));
2915 if (rc2 == 0)
2916 {
2917 e = m->emails[m->msg_count - 1];
2918 struct MailboxView *mv = shared->mailbox_view;
2919 mutt_sort_headers(mv, false);
2920 menu_set_index(priv->menu, e->vnum);
2922 rc = FR_SUCCESS;
2923 }
2924 else if (rc2 > 0)
2925 {
2926 mutt_error(_("Article %s not found on the server"), buf_string(buf));
2927 }
2928 }
2929
2930done:
2931 buf_pool_release(&buf);
2932 return rc;
2933}
2934
2942static int op_main_change_group(struct IndexSharedData *shared,
2943 struct IndexPrivateData *priv, const struct KeyEvent *event)
2944{
2945 struct Buffer *folderbuf = buf_pool_get();
2946 buf_alloc(folderbuf, PATH_MAX);
2947
2948 OptNews = false;
2949 bool read_only;
2950 char *cp = NULL;
2951 const bool c_read_only = cs_subset_bool(shared->sub, "read_only");
2952 const int op = event->op;
2953 if (shared->attach_msg || c_read_only || (op == OP_MAIN_CHANGE_GROUP_READONLY))
2954 {
2955 cp = _("Open newsgroup in read-only mode");
2956 read_only = true;
2957 }
2958 else
2959 {
2960 cp = _("Open newsgroup");
2961 read_only = false;
2962 }
2963
2964 const bool c_change_folder_next = cs_subset_bool(shared->sub, "change_folder_next");
2965 if (c_change_folder_next && shared->mailbox && !buf_is_empty(&shared->mailbox->pathbuf))
2966 {
2967 buf_strcpy(folderbuf, mailbox_path(shared->mailbox));
2968 pretty_mailbox(folderbuf);
2969 }
2970
2971 OptNews = true;
2972 const char *const c_news_server = cs_subset_string(shared->sub, "news_server");
2973 if (!CurrentNewsSrv)
2974 CurrentNewsSrv = nntp_select_server(shared->mailbox, c_news_server, false);
2975 if (!CurrentNewsSrv)
2976 goto changefoldercleanup2;
2977
2978 nntp_mailbox(shared->mailbox, folderbuf->data, folderbuf->dsize);
2979
2980 if (mw_enter_fname(cp, folderbuf, true, shared->mailbox, false, NULL, NULL,
2981 MUTT_SEL_NO_FLAGS) == -1)
2982 {
2983 goto changefoldercleanup2;
2984 }
2985
2986 /* Selected directory is okay, let's save it. */
2988
2989 if (buf_is_empty(folderbuf))
2990 {
2991 msgwin_clear_text(NULL);
2992 goto changefoldercleanup2;
2993 }
2994
2995 struct Mailbox *m = mx_mbox_find2(buf_string(folderbuf));
2996 if (m)
2997 {
2998 change_folder_mailbox(priv->menu, m, &priv->oldcount, shared, read_only);
2999 }
3000 else
3001 {
3002 change_folder_string(priv->menu, folderbuf, &priv->oldcount, shared, read_only);
3003 }
3004 struct MuttWindow *dlg = dialog_find(priv->win_index);
3005 dlg->help_data = IndexNewsHelp;
3006
3007changefoldercleanup2:
3008 buf_pool_release(&folderbuf);
3009 return FR_SUCCESS;
3010}
3011
3019static int op_post(struct IndexSharedData *shared,
3020 struct IndexPrivateData *priv, const struct KeyEvent *event)
3021{
3022 if (!shared->email)
3023 return FR_NO_ACTION;
3024
3025 const int op = event->op;
3026 if ((op != OP_FOLLOWUP) || !shared->email->env->followup_to ||
3027 !mutt_istr_equal(shared->email->env->followup_to, "poster") ||
3028 (query_quadoption(_("Reply by mail as poster prefers?"), shared->sub,
3029 "followup_to_poster") != MUTT_YES))
3030 {
3031 if (shared->mailbox && (shared->mailbox->type == MUTT_NNTP) &&
3032 !((struct NntpMboxData *) shared->mailbox->mdata)->allowed &&
3033 (query_quadoption(_("Posting to this group not allowed, may be moderated. Continue?"),
3034 shared->sub, "post_moderated") != MUTT_YES))
3035 {
3036 return FR_ERROR;
3037 }
3038 if (op == OP_POST)
3039 {
3040 mutt_send_message(SEND_NEWS, NULL, NULL, shared->mailbox, NULL, shared->sub);
3041 }
3042 else
3043 {
3044 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
3045 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
3046 mutt_send_message(((op == OP_FOLLOWUP) ? SEND_REPLY : SEND_FORWARD) | SEND_NEWS,
3047 NULL, NULL, shared->mailbox, &ea, shared->sub);
3048 ARRAY_FREE(&ea);
3049 }
3051 return FR_SUCCESS;
3052 }
3053
3054 struct KeyEvent event_r = { 0, OP_REPLY };
3055 return op_reply(shared, priv, &event_r);
3056}
3057
3058#ifdef USE_NOTMUCH
3062static int op_main_entire_thread(struct IndexSharedData *shared,
3063 struct IndexPrivateData *priv, const struct KeyEvent *event)
3064{
3065 if (shared->mailbox->type != MUTT_NOTMUCH)
3066 {
3067 if (((shared->mailbox->type != MUTT_MH) && (shared->mailbox->type != MUTT_MAILDIR)) ||
3068 (!shared->email || !shared->email->env || !shared->email->env->message_id))
3069 {
3070 mutt_message(_("No virtual folder and no Message-ID, aborting"));
3071 return FR_ERROR;
3072 } // no virtual folder, but we have Message-ID, reconstruct thread on-the-fly
3073
3074 struct Buffer *buf = buf_pool_get();
3075 buf_alloc(buf, PATH_MAX);
3076 buf_addstr(buf, "id:");
3077
3078 int msg_id_offset = 0;
3079 if ((shared->email->env->message_id)[0] == '<')
3080 msg_id_offset = 1;
3081
3082 buf_addstr(buf, shared->email->env->message_id + msg_id_offset);
3083
3084 size_t len = buf_len(buf);
3085 ASSERT(len > 0);
3086 if (buf->data[len - 1] == '>')
3087 buf->data[len - 1] = '\0';
3088
3089 change_folder_notmuch(priv->menu, buf->data, buf->dsize, &priv->oldcount, shared, false);
3090 buf_pool_release(&buf);
3091
3092 // If notmuch doesn't contain the message, we're left in an empty
3093 // vfolder. No messages are found, but nm_read_entire_thread assumes
3094 // a valid Message-ID and will throw a segfault.
3095 //
3096 // To prevent that, stay in the empty vfolder and print an error.
3097 if (shared->mailbox->msg_count == 0)
3098 {
3099 mutt_error(_("failed to find message in notmuch database. try running 'notmuch new'."));
3100 return FR_ERROR;
3101 }
3102 }
3103 priv->oldcount = shared->mailbox->msg_count;
3104 int index = menu_get_index(priv->menu);
3105 struct Email *e_oldcur = mutt_get_virt_email(shared->mailbox, index);
3106 if (!e_oldcur)
3107 return FR_ERROR;
3108
3109 if (nm_read_entire_thread(shared->mailbox, e_oldcur) < 0)
3110 {
3111 mutt_message(_("Failed to read thread, aborting"));
3112 return FR_ERROR;
3113 }
3114
3115 // nm_read_entire_thread() may modify msg_count and menu won't be updated.
3116 priv->menu->max = shared->mailbox->msg_count;
3117
3118 if (priv->oldcount < shared->mailbox->msg_count)
3119 {
3120 /* nm_read_entire_thread() triggers mutt_sort_headers() if necessary */
3121 index = e_oldcur->vnum;
3122 if (e_oldcur->collapsed || shared->mailbox_view->collapsed)
3123 {
3124 index = mutt_uncollapse_thread(e_oldcur);
3125 mutt_set_vnum(shared->mailbox);
3126 }
3127 menu_set_index(priv->menu, index);
3129 }
3130
3131 return FR_SUCCESS;
3132}
3133
3142 struct IndexPrivateData *priv,
3143 const struct KeyEvent *event)
3144{
3145 int rc = FR_SUCCESS;
3146 struct Buffer *buf = buf_pool_get();
3147
3148 if ((mw_get_field("Query: ", buf, MUTT_COMP_NO_FLAGS, HC_OTHER,
3149 &CompleteNmQueryOps, NULL) != 0) ||
3150 buf_is_empty(buf))
3151 {
3152 mutt_message(_("No query, aborting"));
3153 rc = FR_NO_ACTION;
3154 goto done;
3155 }
3156
3157 // Keep copy of user's query to name the mailbox
3158 char *query_unencoded = buf_strdup(buf);
3159
3160 buf_alloc(buf, PATH_MAX);
3161 const int op = event->op;
3162 struct Mailbox *m_query = change_folder_notmuch(priv->menu, buf->data, buf->dsize,
3163 &priv->oldcount, shared,
3164 (op == OP_MAIN_VFOLDER_FROM_QUERY_READONLY));
3165 if (m_query)
3166 {
3167 FREE(&m_query->name);
3168 m_query->name = query_unencoded;
3169 query_unencoded = NULL;
3170 rc = FR_SUCCESS;
3171 }
3172 else
3173 {
3174 FREE(&query_unencoded);
3175 }
3176
3177done:
3178 buf_pool_release(&buf);
3179 return rc;
3180}
3181
3191 struct IndexPrivateData *priv,
3192 const struct KeyEvent *event)
3193{
3194 // Common guard clauses.
3196 {
3197 mutt_message(_("Windowed queries disabled"));
3198 return FR_ERROR;
3199 }
3200 const char *const c_nm_query_window_current_search = cs_subset_string(shared->sub, "nm_query_window_current_search");
3201 if (!c_nm_query_window_current_search)
3202 {
3203 mutt_message(_("No notmuch vfolder currently loaded"));
3204 return FR_ERROR;
3205 }
3206
3207 // Call the specific operation.
3208 switch (event->op)
3209 {
3210 case OP_MAIN_WINDOWED_VFOLDER_BACKWARD:
3212 break;
3213 case OP_MAIN_WINDOWED_VFOLDER_FORWARD:
3215 break;
3216 case OP_MAIN_WINDOWED_VFOLDER_RESET:
3218 break;
3219 }
3220
3221 // Common query window folder change.
3222 char buf[PATH_MAX] = { 0 };
3223 mutt_str_copy(buf, c_nm_query_window_current_search, sizeof(buf));
3224 change_folder_notmuch(priv->menu, buf, sizeof(buf), &priv->oldcount, shared, false);
3225
3226 return FR_SUCCESS;
3227}
3228#endif
3229
3233static int op_main_fetch_mail(struct IndexSharedData *shared,
3234 struct IndexPrivateData *priv, const struct KeyEvent *event)
3235{
3238 return FR_SUCCESS;
3239}
3240
3241// -----------------------------------------------------------------------------
3242
3250static bool prereq(struct IndexSharedData *shared, struct Menu *menu, CheckFlags checks)
3251{
3252 bool result = true;
3253 struct MailboxView *mv = shared->mailbox_view;
3254
3255 if (checks & (CHECK_MSGCOUNT | CHECK_VISIBLE | CHECK_READONLY))
3256 checks |= CHECK_IN_MAILBOX;
3257
3258 if ((checks & CHECK_IN_MAILBOX) && (!mv || !mv->mailbox))
3259 {
3260 mutt_error(_("No mailbox is open"));
3261 result = false;
3262 }
3263
3264 if (result && (checks & CHECK_MSGCOUNT) && (mv->mailbox->msg_count == 0))
3265 {
3266 mutt_error(_("There are no messages"));
3267 result = false;
3268 }
3269
3270 int index = menu_get_index(menu);
3271 if (result && (checks & CHECK_VISIBLE) &&
3272 ((index < 0) || (index >= mv->mailbox->vcount)))
3273 {
3274 mutt_error(_("No visible messages"));
3275 result = false;
3276 }
3277
3278 if (result && (checks & CHECK_READONLY) && mv->mailbox->readonly)
3279 {
3280 mutt_error(_("Mailbox is read-only"));
3281 result = false;
3282 }
3283
3284 if (result && (checks & CHECK_ATTACH) && shared->attach_msg)
3285 {
3286 mutt_error(_("Function not permitted in attach-message mode"));
3287 result = false;
3288 }
3289
3290 if (!result)
3291 mutt_flushinp();
3292
3293 return result;
3294}
3295
3299static const struct IndexFunction IndexFunctions[] = {
3300 // clang-format off
3301 { OP_ALIAS_DIALOG, op_alias_dialog, CHECK_NO_FLAGS },
3307 { OP_COPY_MESSAGE, op_save, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3308 { OP_CREATE_ALIAS, op_create_alias, CHECK_NO_FLAGS },
3309 { OP_DECODE_COPY, op_save, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3310 { OP_DECODE_SAVE, op_save, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3311 { OP_DECRYPT_COPY, op_save, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3312 { OP_DECRYPT_SAVE, op_save, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3320 { OP_EDIT_OR_VIEW_RAW_MESSAGE, op_edit_raw_message, CHECK_ATTACH | CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3322 { OP_END_COND, op_end_cond, CHECK_NO_FLAGS },
3323 { OP_EXIT, op_exit, CHECK_NO_FLAGS },
3327 { OP_FORGET_PASSPHRASE, op_forget_passphrase, CHECK_NO_FLAGS },
3329 { OP_FORWARD_TO_GROUP, op_post, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3333 { OP_GENERIC_SELECT_ENTRY, op_display_message, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3336 { OP_JUMP, op_jump, CHECK_IN_MAILBOX },
3337 { OP_JUMP_1, op_jump, CHECK_IN_MAILBOX },
3338 { OP_JUMP_2, op_jump, CHECK_IN_MAILBOX },
3339 { OP_JUMP_3, op_jump, CHECK_IN_MAILBOX },
3340 { OP_JUMP_4, op_jump, CHECK_IN_MAILBOX },
3341 { OP_JUMP_5, op_jump, CHECK_IN_MAILBOX },
3342 { OP_JUMP_6, op_jump, CHECK_IN_MAILBOX },
3343 { OP_JUMP_7, op_jump, CHECK_IN_MAILBOX },
3344 { OP_JUMP_8, op_jump, CHECK_IN_MAILBOX },
3345 { OP_JUMP_9, op_jump, CHECK_IN_MAILBOX },
3346 { OP_LIMIT_CURRENT_THREAD, op_main_limit, CHECK_IN_MAILBOX },
3350 { OP_MAIL, op_mail, CHECK_ATTACH },
3351 { OP_MAILBOX_LIST, op_mailbox_list, CHECK_NO_FLAGS },
3352 { OP_MAIL_KEY, op_mail_key, CHECK_ATTACH },
3354 { OP_MAIN_CHANGE_FOLDER, op_main_change_folder, CHECK_NO_FLAGS },
3355 { OP_MAIN_CHANGE_FOLDER_READONLY, op_main_change_folder, CHECK_NO_FLAGS },
3356 { OP_MAIN_CHANGE_GROUP, op_main_change_group, CHECK_NO_FLAGS },
3357 { OP_MAIN_CHANGE_GROUP_READONLY, op_main_change_group, CHECK_NO_FLAGS },
3359 { OP_MAIN_CLOSE_ALL_THREADS, op_main_close_all_threads, CHECK_IN_MAILBOX },
3361 { OP_MAIN_COLLAPSE_ALL, op_main_collapse_all, CHECK_IN_MAILBOX },
3362 { OP_MAIN_COLLAPSE_THREAD, op_main_collapse_thread, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3363 { OP_MAIN_DELETE_PATTERN, op_main_delete_pattern, CHECK_ATTACH | CHECK_IN_MAILBOX | CHECK_READONLY },
3364 { OP_MAIN_FETCH_MAIL, op_main_fetch_mail, CHECK_ATTACH },
3365 { OP_MAIN_IMAP_FETCH, op_main_imap_fetch, CHECK_NO_FLAGS },
3366 { OP_MAIN_IMAP_LOGOUT_ALL, op_main_imap_logout_all, CHECK_NO_FLAGS },
3367 { OP_MAIN_LIMIT, op_main_limit, CHECK_IN_MAILBOX },
3370 { OP_MAIN_MODIFY_TAGS_THEN_HIDE, op_main_modify_tags, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_READONLY | CHECK_VISIBLE },
3372 { OP_MAIN_NEXT_NEW_THEN_UNREAD, op_main_next_new, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3373 { OP_MAIN_NEXT_SUBTHREAD, op_main_next_thread, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3376 { OP_MAIN_NEXT_UNREAD, op_main_next_new, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3377 { OP_MAIN_NEXT_UNREAD_MAILBOX, op_main_next_unread_mailbox, CHECK_IN_MAILBOX },
3378 { OP_MAIN_OPEN_ALL_THREADS, op_main_open_all_threads, CHECK_IN_MAILBOX },
3380 { OP_MAIN_PARENT_MESSAGE, op_main_root_message, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3382 { OP_MAIN_PREV_NEW_THEN_UNREAD, op_main_next_new, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3383 { OP_MAIN_PREV_SUBTHREAD, op_main_next_thread, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3386 { OP_MAIN_PREV_UNREAD, op_main_next_new, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3392 { OP_MAIN_SHOW_LIMIT, op_main_show_limit, CHECK_IN_MAILBOX },
3393 { OP_MAIN_SYNC_FOLDER, op_main_sync_folder, CHECK_NO_FLAGS },
3394 { OP_MAIN_TAG_PATTERN, op_main_tag_pattern, CHECK_IN_MAILBOX },
3395 { OP_MAIN_UNDELETE_PATTERN, op_main_undelete_pattern, CHECK_IN_MAILBOX | CHECK_READONLY },
3396 { OP_MAIN_UNTAG_PATTERN, op_main_untag_pattern, CHECK_IN_MAILBOX },
3400 { OP_POST, op_post, CHECK_ATTACH | CHECK_IN_MAILBOX },
3405 { OP_QUERY, op_query, CHECK_ATTACH },
3406 { OP_QUIT, op_quit, CHECK_NO_FLAGS },
3407 { OP_RECALL_MESSAGE, op_recall_message, CHECK_ATTACH },
3412 { OP_SEARCH, op_search, CHECK_IN_MAILBOX },
3413 { OP_SEARCH_NEXT, op_search, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3414 { OP_SEARCH_OPPOSITE, op_search, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3415 { OP_SEARCH_REVERSE, op_search, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3416 { OP_SORT, op_sort, CHECK_NO_FLAGS },
3417 { OP_SORT_REVERSE, op_sort, CHECK_NO_FLAGS },
3422 { OP_TOGGLE_READ, op_main_limit, CHECK_IN_MAILBOX },
3423 { OP_TOGGLE_WRITE, op_toggle_write, CHECK_IN_MAILBOX },
3429#ifdef USE_AUTOCRYPT
3430 { OP_AUTOCRYPT_ACCT_MENU, op_autocrypt_acct_menu, CHECK_NO_FLAGS },
3431#endif
3432#ifdef USE_NOTMUCH
3433 { OP_MAIN_CHANGE_VFOLDER, op_main_change_folder, CHECK_NO_FLAGS },
3435 { OP_MAIN_VFOLDER_FROM_QUERY, op_main_vfolder_from_query, CHECK_NO_FLAGS },
3436 { OP_MAIN_VFOLDER_FROM_QUERY_READONLY, op_main_vfolder_from_query, CHECK_NO_FLAGS },
3437 { OP_MAIN_WINDOWED_VFOLDER_BACKWARD, op_main_windowed_vfolder, CHECK_IN_MAILBOX },
3438 { OP_MAIN_WINDOWED_VFOLDER_FORWARD, op_main_windowed_vfolder, CHECK_IN_MAILBOX },
3439 { OP_MAIN_WINDOWED_VFOLDER_RESET, op_main_windowed_vfolder, CHECK_IN_MAILBOX },
3440#endif
3441 { 0, NULL, CHECK_NO_FLAGS },
3442 // clang-format on
3443};
3444
3448int index_function_dispatcher(struct MuttWindow *win, const struct KeyEvent *event)
3449{
3450 // The Dispatcher may be called on any Window in the Dialog
3451 struct MuttWindow *dlg = dialog_find(win);
3452 if (!event || !dlg || !dlg->wdata || !win->parent || !win->parent->wdata)
3453 return FR_ERROR;
3454
3455 const int op = event->op;
3456 struct IndexPrivateData *priv = win->parent->wdata;
3457 struct IndexSharedData *shared = dlg->wdata;
3458
3459 int rc = FR_UNKNOWN;
3460 for (size_t i = 0; IndexFunctions[i].op != OP_NULL; i++)
3461 {
3462 const struct IndexFunction *fn = &IndexFunctions[i];
3463 if (fn->op == op)
3464 {
3465 if (!prereq(shared, priv->menu, fn->flags))
3466 {
3467 rc = FR_ERROR;
3468 break;
3469 }
3470 rc = fn->function(shared, priv, event);
3471 break;
3472 }
3473 }
3474
3475 if (rc == FR_UNKNOWN) // Not our function
3476 return rc;
3477
3478 const char *result = dispatcher_get_retval_name(rc);
3479 mutt_debug(LL_DEBUG1, "Handled %s (%d) -> %s\n", opcodes_get_name(op), op, NONULL(result));
3480
3481 return rc;
3482}
Email Aliases.
void alias_create(struct AddressList *al, const struct ConfigSubset *sub)
Create a new Alias from an Address.
Definition alias.c:368
struct AddressList * mutt_get_address(struct Envelope *env, const char **prefix)
Get an Address from an Envelope.
Definition alias.c:328
#define ARRAY_FREE(head)
Release all memory.
Definition array.h:209
#define ARRAY_HEAD_INITIALIZER
Static initializer for arrays.
Definition array.h:58
GUI display the mailboxes in a side panel.
Autocrypt end-to-end encryption.
int bool_str_toggle(struct ConfigSubset *sub, const char *name, struct Buffer *err)
Toggle the value of a bool.
Definition bool.c:231
Select a Mailbox from a list.
#define MUTT_SEL_NO_FLAGS
No flags are set.
Definition lib.h:58
int buf_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition buffer.c:161
size_t buf_len(const struct Buffer *buf)
Calculate the length of a Buffer.
Definition buffer.c:491
bool buf_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition buffer.c:291
size_t buf_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition buffer.c:226
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition buffer.c:395
char * buf_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition buffer.c:571
void buf_alloc(struct Buffer *buf, size_t new_size)
Make sure a buffer can store at least new_size bytes.
Definition buffer.c:337
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition buffer.h:96
@ CMD_SHUTDOWN_HOOK
:shutdown-hook
Definition command.h:110
@ CMD_MESSAGE_HOOK
:message-hook
Definition command.h:94
void mutt_pattern_free(struct PatternList **pat)
Free a Pattern.
Definition compile.c:826
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition helpers.c:291
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.
void mailbox_free(struct Mailbox **ptr)
Free a Mailbox.
Definition mailbox.c:90
@ NT_MAILBOX_CHANGE
Mailbox has been changed.
Definition mailbox.h:175
#define MUTT_ACL_INSERT
Add/copy into the mailbox (used when editing a message)
Definition mailbox.h:65
#define MUTT_ACL_DELETE
Delete a message.
Definition mailbox.h:62
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox's path string.
Definition mailbox.h:213
#define MUTT_ACL_WRITE
Write to a message (for flagging or linking threads)
Definition mailbox.h:70
@ MUTT_NOTMUCH
'Notmuch' (virtual) Mailbox type
Definition mailbox.h:50
@ MUTT_MH
'MH' Mailbox type
Definition mailbox.h:46
@ MUTT_NNTP
'NNTP' (Usenet) Mailbox type
Definition mailbox.h:48
@ MUTT_IMAP
'IMAP' Mailbox type
Definition mailbox.h:49
@ MUTT_MAILDIR
'Maildir' Mailbox type
Definition mailbox.h:47
#define MUTT_ACL_SEEN
Change the 'seen' status of a message.
Definition mailbox.h:69
void crypt_extract_keys_from_messages(struct Mailbox *m, struct EmailArray *ea)
Extract keys from a message.
Definition crypt.c:858
void crypt_forget_passphrase(void)
Forget a passphrase and display a message.
Definition crypt.c:89
int digit(const char *s)
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
FunctionRetval
Possible return values for NeoMutt functions.
Definition dispatcher.h:33
@ FR_SUCCESS
Valid function - successfully performed.
Definition dispatcher.h:40
@ FR_DONE
Exit the Dialog.
Definition dispatcher.h:36
@ FR_UNKNOWN
Unknown function.
Definition dispatcher.h:34
@ FR_ERROR
Valid function - error occurred.
Definition dispatcher.h:39
@ FR_NOT_IMPL
Invalid function - feature not enabled.
Definition dispatcher.h:37
@ FR_NO_ACTION
Valid function - no action performed.
Definition dispatcher.h:38
void alias_dialog(struct Mailbox *m, struct ConfigSubset *sub)
Open the aliases dialog.
Definition dlg_alias.c:493
void mutt_browser_select_dir(const char *f)
Remember the last directory selected.
bool check_acl(struct Mailbox *m, AclFlags acl, const char *msg)
Check the ACLs for a function.
Definition dlg_index.c:135
const struct Mapping IndexNewsHelp[]
Help Bar for the News Index dialog.
Definition dlg_index.c:114
void change_folder_mailbox(struct Menu *menu, struct Mailbox *m, int *oldcount, struct IndexSharedData *shared, bool read_only)
Change to a different Mailbox by pointer.
Definition dlg_index.c:629
struct Mailbox * change_folder_notmuch(struct Menu *menu, char *buf, int buflen, int *oldcount, struct IndexSharedData *shared, bool read_only)
Change to a different Notmuch Mailbox by string.
Definition dlg_index.c:750
void update_index(struct Menu *menu, struct MailboxView *mv, enum MxStatus check, int oldcount, const struct IndexSharedData *shared)
Update the index.
Definition dlg_index.c:560
int find_first_message(struct MailboxView *mv)
Get index of first new message.
Definition dlg_index.c:325
void resort_index(struct MailboxView *mv, struct Menu *menu)
Resort the index.
Definition dlg_index.c:385
int find_next_undeleted(struct MailboxView *mv, int msgno, bool uncollapse)
Find the next undeleted email.
Definition dlg_index.c:257
void change_folder_string(struct Menu *menu, struct Buffer *buf, int *oldcount, struct IndexSharedData *shared, bool read_only)
Change to a different Mailbox by string.
Definition dlg_index.c:775
int find_previous_undeleted(struct MailboxView *mv, int msgno, bool uncollapse)
Find the previous undeleted email.
Definition dlg_index.c:291
void collapse_all(struct MailboxView *mv, struct Menu *menu, enum CollapseMode mode)
Collapse/uncollapse all threads.
Definition dlg_index.c:159
void query_index(struct Mailbox *m, struct ConfigSubset *sub)
Perform an Alias Query and display the results.
Definition dlg_query.c:483
int mutt_ev_message(struct Mailbox *m, struct EmailArray *ea, enum EvMessage action)
Edit or view a message.
Definition editmsg.c:282
Edit a string.
#define MUTT_COMP_NO_FLAGS
No flags are set.
Definition wdata.h:42
int mutt_label_message(struct MailboxView *mv, struct EmailArray *ea)
Let the user label a message.
Definition header.c:130
Structs that make up an email.
void mutt_sort_headers(struct MailboxView *mv, bool init)
Sort emails by their headers.
Definition sort.c:354
bool OptNeedResort
(pseudo) used to force a re-sort
Definition globals.c:52
void mutt_break_thread(struct Email *e)
Break the email Thread.
Definition thread.c:229
void mutt_print_message(struct Mailbox *m, struct EmailArray *ea)
Print a message.
Definition external.c:435
bool mutt_select_sort(bool reverse)
Ask the user for a sort method.
Definition external.c:473
void mutt_pipe_message(struct Mailbox *m, struct EmailArray *ea)
Pipe a message.
Definition external.c:404
bool mutt_check_traditional_pgp(struct Mailbox *m, struct EmailArray *ea)
Check if a message has inline PGP content.
Definition external.c:1213
void index_bounce_message(struct Mailbox *m, struct EmailArray *ea)
Bounce an email.
Definition external.c:87
int mutt_save_message(struct Mailbox *m, struct EmailArray *ea, enum MessageSaveOpt save_opt, enum MessageTransformOpt transform_opt)
Save an email.
Definition external.c:780
bool mutt_edit_content_type(struct Email *e, struct Body *b, FILE *fp)
Edit the content type of an attachment.
Definition external.c:1072
void mutt_display_address(struct Envelope *env)
Display the address of a message.
Definition external.c:663
Manage where the email is piped to external commands.
MessageTransformOpt
Message transformation option.
Definition external.h:42
@ TRANSFORM_NONE
No transformation.
Definition external.h:43
@ TRANSFORM_DECODE
Decode message.
Definition external.h:45
@ TRANSFORM_DECRYPT
Decrypt message.
Definition external.h:44
MessageSaveOpt
Message save option.
Definition external.h:52
@ SAVE_MOVE
Move message to another mailbox, removing the original.
Definition external.h:54
@ SAVE_COPY
Copy message, making a duplicate in another mailbox.
Definition external.h:53
int mutt_file_sanitize_regex(struct Buffer *dest, const char *src)
Escape any regex-magic characters in a string.
Definition file.c:624
void mutt_set_flag(struct Mailbox *m, struct Email *e, enum MessageType flag, bool bf, bool upd_mbox)
Set a flag on an email.
Definition flags.c:54
void mutt_emails_set_flag(struct Mailbox *m, struct EmailArray *ea, enum MessageType flag, bool bf)
Set flag on messages.
Definition flags.c:358
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:382
void mutt_flushinp(void)
Empty all the keyboard buffers.
Definition get.c:65
void mutt_unget_ch(int ch)
Return a keystroke to the input buffer.
Definition get.c:122
#define MFF_DEPRECATED
Redraw the pager.
Definition get.h:44
bool OptNews
(pseudo) used to change reader mode
Definition globals.c:53
Global variables.
static int op_search(struct AliasMenuData *mdata, const struct KeyEvent *event)
search for a regular expression - Implements alias_function_t -
Definition functions.c:386
static int op_main_untag_pattern(struct AliasMenuData *mdata, const struct KeyEvent *event)
Untag messages matching a pattern - Implements alias_function_t -.
Definition functions.c:313
static int op_sort(struct AliasMenuData *mdata, const struct KeyEvent *event)
sort aliases - Implements alias_function_t -
Definition functions.c:423
static int op_create_alias(struct AliasMenuData *mdata, const struct KeyEvent *event)
create an alias from a message sender - Implements alias_function_t -
Definition functions.c:153
static int op_main_limit(struct AliasMenuData *mdata, const struct KeyEvent *event)
show only messages matching a pattern - Implements alias_function_t -
Definition functions.c:278
static int op_exit(struct AliasMenuData *mdata, const struct KeyEvent *event)
exit this menu - Implements alias_function_t -
Definition functions.c:234
static int op_query(struct AliasMenuData *mdata, const struct KeyEvent *event)
query external program for addresses - Implements alias_function_t -
Definition functions.c:333
static int op_delete(struct AliasMenuData *mdata, const struct KeyEvent *event)
delete the current entry - Implements alias_function_t -
Definition functions.c:197
static int op_main_tag_pattern(struct AliasMenuData *mdata, const struct KeyEvent *event)
Tag messages matching a pattern - Implements alias_function_t -.
Definition functions.c:297
static int op_forward_message(struct AttachPrivateData *priv, const struct KeyEvent *event)
forward a message with comments - Implements attach_function_t -
Definition functions.c:578
static int op_reply(struct AttachPrivateData *priv, const struct KeyEvent *event)
reply to a message - Implements attach_function_t -
Definition functions.c:612
static int op_forget_passphrase(struct AttachPrivateData *priv, const struct KeyEvent *event)
wipe passphrases from memory - Implements attach_function_t -
Definition functions.c:569
static int op_compose_to_sender(struct AttachPrivateData *priv, const struct KeyEvent *event)
compose new message to the current message sender - Implements attach_function_t -
Definition functions.c:521
static int op_list_subscribe(struct AttachPrivateData *priv, const struct KeyEvent *event)
subscribe to a mailing list - Implements attach_function_t -
Definition functions.c:592
static int op_check_traditional(struct AttachPrivateData *priv, const struct KeyEvent *event)
check for classic PGP - Implements attach_function_t -
Definition functions.c:507
static int op_list_unsubscribe(struct AttachPrivateData *priv, const struct KeyEvent *event)
unsubscribe from a mailing list - Implements attach_function_t -
Definition functions.c:602
static int op_extract_keys(struct AttachPrivateData *priv, const struct KeyEvent *event)
extract supported public keys - Implements attach_function_t -
Definition functions.c:555
static int op_resend(struct AttachPrivateData *priv, const struct KeyEvent *event)
use the current message as a template for a new one - Implements attach_function_t -
Definition functions.c:636
static int op_bounce_message(struct AttachPrivateData *priv, const struct KeyEvent *event)
remail a message to another user - Implements attach_function_t -
Definition functions.c:493
static int op_attach_edit_type(struct AttachPrivateData *priv, const struct KeyEvent *event)
edit attachment content type - Implements attach_function_t -
Definition functions.c:359
static int op_mailbox_list(struct BrowserPrivateData *priv, const struct KeyEvent *event)
List mailboxes with new mail - Implements browser_function_t -.
Definition functions.c:857
static int op_catchup(struct BrowserPrivateData *priv, const struct KeyEvent *event)
Mark all articles in newsgroup as read - Implements browser_function_t -.
Definition functions.c:318
int index_function_dispatcher(struct MuttWindow *win, const struct KeyEvent *event)
Perform an Index function - Implements function_dispatcher_t -.
Definition functions.c:3448
void dlg_attach(struct ConfigSubset *sub, struct MailboxView *mv, struct Email *e, FILE *fp, bool attach_msg)
Show the attachments in a Menu -.
Definition dlg_attach.c:207
void dlg_autocrypt(void)
Display the Autocrypt account Menu -.
int mw_change_flag(struct Mailbox *m, struct EmailArray *ea, bool bf)
Change the flag on a Message -.
Definition flags.c:451
int mw_enter_fname(const char *prompt, struct Buffer *fname, bool mailbox, struct Mailbox *m, bool multiple, char ***files, int *numfiles, SelectFileFlags flags)
Ask the user to select a file -.
Definition curs_lib.c:236
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:463
static int op_quit(struct HistoryData *hd, const struct KeyEvent *event)
Quit this menu - Implements history_function_t -.
Definition functions.c:57
static int op_main_next_undeleted(struct IndexSharedData *shared, struct IndexPrivateData *priv, const struct KeyEvent *event)
Move to the next undeleted message - Implements index_function_t -.
Definition functions.c:1770
static int op_view_attachments(struct IndexSharedData *shared, struct IndexPrivateData *priv, const struct KeyEvent *event)
Show MIME attachments - Implements index_function_t -.
Definition functions.c:2651
static int op_main_link_threads(struct IndexSharedData *shared, struct IndexPrivateData *priv, const struct KeyEvent *event)
Link tagged message to the current one - Implements index_function_t -.
Definition functions.c:1418
static int op_main_set_flag(struct IndexSharedData *shared, struct IndexPrivateData *priv, const struct KeyEvent *event)
Set a status flag on a message - Implements index_function_t -.
Definition functions.c:1944
static int op_pipe(struct IndexSharedData *shared, struct IndexPrivateData *priv, const struct KeyEvent *event)
Pipe message/attachment to a shell command - Implements index_function_t -.
Definition functions.c:2194
static int op_undelete(struct IndexSharedData *shared, struct IndexPrivateData *priv, const struct KeyEvent *event)
Undelete the current entry - Implements index_function_t -.
Definition functions.c:2586
static int op_print(struct IndexSharedData *shared, struct IndexPrivateData *priv, const struct KeyEvent *event)
Print the current entry - Implements index_function_t -.
Definition functions.c:2233
static int op_display_address(struct IndexSharedData *shared, struct IndexPrivateData *priv, const struct KeyEvent *event)
Display full address of sender - Implements index_function_t -.
Definition functions.c:598
static int op_alias_dialog(struct IndexSharedData *shared, struct IndexPrivateData *priv, const struct KeyEvent *event)
Open the aliases dialog - Implements index_function_t -.
Definition functions.c:429
static int op_main_vfolder_from_query(struct IndexSharedData *shared, struct IndexPrivateData *priv, const struct KeyEvent *event)
Generate virtual folder from query - Implements index_function_t -.
Definition functions.c:3141
static int op_toggle_write(struct IndexSharedData *shared, struct IndexPrivateData *priv, const struct KeyEvent *event)
Toggle whether the mailbox will be rewritten - Implements index_function_t -.
Definition functions.c:2576
static int op_main_break_thread(struct IndexSharedData *shared, struct IndexPrivateData *priv, const struct KeyEvent *event)
Break the thread in two - Implements index_function_t -.
Definition functions.c:1053
static int op_main_open_thread(struct IndexSharedData *shared, struct IndexPrivateData *priv, const struct KeyEvent *event)
Open current thread - Implements index_function_t -.
Definition functions.c:1297
static int op_toggle_new(struct IndexSharedData *shared, struct IndexPrivateData *priv, const struct KeyEvent *event)
Toggle a message's 'new' flag - Implements index_function_t -.
Definition functions.c:2533
static int op_list_reply(struct IndexSharedData *shared, struct IndexPrivateData *priv, const struct KeyEvent *event)
Reply to specified mailing list - Implements index_function_t -.
Definition functions.c:974
static int op_autocrypt_acct_menu(struct IndexSharedData *shared, struct IndexPrivateData *priv, const struct KeyEvent *event)
Manage autocrypt accounts - Implements index_function_t -.
Definition functions.c:2680
static int op_main_delete_pattern(struct IndexSharedData *shared, struct IndexPrivateData *priv, const struct KeyEvent *event)
Delete messages matching a pattern - Implements index_function_t -.
Definition functions.c:1324
static int op_tag_thread(struct IndexSharedData *shared, struct IndexPrivateData *priv, const struct KeyEvent *event)
Tag the current thread - Implements index_function_t -.
Definition functions.c:2510
static int op_main_change_group(struct IndexSharedData *shared, struct IndexPrivateData *priv, const struct KeyEvent *event)
Open a different newsgroup - Implements index_function_t -.
Definition functions.c:2942
static int op_main_sync_folder(struct IndexSharedData *shared, struct IndexPrivateData *priv, const struct KeyEvent *event)
Save changes to mailbox - Implements index_function_t -.
Definition functions.c:1991
static int op_main_imap_fetch(struct IndexSharedData *shared, struct IndexPrivateData *priv, const struct KeyEvent *event)
Force retrieval of mail from IMAP server - Implements index_function_t -.
Definition functions.c:2691
static int op_main_root_message(struct IndexSharedData *shared, struct IndexPrivateData *priv, const struct KeyEvent *event)
Jump to root message in thread - Implements index_function_t -.
Definition functions.c:1927
static int op_main_close_thread(struct IndexSharedData *shared, struct IndexPrivateData *priv, const struct KeyEvent *event)
Collapse current thread - Implements index_function_t -.
Definition functions.c:1205
static int op_main_fetch_mail(struct IndexSharedData *shared, struct IndexPrivateData *priv, const struct KeyEvent *event)
Retrieve mail from POP server - Implements index_function_t -.
Definition functions.c:3233
static int op_main_close_all_threads(struct IndexSharedData *shared, struct IndexPrivateData *priv, const struct KeyEvent *event)
Collapse all threads - Implements index_function_t -.
Definition functions.c:1183
static int op_main_imap_logout_all(struct IndexSharedData *shared, struct IndexPrivateData *priv, const struct KeyEvent *event)
Logout from all IMAP servers - Implements index_function_t -.
Definition functions.c:2704
static int op_flag_message(struct IndexSharedData *shared, struct IndexPrivateData *priv, const struct KeyEvent *event)
Toggle a message's 'important' flag - Implements index_function_t -.
Definition functions.c:817
static int op_prev_entry(struct IndexSharedData *shared, struct IndexPrivateData *priv, const struct KeyEvent *event)
Move to the previous entry - Implements index_function_t -.
Definition functions.c:2216
static int op_main_next_new(struct IndexSharedData *shared, struct IndexPrivateData *priv, const struct KeyEvent *event)
Jump to the next new message - Implements index_function_t -.
Definition functions.c:1598
static int op_main_change_folder(struct IndexSharedData *shared, struct IndexPrivateData *priv, const struct KeyEvent *event)
Open a different folder - Implements index_function_t -.
Definition functions.c:1101
static int op_edit_label(struct IndexSharedData *shared, struct IndexPrivateData *priv, const struct KeyEvent *event)
Add, change, or delete a message's label - Implements index_function_t -.
Definition functions.c:687
static int op_delete_thread(struct IndexSharedData *shared, struct IndexPrivateData *priv, const struct KeyEvent *event)
Delete all messages in thread - Implements index_function_t -.
Definition functions.c:562
static int op_main_show_limit(struct IndexSharedData *shared, struct IndexPrivateData *priv, const struct KeyEvent *event)
Show currently active limit pattern - Implements index_function_t -.
Definition functions.c:1969
static int op_get_children(struct IndexSharedData *shared, struct IndexPrivateData *priv, const struct KeyEvent *event)
Get all children of the current message - Implements index_function_t -.
Definition functions.c:2758
static int op_main_next_thread(struct IndexSharedData *shared, struct IndexPrivateData *priv, const struct KeyEvent *event)
Jump to the next thread - Implements index_function_t -.
Definition functions.c:1727
static int op_main_collapse_all(struct IndexSharedData *shared, struct IndexPrivateData *priv, const struct KeyEvent *event)
Collapse/uncollapse all threads - Implements index_function_t -.
Definition functions.c:1166
static int op_edit_raw_message(struct IndexSharedData *shared, struct IndexPrivateData *priv, const struct KeyEvent *event)
Edit the raw message (edit and edit-raw-message are synonyms) - Implements index_function_t -.
Definition functions.c:723
static int op_group_reply(struct IndexSharedData *shared, struct IndexPrivateData *priv, const struct KeyEvent *event)
Reply to all recipients - Implements index_function_t -.
Definition functions.c:892
static int op_main_undelete_pattern(struct IndexSharedData *shared, struct IndexPrivateData *priv, const struct KeyEvent *event)
Undelete messages matching a pattern - Implements index_function_t -.
Definition functions.c:2086
static int op_get_message(struct IndexSharedData *shared, struct IndexPrivateData *priv, const struct KeyEvent *event)
Get parent of the current message - Implements index_function_t -.
Definition functions.c:2860
static int op_mark_msg(struct IndexSharedData *shared, struct IndexPrivateData *priv, const struct KeyEvent *event)
Create a hotkey macro for the current message - Implements index_function_t -.
Definition functions.c:2121
static int op_main_quasi_delete(struct IndexSharedData *shared, struct IndexPrivateData *priv, const struct KeyEvent *event)
Delete from NeoMutt, don't touch on disk - Implements index_function_t -.
Definition functions.c:1860
static int op_display_message(struct IndexSharedData *shared, struct IndexPrivateData *priv, const struct KeyEvent *event)
Display a message - Implements index_function_t -.
Definition functions.c:615
static int op_main_windowed_vfolder(struct IndexSharedData *shared, struct IndexPrivateData *priv, const struct KeyEvent *event)
Shifts virtual folder time window - Implements index_function_t -.
Definition functions.c:3190
static int op_save(struct IndexSharedData *shared, struct IndexPrivateData *priv, const struct KeyEvent *event)
Make decrypted copy - Implements index_function_t -.
Definition functions.c:2375
static int op_post(struct IndexSharedData *shared, struct IndexPrivateData *priv, const struct KeyEvent *event)
Followup to newsgroup - Implements index_function_t -.
Definition functions.c:3019
static int op_main_open_all_threads(struct IndexSharedData *shared, struct IndexPrivateData *priv, const struct KeyEvent *event)
Open all threads - Implements index_function_t -.
Definition functions.c:1275
static int op_main_entire_thread(struct IndexSharedData *shared, struct IndexPrivateData *priv, const struct KeyEvent *event)
Read entire thread of the current message - Implements index_function_t -.
Definition functions.c:3062
static int op_jump(struct IndexSharedData *shared, struct IndexPrivateData *priv, const struct KeyEvent *event)
Jump to an index number - Implements index_function_t -.
Definition functions.c:922
static int op_mail(struct IndexSharedData *shared, struct IndexPrivateData *priv, const struct KeyEvent *event)
Compose a new mail message - Implements index_function_t -.
Definition functions.c:1017
static int op_main_collapse_thread(struct IndexSharedData *shared, struct IndexPrivateData *priv, const struct KeyEvent *event)
Collapse/uncollapse current thread - Implements index_function_t -.
Definition functions.c:1233
static int op_main_modify_tags(struct IndexSharedData *shared, struct IndexPrivateData *priv, const struct KeyEvent *event)
Modify (notmuch/imap) tags - Implements index_function_t -.
Definition functions.c:1476
static int op_main_prev_undeleted(struct IndexSharedData *shared, struct IndexPrivateData *priv, const struct KeyEvent *event)
Move to the previous undeleted message - Implements index_function_t -.
Definition functions.c:1827
static int op_main_next_unread_mailbox(struct IndexSharedData *shared, struct IndexPrivateData *priv, const struct KeyEvent *event)
Open next mailbox with unread mail - Implements index_function_t -.
Definition functions.c:1803
static int op_mail_key(struct IndexSharedData *shared, struct IndexPrivateData *priv, const struct KeyEvent *event)
Mail a PGP public key - Implements index_function_t -.
Definition functions.c:1039
static int op_end_cond(struct IndexSharedData *shared, struct IndexPrivateData *priv, const struct KeyEvent *event)
End of conditional execution (noop) - Implements index_function_t -.
Definition functions.c:769
static int op_main_read_thread(struct IndexSharedData *shared, struct IndexPrivateData *priv, const struct KeyEvent *event)
Mark the current thread as read - Implements index_function_t -.
Definition functions.c:1896
static int op_next_entry(struct IndexSharedData *shared, struct IndexPrivateData *priv, const struct KeyEvent *event)
Move to the next entry - Implements index_function_t -.
Definition functions.c:2177
static int op_tag(struct IndexSharedData *shared, struct IndexPrivateData *priv, const struct KeyEvent *event)
Tag the current entry - Implements index_function_t -.
Definition functions.c:2475
static int op_undelete_thread(struct IndexSharedData *shared, struct IndexPrivateData *priv, const struct KeyEvent *event)
Undelete all messages in thread - Implements index_function_t -.
Definition functions.c:2619
static int op_recall_message(struct IndexSharedData *shared, struct IndexPrivateData *priv, const struct KeyEvent *event)
Recall a postponed message - Implements index_function_t -.
Definition functions.c:2302
#define mutt_warning(...)
Definition logging2.h:92
#define mutt_error(...)
Definition logging2.h:94
#define mutt_message(...)
Definition logging2.h:93
#define mutt_debug(LEVEL,...)
Definition logging2.h:91
Convenience wrapper for the gui headers.
bool mutt_link_threads(struct Email *parent, struct EmailArray *children, struct Mailbox *m)
Forcibly link threads together.
Definition thread.c:1826
void mutt_draw_tree(struct ThreadsContext *tctx)
Draw a tree of threaded emails.
Definition thread.c:465
int mutt_messages_in_thread(struct Mailbox *m, struct Email *e, enum MessageInThread mit)
Count the messages in a thread.
Definition thread.c:1736
off_t mutt_set_vnum(struct Mailbox *m)
Set the virtual index number of all the messages in a mailbox.
Definition thread.c:1483
bool mutt_thread_can_collapse(struct Email *e)
Check whether a thread can be collapsed.
Definition thread.c:1896
int mutt_parent_message(struct Email *e, bool find_root)
Find the parent of a message.
Definition thread.c:1433
struct HashTable * mutt_make_id_hash(struct Mailbox *m)
Create a Hash Table for Message-IDs.
Definition thread.c:1781
#define mutt_thread_next_unread(e)
Definition thread.h:110
#define mutt_using_threads()
Definition thread.h:113
#define mutt_previous_thread(e)
Definition thread.h:119
#define mutt_uncollapse_thread(e)
Definition thread.h:107
@ MIT_POSITION
Our position in the thread.
Definition thread.h:89
#define mutt_next_subthread(e)
Definition thread.h:120
#define mutt_thread_contains_unread(e)
Definition thread.h:108
#define mutt_previous_subthread(e)
Definition thread.h:121
#define mutt_next_thread(e)
Definition thread.h:118
#define mutt_collapse_thread(e)
Definition thread.h:106
void * mutt_hash_find(const struct HashTable *table, const char *strkey)
Find the HashElem data in a Hash Table element using a key.
Definition hash.c:364
Read/write command history from/to a file.
@ HC_OTHER
Miscellaneous strings.
Definition lib.h:60
void exec_startup_shutdown_hook(enum CommandId id)
Execute any startup/shutdown hooks.
Definition exec.c:410
void exec_message_hook(struct Mailbox *m, struct Email *e, enum CommandId id)
Perform a message hook.
Definition exec.c:135
Hook Commands.
IMAP network mailbox.
void imap_logout_all(void)
Close all open connections.
Definition imap.c:667
enum MxStatus imap_check_mailbox(struct Mailbox *m, bool force)
Use the NOOP or IDLE command to poll for new mail.
Definition imap.c:1212
static const struct MenuFuncOp OpIndex[]
Functions for the Index Menu.
Definition functions.c:86
bool index_next_undeleted(struct MuttWindow *win_index)
Select the next undeleted Email (if possible)
Definition functions.c:398
static bool resolve_email(struct IndexPrivateData *priv, struct IndexSharedData *shared, enum ResolveMethod rm)
Pick the next Email to advance the cursor to.
Definition functions.c:349
static const struct MenuOpSeq IndexDefaultBindings[]
Key bindings for the Index Menu.
Definition functions.c:224
void index_init_keys(struct SubMenu *sm_generic)
Initialise the Index Keybindings - Implements ::init_keys_api.
Definition functions.c:326
static bool prereq(struct IndexSharedData *shared, struct Menu *menu, CheckFlags checks)
Check the pre-requisites for a function.
Definition functions.c:3250
struct MenuDefinition * MdIndex
Index Menu Definition.
Definition functions.c:80
static const struct IndexFunction IndexFunctions[]
All the NeoMutt functions that the Index supports.
Definition functions.c:3299
ResolveMethod
How to advance the cursor.
Definition functions.c:316
@ RESOLVE_NEXT_SUBTHREAD
Next sibling sub-thread.
Definition functions.c:320
@ RESOLVE_NEXT_UNDELETED
Next undeleted email.
Definition functions.c:318
@ RESOLVE_NEXT_EMAIL
Next email, whatever its state.
Definition functions.c:317
@ RESOLVE_NEXT_THREAD
Next top-level thread.
Definition functions.c:319
Index functions.
GUI manage the main index (list of emails)
uint8_t CheckFlags
Flags, e.g. CHECK_IN_MAILBOX.
Definition lib.h:78
#define CHECK_NO_FLAGS
No flags are set.
Definition lib.h:79
#define CHECK_ATTACH
Is the user in message-attach mode?
Definition lib.h:84
@ COLLAPSE_MODE_TOGGLE
Toggle collapsed state.
Definition lib.h:91
@ COLLAPSE_MODE_CLOSE
Collapse all threads.
Definition lib.h:92
@ COLLAPSE_MODE_OPEN
Open all threads.
Definition lib.h:93
#define CHECK_VISIBLE
Is the selected message visible in the index?
Definition lib.h:82
#define CHECK_IN_MAILBOX
Is there a mailbox open?
Definition lib.h:80
#define CHECK_READONLY
Is the mailbox readonly?
Definition lib.h:83
#define CHECK_MSGCOUNT
Are there any messages?
Definition lib.h:81
#define NT_INDEX_EMAIL
Email has changed.
Definition lib.h:76
Private state data for the Index.
void index_shared_data_set_email(struct IndexSharedData *shared, struct Email *e)
Set the current Email for the Index and friends.
Data shared between Index, Pager and Sidebar.
void km_menu_add_submenu(struct MenuDefinition *md, struct SubMenu *sm)
Add a SubMenu to a Menu Definition.
Definition init.c:123
struct SubMenu * km_register_submenu(const struct MenuFuncOp functions[])
Register a submenu.
Definition init.c:91
struct MenuDefinition * km_register_menu(int menu, const char *name)
Register a menu.
Definition init.c:107
void km_menu_add_bindings(struct MenuDefinition *md, const struct MenuOpSeq bindings[])
Add Keybindings to a Menu.
Definition init.c:136
enum CommandResult km_bind(struct MenuDefinition *md, const char *key_str, int op, char *macro, char *desc, struct Buffer *err)
Set up a key binding.
Definition menu.c:51
Manage keymappings.
@ LL_DEBUG1
Log at debug level 1.
Definition logging2.h:45
@ LL_NOTIFY
Log of notifications.
Definition logging2.h:50
#define FREE(x)
Free memory and set the pointer to NULL.
Definition memory.h:68
GUI present the user with a selectable list.
#define MENU_REDRAW_FULL
Redraw everything.
Definition lib.h:60
#define MENU_REDRAW_INDEX
Redraw the index.
Definition lib.h:57
MenuRedrawFlags menu_current_middle(struct Menu *menu)
Move the current selection to the centre of the window.
Definition move.c:470
void menu_queue_redraw(struct Menu *menu, MenuRedrawFlags redraw)
Queue a request for a redraw.
Definition menu.c:188
int menu_get_index(struct Menu *menu)
Get the current selection in the Menu.
Definition menu.c:164
#define MENU_REDRAW_CURRENT
Redraw the current line of the menu.
Definition lib.h:59
MenuRedrawFlags menu_set_index(struct Menu *menu, int index)
Set the current selection in the Menu.
Definition menu.c:178
void msgwin_clear_text(struct MuttWindow *win)
Clear the text in the Message Window.
Definition msgwin.c:518
Convenience wrapper for the library headers.
#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_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition string.c:677
bool mutt_strn_equal(const char *a, const char *b, size_t num)
Check for equality of two strings (to a maximum), safely.
Definition string.c:429
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:586
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition string.c:284
Many unsorted constants and some structs.
@ EVM_VIEW
View the message.
Definition mutt.h:76
@ EVM_EDIT
Edit the message.
Definition mutt.h:77
@ MUTT_UNDELETE
Messages to be un-deleted.
Definition mutt.h:95
@ MUTT_LIMIT
Messages in limited view.
Definition mutt.h:101
@ MUTT_UNTAG
Messages to be un-tagged.
Definition mutt.h:100
@ MUTT_READ
Messages that have been read.
Definition mutt.h:92
@ MUTT_PURGE
Messages to be purged (bypass trash)
Definition mutt.h:96
@ MUTT_TAG
Tagged messages.
Definition mutt.h:99
@ MUTT_FLAG
Flagged messages.
Definition mutt.h:98
@ MUTT_DELETE
Messages to be deleted.
Definition mutt.h:94
@ MUTT_NEW
New messages.
Definition mutt.h:89
#define PATH_MAX
Definition mutt.h:49
struct Mailbox * mutt_mailbox_next_unread(struct Mailbox *m_cur, struct Buffer *s)
Find next mailbox with unread mail.
struct Mailbox * mutt_mailbox_next(struct Mailbox *m_cur, struct Buffer *s)
Incoming folders completion routine.
bool mutt_mailbox_list(void)
Show a message with the list of mailboxes with new mail.
Mailbox helper functions.
bool window_is_focused(const struct MuttWindow *win)
Does the given Window have the focus?
struct MuttWindow * window_set_focus(struct MuttWindow *win)
Set the Window focus.
void pretty_mailbox(struct Buffer *buf)
Shorten a mailbox path using '~' or '='.
Definition muttlib.c:428
Some miscellaneous functions.
struct Email * mutt_get_virt_email(struct Mailbox *m, int vnum)
Get a virtual Email.
Definition mview.c:415
bool mutt_limit_current_thread(struct MailboxView *mv, struct Email *e)
Limit the email view to the current thread.
Definition mview.c:478
void mview_free(struct MailboxView **ptr)
Free a MailboxView.
Definition mview.c:47
int ea_add_tagged(struct EmailArray *ea, struct MailboxView *mv, struct Email *e, bool use_tagged)
Get an array of the tagged Emails.
Definition mview.c:375
bool message_is_tagged(struct Email *e)
Is a message in the index tagged (and within limit)
Definition mview.c:361
bool mview_has_limit(const struct MailboxView *mv)
Is a limit active?
Definition mview.c:436
int mx_tags_edit(struct Mailbox *m, const char *tags, struct Buffer *buf)
Start the tag editor of the mailbox.
Definition mx.c:1276
int mx_msg_close(struct Mailbox *m, struct Message **ptr)
Close a message.
Definition mx.c:1182
void mx_fastclose_mailbox(struct Mailbox *m, bool keep_account)
Free up memory associated with the Mailbox.
Definition mx.c:411
struct Mailbox * mx_mbox_find2(const char *path)
Find a Mailbox on an Account.
Definition mx.c:1615
struct Message * mx_msg_open(struct Mailbox *m, struct Email *e)
Return a stream pointer for a message.
Definition mx.c:1136
bool mx_tags_is_supported(struct Mailbox *m)
Return true if mailbox support tagging.
Definition mx.c:1313
int mx_tags_commit(struct Mailbox *m, struct Email *e, const char *tags)
Save tags to the Mailbox - Wrapper for MxOps::tags_commit()
Definition mx.c:1296
int mx_toggle_write(struct Mailbox *m)
Toggle the mailbox's readonly flag.
Definition mx.c:1821
enum MxStatus mx_mbox_sync(struct Mailbox *m)
Save changes to mailbox.
Definition mx.c:903
enum MxStatus mx_mbox_close(struct Mailbox *m)
Save changes and close mailbox.
Definition mx.c:595
API for mailboxes.
MxStatus
Return values from mbox_check(), mbox_check_stats(), mbox_sync(), and mbox_close()
Definition mxapi.h:59
@ MX_STATUS_OK
No changes.
Definition mxapi.h:61
@ MX_STATUS_REOPENED
Mailbox was reopened.
Definition mxapi.h:64
@ MX_STATUS_NEW_MAIL
New mail received in Mailbox.
Definition mxapi.h:62
API for encryption/signing of emails.
#define PGP_TRADITIONAL_CHECKED
Email has a traditional (inline) signature.
Definition lib.h:100
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition lib.h:98
#define WithCrypto
Definition lib.h:124
@ NT_GLOBAL_SHUTDOWN
NeoMutt is about to close.
Definition neomutt.h:71
Usenet network mailbox type; talk to an NNTP server.
int nntp_check_msgid(struct Mailbox *m, const char *msgid)
Fetch article by Message-ID.
Definition nntp.c:2216
int nntp_check_children(struct Mailbox *m, const char *msgid)
Fetch children of article with the Message-ID.
Definition nntp.c:2287
void nntp_mailbox(struct Mailbox *m, char *buf, size_t buflen)
Get first newsgroup with new messages.
Definition newsrc.c:1314
struct NntpMboxData * mutt_newsgroup_catchup(struct Mailbox *m, struct NntpAccountData *adata, char *group)
Catchup newsgroup.
Definition newsrc.c:1232
struct NntpAccountData * CurrentNewsSrv
Current NNTP news server.
Definition nntp.c:74
struct NntpAccountData * nntp_select_server(struct Mailbox *m, const char *server, bool leave_lock)
Open a connection to an NNTP server.
Definition newsrc.c:951
Nntp-specific Mailbox data.
@ NT_MAILBOX
Mailbox has changed, NotifyMailbox, EventMailbox.
Definition notify_type.h:49
@ NT_INDEX
Index data has changed, NotifyIndex, IndexSharedData.
Definition notify_type.h:48
@ NT_GLOBAL
Not object-related, NotifyGlobal.
Definition notify_type.h:46
const struct CompleteOps CompleteNmQueryOps
Auto-Completion of NmQuerys.
Definition complete.c:247
void nm_db_longrun_done(struct Mailbox *m)
Finish a long transaction.
Definition db.c:379
void nm_db_longrun_init(struct Mailbox *m, bool writable)
Start a long transaction.
Definition db.c:364
Notmuch virtual mailbox type.
void nm_query_window_reset(void)
Resets the vfolder window position to the present.
Definition notmuch.c:1721
int nm_read_entire_thread(struct Mailbox *m, struct Email *e)
Get the entire thread of an email.
Definition notmuch.c:1550
void nm_query_window_backward(void)
Function to move the current search window backward in time.
Definition notmuch.c:1710
bool nm_query_window_available(void)
Are windowed queries enabled for use?
Definition notmuch.c:1673
bool nm_message_is_still_queried(struct Mailbox *m, struct Email *e)
Is a message still visible in the query?
Definition notmuch.c:1733
void nm_query_window_forward(void)
Function to move the current search window forward in time.
Definition notmuch.c:1690
const char * opcodes_get_name(int op)
Get the name of an opcode.
Definition opcodes.c:48
const char * pager_get_pager(struct ConfigSubset *sub)
Get the value of $pager.
Definition config.c:111
GUI display a file/email/help in a viewport with paging.
int mutt_display_message(struct MuttWindow *win_index, struct IndexSharedData *shared)
Display a message in the pager.
Definition message.c:444
int external_pager(struct MailboxView *mv, struct Email *e, const char *command)
Display a message in an external program.
Definition message.c:296
Match patterns to emails.
int mutt_search_command(struct MailboxView *mv, struct Menu *menu, int cur, struct SearchState *state, SearchFlags flags)
Perform a search.
Definition pattern.c:478
int mutt_pattern_func(struct MailboxView *mv, int op, char *prompt)
Perform some Pattern matching.
Definition pattern.c:311
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition pool.c:91
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition pool.c:111
POP network mailbox.
void pop_fetch_mail(void)
Fetch messages and save them in $spool_file.
Definition pop.c:518
Progress Bar.
@ MUTT_PROGRESS_WRITE
Progress tracks elements, according to $write_inc
Definition lib.h:85
struct Progress * progress_new(enum ProgressType type, size_t size)
Create a new Progress Bar.
Definition progress.c:139
void progress_free(struct Progress **ptr)
Free a Progress Bar.
Definition progress.c:110
void progress_set_message(struct Progress *progress, const char *fmt,...) __attribute__((__format__(__printf__
bool progress_update(struct Progress *progress, size_t pos, int percent)
Update the state of the progress bar.
Definition progress.c:80
@ MUTT_YES
User answered 'Yes', or assume 'Yes'.
Definition quad.h:39
Ask the user a question.
enum QuadOption query_quadoption(const char *prompt, struct ConfigSubset *sub, const char *name)
Ask the user a quad-question.
Definition question.c:384
#define STAILQ_FIRST(head)
Definition queue.h:388
#define STAILQ_FOREACH(var, head, field)
Definition queue.h:390
#define STAILQ_EMPTY(head)
Definition queue.h:382
#define STAILQ_NEXT(elm, field)
Definition queue.h:439
#define SEARCH_OPPOSITE
Search in the opposite direction.
uint8_t SearchFlags
Flags for a specific search, e.g. SEARCH_PROMPT.
#define SEARCH_NO_FLAGS
No flags are set.
#define SEARCH_PROMPT
Ask for search input.
Convenience wrapper for the send headers.
int mutt_resend_message(FILE *fp, struct Mailbox *m, struct Email *e_cur, struct ConfigSubset *sub)
Resend an email.
Definition send.c:1560
bool mutt_send_list_unsubscribe(struct Mailbox *m, struct Email *e)
Send a mailing-list unsubscription email.
Definition send.c:2992
int mutt_send_message(SendFlags flags, struct Email *e_templ, const char *tempfile, struct Mailbox *m, struct EmailArray *ea, struct ConfigSubset *sub)
Send an email.
Definition send.c:2045
bool mutt_send_list_subscribe(struct Mailbox *m, struct Email *e)
Send a mailing-list subscription email.
Definition send.c:2963
#define SEND_GROUP_CHAT_REPLY
Reply to all recipients preserving To/Cc.
Definition send.h:54
uint32_t SendFlags
Flags for mutt_send_message(), e.g. SEND_REPLY.
Definition send.h:40
#define SEND_GROUP_REPLY
Reply to all.
Definition send.h:43
#define SEND_LIST_REPLY
Reply to mailing list.
Definition send.h:44
#define SEND_KEY
Mail a PGP public key.
Definition send.h:48
#define SEND_POSTPONED
Recall a postponed email.
Definition send.h:46
#define SEND_TO_SENDER
Compose new email to sender.
Definition send.h:53
#define SEND_NO_FLAGS
No flags are set.
Definition send.h:41
#define SEND_REPLY
Reply to sender.
Definition send.h:42
#define SEND_NEWS
Reply to a news article.
Definition send.h:55
#define SEND_FORWARD
Forward email.
Definition send.h:45
struct SubMenu * sidebar_get_submenu(void)
Get the Sidebar SubMenu.
Definition functions.c:106
GUI display the mailboxes in a side panel.
#define ASSERT(COND)
Definition signal2.h:59
#define NONULL(x)
Definition string2.h:44
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
The envelope/body of an email.
Definition email.h:39
bool read
Email is read.
Definition email.h:50
bool visible
Is this message part of the view?
Definition email.h:121
struct Envelope * env
Envelope information.
Definition email.h:68
bool collapsed
Is this message part of a collapsed thread?
Definition email.h:120
SecurityFlags security
bit 0-10: flags, bit 11,12: application, bit 13: traditional pgp See: ncrypt/lib.h pgplib....
Definition email.h:43
struct Body * body
List of MIME parts.
Definition email.h:69
bool old
Email is seen, but unread.
Definition email.h:49
bool attach_del
Has an attachment marked for deletion.
Definition email.h:99
bool flagged
Marked important?
Definition email.h:47
bool threaded
Used for threading.
Definition email.h:108
const struct AttrColor * attr_color
Color-pair to use when displaying in the index.
Definition email.h:112
int vnum
Virtual message number.
Definition email.h:114
struct TagList tags
For drivers that support server tagging.
Definition email.h:72
bool deleted
Email is deleted.
Definition email.h:78
int index
The absolute (unsorted) message number.
Definition email.h:110
bool quasi_deleted
Deleted from neomutt, but not modified on disk.
Definition email.h:103
bool tagged
Email is tagged.
Definition email.h:107
char * followup_to
List of 'followup-to' fields.
Definition envelope.h:80
char * message_id
Message ID.
Definition envelope.h:73
struct ListHead references
message references (in reverse order)
Definition envelope.h:83
struct ListHead in_reply_to
in-reply-to header content
Definition envelope.h:84
An Event that happened to a Mailbox.
Definition mailbox.h:189
A NeoMutt function.
Definition functions.h:56
int op
Op code, e.g. OP_MAIN_LIMIT.
Definition functions.h:57
index_function_t function
Function to call.
Definition functions.h:58
int flags
Prerequisites for the function, e.g. CHECK_IN_MAILBOX.
Definition functions.h:59
Private state data for the Index.
struct MuttWindow * win_index
Window for the Index.
struct IndexSharedData * shared
Shared Index data.
bool tag_prefix
tag-prefix has been pressed
struct Menu * menu
Menu controlling the index.
int oldcount
Old count of mails in the mailbox.
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 ConfigSubset * sub
Config set to use.
Definition shared_data.h:38
struct MailboxView * mailbox_view
Current Mailbox view.
Definition shared_data.h:40
struct SearchState * search_state
State of the current search.
Definition shared_data.h:45
struct Notify * notify
Notifications: NotifyIndex, IndexSharedData.
Definition shared_data.h:44
An event such as a keypress.
Definition get.h:50
int op
Function opcode, e.g. OP_HELP.
Definition get.h:52
A List node for strings.
Definition list.h:37
char * data
String.
Definition list.h:38
View of a Mailbox.
Definition mview.h:40
bool collapsed
Are all threads collapsed?
Definition mview.h:49
struct Menu * menu
Needed for pattern compilation.
Definition mview.h:47
struct ThreadsContext * threads
Threads context.
Definition mview.h:44
struct Mailbox * mailbox
Current Mailbox.
Definition mview.h:51
char * pattern
Limit pattern string.
Definition mview.h:42
A mailbox.
Definition mailbox.h:78
int vcount
The number of virtual messages.
Definition mailbox.h:98
bool changed
Mailbox has been modified.
Definition mailbox.h:109
int msg_count
Total number of messages.
Definition mailbox.h:87
AclFlags rights
ACL bits, see AclFlags.
Definition mailbox.h:118
enum MailboxType type
Mailbox type.
Definition mailbox.h:101
void * mdata
Driver specific data.
Definition mailbox.h:131
struct Email ** emails
Array of Emails.
Definition mailbox.h:95
char * name
A short name for the Mailbox.
Definition mailbox.h:81
struct Notify * notify
Notifications: NotifyMailbox, EventMailbox.
Definition mailbox.h:144
struct HashTable * id_hash
Hash Table: "Message-ID" -> Email.
Definition mailbox.h:122
struct Buffer pathbuf
Path of the Mailbox.
Definition mailbox.h:79
bool readonly
Don't allow changes to the mailbox.
Definition mailbox.h:115
int msg_tagged
How many messages are tagged?
Definition mailbox.h:93
bool verbose
Display status messages?
Definition mailbox.h:116
Functions for a Dialog or Window.
Definition menu.h:80
Mapping between a function and an operation.
Definition menu.h:38
Mapping between an operation and a key sequence.
Definition menu.h:48
Definition lib.h:80
int max
Number of entries in the menu.
Definition lib.h:82
A local copy of an email.
Definition message.h:34
FILE * fp
pointer to the message data
Definition message.h:35
const struct Mapping * help_data
Data for the Help Bar.
void * wdata
Private data.
struct MuttWindow * parent
Parent Window.
Container for Accounts, Notifications.
Definition neomutt.h:41
struct Notify * notify
Notifications handler.
Definition neomutt.h:45
struct ConfigSubset * sub
Inherited config items.
Definition neomutt.h:49
NNTP-specific Mailbox data -.
Definition mdata.h:34
bool reverse
search backwards
struct PatternList * pattern
compiled search pattern
Collection of related functions.
Definition menu.h:68
void driver_tags_get_with_hidden(struct TagList *tl, struct Buffer *tags)
Get all tags, also hidden ones, separated by space.
Definition tags.c:175
@ MENU_INDEX
Index panel (list of emails)
Definition type.h:44