NeoMutt  2025-12-11-1039-g550ac6
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 "mlist/lib.h"
53#include "ncrypt/lib.h"
54#include "nntp/lib.h"
55#include "pager/lib.h"
56#include "pattern/lib.h"
57#include "pop/lib.h"
58#include "progress/lib.h"
59#include "question/lib.h"
60#include "send/lib.h"
61#include "sidebar/lib.h"
62#include "external.h"
63#include "globals.h"
64#include "module_data.h"
65#include "mutt_mailbox.h"
66#include "muttlib.h"
67#include "mx.h"
68#include "nntp/mdata.h"
69#include "nntp/module_data.h"
70#include "private_data.h"
71#include "shared_data.h"
72#ifdef USE_AUTOCRYPT
73#include "autocrypt/lib.h"
74#endif
75#ifdef USE_NOTMUCH
76#include "notmuch/lib.h"
77#endif
78#ifdef ENABLE_NLS
79#include <libintl.h>
80#endif
81
82static int op_jump(struct IndexFunctionData *fdata, const struct KeyEvent *event);
83
84// clang-format off
88static const struct MenuFuncOp OpIndex[] = { /* map: index */
89 { "alias-dialog", OP_ALIAS_DIALOG },
90#ifdef USE_AUTOCRYPT
91 { "autocrypt-acct-menu", OP_AUTOCRYPT_ACCT_MENU },
92#endif
93 { "bounce-message", OP_BOUNCE_MESSAGE },
94 { "break-thread", OP_MAIN_BREAK_THREAD },
95 { "browse-mailboxes", OP_MAIN_BROWSE_MAILBOXES },
96 { "browse-mailboxes-readonly", OP_MAIN_BROWSE_MAILBOXES_READONLY },
97 { "catchup", OP_CATCHUP },
98 { "change-folder", OP_MAIN_CHANGE_FOLDER },
99 { "change-folder-readonly", OP_MAIN_CHANGE_FOLDER_READONLY },
100 { "change-newsgroup", OP_MAIN_CHANGE_GROUP },
101 { "change-newsgroup-readonly", OP_MAIN_CHANGE_GROUP_READONLY },
102#ifdef USE_NOTMUCH
103 { "change-vfolder", OP_MAIN_CHANGE_VFOLDER },
104#endif
105 { "check-traditional-pgp", OP_CHECK_TRADITIONAL },
106 { "clear-flag", OP_MAIN_CLEAR_FLAG },
107 { "close-all-threads", OP_MAIN_CLOSE_ALL_THREADS },
108 { "close-thread", OP_MAIN_CLOSE_THREAD },
109 { "collapse-all", OP_MAIN_COLLAPSE_ALL },
110 { "collapse-thread", OP_MAIN_COLLAPSE_THREAD },
111 { "compose-to-sender", OP_COMPOSE_TO_SENDER },
112 { "copy-message", OP_COPY_MESSAGE },
113 { "create-alias", OP_CREATE_ALIAS },
114 { "decode-copy", OP_DECODE_COPY },
115 { "decode-save", OP_DECODE_SAVE },
116 { "decrypt-copy", OP_DECRYPT_COPY },
117 { "decrypt-save", OP_DECRYPT_SAVE },
118 { "delete-message", OP_DELETE },
119 { "delete-pattern", OP_MAIN_DELETE_PATTERN },
120 { "delete-subthread", OP_DELETE_SUBTHREAD },
121 { "delete-thread", OP_DELETE_THREAD },
122 { "display-address", OP_DISPLAY_ADDRESS },
123 { "display-message", OP_DISPLAY_MESSAGE },
124 { "display-toggle-weed", OP_DISPLAY_HEADERS },
125 { "edit", OP_EDIT_RAW_MESSAGE },
126 { "edit-label", OP_EDIT_LABEL },
127 { "edit-or-view-raw-message", OP_EDIT_OR_VIEW_RAW_MESSAGE },
128 { "edit-raw-message", OP_EDIT_RAW_MESSAGE },
129 { "edit-type", OP_ATTACH_EDIT_TYPE },
130#ifdef USE_NOTMUCH
131 { "entire-thread", OP_MAIN_ENTIRE_THREAD },
132#endif
133 { "extract-keys", OP_EXTRACT_KEYS },
134 { "fetch-mail", OP_MAIN_FETCH_MAIL },
135 { "flag-message", OP_FLAG_MESSAGE },
136 { "followup-message", OP_FOLLOWUP },
137 { "forward-message", OP_FORWARD_MESSAGE },
138 { "forward-to-group", OP_FORWARD_TO_GROUP },
139 { "get-children", OP_GET_CHILDREN },
140 { "get-message", OP_GET_MESSAGE },
141 { "get-parent", OP_GET_PARENT },
142 { "group-chat-reply", OP_GROUP_CHAT_REPLY },
143 { "group-reply", OP_GROUP_REPLY },
144 { "imap-fetch-mail", OP_MAIN_IMAP_FETCH },
145 { "imap-logout-all", OP_MAIN_IMAP_LOGOUT_ALL },
146 { "limit", OP_MAIN_LIMIT },
147 { "limit-current-thread", OP_LIMIT_CURRENT_THREAD },
148 { "link-threads", OP_MAIN_LINK_THREADS },
149 { "list-action", OP_LIST_ACTION },
150 { "list-reply", OP_LIST_REPLY },
151 { "list-subscribe", OP_LIST_SUBSCRIBE },
152 { "list-unsubscribe", OP_LIST_UNSUBSCRIBE },
153 { "mail", OP_MAIL },
154 { "mail-key", OP_MAIL_KEY },
155 { "mailbox-list", OP_MAILBOX_LIST },
156 { "mark-message", OP_MARK_MSG },
157 { "modify-labels", OP_MAIN_MODIFY_TAGS },
158 { "modify-labels-then-hide", OP_MAIN_MODIFY_TAGS_THEN_HIDE },
159 { "modify-tags", OP_MAIN_MODIFY_TAGS },
160 { "modify-tags-then-hide", OP_MAIN_MODIFY_TAGS_THEN_HIDE },
161 { "next-new", OP_MAIN_NEXT_NEW },
162 { "next-new-then-unread", OP_MAIN_NEXT_NEW_THEN_UNREAD },
163 { "next-subthread", OP_MAIN_NEXT_SUBTHREAD },
164 { "next-thread", OP_MAIN_NEXT_THREAD },
165 { "next-undeleted", OP_MAIN_NEXT_UNDELETED },
166 { "next-unread", OP_MAIN_NEXT_UNREAD },
167 { "next-unread-mailbox", OP_MAIN_NEXT_UNREAD_MAILBOX },
168 { "open-all-threads", OP_MAIN_OPEN_ALL_THREADS },
169 { "open-thread", OP_MAIN_OPEN_THREAD },
170 { "parent-message", OP_MAIN_PARENT_MESSAGE },
171 { "pipe-entry", OP_PIPE },
172 { "pipe-message", OP_PIPE },
173 { "post-message", OP_POST },
174 { "previous-new", OP_MAIN_PREV_NEW },
175 { "previous-new-then-unread", OP_MAIN_PREV_NEW_THEN_UNREAD },
176 { "previous-subthread", OP_MAIN_PREV_SUBTHREAD },
177 { "previous-thread", OP_MAIN_PREV_THREAD },
178 { "previous-undeleted", OP_MAIN_PREV_UNDELETED },
179 { "previous-unread", OP_MAIN_PREV_UNREAD },
180 { "previous-unread-mailbox", OP_MAIN_PREV_UNREAD_MAILBOX },
181 { "print-message", OP_PRINT },
182 { "purge-message", OP_PURGE_MESSAGE },
183 { "purge-pattern", OP_PURGE_PATTERN },
184 { "purge-subthread", OP_PURGE_SUBTHREAD },
185 { "purge-thread", OP_PURGE_THREAD },
186 { "quasi-delete", OP_MAIN_QUASI_DELETE },
187 { "query", OP_QUERY },
188 { "read-subthread", OP_MAIN_READ_SUBTHREAD },
189 { "read-thread", OP_MAIN_READ_THREAD },
190 { "recall-message", OP_RECALL_MESSAGE },
191 { "reconstruct-thread", OP_RECONSTRUCT_THREAD },
192 { "reply", OP_REPLY },
193 { "resend-message", OP_RESEND },
194 { "root-message", OP_MAIN_ROOT_MESSAGE },
195 { "save-message", OP_SAVE },
196 { "set-flag", OP_MAIN_SET_FLAG },
197 { "show-limit", OP_MAIN_SHOW_LIMIT },
198 { "sort-mailbox", OP_SORT },
199 { "sort-reverse", OP_SORT_REVERSE },
200 { "sync-mailbox", OP_MAIN_SYNC_FOLDER },
201 { "tag-pattern", OP_MAIN_TAG_PATTERN },
202 { "tag-subthread", OP_TAG_SUBTHREAD },
203 { "tag-thread", OP_TAG_THREAD },
204 { "toggle-new", OP_TOGGLE_NEW },
205 { "toggle-read", OP_TOGGLE_READ },
206 { "toggle-write", OP_TOGGLE_WRITE },
207 { "undelete-message", OP_UNDELETE },
208 { "undelete-pattern", OP_MAIN_UNDELETE_PATTERN },
209 { "undelete-subthread", OP_UNDELETE_SUBTHREAD },
210 { "undelete-thread", OP_UNDELETE_THREAD },
211 { "untag-pattern", OP_MAIN_UNTAG_PATTERN },
212#ifdef USE_NOTMUCH
213 { "vfolder-from-query", OP_MAIN_VFOLDER_FROM_QUERY },
214 { "vfolder-from-query-readonly", OP_MAIN_VFOLDER_FROM_QUERY_READONLY },
215 { "vfolder-window-backward", OP_MAIN_WINDOWED_VFOLDER_BACKWARD },
216 { "vfolder-window-forward", OP_MAIN_WINDOWED_VFOLDER_FORWARD },
217 { "vfolder-window-reset", OP_MAIN_WINDOWED_VFOLDER_RESET },
218#endif
219 { "view-attachments", OP_VIEW_ATTACHMENTS },
220 { "view-raw-message", OP_VIEW_RAW_MESSAGE },
221 // Deprecated
222 { "buffy-list", OP_MAILBOX_LIST, MFF_DEPRECATED },
223 { NULL, 0 },
224};
225
229static const struct MenuOpSeq IndexDefaultBindings[] = { /* map: index */
230 { OP_ATTACH_EDIT_TYPE, "\005" }, // <Ctrl-E>
231#ifdef USE_AUTOCRYPT
232 { OP_AUTOCRYPT_ACCT_MENU, "A" },
233#endif
234 { OP_BOUNCE_MESSAGE, "b" },
235 { OP_CHECK_TRADITIONAL, "\033P" }, // <Alt-P>
236 { OP_COPY_MESSAGE, "C" },
237 { OP_CREATE_ALIAS, "a" },
238 { OP_DECODE_COPY, "\033C" }, // <Alt-C>
239 { OP_DECODE_SAVE, "\033s" }, // <Alt-s>
240 { OP_DELETE, "d" },
241 { OP_DELETE_SUBTHREAD, "\033d" }, // <Alt-d>
242 { OP_DELETE_THREAD, "\004" }, // <Ctrl-D>
243 { OP_DISPLAY_ADDRESS, "@" },
244 { OP_DISPLAY_HEADERS, "h" },
245 { OP_DISPLAY_MESSAGE, " " }, // <Space>
246 { OP_DISPLAY_MESSAGE, "<keypadenter>" },
247 { OP_DISPLAY_MESSAGE, "\n" }, // <Enter>
248 { OP_DISPLAY_MESSAGE, "\r" }, // <Return>
249 { OP_EDIT_LABEL, "Y" },
250 { OP_EDIT_OR_VIEW_RAW_MESSAGE, "e" },
251 { OP_EXIT, "x" },
252 { OP_EXTRACT_KEYS, "\013" }, // <Ctrl-K>
253 { OP_FLAG_MESSAGE, "F" },
254 { OP_FORGET_PASSPHRASE, "\006" }, // <Ctrl-F>
255 { OP_FORWARD_MESSAGE, "f" },
256 { OP_GROUP_REPLY, "g" },
257 { OP_LIST_ACTION, "\033L" }, // <Alt-L>
258 { OP_LIST_REPLY, "L" },
259 { OP_MAIL, "m" },
260 { OP_MAILBOX_LIST, "." },
261 { OP_MAIL_KEY, "\033k" }, // <Alt-k>
262 { OP_MAIN_BREAK_THREAD, "#" },
263 { OP_MAIN_BROWSE_MAILBOXES, "y" },
264 { OP_MAIN_CHANGE_FOLDER, "c" },
265 { OP_MAIN_CHANGE_FOLDER_READONLY, "\033c" }, // <Alt-c>
266 { OP_MAIN_CHANGE_GROUP, "i" },
267 { OP_MAIN_CHANGE_GROUP_READONLY, "\033i" }, // <Alt-i>
268 { OP_MAIN_CLEAR_FLAG, "W" },
269 { OP_MAIN_COLLAPSE_ALL, "\033V" }, // <Alt-V>
270 { OP_MAIN_COLLAPSE_THREAD, "\033v" }, // <Alt-v>
271 { OP_MAIN_DELETE_PATTERN, "D" },
272 { OP_MAIN_FETCH_MAIL, "G" },
273 { OP_MAIN_LIMIT, "l" },
274 { OP_MAIN_LINK_THREADS, "&" },
275 { OP_MAIN_NEXT_NEW_THEN_UNREAD, "\t" }, // <Tab>
276 { OP_MAIN_NEXT_SUBTHREAD, "\033n" }, // <Alt-n>
277 { OP_MAIN_NEXT_THREAD, "\016" }, // <Ctrl-N>
278 { OP_MAIN_NEXT_UNDELETED, "<down>" },
279 { OP_MAIN_NEXT_UNDELETED, "j" },
280 { OP_MAIN_PARENT_MESSAGE, "P" },
281 { OP_MAIN_PREV_NEW_THEN_UNREAD, "\033\t" }, // <Alt-Tab>
282 { OP_MAIN_PREV_SUBTHREAD, "\033p" }, // <Alt-p>
283 { OP_MAIN_PREV_THREAD, "\020" }, // <Ctrl-P>
284 { OP_MAIN_PREV_UNDELETED, "<up>" },
285 { OP_MAIN_PREV_UNDELETED, "k" },
286 { OP_MAIN_READ_SUBTHREAD, "\033r" }, // <Alt-r>
287 { OP_MAIN_READ_THREAD, "\022" }, // <Ctrl-R>
288 { OP_MAIN_SET_FLAG, "w" },
289 { OP_MAIN_SHOW_LIMIT, "\033l" }, // <Alt-l>
290 { OP_MAIN_SYNC_FOLDER, "$" },
291 { OP_MAIN_TAG_PATTERN, "T" },
292 { OP_MAIN_UNDELETE_PATTERN, "U" },
293 { OP_MAIN_UNTAG_PATTERN, "\024" }, // <Ctrl-T>
294 { OP_MARK_MSG, "~" },
295 { OP_NEXT_ENTRY, "J" },
296 { OP_PIPE, "|" },
297 { OP_PREV_ENTRY, "K" },
298 { OP_PRINT, "p" },
299 { OP_QUERY, "Q" },
300 { OP_QUIT, "q" },
301 { OP_RECALL_MESSAGE, "R" },
302 { OP_REPLY, "r" },
303 { OP_RESEND, "\033e" }, // <Alt-e>
304 { OP_SAVE, "s" },
305 { OP_SHOW_LOG_MESSAGES, "M" },
306 { OP_SORT, "o" },
307 { OP_SORT_REVERSE, "O" },
308 { OP_TAG_THREAD, "\033t" }, // <Alt-t>
309 { OP_TOGGLE_NEW, "N" },
310 { OP_TOGGLE_WRITE, "%" },
311 { OP_UNDELETE, "u" },
312 { OP_UNDELETE_SUBTHREAD, "\033u" }, // <Alt-u>
313 { OP_UNDELETE_THREAD, "\025" }, // <Ctrl-U>
314 { OP_VIEW_ATTACHMENTS, "v" },
315 { 0, NULL },
316};
317
328
332void index_init_keys(struct NeoMutt *n, struct SubMenu *sm_generic)
333{
334 struct MenuDefinition *md = NULL;
335 struct SubMenu *sm_index = NULL;
336 struct SubMenu *sm_sidebar = sidebar_get_submenu();
337
338 sm_index = km_register_submenu(OpIndex);
339 md = km_register_menu(MENU_INDEX, "index");
340 km_menu_add_submenu(md, sm_index);
341 km_menu_add_submenu(md, sm_sidebar);
342 km_menu_add_submenu(md, sm_generic);
344
346 ASSERT(mod_data);
347 mod_data->md_index = md;
348 mod_data->sm_index = sm_index;
349}
350
356{
358 ASSERT(mod_data);
359
360 return mod_data->sm_index;
361}
362
371static bool resolve_email(struct IndexPrivateData *priv, struct IndexSharedData *shared,
372 enum ResolveMethod rm, int count)
373{
374 if (!priv || !priv->menu || !shared || !shared->mailbox || !shared->email)
375 return false;
376
377 const bool c_resolve = cs_subset_bool(shared->sub, "resolve");
378 if (!c_resolve)
379 return false;
380
381 count = MAX(count, 1);
382 int index = menu_get_index(priv->menu);
383
384 switch (rm)
385 {
387 index = index + count;
388 break;
389
391 {
392 const bool uncollapse = mutt_using_threads() && !window_is_focused(priv->win_index);
393 for (int i = 0; i < count; i++)
394 {
395 int next = find_next_undeleted(shared->mailbox_view, index, uncollapse);
396 if (next < 0)
397 break;
398 index = next;
399 }
400 break;
401 }
402
404 for (int i = 0; i < count; i++)
405 {
406 struct Email *e = mutt_get_virt_email(shared->mailbox, index);
407 if (!e)
408 break;
409 int next = mutt_next_thread(e);
410 if (next < 0)
411 break;
412 index = next;
413 }
414 break;
415
417 for (int i = 0; i < count; i++)
418 {
419 struct Email *e = mutt_get_virt_email(shared->mailbox, index);
420 if (!e)
421 break;
422 int next = mutt_next_subthread(e);
423 if (next < 0)
424 break;
425 index = next;
426 }
427 break;
428 }
429
430 if (index < 0)
431 index = 0;
432 if (index >= shared->mailbox->vcount)
433 index = shared->mailbox->vcount - 1;
434
435 menu_set_index(priv->menu, index);
436 return true;
437}
438
444bool index_next_undeleted(struct MuttWindow *win_index)
445{
446 struct MuttWindow *dlg = dialog_find(win_index);
447 if (!dlg)
448 return false;
449
450 struct Menu *menu = win_index->wdata;
451 struct IndexSharedData *shared = dlg->wdata;
452 if (!shared)
453 return false;
454
455 struct IndexPrivateData *priv = win_index->parent->wdata;
456 const bool uncollapse = mutt_using_threads() && !window_is_focused(priv->win_index);
457
458 int index = find_next_undeleted(shared->mailbox_view, menu_get_index(menu), uncollapse);
459 if ((index < 0) || (index >= shared->mailbox->vcount))
460 {
461 // Selection failed
463 return false;
464 }
465
466 menu_set_index(menu, index);
467 return true;
468}
469
480static int ea_add_selection(struct EmailArray *ea, struct MailboxView *mv,
481 struct Email *e, bool use_tagged, int count)
482{
483 if (!ea)
484 return -1;
485
486 if (use_tagged)
487 return ea_add_tagged(ea, mv, e, true);
488
489 if (!mv || !mv->mailbox || !e)
490 return -1;
491
492 const int index = e->vnum;
493 if ((index < 0) || (index >= mv->mailbox->vcount))
494 return -1;
495
496 int n = (count > 1) ? count : 1;
497 if ((index + n) > mv->mailbox->vcount)
498 n = mv->mailbox->vcount - index;
499
500 for (int i = 0; i < n; i++)
501 {
502 struct Email *sel = mutt_get_virt_email(mv->mailbox, index + i);
503 if (sel)
504 ea_add_tagged(ea, mv, sel, false);
505 }
506
507 return ARRAY_SIZE(ea);
508}
509
516static struct MuttThread *thread_target(struct Email *e, bool subthread)
517{
518 if (!e || !e->thread)
519 return NULL;
520
521 struct MuttThread *thread = e->thread;
522 if (!subthread)
523 {
524 while (thread->parent)
525 thread = thread->parent;
526 }
527
528 return thread;
529}
530
538static bool ea_contains_thread_target(struct EmailArray *ea, struct Email *e, bool subthread)
539{
540 if (!ea || !e)
541 return false;
542
543 struct MuttThread *target = thread_target(e, subthread);
544 if (!target)
545 return false;
546
547 struct Email **ep = NULL;
548 ARRAY_FOREACH(ep, ea)
549 {
550 if (thread_target(*ep, subthread) == target)
551 return true;
552 }
553
554 return false;
555}
556
568static int ea_add_selection_threads(struct EmailArray *ea,
569 struct MailboxView *mv, struct Email *e,
570 bool use_tagged, bool subthread, int count)
571{
572 if (!ea)
573 return -1;
574
575 if (!use_tagged)
576 {
577 if (!mv || !mv->mailbox || !e)
578 return -1;
579
580 const int index = e->vnum;
581 if ((index < 0) || (index >= mv->mailbox->vcount))
582 return -1;
583
584 const int n = (count > 1) ? count : 1;
585 for (int i = index; (i < mv->mailbox->vcount) && (ARRAY_SIZE(ea) < n); i++)
586 {
587 struct Email *sel = mutt_get_virt_email(mv->mailbox, i);
588 if (!sel || ea_contains_thread_target(ea, sel, subthread))
589 continue;
590
591 ARRAY_ADD(ea, sel);
592 }
593 return ARRAY_SIZE(ea);
594 }
595
596 if (!mv || !mv->mailbox || !mv->mailbox->emails)
597 return -1;
598
599 struct Mailbox *m = mv->mailbox;
600 for (int i = 0; i < m->msg_count; i++)
601 {
602 struct Email *et = m->emails[i];
603 if (!et)
604 break;
605 if (!message_is_tagged(et))
606 continue;
607
608 if (!ea_contains_thread_target(ea, et, subthread))
609 ARRAY_ADD(ea, et);
610 }
611
612 return ARRAY_SIZE(ea);
613}
614
615// -----------------------------------------------------------------------------
616
620static int op_alias_dialog(struct IndexFunctionData *fdata, const struct KeyEvent *event)
621{
622 struct IndexSharedData *shared = fdata->shared;
623 alias_dialog(shared->mailbox, shared->sub);
624 return FR_SUCCESS;
625}
626
630static int op_attach_edit_type(struct IndexFunctionData *fdata, const struct KeyEvent *event)
631{
632 struct IndexSharedData *shared = fdata->shared;
633 struct IndexPrivateData *priv = fdata->priv;
634 if (!shared->email)
635 return FR_NO_ACTION;
637
639 return FR_SUCCESS;
640}
641
645static int op_bounce_message(struct IndexFunctionData *fdata, const struct KeyEvent *event)
646{
647 struct IndexSharedData *shared = fdata->shared;
648 struct IndexPrivateData *priv = fdata->priv;
649 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
650 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
651 index_bounce_message(shared->mailbox, &ea);
652 ARRAY_FREE(&ea);
653
654 return FR_SUCCESS;
655}
656
660static int op_check_traditional(struct IndexFunctionData *fdata, const struct KeyEvent *event)
661{
662 struct IndexSharedData *shared = fdata->shared;
663 struct IndexPrivateData *priv = fdata->priv;
665 return FR_NOT_IMPL;
666 if (!shared->email)
667 return FR_NO_ACTION;
668
670 {
671 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
672 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
673 if (mutt_check_traditional_pgp(shared->mailbox, &ea))
675 ARRAY_FREE(&ea);
676 }
677
678 return FR_SUCCESS;
679}
680
684static int op_compose_to_sender(struct IndexFunctionData *fdata, const struct KeyEvent *event)
685{
686 struct IndexSharedData *shared = fdata->shared;
687 struct IndexPrivateData *priv = fdata->priv;
688 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
689 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
690 int rc = mutt_send_message(SEND_TO_SENDER, NULL, NULL, shared->mailbox, &ea,
691 shared->sub);
692 ARRAY_FREE(&ea);
694
695 return (rc == -1) ? FR_ERROR : FR_SUCCESS;
696}
697
701static int op_create_alias(struct IndexFunctionData *fdata, const struct KeyEvent *event)
702{
703 struct IndexSharedData *shared = fdata->shared;
704 struct IndexPrivateData *priv = fdata->priv;
705 struct AddressList *al = NULL;
706 if (shared->email && shared->email->env)
707 al = mutt_get_address(shared->email->env, NULL);
708 alias_create(al, shared->sub);
710
711 return FR_SUCCESS;
712}
713
721static int op_delete(struct IndexFunctionData *fdata, const struct KeyEvent *event)
722{
723 struct IndexSharedData *shared = fdata->shared;
724 struct IndexPrivateData *priv = fdata->priv;
725 /* L10N: CHECK_ACL */
726 if (!check_acl(shared->mailbox, MUTT_ACL_DELETE, _("Can't delete message")))
727 return FR_ERROR;
728
729 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
730 ea_add_selection(&ea, shared->mailbox_view, shared->email, priv->tag_prefix,
731 event->count);
732 if (ARRAY_EMPTY(&ea))
733 {
734 ARRAY_FREE(&ea);
735 return FR_NO_ACTION;
736 }
737
738 mutt_emails_set_flag(shared->mailbox, &ea, MUTT_DELETE, true);
739 mutt_emails_set_flag(shared->mailbox, &ea, MUTT_PURGE, (event->op == OP_PURGE_MESSAGE));
740 const bool c_delete_untag = cs_subset_bool(shared->sub, "delete_untag");
741 if (c_delete_untag)
742 mutt_emails_set_flag(shared->mailbox, &ea, MUTT_TAG, false);
743 ARRAY_FREE(&ea);
744
745 if (priv->tag_prefix)
746 {
748 }
749 else
750 {
751 resolve_email(priv, shared, RESOLVE_NEXT_UNDELETED, 1);
752 }
753
754 return FR_SUCCESS;
755}
756
762static void update_thread_email(struct IndexPrivateData *priv, struct Email *email)
763{
764 if (!priv || !priv->menu || !email)
765 return;
766
767 int index = email->vnum;
768 if (index < 0)
769 {
770 struct MuttThread *thread = thread_target(email, false);
771 struct Email *e = find_virtual(thread, false);
772 if (e)
773 index = e->vnum;
774 }
775
776 if (index >= 0)
777 menu_set_index(priv->menu, index);
778}
779
788 struct EmailArray *ea, enum CollapseMode mode)
789{
790 struct IndexSharedData *shared = fdata->shared;
791 struct IndexPrivateData *priv = fdata->priv;
792 if (!mutt_using_threads())
793 {
794 mutt_warning(_("Threading is not enabled"));
795 return FR_ERROR;
796 }
797
798 if (!ea || ARRAY_EMPTY(ea))
799 return FR_NO_ACTION;
800
801 bool changed = false;
802 bool blocked = false;
803 struct Email **ep = NULL;
804 ARRAY_FOREACH(ep, ea)
805 {
806 struct Email *e = *ep;
807 if (!e)
808 continue;
809
810 switch (mode)
811 {
813 if (!e->collapsed)
814 continue;
816 changed = true;
817 break;
819 if (e->collapsed)
820 continue;
822 {
823 blocked = true;
824 continue;
825 }
827 changed = true;
828 break;
830 if (e->collapsed)
831 {
833 changed = true;
834 }
835 else if (mutt_thread_can_collapse(e))
836 {
838 changed = true;
839 }
840 else
841 {
842 blocked = true;
843 }
844 break;
845 }
846 }
847
848 if (!changed)
849 {
850 if (blocked)
851 {
852 mutt_warning(_("Thread contains unread or flagged messages"));
853 return FR_ERROR;
854 }
855 return FR_NO_ACTION;
856 }
857
858 mutt_set_vnum(shared->mailbox);
859 update_thread_email(priv, shared->email);
861 notify_send(shared->notify, NT_INDEX, NT_INDEX_EMAIL, NULL);
862 return FR_SUCCESS;
863}
864
874static int op_delete_thread(struct IndexFunctionData *fdata, const struct KeyEvent *event)
875{
876 struct IndexSharedData *shared = fdata->shared;
877 struct IndexPrivateData *priv = fdata->priv;
878 /* L10N: CHECK_ACL */
879 /* L10N: Due to the implementation details we do not know whether we
880 delete zero, 1, 12, ... messages. So in English we use
881 "messages". Your language might have other means to express this. */
882 if (!check_acl(shared->mailbox, MUTT_ACL_DELETE, _("Can't delete messages")))
883 return FR_ERROR;
884 if (!shared->email)
885 return FR_NO_ACTION;
886
887 const int op = event->op;
888 const bool subthread = ((op == OP_DELETE_SUBTHREAD) || (op == OP_PURGE_SUBTHREAD));
889 int rc = 0;
890 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
891 ea_add_selection_threads(&ea, shared->mailbox_view, shared->email,
892 priv->tag_prefix, subthread, event->count);
893
894 struct Email **ep = NULL;
895 ARRAY_FOREACH(ep, &ea)
896 {
897 rc = mutt_thread_set_flag(shared->mailbox, *ep, MUTT_DELETE, true, subthread);
898 if (rc == -1)
899 break;
900
901 if ((op == OP_PURGE_THREAD) || (op == OP_PURGE_SUBTHREAD))
902 {
903 rc = mutt_thread_set_flag(shared->mailbox, *ep, MUTT_PURGE, true, subthread);
904 if (rc == -1)
905 break;
906 }
907
908 const bool c_delete_untag = cs_subset_bool(shared->sub, "delete_untag");
909 if (c_delete_untag)
910 mutt_thread_set_flag(shared->mailbox, *ep, MUTT_TAG, false, subthread);
911 }
912 ARRAY_FREE(&ea);
913
914 if (rc == -1)
915 return FR_ERROR;
916
917 if (priv->tag_prefix)
918 {
920 return FR_SUCCESS;
921 }
922
923 resolve_email(priv, shared, RESOLVE_NEXT_UNDELETED, 1);
925 return FR_SUCCESS;
926}
927
931static int op_display_address(struct IndexFunctionData *fdata, const struct KeyEvent *event)
932{
933 struct IndexSharedData *shared = fdata->shared;
934 if (!shared->email)
935 return FR_NO_ACTION;
937
938 return FR_SUCCESS;
939}
940
949static int op_display_message(struct IndexFunctionData *fdata, const struct KeyEvent *event)
950{
951 struct IndexSharedData *shared = fdata->shared;
952 struct IndexPrivateData *priv = fdata->priv;
953 if (!shared->email)
954 return FR_NO_ACTION;
955
956 if (event->count > 0)
957 return op_jump(fdata, event);
958
959 int op = event->op;
960
961 if (op == OP_DISPLAY_MESSAGE)
962 {
963 if (!window_is_focused(priv->win_index))
964 return FR_SUCCESS;
965 }
966
968
969 /* toggle the weeding of headers so that a user can press the key
970 * again while reading the message. */
971 if (op == OP_DISPLAY_HEADERS)
972 {
973 bool_str_toggle(shared->sub, "weed", NULL);
975 if (!window_is_focused(priv->win_index))
976 return FR_SUCCESS;
977 }
978
979 OptNeedResort = false;
980
982 {
985 const bool c_uncollapse_jump = cs_subset_bool(shared->sub, "uncollapse_jump");
986 if (c_uncollapse_jump)
988 }
989
990 const bool c_pgp_auto_decode = cs_subset_bool(shared->sub, "pgp_auto_decode");
991 if (c_pgp_auto_decode &&
993 {
994 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
995 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
996 if (mutt_check_traditional_pgp(shared->mailbox, &ea))
998 ARRAY_FREE(&ea);
999 }
1000 const int index = menu_get_index(priv->menu);
1002
1003 const char *const c_pager = pager_get_pager(fdata->n->sub);
1004 if (c_pager)
1005 {
1006 op = external_pager(shared->mailbox_view, shared->email, c_pager);
1007 }
1008 else
1009 {
1010 op = mutt_display_message(priv->win_index, shared);
1011 }
1012
1014 if (op < OP_NULL)
1015 {
1016 OptNeedResort = false;
1017 return FR_ERROR;
1018 }
1019
1020 if (shared->mailbox)
1021 {
1023 shared->mailbox->msg_count, shared);
1024 }
1025
1026 return op;
1027}
1028
1032static int op_edit_label(struct IndexFunctionData *fdata, const struct KeyEvent *event)
1033{
1034 struct IndexSharedData *shared = fdata->shared;
1035 struct IndexPrivateData *priv = fdata->priv;
1036 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
1037 ea_add_selection(&ea, shared->mailbox_view, shared->email, priv->tag_prefix,
1038 event->count);
1039 if (ARRAY_EMPTY(&ea))
1040 {
1041 ARRAY_FREE(&ea);
1042 return FR_NO_ACTION;
1043 }
1044 const int num = ARRAY_SIZE(&ea);
1045 int num_changed = mutt_label_message(shared->mailbox_view, &ea);
1046 ARRAY_FREE(&ea);
1047
1048 if (num_changed > 0)
1049 {
1050 shared->mailbox->changed = true;
1052 /* L10N: This is displayed when the x-label on one or more
1053 messages is edited. */
1054 mutt_message(ngettext("%d label changed", "%d labels changed", num_changed), num_changed);
1055
1056 if (!priv->tag_prefix)
1057 resolve_email(priv, shared, RESOLVE_NEXT_UNDELETED, num);
1058 return FR_SUCCESS;
1059 }
1060
1061 /* L10N: This is displayed when editing an x-label, but no messages
1062 were updated. Possibly due to canceling at the prompt or if the new
1063 label is the same as the old label. */
1064 mutt_message(_("No labels changed"));
1065 return FR_NO_ACTION;
1066}
1067
1076static int op_edit_raw_message(struct IndexFunctionData *fdata, const struct KeyEvent *event)
1077{
1078 struct IndexSharedData *shared = fdata->shared;
1079 struct IndexPrivateData *priv = fdata->priv;
1080 /* TODO split this into 3 cases? */
1081 bool edit;
1082 const int op = event->op;
1083 if (op == OP_EDIT_RAW_MESSAGE)
1084 {
1085 /* L10N: CHECK_ACL */
1086 if (!check_acl(shared->mailbox, MUTT_ACL_INSERT, _("Can't edit message")))
1087 return FR_ERROR;
1088 edit = true;
1089 }
1090 else if (op == OP_EDIT_OR_VIEW_RAW_MESSAGE)
1091 {
1093 }
1094 else
1095 {
1096 edit = false;
1097 }
1098
1099 if (!shared->email)
1100 return FR_NO_ACTION;
1101 const bool c_pgp_auto_decode = cs_subset_bool(shared->sub, "pgp_auto_decode");
1102 if (c_pgp_auto_decode &&
1104 {
1105 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
1106 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
1107 if (mutt_check_traditional_pgp(shared->mailbox, &ea))
1109 ARRAY_FREE(&ea);
1110 }
1111 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
1112 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
1113 mutt_ev_message(shared->mailbox, &ea, edit ? EVM_EDIT : EVM_VIEW);
1114 ARRAY_FREE(&ea);
1116
1117 return FR_SUCCESS;
1118}
1119
1123static int op_end_cond(struct IndexFunctionData *fdata, const struct KeyEvent *event)
1124{
1125 return FR_SUCCESS;
1126}
1127
1131static int op_exit(struct IndexFunctionData *fdata, const struct KeyEvent *event)
1132{
1133 struct IndexSharedData *shared = fdata->shared;
1134 if (shared->attach_msg)
1135 return FR_DONE;
1136
1137 if (query_quadoption(_("Exit NeoMutt without saving?"), shared->sub, "quit") == MUTT_YES)
1138 {
1139 if (shared->mailbox_view)
1140 {
1141 mx_fastclose_mailbox(shared->mailbox, false);
1142 mview_free(&shared->mailbox_view);
1143 }
1144 return FR_DONE;
1145 }
1146
1147 return FR_NO_ACTION;
1148}
1149
1153static int op_extract_keys(struct IndexFunctionData *fdata, const struct KeyEvent *event)
1154{
1155 struct IndexSharedData *shared = fdata->shared;
1156 struct IndexPrivateData *priv = fdata->priv;
1157 if (!WithCrypto)
1158 return FR_NOT_IMPL;
1159 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
1160 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
1162 ARRAY_FREE(&ea);
1164
1165 return FR_SUCCESS;
1166}
1167
1171static int op_flag_message(struct IndexFunctionData *fdata, const struct KeyEvent *event)
1172{
1173 struct IndexSharedData *shared = fdata->shared;
1174 struct IndexPrivateData *priv = fdata->priv;
1175 /* L10N: CHECK_ACL */
1176 if (!check_acl(shared->mailbox, MUTT_ACL_WRITE, _("Can't flag message")))
1177 return FR_ERROR;
1178
1179 struct Mailbox *m = shared->mailbox;
1180 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
1181 ea_add_selection(&ea, shared->mailbox_view, shared->email, priv->tag_prefix,
1182 event->count);
1183 if (ARRAY_EMPTY(&ea))
1184 {
1185 ARRAY_FREE(&ea);
1186 return FR_NO_ACTION;
1187 }
1188 const int num = ARRAY_SIZE(&ea);
1189
1190 struct Email **ep = NULL;
1191 ARRAY_FOREACH(ep, &ea)
1192 mutt_set_flag(m, *ep, MUTT_FLAG, !(*ep)->flagged, true);
1193 ARRAY_FREE(&ea);
1194
1195 if (priv->tag_prefix)
1196 {
1198 }
1199 else
1200 {
1201 resolve_email(priv, shared, RESOLVE_NEXT_UNDELETED, num);
1202 if (num > 1)
1204 }
1205
1206 return FR_SUCCESS;
1207}
1208
1212static int op_forward_message(struct IndexFunctionData *fdata, const struct KeyEvent *event)
1213{
1214 struct IndexSharedData *shared = fdata->shared;
1215 struct IndexPrivateData *priv = fdata->priv;
1216 if (!shared->email)
1217 return FR_NO_ACTION;
1218 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
1219 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
1220 const bool c_pgp_auto_decode = cs_subset_bool(shared->sub, "pgp_auto_decode");
1221 if (c_pgp_auto_decode &&
1222 (priv->tag_prefix || !(shared->email->security & PGP_TRADITIONAL_CHECKED)))
1223 {
1224 if (mutt_check_traditional_pgp(shared->mailbox, &ea))
1226 }
1227 int rc = mutt_send_message(SEND_FORWARD, NULL, NULL, shared->mailbox, &ea,
1228 shared->sub);
1229 ARRAY_FREE(&ea);
1231
1232 return (rc == -1) ? FR_ERROR : FR_SUCCESS;
1233}
1234
1242static int op_group_reply(struct IndexFunctionData *fdata, const struct KeyEvent *event)
1243{
1244 struct IndexSharedData *shared = fdata->shared;
1245 struct IndexPrivateData *priv = fdata->priv;
1246 SendFlags replyflags = SEND_REPLY;
1247 if (event->op == OP_GROUP_REPLY)
1248 replyflags |= SEND_GROUP_REPLY;
1249 else
1250 replyflags |= SEND_GROUP_CHAT_REPLY;
1251 if (!shared->email)
1252 return FR_NO_ACTION;
1253 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
1254 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
1255 const bool c_pgp_auto_decode = cs_subset_bool(shared->sub, "pgp_auto_decode");
1256 if (c_pgp_auto_decode &&
1257 (priv->tag_prefix || !(shared->email->security & PGP_TRADITIONAL_CHECKED)))
1258 {
1259 if (mutt_check_traditional_pgp(shared->mailbox, &ea))
1261 }
1262 int rc = mutt_send_message(replyflags, NULL, NULL, shared->mailbox, &ea,
1263 shared->sub);
1264 ARRAY_FREE(&ea);
1266
1267 return (rc == -1) ? FR_ERROR : FR_SUCCESS;
1268}
1269
1273static int op_jump(struct IndexFunctionData *fdata, const struct KeyEvent *event)
1274{
1275 struct IndexSharedData *shared = fdata->shared;
1276 struct IndexPrivateData *priv = fdata->priv;
1277 int rc = FR_ERROR;
1278 struct Buffer *buf = buf_pool_get();
1279
1280 int num = event->count;
1281 if (num == 0)
1282 {
1283 if ((mw_get_field(_("Jump to message: "), buf, MUTT_COMP_NONE, HC_OTHER, NULL, NULL) != 0) ||
1284 buf_is_empty(buf))
1285 {
1286 mutt_message(_("Nothing to do"));
1287 rc = FR_NO_ACTION;
1288 goto done;
1289 }
1290
1291 if (!mutt_str_atoi_full(buf_string(buf), &num))
1292 {
1293 mutt_warning(_("Argument must be a message number"));
1294 goto done;
1295 }
1296 }
1297
1298 if ((num < 1) || (num > shared->mailbox->msg_count))
1299 {
1300 mutt_warning(_("Invalid message number"));
1301 }
1302 else if (!shared->mailbox->emails[num - 1] ||
1303 !shared->mailbox->emails[num - 1]->visible)
1304 {
1305 mutt_warning(_("That message is not visible"));
1306 }
1307 else
1308 {
1309 struct Email *e = shared->mailbox->emails[num - 1];
1310
1311 if (mutt_messages_in_thread(shared->mailbox, e, MIT_POSITION) > 1)
1312 {
1314 mutt_set_vnum(shared->mailbox);
1315 }
1316 menu_set_index(priv->menu, e->vnum);
1317 rc = FR_SUCCESS;
1318 }
1319
1320done:
1321 buf_pool_release(&buf);
1322 return rc;
1323}
1324
1328static int op_list_action(struct IndexFunctionData *fdata, const struct KeyEvent *event)
1329{
1330 struct IndexSharedData *shared = fdata->shared;
1331 struct IndexPrivateData *priv = fdata->priv;
1332
1335 return FR_SUCCESS;
1336}
1337
1341static int op_list_reply(struct IndexFunctionData *fdata, const struct KeyEvent *event)
1342{
1343 struct IndexSharedData *shared = fdata->shared;
1344 struct IndexPrivateData *priv = fdata->priv;
1345 if (!shared->email)
1346 return FR_NO_ACTION;
1347 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
1348 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
1349 const bool c_pgp_auto_decode = cs_subset_bool(shared->sub, "pgp_auto_decode");
1350 if (c_pgp_auto_decode &&
1351 (priv->tag_prefix || !(shared->email->security & PGP_TRADITIONAL_CHECKED)))
1352 {
1353 if (mutt_check_traditional_pgp(shared->mailbox, &ea))
1355 }
1356 int rc = mutt_send_message(SEND_REPLY | SEND_LIST_REPLY, NULL, NULL,
1357 shared->mailbox, &ea, shared->sub);
1358 ARRAY_FREE(&ea);
1360
1361 return (rc == -1) ? FR_ERROR : FR_SUCCESS;
1362}
1363
1367static int op_list_subscribe(struct IndexFunctionData *fdata, const struct KeyEvent *event)
1368{
1369 struct IndexSharedData *shared = fdata->shared;
1370 return mutt_send_list_subscribe(shared->mailbox, shared->email) ? FR_SUCCESS : FR_ERROR;
1371}
1372
1376static int op_list_unsubscribe(struct IndexFunctionData *fdata, const struct KeyEvent *event)
1377{
1378 struct IndexSharedData *shared = fdata->shared;
1379 return mutt_send_list_unsubscribe(shared->mailbox, shared->email) ? FR_SUCCESS : FR_ERROR;
1380}
1381
1385static int op_mail(struct IndexFunctionData *fdata, const struct KeyEvent *event)
1386{
1387 struct IndexSharedData *shared = fdata->shared;
1388 struct IndexPrivateData *priv = fdata->priv;
1389 int rc = mutt_send_message(SEND_NONE, NULL, NULL, shared->mailbox, NULL,
1390 shared->sub);
1392 return (rc == -1) ? FR_ERROR : FR_SUCCESS;
1393}
1394
1398static int op_mailbox_list(struct IndexFunctionData *fdata, const struct KeyEvent *event)
1399{
1401 return FR_SUCCESS;
1402}
1403
1407static int op_mail_key(struct IndexFunctionData *fdata, const struct KeyEvent *event)
1408{
1409 struct IndexSharedData *shared = fdata->shared;
1410 struct IndexPrivateData *priv = fdata->priv;
1411 if (!(WithCrypto & APPLICATION_PGP))
1412 return FR_NOT_IMPL;
1413 int rc = mutt_send_message(SEND_KEY, NULL, NULL, NULL, NULL, shared->sub);
1415
1416 return (rc == -1) ? FR_ERROR : FR_SUCCESS;
1417}
1418
1422static int op_main_break_thread(struct IndexFunctionData *fdata, const struct KeyEvent *event)
1423{
1424 struct IndexSharedData *shared = fdata->shared;
1425 struct IndexPrivateData *priv = fdata->priv;
1426 struct Mailbox *m = shared->mailbox;
1427 /* L10N: CHECK_ACL */
1428 if (!check_acl(m, MUTT_ACL_WRITE, _("Can't break thread")))
1429 return FR_ERROR;
1430
1431 struct Email *e = shared->email;
1432 if (!e)
1433 return FR_NO_ACTION;
1434
1435 const bool has_repeat_count = (event->count > 0);
1436
1437 if (!mutt_using_threads())
1438 {
1439 mutt_warning(_("Threading is not enabled"));
1440 return FR_ERROR;
1441 }
1442
1443 struct MailboxView *mv = shared->mailbox_view;
1444 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
1445 if (ea_add_selection(&ea, mv, e, false, event->count) <= 0)
1446 {
1447 ARRAY_FREE(&ea);
1448 return FR_NO_ACTION;
1449 }
1450
1451 bool changed = false;
1452 struct Email **ep = NULL;
1453 ARRAY_FOREACH(ep, &ea)
1454 {
1455 e = *ep;
1456 if (!e || (STAILQ_EMPTY(&e->env->in_reply_to) && STAILQ_EMPTY(&e->env->references)))
1457 continue;
1458
1459 {
1461 changed = true;
1462 }
1463 }
1464 ARRAY_FREE(&ea);
1465
1466 if (changed)
1467 {
1468 mutt_sort_headers(mv, true);
1469 menu_set_index(priv->menu, shared->email->vnum);
1470 m->changed = true;
1471 mutt_message(_("Thread broken"));
1472
1474 }
1475 else if (!has_repeat_count)
1476 {
1477 mutt_error(_("Thread can't be broken, message is not part of a thread"));
1478 return FR_ERROR;
1479 }
1480
1481 return FR_SUCCESS;
1482}
1483
1494static int op_main_change_folder(struct IndexFunctionData *fdata, const struct KeyEvent *event)
1495{
1496 struct IndexSharedData *shared = fdata->shared;
1497 struct IndexPrivateData *priv = fdata->priv;
1498 struct Buffer *folderbuf = buf_pool_get();
1499 buf_alloc(folderbuf, PATH_MAX);
1500
1501 const int op = event->op;
1502 const bool browse = (op == OP_MAIN_BROWSE_MAILBOXES) ||
1503 (op == OP_MAIN_BROWSE_MAILBOXES_READONLY);
1504 const bool c_read_only = cs_subset_bool(shared->sub, "read_only");
1505 const bool read_only = shared->attach_msg || c_read_only ||
1506 (op == OP_MAIN_BROWSE_MAILBOXES_READONLY) ||
1507 (op == OP_MAIN_CHANGE_FOLDER_READONLY);
1508
1509 if (browse)
1510 {
1512 shared->mailbox, NULL, NULL);
1513 }
1514 else
1515 {
1516 const char *cp = read_only ? _("Open mailbox in read-only mode") :
1517 _("Open mailbox");
1518
1519 const bool c_change_folder_next = cs_subset_bool(shared->sub, "change_folder_next");
1520 if (c_change_folder_next && shared->mailbox && !buf_is_empty(&shared->mailbox->pathbuf))
1521 {
1522 buf_strcpy(folderbuf, mailbox_path(shared->mailbox));
1523 pretty_mailbox(folderbuf);
1524 }
1525 /* By default, fill buf with the next mailbox that contains unread mail */
1526 mutt_mailbox_next(shared->mailbox_view ? shared->mailbox : NULL, folderbuf);
1527
1528 if (mw_enter_fname(cp, folderbuf, true, shared->mailbox, false, NULL, NULL,
1529 MUTT_SEL_NONE) == -1)
1530 {
1531 goto changefoldercleanup;
1532 }
1533 }
1534
1535 /* Selected directory is okay, let's save it. */
1537
1538 if (buf_is_empty(folderbuf))
1539 {
1540 msgwin_clear_text(NULL);
1541 goto changefoldercleanup;
1542 }
1543
1544 struct Mailbox *m = mx_mbox_find2(buf_string(folderbuf));
1545 if (m)
1546 {
1547 change_folder_mailbox(priv->menu, m, &priv->oldcount, shared, read_only);
1548 }
1549 else
1550 {
1551 change_folder_string(priv->menu, folderbuf, &priv->oldcount, shared, read_only);
1552 }
1553
1554changefoldercleanup:
1555 buf_pool_release(&folderbuf);
1557
1558 return FR_SUCCESS;
1559}
1560
1564static int op_main_collapse_all(struct IndexFunctionData *fdata, const struct KeyEvent *event)
1565{
1566 struct IndexSharedData *shared = fdata->shared;
1567 struct IndexPrivateData *priv = fdata->priv;
1568 if (!mutt_using_threads())
1569 {
1570 mutt_warning(_("Threading is not enabled"));
1571 return FR_ERROR;
1572 }
1575
1576 return FR_SUCCESS;
1577}
1578
1583 const struct KeyEvent *event)
1584{
1585 struct IndexSharedData *shared = fdata->shared;
1586 struct IndexPrivateData *priv = fdata->priv;
1587 if (!mutt_using_threads())
1588 {
1589 mutt_warning(_("Threading is not enabled"));
1590 return FR_ERROR;
1591 }
1592
1594 return FR_NO_ACTION;
1595
1598
1599 return FR_SUCCESS;
1600}
1601
1605static int op_main_close_thread(struct IndexFunctionData *fdata, const struct KeyEvent *event)
1606{
1607 struct IndexSharedData *shared = fdata->shared;
1608 struct IndexPrivateData *priv = fdata->priv;
1609 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
1610 ea_add_selection_threads(&ea, shared->mailbox_view, shared->email,
1611 priv->tag_prefix, false, event->count);
1612 const int rc = op_main_change_thread(fdata, &ea, COLLAPSE_MODE_CLOSE);
1613 ARRAY_FREE(&ea);
1614 return rc;
1615}
1616
1620static int op_main_collapse_thread(struct IndexFunctionData *fdata, const struct KeyEvent *event)
1621{
1622 struct IndexSharedData *shared = fdata->shared;
1623 struct IndexPrivateData *priv = fdata->priv;
1624 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
1625 ea_add_selection_threads(&ea, shared->mailbox_view, shared->email,
1626 priv->tag_prefix, false, event->count);
1627 const int rc = op_main_change_thread(fdata, &ea, COLLAPSE_MODE_TOGGLE);
1628 ARRAY_FREE(&ea);
1629 return rc;
1630}
1631
1636 const struct KeyEvent *event)
1637{
1638 struct IndexSharedData *shared = fdata->shared;
1639 struct IndexPrivateData *priv = fdata->priv;
1640 if (!mutt_using_threads())
1641 {
1642 mutt_warning(_("Threading is not enabled"));
1643 return FR_ERROR;
1644 }
1645
1647 return FR_NO_ACTION;
1648
1651
1652 return FR_SUCCESS;
1653}
1654
1658static int op_main_open_thread(struct IndexFunctionData *fdata, const struct KeyEvent *event)
1659{
1660 struct IndexSharedData *shared = fdata->shared;
1661 struct IndexPrivateData *priv = fdata->priv;
1662 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
1663 ea_add_selection_threads(&ea, shared->mailbox_view, shared->email,
1664 priv->tag_prefix, false, event->count);
1665 const int rc = op_main_change_thread(fdata, &ea, COLLAPSE_MODE_OPEN);
1666 ARRAY_FREE(&ea);
1667 return rc;
1668}
1669
1677static int op_main_delete_pattern(struct IndexFunctionData *fdata, const struct KeyEvent *event)
1678{
1679 struct IndexSharedData *shared = fdata->shared;
1680 struct IndexPrivateData *priv = fdata->priv;
1681 /* L10N: CHECK_ACL */
1682 /* L10N: Due to the implementation details we do not know whether we
1683 delete zero, 1, 12, ... messages. So in English we use
1684 "messages". Your language might have other means to express this. */
1685 if (!check_acl(shared->mailbox, MUTT_ACL_DELETE, _("Can't delete messages")))
1686 return FR_ERROR;
1687
1688 const bool purge = (event->op == OP_PURGE_PATTERN);
1689 mutt_pattern_func(shared->mailbox_view, MUTT_DELETE, _("Delete messages matching: "));
1690 if (purge)
1693
1694 return FR_SUCCESS;
1695}
1696
1705static int op_main_limit(struct IndexFunctionData *fdata, const struct KeyEvent *event)
1706{
1707 struct IndexSharedData *shared = fdata->shared;
1708 struct IndexPrivateData *priv = fdata->priv;
1709 const bool lmt = mview_has_limit(shared->mailbox_view);
1710 int old_index = shared->email ? shared->email->index : -1;
1711 const int op = event->op;
1712 if (op == OP_TOGGLE_READ)
1713 {
1714 struct Buffer *buf2 = buf_pool_get();
1715
1716 if (!lmt || !mutt_strn_equal(shared->mailbox_view->pattern, "!~R!~D~s", 8))
1717 {
1718 buf_printf(buf2, "!~R!~D~s%s", lmt ? shared->mailbox_view->pattern : ".*");
1719 }
1720 else
1721 {
1722 const char *pat = shared->mailbox_view->pattern + 8;
1723 if ((*pat == '\0') || mutt_strn_equal(pat, ".*", 2))
1724 buf_strcpy(buf2, "~A");
1725 else
1726 buf_strcpy(buf2, pat);
1727 }
1729 buf_pool_release(&buf2);
1731 }
1732
1733 if (((op == OP_LIMIT_CURRENT_THREAD) &&
1734 mutt_limit_current_thread(shared->mailbox_view, shared->email)) ||
1735 (op == OP_TOGGLE_READ) ||
1736 ((op == OP_MAIN_LIMIT) && (mutt_pattern_func(shared->mailbox_view, MUTT_LIMIT,
1737 _("Limit to messages matching: ")) == 0)))
1738 {
1739 priv->menu->max = shared->mailbox->vcount;
1740 menu_set_index(priv->menu, 0);
1741 if (old_index >= 0)
1742 {
1743 /* try to find what used to be the current message */
1744 for (size_t i = 0; i < shared->mailbox->vcount; i++)
1745 {
1746 struct Email *e = mutt_get_virt_email(shared->mailbox, i);
1747 if (!e)
1748 continue;
1749 if (e->index == old_index)
1750 {
1751 menu_set_index(priv->menu, i);
1752 break;
1753 }
1754 }
1755 }
1756
1757 if ((shared->mailbox->msg_count != 0) && mutt_using_threads())
1758 {
1759 const bool c_collapse_all = cs_subset_bool(shared->sub, "collapse_all");
1760 if (c_collapse_all)
1763 }
1764 notify_send(shared->notify, NT_INDEX, NT_INDEX_EMAIL, NULL);
1766 }
1767 if (lmt)
1768 mutt_message(_("To view all messages, limit to \"all\""));
1769
1770 return FR_SUCCESS;
1771}
1772
1779static int op_main_link_threads(struct IndexFunctionData *fdata, const struct KeyEvent *event)
1780{
1781 struct IndexSharedData *shared = fdata->shared;
1782 struct IndexPrivateData *priv = fdata->priv;
1783 struct Mailbox *m = shared->mailbox;
1784 /* L10N: CHECK_ACL */
1785 if (!check_acl(m, MUTT_ACL_WRITE, _("Can't link threads")))
1786 return FR_ERROR;
1787
1788 struct Email *e = shared->email;
1789 if (!e)
1790 return FR_NO_ACTION;
1791
1792 enum FunctionRetval rc = FR_ERROR;
1793
1794 if (!mutt_using_threads())
1795 {
1796 mutt_warning(_("Threading is not enabled"));
1797 rc = FR_ERROR;
1798 }
1799 else if (!e->env->message_id)
1800 {
1801 mutt_error(_("No Message-ID: header available to link thread"));
1802 }
1803 else
1804 {
1805 struct MailboxView *mv = shared->mailbox_view;
1806 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
1807
1808 // If there's a repeat-count, use it.
1809 // If not, behave as if <tag-prefix> has been pressed.
1810 const bool tag_prefix = (event->count < 1);
1811 ea_add_selection(&ea, mv, e, tag_prefix, event->count);
1812
1813 if (!tag_prefix)
1814 {
1815 struct Email **ep = ARRAY_GET(&ea, 0);
1816 if (ep && (*ep == e))
1817 ARRAY_REMOVE(&ea, ep);
1818 }
1819
1820 if (mutt_link_threads(e, &ea, m))
1821 {
1822 mutt_sort_headers(mv, true);
1823 menu_set_index(priv->menu, e->vnum);
1824
1825 m->changed = true;
1826 mutt_message(_("Threads linked"));
1827 rc = FR_SUCCESS;
1828 }
1829 else
1830 {
1831 mutt_error(_("No thread linked"));
1832 rc = FR_ERROR;
1833 }
1834
1835 ARRAY_FREE(&ea);
1836 }
1837
1839 return rc;
1840}
1841
1849static int op_main_modify_tags(struct IndexFunctionData *fdata, const struct KeyEvent *event)
1850{
1851 struct IndexSharedData *shared = fdata->shared;
1852 struct IndexPrivateData *priv = fdata->priv;
1853 int rc = FR_ERROR;
1854 struct Buffer *buf = NULL;
1855 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
1856
1857 if (!shared->mailbox)
1858 goto done;
1859 struct Mailbox *m = shared->mailbox;
1860 if (!mx_tags_is_supported(m))
1861 {
1862 mutt_message(_("Folder doesn't support tagging, aborting"));
1863 goto done;
1864 }
1865 if (!shared->email)
1866 {
1867 rc = FR_NO_ACTION;
1868 goto done;
1869 }
1870
1871 const int op = event->op;
1872 struct Buffer *tags = buf_pool_get();
1873 if (!priv->tag_prefix)
1874 driver_tags_get_with_hidden(&shared->email->tags, tags);
1875 /* Prompt the user to edit the tag string */
1876 buf = buf_pool_get();
1877 int rc2 = mx_tags_edit(m, buf_string(tags), buf);
1878 buf_pool_release(&tags);
1879 if (rc2 < 0)
1880 {
1881 goto done;
1882 }
1883 else if (rc2 == 0)
1884 {
1885 mutt_message(_("No tag specified, aborting"));
1886 goto done;
1887 }
1888
1889 ea_add_selection(&ea, shared->mailbox_view, shared->email, priv->tag_prefix,
1890 event->count);
1891 const int num = ARRAY_SIZE(&ea);
1892
1893 if (priv->tag_prefix || (num > 1))
1894 {
1895 struct Progress *progress = NULL;
1896
1897 if (m->verbose)
1898 {
1899 progress = progress_new(MUTT_PROGRESS_WRITE, num);
1900 progress_set_message(progress, _("Update tags..."));
1901 }
1902
1903#ifdef USE_NOTMUCH
1904 if (m->type == MUTT_NOTMUCH)
1905 nm_db_longrun_init(m, true);
1906#endif
1907 struct Email **ep = NULL;
1908 int px = 0;
1909 ARRAY_FOREACH(ep, &ea)
1910 {
1911 struct Email *e = *ep;
1912
1913 progress_update(progress, ++px, -1);
1914 mx_tags_commit(m, e, buf_string(buf));
1915 e->attr_color = NULL;
1916 if (op == OP_MAIN_MODIFY_TAGS_THEN_HIDE)
1917 {
1918 bool still_queried = false;
1919#ifdef USE_NOTMUCH
1920 if (m->type == MUTT_NOTMUCH)
1921 still_queried = nm_message_is_still_queried(m, e);
1922#endif
1923 e->quasi_deleted = !still_queried;
1924 m->changed = true;
1925 }
1926 }
1927 progress_free(&progress);
1928#ifdef USE_NOTMUCH
1929 if (m->type == MUTT_NOTMUCH)
1931#endif
1933 if (!priv->tag_prefix)
1935 (op == OP_MAIN_MODIFY_TAGS_THEN_HIDE) ? 1 : num);
1936 }
1937 else
1938 {
1939 if (mx_tags_commit(m, shared->email, buf_string(buf)))
1940 {
1941 mutt_message(_("Failed to modify tags, aborting"));
1942 goto done;
1943 }
1944 shared->email->attr_color = NULL;
1945 if (op == OP_MAIN_MODIFY_TAGS_THEN_HIDE)
1946 {
1947 bool still_queried = false;
1948#ifdef USE_NOTMUCH
1949 if (m->type == MUTT_NOTMUCH)
1950 still_queried = nm_message_is_still_queried(m, shared->email);
1951#endif
1952 shared->email->quasi_deleted = !still_queried;
1953 m->changed = true;
1954 }
1955
1957 (op == OP_MAIN_MODIFY_TAGS_THEN_HIDE) ? 1 : num);
1958 }
1959 rc = FR_SUCCESS;
1960
1961done:
1962 ARRAY_FREE(&ea);
1963 buf_pool_release(&buf);
1964 return rc;
1965}
1966
1987static int find_next_new_email(struct Mailbox *m, int start, bool forwards, int op)
1988{
1989 int first_unread = -1;
1990 int first_new = -1;
1991 int mcur = start;
1992 const bool threaded = mutt_using_threads();
1993
1994 for (int i = 0; i < m->vcount; i++)
1995 {
1996 if (forwards)
1997 {
1998 mcur++;
1999 if (mcur > (m->vcount - 1))
2000 mcur = 0;
2001 }
2002 else
2003 {
2004 mcur--;
2005 if (mcur < 0)
2006 mcur = m->vcount - 1;
2007 }
2008
2009 struct Email *e = mutt_get_virt_email(m, mcur);
2010 if (!e)
2011 break;
2012 if (e->collapsed && threaded)
2013 {
2014 int unread = mutt_thread_contains_unread(e);
2015 if ((unread != 0) && (first_unread == -1))
2016 first_unread = mcur;
2017 if ((unread == 1) && (first_new == -1))
2018 first_new = mcur;
2019 }
2020 else if (!e->deleted && !e->read)
2021 {
2022 if (first_unread == -1)
2023 first_unread = mcur;
2024 if (!e->old && (first_new == -1))
2025 first_new = mcur;
2026 }
2027
2028 if (((op == OP_MAIN_NEXT_UNREAD) || (op == OP_MAIN_PREV_UNREAD)) && (first_unread != -1))
2029 break;
2030 if (((op == OP_MAIN_NEXT_NEW) || (op == OP_MAIN_PREV_NEW) ||
2031 (op == OP_MAIN_NEXT_NEW_THEN_UNREAD) || (op == OP_MAIN_PREV_NEW_THEN_UNREAD)) &&
2032 (first_new != -1))
2033 {
2034 break;
2035 }
2036 }
2037
2038 if (((op == OP_MAIN_NEXT_NEW) || (op == OP_MAIN_PREV_NEW) ||
2039 (op == OP_MAIN_NEXT_NEW_THEN_UNREAD) || (op == OP_MAIN_PREV_NEW_THEN_UNREAD)) &&
2040 (first_new != -1))
2041 {
2042 return first_new;
2043 }
2044 if (((op == OP_MAIN_NEXT_UNREAD) || (op == OP_MAIN_PREV_UNREAD) ||
2045 (op == OP_MAIN_NEXT_NEW_THEN_UNREAD) || (op == OP_MAIN_PREV_NEW_THEN_UNREAD)) &&
2046 (first_unread != -1))
2047 {
2048 return first_unread;
2049 }
2050
2051 return -1;
2052}
2053
2054static int op_main_next_new(struct IndexFunctionData *fdata, const struct KeyEvent *event)
2055{
2056 struct IndexSharedData *shared = fdata->shared;
2057 struct IndexPrivateData *priv = fdata->priv;
2058
2059 const int saved_current = menu_get_index(priv->menu);
2060 const int op = event->op;
2061 const bool forwards = (op == OP_MAIN_NEXT_NEW) || (op == OP_MAIN_NEXT_UNREAD) ||
2062 (op == OP_MAIN_NEXT_NEW_THEN_UNREAD);
2063 const int count = event->count;
2064
2065 if (count > 0)
2066 {
2067 int cur = saved_current;
2068 int last_good = saved_current;
2069 for (int i = 0; i < count; i++)
2070 {
2071 int next = find_next_new_email(shared->mailbox, cur, forwards, op);
2072 if (next == -1)
2073 break;
2074 last_good = next;
2075 cur = next;
2076 }
2077 if (last_good != saved_current)
2078 menu_set_index(priv->menu, last_good);
2079 return FR_SUCCESS;
2080 }
2081
2082 int index = find_next_new_email(shared->mailbox, saved_current, forwards, op);
2083
2084 if (index == -1)
2085 {
2086 menu_set_index(priv->menu, saved_current);
2087 if ((op == OP_MAIN_NEXT_NEW) || (op == OP_MAIN_PREV_NEW))
2088 {
2090 mutt_error(_("No new messages in this limited view"));
2091 else
2092 mutt_error(_("No new messages"));
2093 }
2094 else
2095 {
2097 mutt_error(_("No unread messages in this limited view"));
2098 else
2099 mutt_error(_("No unread messages"));
2100 }
2102 return FR_ERROR;
2103 }
2104
2105 menu_set_index(priv->menu, index);
2106
2107 index = menu_get_index(priv->menu);
2108 if (forwards)
2109 {
2110 if (saved_current > index)
2111 {
2112 mutt_message(_("Search wrapped to top"));
2113 }
2114 }
2115 else if (saved_current < index)
2116 {
2117 mutt_message(_("Search wrapped to bottom"));
2118 }
2119
2120 return FR_SUCCESS;
2121}
2122
2132static int op_main_next_thread(struct IndexFunctionData *fdata, const struct KeyEvent *event)
2133{
2134 struct IndexSharedData *shared = fdata->shared;
2135 struct IndexPrivateData *priv = fdata->priv;
2136 const int op = event->op;
2137 const int count = event->count;
2138 const bool forwards = (op == OP_MAIN_NEXT_THREAD) || (op == OP_MAIN_NEXT_SUBTHREAD);
2139 const bool subthreads = (op == OP_MAIN_NEXT_SUBTHREAD) || (op == OP_MAIN_PREV_SUBTHREAD);
2140
2141 if (count > 0)
2142 {
2143 for (int i = 0; i < count; i++)
2144 {
2145 int index = mutt_aside_thread(shared->email, forwards, subthreads);
2146 if (index == -1)
2147 break;
2148 menu_set_index(priv->menu, index);
2149 }
2150 return FR_SUCCESS;
2151 }
2152
2153 int index = mutt_aside_thread(shared->email, forwards, subthreads);
2154
2155 if (index != -1)
2156 menu_set_index(priv->menu, index);
2157
2158 if (index < 0)
2159 {
2160 if (forwards)
2161 mutt_error(_("No more threads"));
2162 else
2163 mutt_error(_("You are on the first thread"));
2164
2166 return FR_ERROR;
2167 }
2168
2169 return FR_SUCCESS;
2170}
2171
2175static int op_main_next_undeleted(struct IndexFunctionData *fdata, const struct KeyEvent *event)
2176{
2177 struct IndexSharedData *shared = fdata->shared;
2178 struct IndexPrivateData *priv = fdata->priv;
2179 const int count = event->count;
2180 int index = menu_get_index(priv->menu);
2181
2182 if (count > 0)
2183 {
2184 const bool uncollapse = mutt_using_threads() && !window_is_focused(priv->win_index);
2185 int last_good = index;
2186 for (int i = 0; i < count; i++)
2187 {
2188 int next = find_next_undeleted(shared->mailbox_view, index, uncollapse);
2189 if (next == -1)
2190 break;
2191 last_good = next;
2192 index = next;
2193 }
2194 if (last_good != menu_get_index(priv->menu))
2195 {
2196 menu_set_index(priv->menu, last_good);
2197 if (uncollapse)
2199 }
2200 return FR_SUCCESS;
2201 }
2202
2203 if (index >= (shared->mailbox->vcount - 1))
2204 {
2206 mutt_message(_("You are on the last message"));
2207 return FR_ERROR;
2208 }
2209
2210 const bool uncollapse = mutt_using_threads() && !window_is_focused(priv->win_index);
2211
2212 index = find_next_undeleted(shared->mailbox_view, index, uncollapse);
2213 if (index != -1)
2214 {
2215 menu_set_index(priv->menu, index);
2216 if (uncollapse)
2218 }
2219
2220 if (index == -1)
2221 {
2223 mutt_error(_("No undeleted messages"));
2224 return FR_ERROR;
2225 }
2226
2227 return FR_SUCCESS;
2228}
2229
2234 const struct KeyEvent *event)
2235{
2236 struct IndexSharedData *shared = fdata->shared;
2237 struct IndexPrivateData *priv = fdata->priv;
2238 struct Mailbox *m = shared->mailbox;
2239
2240 struct Buffer *folderbuf = buf_pool_get();
2241 buf_strcpy(folderbuf, mailbox_path(m));
2242 m = mutt_mailbox_next_unread(m, folderbuf);
2243 buf_pool_release(&folderbuf);
2244
2245 if (!m)
2246 {
2247 mutt_error(_("No mailboxes have new mail"));
2248 return FR_ERROR;
2249 }
2250
2251 change_folder_mailbox(priv->menu, m, &priv->oldcount, shared, false);
2252 return FR_SUCCESS;
2253}
2254
2259 const struct KeyEvent *event)
2260{
2261 struct IndexSharedData *shared = fdata->shared;
2262 struct IndexPrivateData *priv = fdata->priv;
2263 struct Mailbox *m = shared->mailbox;
2264
2265 struct Buffer *folderbuf = buf_pool_get();
2266 buf_strcpy(folderbuf, mailbox_path(m));
2267 m = mutt_mailbox_prev_unread(m, folderbuf);
2268 buf_pool_release(&folderbuf);
2269
2270 if (!m)
2271 {
2272 mutt_error(_("No mailboxes have new mail"));
2273 return FR_ERROR;
2274 }
2275
2276 change_folder_mailbox(priv->menu, m, &priv->oldcount, shared, false);
2277 return FR_SUCCESS;
2278}
2279
2283static int op_main_prev_undeleted(struct IndexFunctionData *fdata, const struct KeyEvent *event)
2284{
2285 struct IndexSharedData *shared = fdata->shared;
2286 struct IndexPrivateData *priv = fdata->priv;
2287 const int count = event->count;
2288 int index = menu_get_index(priv->menu);
2289
2290 if (count > 0)
2291 {
2292 const bool uncollapse = mutt_using_threads() && !window_is_focused(priv->win_index);
2293 int last_good = index;
2294 for (int i = 0; i < count; i++)
2295 {
2296 int prev = find_previous_undeleted(shared->mailbox_view, index, uncollapse);
2297 if (prev == -1)
2298 break;
2299 last_good = prev;
2300 index = prev;
2301 }
2302 if (last_good != menu_get_index(priv->menu))
2303 {
2304 menu_set_index(priv->menu, last_good);
2305 if (uncollapse)
2307 }
2308 return FR_SUCCESS;
2309 }
2310
2311 if (index < 1)
2312 {
2314 mutt_message(_("You are on the first message"));
2315 return FR_ERROR;
2316 }
2317
2318 const bool uncollapse = mutt_using_threads() && !window_is_focused(priv->win_index);
2319
2320 index = find_previous_undeleted(shared->mailbox_view, index, uncollapse);
2321 if (index != -1)
2322 {
2323 menu_set_index(priv->menu, index);
2324 if (uncollapse)
2326 }
2327
2328 if (index == -1)
2329 {
2330 mutt_error(_("No undeleted messages"));
2332 return FR_ERROR;
2333 }
2334
2335 return FR_SUCCESS;
2336}
2337
2341static int op_main_quasi_delete(struct IndexFunctionData *fdata, const struct KeyEvent *event)
2342{
2343 struct IndexSharedData *shared = fdata->shared;
2344 struct IndexPrivateData *priv = fdata->priv;
2345 struct Mailbox *m = shared->mailbox;
2346 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
2347 ea_add_selection(&ea, shared->mailbox_view, shared->email, priv->tag_prefix,
2348 event->count);
2349 if (ARRAY_EMPTY(&ea))
2350 {
2351 ARRAY_FREE(&ea);
2352 return FR_NO_ACTION;
2353 }
2354 const int num = ARRAY_SIZE(&ea);
2355
2356 struct Email **ep = NULL;
2357 ARRAY_FOREACH(ep, &ea)
2358 {
2359 (*ep)->quasi_deleted = true;
2360 m->changed = true;
2361 }
2362 ARRAY_FREE(&ea);
2363
2364 if (priv->tag_prefix || (num > 1))
2366
2367 return FR_SUCCESS;
2368}
2369
2377static int op_main_read_thread(struct IndexFunctionData *fdata, const struct KeyEvent *event)
2378{
2379 struct IndexSharedData *shared = fdata->shared;
2380 struct IndexPrivateData *priv = fdata->priv;
2381 /* L10N: CHECK_ACL */
2382 /* L10N: Due to the implementation details we do not know whether we
2383 mark zero, 1, 12, ... messages as read. So in English we use
2384 "messages". Your language might have other means to express this. */
2385 if (!check_acl(shared->mailbox, MUTT_ACL_SEEN, _("Can't mark messages as read")))
2386 return FR_ERROR;
2387
2388 const int op = event->op;
2389 const bool subthread = (op != OP_MAIN_READ_THREAD);
2390 int rc = 0;
2391 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
2392 ea_add_selection_threads(&ea, shared->mailbox_view, shared->email,
2393 priv->tag_prefix, subthread, event->count);
2394 const int num = ARRAY_SIZE(&ea);
2395
2396 struct Email **ep = NULL;
2397 ARRAY_FOREACH(ep, &ea)
2398 {
2399 rc = mutt_thread_set_flag(shared->mailbox, *ep, MUTT_READ, true, subthread);
2400 if (rc == -1)
2401 break;
2402 }
2403 ARRAY_FREE(&ea);
2404
2405 if (rc == -1)
2406 return FR_ERROR;
2407
2408 if (priv->tag_prefix)
2409 {
2411 return FR_SUCCESS;
2412 }
2413
2414 const enum ResolveMethod rm = (op == OP_MAIN_READ_THREAD) ? RESOLVE_NEXT_THREAD :
2416 resolve_email(priv, shared, rm, num);
2418 return FR_SUCCESS;
2419}
2420
2431static int op_main_root_message(struct IndexFunctionData *fdata, const struct KeyEvent *event)
2432{
2433 struct IndexSharedData *shared = fdata->shared;
2434 struct IndexPrivateData *priv = fdata->priv;
2435 int count = event->op == OP_MAIN_ROOT_MESSAGE ? 0 : MAX(event->count, 1);
2436 int index = mutt_parent_message(shared->email, event->op == OP_MAIN_ROOT_MESSAGE, count);
2437 if (index != -1)
2438 menu_set_index(priv->menu, index);
2439
2440 return FR_SUCCESS;
2441}
2442
2450static int op_main_set_flag(struct IndexFunctionData *fdata, const struct KeyEvent *event)
2451{
2452 struct IndexSharedData *shared = fdata->shared;
2453 struct IndexPrivateData *priv = fdata->priv;
2454 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
2455 ea_add_selection(&ea, shared->mailbox_view, shared->email, priv->tag_prefix,
2456 event->count);
2457 if (ARRAY_EMPTY(&ea))
2458 {
2459 ARRAY_FREE(&ea);
2460 return FR_NO_ACTION;
2461 }
2462 const int num = ARRAY_SIZE(&ea);
2463
2464 if (mw_change_flag(shared->mailbox, &ea, (event->op == OP_MAIN_SET_FLAG)) == 0)
2465 {
2466 if (priv->tag_prefix)
2467 {
2469 }
2470 else
2471 {
2472 resolve_email(priv, shared, RESOLVE_NEXT_UNDELETED, num);
2473 if (num > 1)
2475 }
2476 }
2477 ARRAY_FREE(&ea);
2478
2479 return FR_SUCCESS;
2480}
2481
2485static int op_main_show_limit(struct IndexFunctionData *fdata, const struct KeyEvent *event)
2486{
2487 struct IndexSharedData *shared = fdata->shared;
2488 if (mview_has_limit(shared->mailbox_view))
2489 {
2490 struct Buffer *buf = buf_pool_get();
2491 /* L10N: ask for a limit to apply */
2492 buf_printf(buf, _("Limit: %s"), shared->mailbox_view->pattern);
2493 mutt_message("%s", buf_string(buf));
2494 buf_pool_release(&buf);
2495 }
2496 else
2497 {
2498 mutt_message(_("No limit pattern is in effect"));
2499 }
2500
2501 return FR_SUCCESS;
2502}
2503
2507static int op_main_sync_folder(struct IndexFunctionData *fdata, const struct KeyEvent *event)
2508{
2509 struct IndexSharedData *shared = fdata->shared;
2510 struct IndexPrivateData *priv = fdata->priv;
2512 return FR_NO_ACTION;
2513
2514 int ovc = shared->mailbox->vcount;
2515 int oc = shared->mailbox->msg_count;
2516 struct Email *e = NULL;
2517
2518 /* don't attempt to move the cursor if there are no visible messages in the current limit */
2519 int index = menu_get_index(priv->menu);
2520 if (index < shared->mailbox->vcount)
2521 {
2522 /* threads may be reordered, so figure out what header the cursor
2523 * should be on. */
2524 int newidx = index;
2525 if (!shared->email)
2526 return FR_NO_ACTION;
2527 if (shared->email->deleted)
2528 newidx = find_next_undeleted(shared->mailbox_view, index, false);
2529 if (newidx < 0)
2530 newidx = find_previous_undeleted(shared->mailbox_view, index, false);
2531 if (newidx >= 0)
2532 e = mutt_get_virt_email(shared->mailbox, newidx);
2533 }
2534
2535 enum MxStatus check = mx_mbox_sync(shared->mailbox);
2536 if (check == MX_STATUS_OK)
2537 {
2538 if (e && (shared->mailbox->vcount != ovc))
2539 {
2540 for (size_t i = 0; i < shared->mailbox->vcount; i++)
2541 {
2542 struct Email *e2 = mutt_get_virt_email(shared->mailbox, i);
2543 if (e2 == e)
2544 {
2545 menu_set_index(priv->menu, i);
2546 break;
2547 }
2548 }
2549 }
2551 }
2552 else if ((check == MX_STATUS_NEW_MAIL) || (check == MX_STATUS_REOPENED))
2553 {
2554 update_index(priv->menu, shared->mailbox_view, check, oc, shared);
2555 }
2556
2557 /* do a sanity check even if mx_mbox_sync failed. */
2558
2559 index = menu_get_index(priv->menu);
2560 if ((index < 0) || (shared->mailbox && (index >= shared->mailbox->vcount)))
2561 {
2563 }
2564
2565 /* check for a fatal error, or all messages deleted */
2566 if (shared->mailbox && buf_is_empty(&shared->mailbox->pathbuf))
2567 {
2568 mview_free(&shared->mailbox_view);
2569 }
2570
2571 if (shared->mailbox)
2572 {
2573 priv->menu->max = shared->mailbox->vcount;
2575
2576 struct EventMailbox ev_m = { shared->mailbox };
2578 }
2579 else
2580 {
2581 priv->menu->max = 0;
2583 }
2584
2585 return FR_SUCCESS;
2586}
2587
2591static int op_main_tag_pattern(struct IndexFunctionData *fdata, const struct KeyEvent *event)
2592{
2593 struct IndexSharedData *shared = fdata->shared;
2594 struct IndexPrivateData *priv = fdata->priv;
2595 mutt_pattern_func(shared->mailbox_view, MUTT_TAG, _("Tag messages matching: "));
2597
2598 return FR_SUCCESS;
2599}
2600
2605 const struct KeyEvent *event)
2606{
2607 struct IndexSharedData *shared = fdata->shared;
2608 struct IndexPrivateData *priv = fdata->priv;
2609 /* L10N: CHECK_ACL */
2610 /* L10N: Due to the implementation details we do not know whether we
2611 undelete zero, 1, 12, ... messages. So in English we use
2612 "messages". Your language might have other means to express this. */
2613 if (!check_acl(shared->mailbox, MUTT_ACL_DELETE, _("Can't undelete messages")))
2614 return FR_ERROR;
2615
2617 _("Undelete messages matching: ")) == 0)
2618 {
2620 }
2621
2622 return FR_SUCCESS;
2623}
2624
2628static int op_main_untag_pattern(struct IndexFunctionData *fdata, const struct KeyEvent *event)
2629{
2630 struct IndexSharedData *shared = fdata->shared;
2631 struct IndexPrivateData *priv = fdata->priv;
2632 if (mutt_pattern_func(shared->mailbox_view, MUTT_UNTAG, _("Untag messages matching: ")) == 0)
2634
2635 return FR_SUCCESS;
2636}
2637
2641static int op_mark_msg(struct IndexFunctionData *fdata, const struct KeyEvent *event)
2642{
2643 struct IndexSharedData *shared = fdata->shared;
2644 if (!shared->email)
2645 return FR_NO_ACTION;
2646
2647 int rc = FR_SUCCESS;
2648
2649 if (shared->email->env->message_id)
2650 {
2651 struct Buffer *buf = buf_pool_get();
2652
2653 /* L10N: This is the prompt for <mark-message>. Whatever they
2654 enter will be prefixed by $mark_macro_prefix and will become
2655 a macro hotkey to jump to the currently selected message. */
2656 if ((mw_get_field(_("Enter macro stroke: "), buf, MUTT_COMP_NONE, HC_OTHER,
2657 NULL, NULL) == 0) &&
2658 !buf_is_empty(buf))
2659 {
2660 const char *const c_mark_macro_prefix = cs_subset_string(shared->sub, "mark_macro_prefix");
2661 char str[256] = { 0 };
2662 snprintf(str, sizeof(str), "%s%s", c_mark_macro_prefix, buf_string(buf));
2663
2664 struct Buffer *msg_id = buf_pool_get();
2665 mutt_file_sanitize_regex(msg_id, shared->email->env->message_id);
2666 char macro[256] = { 0 };
2667 snprintf(macro, sizeof(macro), "<search>~i '%s'\n", buf_string(msg_id));
2668 buf_pool_release(&msg_id);
2669
2670 /* L10N: "message hotkey" is the key bindings menu description of a
2671 macro created by <mark-message>. */
2672 km_bind(fdata->mod_data->md_index, str, OP_MACRO, macro, _("message hotkey"), NULL);
2673
2674 /* L10N: This is echoed after <mark-message> creates a new hotkey
2675 macro. %s is the hotkey string ($mark_macro_prefix followed
2676 by whatever they typed at the prompt.) */
2677 buf_printf(buf, _("Message bound to %s"), str);
2678 mutt_message("%s", buf_string(buf));
2679 mutt_debug(LL_DEBUG1, "Mark: %s => %s\n", str, macro);
2680 }
2681 buf_pool_release(&buf);
2682 }
2683 else
2684 {
2685 /* L10N: This error is printed if <mark-message> can't find a
2686 Message-ID for the currently selected message in the index. */
2687 mutt_error(_("No message ID to macro"));
2688 rc = FR_ERROR;
2689 }
2690
2691 return rc;
2692}
2693
2697static int op_next_entry(struct IndexFunctionData *fdata, const struct KeyEvent *event)
2698{
2699 struct IndexSharedData *shared = fdata->shared;
2700 struct IndexPrivateData *priv = fdata->priv;
2701 int count = MAX(event->count, 1);
2702 int index = menu_get_index(priv->menu) + count;
2703
2704 if (index >= shared->mailbox->vcount)
2705 {
2706 index = shared->mailbox->vcount - 1;
2707 if (event->count == 0)
2708 {
2709 mutt_message(_("You are on the last message"));
2711 }
2712 }
2713
2714 menu_set_index(priv->menu, index);
2715 return FR_SUCCESS;
2716}
2717
2721static int op_pipe(struct IndexFunctionData *fdata, const struct KeyEvent *event)
2722{
2723 struct IndexSharedData *shared = fdata->shared;
2724 struct IndexPrivateData *priv = fdata->priv;
2725 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
2726 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
2727 mutt_pipe_message(shared->mailbox, &ea);
2728 ARRAY_FREE(&ea);
2729
2730 /* in an IMAP folder index with imap_peek=no, piping could change
2731 * new or old messages status to read. Redraw what's needed. */
2732 const bool c_imap_peek = cs_subset_bool(shared->sub, "imap_peek");
2733 if ((shared->mailbox->type == MUTT_IMAP) && !c_imap_peek)
2734 {
2736 }
2737
2738 return FR_SUCCESS;
2739}
2740
2744static int op_prev_entry(struct IndexFunctionData *fdata, const struct KeyEvent *event)
2745{
2746 struct IndexSharedData *shared = fdata->shared;
2747 struct IndexPrivateData *priv = fdata->priv;
2748 int count = MAX(event->count, 1);
2749 int index = menu_get_index(priv->menu) - count;
2750
2751 if (index < 0)
2752 {
2753 index = 0;
2754 if (event->count == 0)
2755 {
2757 mutt_message(_("You are on the first message"));
2758 }
2759 }
2760
2761 menu_set_index(priv->menu, index);
2762 return FR_SUCCESS;
2763}
2764
2768static int op_print(struct IndexFunctionData *fdata, const struct KeyEvent *event)
2769{
2770 struct IndexSharedData *shared = fdata->shared;
2771 struct IndexPrivateData *priv = fdata->priv;
2772 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
2773 ea_add_selection(&ea, shared->mailbox_view, shared->email, priv->tag_prefix,
2774 event->count);
2775 if (ARRAY_EMPTY(&ea))
2776 {
2777 ARRAY_FREE(&ea);
2778 return FR_NO_ACTION;
2779 }
2780 const int num = ARRAY_SIZE(&ea);
2781 const bool printed = mutt_print_message(shared->mailbox, &ea);
2782 ARRAY_FREE(&ea);
2783
2784 if (printed && !priv->tag_prefix)
2785 resolve_email(priv, shared, RESOLVE_NEXT_EMAIL, num);
2786
2787 /* in an IMAP folder index with imap_peek=no, printing could change
2788 * new or old messages status to read. Redraw what's needed. */
2789 const bool c_imap_peek = cs_subset_bool(shared->sub, "imap_peek");
2790 if (printed && (shared->mailbox->type == MUTT_IMAP) && !c_imap_peek)
2791 {
2792 menu_queue_redraw(priv->menu,
2793 ((priv->tag_prefix || (num > 1)) ? MENU_REDRAW_INDEX : MENU_REDRAW_CURRENT));
2794 }
2795
2796 return FR_SUCCESS;
2797}
2798
2802static int op_query(struct IndexFunctionData *fdata, const struct KeyEvent *event)
2803{
2804 struct IndexSharedData *shared = fdata->shared;
2805 query_index(shared->mailbox, shared->sub);
2806 return FR_SUCCESS;
2807}
2808
2812static int op_quit(struct IndexFunctionData *fdata, const struct KeyEvent *event)
2813{
2814 struct IndexSharedData *shared = fdata->shared;
2815 struct IndexPrivateData *priv = fdata->priv;
2816 if (shared->attach_msg)
2817 return FR_DONE;
2818
2819 if (query_quadoption(_("Quit NeoMutt?"), shared->sub, "quit") == MUTT_YES)
2820 {
2821 priv->oldcount = shared->mailbox ? shared->mailbox->msg_count : 0;
2822
2824 mutt_debug(LL_NOTIFY, "NT_GLOBAL_SHUTDOWN\n");
2826
2827 enum MxStatus check = MX_STATUS_OK;
2828 if (!shared->mailbox_view || ((check = mx_mbox_close(shared->mailbox)) == MX_STATUS_OK))
2829 {
2832 return FR_DONE;
2833 }
2834
2835 if ((check == MX_STATUS_NEW_MAIL) || (check == MX_STATUS_REOPENED))
2836 {
2837 update_index(priv->menu, shared->mailbox_view, check, priv->oldcount, shared);
2838 }
2839
2840 menu_queue_redraw(priv->menu, MENU_REDRAW_FULL); /* new mail arrived? */
2842 }
2843
2844 return FR_NO_ACTION;
2845}
2846
2850static int op_recall_message(struct IndexFunctionData *fdata, const struct KeyEvent *event)
2851{
2852 struct IndexSharedData *shared = fdata->shared;
2853 struct IndexPrivateData *priv = fdata->priv;
2854 int rc = mutt_send_message(SEND_POSTPONED, NULL, NULL, shared->mailbox, NULL,
2855 shared->sub);
2857 return (rc == -1) ? FR_ERROR : FR_SUCCESS;
2858}
2859
2863static int op_reply(struct IndexFunctionData *fdata, const struct KeyEvent *event)
2864{
2865 struct IndexSharedData *shared = fdata->shared;
2866 struct IndexPrivateData *priv = fdata->priv;
2867 if (!shared->email)
2868 return FR_NO_ACTION;
2869 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
2870 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
2871 const bool c_pgp_auto_decode = cs_subset_bool(shared->sub, "pgp_auto_decode");
2872 if (c_pgp_auto_decode &&
2873 (priv->tag_prefix || !(shared->email->security & PGP_TRADITIONAL_CHECKED)))
2874 {
2875 if (mutt_check_traditional_pgp(shared->mailbox, &ea))
2877 }
2878 int rc = mutt_send_message(SEND_REPLY, NULL, NULL, shared->mailbox, &ea,
2879 shared->sub);
2880 ARRAY_FREE(&ea);
2882
2883 return (rc == -1) ? FR_ERROR : FR_SUCCESS;
2884}
2885
2889static int op_resend(struct IndexFunctionData *fdata, const struct KeyEvent *event)
2890{
2891 struct IndexSharedData *shared = fdata->shared;
2892 struct IndexPrivateData *priv = fdata->priv;
2893 int rc = -1;
2894 if (priv->tag_prefix)
2895 {
2896 struct Mailbox *m = shared->mailbox;
2897 for (size_t i = 0; i < m->msg_count; i++)
2898 {
2899 struct Email *e = m->emails[i];
2900 if (!e)
2901 break;
2902 if (message_is_tagged(e))
2903 rc = mutt_resend_message(NULL, shared->mailbox, e, shared->sub);
2904 }
2905 }
2906 else
2907 {
2908 rc = mutt_resend_message(NULL, shared->mailbox, shared->email, shared->sub);
2909 }
2910
2912 return (rc == -1) ? FR_ERROR : FR_SUCCESS;
2913}
2914
2926static int op_save(struct IndexFunctionData *fdata, const struct KeyEvent *event)
2927{
2928 struct IndexSharedData *shared = fdata->shared;
2929 struct IndexPrivateData *priv = fdata->priv;
2930 const int op = event->op;
2931 if (((op == OP_DECRYPT_COPY) || (op == OP_DECRYPT_SAVE)) && !WithCrypto)
2932 return FR_NOT_IMPL;
2933
2934 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
2935 ea_add_selection(&ea, shared->mailbox_view, shared->email, priv->tag_prefix,
2936 event->count);
2937 if (ARRAY_EMPTY(&ea))
2938 {
2939 ARRAY_FREE(&ea);
2940 return FR_NO_ACTION;
2941 }
2942 const int num = ARRAY_SIZE(&ea);
2943
2944 const enum MessageSaveOpt save_opt = ((op == OP_SAVE) || (op == OP_DECODE_SAVE) ||
2945 (op == OP_DECRYPT_SAVE)) ?
2946 SAVE_MOVE :
2947 SAVE_COPY;
2948
2949 enum MessageTransformOpt transform_opt =
2950 ((op == OP_DECODE_SAVE) || (op == OP_DECODE_COPY)) ? TRANSFORM_DECODE :
2951 ((op == OP_DECRYPT_SAVE) || (op == OP_DECRYPT_COPY)) ? TRANSFORM_DECRYPT :
2953
2954 const int rc = mutt_save_message(shared->mailbox, &ea, save_opt, transform_opt);
2955 if ((rc == 0) && (save_opt == SAVE_MOVE) && !priv->tag_prefix)
2956 {
2957 resolve_email(priv, shared, RESOLVE_NEXT_UNDELETED, 1);
2958 }
2959 ARRAY_FREE(&ea);
2960
2961 if (priv->tag_prefix || (num > 1))
2963
2964 return (rc == -1) ? FR_ERROR : FR_SUCCESS;
2965}
2966
2976static int op_search(struct IndexFunctionData *fdata, const struct KeyEvent *event)
2977{
2978 struct IndexSharedData *shared = fdata->shared;
2979 struct IndexPrivateData *priv = fdata->priv;
2980 SearchFlags flags = SEARCH_NONE;
2981 switch (event->op)
2982 {
2983 case OP_SEARCH:
2984 flags |= SEARCH_PROMPT;
2985 shared->search_state->reverse = false;
2986 break;
2987 case OP_SEARCH_REVERSE:
2988 flags |= SEARCH_PROMPT;
2989 shared->search_state->reverse = true;
2990 break;
2991 case OP_SEARCH_NEXT:
2992 break;
2993 case OP_SEARCH_OPPOSITE:
2994 flags |= SEARCH_OPPOSITE;
2995 break;
2996
2997 default:
2998 break;
2999 }
3000
3001 // Initiating a search can happen on an empty mailbox, but
3002 // searching for next/previous/... needs to be on a message and
3003 // thus a non-empty mailbox
3004 int index = menu_get_index(priv->menu);
3005 index = mutt_search_command(shared->mailbox_view, priv->menu, index,
3006 shared->search_state, flags);
3007 if (index != -1)
3008 menu_set_index(priv->menu, index);
3009
3010 return FR_SUCCESS;
3011}
3012
3020static int op_sort(struct IndexFunctionData *fdata, const struct KeyEvent *event)
3021{
3022 struct IndexSharedData *shared = fdata->shared;
3023 struct IndexPrivateData *priv = fdata->priv;
3024 if (!mutt_select_sort(event->op == OP_SORT_REVERSE))
3025 return FR_ERROR;
3026
3027 if (shared->mailbox && (shared->mailbox->msg_count != 0))
3028 {
3031 }
3032
3033 return FR_SUCCESS;
3034}
3035
3039static int op_tag(struct IndexFunctionData *fdata, const struct KeyEvent *event)
3040{
3041 struct IndexSharedData *shared = fdata->shared;
3042 struct IndexPrivateData *priv = fdata->priv;
3043 const bool c_auto_tag = cs_subset_bool(shared->sub, "auto_tag");
3044 if (priv->tag_prefix && !c_auto_tag)
3045 {
3046 struct Mailbox *m = shared->mailbox;
3047 for (size_t i = 0; i < m->msg_count; i++)
3048 {
3049 struct Email *e = m->emails[i];
3050 if (!e)
3051 continue;
3052 if (e->visible)
3053 mutt_set_flag(m, e, MUTT_TAG, false, true);
3054 }
3056 return FR_SUCCESS;
3057 }
3058
3059 if (!shared->email)
3060 return FR_NO_ACTION;
3061
3062 int count = MAX(event->count, 1);
3063 int current_index = menu_get_index(priv->menu);
3064
3065 for (int i = 0; i < count && current_index + i < shared->mailbox->vcount; i++)
3066 {
3067 struct Email *e = mutt_get_virt_email(shared->mailbox, current_index + i);
3068 if (e)
3069 mutt_set_flag(shared->mailbox, e, MUTT_TAG, !e->tagged, true);
3070 }
3071
3072 if (count > 0)
3073 resolve_email(priv, shared, RESOLVE_NEXT_EMAIL, count);
3074
3075 return FR_SUCCESS;
3076}
3077
3085static int op_tag_thread(struct IndexFunctionData *fdata, const struct KeyEvent *event)
3086{
3087 struct IndexSharedData *shared = fdata->shared;
3088 struct IndexPrivateData *priv = fdata->priv;
3089 if (!shared->email)
3090 return FR_NO_ACTION;
3091
3092 const int op = event->op;
3094 !shared->email->tagged, (op != OP_TAG_THREAD));
3095 if (rc != -1)
3096 {
3097 const enum ResolveMethod rm = (op == OP_TAG_THREAD) ? RESOLVE_NEXT_THREAD :
3099 resolve_email(priv, shared, rm, 1);
3101 }
3102
3103 return FR_SUCCESS;
3104}
3105
3109static int op_toggle_new(struct IndexFunctionData *fdata, const struct KeyEvent *event)
3110{
3111 struct IndexSharedData *shared = fdata->shared;
3112 struct IndexPrivateData *priv = fdata->priv;
3113 /* L10N: CHECK_ACL */
3114 if (!check_acl(shared->mailbox, MUTT_ACL_SEEN, _("Can't toggle new")))
3115 return FR_ERROR;
3116
3117 struct Mailbox *m = shared->mailbox;
3118 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
3119 ea_add_selection(&ea, shared->mailbox_view, shared->email, priv->tag_prefix,
3120 event->count);
3121 if (ARRAY_EMPTY(&ea))
3122 {
3123 ARRAY_FREE(&ea);
3124 return FR_NO_ACTION;
3125 }
3126 const int num = ARRAY_SIZE(&ea);
3127
3128 struct Email **ep = NULL;
3129 ARRAY_FOREACH(ep, &ea)
3130 {
3131 if ((*ep)->read || (*ep)->old)
3132 mutt_set_flag(m, *ep, MUTT_NEW, true, true);
3133 else
3134 mutt_set_flag(m, *ep, MUTT_READ, true, true);
3135 }
3136 ARRAY_FREE(&ea);
3137
3138 if (priv->tag_prefix)
3139 {
3141 }
3142 else
3143 {
3144 resolve_email(priv, shared, RESOLVE_NEXT_UNDELETED, num);
3145 if (num > 1)
3147 }
3148
3149 return FR_SUCCESS;
3150}
3151
3155static int op_toggle_write(struct IndexFunctionData *fdata, const struct KeyEvent *event)
3156{
3157 struct IndexSharedData *shared = fdata->shared;
3158 mx_toggle_write(shared->mailbox);
3159 return FR_SUCCESS;
3160}
3161
3165static int op_undelete(struct IndexFunctionData *fdata, const struct KeyEvent *event)
3166{
3167 struct IndexSharedData *shared = fdata->shared;
3168 struct IndexPrivateData *priv = fdata->priv;
3169 /* L10N: CHECK_ACL */
3170 if (!check_acl(shared->mailbox, MUTT_ACL_DELETE, _("Can't undelete message")))
3171 return FR_ERROR;
3172
3173 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
3174 ea_add_selection(&ea, shared->mailbox_view, shared->email, priv->tag_prefix,
3175 event->count);
3176 if (ARRAY_EMPTY(&ea))
3177 {
3178 ARRAY_FREE(&ea);
3179 return FR_NO_ACTION;
3180 }
3181 const int num = ARRAY_SIZE(&ea);
3182
3183 mutt_emails_set_flag(shared->mailbox, &ea, MUTT_DELETE, false);
3184 mutt_emails_set_flag(shared->mailbox, &ea, MUTT_PURGE, false);
3185 ARRAY_FREE(&ea);
3186
3187 if (priv->tag_prefix)
3188 {
3190 }
3191 else
3192 {
3193 resolve_email(priv, shared, RESOLVE_NEXT_EMAIL, num);
3194 if (num > 1)
3196 }
3197
3198 return FR_SUCCESS;
3199}
3200
3208static int op_undelete_thread(struct IndexFunctionData *fdata, const struct KeyEvent *event)
3209{
3210 struct IndexSharedData *shared = fdata->shared;
3211 struct IndexPrivateData *priv = fdata->priv;
3212 /* L10N: CHECK_ACL */
3213 /* L10N: Due to the implementation details we do not know whether we
3214 undelete zero, 1, 12, ... messages. So in English we use
3215 "messages". Your language might have other means to express this. */
3216 if (!check_acl(shared->mailbox, MUTT_ACL_DELETE, _("Can't undelete messages")))
3217 return FR_ERROR;
3218
3219 const int op = event->op;
3220 const bool subthread = (op != OP_UNDELETE_THREAD);
3221 int rc = 0;
3222 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
3223 ea_add_selection_threads(&ea, shared->mailbox_view, shared->email,
3224 priv->tag_prefix, subthread, event->count);
3225 const int num = ARRAY_SIZE(&ea);
3226
3227 struct Email **ep = NULL;
3228 ARRAY_FOREACH(ep, &ea)
3229 {
3230 rc = mutt_thread_set_flag(shared->mailbox, *ep, MUTT_DELETE, false, subthread);
3231 if (rc == -1)
3232 break;
3233 rc = mutt_thread_set_flag(shared->mailbox, *ep, MUTT_PURGE, false, subthread);
3234 if (rc == -1)
3235 break;
3236 }
3237 ARRAY_FREE(&ea);
3238
3239 if (rc == -1)
3240 return FR_ERROR;
3241
3242 if (priv->tag_prefix)
3243 {
3245 return FR_SUCCESS;
3246 }
3247
3248 const enum ResolveMethod rm = (op == OP_UNDELETE_THREAD) ? RESOLVE_NEXT_THREAD :
3250 resolve_email(priv, shared, rm, num);
3252 return FR_SUCCESS;
3253}
3254
3258static int op_view_attachments(struct IndexFunctionData *fdata, const struct KeyEvent *event)
3259{
3260 struct IndexSharedData *shared = fdata->shared;
3261 struct IndexPrivateData *priv = fdata->priv;
3262 if (!shared->email)
3263 return FR_NO_ACTION;
3264
3265 enum FunctionRetval rc = FR_ERROR;
3266 struct Message *msg = mx_msg_open(shared->mailbox, shared->email);
3267 if (msg)
3268 {
3269 dlg_attach(fdata->n->sub, shared->mailbox_view, shared->email, msg->fp,
3270 shared->attach_msg);
3271 if (shared->email->attach_del)
3272 {
3273 shared->mailbox->changed = true;
3274 }
3275 mx_msg_close(shared->mailbox, &msg);
3276 rc = FR_SUCCESS;
3277 }
3279 return rc;
3280}
3281
3282// -----------------------------------------------------------------------------
3283
3284#ifdef USE_AUTOCRYPT
3288static int op_autocrypt_acct_menu(struct IndexFunctionData *fdata, const struct KeyEvent *event)
3289{
3290 dlg_autocrypt();
3291 return FR_SUCCESS;
3292}
3293#endif
3294
3298static int op_main_imap_fetch(struct IndexFunctionData *fdata, const struct KeyEvent *event)
3299{
3300 struct IndexSharedData *shared = fdata->shared;
3301 if (!shared->mailbox || (shared->mailbox->type != MUTT_IMAP))
3302 return FR_NO_ACTION;
3303
3304 imap_check_mailbox(shared->mailbox, true);
3305 return FR_SUCCESS;
3306}
3307
3311static int op_main_imap_logout_all(struct IndexFunctionData *fdata, const struct KeyEvent *event)
3312{
3313 struct IndexSharedData *shared = fdata->shared;
3314 struct IndexPrivateData *priv = fdata->priv;
3315 if (shared->mailbox && (shared->mailbox->type == MUTT_IMAP))
3316 {
3317 const enum MxStatus check = mx_mbox_close(shared->mailbox);
3318 if (check == MX_STATUS_OK)
3319 {
3321 }
3322 else
3323 {
3324 if ((check == MX_STATUS_NEW_MAIL) || (check == MX_STATUS_REOPENED))
3325 {
3326 update_index(priv->menu, shared->mailbox_view, check, priv->oldcount, shared);
3327 }
3330 return FR_ERROR;
3331 }
3332 }
3334 mutt_message(_("Logged out of IMAP servers"));
3337
3338 return FR_SUCCESS;
3339}
3340
3344static int op_catchup(struct IndexFunctionData *fdata, const struct KeyEvent *event)
3345{
3346 struct IndexSharedData *shared = fdata->shared;
3347 struct IndexPrivateData *priv = fdata->priv;
3348 struct Mailbox *m = shared->mailbox;
3349 if (!m || (m->type != MUTT_NNTP))
3350 return FR_NO_ACTION;
3351
3352 struct NntpMboxData *mdata = m->mdata;
3353 if (mutt_newsgroup_catchup(m, mdata->adata, mdata->group))
3355
3356 return FR_SUCCESS;
3357}
3358
3366static int op_get_children(struct IndexFunctionData *fdata, const struct KeyEvent *event)
3367{
3368 struct IndexSharedData *shared = fdata->shared;
3369 struct IndexPrivateData *priv = fdata->priv;
3370 struct Mailbox *m = shared->mailbox;
3371 if (m->type != MUTT_NNTP)
3372 return FR_ERROR;
3373
3374 struct Email *e = shared->email;
3375 if (!e)
3376 return FR_NO_ACTION;
3377
3378 char buf[PATH_MAX] = { 0 };
3379 int oldmsgcount = m->msg_count;
3380 int oldindex = e->index;
3381 int rc = 0;
3382
3383 if (!e->env->message_id)
3384 {
3385 mutt_error(_("No Message-ID. Unable to perform operation."));
3386 return FR_ERROR;
3387 }
3388
3389 mutt_message(_("Fetching message headers..."));
3390 if (!m->id_hash)
3391 m->id_hash = mutt_make_id_hash(m);
3392 mutt_str_copy(buf, e->env->message_id, sizeof(buf));
3393
3394 const int op = event->op;
3395 /* trying to find msgid of the root message */
3396 if (op == OP_RECONSTRUCT_THREAD)
3397 {
3398 struct ListNode *ref = NULL;
3399 STAILQ_FOREACH(ref, &e->env->references, entries)
3400 {
3401 if (!mutt_hash_find(m->id_hash, ref->data))
3402 {
3403 rc = nntp_check_msgid(m, ref->data);
3404 if (rc < 0)
3405 return FR_ERROR;
3406 }
3407
3408 /* the last msgid in References is the root message */
3409 if (!STAILQ_NEXT(ref, entries))
3410 mutt_str_copy(buf, ref->data, sizeof(buf));
3411 }
3412 }
3413
3414 /* fetching all child messages */
3415 rc = nntp_check_children(m, buf);
3416
3417 /* at least one message has been loaded */
3418 if (m->msg_count > oldmsgcount)
3419 {
3420 bool verbose = m->verbose;
3421
3422 if (rc < 0)
3423 m->verbose = false;
3424
3425 struct MailboxView *mv = shared->mailbox_view;
3426 mutt_sort_headers(mv, (op == OP_RECONSTRUCT_THREAD));
3427 m->verbose = verbose;
3428
3429 /* if the root message was retrieved, move to it */
3430 struct Email *e2 = mutt_hash_find(m->id_hash, buf);
3431 if (e2)
3432 {
3433 menu_set_index(priv->menu, e2->vnum);
3434 }
3435 else
3436 {
3437 /* try to restore old position */
3438 for (int i = 0; i < m->msg_count; i++)
3439 {
3440 e2 = m->emails[i];
3441 if (!e2)
3442 break;
3443 if (e2->index == oldindex)
3444 {
3445 menu_set_index(priv->menu, e2->vnum);
3446 /* as an added courtesy, recenter the menu
3447 * with the current entry at the middle of the screen */
3449 }
3450 }
3451 }
3453 }
3454 else if (rc >= 0)
3455 {
3456 mutt_error(_("No deleted messages found in the thread"));
3457 return FR_ERROR;
3458 }
3459
3460 return FR_SUCCESS;
3461}
3462
3470static int op_get_message(struct IndexFunctionData *fdata, const struct KeyEvent *event)
3471{
3472 struct IndexSharedData *shared = fdata->shared;
3473 struct IndexPrivateData *priv = fdata->priv;
3474 struct Mailbox *m = shared->mailbox;
3475 if (m->type != MUTT_NNTP)
3476 return FR_SUCCESS;
3477
3478 int rc = FR_ERROR;
3479 struct Buffer *buf = buf_pool_get();
3480
3481 const int op = event->op;
3482 if (op == OP_GET_MESSAGE)
3483 {
3484 if ((mw_get_field(_("Enter Message-ID: "), buf, MUTT_COMP_NONE, HC_OTHER, NULL, NULL) != 0) ||
3485 buf_is_empty(buf))
3486 {
3487 goto done;
3488 }
3489 }
3490 else
3491 {
3492 struct Email *e = shared->email;
3493 if (!e || STAILQ_EMPTY(&e->env->references))
3494 {
3495 mutt_error(_("Article has no parent reference"));
3496 goto done;
3497 }
3499 }
3500
3501 if (!m->id_hash)
3502 m->id_hash = mutt_make_id_hash(m);
3503 struct Email *e = mutt_hash_find(m->id_hash, buf_string(buf));
3504 if (e)
3505 {
3506 if (e->vnum != -1)
3507 {
3508 menu_set_index(priv->menu, e->vnum);
3509 }
3510 else if (e->collapsed)
3511 {
3513 mutt_set_vnum(m);
3514 menu_set_index(priv->menu, e->vnum);
3515 }
3516 else
3517 {
3518 mutt_error(_("Message is not visible in limited view"));
3519 }
3520 }
3521 else
3522 {
3523 mutt_message(_("Fetching %s from server..."), buf_string(buf));
3524 int rc2 = nntp_check_msgid(m, buf_string(buf));
3525 if (rc2 == 0)
3526 {
3527 e = m->emails[m->msg_count - 1];
3528 struct MailboxView *mv = shared->mailbox_view;
3529 mutt_sort_headers(mv, false);
3530 menu_set_index(priv->menu, e->vnum);
3532 rc = FR_SUCCESS;
3533 }
3534 else if (rc2 > 0)
3535 {
3536 mutt_error(_("Article %s not found on the server"), buf_string(buf));
3537 }
3538 }
3539
3540done:
3541 buf_pool_release(&buf);
3542 return rc;
3543}
3544
3552static int op_main_change_group(struct IndexFunctionData *fdata, const struct KeyEvent *event)
3553{
3555 struct IndexSharedData *shared = fdata->shared;
3556 struct IndexPrivateData *priv = fdata->priv;
3557 struct Buffer *folderbuf = buf_pool_get();
3558 buf_alloc(folderbuf, PATH_MAX);
3559
3560 OptNews = false;
3561 bool read_only;
3562 char *cp = NULL;
3563 const bool c_read_only = cs_subset_bool(shared->sub, "read_only");
3564 const int op = event->op;
3565 if (shared->attach_msg || c_read_only || (op == OP_MAIN_CHANGE_GROUP_READONLY))
3566 {
3567 cp = _("Open newsgroup in read-only mode");
3568 read_only = true;
3569 }
3570 else
3571 {
3572 cp = _("Open newsgroup");
3573 read_only = false;
3574 }
3575
3576 const bool c_change_folder_next = cs_subset_bool(shared->sub, "change_folder_next");
3577 if (c_change_folder_next && shared->mailbox && !buf_is_empty(&shared->mailbox->pathbuf))
3578 {
3579 buf_strcpy(folderbuf, mailbox_path(shared->mailbox));
3580 pretty_mailbox(folderbuf);
3581 }
3582
3583 OptNews = true;
3584 const char *const c_news_server = cs_subset_string(shared->sub, "news_server");
3585 if (!mod_data->current_news_srv)
3586 mod_data->current_news_srv = nntp_select_server(shared->mailbox, c_news_server, false);
3587 if (!mod_data->current_news_srv)
3588 goto changefoldercleanup2;
3589
3590 nntp_mailbox(shared->mailbox, folderbuf->data, folderbuf->dsize);
3591
3592 if (mw_enter_fname(cp, folderbuf, true, shared->mailbox, false, NULL, NULL,
3593 MUTT_SEL_NONE) == -1)
3594 {
3595 goto changefoldercleanup2;
3596 }
3597
3598 /* Selected directory is okay, let's save it. */
3600
3601 if (buf_is_empty(folderbuf))
3602 {
3603 msgwin_clear_text(NULL);
3604 goto changefoldercleanup2;
3605 }
3606
3607 struct Mailbox *m = mx_mbox_find2(buf_string(folderbuf));
3608 if (m)
3609 {
3610 change_folder_mailbox(priv->menu, m, &priv->oldcount, shared, read_only);
3611 }
3612 else
3613 {
3614 change_folder_string(priv->menu, folderbuf, &priv->oldcount, shared, read_only);
3615 }
3616 struct MuttWindow *dlg = dialog_find(priv->win_index);
3617 dlg->help_data = IndexNewsHelp;
3618
3619changefoldercleanup2:
3620 buf_pool_release(&folderbuf);
3621 return FR_SUCCESS;
3622}
3623
3632static int op_post(struct IndexFunctionData *fdata, const struct KeyEvent *event)
3633{
3634 struct IndexSharedData *shared = fdata->shared;
3635 struct IndexPrivateData *priv = fdata->priv;
3636 if (!shared->email)
3637 return FR_NO_ACTION;
3638
3639 const int op = event->op;
3640 if ((op != OP_FOLLOWUP) || !shared->email->env->followup_to ||
3641 !mutt_istr_equal(shared->email->env->followup_to, "poster") ||
3642 (query_quadoption(_("Reply by mail as poster prefers?"), shared->sub,
3643 "followup_to_poster") != MUTT_YES))
3644 {
3645 if (shared->mailbox && (shared->mailbox->type == MUTT_NNTP) &&
3646 !((struct NntpMboxData *) shared->mailbox->mdata)->allowed &&
3647 (query_quadoption(_("Posting to this group not allowed, may be moderated. Continue?"),
3648 shared->sub, "post_moderated") != MUTT_YES))
3649 {
3650 return FR_ERROR;
3651 }
3652 if (op == OP_POST)
3653 {
3654 mutt_send_message(SEND_NEWS, NULL, NULL, shared->mailbox, NULL, shared->sub);
3655 }
3656 else
3657 {
3658 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
3659 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
3660 mutt_send_message(((op == OP_FOLLOWUP) ? SEND_REPLY : SEND_FORWARD) | SEND_NEWS,
3661 NULL, NULL, shared->mailbox, &ea, shared->sub);
3662 ARRAY_FREE(&ea);
3663 }
3665 return FR_SUCCESS;
3666 }
3667
3668 struct KeyEvent event_r = { 0, OP_REPLY };
3669 return op_reply(fdata, &event_r);
3670}
3671
3672#ifdef USE_NOTMUCH
3676static int op_main_entire_thread(struct IndexFunctionData *fdata, const struct KeyEvent *event)
3677{
3678 struct IndexSharedData *shared = fdata->shared;
3679 struct IndexPrivateData *priv = fdata->priv;
3681 {
3682 if (!shared->email || !shared->email->env || !shared->email->env->message_id)
3683 {
3684 mutt_message(_("No virtual folder and no Message-ID, aborting"));
3685 return FR_ERROR;
3686 } // no virtual folder, but we have Message-ID, reconstruct thread on-the-fly
3687
3688 struct Buffer *buf = buf_pool_get();
3689 buf_alloc(buf, PATH_MAX);
3690 buf_addstr(buf, "id:");
3691
3692 int msg_id_offset = 0;
3693 if ((shared->email->env->message_id)[0] == '<')
3694 msg_id_offset = 1;
3695
3696 buf_addstr(buf, shared->email->env->message_id + msg_id_offset);
3697
3698 size_t len = buf_len(buf);
3699 ASSERT(len > 0);
3700 if (buf->data[len - 1] == '>')
3701 buf->data[len - 1] = '\0';
3702
3703 change_folder_notmuch(priv->menu, buf->data, buf->dsize, &priv->oldcount, shared, false);
3704 buf_pool_release(&buf);
3705
3706 // If notmuch doesn't contain the message, we're left in an empty
3707 // vfolder. No messages are found, but nm_read_entire_thread assumes
3708 // a valid Message-ID and will throw a segfault.
3709 //
3710 // To prevent that, stay in the empty vfolder and print an error.
3711 if (!shared->mailbox)
3712 return FR_ERROR;
3713
3714 if (shared->mailbox->msg_count == 0)
3715 {
3716 mutt_error(_("failed to find message in notmuch database. try running 'notmuch new'."));
3717 return FR_ERROR;
3718 }
3719 }
3720 priv->oldcount = shared->mailbox->msg_count;
3721 int index = menu_get_index(priv->menu);
3722 struct Email *e_oldcur = mutt_get_virt_email(shared->mailbox, index);
3723 if (!e_oldcur)
3724 return FR_ERROR;
3725
3726 if (nm_read_entire_thread(shared->mailbox, e_oldcur) < 0)
3727 {
3728 mutt_message(_("Failed to read thread, aborting"));
3729 return FR_ERROR;
3730 }
3731
3732 // nm_read_entire_thread() may modify msg_count and menu won't be updated.
3733 priv->menu->max = shared->mailbox->msg_count;
3734
3735 if (priv->oldcount < shared->mailbox->msg_count)
3736 {
3737 /* nm_read_entire_thread() triggers mutt_sort_headers() if necessary */
3738 index = e_oldcur->vnum;
3739 if (e_oldcur->collapsed || shared->mailbox_view->collapsed)
3740 {
3741 index = mutt_uncollapse_thread(e_oldcur);
3742 mutt_set_vnum(shared->mailbox);
3743 }
3744 menu_set_index(priv->menu, index);
3746 }
3747
3748 return FR_SUCCESS;
3749}
3750
3759 const struct KeyEvent *event)
3760{
3761 struct IndexSharedData *shared = fdata->shared;
3762 struct IndexPrivateData *priv = fdata->priv;
3763 int rc = FR_SUCCESS;
3764 struct Buffer *buf = buf_pool_get();
3765
3766 if ((mw_get_field("Query: ", buf, MUTT_COMP_NONE, HC_OTHER, &CompleteNmQueryOps, NULL) != 0) ||
3767 buf_is_empty(buf))
3768 {
3769 mutt_message(_("No query, aborting"));
3770 rc = FR_NO_ACTION;
3771 goto done;
3772 }
3773
3774 // Keep copy of user's query to name the mailbox
3775 char *query_unencoded = buf_strdup(buf);
3776
3777 buf_alloc(buf, PATH_MAX);
3778 const int op = event->op;
3779 struct Mailbox *m_query = change_folder_notmuch(priv->menu, buf->data, buf->dsize,
3780 &priv->oldcount, shared,
3781 (op == OP_MAIN_VFOLDER_FROM_QUERY_READONLY));
3782 if (m_query)
3783 {
3784 FREE(&m_query->name);
3785 m_query->name = query_unencoded;
3786 query_unencoded = NULL;
3787 rc = FR_SUCCESS;
3788 }
3789 else
3790 {
3791 FREE(&query_unencoded);
3792 }
3793
3794done:
3795 buf_pool_release(&buf);
3796 return rc;
3797}
3798
3808 const struct KeyEvent *event)
3809{
3810 struct IndexSharedData *shared = fdata->shared;
3811 struct IndexPrivateData *priv = fdata->priv;
3812 // Common guard clauses.
3814 {
3815 mutt_message(_("Windowed queries disabled"));
3816 return FR_ERROR;
3817 }
3818 const char *const c_nm_query_window_current_search = cs_subset_string(shared->sub, "nm_query_window_current_search");
3819 if (!c_nm_query_window_current_search)
3820 {
3821 mutt_message(_("No notmuch vfolder currently loaded"));
3822 return FR_ERROR;
3823 }
3824
3825 // Call the specific operation.
3826 switch (event->op)
3827 {
3828 case OP_MAIN_WINDOWED_VFOLDER_BACKWARD:
3830 break;
3831 case OP_MAIN_WINDOWED_VFOLDER_FORWARD:
3833 break;
3834 case OP_MAIN_WINDOWED_VFOLDER_RESET:
3836 break;
3837
3838 default:
3839 break;
3840 }
3841
3842 // Common query window folder change.
3843 char buf[PATH_MAX] = { 0 };
3844 mutt_str_copy(buf, c_nm_query_window_current_search, sizeof(buf));
3845 change_folder_notmuch(priv->menu, buf, sizeof(buf), &priv->oldcount, shared, false);
3846
3847 return FR_SUCCESS;
3848}
3849#endif
3850
3854static int op_main_fetch_mail(struct IndexFunctionData *fdata, const struct KeyEvent *event)
3855{
3856 struct IndexPrivateData *priv = fdata->priv;
3859 return FR_SUCCESS;
3860}
3861
3862// -----------------------------------------------------------------------------
3863
3871static bool prereq(struct IndexSharedData *shared, struct Menu *menu, CheckFlags checks)
3872{
3873 bool result = true;
3874 struct MailboxView *mv = shared->mailbox_view;
3875
3876 if (checks & (CHECK_MSGCOUNT | CHECK_VISIBLE | CHECK_READONLY))
3877 checks |= CHECK_IN_MAILBOX;
3878
3879 if ((checks & CHECK_IN_MAILBOX) && (!mv || !mv->mailbox))
3880 {
3881 mutt_error(_("No mailbox is open"));
3882 result = false;
3883 }
3884
3885 if (result && (checks & CHECK_MSGCOUNT) && (mv->mailbox->msg_count == 0))
3886 {
3887 mutt_error(_("There are no messages"));
3888 result = false;
3889 }
3890
3891 int index = menu_get_index(menu);
3892 if (result && (checks & CHECK_VISIBLE) &&
3893 ((index < 0) || (index >= mv->mailbox->vcount)))
3894 {
3895 mutt_error(_("No visible messages"));
3896 result = false;
3897 }
3898
3899 if (result && (checks & CHECK_READONLY) && mv->mailbox->readonly)
3900 {
3901 mutt_error(_("Mailbox is read-only"));
3902 result = false;
3903 }
3904
3905 if (result && (checks & CHECK_ATTACH) && shared->attach_msg)
3906 {
3907 mutt_error(_("Function not permitted in attach-message mode"));
3908 result = false;
3909 }
3910
3911 if (!result)
3912 mutt_flushinp();
3913
3914 return result;
3915}
3916
3920static const struct IndexFunction IndexFunctions[] = {
3921 // clang-format off
3922 { OP_ALIAS_DIALOG, op_alias_dialog, CHECK_NONE },
3928 { OP_COPY_MESSAGE, op_save, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3929 { OP_CREATE_ALIAS, op_create_alias, CHECK_NONE },
3930 { OP_DECODE_COPY, op_save, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3931 { OP_DECODE_SAVE, op_save, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3932 { OP_DECRYPT_COPY, op_save, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3933 { OP_DECRYPT_SAVE, op_save, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3941 { OP_EDIT_OR_VIEW_RAW_MESSAGE, op_edit_raw_message, CHECK_ATTACH | CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3943 { OP_END_COND, op_end_cond, CHECK_NONE },
3944 { OP_EXIT, op_exit, CHECK_NONE },
3949 { OP_FORWARD_TO_GROUP, op_post, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3951 { OP_GET_MESSAGE, op_get_message, CHECK_ATTACH | CHECK_IN_MAILBOX },
3953 { OP_GENERIC_SELECT_ENTRY, op_display_message, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3956 { OP_JUMP, op_jump, CHECK_IN_MAILBOX },
3957 { OP_LIMIT_CURRENT_THREAD, op_main_limit, CHECK_IN_MAILBOX },
3962 { OP_MAIL, op_mail, CHECK_ATTACH },
3963 { OP_MAILBOX_LIST, op_mailbox_list, CHECK_NONE },
3964 { OP_MAIL_KEY, op_mail_key, CHECK_ATTACH },
3966 { OP_MAIN_BROWSE_MAILBOXES, op_main_change_folder, CHECK_NONE },
3967 { OP_MAIN_BROWSE_MAILBOXES_READONLY, op_main_change_folder, CHECK_NONE },
3968 { OP_MAIN_CHANGE_FOLDER, op_main_change_folder, CHECK_NONE },
3969 { OP_MAIN_CHANGE_FOLDER_READONLY, op_main_change_folder, CHECK_NONE },
3970 { OP_MAIN_CHANGE_GROUP, op_main_change_group, CHECK_NONE },
3971 { OP_MAIN_CHANGE_GROUP_READONLY, op_main_change_group, CHECK_NONE },
3973 { OP_MAIN_CLOSE_ALL_THREADS, op_main_close_all_threads, CHECK_IN_MAILBOX },
3975 { OP_MAIN_COLLAPSE_ALL, op_main_collapse_all, CHECK_IN_MAILBOX },
3976 { OP_MAIN_COLLAPSE_THREAD, op_main_collapse_thread, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3977 { OP_MAIN_DELETE_PATTERN, op_main_delete_pattern, CHECK_ATTACH | CHECK_IN_MAILBOX | CHECK_READONLY },
3978 { OP_MAIN_FETCH_MAIL, op_main_fetch_mail, CHECK_ATTACH },
3979 { OP_MAIN_IMAP_FETCH, op_main_imap_fetch, CHECK_NONE },
3980 { OP_MAIN_IMAP_LOGOUT_ALL, op_main_imap_logout_all, CHECK_NONE },
3981 { OP_MAIN_LIMIT, op_main_limit, CHECK_IN_MAILBOX },
3984 { OP_MAIN_MODIFY_TAGS_THEN_HIDE, op_main_modify_tags, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_READONLY | CHECK_VISIBLE },
3986 { OP_MAIN_NEXT_NEW_THEN_UNREAD, op_main_next_new, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3987 { OP_MAIN_NEXT_SUBTHREAD, op_main_next_thread, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3990 { OP_MAIN_NEXT_UNREAD, op_main_next_new, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3991 { OP_MAIN_NEXT_UNREAD_MAILBOX, op_main_next_unread_mailbox, CHECK_IN_MAILBOX },
3992 { OP_MAIN_PREV_UNREAD_MAILBOX, op_main_prev_unread_mailbox, CHECK_IN_MAILBOX },
3993 { OP_MAIN_OPEN_ALL_THREADS, op_main_open_all_threads, CHECK_IN_MAILBOX },
3995 { OP_MAIN_PARENT_MESSAGE, op_main_root_message, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3997 { OP_MAIN_PREV_NEW_THEN_UNREAD, op_main_next_new, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3998 { OP_MAIN_PREV_SUBTHREAD, op_main_next_thread, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
4001 { OP_MAIN_PREV_UNREAD, op_main_next_new, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
4007 { OP_MAIN_SHOW_LIMIT, op_main_show_limit, CHECK_IN_MAILBOX },
4008 { OP_MAIN_SYNC_FOLDER, op_main_sync_folder, CHECK_NONE },
4009 { OP_MAIN_TAG_PATTERN, op_main_tag_pattern, CHECK_IN_MAILBOX },
4010 { OP_MAIN_UNDELETE_PATTERN, op_main_undelete_pattern, CHECK_IN_MAILBOX | CHECK_READONLY },
4011 { OP_MAIN_UNTAG_PATTERN, op_main_untag_pattern, CHECK_IN_MAILBOX },
4015 { OP_POST, op_post, CHECK_ATTACH | CHECK_IN_MAILBOX },
4022 { OP_QUERY, op_query, CHECK_ATTACH },
4023 { OP_QUIT, op_quit, CHECK_NONE },
4024 { OP_RECALL_MESSAGE, op_recall_message, CHECK_ATTACH },
4029 { OP_SEARCH, op_search, CHECK_IN_MAILBOX },
4030 { OP_SEARCH_NEXT, op_search, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
4031 { OP_SEARCH_OPPOSITE, op_search, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
4032 { OP_SEARCH_REVERSE, op_search, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
4033 { OP_SORT, op_sort, CHECK_NONE },
4034 { OP_SORT_REVERSE, op_sort, CHECK_NONE },
4039 { OP_TOGGLE_READ, op_main_limit, CHECK_IN_MAILBOX },
4040 { OP_TOGGLE_WRITE, op_toggle_write, CHECK_IN_MAILBOX },
4046#ifdef USE_AUTOCRYPT
4047 { OP_AUTOCRYPT_ACCT_MENU, op_autocrypt_acct_menu, CHECK_NONE },
4048#endif
4049#ifdef USE_NOTMUCH
4050 { OP_MAIN_CHANGE_VFOLDER, op_main_change_folder, CHECK_NONE },
4052 { OP_MAIN_VFOLDER_FROM_QUERY, op_main_vfolder_from_query, CHECK_NONE },
4053 { OP_MAIN_VFOLDER_FROM_QUERY_READONLY, op_main_vfolder_from_query, CHECK_NONE },
4054 { OP_MAIN_WINDOWED_VFOLDER_BACKWARD, op_main_windowed_vfolder, CHECK_IN_MAILBOX },
4055 { OP_MAIN_WINDOWED_VFOLDER_FORWARD, op_main_windowed_vfolder, CHECK_IN_MAILBOX },
4056 { OP_MAIN_WINDOWED_VFOLDER_RESET, op_main_windowed_vfolder, CHECK_IN_MAILBOX },
4057#endif
4058 { 0, NULL, CHECK_NONE },
4059 // clang-format on
4060};
4061
4065int index_function_dispatcher(struct MuttWindow *win, const struct KeyEvent *event)
4066{
4067 // The Dispatcher may be called on any Window in the Dialog
4068 struct MuttWindow *dlg = dialog_find(win);
4069 if (!event || !dlg || !dlg->wdata || !win->parent || !win->parent->wdata)
4070 {
4072 return FR_ERROR;
4073 }
4074
4075 const int op = event->op;
4076 struct IndexPrivateData *priv = win->parent->wdata;
4077 struct IndexSharedData *shared = dlg->wdata;
4078
4080
4081 struct IndexFunctionData fdata = {
4082 .n = NeoMutt,
4083 .mod_data = mod_data,
4084 .shared = shared,
4085 .priv = priv,
4086 };
4087
4088 int rc = FR_UNKNOWN;
4089 for (size_t i = 0; IndexFunctions[i].op != OP_NULL; i++)
4090 {
4091 const struct IndexFunction *fn = &IndexFunctions[i];
4092 if (fn->op == op)
4093 {
4094 if (!prereq(shared, priv->menu, fn->flags))
4095 {
4096 rc = FR_ERROR;
4097 break;
4098 }
4099 rc = fn->function(&fdata, event);
4100 break;
4101 }
4102 }
4103
4104 if (rc == FR_UNKNOWN) // Not our function
4105 return rc;
4106
4107 const char *result = dispatcher_get_retval_name(rc);
4108 mutt_debug(LL_DEBUG1, "Handled %s (%d) -> %s\n", opcodes_get_name(op), op, NONULL(result));
4109
4111 return rc;
4112}
4113
4119{
4121 ASSERT(mod_data);
4122
4123 return mod_data->md_index;
4124}
Email Aliases.
void alias_create(struct AddressList *al, const struct ConfigSubset *sub)
Create a new Alias from an Address.
Definition alias.c:369
struct AddressList * mutt_get_address(struct Envelope *env, const char **prefix)
Get an Address from an Envelope.
Definition alias.c:329
#define ARRAY_ADD(head, elem)
Add an element at the end of the array.
Definition array.h:157
#define ARRAY_REMOVE(head, elem)
Remove an entry from the array, shifting down the subsequent entries.
Definition array.h:355
#define ARRAY_FOREACH(elem, head)
Iterate over all elements of the array.
Definition array.h:223
#define ARRAY_EMPTY(head)
Check if an array is empty.
Definition array.h:74
#define ARRAY_SIZE(head)
The number of elements stored.
Definition array.h:87
#define ARRAY_FREE(head)
Release all memory.
Definition array.h:209
#define ARRAY_GET(head, idx)
Return the element at index.
Definition array.h:109
#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.
@ MUTT_SEL_MAILBOX
Select a mailbox.
Definition lib.h:60
@ MUTT_SEL_FOLDER
Select a local directory.
Definition lib.h:62
@ MUTT_SEL_NONE
No flags are set.
Definition lib.h:59
int buf_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition buffer.c:168
size_t buf_len(const struct Buffer *buf)
Calculate the length of a Buffer.
Definition buffer.c:497
bool buf_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition buffer.c:298
size_t buf_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition buffer.c:233
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition buffer.c:401
char * buf_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition buffer.c:577
void buf_alloc(struct Buffer *buf, size_t new_size)
Make sure a buffer can store at least new_size bytes.
Definition buffer.c:342
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:113
@ CMD_MESSAGE_HOOK
:message-hook
Definition command.h:97
void mutt_pattern_free(struct PatternList **pat)
Free a Pattern.
Definition compile.c:836
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:178
@ MUTT_ACL_WRITE
Write to a message (for flagging or linking threads).
Definition mailbox.h:71
@ MUTT_ACL_INSERT
Add/copy into the mailbox (used when editing a message).
Definition mailbox.h:66
@ MUTT_ACL_DELETE
Delete a message.
Definition mailbox.h:63
@ MUTT_ACL_SEEN
Change the 'seen' status of a message.
Definition mailbox.h:70
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox's path string.
Definition mailbox.h:216
@ MUTT_NOTMUCH
'Notmuch' (virtual) Mailbox type
Definition mailbox.h:50
@ MUTT_NNTP
'NNTP' (Usenet) Mailbox type
Definition mailbox.h:48
@ MUTT_IMAP
'IMAP' Mailbox type
Definition mailbox.h:49
void crypt_extract_keys_from_messages(struct Mailbox *m, struct EmailArray *ea)
Extract keys from a message.
Definition crypt.c:864
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:55
void dispatcher_flush_on_error(int rv)
Flush pending keys after a dispatch error.
Definition dispatcher.c:65
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:508
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:137
const struct Mapping IndexNewsHelp[]
Help Bar for the News Index dialog.
Definition dlg_index.c:116
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:631
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:752
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:562
int find_first_message(struct MailboxView *mv)
Get index of first new message.
Definition dlg_index.c:327
void resort_index(struct MailboxView *mv, struct Menu *menu)
Resort the index.
Definition dlg_index.c:387
int find_next_undeleted(struct MailboxView *mv, int msgno, bool uncollapse)
Find the next undeleted email.
Definition dlg_index.c:259
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:777
int find_previous_undeleted(struct MailboxView *mv, int msgno, bool uncollapse)
Find the previous undeleted email.
Definition dlg_index.c:293
void collapse_all(struct MailboxView *mv, struct Menu *menu, enum CollapseMode mode)
Collapse/uncollapse all threads.
Definition dlg_index.c:161
void query_index(struct Mailbox *m, struct ConfigSubset *sub)
Perform an Alias Query and display the results.
Definition dlg_query.c:491
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.
@ MUTT_COMP_NONE
No flags are set.
Definition wdata.h:46
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:358
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
struct Email * find_virtual(struct MuttThread *cur, bool reverse)
Find an email with a Virtual message number.
Definition thread.c:124
bool mutt_select_sort(bool reverse)
Ask the user for a sort method.
Definition external.c:475
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:1218
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:784
bool mutt_edit_content_type(struct Email *e, struct Body *b, FILE *fp)
Edit the content type of an attachment.
Definition external.c:1077
bool mutt_print_message(struct Mailbox *m, struct EmailArray *ea)
Print a message.
Definition external.c:437
void mutt_display_address(struct Envelope *env)
Display the address of a message.
Definition external.c:667
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
struct SubMenu * sidebar_get_submenu(void)
Get the Sidebar SubMenu.
void mutt_flushinp(void)
MacroEvents moved to KeyModuleData UngetKeyEvents moved to KeyModuleData.
Definition get.c:81
@ MFF_DEPRECATED
Function is deprecated.
Definition get.h:67
bool OptNews
(pseudo) used to change reader mode
Definition globals.c:53
Global variables.
static int op_quit(struct AliasFunctionData *fdata, const struct KeyEvent *event)
Save changes and exit this dialog - Implements alias_function_t -.
Definition functions.c:308
static int op_main_limit(struct AliasFunctionData *fdata, const struct KeyEvent *event)
show only messages matching a pattern - Implements alias_function_t -
Definition functions.c:407
static int op_query(struct AliasFunctionData *fdata, const struct KeyEvent *event)
query external program for addresses - Implements alias_function_t -
Definition functions.c:465
static int op_create_alias(struct AliasFunctionData *fdata, const struct KeyEvent *event)
create an alias from a message sender - Implements alias_function_t -
Definition functions.c:148
static int op_jump(struct AliasFunctionData *fdata, const struct KeyEvent *event)
Jump to an index number - Implements alias_function_t -.
Definition functions.c:316
static int op_main_untag_pattern(struct AliasFunctionData *fdata, const struct KeyEvent *event)
Untag messages matching a pattern - Implements alias_function_t -.
Definition functions.c:444
static int op_main_tag_pattern(struct AliasFunctionData *fdata, const struct KeyEvent *event)
Tag messages matching a pattern - Implements alias_function_t -.
Definition functions.c:427
static int op_mail(struct AliasFunctionData *fdata, const struct KeyEvent *event)
mail the selected entries - Implements alias_function_t -
Definition functions.c:399
static int op_delete(struct AliasFunctionData *fdata, const struct KeyEvent *event)
delete the current entry - Implements alias_function_t -
Definition functions.c:270
static int op_search(struct AliasFunctionData *fdata, const struct KeyEvent *event)
search for a regular expression - Implements alias_function_t -
Definition functions.c:519
static int op_sort(struct AliasFunctionData *fdata, const struct KeyEvent *event)
sort aliases - Implements alias_function_t -
Definition functions.c:559
static int op_list_unsubscribe(struct AttachFunctionData *fdata, const struct KeyEvent *event)
unsubscribe from a mailing list - Implements attach_function_t -
Definition functions.c:670
static int op_attach_edit_type(struct AttachFunctionData *fdata, const struct KeyEvent *event)
edit attachment content type - Implements attach_function_t -
Definition functions.c:391
static int op_resend(struct AttachFunctionData *fdata, const struct KeyEvent *event)
use the current message as a template for a new one - Implements attach_function_t -
Definition functions.c:714
static int op_forward_message(struct AttachFunctionData *fdata, const struct KeyEvent *event)
forward a message with comments - Implements attach_function_t -
Definition functions.c:642
static int op_compose_to_sender(struct AttachFunctionData *fdata, const struct KeyEvent *event)
compose new message to the current message sender - Implements attach_function_t -
Definition functions.c:586
static int op_list_subscribe(struct AttachFunctionData *fdata, const struct KeyEvent *event)
subscribe to a mailing list - Implements attach_function_t -
Definition functions.c:658
static int op_check_traditional(struct AttachFunctionData *fdata, const struct KeyEvent *event)
check for classic PGP - Implements attach_function_t -
Definition functions.c:569
static int op_extract_keys(struct AttachFunctionData *fdata, const struct KeyEvent *event)
extract supported public keys - Implements attach_function_t -
Definition functions.c:624
static int op_reply(struct AttachFunctionData *fdata, const struct KeyEvent *event)
reply to a message - Implements attach_function_t -
Definition functions.c:688
static int op_bounce_message(struct AttachFunctionData *fdata, const struct KeyEvent *event)
remail a message to another user - Implements attach_function_t -
Definition functions.c:553
static int op_mailbox_list(struct BrowserPrivateData *priv, const struct KeyEvent *event)
List mailboxes with new mail - Implements browser_function_t -.
Definition functions.c:1175
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:502
int index_function_dispatcher(struct MuttWindow *win, const struct KeyEvent *event)
Perform an Index function - Implements function_dispatcher_t -.
Definition functions.c:4065
void dlg_browser(struct Buffer *file, SelectFileFlags flags, struct Mailbox *m, char ***files, int *numfiles)
Let the user select a file -.
void dlg_mlist(struct Mailbox *m, struct Email *e)
Display mailing-list actions for an email -.
Definition dlg_mlist.c:118
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:208
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:456
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:237
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:502
static int op_edit_label(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Add, change, or delete a message's label - Implements index_function_t -.
Definition functions.c:1032
static int op_display_address(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Display full address of sender - Implements index_function_t -.
Definition functions.c:931
static int op_next_entry(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Move to the next entry - Implements index_function_t -.
Definition functions.c:2697
static int op_main_undelete_pattern(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Undelete messages matching a pattern - Implements index_function_t -.
Definition functions.c:2604
static int op_main_link_threads(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Link tagged message to the current one - Implements index_function_t -.
Definition functions.c:1779
static int op_get_children(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Get all children of the current message - Implements index_function_t -.
Definition functions.c:3366
static int op_main_prev_undeleted(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Move to the previous undeleted message - Implements index_function_t -.
Definition functions.c:2283
static int op_main_imap_fetch(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Force retrieval of mail from IMAP server - Implements index_function_t -.
Definition functions.c:3298
static int op_display_message(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Display a message - Implements index_function_t -.
Definition functions.c:949
static int op_list_reply(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Reply to specified mailing list - Implements index_function_t -.
Definition functions.c:1341
static int op_main_vfolder_from_query(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Generate virtual folder from query - Implements index_function_t -.
Definition functions.c:3758
static int op_save(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Make decrypted copy - Implements index_function_t -.
Definition functions.c:2926
static int op_main_next_unread_mailbox(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Open next mailbox with unread mail - Implements index_function_t -.
Definition functions.c:2233
static int op_list_action(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Show mailing-list actions - Implements index_function_t -.
Definition functions.c:1328
static int op_mail_key(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Mail a PGP public key - Implements index_function_t -.
Definition functions.c:1407
static int op_alias_dialog(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Open the aliases dialog - Implements index_function_t -.
Definition functions.c:620
static int op_main_show_limit(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Show currently active limit pattern - Implements index_function_t -.
Definition functions.c:2485
static int op_exit(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Exit this menu - Implements index_function_t -.
Definition functions.c:1131
static int op_recall_message(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Recall a postponed message - Implements index_function_t -.
Definition functions.c:2850
static int op_main_sync_folder(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Save changes to mailbox - Implements index_function_t -.
Definition functions.c:2507
static int op_main_windowed_vfolder(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Shifts virtual folder time window - Implements index_function_t -.
Definition functions.c:3807
static int op_tag_thread(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Tag the current thread - Implements index_function_t -.
Definition functions.c:3085
static int op_edit_raw_message(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Edit the raw message (edit and edit-raw-message are synonyms) - Implements index_function_t -.
Definition functions.c:1076
static int op_post(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Followup to newsgroup - Implements index_function_t -.
Definition functions.c:3632
static int op_get_message(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Get parent of the current message - Implements index_function_t -.
Definition functions.c:3470
static int op_delete_thread(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Delete all messages in thread - Implements index_function_t -.
Definition functions.c:874
static int op_pipe(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Pipe message/attachment to a shell command - Implements index_function_t -.
Definition functions.c:2721
static int op_main_break_thread(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Break the thread in two - Implements index_function_t -.
Definition functions.c:1422
static int op_group_reply(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Reply to all recipients - Implements index_function_t -.
Definition functions.c:1242
static int op_toggle_new(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Toggle a message's 'new' flag - Implements index_function_t -.
Definition functions.c:3109
static int op_main_imap_logout_all(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Logout from all IMAP servers - Implements index_function_t -.
Definition functions.c:3311
static int op_main_close_all_threads(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Collapse all threads - Implements index_function_t -.
Definition functions.c:1582
static int op_main_open_all_threads(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Open all threads - Implements index_function_t -.
Definition functions.c:1635
static int op_end_cond(struct IndexFunctionData *fdata, const struct KeyEvent *event)
End of conditional execution (noop) - Implements index_function_t -.
Definition functions.c:1123
static int op_print(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Print the current entry - Implements index_function_t -.
Definition functions.c:2768
static int op_view_attachments(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Show MIME attachments - Implements index_function_t -.
Definition functions.c:3258
static int op_toggle_write(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Toggle whether the mailbox will be rewritten - Implements index_function_t -.
Definition functions.c:3155
static int op_main_change_folder(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Open a different folder - Implements index_function_t -.
Definition functions.c:1494
static int op_main_fetch_mail(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Retrieve mail from POP server - Implements index_function_t -.
Definition functions.c:3854
static int op_main_prev_unread_mailbox(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Open previous mailbox with unread mail - Implements index_function_t -.
Definition functions.c:2258
static int op_main_collapse_all(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Collapse/uncollapse all threads - Implements index_function_t -.
Definition functions.c:1564
static int op_main_next_undeleted(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Move to the next undeleted message - Implements index_function_t -.
Definition functions.c:2175
static int find_next_new_email(struct Mailbox *m, int start, bool forwards, int op)
Jump to next new message - Implements index_function_t -.
Definition functions.c:1987
static int op_autocrypt_acct_menu(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Manage autocrypt accounts - Implements index_function_t -.
Definition functions.c:3288
static int op_tag(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Tag the current entry - Implements index_function_t -.
Definition functions.c:3039
static int op_main_open_thread(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Open current thread - Implements index_function_t -.
Definition functions.c:1658
static int op_undelete(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Undelete the current entry - Implements index_function_t -.
Definition functions.c:3165
static int op_main_collapse_thread(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Collapse/uncollapse current thread - Implements index_function_t -.
Definition functions.c:1620
static int op_main_next_thread(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Jump to the next thread - Implements index_function_t -.
Definition functions.c:2132
static int op_main_delete_pattern(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Delete messages matching a pattern - Implements index_function_t -.
Definition functions.c:1677
static int op_main_entire_thread(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Read entire thread of the current message - Implements index_function_t -.
Definition functions.c:3676
static int op_mark_msg(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Create a hotkey macro for the current message - Implements index_function_t -.
Definition functions.c:2641
static int op_main_quasi_delete(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Delete from NeoMutt, don't touch on disk - Implements index_function_t -.
Definition functions.c:2341
static int op_undelete_thread(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Undelete all messages in thread - Implements index_function_t -.
Definition functions.c:3208
static int op_main_set_flag(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Set a status flag on a message - Implements index_function_t -.
Definition functions.c:2450
static int op_main_root_message(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Jump to root message in thread - Implements index_function_t -.
Definition functions.c:2431
static int op_main_read_thread(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Mark the current thread as read - Implements index_function_t -.
Definition functions.c:2377
static int op_main_change_group(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Open a different newsgroup - Implements index_function_t -.
Definition functions.c:3552
static int op_main_close_thread(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Collapse current thread - Implements index_function_t -.
Definition functions.c:1605
static int op_prev_entry(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Move to the previous entry - Implements index_function_t -.
Definition functions.c:2744
static int op_flag_message(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Toggle a message's 'important' flag - Implements index_function_t -.
Definition functions.c:1171
static int op_main_modify_tags(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Modify (notmuch/imap) tags - Implements index_function_t -.
Definition functions.c:1849
#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.
int mutt_parent_message(struct Email *e, bool find_root, int count)
Find the parent of a message.
Definition thread.c:1457
bool mutt_link_threads(struct Email *parent, struct EmailArray *children, struct Mailbox *m)
Forcibly link threads together.
Definition thread.c:1870
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:1774
off_t mutt_set_vnum(struct Mailbox *m)
Set the virtual index number of all the messages in a mailbox.
Definition thread.c:1515
int mutt_aside_thread(struct Email *e, bool forwards, bool subthreads)
Find the next/previous (sub)thread.
Definition thread.c:1389
bool mutt_thread_can_collapse(struct Email *e)
Check whether a thread can be collapsed.
Definition thread.c:1940
struct HashTable * mutt_make_id_hash(struct Mailbox *m)
Create a Hash Table for Message-IDs.
Definition thread.c:1825
#define mutt_thread_next_unread(e)
Definition thread.h:116
#define mutt_using_threads()
Definition thread.h:119
#define mutt_uncollapse_thread(e)
Definition thread.h:113
@ MIT_POSITION
Our position in the thread.
Definition thread.h:95
#define mutt_next_subthread(e)
Definition thread.h:126
#define mutt_thread_contains_unread(e)
Definition thread.h:114
#define mutt_next_thread(e)
Definition thread.h:124
#define mutt_collapse_thread(e)
Definition thread.h:112
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:365
Read/write command history from/to a file.
@ HC_OTHER
Miscellaneous strings.
Definition lib.h:61
void exec_startup_shutdown_hook(enum CommandId id)
Execute any startup/shutdown hooks.
Definition exec.c:418
void exec_message_hook(struct Mailbox *m, struct Email *e, enum CommandId id)
Perform a message hook.
Definition exec.c:137
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:1220
static int op_main_change_thread(struct IndexFunctionData *fdata, struct EmailArray *ea, enum CollapseMode mode)
Open/close/collapse a working set of threads.
Definition functions.c:787
static void update_thread_email(struct IndexPrivateData *priv, struct Email *email)
Focus a visible email in the current thread.
Definition functions.c:762
static const struct MenuFuncOp OpIndex[]
Functions for the Index Menu.
Definition functions.c:88
static bool ea_contains_thread_target(struct EmailArray *ea, struct Email *e, bool subthread)
Does the array already include this thread target?
Definition functions.c:538
static int ea_add_selection(struct EmailArray *ea, struct MailboxView *mv, struct Email *e, bool use_tagged, int count)
Build a working set of Emails for an action.
Definition functions.c:480
static int ea_add_selection_threads(struct EmailArray *ea, struct MailboxView *mv, struct Email *e, bool use_tagged, bool subthread, int count)
Build a working set of threads/subthreads.
Definition functions.c:568
void index_init_keys(struct NeoMutt *n, struct SubMenu *sm_generic)
Initialise the Index Keybindings - Implements init_keys_api.
Definition functions.c:332
bool index_next_undeleted(struct MuttWindow *win_index)
Select the next undeleted Email (if possible).
Definition functions.c:444
struct MenuDefinition * index_get_menu_definition(void)
Get the Index Menu Definition.
Definition functions.c:4118
static bool resolve_email(struct IndexPrivateData *priv, struct IndexSharedData *shared, enum ResolveMethod rm, int count)
Pick the next Email to advance the cursor to.
Definition functions.c:371
struct SubMenu * index_get_submenu(void)
Get the Index SubMenu.
Definition functions.c:355
static const struct MenuOpSeq IndexDefaultBindings[]
Key bindings for the Index Menu.
Definition functions.c:229
static struct MuttThread * thread_target(struct Email *e, bool subthread)
Get the thread/subthread target for an email.
Definition functions.c:516
static bool prereq(struct IndexSharedData *shared, struct Menu *menu, CheckFlags checks)
Check the pre-requisites for a function.
Definition functions.c:3871
static const struct IndexFunction IndexFunctions[]
All the NeoMutt functions that the Index supports.
Definition functions.c:3920
ResolveMethod
How to advance the cursor.
Definition functions.c:322
@ RESOLVE_NEXT_SUBTHREAD
Next sibling sub-thread.
Definition functions.c:326
@ RESOLVE_NEXT_UNDELETED
Next undeleted email.
Definition functions.c:324
@ RESOLVE_NEXT_EMAIL
Next email, whatever its state.
Definition functions.c:323
@ RESOLVE_NEXT_THREAD
Next top-level thread.
Definition functions.c:325
static int op_main_next_new(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Definition functions.c:2054
Index functions.
GUI manage the main index (list of emails).
uint8_t CheckFlags
Definition lib.h:96
@ NT_INDEX_EMAIL
Email has changed.
Definition lib.h:80
CollapseMode
Action to perform on a Thread.
Definition lib.h:102
@ COLLAPSE_MODE_TOGGLE
Toggle collapsed state.
Definition lib.h:103
@ COLLAPSE_MODE_CLOSE
Collapse all threads.
Definition lib.h:104
@ COLLAPSE_MODE_OPEN
Open all threads.
Definition lib.h:105
@ CHECK_VISIBLE
Is the selected message visible in the index?
Definition lib.h:92
@ CHECK_NONE
No flags are set.
Definition lib.h:89
@ CHECK_READONLY
Is the mailbox readonly?
Definition lib.h:93
@ CHECK_MSGCOUNT
Are there any messages?
Definition lib.h:91
@ CHECK_IN_MAILBOX
Is there a mailbox open?
Definition lib.h:90
@ CHECK_ATTACH
Is the user in message-attach mode?
Definition lib.h:94
Index private Module data.
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:88
struct MenuDefinition * km_register_menu(int menu, const char *name)
Register a menu.
Definition init.c:105
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(const struct MenuDefinition *md, const char *key_str, int op, char *macro, char *desc, struct Buffer *err)
Set up a key binding.
Definition menu.c:52
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
#define MAX(a, b)
Return the maximum of two values.
Definition memory.h:38
GUI present the user with a selectable list.
MenuRedrawFlags menu_current_middle(struct Menu *menu)
Move the current selection to the centre of the window.
Definition move.c:486
void menu_queue_redraw(struct Menu *menu, MenuRedrawFlags redraw)
Queue a request for a redraw.
Definition menu.c:177
int menu_get_index(struct Menu *menu)
Get the current selection in the Menu.
Definition menu.c:153
@ MENU_REDRAW_INDEX
Redraw the index.
Definition lib.h:61
@ MENU_REDRAW_FULL
Redraw everything.
Definition lib.h:64
@ MENU_REDRAW_CURRENT
Redraw the current line of the menu.
Definition lib.h:63
MenuRedrawFlags menu_set_index(struct Menu *menu, int index)
Set the current selection in the Menu.
Definition menu.c:167
Mailing-list action dialog.
@ MODULE_ID_INDEX
ModuleIndex, Index
Definition module_api.h:73
@ MODULE_ID_NNTP
ModuleNntp, Nntp
Definition module_api.h:83
void msgwin_clear_text(struct MuttWindow *win)
Clear the text in the Message Window.
Definition msgwin.c:556
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:678
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:587
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.
struct Mailbox * mutt_mailbox_prev_unread(struct Mailbox *m_cur, struct Buffer *s)
Find previous mailbox with unread 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:431
Some miscellaneous functions.
struct Email * mutt_get_virt_email(struct Mailbox *m, int vnum)
Get a virtual Email.
Definition mview.c:378
bool mutt_limit_current_thread(struct MailboxView *mv, struct Email *e)
Limit the email view to the current thread.
Definition mview.c:441
void mview_free(struct MailboxView **ptr)
Free a MailboxView.
Definition mview.c:47
bool message_is_tagged(struct Email *e)
Is a message in the index tagged (and within limit).
Definition mview.c:363
bool mview_has_limit(const struct MailboxView *mv)
Is a limit active?
Definition mview.c:399
int ea_add_tagged(struct EmailArray *ea, struct MailboxView *mv, struct Email *e, bool use_tagged)
Get an array of the tagged Emails.
Definition selection.c:128
int mx_tags_edit(struct Mailbox *m, const char *tags, struct Buffer *buf)
Start the tag editor of the mailbox.
Definition mx.c:1279
int mx_msg_close(struct Mailbox *m, struct Message **ptr)
Close a message.
Definition mx.c:1185
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:1618
struct Message * mx_msg_open(struct Mailbox *m, struct Email *e)
Return a stream pointer for a message.
Definition mx.c:1139
bool mx_tags_is_supported(struct Mailbox *m)
Return true if mailbox support tagging.
Definition mx.c:1316
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:1299
int mx_toggle_write(struct Mailbox *m)
Toggle the mailbox's readonly flag.
Definition mx.c:1824
enum MxStatus mx_mbox_sync(struct Mailbox *m)
Save changes to mailbox.
Definition mx.c:904
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:70
@ MX_STATUS_OK
No changes.
Definition mxapi.h:72
@ MX_STATUS_REOPENED
Mailbox was reopened.
Definition mxapi.h:75
@ MX_STATUS_NEW_MAIL
New mail received in Mailbox.
Definition mxapi.h:73
API for encryption/signing of emails.
#define PGP_TRADITIONAL_CHECKED
Email has a traditional (inline) signature.
Definition lib.h:108
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition lib.h:106
#define WithCrypto
Definition lib.h:132
void * neomutt_get_module_data(struct NeoMutt *n, enum ModuleId id)
Get the private data for a Module.
Definition neomutt.c:666
@ NT_GLOBAL_SHUTDOWN
NeoMutt is about to close.
Definition neomutt.h:70
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:2227
int nntp_check_children(struct Mailbox *m, const char *msgid)
Fetch children of article with the Message-ID.
Definition nntp.c:2298
void nntp_mailbox(struct Mailbox *m, char *buf, size_t buflen)
Get first newsgroup with new messages.
Definition newsrc.c:1321
struct NntpMboxData * mutt_newsgroup_catchup(struct Mailbox *m, struct NntpAccountData *adata, char *group)
Catchup newsgroup.
Definition newsrc.c:1239
struct NntpAccountData * nntp_select_server(struct Mailbox *m, const char *server, bool leave_lock)
Open a connection to an NNTP server.
Definition newsrc.c:957
Nntp-specific Mailbox data.
Nntp private Module data.
@ NT_MAILBOX
Mailbox has changed, NotifyMailbox, EventMailbox.
Definition notify_type.h:50
@ 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:284
void nm_db_longrun_done(struct Mailbox *m)
Finish a long transaction.
Definition db.c:393
void nm_db_longrun_init(struct Mailbox *m, bool writable)
Start a long transaction.
Definition db.c:378
Notmuch virtual mailbox type.
void nm_query_window_reset(void)
Resets the vfolder window position to the present.
Definition notmuch.c:1725
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:1714
bool nm_query_window_available(void)
Are windowed queries enabled for use?
Definition notmuch.c:1677
bool nm_message_is_still_queried(struct Mailbox *m, struct Email *e)
Is a message still visible in the query?
Definition notmuch.c:1737
void nm_query_window_forward(void)
Function to move the current search window forward in time.
Definition notmuch.c:1694
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:447
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:465
int mutt_pattern_func(struct MailboxView *mv, int op, char *prompt)
Perform some Pattern matching.
Definition pattern.c:295
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:533
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
uint8_t SearchFlags
@ SEARCH_NONE
No flags are set.
@ SEARCH_PROMPT
Ask for search input.
@ SEARCH_OPPOSITE
Search in the opposite direction.
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:1561
bool mutt_send_list_unsubscribe(struct Mailbox *m, struct Email *e)
Send a mailing-list unsubscription email.
Definition send.c:2990
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:2035
bool mutt_send_list_subscribe(struct Mailbox *m, struct Email *e)
Send a mailing-list subscription email.
Definition send.c:2961
uint32_t SendFlags
Definition send.h:64
@ SEND_KEY
Mail a PGP public key.
Definition send.h:52
@ SEND_GROUP_CHAT_REPLY
Reply to all recipients preserving To/Cc.
Definition send.h:58
@ SEND_REPLY
Reply to sender.
Definition send.h:46
@ SEND_NONE
No flags are set.
Definition send.h:45
@ SEND_FORWARD
Forward email.
Definition send.h:49
@ SEND_GROUP_REPLY
Reply to all.
Definition send.h:47
@ SEND_TO_SENDER
Compose new email to sender.
Definition send.h:57
@ SEND_LIST_REPLY
Reply to mailing list.
Definition send.h:48
@ SEND_NEWS
Reply to a news article.
Definition send.h:59
@ SEND_POSTPONED
Recall a postponed email.
Definition send.h:50
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 changed
Email has been edited.
Definition email.h:77
bool attach_del
Has an attachment marked for deletion.
Definition email.h:99
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
struct MuttThread * thread
Thread of Emails.
Definition email.h:119
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:192
Data passed to Index worker functions.
Definition functions.h:35
struct IndexSharedData * shared
Shared Index data.
Definition functions.h:38
struct IndexPrivateData * priv
Private Index data.
Definition functions.h:39
struct IndexModuleData * mod_data
Index module data.
Definition functions.h:37
struct NeoMutt * n
NeoMutt application data.
Definition functions.h:36
A NeoMutt function.
Definition functions.h:62
int op
Op code, e.g. OP_MAIN_LIMIT.
Definition functions.h:63
index_function_t function
Function to call.
Definition functions.h:64
int flags
Prerequisites for the function, e.g. CHECK_IN_MAILBOX.
Definition functions.h:65
Index private Module data.
Definition module_data.h:32
struct MenuDefinition * md_index
Index Menu Definition.
Definition module_data.h:34
struct SubMenu * sm_index
Index functions.
Definition module_data.h:35
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:75
int count
Optional count prefix, e.g. 3 for 3j.
Definition get.h:78
int op
Function opcode, e.g. OP_HELP.
Definition get.h:77
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:81
int vcount
The number of virtual messages.
Definition mailbox.h:101
bool changed
Mailbox has been modified.
Definition mailbox.h:112
int msg_count
Total number of messages.
Definition mailbox.h:90
AclFlags rights
ACL bits, see AclFlags.
Definition mailbox.h:121
enum MailboxType type
Mailbox type.
Definition mailbox.h:104
void * mdata
Driver specific data.
Definition mailbox.h:134
struct Email ** emails
Array of Emails.
Definition mailbox.h:98
char * name
A short name for the Mailbox.
Definition mailbox.h:84
struct Notify * notify
Notifications: NotifyMailbox, EventMailbox.
Definition mailbox.h:147
struct HashTable * id_hash
Hash Table: "Message-ID" -> Email.
Definition mailbox.h:125
struct Buffer pathbuf
Path of the Mailbox.
Definition mailbox.h:82
bool readonly
Don't allow changes to the mailbox.
Definition mailbox.h:118
bool verbose
Display status messages?
Definition mailbox.h:119
Functions for a Dialog or Window.
Definition menudef.h:44
Mapping between a function and an operation.
Definition menu.h:37
Mapping between an operation and a key sequence.
Definition menu.h:47
Definition lib.h:86
int max
Number of entries in the menu.
Definition lib.h:88
A local copy of an email.
Definition message.h:34
FILE * fp
pointer to the message data
Definition message.h:35
An Email conversation.
Definition thread.h:34
struct MuttThread * parent
Parent of this Thread.
Definition thread.h:44
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
Nntp private Module data.
Definition module_data.h:30
struct NntpAccountData * current_news_srv
Current NNTP news server.
Definition module_data.h:32
bool reverse
search backwards
struct PatternList * pattern
compiled search pattern
Collection of related functions.
Definition menudef.h:33
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