NeoMutt  2025-12-11-911-gd8d604
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
functions.c
Go to the documentation of this file.
1
24
30
31#include "config.h"
32#include <limits.h>
33#include <stdbool.h>
34#include <stdio.h>
35#include "mutt/lib.h"
36#include "config/lib.h"
37#include "email/lib.h"
38#include "core/lib.h"
39#include "alias/lib.h"
40#include "gui/lib.h"
41#include "mutt.h"
42#include "functions.h"
43#include "lib.h"
44#include "attach/lib.h"
45#include "browser/lib.h"
46#include "editor/lib.h"
47#include "history/lib.h"
48#include "hooks/lib.h"
49#include "imap/lib.h"
50#include "key/lib.h"
51#include "menu/lib.h"
52#include "ncrypt/lib.h"
53#include "nntp/lib.h"
54#include "pager/lib.h"
55#include "pattern/lib.h"
56#include "pop/lib.h"
57#include "progress/lib.h"
58#include "question/lib.h"
59#include "send/lib.h"
60#include "sidebar/lib.h"
61#include "external.h"
62#include "globals.h"
63#include "module_data.h"
64#include "mutt_mailbox.h"
65#include "muttlib.h"
66#include "mx.h"
67#include "nntp/mdata.h"
68#include "nntp/module_data.h"
69#include "private_data.h"
70#include "shared_data.h"
71#ifdef USE_AUTOCRYPT
72#include "autocrypt/lib.h"
73#endif
74#ifdef USE_NOTMUCH
75#include "notmuch/lib.h"
76#endif
77#ifdef ENABLE_NLS
78#include <libintl.h>
79#endif
80
81static int op_jump(struct IndexFunctionData *fdata, const struct KeyEvent *event);
82
83// clang-format off
87static const struct MenuFuncOp OpIndex[] = { /* map: index */
88 { "alias-dialog", OP_ALIAS_DIALOG },
89#ifdef USE_AUTOCRYPT
90 { "autocrypt-acct-menu", OP_AUTOCRYPT_ACCT_MENU },
91#endif
92 { "bounce-message", OP_BOUNCE_MESSAGE },
93 { "break-thread", OP_MAIN_BREAK_THREAD },
94 { "catchup", OP_CATCHUP },
95 { "change-folder", OP_MAIN_CHANGE_FOLDER },
96 { "change-folder-readonly", OP_MAIN_CHANGE_FOLDER_READONLY },
97 { "change-newsgroup", OP_MAIN_CHANGE_GROUP },
98 { "change-newsgroup-readonly", OP_MAIN_CHANGE_GROUP_READONLY },
99#ifdef USE_NOTMUCH
100 { "change-vfolder", OP_MAIN_CHANGE_VFOLDER },
101#endif
102 { "check-traditional-pgp", OP_CHECK_TRADITIONAL },
103 { "clear-flag", OP_MAIN_CLEAR_FLAG },
104 { "close-all-threads", OP_MAIN_CLOSE_ALL_THREADS },
105 { "close-thread", OP_MAIN_CLOSE_THREAD },
106 { "collapse-all", OP_MAIN_COLLAPSE_ALL },
107 { "collapse-thread", OP_MAIN_COLLAPSE_THREAD },
108 { "compose-to-sender", OP_COMPOSE_TO_SENDER },
109 { "copy-message", OP_COPY_MESSAGE },
110 { "create-alias", OP_CREATE_ALIAS },
111 { "decode-copy", OP_DECODE_COPY },
112 { "decode-save", OP_DECODE_SAVE },
113 { "decrypt-copy", OP_DECRYPT_COPY },
114 { "decrypt-save", OP_DECRYPT_SAVE },
115 { "delete-message", OP_DELETE },
116 { "delete-pattern", OP_MAIN_DELETE_PATTERN },
117 { "delete-subthread", OP_DELETE_SUBTHREAD },
118 { "delete-thread", OP_DELETE_THREAD },
119 { "display-address", OP_DISPLAY_ADDRESS },
120 { "display-message", OP_DISPLAY_MESSAGE },
121 { "display-toggle-weed", OP_DISPLAY_HEADERS },
122 { "edit", OP_EDIT_RAW_MESSAGE },
123 { "edit-label", OP_EDIT_LABEL },
124 { "edit-or-view-raw-message", OP_EDIT_OR_VIEW_RAW_MESSAGE },
125 { "edit-raw-message", OP_EDIT_RAW_MESSAGE },
126 { "edit-type", OP_ATTACH_EDIT_TYPE },
127#ifdef USE_NOTMUCH
128 { "entire-thread", OP_MAIN_ENTIRE_THREAD },
129#endif
130 { "exit", OP_EXIT },
131 { "extract-keys", OP_EXTRACT_KEYS },
132 { "fetch-mail", OP_MAIN_FETCH_MAIL },
133 { "flag-message", OP_FLAG_MESSAGE },
134 { "followup-message", OP_FOLLOWUP },
135 { "forget-passphrase", OP_FORGET_PASSPHRASE },
136 { "forward-message", OP_FORWARD_MESSAGE },
137 { "forward-to-group", OP_FORWARD_TO_GROUP },
138 { "get-children", OP_GET_CHILDREN },
139 { "get-message", OP_GET_MESSAGE },
140 { "get-parent", OP_GET_PARENT },
141 { "group-chat-reply", OP_GROUP_CHAT_REPLY },
142 { "group-reply", OP_GROUP_REPLY },
143 { "imap-fetch-mail", OP_MAIN_IMAP_FETCH },
144 { "imap-logout-all", OP_MAIN_IMAP_LOGOUT_ALL },
145 { "limit", OP_MAIN_LIMIT },
146 { "limit-current-thread", OP_LIMIT_CURRENT_THREAD },
147 { "link-threads", OP_MAIN_LINK_THREADS },
148 { "list-action", OP_LIST_ACTION },
149 { "list-reply", OP_LIST_REPLY },
150 { "list-subscribe", OP_LIST_SUBSCRIBE },
151 { "list-unsubscribe", OP_LIST_UNSUBSCRIBE },
152 { "mail", OP_MAIL },
153 { "mail-key", OP_MAIL_KEY },
154 { "mailbox-list", OP_MAILBOX_LIST },
155 { "mark-message", OP_MARK_MSG },
156 { "modify-labels", OP_MAIN_MODIFY_TAGS },
157 { "modify-labels-then-hide", OP_MAIN_MODIFY_TAGS_THEN_HIDE },
158 { "modify-tags", OP_MAIN_MODIFY_TAGS },
159 { "modify-tags-then-hide", OP_MAIN_MODIFY_TAGS_THEN_HIDE },
160 { "next-new", OP_MAIN_NEXT_NEW },
161 { "next-new-then-unread", OP_MAIN_NEXT_NEW_THEN_UNREAD },
162 { "next-subthread", OP_MAIN_NEXT_SUBTHREAD },
163 { "next-thread", OP_MAIN_NEXT_THREAD },
164 { "next-undeleted", OP_MAIN_NEXT_UNDELETED },
165 { "next-unread", OP_MAIN_NEXT_UNREAD },
166 { "next-unread-mailbox", OP_MAIN_NEXT_UNREAD_MAILBOX },
167 { "open-all-threads", OP_MAIN_OPEN_ALL_THREADS },
168 { "open-thread", OP_MAIN_OPEN_THREAD },
169 { "parent-message", OP_MAIN_PARENT_MESSAGE },
170 { "pipe-entry", OP_PIPE },
171 { "pipe-message", OP_PIPE },
172 { "post-message", OP_POST },
173 { "previous-new", OP_MAIN_PREV_NEW },
174 { "previous-new-then-unread", OP_MAIN_PREV_NEW_THEN_UNREAD },
175 { "previous-subthread", OP_MAIN_PREV_SUBTHREAD },
176 { "previous-thread", OP_MAIN_PREV_THREAD },
177 { "previous-undeleted", OP_MAIN_PREV_UNDELETED },
178 { "previous-unread", OP_MAIN_PREV_UNREAD },
179 { "previous-unread-mailbox", OP_MAIN_PREV_UNREAD_MAILBOX },
180 { "print-message", OP_PRINT },
181 { "purge-message", OP_PURGE_MESSAGE },
182 { "purge-thread", OP_PURGE_THREAD },
183 { "quasi-delete", OP_MAIN_QUASI_DELETE },
184 { "query", OP_QUERY },
185 { "quit", OP_QUIT },
186 { "read-subthread", OP_MAIN_READ_SUBTHREAD },
187 { "read-thread", OP_MAIN_READ_THREAD },
188 { "recall-message", OP_RECALL_MESSAGE },
189 { "reconstruct-thread", OP_RECONSTRUCT_THREAD },
190 { "reply", OP_REPLY },
191 { "resend-message", OP_RESEND },
192 { "root-message", OP_MAIN_ROOT_MESSAGE },
193 { "save-message", OP_SAVE },
194 { "set-flag", OP_MAIN_SET_FLAG },
195 { "show-limit", OP_MAIN_SHOW_LIMIT },
196 { "sort-mailbox", OP_SORT },
197 { "sort-reverse", OP_SORT_REVERSE },
198 { "sync-mailbox", OP_MAIN_SYNC_FOLDER },
199 { "tag-pattern", OP_MAIN_TAG_PATTERN },
200 { "tag-subthread", OP_TAG_SUBTHREAD },
201 { "tag-thread", OP_TAG_THREAD },
202 { "toggle-new", OP_TOGGLE_NEW },
203 { "toggle-read", OP_TOGGLE_READ },
204 { "toggle-write", OP_TOGGLE_WRITE },
205 { "undelete-message", OP_UNDELETE },
206 { "undelete-pattern", OP_MAIN_UNDELETE_PATTERN },
207 { "undelete-subthread", OP_UNDELETE_SUBTHREAD },
208 { "undelete-thread", OP_UNDELETE_THREAD },
209 { "untag-pattern", OP_MAIN_UNTAG_PATTERN },
210#ifdef USE_NOTMUCH
211 { "vfolder-from-query", OP_MAIN_VFOLDER_FROM_QUERY },
212 { "vfolder-from-query-readonly", OP_MAIN_VFOLDER_FROM_QUERY_READONLY },
213 { "vfolder-window-backward", OP_MAIN_WINDOWED_VFOLDER_BACKWARD },
214 { "vfolder-window-forward", OP_MAIN_WINDOWED_VFOLDER_FORWARD },
215 { "vfolder-window-reset", OP_MAIN_WINDOWED_VFOLDER_RESET },
216#endif
217 { "view-attachments", OP_VIEW_ATTACHMENTS },
218 { "view-raw-message", OP_VIEW_RAW_MESSAGE },
219 // Deprecated
220 { "buffy-list", OP_MAILBOX_LIST, MFF_DEPRECATED },
221 { NULL, 0 },
222};
223
227static const struct MenuFuncOp OpList[] = { /* map: list */
228 { "exit", OP_EXIT },
229 { "list-archive", OP_LIST_ARCHIVE },
230 { "list-help", OP_LIST_HELP },
231 { "list-owner", OP_LIST_OWNER },
232 { "list-post", OP_LIST_POST },
233 { "list-subscribe", OP_LIST_SUBSCRIBE },
234 { "list-unsubscribe", OP_LIST_UNSUBSCRIBE },
235 { NULL, 0 },
236};
237
241static const struct MenuOpSeq IndexDefaultBindings[] = { /* map: index */
242 { OP_ATTACH_EDIT_TYPE, "\005" }, // <Ctrl-E>
243#ifdef USE_AUTOCRYPT
244 { OP_AUTOCRYPT_ACCT_MENU, "A" },
245#endif
246 { OP_BOUNCE_MESSAGE, "b" },
247 { OP_CHECK_TRADITIONAL, "\033P" }, // <Alt-P>
248 { OP_COPY_MESSAGE, "C" },
249 { OP_CREATE_ALIAS, "a" },
250 { OP_DECODE_COPY, "\033C" }, // <Alt-C>
251 { OP_DECODE_SAVE, "\033s" }, // <Alt-s>
252 { OP_DELETE, "d" },
253 { OP_DELETE_SUBTHREAD, "\033d" }, // <Alt-d>
254 { OP_DELETE_THREAD, "\004" }, // <Ctrl-D>
255 { OP_DISPLAY_ADDRESS, "@" },
256 { OP_DISPLAY_HEADERS, "h" },
257 { OP_DISPLAY_MESSAGE, " " }, // <Space>
258 { OP_DISPLAY_MESSAGE, "<keypadenter>" },
259 { OP_DISPLAY_MESSAGE, "\n" }, // <Enter>
260 { OP_DISPLAY_MESSAGE, "\r" }, // <Return>
261 { OP_EDIT_LABEL, "Y" },
262 { OP_EDIT_OR_VIEW_RAW_MESSAGE, "e" },
263 { OP_EXIT, "x" },
264 { OP_EXTRACT_KEYS, "\013" }, // <Ctrl-K>
265 { OP_FLAG_MESSAGE, "F" },
266 { OP_FORGET_PASSPHRASE, "\006" }, // <Ctrl-F>
267 { OP_FORWARD_MESSAGE, "f" },
268 { OP_GROUP_REPLY, "g" },
269 { OP_LIST_ACTION, "\033L" }, // <Alt-L>
270 { OP_LIST_REPLY, "L" },
271 { OP_MAIL, "m" },
272 { OP_MAILBOX_LIST, "." },
273 { OP_MAIL_KEY, "\033k" }, // <Alt-k>
274 { OP_MAIN_BREAK_THREAD, "#" },
275 { OP_MAIN_CHANGE_FOLDER, "c" },
276 { OP_MAIN_CHANGE_FOLDER_READONLY, "\033c" }, // <Alt-c>
277 { OP_MAIN_CHANGE_GROUP, "i" },
278 { OP_MAIN_CHANGE_GROUP_READONLY, "\033i" }, // <Alt-i>
279 { OP_MAIN_CLEAR_FLAG, "W" },
280 { OP_MAIN_COLLAPSE_ALL, "\033V" }, // <Alt-V>
281 { OP_MAIN_COLLAPSE_THREAD, "\033v" }, // <Alt-v>
282 { OP_MAIN_DELETE_PATTERN, "D" },
283 { OP_MAIN_FETCH_MAIL, "G" },
284 { OP_MAIN_LIMIT, "l" },
285 { OP_MAIN_LINK_THREADS, "&" },
286 { OP_MAIN_NEXT_NEW_THEN_UNREAD, "\t" }, // <Tab>
287 { OP_MAIN_NEXT_SUBTHREAD, "\033n" }, // <Alt-n>
288 { OP_MAIN_NEXT_THREAD, "\016" }, // <Ctrl-N>
289 { OP_MAIN_NEXT_UNDELETED, "<down>" },
290 { OP_MAIN_NEXT_UNDELETED, "j" },
291 { OP_MAIN_PARENT_MESSAGE, "P" },
292 { OP_MAIN_PREV_NEW_THEN_UNREAD, "\033\t" }, // <Alt-Tab>
293 { OP_MAIN_PREV_SUBTHREAD, "\033p" }, // <Alt-p>
294 { OP_MAIN_PREV_THREAD, "\020" }, // <Ctrl-P>
295 { OP_MAIN_PREV_UNDELETED, "<up>" },
296 { OP_MAIN_PREV_UNDELETED, "k" },
297 { OP_MAIN_READ_SUBTHREAD, "\033r" }, // <Alt-r>
298 { OP_MAIN_READ_THREAD, "\022" }, // <Ctrl-R>
299 { OP_MAIN_SET_FLAG, "w" },
300 { OP_MAIN_SHOW_LIMIT, "\033l" }, // <Alt-l>
301 { OP_MAIN_SYNC_FOLDER, "$" },
302 { OP_MAIN_TAG_PATTERN, "T" },
303 { OP_MAIN_UNDELETE_PATTERN, "U" },
304 { OP_MAIN_UNTAG_PATTERN, "\024" }, // <Ctrl-T>
305 { OP_MARK_MSG, "~" },
306 { OP_NEXT_ENTRY, "J" },
307 { OP_PIPE, "|" },
308 { OP_PREV_ENTRY, "K" },
309 { OP_PRINT, "p" },
310 { OP_QUERY, "Q" },
311 { OP_QUIT, "q" },
312 { OP_RECALL_MESSAGE, "R" },
313 { OP_REPLY, "r" },
314 { OP_RESEND, "\033e" }, // <Alt-e>
315 { OP_SAVE, "s" },
316 { OP_SHOW_LOG_MESSAGES, "M" },
317 { OP_SORT, "o" },
318 { OP_SORT_REVERSE, "O" },
319 { OP_TAG_THREAD, "\033t" }, // <Alt-t>
320 { OP_TOGGLE_NEW, "N" },
321 { OP_TOGGLE_WRITE, "%" },
322 { OP_UNDELETE, "u" },
323 { OP_UNDELETE_SUBTHREAD, "\033u" }, // <Alt-u>
324 { OP_UNDELETE_THREAD, "\025" }, // <Ctrl-U>
325 { OP_VIEW_ATTACHMENTS, "v" },
326 { 0, NULL },
327};
328
332static const struct MenuOpSeq ListDefaultBindings[] = { /* map: list */
333 { OP_EXIT, "q" },
334 { OP_LIST_ARCHIVE, "a" },
335 { OP_LIST_HELP, "h" },
336 { OP_LIST_OWNER, "o" },
337 { OP_LIST_POST, "p" },
338 { OP_LIST_SUBSCRIBE, "s" },
339 { OP_LIST_UNSUBSCRIBE, "u" },
340 { 0, NULL },
341};
342// clang-format on
343
354
358void index_init_keys(struct NeoMutt *n, struct SubMenu *sm_generic)
359{
360 struct MenuDefinition *md = NULL;
361 struct MenuDefinition *md_list = NULL;
362 struct SubMenu *sm_index = NULL;
363 struct SubMenu *sm_list = NULL;
364 struct SubMenu *sm_sidebar = sidebar_get_submenu();
365
366 sm_list = km_register_submenu(OpList);
367 md_list = km_register_menu(MENU_LIST, "list");
368 km_menu_add_submenu(md_list, sm_list);
369 km_menu_add_submenu(md_list, sm_generic);
371
372 sm_index = km_register_submenu(OpIndex);
373 md = km_register_menu(MENU_INDEX, "index");
374 km_menu_add_submenu(md, sm_index);
375 km_menu_add_submenu(md, sm_sidebar);
376 km_menu_add_submenu(md, sm_generic);
378
380 ASSERT(mod_data);
381 mod_data->menu_list = md_list;
382 mod_data->menu_index = md;
383}
384
393static bool resolve_email(struct IndexPrivateData *priv, struct IndexSharedData *shared,
394 enum ResolveMethod rm, int count)
395{
396 if (!priv || !priv->menu || !shared || !shared->mailbox || !shared->email)
397 return false;
398
399 const bool c_resolve = cs_subset_bool(shared->sub, "resolve");
400 if (!c_resolve)
401 return false;
402
403 count = MAX(count, 1);
404 int index = menu_get_index(priv->menu);
405
406 switch (rm)
407 {
409 index = index + count;
410 break;
411
413 {
414 const bool uncollapse = mutt_using_threads() && !window_is_focused(priv->win_index);
415 for (int i = 0; i < count; i++)
416 {
417 int next = find_next_undeleted(shared->mailbox_view, index, uncollapse);
418 if (next < 0)
419 break;
420 index = next;
421 }
422 break;
423 }
424
426 for (int i = 0; i < count; i++)
427 {
428 struct Email *e = mutt_get_virt_email(shared->mailbox, index);
429 if (!e)
430 break;
431 int next = mutt_next_thread(e);
432 if (next < 0)
433 break;
434 index = next;
435 }
436 break;
437
439 for (int i = 0; i < count; i++)
440 {
441 struct Email *e = mutt_get_virt_email(shared->mailbox, index);
442 if (!e)
443 break;
444 int next = mutt_next_subthread(e);
445 if (next < 0)
446 break;
447 index = next;
448 }
449 break;
450 }
451
452 if (index < 0)
453 index = 0;
454 if (index >= shared->mailbox->vcount)
455 index = shared->mailbox->vcount - 1;
456
457 menu_set_index(priv->menu, index);
458 return true;
459}
460
466bool index_next_undeleted(struct MuttWindow *win_index)
467{
468 struct MuttWindow *dlg = dialog_find(win_index);
469 if (!dlg)
470 return false;
471
472 struct Menu *menu = win_index->wdata;
473 struct IndexSharedData *shared = dlg->wdata;
474 if (!shared)
475 return false;
476
477 struct IndexPrivateData *priv = win_index->parent->wdata;
478 const bool uncollapse = mutt_using_threads() && !window_is_focused(priv->win_index);
479
480 int index = find_next_undeleted(shared->mailbox_view, menu_get_index(menu), uncollapse);
481 if ((index < 0) || (index >= shared->mailbox->vcount))
482 {
483 // Selection failed
485 return false;
486 }
487
488 menu_set_index(menu, index);
489 return true;
490}
491
502static int ea_add_selection(struct EmailArray *ea, struct MailboxView *mv,
503 struct Email *e, bool use_tagged, int count)
504{
505 if (!ea)
506 return -1;
507
508 if (use_tagged)
509 return ea_add_tagged(ea, mv, e, true);
510
511 if (!mv || !mv->mailbox || !e)
512 return -1;
513
514 const int index = e->vnum;
515 if ((index < 0) || (index >= mv->mailbox->vcount))
516 return -1;
517
518 int n = (count > 1) ? count : 1;
519 if ((index + n) > mv->mailbox->vcount)
520 n = mv->mailbox->vcount - index;
521
522 for (int i = 0; i < n; i++)
523 {
524 struct Email *sel = mutt_get_virt_email(mv->mailbox, index + i);
525 if (sel)
526 ea_add_tagged(ea, mv, sel, false);
527 }
528
529 return ARRAY_SIZE(ea);
530}
531
538static struct MuttThread *thread_target(struct Email *e, bool subthread)
539{
540 if (!e || !e->thread)
541 return NULL;
542
543 struct MuttThread *thread = e->thread;
544 if (!subthread)
545 {
546 while (thread->parent)
547 thread = thread->parent;
548 }
549
550 return thread;
551}
552
560static bool ea_contains_thread_target(struct EmailArray *ea, struct Email *e, bool subthread)
561{
562 if (!ea || !e)
563 return false;
564
565 struct MuttThread *target = thread_target(e, subthread);
566 if (!target)
567 return false;
568
569 struct Email **ep = NULL;
570 ARRAY_FOREACH(ep, ea)
571 {
572 if (thread_target(*ep, subthread) == target)
573 return true;
574 }
575
576 return false;
577}
578
590static int ea_add_selection_threads(struct EmailArray *ea,
591 struct MailboxView *mv, struct Email *e,
592 bool use_tagged, bool subthread, int count)
593{
594 if (!ea)
595 return -1;
596
597 if (!use_tagged)
598 {
599 if (!mv || !mv->mailbox || !e)
600 return -1;
601
602 const int index = e->vnum;
603 if ((index < 0) || (index >= mv->mailbox->vcount))
604 return -1;
605
606 const int n = (count > 1) ? count : 1;
607 for (int i = index; (i < mv->mailbox->vcount) && (ARRAY_SIZE(ea) < n); i++)
608 {
609 struct Email *sel = mutt_get_virt_email(mv->mailbox, i);
610 if (!sel || ea_contains_thread_target(ea, sel, subthread))
611 continue;
612
613 ARRAY_ADD(ea, sel);
614 }
615 return ARRAY_SIZE(ea);
616 }
617
618 if (!mv || !mv->mailbox || !mv->mailbox->emails)
619 return -1;
620
621 struct Mailbox *m = mv->mailbox;
622 for (int i = 0; i < m->msg_count; i++)
623 {
624 struct Email *et = m->emails[i];
625 if (!et)
626 break;
627 if (!message_is_tagged(et))
628 continue;
629
630 if (!ea_contains_thread_target(ea, et, subthread))
631 ARRAY_ADD(ea, et);
632 }
633
634 return ARRAY_SIZE(ea);
635}
636
637// -----------------------------------------------------------------------------
638
642static int op_alias_dialog(struct IndexFunctionData *fdata, const struct KeyEvent *event)
643{
644 struct IndexSharedData *shared = fdata->shared;
645 alias_dialog(shared->mailbox, shared->sub);
646 return FR_SUCCESS;
647}
648
652static int op_attach_edit_type(struct IndexFunctionData *fdata, const struct KeyEvent *event)
653{
654 struct IndexSharedData *shared = fdata->shared;
655 struct IndexPrivateData *priv = fdata->priv;
656 if (!shared->email)
657 return FR_NO_ACTION;
659
661 return FR_SUCCESS;
662}
663
667static int op_bounce_message(struct IndexFunctionData *fdata, const struct KeyEvent *event)
668{
669 struct IndexSharedData *shared = fdata->shared;
670 struct IndexPrivateData *priv = fdata->priv;
671 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
672 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
673 index_bounce_message(shared->mailbox, &ea);
674 ARRAY_FREE(&ea);
675
676 return FR_SUCCESS;
677}
678
682static int op_check_traditional(struct IndexFunctionData *fdata, const struct KeyEvent *event)
683{
684 struct IndexSharedData *shared = fdata->shared;
685 struct IndexPrivateData *priv = fdata->priv;
687 return FR_NOT_IMPL;
688 if (!shared->email)
689 return FR_NO_ACTION;
690
692 {
693 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
694 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
695 if (mutt_check_traditional_pgp(shared->mailbox, &ea))
697 ARRAY_FREE(&ea);
698 }
699
700 return FR_SUCCESS;
701}
702
706static int op_compose_to_sender(struct IndexFunctionData *fdata, const struct KeyEvent *event)
707{
708 struct IndexSharedData *shared = fdata->shared;
709 struct IndexPrivateData *priv = fdata->priv;
710 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
711 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
712 int rc = mutt_send_message(SEND_TO_SENDER, NULL, NULL, shared->mailbox, &ea,
713 shared->sub);
714 ARRAY_FREE(&ea);
716
717 return (rc == -1) ? FR_ERROR : FR_SUCCESS;
718}
719
723static int op_create_alias(struct IndexFunctionData *fdata, const struct KeyEvent *event)
724{
725 struct IndexSharedData *shared = fdata->shared;
726 struct IndexPrivateData *priv = fdata->priv;
727 struct AddressList *al = NULL;
728 if (shared->email && shared->email->env)
729 al = mutt_get_address(shared->email->env, NULL);
730 alias_create(al, shared->sub);
732
733 return FR_SUCCESS;
734}
735
743static int op_delete(struct IndexFunctionData *fdata, const struct KeyEvent *event)
744{
745 struct IndexSharedData *shared = fdata->shared;
746 struct IndexPrivateData *priv = fdata->priv;
747 /* L10N: CHECK_ACL */
748 if (!check_acl(shared->mailbox, MUTT_ACL_DELETE, _("Can't delete message")))
749 return FR_ERROR;
750
751 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
752 ea_add_selection(&ea, shared->mailbox_view, shared->email, priv->tag_prefix,
753 event->count);
754 if (ARRAY_EMPTY(&ea))
755 {
756 ARRAY_FREE(&ea);
757 return FR_NO_ACTION;
758 }
759
760 mutt_emails_set_flag(shared->mailbox, &ea, MUTT_DELETE, true);
761 mutt_emails_set_flag(shared->mailbox, &ea, MUTT_PURGE, (event->op == OP_PURGE_MESSAGE));
762 const bool c_delete_untag = cs_subset_bool(shared->sub, "delete_untag");
763 if (c_delete_untag)
764 mutt_emails_set_flag(shared->mailbox, &ea, MUTT_TAG, false);
765 ARRAY_FREE(&ea);
766
767 if (priv->tag_prefix)
768 {
770 }
771 else
772 {
773 resolve_email(priv, shared, RESOLVE_NEXT_UNDELETED, 1);
774 }
775
776 return FR_SUCCESS;
777}
778
784static void update_thread_email(struct IndexPrivateData *priv, struct Email *email)
785{
786 if (!priv || !priv->menu || !email)
787 return;
788
789 int index = email->vnum;
790 if (index < 0)
791 {
792 struct MuttThread *thread = thread_target(email, false);
793 struct Email *e = find_virtual(thread, false);
794 if (e)
795 index = e->vnum;
796 }
797
798 if (index >= 0)
799 menu_set_index(priv->menu, index);
800}
801
810 struct EmailArray *ea, enum CollapseMode mode)
811{
812 struct IndexSharedData *shared = fdata->shared;
813 struct IndexPrivateData *priv = fdata->priv;
814 if (!mutt_using_threads())
815 {
816 mutt_warning(_("Threading is not enabled"));
817 return FR_ERROR;
818 }
819
820 if (!ea || ARRAY_EMPTY(ea))
821 return FR_NO_ACTION;
822
823 bool changed = false;
824 bool blocked = false;
825 struct Email **ep = NULL;
826 ARRAY_FOREACH(ep, ea)
827 {
828 struct Email *e = *ep;
829 if (!e)
830 continue;
831
832 switch (mode)
833 {
835 if (!e->collapsed)
836 continue;
838 changed = true;
839 break;
841 if (e->collapsed)
842 continue;
844 {
845 blocked = true;
846 continue;
847 }
849 changed = true;
850 break;
852 if (e->collapsed)
853 {
855 changed = true;
856 }
857 else if (mutt_thread_can_collapse(e))
858 {
860 changed = true;
861 }
862 else
863 {
864 blocked = true;
865 }
866 break;
867 }
868 }
869
870 if (!changed)
871 {
872 if (blocked)
873 {
874 mutt_warning(_("Thread contains unread or flagged messages"));
875 return FR_ERROR;
876 }
877 return FR_NO_ACTION;
878 }
879
880 mutt_set_vnum(shared->mailbox);
881 update_thread_email(priv, shared->email);
883 notify_send(shared->notify, NT_INDEX, NT_INDEX_EMAIL, NULL);
884 return FR_SUCCESS;
885}
886
895static int op_delete_thread(struct IndexFunctionData *fdata, const struct KeyEvent *event)
896{
897 struct IndexSharedData *shared = fdata->shared;
898 struct IndexPrivateData *priv = fdata->priv;
899 /* L10N: CHECK_ACL */
900 /* L10N: Due to the implementation details we do not know whether we
901 delete zero, 1, 12, ... messages. So in English we use
902 "messages". Your language might have other means to express this. */
903 if (!check_acl(shared->mailbox, MUTT_ACL_DELETE, _("Can't delete messages")))
904 return FR_ERROR;
905 if (!shared->email)
906 return FR_NO_ACTION;
907
908 const int op = event->op;
909 const bool subthread = (op == OP_DELETE_SUBTHREAD);
910 int rc = 0;
911 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
912 ea_add_selection_threads(&ea, shared->mailbox_view, shared->email,
913 priv->tag_prefix, subthread, event->count);
914
915 struct Email **ep = NULL;
916 ARRAY_FOREACH(ep, &ea)
917 {
918 rc = mutt_thread_set_flag(shared->mailbox, *ep, MUTT_DELETE, true, subthread);
919 if (rc == -1)
920 break;
921
922 if (op == OP_PURGE_THREAD)
923 {
924 rc = mutt_thread_set_flag(shared->mailbox, *ep, MUTT_PURGE, true, subthread);
925 if (rc == -1)
926 break;
927 }
928
929 const bool c_delete_untag = cs_subset_bool(shared->sub, "delete_untag");
930 if (c_delete_untag)
931 mutt_thread_set_flag(shared->mailbox, *ep, MUTT_TAG, false, subthread);
932 }
933 ARRAY_FREE(&ea);
934
935 if (rc == -1)
936 return FR_ERROR;
937
938 if (priv->tag_prefix)
939 {
941 return FR_SUCCESS;
942 }
943
944 resolve_email(priv, shared, RESOLVE_NEXT_UNDELETED, 1);
946 return FR_SUCCESS;
947}
948
952static int op_display_address(struct IndexFunctionData *fdata, const struct KeyEvent *event)
953{
954 struct IndexSharedData *shared = fdata->shared;
955 if (!shared->email)
956 return FR_NO_ACTION;
958
959 return FR_SUCCESS;
960}
961
970static int op_display_message(struct IndexFunctionData *fdata, const struct KeyEvent *event)
971{
972 struct IndexSharedData *shared = fdata->shared;
973 struct IndexPrivateData *priv = fdata->priv;
974 if (!shared->email)
975 return FR_NO_ACTION;
976
977 if (event->count > 0)
978 return op_jump(fdata, event);
979
981
982 int op = event->op;
983 /* toggle the weeding of headers so that a user can press the key
984 * again while reading the message. */
985 if (op == OP_DISPLAY_HEADERS)
986 {
987 bool_str_toggle(shared->sub, "weed", NULL);
989 if (!window_is_focused(priv->win_index))
990 return FR_SUCCESS;
991 }
992
993 OptNeedResort = false;
994
996 {
999 const bool c_uncollapse_jump = cs_subset_bool(shared->sub, "uncollapse_jump");
1000 if (c_uncollapse_jump)
1002 }
1003
1004 const bool c_pgp_auto_decode = cs_subset_bool(shared->sub, "pgp_auto_decode");
1005 if (c_pgp_auto_decode &&
1007 {
1008 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
1009 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
1010 if (mutt_check_traditional_pgp(shared->mailbox, &ea))
1012 ARRAY_FREE(&ea);
1013 }
1014 const int index = menu_get_index(priv->menu);
1016
1017 const char *const c_pager = pager_get_pager(fdata->n->sub);
1018 if (c_pager)
1019 {
1020 op = external_pager(shared->mailbox_view, shared->email, c_pager);
1021 }
1022 else
1023 {
1024 op = mutt_display_message(priv->win_index, shared);
1025 }
1026
1028 if (op < OP_NULL)
1029 {
1030 OptNeedResort = false;
1031 return FR_ERROR;
1032 }
1033
1034 if (shared->mailbox)
1035 {
1037 shared->mailbox->msg_count, shared);
1038 }
1039
1040 return op;
1041}
1042
1046static int op_edit_label(struct IndexFunctionData *fdata, const struct KeyEvent *event)
1047{
1048 struct IndexSharedData *shared = fdata->shared;
1049 struct IndexPrivateData *priv = fdata->priv;
1050 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
1051 ea_add_selection(&ea, shared->mailbox_view, shared->email, priv->tag_prefix,
1052 event->count);
1053 if (ARRAY_EMPTY(&ea))
1054 {
1055 ARRAY_FREE(&ea);
1056 return FR_NO_ACTION;
1057 }
1058 const int num = ARRAY_SIZE(&ea);
1059 int num_changed = mutt_label_message(shared->mailbox_view, &ea);
1060 ARRAY_FREE(&ea);
1061
1062 if (num_changed > 0)
1063 {
1064 shared->mailbox->changed = true;
1066 /* L10N: This is displayed when the x-label on one or more
1067 messages is edited. */
1068 mutt_message(ngettext("%d label changed", "%d labels changed", num_changed), num_changed);
1069
1070 if (!priv->tag_prefix)
1071 resolve_email(priv, shared, RESOLVE_NEXT_UNDELETED, num);
1072 return FR_SUCCESS;
1073 }
1074
1075 /* L10N: This is displayed when editing an x-label, but no messages
1076 were updated. Possibly due to canceling at the prompt or if the new
1077 label is the same as the old label. */
1078 mutt_message(_("No labels changed"));
1079 return FR_NO_ACTION;
1080}
1081
1090static int op_edit_raw_message(struct IndexFunctionData *fdata, const struct KeyEvent *event)
1091{
1092 struct IndexSharedData *shared = fdata->shared;
1093 struct IndexPrivateData *priv = fdata->priv;
1094 /* TODO split this into 3 cases? */
1095 bool edit;
1096 const int op = event->op;
1097 if (op == OP_EDIT_RAW_MESSAGE)
1098 {
1099 /* L10N: CHECK_ACL */
1100 if (!check_acl(shared->mailbox, MUTT_ACL_INSERT, _("Can't edit message")))
1101 return FR_ERROR;
1102 edit = true;
1103 }
1104 else if (op == OP_EDIT_OR_VIEW_RAW_MESSAGE)
1105 {
1107 }
1108 else
1109 {
1110 edit = false;
1111 }
1112
1113 if (!shared->email)
1114 return FR_NO_ACTION;
1115 const bool c_pgp_auto_decode = cs_subset_bool(shared->sub, "pgp_auto_decode");
1116 if (c_pgp_auto_decode &&
1118 {
1119 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
1120 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
1121 if (mutt_check_traditional_pgp(shared->mailbox, &ea))
1123 ARRAY_FREE(&ea);
1124 }
1125 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
1126 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
1127 mutt_ev_message(shared->mailbox, &ea, edit ? EVM_EDIT : EVM_VIEW);
1128 ARRAY_FREE(&ea);
1130
1131 return FR_SUCCESS;
1132}
1133
1137static int op_end_cond(struct IndexFunctionData *fdata, const struct KeyEvent *event)
1138{
1139 return FR_SUCCESS;
1140}
1141
1145static int op_exit(struct IndexFunctionData *fdata, const struct KeyEvent *event)
1146{
1147 struct IndexSharedData *shared = fdata->shared;
1148 if (shared->attach_msg)
1149 return FR_DONE;
1150
1151 if (query_quadoption(_("Exit NeoMutt without saving?"), shared->sub, "quit") == MUTT_YES)
1152 {
1153 if (shared->mailbox_view)
1154 {
1155 mx_fastclose_mailbox(shared->mailbox, false);
1156 mview_free(&shared->mailbox_view);
1157 }
1158 return FR_DONE;
1159 }
1160
1161 return FR_NO_ACTION;
1162}
1163
1167static int op_extract_keys(struct IndexFunctionData *fdata, const struct KeyEvent *event)
1168{
1169 struct IndexSharedData *shared = fdata->shared;
1170 struct IndexPrivateData *priv = fdata->priv;
1171 if (!WithCrypto)
1172 return FR_NOT_IMPL;
1173 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
1174 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
1176 ARRAY_FREE(&ea);
1178
1179 return FR_SUCCESS;
1180}
1181
1185static int op_flag_message(struct IndexFunctionData *fdata, const struct KeyEvent *event)
1186{
1187 struct IndexSharedData *shared = fdata->shared;
1188 struct IndexPrivateData *priv = fdata->priv;
1189 /* L10N: CHECK_ACL */
1190 if (!check_acl(shared->mailbox, MUTT_ACL_WRITE, _("Can't flag message")))
1191 return FR_ERROR;
1192
1193 struct Mailbox *m = shared->mailbox;
1194 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
1195 ea_add_selection(&ea, shared->mailbox_view, shared->email, priv->tag_prefix,
1196 event->count);
1197 if (ARRAY_EMPTY(&ea))
1198 {
1199 ARRAY_FREE(&ea);
1200 return FR_NO_ACTION;
1201 }
1202 const int num = ARRAY_SIZE(&ea);
1203
1204 struct Email **ep = NULL;
1205 ARRAY_FOREACH(ep, &ea)
1206 mutt_set_flag(m, *ep, MUTT_FLAG, !(*ep)->flagged, true);
1207 ARRAY_FREE(&ea);
1208
1209 if (priv->tag_prefix)
1210 {
1212 }
1213 else
1214 {
1215 resolve_email(priv, shared, RESOLVE_NEXT_UNDELETED, num);
1216 if (num > 1)
1218 }
1219
1220 return FR_SUCCESS;
1221}
1222
1226static int op_forget_passphrase(struct IndexFunctionData *fdata, const struct KeyEvent *event)
1227{
1229 return FR_SUCCESS;
1230}
1231
1235static int op_forward_message(struct IndexFunctionData *fdata, const struct KeyEvent *event)
1236{
1237 struct IndexSharedData *shared = fdata->shared;
1238 struct IndexPrivateData *priv = fdata->priv;
1239 if (!shared->email)
1240 return FR_NO_ACTION;
1241 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
1242 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
1243 const bool c_pgp_auto_decode = cs_subset_bool(shared->sub, "pgp_auto_decode");
1244 if (c_pgp_auto_decode &&
1245 (priv->tag_prefix || !(shared->email->security & PGP_TRADITIONAL_CHECKED)))
1246 {
1247 if (mutt_check_traditional_pgp(shared->mailbox, &ea))
1249 }
1250 int rc = mutt_send_message(SEND_FORWARD, NULL, NULL, shared->mailbox, &ea,
1251 shared->sub);
1252 ARRAY_FREE(&ea);
1254
1255 return (rc == -1) ? FR_ERROR : FR_SUCCESS;
1256}
1257
1265static int op_group_reply(struct IndexFunctionData *fdata, const struct KeyEvent *event)
1266{
1267 struct IndexSharedData *shared = fdata->shared;
1268 struct IndexPrivateData *priv = fdata->priv;
1269 SendFlags replyflags = SEND_REPLY;
1270 if (event->op == OP_GROUP_REPLY)
1271 replyflags |= SEND_GROUP_REPLY;
1272 else
1273 replyflags |= SEND_GROUP_CHAT_REPLY;
1274 if (!shared->email)
1275 return FR_NO_ACTION;
1276 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
1277 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
1278 const bool c_pgp_auto_decode = cs_subset_bool(shared->sub, "pgp_auto_decode");
1279 if (c_pgp_auto_decode &&
1280 (priv->tag_prefix || !(shared->email->security & PGP_TRADITIONAL_CHECKED)))
1281 {
1282 if (mutt_check_traditional_pgp(shared->mailbox, &ea))
1284 }
1285 int rc = mutt_send_message(replyflags, NULL, NULL, shared->mailbox, &ea,
1286 shared->sub);
1287 ARRAY_FREE(&ea);
1289
1290 return (rc == -1) ? FR_ERROR : FR_SUCCESS;
1291}
1292
1296static int op_jump(struct IndexFunctionData *fdata, const struct KeyEvent *event)
1297{
1298 struct IndexSharedData *shared = fdata->shared;
1299 struct IndexPrivateData *priv = fdata->priv;
1300 int rc = FR_ERROR;
1301 struct Buffer *buf = buf_pool_get();
1302
1303 int num = event->count;
1304 if (num == 0)
1305 {
1306 if ((mw_get_field(_("Jump to message: "), buf, MUTT_COMP_NONE, HC_OTHER, NULL, NULL) != 0) ||
1307 buf_is_empty(buf))
1308 {
1309 mutt_message(_("Nothing to do"));
1310 rc = FR_NO_ACTION;
1311 goto done;
1312 }
1313
1314 if (!mutt_str_atoi_full(buf_string(buf), &num))
1315 {
1316 mutt_warning(_("Argument must be a message number"));
1317 goto done;
1318 }
1319 }
1320
1321 if ((num < 1) || (num > shared->mailbox->msg_count))
1322 {
1323 mutt_warning(_("Invalid message number"));
1324 }
1325 else if (!shared->mailbox->emails[num - 1] ||
1326 !shared->mailbox->emails[num - 1]->visible)
1327 {
1328 mutt_warning(_("That message is not visible"));
1329 }
1330 else
1331 {
1332 struct Email *e = shared->mailbox->emails[num - 1];
1333
1334 if (mutt_messages_in_thread(shared->mailbox, e, MIT_POSITION) > 1)
1335 {
1337 mutt_set_vnum(shared->mailbox);
1338 }
1339 menu_set_index(priv->menu, e->vnum);
1340 rc = FR_SUCCESS;
1341 }
1342
1343done:
1344 buf_pool_release(&buf);
1345 return rc;
1346}
1347
1351static int op_list_action(struct IndexFunctionData *fdata, const struct KeyEvent *event)
1352{
1353 struct IndexSharedData *shared = fdata->shared;
1354 struct IndexPrivateData *priv = fdata->priv;
1355
1358 return FR_SUCCESS;
1359}
1360
1364static int op_list_reply(struct IndexFunctionData *fdata, const struct KeyEvent *event)
1365{
1366 struct IndexSharedData *shared = fdata->shared;
1367 struct IndexPrivateData *priv = fdata->priv;
1368 if (!shared->email)
1369 return FR_NO_ACTION;
1370 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
1371 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
1372 const bool c_pgp_auto_decode = cs_subset_bool(shared->sub, "pgp_auto_decode");
1373 if (c_pgp_auto_decode &&
1374 (priv->tag_prefix || !(shared->email->security & PGP_TRADITIONAL_CHECKED)))
1375 {
1376 if (mutt_check_traditional_pgp(shared->mailbox, &ea))
1378 }
1379 int rc = mutt_send_message(SEND_REPLY | SEND_LIST_REPLY, NULL, NULL,
1380 shared->mailbox, &ea, shared->sub);
1381 ARRAY_FREE(&ea);
1383
1384 return (rc == -1) ? FR_ERROR : FR_SUCCESS;
1385}
1386
1390static int op_list_subscribe(struct IndexFunctionData *fdata, const struct KeyEvent *event)
1391{
1392 struct IndexSharedData *shared = fdata->shared;
1393 return mutt_send_list_subscribe(shared->mailbox, shared->email) ? FR_SUCCESS : FR_ERROR;
1394}
1395
1399static int op_list_unsubscribe(struct IndexFunctionData *fdata, const struct KeyEvent *event)
1400{
1401 struct IndexSharedData *shared = fdata->shared;
1402 return mutt_send_list_unsubscribe(shared->mailbox, shared->email) ? FR_SUCCESS : FR_ERROR;
1403}
1404
1408static int op_mail(struct IndexFunctionData *fdata, const struct KeyEvent *event)
1409{
1410 struct IndexSharedData *shared = fdata->shared;
1411 struct IndexPrivateData *priv = fdata->priv;
1412 int rc = mutt_send_message(SEND_NONE, NULL, NULL, shared->mailbox, NULL,
1413 shared->sub);
1415 return (rc == -1) ? FR_ERROR : FR_SUCCESS;
1416}
1417
1421static int op_mailbox_list(struct IndexFunctionData *fdata, const struct KeyEvent *event)
1422{
1424 return FR_SUCCESS;
1425}
1426
1430static int op_mail_key(struct IndexFunctionData *fdata, const struct KeyEvent *event)
1431{
1432 struct IndexSharedData *shared = fdata->shared;
1433 struct IndexPrivateData *priv = fdata->priv;
1434 if (!(WithCrypto & APPLICATION_PGP))
1435 return FR_NOT_IMPL;
1436 int rc = mutt_send_message(SEND_KEY, NULL, NULL, NULL, NULL, shared->sub);
1438
1439 return (rc == -1) ? FR_ERROR : FR_SUCCESS;
1440}
1441
1445static int op_main_break_thread(struct IndexFunctionData *fdata, const struct KeyEvent *event)
1446{
1447 struct IndexSharedData *shared = fdata->shared;
1448 struct IndexPrivateData *priv = fdata->priv;
1449 struct Mailbox *m = shared->mailbox;
1450 /* L10N: CHECK_ACL */
1451 if (!check_acl(m, MUTT_ACL_WRITE, _("Can't break thread")))
1452 return FR_ERROR;
1453
1454 struct Email *e = shared->email;
1455 if (!e)
1456 return FR_NO_ACTION;
1457
1458 const bool has_repeat_count = (event->count > 0);
1459
1460 if (!mutt_using_threads())
1461 {
1462 mutt_warning(_("Threading is not enabled"));
1463 return FR_ERROR;
1464 }
1465
1466 struct MailboxView *mv = shared->mailbox_view;
1467 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
1468 if (ea_add_selection(&ea, mv, e, false, event->count) <= 0)
1469 {
1470 ARRAY_FREE(&ea);
1471 return FR_NO_ACTION;
1472 }
1473
1474 bool changed = false;
1475 struct Email **ep = NULL;
1476 ARRAY_FOREACH(ep, &ea)
1477 {
1478 e = *ep;
1479 if (!e || (STAILQ_EMPTY(&e->env->in_reply_to) && STAILQ_EMPTY(&e->env->references)))
1480 continue;
1481
1482 {
1484 changed = true;
1485 }
1486 }
1487 ARRAY_FREE(&ea);
1488
1489 if (changed)
1490 {
1491 mutt_sort_headers(mv, true);
1492 menu_set_index(priv->menu, shared->email->vnum);
1493 m->changed = true;
1494 mutt_message(_("Thread broken"));
1495
1497 }
1498 else if (!has_repeat_count)
1499 {
1500 mutt_error(_("Thread can't be broken, message is not part of a thread"));
1501 return FR_ERROR;
1502 }
1503
1504 return FR_SUCCESS;
1505}
1506
1515static int op_main_change_folder(struct IndexFunctionData *fdata, const struct KeyEvent *event)
1516{
1517 struct IndexSharedData *shared = fdata->shared;
1518 struct IndexPrivateData *priv = fdata->priv;
1519 struct Buffer *folderbuf = buf_pool_get();
1520 buf_alloc(folderbuf, PATH_MAX);
1521
1522 char *cp = NULL;
1523 bool read_only;
1524 const bool c_read_only = cs_subset_bool(shared->sub, "read_only");
1525 const int op = event->op;
1526 if (shared->attach_msg || c_read_only || (op == OP_MAIN_CHANGE_FOLDER_READONLY))
1527 {
1528 cp = _("Open mailbox in read-only mode");
1529 read_only = true;
1530 }
1531 else
1532 {
1533 cp = _("Open mailbox");
1534 read_only = false;
1535 }
1536
1537 const bool c_change_folder_next = cs_subset_bool(shared->sub, "change_folder_next");
1538 if (c_change_folder_next && shared->mailbox && !buf_is_empty(&shared->mailbox->pathbuf))
1539 {
1540 buf_strcpy(folderbuf, mailbox_path(shared->mailbox));
1541 pretty_mailbox(folderbuf);
1542 }
1543 /* By default, fill buf with the next mailbox that contains unread mail */
1544 mutt_mailbox_next(shared->mailbox_view ? shared->mailbox : NULL, folderbuf);
1545
1546 if (mw_enter_fname(cp, folderbuf, true, shared->mailbox, false, NULL, NULL,
1547 MUTT_SEL_NONE) == -1)
1548 {
1549 goto changefoldercleanup;
1550 }
1551
1552 /* Selected directory is okay, let's save it. */
1554
1555 if (buf_is_empty(folderbuf))
1556 {
1557 msgwin_clear_text(NULL);
1558 goto changefoldercleanup;
1559 }
1560
1561 struct Mailbox *m = mx_mbox_find2(buf_string(folderbuf));
1562 if (m)
1563 {
1564 change_folder_mailbox(priv->menu, m, &priv->oldcount, shared, read_only);
1565 }
1566 else
1567 {
1568 change_folder_string(priv->menu, folderbuf, &priv->oldcount, shared, read_only);
1569 }
1570
1571changefoldercleanup:
1572 buf_pool_release(&folderbuf);
1574
1575 return FR_SUCCESS;
1576}
1577
1581static int op_main_collapse_all(struct IndexFunctionData *fdata, const struct KeyEvent *event)
1582{
1583 struct IndexSharedData *shared = fdata->shared;
1584 struct IndexPrivateData *priv = fdata->priv;
1585 if (!mutt_using_threads())
1586 {
1587 mutt_warning(_("Threading is not enabled"));
1588 return FR_ERROR;
1589 }
1592
1593 return FR_SUCCESS;
1594}
1595
1600 const struct KeyEvent *event)
1601{
1602 struct IndexSharedData *shared = fdata->shared;
1603 struct IndexPrivateData *priv = fdata->priv;
1604 if (!mutt_using_threads())
1605 {
1606 mutt_warning(_("Threading is not enabled"));
1607 return FR_ERROR;
1608 }
1609
1611 return FR_NO_ACTION;
1612
1615
1616 return FR_SUCCESS;
1617}
1618
1622static int op_main_close_thread(struct IndexFunctionData *fdata, const struct KeyEvent *event)
1623{
1624 struct IndexSharedData *shared = fdata->shared;
1625 struct IndexPrivateData *priv = fdata->priv;
1626 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
1627 ea_add_selection_threads(&ea, shared->mailbox_view, shared->email,
1628 priv->tag_prefix, false, event->count);
1629 const int rc = op_main_change_thread(fdata, &ea, COLLAPSE_MODE_CLOSE);
1630 ARRAY_FREE(&ea);
1631 return rc;
1632}
1633
1637static int op_main_collapse_thread(struct IndexFunctionData *fdata, const struct KeyEvent *event)
1638{
1639 struct IndexSharedData *shared = fdata->shared;
1640 struct IndexPrivateData *priv = fdata->priv;
1641 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
1642 ea_add_selection_threads(&ea, shared->mailbox_view, shared->email,
1643 priv->tag_prefix, false, event->count);
1644 const int rc = op_main_change_thread(fdata, &ea, COLLAPSE_MODE_TOGGLE);
1645 ARRAY_FREE(&ea);
1646 return rc;
1647}
1648
1653 const struct KeyEvent *event)
1654{
1655 struct IndexSharedData *shared = fdata->shared;
1656 struct IndexPrivateData *priv = fdata->priv;
1657 if (!mutt_using_threads())
1658 {
1659 mutt_warning(_("Threading is not enabled"));
1660 return FR_ERROR;
1661 }
1662
1664 return FR_NO_ACTION;
1665
1668
1669 return FR_SUCCESS;
1670}
1671
1675static int op_main_open_thread(struct IndexFunctionData *fdata, const struct KeyEvent *event)
1676{
1677 struct IndexSharedData *shared = fdata->shared;
1678 struct IndexPrivateData *priv = fdata->priv;
1679 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
1680 ea_add_selection_threads(&ea, shared->mailbox_view, shared->email,
1681 priv->tag_prefix, false, event->count);
1682 const int rc = op_main_change_thread(fdata, &ea, COLLAPSE_MODE_OPEN);
1683 ARRAY_FREE(&ea);
1684 return rc;
1685}
1686
1690static int op_main_delete_pattern(struct IndexFunctionData *fdata, const struct KeyEvent *event)
1691{
1692 struct IndexSharedData *shared = fdata->shared;
1693 struct IndexPrivateData *priv = fdata->priv;
1694 /* L10N: CHECK_ACL */
1695 /* L10N: Due to the implementation details we do not know whether we
1696 delete zero, 1, 12, ... messages. So in English we use
1697 "messages". Your language might have other means to express this. */
1698 if (!check_acl(shared->mailbox, MUTT_ACL_DELETE, _("Can't delete messages")))
1699 return FR_ERROR;
1700
1701 mutt_pattern_func(shared->mailbox_view, MUTT_DELETE, _("Delete messages matching: "));
1703
1704 return FR_SUCCESS;
1705}
1706
1715static int op_main_limit(struct IndexFunctionData *fdata, const struct KeyEvent *event)
1716{
1717 struct IndexSharedData *shared = fdata->shared;
1718 struct IndexPrivateData *priv = fdata->priv;
1719 const bool lmt = mview_has_limit(shared->mailbox_view);
1720 int old_index = shared->email ? shared->email->index : -1;
1721 const int op = event->op;
1722 if (op == OP_TOGGLE_READ)
1723 {
1724 struct Buffer *buf2 = buf_pool_get();
1725
1726 if (!lmt || !mutt_strn_equal(shared->mailbox_view->pattern, "!~R!~D~s", 8))
1727 {
1728 buf_printf(buf2, "!~R!~D~s%s", lmt ? shared->mailbox_view->pattern : ".*");
1729 }
1730 else
1731 {
1732 const char *pat = shared->mailbox_view->pattern + 8;
1733 if ((*pat == '\0') || mutt_strn_equal(pat, ".*", 2))
1734 buf_strcpy(buf2, "~A");
1735 else
1736 buf_strcpy(buf2, pat);
1737 }
1739 buf_pool_release(&buf2);
1741 }
1742
1743 if (((op == OP_LIMIT_CURRENT_THREAD) &&
1744 mutt_limit_current_thread(shared->mailbox_view, shared->email)) ||
1745 (op == OP_TOGGLE_READ) ||
1746 ((op == OP_MAIN_LIMIT) && (mutt_pattern_func(shared->mailbox_view, MUTT_LIMIT,
1747 _("Limit to messages matching: ")) == 0)))
1748 {
1749 priv->menu->max = shared->mailbox->vcount;
1750 menu_set_index(priv->menu, 0);
1751 if (old_index >= 0)
1752 {
1753 /* try to find what used to be the current message */
1754 for (size_t i = 0; i < shared->mailbox->vcount; i++)
1755 {
1756 struct Email *e = mutt_get_virt_email(shared->mailbox, i);
1757 if (!e)
1758 continue;
1759 if (e->index == old_index)
1760 {
1761 menu_set_index(priv->menu, i);
1762 break;
1763 }
1764 }
1765 }
1766
1767 if ((shared->mailbox->msg_count != 0) && mutt_using_threads())
1768 {
1769 const bool c_collapse_all = cs_subset_bool(shared->sub, "collapse_all");
1770 if (c_collapse_all)
1773 }
1774 notify_send(shared->notify, NT_INDEX, NT_INDEX_EMAIL, NULL);
1776 }
1777 if (lmt)
1778 mutt_message(_("To view all messages, limit to \"all\""));
1779
1780 return FR_SUCCESS;
1781}
1782
1789static int op_main_link_threads(struct IndexFunctionData *fdata, const struct KeyEvent *event)
1790{
1791 struct IndexSharedData *shared = fdata->shared;
1792 struct IndexPrivateData *priv = fdata->priv;
1793 struct Mailbox *m = shared->mailbox;
1794 /* L10N: CHECK_ACL */
1795 if (!check_acl(m, MUTT_ACL_WRITE, _("Can't link threads")))
1796 return FR_ERROR;
1797
1798 struct Email *e = shared->email;
1799 if (!e)
1800 return FR_NO_ACTION;
1801
1802 enum FunctionRetval rc = FR_ERROR;
1803
1804 if (!mutt_using_threads())
1805 {
1806 mutt_warning(_("Threading is not enabled"));
1807 rc = FR_ERROR;
1808 }
1809 else if (!e->env->message_id)
1810 {
1811 mutt_error(_("No Message-ID: header available to link thread"));
1812 }
1813 else
1814 {
1815 struct MailboxView *mv = shared->mailbox_view;
1816 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
1817
1818 // If there's a repeat-count, use it.
1819 // If not, behave as if <tag-prefix> has been pressed.
1820 const bool tag_prefix = (event->count < 1);
1821 ea_add_selection(&ea, mv, e, tag_prefix, event->count);
1822
1823 if (!tag_prefix)
1824 {
1825 struct Email **ep = ARRAY_GET(&ea, 0);
1826 if (ep && (*ep == e))
1827 ARRAY_REMOVE(&ea, ep);
1828 }
1829
1830 if (mutt_link_threads(e, &ea, m))
1831 {
1832 mutt_sort_headers(mv, true);
1833 menu_set_index(priv->menu, e->vnum);
1834
1835 m->changed = true;
1836 mutt_message(_("Threads linked"));
1837 rc = FR_SUCCESS;
1838 }
1839 else
1840 {
1841 mutt_error(_("No thread linked"));
1842 rc = FR_ERROR;
1843 }
1844
1845 ARRAY_FREE(&ea);
1846 }
1847
1849 return rc;
1850}
1851
1859static int op_main_modify_tags(struct IndexFunctionData *fdata, const struct KeyEvent *event)
1860{
1861 struct IndexSharedData *shared = fdata->shared;
1862 struct IndexPrivateData *priv = fdata->priv;
1863 int rc = FR_ERROR;
1864 struct Buffer *buf = NULL;
1865 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
1866
1867 if (!shared->mailbox)
1868 goto done;
1869 struct Mailbox *m = shared->mailbox;
1870 if (!mx_tags_is_supported(m))
1871 {
1872 mutt_message(_("Folder doesn't support tagging, aborting"));
1873 goto done;
1874 }
1875 if (!shared->email)
1876 {
1877 rc = FR_NO_ACTION;
1878 goto done;
1879 }
1880
1881 const int op = event->op;
1882 struct Buffer *tags = buf_pool_get();
1883 if (!priv->tag_prefix)
1884 driver_tags_get_with_hidden(&shared->email->tags, tags);
1885 /* Prompt the user to edit the tag string */
1886 buf = buf_pool_get();
1887 int rc2 = mx_tags_edit(m, buf_string(tags), buf);
1888 buf_pool_release(&tags);
1889 if (rc2 < 0)
1890 {
1891 goto done;
1892 }
1893 else if (rc2 == 0)
1894 {
1895 mutt_message(_("No tag specified, aborting"));
1896 goto done;
1897 }
1898
1899 ea_add_selection(&ea, shared->mailbox_view, shared->email, priv->tag_prefix,
1900 event->count);
1901 const int num = ARRAY_SIZE(&ea);
1902
1903 if (priv->tag_prefix || (num > 1))
1904 {
1905 struct Progress *progress = NULL;
1906
1907 if (m->verbose)
1908 {
1909 progress = progress_new(MUTT_PROGRESS_WRITE, num);
1910 progress_set_message(progress, _("Update tags..."));
1911 }
1912
1913#ifdef USE_NOTMUCH
1914 if (m->type == MUTT_NOTMUCH)
1915 nm_db_longrun_init(m, true);
1916#endif
1917 struct Email **ep = NULL;
1918 int px = 0;
1919 ARRAY_FOREACH(ep, &ea)
1920 {
1921 struct Email *e = *ep;
1922
1923 progress_update(progress, ++px, -1);
1924 mx_tags_commit(m, e, buf_string(buf));
1925 e->attr_color = NULL;
1926 if (op == OP_MAIN_MODIFY_TAGS_THEN_HIDE)
1927 {
1928 bool still_queried = false;
1929#ifdef USE_NOTMUCH
1930 if (m->type == MUTT_NOTMUCH)
1931 still_queried = nm_message_is_still_queried(m, e);
1932#endif
1933 e->quasi_deleted = !still_queried;
1934 m->changed = true;
1935 }
1936 }
1937 progress_free(&progress);
1938#ifdef USE_NOTMUCH
1939 if (m->type == MUTT_NOTMUCH)
1941#endif
1943 if (!priv->tag_prefix)
1945 (op == OP_MAIN_MODIFY_TAGS_THEN_HIDE) ? 1 : num);
1946 }
1947 else
1948 {
1949 if (mx_tags_commit(m, shared->email, buf_string(buf)))
1950 {
1951 mutt_message(_("Failed to modify tags, aborting"));
1952 goto done;
1953 }
1954 shared->email->attr_color = NULL;
1955 if (op == OP_MAIN_MODIFY_TAGS_THEN_HIDE)
1956 {
1957 bool still_queried = false;
1958#ifdef USE_NOTMUCH
1959 if (m->type == MUTT_NOTMUCH)
1960 still_queried = nm_message_is_still_queried(m, shared->email);
1961#endif
1962 shared->email->quasi_deleted = !still_queried;
1963 m->changed = true;
1964 }
1965
1967 (op == OP_MAIN_MODIFY_TAGS_THEN_HIDE) ? 1 : num);
1968 }
1969 rc = FR_SUCCESS;
1970
1971done:
1972 ARRAY_FREE(&ea);
1973 buf_pool_release(&buf);
1974 return rc;
1975}
1976
1997static int find_next_new_email(struct Mailbox *m, int start, bool forwards, int op)
1998{
1999 int first_unread = -1;
2000 int first_new = -1;
2001 int mcur = start;
2002 const bool threaded = mutt_using_threads();
2003
2004 for (int i = 0; i < m->vcount; i++)
2005 {
2006 if (forwards)
2007 {
2008 mcur++;
2009 if (mcur > (m->vcount - 1))
2010 mcur = 0;
2011 }
2012 else
2013 {
2014 mcur--;
2015 if (mcur < 0)
2016 mcur = m->vcount - 1;
2017 }
2018
2019 struct Email *e = mutt_get_virt_email(m, mcur);
2020 if (!e)
2021 break;
2022 if (e->collapsed && threaded)
2023 {
2024 int unread = mutt_thread_contains_unread(e);
2025 if ((unread != 0) && (first_unread == -1))
2026 first_unread = mcur;
2027 if ((unread == 1) && (first_new == -1))
2028 first_new = mcur;
2029 }
2030 else if (!e->deleted && !e->read)
2031 {
2032 if (first_unread == -1)
2033 first_unread = mcur;
2034 if (!e->old && (first_new == -1))
2035 first_new = mcur;
2036 }
2037
2038 if (((op == OP_MAIN_NEXT_UNREAD) || (op == OP_MAIN_PREV_UNREAD)) && (first_unread != -1))
2039 break;
2040 if (((op == OP_MAIN_NEXT_NEW) || (op == OP_MAIN_PREV_NEW) ||
2041 (op == OP_MAIN_NEXT_NEW_THEN_UNREAD) || (op == OP_MAIN_PREV_NEW_THEN_UNREAD)) &&
2042 (first_new != -1))
2043 {
2044 break;
2045 }
2046 }
2047
2048 if (((op == OP_MAIN_NEXT_NEW) || (op == OP_MAIN_PREV_NEW) ||
2049 (op == OP_MAIN_NEXT_NEW_THEN_UNREAD) || (op == OP_MAIN_PREV_NEW_THEN_UNREAD)) &&
2050 (first_new != -1))
2051 {
2052 return first_new;
2053 }
2054 if (((op == OP_MAIN_NEXT_UNREAD) || (op == OP_MAIN_PREV_UNREAD) ||
2055 (op == OP_MAIN_NEXT_NEW_THEN_UNREAD) || (op == OP_MAIN_PREV_NEW_THEN_UNREAD)) &&
2056 (first_unread != -1))
2057 {
2058 return first_unread;
2059 }
2060
2061 return -1;
2062}
2063
2064static int op_main_next_new(struct IndexFunctionData *fdata, const struct KeyEvent *event)
2065{
2066 struct IndexSharedData *shared = fdata->shared;
2067 struct IndexPrivateData *priv = fdata->priv;
2068
2069 const int saved_current = menu_get_index(priv->menu);
2070 const int op = event->op;
2071 const bool forwards = (op == OP_MAIN_NEXT_NEW) || (op == OP_MAIN_NEXT_UNREAD) ||
2072 (op == OP_MAIN_NEXT_NEW_THEN_UNREAD);
2073 const int count = event->count;
2074
2075 if (count > 0)
2076 {
2077 int cur = saved_current;
2078 int last_good = saved_current;
2079 for (int i = 0; i < count; i++)
2080 {
2081 int next = find_next_new_email(shared->mailbox, cur, forwards, op);
2082 if (next == -1)
2083 break;
2084 last_good = next;
2085 cur = next;
2086 }
2087 if (last_good != saved_current)
2088 menu_set_index(priv->menu, last_good);
2089 return FR_SUCCESS;
2090 }
2091
2092 int index = find_next_new_email(shared->mailbox, saved_current, forwards, op);
2093
2094 if (index == -1)
2095 {
2096 menu_set_index(priv->menu, saved_current);
2097 if ((op == OP_MAIN_NEXT_NEW) || (op == OP_MAIN_PREV_NEW))
2098 {
2100 mutt_error(_("No new messages in this limited view"));
2101 else
2102 mutt_error(_("No new messages"));
2103 }
2104 else
2105 {
2107 mutt_error(_("No unread messages in this limited view"));
2108 else
2109 mutt_error(_("No unread messages"));
2110 }
2112 return FR_ERROR;
2113 }
2114
2115 menu_set_index(priv->menu, index);
2116
2117 index = menu_get_index(priv->menu);
2118 if (forwards)
2119 {
2120 if (saved_current > index)
2121 {
2122 mutt_message(_("Search wrapped to top"));
2123 }
2124 }
2125 else if (saved_current < index)
2126 {
2127 mutt_message(_("Search wrapped to bottom"));
2128 }
2129
2130 return FR_SUCCESS;
2131}
2132
2142static int op_main_next_thread(struct IndexFunctionData *fdata, const struct KeyEvent *event)
2143{
2144 struct IndexSharedData *shared = fdata->shared;
2145 struct IndexPrivateData *priv = fdata->priv;
2146 const int op = event->op;
2147 const int count = event->count;
2148 const bool forwards = (op == OP_MAIN_NEXT_THREAD) || (op == OP_MAIN_NEXT_SUBTHREAD);
2149 const bool subthreads = (op == OP_MAIN_NEXT_SUBTHREAD) || (op == OP_MAIN_PREV_SUBTHREAD);
2150
2151 if (count > 0)
2152 {
2153 for (int i = 0; i < count; i++)
2154 {
2155 int index = mutt_aside_thread(shared->email, forwards, subthreads);
2156 if (index == -1)
2157 break;
2158 menu_set_index(priv->menu, index);
2159 }
2160 return FR_SUCCESS;
2161 }
2162
2163 int index = mutt_aside_thread(shared->email, forwards, subthreads);
2164
2165 if (index != -1)
2166 menu_set_index(priv->menu, index);
2167
2168 if (index < 0)
2169 {
2170 if (forwards)
2171 mutt_error(_("No more threads"));
2172 else
2173 mutt_error(_("You are on the first thread"));
2174
2176 return FR_ERROR;
2177 }
2178
2179 return FR_SUCCESS;
2180}
2181
2185static int op_main_next_undeleted(struct IndexFunctionData *fdata, const struct KeyEvent *event)
2186{
2187 struct IndexSharedData *shared = fdata->shared;
2188 struct IndexPrivateData *priv = fdata->priv;
2189 const int count = event->count;
2190 int index = menu_get_index(priv->menu);
2191
2192 if (count > 0)
2193 {
2194 const bool uncollapse = mutt_using_threads() && !window_is_focused(priv->win_index);
2195 int last_good = index;
2196 for (int i = 0; i < count; i++)
2197 {
2198 int next = find_next_undeleted(shared->mailbox_view, index, uncollapse);
2199 if (next == -1)
2200 break;
2201 last_good = next;
2202 index = next;
2203 }
2204 if (last_good != menu_get_index(priv->menu))
2205 {
2206 menu_set_index(priv->menu, last_good);
2207 if (uncollapse)
2209 }
2210 return FR_SUCCESS;
2211 }
2212
2213 if (index >= (shared->mailbox->vcount - 1))
2214 {
2216 mutt_message(_("You are on the last message"));
2217 return FR_ERROR;
2218 }
2219
2220 const bool uncollapse = mutt_using_threads() && !window_is_focused(priv->win_index);
2221
2222 index = find_next_undeleted(shared->mailbox_view, index, uncollapse);
2223 if (index != -1)
2224 {
2225 menu_set_index(priv->menu, index);
2226 if (uncollapse)
2228 }
2229
2230 if (index == -1)
2231 {
2233 mutt_error(_("No undeleted messages"));
2234 return FR_ERROR;
2235 }
2236
2237 return FR_SUCCESS;
2238}
2239
2244 const struct KeyEvent *event)
2245{
2246 struct IndexSharedData *shared = fdata->shared;
2247 struct IndexPrivateData *priv = fdata->priv;
2248 struct Mailbox *m = shared->mailbox;
2249
2250 struct Buffer *folderbuf = buf_pool_get();
2251 buf_strcpy(folderbuf, mailbox_path(m));
2252 m = mutt_mailbox_next_unread(m, folderbuf);
2253 buf_pool_release(&folderbuf);
2254
2255 if (!m)
2256 {
2257 mutt_error(_("No mailboxes have new mail"));
2258 return FR_ERROR;
2259 }
2260
2261 change_folder_mailbox(priv->menu, m, &priv->oldcount, shared, false);
2262 return FR_SUCCESS;
2263}
2264
2269 const struct KeyEvent *event)
2270{
2271 struct IndexSharedData *shared = fdata->shared;
2272 struct IndexPrivateData *priv = fdata->priv;
2273 struct Mailbox *m = shared->mailbox;
2274
2275 struct Buffer *folderbuf = buf_pool_get();
2276 buf_strcpy(folderbuf, mailbox_path(m));
2277 m = mutt_mailbox_prev_unread(m, folderbuf);
2278 buf_pool_release(&folderbuf);
2279
2280 if (!m)
2281 {
2282 mutt_error(_("No mailboxes have new mail"));
2283 return FR_ERROR;
2284 }
2285
2286 change_folder_mailbox(priv->menu, m, &priv->oldcount, shared, false);
2287 return FR_SUCCESS;
2288}
2289
2293static int op_main_prev_undeleted(struct IndexFunctionData *fdata, const struct KeyEvent *event)
2294{
2295 struct IndexSharedData *shared = fdata->shared;
2296 struct IndexPrivateData *priv = fdata->priv;
2297 const int count = event->count;
2298 int index = menu_get_index(priv->menu);
2299
2300 if (count > 0)
2301 {
2302 const bool uncollapse = mutt_using_threads() && !window_is_focused(priv->win_index);
2303 int last_good = index;
2304 for (int i = 0; i < count; i++)
2305 {
2306 int prev = find_previous_undeleted(shared->mailbox_view, index, uncollapse);
2307 if (prev == -1)
2308 break;
2309 last_good = prev;
2310 index = prev;
2311 }
2312 if (last_good != menu_get_index(priv->menu))
2313 {
2314 menu_set_index(priv->menu, last_good);
2315 if (uncollapse)
2317 }
2318 return FR_SUCCESS;
2319 }
2320
2321 if (index < 1)
2322 {
2324 mutt_message(_("You are on the first message"));
2325 return FR_ERROR;
2326 }
2327
2328 const bool uncollapse = mutt_using_threads() && !window_is_focused(priv->win_index);
2329
2330 index = find_previous_undeleted(shared->mailbox_view, index, uncollapse);
2331 if (index != -1)
2332 {
2333 menu_set_index(priv->menu, index);
2334 if (uncollapse)
2336 }
2337
2338 if (index == -1)
2339 {
2340 mutt_error(_("No undeleted messages"));
2342 return FR_ERROR;
2343 }
2344
2345 return FR_SUCCESS;
2346}
2347
2351static int op_main_quasi_delete(struct IndexFunctionData *fdata, const struct KeyEvent *event)
2352{
2353 struct IndexSharedData *shared = fdata->shared;
2354 struct IndexPrivateData *priv = fdata->priv;
2355 struct Mailbox *m = shared->mailbox;
2356 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
2357 ea_add_selection(&ea, shared->mailbox_view, shared->email, priv->tag_prefix,
2358 event->count);
2359 if (ARRAY_EMPTY(&ea))
2360 {
2361 ARRAY_FREE(&ea);
2362 return FR_NO_ACTION;
2363 }
2364 const int num = ARRAY_SIZE(&ea);
2365
2366 struct Email **ep = NULL;
2367 ARRAY_FOREACH(ep, &ea)
2368 {
2369 (*ep)->quasi_deleted = true;
2370 m->changed = true;
2371 }
2372 ARRAY_FREE(&ea);
2373
2374 if (priv->tag_prefix || (num > 1))
2376
2377 return FR_SUCCESS;
2378}
2379
2387static int op_main_read_thread(struct IndexFunctionData *fdata, const struct KeyEvent *event)
2388{
2389 struct IndexSharedData *shared = fdata->shared;
2390 struct IndexPrivateData *priv = fdata->priv;
2391 /* L10N: CHECK_ACL */
2392 /* L10N: Due to the implementation details we do not know whether we
2393 mark zero, 1, 12, ... messages as read. So in English we use
2394 "messages". Your language might have other means to express this. */
2395 if (!check_acl(shared->mailbox, MUTT_ACL_SEEN, _("Can't mark messages as read")))
2396 return FR_ERROR;
2397
2398 const int op = event->op;
2399 const bool subthread = (op != OP_MAIN_READ_THREAD);
2400 int rc = 0;
2401 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
2402 ea_add_selection_threads(&ea, shared->mailbox_view, shared->email,
2403 priv->tag_prefix, subthread, event->count);
2404 const int num = ARRAY_SIZE(&ea);
2405
2406 struct Email **ep = NULL;
2407 ARRAY_FOREACH(ep, &ea)
2408 {
2409 rc = mutt_thread_set_flag(shared->mailbox, *ep, MUTT_READ, true, subthread);
2410 if (rc == -1)
2411 break;
2412 }
2413 ARRAY_FREE(&ea);
2414
2415 if (rc == -1)
2416 return FR_ERROR;
2417
2418 if (priv->tag_prefix)
2419 {
2421 return FR_SUCCESS;
2422 }
2423
2424 const enum ResolveMethod rm = (op == OP_MAIN_READ_THREAD) ? RESOLVE_NEXT_THREAD :
2426 resolve_email(priv, shared, rm, num);
2428 return FR_SUCCESS;
2429}
2430
2441static int op_main_root_message(struct IndexFunctionData *fdata, const struct KeyEvent *event)
2442{
2443 struct IndexSharedData *shared = fdata->shared;
2444 struct IndexPrivateData *priv = fdata->priv;
2445 int count = event->op == OP_MAIN_ROOT_MESSAGE ? 0 : MAX(event->count, 1);
2446 int index = mutt_parent_message(shared->email, event->op == OP_MAIN_ROOT_MESSAGE, count);
2447 if (index != -1)
2448 menu_set_index(priv->menu, index);
2449
2450 return FR_SUCCESS;
2451}
2452
2460static int op_main_set_flag(struct IndexFunctionData *fdata, const struct KeyEvent *event)
2461{
2462 struct IndexSharedData *shared = fdata->shared;
2463 struct IndexPrivateData *priv = fdata->priv;
2464 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
2465 ea_add_selection(&ea, shared->mailbox_view, shared->email, priv->tag_prefix,
2466 event->count);
2467 if (ARRAY_EMPTY(&ea))
2468 {
2469 ARRAY_FREE(&ea);
2470 return FR_NO_ACTION;
2471 }
2472 const int num = ARRAY_SIZE(&ea);
2473
2474 if (mw_change_flag(shared->mailbox, &ea, (event->op == OP_MAIN_SET_FLAG)) == 0)
2475 {
2476 if (priv->tag_prefix)
2477 {
2479 }
2480 else
2481 {
2482 resolve_email(priv, shared, RESOLVE_NEXT_UNDELETED, num);
2483 if (num > 1)
2485 }
2486 }
2487 ARRAY_FREE(&ea);
2488
2489 return FR_SUCCESS;
2490}
2491
2495static int op_main_show_limit(struct IndexFunctionData *fdata, const struct KeyEvent *event)
2496{
2497 struct IndexSharedData *shared = fdata->shared;
2498 if (mview_has_limit(shared->mailbox_view))
2499 {
2500 struct Buffer *buf = buf_pool_get();
2501 /* L10N: ask for a limit to apply */
2502 buf_printf(buf, _("Limit: %s"), shared->mailbox_view->pattern);
2503 mutt_message("%s", buf_string(buf));
2504 buf_pool_release(&buf);
2505 }
2506 else
2507 {
2508 mutt_message(_("No limit pattern is in effect"));
2509 }
2510
2511 return FR_SUCCESS;
2512}
2513
2517static int op_main_sync_folder(struct IndexFunctionData *fdata, const struct KeyEvent *event)
2518{
2519 struct IndexSharedData *shared = fdata->shared;
2520 struct IndexPrivateData *priv = fdata->priv;
2522 return FR_NO_ACTION;
2523
2524 int ovc = shared->mailbox->vcount;
2525 int oc = shared->mailbox->msg_count;
2526 struct Email *e = NULL;
2527
2528 /* don't attempt to move the cursor if there are no visible messages in the current limit */
2529 int index = menu_get_index(priv->menu);
2530 if (index < shared->mailbox->vcount)
2531 {
2532 /* threads may be reordered, so figure out what header the cursor
2533 * should be on. */
2534 int newidx = index;
2535 if (!shared->email)
2536 return FR_NO_ACTION;
2537 if (shared->email->deleted)
2538 newidx = find_next_undeleted(shared->mailbox_view, index, false);
2539 if (newidx < 0)
2540 newidx = find_previous_undeleted(shared->mailbox_view, index, false);
2541 if (newidx >= 0)
2542 e = mutt_get_virt_email(shared->mailbox, newidx);
2543 }
2544
2545 enum MxStatus check = mx_mbox_sync(shared->mailbox);
2546 if (check == MX_STATUS_OK)
2547 {
2548 if (e && (shared->mailbox->vcount != ovc))
2549 {
2550 for (size_t i = 0; i < shared->mailbox->vcount; i++)
2551 {
2552 struct Email *e2 = mutt_get_virt_email(shared->mailbox, i);
2553 if (e2 == e)
2554 {
2555 menu_set_index(priv->menu, i);
2556 break;
2557 }
2558 }
2559 }
2561 }
2562 else if ((check == MX_STATUS_NEW_MAIL) || (check == MX_STATUS_REOPENED))
2563 {
2564 update_index(priv->menu, shared->mailbox_view, check, oc, shared);
2565 }
2566
2567 /* do a sanity check even if mx_mbox_sync failed. */
2568
2569 index = menu_get_index(priv->menu);
2570 if ((index < 0) || (shared->mailbox && (index >= shared->mailbox->vcount)))
2571 {
2573 }
2574
2575 /* check for a fatal error, or all messages deleted */
2576 if (shared->mailbox && buf_is_empty(&shared->mailbox->pathbuf))
2577 {
2578 mview_free(&shared->mailbox_view);
2579 }
2580
2581 if (shared->mailbox)
2582 {
2583 priv->menu->max = shared->mailbox->vcount;
2585
2586 struct EventMailbox ev_m = { shared->mailbox };
2588 }
2589 else
2590 {
2591 priv->menu->max = 0;
2593 }
2594
2595 return FR_SUCCESS;
2596}
2597
2601static int op_main_tag_pattern(struct IndexFunctionData *fdata, const struct KeyEvent *event)
2602{
2603 struct IndexSharedData *shared = fdata->shared;
2604 struct IndexPrivateData *priv = fdata->priv;
2605 mutt_pattern_func(shared->mailbox_view, MUTT_TAG, _("Tag messages matching: "));
2607
2608 return FR_SUCCESS;
2609}
2610
2615 const struct KeyEvent *event)
2616{
2617 struct IndexSharedData *shared = fdata->shared;
2618 struct IndexPrivateData *priv = fdata->priv;
2619 /* L10N: CHECK_ACL */
2620 /* L10N: Due to the implementation details we do not know whether we
2621 undelete zero, 1, 12, ... messages. So in English we use
2622 "messages". Your language might have other means to express this. */
2623 if (!check_acl(shared->mailbox, MUTT_ACL_DELETE, _("Can't undelete messages")))
2624 return FR_ERROR;
2625
2627 _("Undelete messages matching: ")) == 0)
2628 {
2630 }
2631
2632 return FR_SUCCESS;
2633}
2634
2638static int op_main_untag_pattern(struct IndexFunctionData *fdata, const struct KeyEvent *event)
2639{
2640 struct IndexSharedData *shared = fdata->shared;
2641 struct IndexPrivateData *priv = fdata->priv;
2642 if (mutt_pattern_func(shared->mailbox_view, MUTT_UNTAG, _("Untag messages matching: ")) == 0)
2644
2645 return FR_SUCCESS;
2646}
2647
2651static int op_mark_msg(struct IndexFunctionData *fdata, const struct KeyEvent *event)
2652{
2653 struct IndexSharedData *shared = fdata->shared;
2654 if (!shared->email)
2655 return FR_NO_ACTION;
2656
2657 int rc = FR_SUCCESS;
2658
2659 if (shared->email->env->message_id)
2660 {
2661 struct Buffer *buf = buf_pool_get();
2662
2663 /* L10N: This is the prompt for <mark-message>. Whatever they
2664 enter will be prefixed by $mark_macro_prefix and will become
2665 a macro hotkey to jump to the currently selected message. */
2666 if ((mw_get_field(_("Enter macro stroke: "), buf, MUTT_COMP_NONE, HC_OTHER,
2667 NULL, NULL) == 0) &&
2668 !buf_is_empty(buf))
2669 {
2670 const char *const c_mark_macro_prefix = cs_subset_string(shared->sub, "mark_macro_prefix");
2671 char str[256] = { 0 };
2672 snprintf(str, sizeof(str), "%s%s", c_mark_macro_prefix, buf_string(buf));
2673
2674 struct Buffer *msg_id = buf_pool_get();
2675 mutt_file_sanitize_regex(msg_id, shared->email->env->message_id);
2676 char macro[256] = { 0 };
2677 snprintf(macro, sizeof(macro), "<search>~i '%s'\n", buf_string(msg_id));
2678 buf_pool_release(&msg_id);
2679
2680 /* L10N: "message hotkey" is the key bindings menu description of a
2681 macro created by <mark-message>. */
2682 km_bind(fdata->mod_data->menu_index, str, OP_MACRO, macro, _("message hotkey"), NULL);
2683
2684 /* L10N: This is echoed after <mark-message> creates a new hotkey
2685 macro. %s is the hotkey string ($mark_macro_prefix followed
2686 by whatever they typed at the prompt.) */
2687 buf_printf(buf, _("Message bound to %s"), str);
2688 mutt_message("%s", buf_string(buf));
2689 mutt_debug(LL_DEBUG1, "Mark: %s => %s\n", str, macro);
2690 }
2691 buf_pool_release(&buf);
2692 }
2693 else
2694 {
2695 /* L10N: This error is printed if <mark-message> can't find a
2696 Message-ID for the currently selected message in the index. */
2697 mutt_error(_("No message ID to macro"));
2698 rc = FR_ERROR;
2699 }
2700
2701 return rc;
2702}
2703
2707static int op_next_entry(struct IndexFunctionData *fdata, const struct KeyEvent *event)
2708{
2709 struct IndexSharedData *shared = fdata->shared;
2710 struct IndexPrivateData *priv = fdata->priv;
2711 int count = MAX(event->count, 1);
2712 int index = menu_get_index(priv->menu) + count;
2713
2714 if (index >= shared->mailbox->vcount)
2715 {
2716 index = shared->mailbox->vcount - 1;
2717 if (event->count == 0)
2718 {
2719 mutt_message(_("You are on the last message"));
2721 }
2722 }
2723
2724 menu_set_index(priv->menu, index);
2725 return FR_SUCCESS;
2726}
2727
2731static int op_pipe(struct IndexFunctionData *fdata, const struct KeyEvent *event)
2732{
2733 struct IndexSharedData *shared = fdata->shared;
2734 struct IndexPrivateData *priv = fdata->priv;
2735 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
2736 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
2737 mutt_pipe_message(shared->mailbox, &ea);
2738 ARRAY_FREE(&ea);
2739
2740 /* in an IMAP folder index with imap_peek=no, piping could change
2741 * new or old messages status to read. Redraw what's needed. */
2742 const bool c_imap_peek = cs_subset_bool(shared->sub, "imap_peek");
2743 if ((shared->mailbox->type == MUTT_IMAP) && !c_imap_peek)
2744 {
2746 }
2747
2748 return FR_SUCCESS;
2749}
2750
2754static int op_prev_entry(struct IndexFunctionData *fdata, const struct KeyEvent *event)
2755{
2756 struct IndexSharedData *shared = fdata->shared;
2757 struct IndexPrivateData *priv = fdata->priv;
2758 int count = MAX(event->count, 1);
2759 int index = menu_get_index(priv->menu) - count;
2760
2761 if (index < 0)
2762 {
2763 index = 0;
2764 if (event->count == 0)
2765 {
2767 mutt_message(_("You are on the first message"));
2768 }
2769 }
2770
2771 menu_set_index(priv->menu, index);
2772 return FR_SUCCESS;
2773}
2774
2778static int op_print(struct IndexFunctionData *fdata, const struct KeyEvent *event)
2779{
2780 struct IndexSharedData *shared = fdata->shared;
2781 struct IndexPrivateData *priv = fdata->priv;
2782 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
2783 ea_add_selection(&ea, shared->mailbox_view, shared->email, priv->tag_prefix,
2784 event->count);
2785 if (ARRAY_EMPTY(&ea))
2786 {
2787 ARRAY_FREE(&ea);
2788 return FR_NO_ACTION;
2789 }
2790 const int num = ARRAY_SIZE(&ea);
2791 const bool printed = mutt_print_message(shared->mailbox, &ea);
2792 ARRAY_FREE(&ea);
2793
2794 if (printed && !priv->tag_prefix)
2795 resolve_email(priv, shared, RESOLVE_NEXT_EMAIL, num);
2796
2797 /* in an IMAP folder index with imap_peek=no, printing could change
2798 * new or old messages status to read. Redraw what's needed. */
2799 const bool c_imap_peek = cs_subset_bool(shared->sub, "imap_peek");
2800 if (printed && (shared->mailbox->type == MUTT_IMAP) && !c_imap_peek)
2801 {
2802 menu_queue_redraw(priv->menu,
2803 ((priv->tag_prefix || (num > 1)) ? MENU_REDRAW_INDEX : MENU_REDRAW_CURRENT));
2804 }
2805
2806 return FR_SUCCESS;
2807}
2808
2812static int op_query(struct IndexFunctionData *fdata, const struct KeyEvent *event)
2813{
2814 struct IndexSharedData *shared = fdata->shared;
2815 query_index(shared->mailbox, shared->sub);
2816 return FR_SUCCESS;
2817}
2818
2822static int op_quit(struct IndexFunctionData *fdata, const struct KeyEvent *event)
2823{
2824 struct IndexSharedData *shared = fdata->shared;
2825 struct IndexPrivateData *priv = fdata->priv;
2826 if (shared->attach_msg)
2827 return FR_DONE;
2828
2829 if (query_quadoption(_("Quit NeoMutt?"), shared->sub, "quit") == MUTT_YES)
2830 {
2831 priv->oldcount = shared->mailbox ? shared->mailbox->msg_count : 0;
2832
2834 mutt_debug(LL_NOTIFY, "NT_GLOBAL_SHUTDOWN\n");
2836
2837 enum MxStatus check = MX_STATUS_OK;
2838 if (!shared->mailbox_view || ((check = mx_mbox_close(shared->mailbox)) == MX_STATUS_OK))
2839 {
2842 return FR_DONE;
2843 }
2844
2845 if ((check == MX_STATUS_NEW_MAIL) || (check == MX_STATUS_REOPENED))
2846 {
2847 update_index(priv->menu, shared->mailbox_view, check, priv->oldcount, shared);
2848 }
2849
2850 menu_queue_redraw(priv->menu, MENU_REDRAW_FULL); /* new mail arrived? */
2852 }
2853
2854 return FR_NO_ACTION;
2855}
2856
2860static int op_recall_message(struct IndexFunctionData *fdata, const struct KeyEvent *event)
2861{
2862 struct IndexSharedData *shared = fdata->shared;
2863 struct IndexPrivateData *priv = fdata->priv;
2864 int rc = mutt_send_message(SEND_POSTPONED, NULL, NULL, shared->mailbox, NULL,
2865 shared->sub);
2867 return (rc == -1) ? FR_ERROR : FR_SUCCESS;
2868}
2869
2873static int op_reply(struct IndexFunctionData *fdata, const struct KeyEvent *event)
2874{
2875 struct IndexSharedData *shared = fdata->shared;
2876 struct IndexPrivateData *priv = fdata->priv;
2877 if (!shared->email)
2878 return FR_NO_ACTION;
2879 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
2880 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
2881 const bool c_pgp_auto_decode = cs_subset_bool(shared->sub, "pgp_auto_decode");
2882 if (c_pgp_auto_decode &&
2883 (priv->tag_prefix || !(shared->email->security & PGP_TRADITIONAL_CHECKED)))
2884 {
2885 if (mutt_check_traditional_pgp(shared->mailbox, &ea))
2887 }
2888 int rc = mutt_send_message(SEND_REPLY, NULL, NULL, shared->mailbox, &ea,
2889 shared->sub);
2890 ARRAY_FREE(&ea);
2892
2893 return (rc == -1) ? FR_ERROR : FR_SUCCESS;
2894}
2895
2899static int op_resend(struct IndexFunctionData *fdata, const struct KeyEvent *event)
2900{
2901 struct IndexSharedData *shared = fdata->shared;
2902 struct IndexPrivateData *priv = fdata->priv;
2903 int rc = -1;
2904 if (priv->tag_prefix)
2905 {
2906 struct Mailbox *m = shared->mailbox;
2907 for (size_t i = 0; i < m->msg_count; i++)
2908 {
2909 struct Email *e = m->emails[i];
2910 if (!e)
2911 break;
2912 if (message_is_tagged(e))
2913 rc = mutt_resend_message(NULL, shared->mailbox, e, shared->sub);
2914 }
2915 }
2916 else
2917 {
2918 rc = mutt_resend_message(NULL, shared->mailbox, shared->email, shared->sub);
2919 }
2920
2922 return (rc == -1) ? FR_ERROR : FR_SUCCESS;
2923}
2924
2936static int op_save(struct IndexFunctionData *fdata, const struct KeyEvent *event)
2937{
2938 struct IndexSharedData *shared = fdata->shared;
2939 struct IndexPrivateData *priv = fdata->priv;
2940 const int op = event->op;
2941 if (((op == OP_DECRYPT_COPY) || (op == OP_DECRYPT_SAVE)) && !WithCrypto)
2942 return FR_NOT_IMPL;
2943
2944 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
2945 ea_add_selection(&ea, shared->mailbox_view, shared->email, priv->tag_prefix,
2946 event->count);
2947 if (ARRAY_EMPTY(&ea))
2948 {
2949 ARRAY_FREE(&ea);
2950 return FR_NO_ACTION;
2951 }
2952 const int num = ARRAY_SIZE(&ea);
2953
2954 const enum MessageSaveOpt save_opt = ((op == OP_SAVE) || (op == OP_DECODE_SAVE) ||
2955 (op == OP_DECRYPT_SAVE)) ?
2956 SAVE_MOVE :
2957 SAVE_COPY;
2958
2959 enum MessageTransformOpt transform_opt =
2960 ((op == OP_DECODE_SAVE) || (op == OP_DECODE_COPY)) ? TRANSFORM_DECODE :
2961 ((op == OP_DECRYPT_SAVE) || (op == OP_DECRYPT_COPY)) ? TRANSFORM_DECRYPT :
2963
2964 const int rc = mutt_save_message(shared->mailbox, &ea, save_opt, transform_opt);
2965 if ((rc == 0) && (save_opt == SAVE_MOVE) && !priv->tag_prefix)
2966 {
2967 resolve_email(priv, shared, RESOLVE_NEXT_UNDELETED, 1);
2968 }
2969 ARRAY_FREE(&ea);
2970
2971 if (priv->tag_prefix || (num > 1))
2973
2974 return (rc == -1) ? FR_ERROR : FR_SUCCESS;
2975}
2976
2986static int op_search(struct IndexFunctionData *fdata, const struct KeyEvent *event)
2987{
2988 struct IndexSharedData *shared = fdata->shared;
2989 struct IndexPrivateData *priv = fdata->priv;
2990 SearchFlags flags = SEARCH_NONE;
2991 switch (event->op)
2992 {
2993 case OP_SEARCH:
2994 flags |= SEARCH_PROMPT;
2995 shared->search_state->reverse = false;
2996 break;
2997 case OP_SEARCH_REVERSE:
2998 flags |= SEARCH_PROMPT;
2999 shared->search_state->reverse = true;
3000 break;
3001 case OP_SEARCH_NEXT:
3002 break;
3003 case OP_SEARCH_OPPOSITE:
3004 flags |= SEARCH_OPPOSITE;
3005 break;
3006 }
3007
3008 // Initiating a search can happen on an empty mailbox, but
3009 // searching for next/previous/... needs to be on a message and
3010 // thus a non-empty mailbox
3011 int index = menu_get_index(priv->menu);
3012 index = mutt_search_command(shared->mailbox_view, priv->menu, index,
3013 shared->search_state, flags);
3014 if (index != -1)
3015 menu_set_index(priv->menu, index);
3016
3017 return FR_SUCCESS;
3018}
3019
3027static int op_sort(struct IndexFunctionData *fdata, const struct KeyEvent *event)
3028{
3029 struct IndexSharedData *shared = fdata->shared;
3030 struct IndexPrivateData *priv = fdata->priv;
3031 if (!mutt_select_sort(event->op == OP_SORT_REVERSE))
3032 return FR_ERROR;
3033
3034 if (shared->mailbox && (shared->mailbox->msg_count != 0))
3035 {
3038 }
3039
3040 return FR_SUCCESS;
3041}
3042
3046static int op_tag(struct IndexFunctionData *fdata, const struct KeyEvent *event)
3047{
3048 struct IndexSharedData *shared = fdata->shared;
3049 struct IndexPrivateData *priv = fdata->priv;
3050 const bool c_auto_tag = cs_subset_bool(shared->sub, "auto_tag");
3051 if (priv->tag_prefix && !c_auto_tag)
3052 {
3053 struct Mailbox *m = shared->mailbox;
3054 for (size_t i = 0; i < m->msg_count; i++)
3055 {
3056 struct Email *e = m->emails[i];
3057 if (!e)
3058 break;
3059 if (e->visible)
3060 mutt_set_flag(m, e, MUTT_TAG, false, true);
3061 }
3063 return FR_SUCCESS;
3064 }
3065
3066 if (!shared->email)
3067 return FR_NO_ACTION;
3068
3069 int count = MAX(event->count, 1);
3070 int current_index = menu_get_index(priv->menu);
3071
3072 for (int i = 0; i < count && current_index + i < shared->mailbox->vcount; i++)
3073 {
3074 struct Email *e = mutt_get_virt_email(shared->mailbox, current_index + i);
3075 if (e)
3076 mutt_set_flag(shared->mailbox, e, MUTT_TAG, !e->tagged, true);
3077 }
3078
3079 if (count > 0)
3080 resolve_email(priv, shared, RESOLVE_NEXT_EMAIL, count);
3081
3082 return FR_SUCCESS;
3083}
3084
3092static int op_tag_thread(struct IndexFunctionData *fdata, const struct KeyEvent *event)
3093{
3094 struct IndexSharedData *shared = fdata->shared;
3095 struct IndexPrivateData *priv = fdata->priv;
3096 if (!shared->email)
3097 return FR_NO_ACTION;
3098
3099 const int op = event->op;
3101 !shared->email->tagged, (op != OP_TAG_THREAD));
3102 if (rc != -1)
3103 {
3104 const enum ResolveMethod rm = (op == OP_TAG_THREAD) ? RESOLVE_NEXT_THREAD :
3106 resolve_email(priv, shared, rm, 1);
3108 }
3109
3110 return FR_SUCCESS;
3111}
3112
3116static int op_toggle_new(struct IndexFunctionData *fdata, const struct KeyEvent *event)
3117{
3118 struct IndexSharedData *shared = fdata->shared;
3119 struct IndexPrivateData *priv = fdata->priv;
3120 /* L10N: CHECK_ACL */
3121 if (!check_acl(shared->mailbox, MUTT_ACL_SEEN, _("Can't toggle new")))
3122 return FR_ERROR;
3123
3124 struct Mailbox *m = shared->mailbox;
3125 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
3126 ea_add_selection(&ea, shared->mailbox_view, shared->email, priv->tag_prefix,
3127 event->count);
3128 if (ARRAY_EMPTY(&ea))
3129 {
3130 ARRAY_FREE(&ea);
3131 return FR_NO_ACTION;
3132 }
3133 const int num = ARRAY_SIZE(&ea);
3134
3135 struct Email **ep = NULL;
3136 ARRAY_FOREACH(ep, &ea)
3137 {
3138 if ((*ep)->read || (*ep)->old)
3139 mutt_set_flag(m, *ep, MUTT_NEW, true, true);
3140 else
3141 mutt_set_flag(m, *ep, MUTT_READ, true, true);
3142 }
3143 ARRAY_FREE(&ea);
3144
3145 if (priv->tag_prefix)
3146 {
3148 }
3149 else
3150 {
3151 resolve_email(priv, shared, RESOLVE_NEXT_UNDELETED, num);
3152 if (num > 1)
3154 }
3155
3156 return FR_SUCCESS;
3157}
3158
3162static int op_toggle_write(struct IndexFunctionData *fdata, const struct KeyEvent *event)
3163{
3164 struct IndexSharedData *shared = fdata->shared;
3165 mx_toggle_write(shared->mailbox);
3166 return FR_SUCCESS;
3167}
3168
3172static int op_undelete(struct IndexFunctionData *fdata, const struct KeyEvent *event)
3173{
3174 struct IndexSharedData *shared = fdata->shared;
3175 struct IndexPrivateData *priv = fdata->priv;
3176 /* L10N: CHECK_ACL */
3177 if (!check_acl(shared->mailbox, MUTT_ACL_DELETE, _("Can't undelete message")))
3178 return FR_ERROR;
3179
3180 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
3181 ea_add_selection(&ea, shared->mailbox_view, shared->email, priv->tag_prefix,
3182 event->count);
3183 if (ARRAY_EMPTY(&ea))
3184 {
3185 ARRAY_FREE(&ea);
3186 return FR_NO_ACTION;
3187 }
3188 const int num = ARRAY_SIZE(&ea);
3189
3190 mutt_emails_set_flag(shared->mailbox, &ea, MUTT_DELETE, false);
3191 mutt_emails_set_flag(shared->mailbox, &ea, MUTT_PURGE, false);
3192 ARRAY_FREE(&ea);
3193
3194 if (priv->tag_prefix)
3195 {
3197 }
3198 else
3199 {
3200 resolve_email(priv, shared, RESOLVE_NEXT_EMAIL, num);
3201 if (num > 1)
3203 }
3204
3205 return FR_SUCCESS;
3206}
3207
3215static int op_undelete_thread(struct IndexFunctionData *fdata, const struct KeyEvent *event)
3216{
3217 struct IndexSharedData *shared = fdata->shared;
3218 struct IndexPrivateData *priv = fdata->priv;
3219 /* L10N: CHECK_ACL */
3220 /* L10N: Due to the implementation details we do not know whether we
3221 undelete zero, 1, 12, ... messages. So in English we use
3222 "messages". Your language might have other means to express this. */
3223 if (!check_acl(shared->mailbox, MUTT_ACL_DELETE, _("Can't undelete messages")))
3224 return FR_ERROR;
3225
3226 const int op = event->op;
3227 const bool subthread = (op != OP_UNDELETE_THREAD);
3228 int rc = 0;
3229 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
3230 ea_add_selection_threads(&ea, shared->mailbox_view, shared->email,
3231 priv->tag_prefix, subthread, event->count);
3232 const int num = ARRAY_SIZE(&ea);
3233
3234 struct Email **ep = NULL;
3235 ARRAY_FOREACH(ep, &ea)
3236 {
3237 rc = mutt_thread_set_flag(shared->mailbox, *ep, MUTT_DELETE, false, subthread);
3238 if (rc == -1)
3239 break;
3240 rc = mutt_thread_set_flag(shared->mailbox, *ep, MUTT_PURGE, false, subthread);
3241 if (rc == -1)
3242 break;
3243 }
3244 ARRAY_FREE(&ea);
3245
3246 if (rc == -1)
3247 return FR_ERROR;
3248
3249 if (priv->tag_prefix)
3250 {
3252 return FR_SUCCESS;
3253 }
3254
3255 const enum ResolveMethod rm = (op == OP_UNDELETE_THREAD) ? RESOLVE_NEXT_THREAD :
3257 resolve_email(priv, shared, rm, num);
3259 return FR_SUCCESS;
3260}
3261
3265static int op_view_attachments(struct IndexFunctionData *fdata, const struct KeyEvent *event)
3266{
3267 struct IndexSharedData *shared = fdata->shared;
3268 struct IndexPrivateData *priv = fdata->priv;
3269 if (!shared->email)
3270 return FR_NO_ACTION;
3271
3272 enum FunctionRetval rc = FR_ERROR;
3273 struct Message *msg = mx_msg_open(shared->mailbox, shared->email);
3274 if (msg)
3275 {
3276 dlg_attach(fdata->n->sub, shared->mailbox_view, shared->email, msg->fp,
3277 shared->attach_msg);
3278 if (shared->email->attach_del)
3279 {
3280 shared->mailbox->changed = true;
3281 }
3282 mx_msg_close(shared->mailbox, &msg);
3283 rc = FR_SUCCESS;
3284 }
3286 return rc;
3287}
3288
3289// -----------------------------------------------------------------------------
3290
3291#ifdef USE_AUTOCRYPT
3295static int op_autocrypt_acct_menu(struct IndexFunctionData *fdata, const struct KeyEvent *event)
3296{
3297 dlg_autocrypt();
3298 return FR_SUCCESS;
3299}
3300#endif
3301
3305static int op_main_imap_fetch(struct IndexFunctionData *fdata, const struct KeyEvent *event)
3306{
3307 struct IndexSharedData *shared = fdata->shared;
3308 if (!shared->mailbox || (shared->mailbox->type != MUTT_IMAP))
3309 return FR_NO_ACTION;
3310
3311 imap_check_mailbox(shared->mailbox, true);
3312 return FR_SUCCESS;
3313}
3314
3318static int op_main_imap_logout_all(struct IndexFunctionData *fdata, const struct KeyEvent *event)
3319{
3320 struct IndexSharedData *shared = fdata->shared;
3321 struct IndexPrivateData *priv = fdata->priv;
3322 if (shared->mailbox && (shared->mailbox->type == MUTT_IMAP))
3323 {
3324 const enum MxStatus check = mx_mbox_close(shared->mailbox);
3325 if (check == MX_STATUS_OK)
3326 {
3328 }
3329 else
3330 {
3331 if ((check == MX_STATUS_NEW_MAIL) || (check == MX_STATUS_REOPENED))
3332 {
3333 update_index(priv->menu, shared->mailbox_view, check, priv->oldcount, shared);
3334 }
3337 return FR_ERROR;
3338 }
3339 }
3341 mutt_message(_("Logged out of IMAP servers"));
3344
3345 return FR_SUCCESS;
3346}
3347
3351static int op_catchup(struct IndexFunctionData *fdata, const struct KeyEvent *event)
3352{
3353 struct IndexSharedData *shared = fdata->shared;
3354 struct IndexPrivateData *priv = fdata->priv;
3355 struct Mailbox *m = shared->mailbox;
3356 if (!m || (m->type != MUTT_NNTP))
3357 return FR_NO_ACTION;
3358
3359 struct NntpMboxData *mdata = m->mdata;
3360 if (mutt_newsgroup_catchup(m, mdata->adata, mdata->group))
3362
3363 return FR_SUCCESS;
3364}
3365
3373static int op_get_children(struct IndexFunctionData *fdata, const struct KeyEvent *event)
3374{
3375 struct IndexSharedData *shared = fdata->shared;
3376 struct IndexPrivateData *priv = fdata->priv;
3377 struct Mailbox *m = shared->mailbox;
3378 if (m->type != MUTT_NNTP)
3379 return FR_ERROR;
3380
3381 struct Email *e = shared->email;
3382 if (!e)
3383 return FR_NO_ACTION;
3384
3385 char buf[PATH_MAX] = { 0 };
3386 int oldmsgcount = m->msg_count;
3387 int oldindex = e->index;
3388 int rc = 0;
3389
3390 if (!e->env->message_id)
3391 {
3392 mutt_error(_("No Message-ID. Unable to perform operation."));
3393 return FR_ERROR;
3394 }
3395
3396 mutt_message(_("Fetching message headers..."));
3397 if (!m->id_hash)
3398 m->id_hash = mutt_make_id_hash(m);
3399 mutt_str_copy(buf, e->env->message_id, sizeof(buf));
3400
3401 const int op = event->op;
3402 /* trying to find msgid of the root message */
3403 if (op == OP_RECONSTRUCT_THREAD)
3404 {
3405 struct ListNode *ref = NULL;
3406 STAILQ_FOREACH(ref, &e->env->references, entries)
3407 {
3408 if (!mutt_hash_find(m->id_hash, ref->data))
3409 {
3410 rc = nntp_check_msgid(m, ref->data);
3411 if (rc < 0)
3412 return FR_ERROR;
3413 }
3414
3415 /* the last msgid in References is the root message */
3416 if (!STAILQ_NEXT(ref, entries))
3417 mutt_str_copy(buf, ref->data, sizeof(buf));
3418 }
3419 }
3420
3421 /* fetching all child messages */
3422 rc = nntp_check_children(m, buf);
3423
3424 /* at least one message has been loaded */
3425 if (m->msg_count > oldmsgcount)
3426 {
3427 bool verbose = m->verbose;
3428
3429 if (rc < 0)
3430 m->verbose = false;
3431
3432 struct MailboxView *mv = shared->mailbox_view;
3433 mutt_sort_headers(mv, (op == OP_RECONSTRUCT_THREAD));
3434 m->verbose = verbose;
3435
3436 /* if the root message was retrieved, move to it */
3437 struct Email *e2 = mutt_hash_find(m->id_hash, buf);
3438 if (e2)
3439 {
3440 menu_set_index(priv->menu, e2->vnum);
3441 }
3442 else
3443 {
3444 /* try to restore old position */
3445 for (int i = 0; i < m->msg_count; i++)
3446 {
3447 e2 = m->emails[i];
3448 if (!e2)
3449 break;
3450 if (e2->index == oldindex)
3451 {
3452 menu_set_index(priv->menu, e2->vnum);
3453 /* as an added courtesy, recenter the menu
3454 * with the current entry at the middle of the screen */
3456 }
3457 }
3458 }
3460 }
3461 else if (rc >= 0)
3462 {
3463 mutt_error(_("No deleted messages found in the thread"));
3464 return FR_ERROR;
3465 }
3466
3467 return FR_SUCCESS;
3468}
3469
3477static int op_get_message(struct IndexFunctionData *fdata, const struct KeyEvent *event)
3478{
3479 struct IndexSharedData *shared = fdata->shared;
3480 struct IndexPrivateData *priv = fdata->priv;
3481 struct Mailbox *m = shared->mailbox;
3482 if (m->type != MUTT_NNTP)
3483 return FR_SUCCESS;
3484
3485 int rc = FR_ERROR;
3486 struct Buffer *buf = buf_pool_get();
3487
3488 const int op = event->op;
3489 if (op == OP_GET_MESSAGE)
3490 {
3491 if ((mw_get_field(_("Enter Message-ID: "), buf, MUTT_COMP_NONE, HC_OTHER, NULL, NULL) != 0) ||
3492 buf_is_empty(buf))
3493 {
3494 goto done;
3495 }
3496 }
3497 else
3498 {
3499 struct Email *e = shared->email;
3500 if (!e || STAILQ_EMPTY(&e->env->references))
3501 {
3502 mutt_error(_("Article has no parent reference"));
3503 goto done;
3504 }
3506 }
3507
3508 if (!m->id_hash)
3509 m->id_hash = mutt_make_id_hash(m);
3510 struct Email *e = mutt_hash_find(m->id_hash, buf_string(buf));
3511 if (e)
3512 {
3513 if (e->vnum != -1)
3514 {
3515 menu_set_index(priv->menu, e->vnum);
3516 }
3517 else if (e->collapsed)
3518 {
3520 mutt_set_vnum(m);
3521 menu_set_index(priv->menu, e->vnum);
3522 }
3523 else
3524 {
3525 mutt_error(_("Message is not visible in limited view"));
3526 }
3527 }
3528 else
3529 {
3530 mutt_message(_("Fetching %s from server..."), buf_string(buf));
3531 int rc2 = nntp_check_msgid(m, buf_string(buf));
3532 if (rc2 == 0)
3533 {
3534 e = m->emails[m->msg_count - 1];
3535 struct MailboxView *mv = shared->mailbox_view;
3536 mutt_sort_headers(mv, false);
3537 menu_set_index(priv->menu, e->vnum);
3539 rc = FR_SUCCESS;
3540 }
3541 else if (rc2 > 0)
3542 {
3543 mutt_error(_("Article %s not found on the server"), buf_string(buf));
3544 }
3545 }
3546
3547done:
3548 buf_pool_release(&buf);
3549 return rc;
3550}
3551
3559static int op_main_change_group(struct IndexFunctionData *fdata, const struct KeyEvent *event)
3560{
3562 struct IndexSharedData *shared = fdata->shared;
3563 struct IndexPrivateData *priv = fdata->priv;
3564 struct Buffer *folderbuf = buf_pool_get();
3565 buf_alloc(folderbuf, PATH_MAX);
3566
3567 OptNews = false;
3568 bool read_only;
3569 char *cp = NULL;
3570 const bool c_read_only = cs_subset_bool(shared->sub, "read_only");
3571 const int op = event->op;
3572 if (shared->attach_msg || c_read_only || (op == OP_MAIN_CHANGE_GROUP_READONLY))
3573 {
3574 cp = _("Open newsgroup in read-only mode");
3575 read_only = true;
3576 }
3577 else
3578 {
3579 cp = _("Open newsgroup");
3580 read_only = false;
3581 }
3582
3583 const bool c_change_folder_next = cs_subset_bool(shared->sub, "change_folder_next");
3584 if (c_change_folder_next && shared->mailbox && !buf_is_empty(&shared->mailbox->pathbuf))
3585 {
3586 buf_strcpy(folderbuf, mailbox_path(shared->mailbox));
3587 pretty_mailbox(folderbuf);
3588 }
3589
3590 OptNews = true;
3591 const char *const c_news_server = cs_subset_string(shared->sub, "news_server");
3592 if (!mod_data->current_news_srv)
3593 mod_data->current_news_srv = nntp_select_server(shared->mailbox, c_news_server, false);
3594 if (!mod_data->current_news_srv)
3595 goto changefoldercleanup2;
3596
3597 nntp_mailbox(shared->mailbox, folderbuf->data, folderbuf->dsize);
3598
3599 if (mw_enter_fname(cp, folderbuf, true, shared->mailbox, false, NULL, NULL,
3600 MUTT_SEL_NONE) == -1)
3601 {
3602 goto changefoldercleanup2;
3603 }
3604
3605 /* Selected directory is okay, let's save it. */
3607
3608 if (buf_is_empty(folderbuf))
3609 {
3610 msgwin_clear_text(NULL);
3611 goto changefoldercleanup2;
3612 }
3613
3614 struct Mailbox *m = mx_mbox_find2(buf_string(folderbuf));
3615 if (m)
3616 {
3617 change_folder_mailbox(priv->menu, m, &priv->oldcount, shared, read_only);
3618 }
3619 else
3620 {
3621 change_folder_string(priv->menu, folderbuf, &priv->oldcount, shared, read_only);
3622 }
3623 struct MuttWindow *dlg = dialog_find(priv->win_index);
3624 dlg->help_data = IndexNewsHelp;
3625
3626changefoldercleanup2:
3627 buf_pool_release(&folderbuf);
3628 return FR_SUCCESS;
3629}
3630
3639static int op_post(struct IndexFunctionData *fdata, const struct KeyEvent *event)
3640{
3641 struct IndexSharedData *shared = fdata->shared;
3642 struct IndexPrivateData *priv = fdata->priv;
3643 if (!shared->email)
3644 return FR_NO_ACTION;
3645
3646 const int op = event->op;
3647 if ((op != OP_FOLLOWUP) || !shared->email->env->followup_to ||
3648 !mutt_istr_equal(shared->email->env->followup_to, "poster") ||
3649 (query_quadoption(_("Reply by mail as poster prefers?"), shared->sub,
3650 "followup_to_poster") != MUTT_YES))
3651 {
3652 if (shared->mailbox && (shared->mailbox->type == MUTT_NNTP) &&
3653 !((struct NntpMboxData *) shared->mailbox->mdata)->allowed &&
3654 (query_quadoption(_("Posting to this group not allowed, may be moderated. Continue?"),
3655 shared->sub, "post_moderated") != MUTT_YES))
3656 {
3657 return FR_ERROR;
3658 }
3659 if (op == OP_POST)
3660 {
3661 mutt_send_message(SEND_NEWS, NULL, NULL, shared->mailbox, NULL, shared->sub);
3662 }
3663 else
3664 {
3665 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
3666 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
3667 mutt_send_message(((op == OP_FOLLOWUP) ? SEND_REPLY : SEND_FORWARD) | SEND_NEWS,
3668 NULL, NULL, shared->mailbox, &ea, shared->sub);
3669 ARRAY_FREE(&ea);
3670 }
3672 return FR_SUCCESS;
3673 }
3674
3675 struct KeyEvent event_r = { 0, OP_REPLY };
3676 return op_reply(fdata, &event_r);
3677}
3678
3679#ifdef USE_NOTMUCH
3683static int op_main_entire_thread(struct IndexFunctionData *fdata, const struct KeyEvent *event)
3684{
3685 struct IndexSharedData *shared = fdata->shared;
3686 struct IndexPrivateData *priv = fdata->priv;
3688 {
3689 if (((shared->mailbox->type != MUTT_MH) && (shared->mailbox->type != MUTT_MAILDIR)) ||
3691 {
3692 mutt_message(_("No virtual folder and no Message-ID, aborting"));
3693 return FR_ERROR;
3694 } // no virtual folder, but we have Message-ID, reconstruct thread on-the-fly
3695
3696 struct Buffer *buf = buf_pool_get();
3697 buf_alloc(buf, PATH_MAX);
3698 buf_addstr(buf, "id:");
3699
3700 int msg_id_offset = 0;
3701 if ((shared->email->env->message_id)[0] == '<')
3702 msg_id_offset = 1;
3703
3704 buf_addstr(buf, shared->email->env->message_id + msg_id_offset);
3705
3706 size_t len = buf_len(buf);
3707 ASSERT(len > 0);
3708 if (buf->data[len - 1] == '>')
3709 buf->data[len - 1] = '\0';
3710
3711 change_folder_notmuch(priv->menu, buf->data, buf->dsize, &priv->oldcount, shared, false);
3712 buf_pool_release(&buf);
3713
3714 // If notmuch doesn't contain the message, we're left in an empty
3715 // vfolder. No messages are found, but nm_read_entire_thread assumes
3716 // a valid Message-ID and will throw a segfault.
3717 //
3718 // To prevent that, stay in the empty vfolder and print an error.
3719 if (!shared->mailbox)
3720 return FR_ERROR;
3721
3722 if (shared->mailbox->msg_count == 0)
3723 {
3724 mutt_error(_("failed to find message in notmuch database. try running 'notmuch new'."));
3725 return FR_ERROR;
3726 }
3727 }
3728 priv->oldcount = shared->mailbox->msg_count;
3729 int index = menu_get_index(priv->menu);
3730 struct Email *e_oldcur = mutt_get_virt_email(shared->mailbox, index);
3731 if (!e_oldcur)
3732 return FR_ERROR;
3733
3734 if (nm_read_entire_thread(shared->mailbox, e_oldcur) < 0)
3735 {
3736 mutt_message(_("Failed to read thread, aborting"));
3737 return FR_ERROR;
3738 }
3739
3740 // nm_read_entire_thread() may modify msg_count and menu won't be updated.
3741 priv->menu->max = shared->mailbox->msg_count;
3742
3743 if (priv->oldcount < shared->mailbox->msg_count)
3744 {
3745 /* nm_read_entire_thread() triggers mutt_sort_headers() if necessary */
3746 index = e_oldcur->vnum;
3747 if (e_oldcur->collapsed || shared->mailbox_view->collapsed)
3748 {
3749 index = mutt_uncollapse_thread(e_oldcur);
3750 mutt_set_vnum(shared->mailbox);
3751 }
3752 menu_set_index(priv->menu, index);
3754 }
3755
3756 return FR_SUCCESS;
3757}
3758
3767 const struct KeyEvent *event)
3768{
3769 struct IndexSharedData *shared = fdata->shared;
3770 struct IndexPrivateData *priv = fdata->priv;
3771 int rc = FR_SUCCESS;
3772 struct Buffer *buf = buf_pool_get();
3773
3774 if ((mw_get_field("Query: ", buf, MUTT_COMP_NONE, HC_OTHER, &CompleteNmQueryOps, NULL) != 0) ||
3775 buf_is_empty(buf))
3776 {
3777 mutt_message(_("No query, aborting"));
3778 rc = FR_NO_ACTION;
3779 goto done;
3780 }
3781
3782 // Keep copy of user's query to name the mailbox
3783 char *query_unencoded = buf_strdup(buf);
3784
3785 buf_alloc(buf, PATH_MAX);
3786 const int op = event->op;
3787 struct Mailbox *m_query = change_folder_notmuch(priv->menu, buf->data, buf->dsize,
3788 &priv->oldcount, shared,
3789 (op == OP_MAIN_VFOLDER_FROM_QUERY_READONLY));
3790 if (m_query)
3791 {
3792 FREE(&m_query->name);
3793 m_query->name = query_unencoded;
3794 query_unencoded = NULL;
3795 rc = FR_SUCCESS;
3796 }
3797 else
3798 {
3799 FREE(&query_unencoded);
3800 }
3801
3802done:
3803 buf_pool_release(&buf);
3804 return rc;
3805}
3806
3816 const struct KeyEvent *event)
3817{
3818 struct IndexSharedData *shared = fdata->shared;
3819 struct IndexPrivateData *priv = fdata->priv;
3820 // Common guard clauses.
3822 {
3823 mutt_message(_("Windowed queries disabled"));
3824 return FR_ERROR;
3825 }
3826 const char *const c_nm_query_window_current_search = cs_subset_string(shared->sub, "nm_query_window_current_search");
3827 if (!c_nm_query_window_current_search)
3828 {
3829 mutt_message(_("No notmuch vfolder currently loaded"));
3830 return FR_ERROR;
3831 }
3832
3833 // Call the specific operation.
3834 switch (event->op)
3835 {
3836 case OP_MAIN_WINDOWED_VFOLDER_BACKWARD:
3838 break;
3839 case OP_MAIN_WINDOWED_VFOLDER_FORWARD:
3841 break;
3842 case OP_MAIN_WINDOWED_VFOLDER_RESET:
3844 break;
3845 }
3846
3847 // Common query window folder change.
3848 char buf[PATH_MAX] = { 0 };
3849 mutt_str_copy(buf, c_nm_query_window_current_search, sizeof(buf));
3850 change_folder_notmuch(priv->menu, buf, sizeof(buf), &priv->oldcount, shared, false);
3851
3852 return FR_SUCCESS;
3853}
3854#endif
3855
3859static int op_main_fetch_mail(struct IndexFunctionData *fdata, const struct KeyEvent *event)
3860{
3861 struct IndexPrivateData *priv = fdata->priv;
3864 return FR_SUCCESS;
3865}
3866
3867// -----------------------------------------------------------------------------
3868
3876static bool prereq(struct IndexSharedData *shared, struct Menu *menu, CheckFlags checks)
3877{
3878 bool result = true;
3879 struct MailboxView *mv = shared->mailbox_view;
3880
3881 if (checks & (CHECK_MSGCOUNT | CHECK_VISIBLE | CHECK_READONLY))
3882 checks |= CHECK_IN_MAILBOX;
3883
3884 if ((checks & CHECK_IN_MAILBOX) && (!mv || !mv->mailbox))
3885 {
3886 mutt_error(_("No mailbox is open"));
3887 result = false;
3888 }
3889
3890 if (result && (checks & CHECK_MSGCOUNT) && (mv->mailbox->msg_count == 0))
3891 {
3892 mutt_error(_("There are no messages"));
3893 result = false;
3894 }
3895
3896 int index = menu_get_index(menu);
3897 if (result && (checks & CHECK_VISIBLE) &&
3898 ((index < 0) || (index >= mv->mailbox->vcount)))
3899 {
3900 mutt_error(_("No visible messages"));
3901 result = false;
3902 }
3903
3904 if (result && (checks & CHECK_READONLY) && mv->mailbox->readonly)
3905 {
3906 mutt_error(_("Mailbox is read-only"));
3907 result = false;
3908 }
3909
3910 if (result && (checks & CHECK_ATTACH) && shared->attach_msg)
3911 {
3912 mutt_error(_("Function not permitted in attach-message mode"));
3913 result = false;
3914 }
3915
3916 if (!result)
3917 mutt_flushinp();
3918
3919 return result;
3920}
3921
3925static const struct IndexFunction IndexFunctions[] = {
3926 // clang-format off
3927 { OP_ALIAS_DIALOG, op_alias_dialog, CHECK_NONE },
3933 { OP_COPY_MESSAGE, op_save, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3934 { OP_CREATE_ALIAS, op_create_alias, CHECK_NONE },
3935 { OP_DECODE_COPY, op_save, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3936 { OP_DECODE_SAVE, op_save, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3937 { OP_DECRYPT_COPY, op_save, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3938 { OP_DECRYPT_SAVE, op_save, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3946 { OP_EDIT_OR_VIEW_RAW_MESSAGE, op_edit_raw_message, CHECK_ATTACH | CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3948 { OP_END_COND, op_end_cond, CHECK_NONE },
3949 { OP_EXIT, op_exit, CHECK_NONE },
3953 { OP_FORGET_PASSPHRASE, op_forget_passphrase, CHECK_NONE },
3955 { OP_FORWARD_TO_GROUP, op_post, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3959 { OP_GENERIC_SELECT_ENTRY, op_display_message, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3962 { OP_JUMP, op_jump, CHECK_IN_MAILBOX },
3963 { OP_LIMIT_CURRENT_THREAD, op_main_limit, CHECK_IN_MAILBOX },
3968 { OP_MAIL, op_mail, CHECK_ATTACH },
3969 { OP_MAILBOX_LIST, op_mailbox_list, CHECK_NONE },
3970 { OP_MAIL_KEY, op_mail_key, CHECK_ATTACH },
3972 { OP_MAIN_CHANGE_FOLDER, op_main_change_folder, CHECK_NONE },
3973 { OP_MAIN_CHANGE_FOLDER_READONLY, op_main_change_folder, CHECK_NONE },
3974 { OP_MAIN_CHANGE_GROUP, op_main_change_group, CHECK_NONE },
3975 { OP_MAIN_CHANGE_GROUP_READONLY, op_main_change_group, CHECK_NONE },
3977 { OP_MAIN_CLOSE_ALL_THREADS, op_main_close_all_threads, CHECK_IN_MAILBOX },
3979 { OP_MAIN_COLLAPSE_ALL, op_main_collapse_all, CHECK_IN_MAILBOX },
3980 { OP_MAIN_COLLAPSE_THREAD, op_main_collapse_thread, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3981 { OP_MAIN_DELETE_PATTERN, op_main_delete_pattern, CHECK_ATTACH | CHECK_IN_MAILBOX | CHECK_READONLY },
3982 { OP_MAIN_FETCH_MAIL, op_main_fetch_mail, CHECK_ATTACH },
3983 { OP_MAIN_IMAP_FETCH, op_main_imap_fetch, CHECK_NONE },
3984 { OP_MAIN_IMAP_LOGOUT_ALL, op_main_imap_logout_all, CHECK_NONE },
3985 { OP_MAIN_LIMIT, op_main_limit, CHECK_IN_MAILBOX },
3988 { OP_MAIN_MODIFY_TAGS_THEN_HIDE, op_main_modify_tags, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_READONLY | CHECK_VISIBLE },
3990 { OP_MAIN_NEXT_NEW_THEN_UNREAD, op_main_next_new, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3991 { OP_MAIN_NEXT_SUBTHREAD, op_main_next_thread, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3994 { OP_MAIN_NEXT_UNREAD, op_main_next_new, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3995 { OP_MAIN_NEXT_UNREAD_MAILBOX, op_main_next_unread_mailbox, CHECK_IN_MAILBOX },
3996 { OP_MAIN_PREV_UNREAD_MAILBOX, op_main_prev_unread_mailbox, CHECK_IN_MAILBOX },
3997 { OP_MAIN_OPEN_ALL_THREADS, op_main_open_all_threads, CHECK_IN_MAILBOX },
3999 { OP_MAIN_PARENT_MESSAGE, op_main_root_message, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
4001 { OP_MAIN_PREV_NEW_THEN_UNREAD, op_main_next_new, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
4002 { OP_MAIN_PREV_SUBTHREAD, op_main_next_thread, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
4005 { OP_MAIN_PREV_UNREAD, op_main_next_new, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
4011 { OP_MAIN_SHOW_LIMIT, op_main_show_limit, CHECK_IN_MAILBOX },
4012 { OP_MAIN_SYNC_FOLDER, op_main_sync_folder, CHECK_NONE },
4013 { OP_MAIN_TAG_PATTERN, op_main_tag_pattern, CHECK_IN_MAILBOX },
4014 { OP_MAIN_UNDELETE_PATTERN, op_main_undelete_pattern, CHECK_IN_MAILBOX | CHECK_READONLY },
4015 { OP_MAIN_UNTAG_PATTERN, op_main_untag_pattern, CHECK_IN_MAILBOX },
4019 { OP_POST, op_post, CHECK_ATTACH | CHECK_IN_MAILBOX },
4024 { OP_QUERY, op_query, CHECK_ATTACH },
4025 { OP_QUIT, op_quit, CHECK_NONE },
4026 { OP_RECALL_MESSAGE, op_recall_message, CHECK_ATTACH },
4031 { OP_SEARCH, op_search, CHECK_IN_MAILBOX },
4032 { OP_SEARCH_NEXT, op_search, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
4033 { OP_SEARCH_OPPOSITE, op_search, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
4034 { OP_SEARCH_REVERSE, op_search, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
4035 { OP_SORT, op_sort, CHECK_NONE },
4036 { OP_SORT_REVERSE, op_sort, CHECK_NONE },
4041 { OP_TOGGLE_READ, op_main_limit, CHECK_IN_MAILBOX },
4042 { OP_TOGGLE_WRITE, op_toggle_write, CHECK_IN_MAILBOX },
4048#ifdef USE_AUTOCRYPT
4049 { OP_AUTOCRYPT_ACCT_MENU, op_autocrypt_acct_menu, CHECK_NONE },
4050#endif
4051#ifdef USE_NOTMUCH
4052 { OP_MAIN_CHANGE_VFOLDER, op_main_change_folder, CHECK_NONE },
4054 { OP_MAIN_VFOLDER_FROM_QUERY, op_main_vfolder_from_query, CHECK_NONE },
4055 { OP_MAIN_VFOLDER_FROM_QUERY_READONLY, op_main_vfolder_from_query, CHECK_NONE },
4056 { OP_MAIN_WINDOWED_VFOLDER_BACKWARD, op_main_windowed_vfolder, CHECK_IN_MAILBOX },
4057 { OP_MAIN_WINDOWED_VFOLDER_FORWARD, op_main_windowed_vfolder, CHECK_IN_MAILBOX },
4058 { OP_MAIN_WINDOWED_VFOLDER_RESET, op_main_windowed_vfolder, CHECK_IN_MAILBOX },
4059#endif
4060 { 0, NULL, CHECK_NONE },
4061 // clang-format on
4062};
4063
4067int index_function_dispatcher(struct MuttWindow *win, const struct KeyEvent *event)
4068{
4069 // The Dispatcher may be called on any Window in the Dialog
4070 struct MuttWindow *dlg = dialog_find(win);
4071 if (!event || !dlg || !dlg->wdata || !win->parent || !win->parent->wdata)
4072 {
4074 return FR_ERROR;
4075 }
4076
4077 const int op = event->op;
4078 struct IndexPrivateData *priv = win->parent->wdata;
4079 struct IndexSharedData *shared = dlg->wdata;
4080
4082
4083 struct IndexFunctionData fdata = {
4084 .n = NeoMutt,
4085 .mod_data = mod_data,
4086 .shared = shared,
4087 .priv = priv,
4088 };
4089
4090 int rc = FR_UNKNOWN;
4091 for (size_t i = 0; IndexFunctions[i].op != OP_NULL; i++)
4092 {
4093 const struct IndexFunction *fn = &IndexFunctions[i];
4094 if (fn->op == op)
4095 {
4096 if (!prereq(shared, priv->menu, fn->flags))
4097 {
4098 rc = FR_ERROR;
4099 break;
4100 }
4101 rc = fn->function(&fdata, event);
4102 break;
4103 }
4104 }
4105
4106 if (rc == FR_UNKNOWN) // Not our function
4107 return rc;
4108
4109 const char *result = dispatcher_get_retval_name(rc);
4110 mutt_debug(LL_DEBUG1, "Handled %s (%d) -> %s\n", opcodes_get_name(op), op, NONULL(result));
4111
4113 return rc;
4114}
4115
4121{
4123 ASSERT(mod_data);
4124
4125 return mod_data->menu_index;
4126}
Email Aliases.
void alias_create(struct AddressList *al, const struct ConfigSubset *sub)
Create a new Alias from an Address.
Definition alias.c:368
struct AddressList * mutt_get_address(struct Envelope *env, const char **prefix)
Get an Address from an Envelope.
Definition alias.c:328
#define ARRAY_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_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:161
size_t buf_len(const struct Buffer *buf)
Calculate the length of a Buffer.
Definition buffer.c:491
bool buf_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition buffer.c:291
size_t buf_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition buffer.c:226
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition buffer.c:395
char * buf_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition buffer.c:571
void buf_alloc(struct Buffer *buf, size_t new_size)
Make sure a buffer can store at least new_size bytes.
Definition buffer.c:337
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition buffer.h:96
@ CMD_SHUTDOWN_HOOK
:shutdown-hook
Definition command.h: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_MH
'MH' Mailbox type
Definition mailbox.h:46
@ MUTT_NNTP
'NNTP' (Usenet) Mailbox type
Definition mailbox.h:48
@ MUTT_IMAP
'IMAP' Mailbox type
Definition mailbox.h:49
@ MUTT_MAILDIR
'Maildir' Mailbox type
Definition mailbox.h:47
void crypt_extract_keys_from_messages(struct Mailbox *m, struct EmailArray *ea)
Extract keys from a message.
Definition crypt.c:863
void crypt_forget_passphrase(void)
Forget a passphrase and display a message.
Definition crypt.c:89
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:500
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:354
bool OptNeedResort
(pseudo) used to force a re-sort
Definition globals.c:52
void mutt_break_thread(struct Email *e)
Break the email Thread.
Definition thread.c:229
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:1214
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:781
bool mutt_edit_content_type(struct Email *e, struct Body *b, FILE *fp)
Edit the content type of an attachment.
Definition external.c:1073
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:664
Manage where the email is piped to external commands.
MessageTransformOpt
Message transformation option.
Definition external.h:42
@ TRANSFORM_NONE
No transformation.
Definition external.h:43
@ TRANSFORM_DECODE
Decode message.
Definition external.h:45
@ TRANSFORM_DECRYPT
Decrypt message.
Definition external.h:44
MessageSaveOpt
Message save option.
Definition external.h:52
@ SAVE_MOVE
Move message to another mailbox, removing the original.
Definition external.h:54
@ SAVE_COPY
Copy message, making a duplicate in another mailbox.
Definition external.h:53
int mutt_file_sanitize_regex(struct Buffer *dest, const char *src)
Escape any regex-magic characters in a string.
Definition file.c:624
void mutt_set_flag(struct Mailbox *m, struct Email *e, enum MessageType flag, bool bf, bool upd_mbox)
Set a flag on an email.
Definition flags.c:54
void mutt_emails_set_flag(struct Mailbox *m, struct EmailArray *ea, enum MessageType flag, bool bf)
Set flag on messages.
Definition flags.c:358
int mutt_thread_set_flag(struct Mailbox *m, struct Email *e, enum MessageType flag, bool bf, bool subthread)
Set a flag on an entire thread.
Definition flags.c:382
void mutt_flushinp(void)
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_main_limit(struct AliasFunctionData *fdata, const struct KeyEvent *event)
show only messages matching a pattern - Implements alias_function_t -
Definition functions.c:411
static int op_query(struct AliasFunctionData *fdata, const struct KeyEvent *event)
query external program for addresses - Implements alias_function_t -
Definition functions.c:469
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:152
static int op_jump(struct AliasFunctionData *fdata, const struct KeyEvent *event)
Jump to an index number - Implements alias_function_t -.
Definition functions.c:320
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:448
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:431
static int op_exit(struct AliasFunctionData *fdata, const struct KeyEvent *event)
exit this menu - Implements alias_function_t -
Definition functions.c:312
static int op_mail(struct AliasFunctionData *fdata, const struct KeyEvent *event)
mail the selected entries - Implements alias_function_t -
Definition functions.c:403
static int op_delete(struct AliasFunctionData *fdata, const struct KeyEvent *event)
delete the current entry - Implements alias_function_t -
Definition functions.c:274
static int op_search(struct AliasFunctionData *fdata, const struct KeyEvent *event)
search for a regular expression - Implements alias_function_t -
Definition functions.c:523
static int op_sort(struct AliasFunctionData *fdata, const struct KeyEvent *event)
sort aliases - Implements alias_function_t -
Definition functions.c:561
static int op_list_unsubscribe(struct AttachFunctionData *fdata, const struct KeyEvent *event)
unsubscribe from a mailing list - Implements attach_function_t -
Definition functions.c:681
static int op_attach_edit_type(struct AttachFunctionData *fdata, const struct KeyEvent *event)
edit attachment content type - Implements attach_function_t -
Definition functions.c:393
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:725
static int op_forward_message(struct AttachFunctionData *fdata, const struct KeyEvent *event)
forward a message with comments - Implements attach_function_t -
Definition functions.c:653
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:588
static int op_list_subscribe(struct AttachFunctionData *fdata, const struct KeyEvent *event)
subscribe to a mailing list - Implements attach_function_t -
Definition functions.c:669
static int op_check_traditional(struct AttachFunctionData *fdata, const struct KeyEvent *event)
check for classic PGP - Implements attach_function_t -
Definition functions.c:571
static int op_extract_keys(struct AttachFunctionData *fdata, const struct KeyEvent *event)
extract supported public keys - Implements attach_function_t -
Definition functions.c:626
static int op_reply(struct AttachFunctionData *fdata, const struct KeyEvent *event)
reply to a message - Implements attach_function_t -
Definition functions.c:699
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:555
static int op_forget_passphrase(struct AttachFunctionData *fdata, const struct KeyEvent *event)
wipe passphrases from memory - Implements attach_function_t -
Definition functions.c:644
static int op_mailbox_list(struct BrowserPrivateData *priv, const struct KeyEvent *event)
List mailboxes with new mail - Implements browser_function_t -.
Definition functions.c:1132
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:470
int index_function_dispatcher(struct MuttWindow *win, const struct KeyEvent *event)
Perform an Index function - Implements function_dispatcher_t -.
Definition functions.c:4067
void dlg_list(struct Mailbox *m, struct Email *e)
Display mailing-list actions for an email -.
Definition dlg_list.c:293
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:451
int mw_enter_fname(const char *prompt, struct Buffer *fname, bool mailbox, struct Mailbox *m, bool multiple, char ***files, int *numfiles, SelectFileFlags flags)
Ask the user to select a file -.
Definition curs_lib.c:238
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_quit(struct HistoryData *hd, const struct KeyEvent *event)
Quit this menu - Implements history_function_t -.
Definition functions.c:61
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:1046
static int op_display_address(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Display full address of sender - Implements index_function_t -.
Definition functions.c:952
static int op_next_entry(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Move to the next entry - Implements index_function_t -.
Definition functions.c:2707
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:2614
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:1789
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:3373
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:2293
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:3305
static int op_display_message(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Display a message - Implements index_function_t -.
Definition functions.c:970
static int op_list_reply(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Reply to specified mailing list - Implements index_function_t -.
Definition functions.c:1364
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:3766
static int op_save(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Make decrypted copy - Implements index_function_t -.
Definition functions.c:2936
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:2243
static int op_list_action(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Show mailing-list actions - Implements index_function_t -.
Definition functions.c:1351
static int op_mail_key(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Mail a PGP public key - Implements index_function_t -.
Definition functions.c:1430
static int op_alias_dialog(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Open the aliases dialog - Implements index_function_t -.
Definition functions.c:642
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:2495
static int op_recall_message(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Recall a postponed message - Implements index_function_t -.
Definition functions.c:2860
static int op_main_sync_folder(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Save changes to mailbox - Implements index_function_t -.
Definition functions.c:2517
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:3815
static int op_tag_thread(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Tag the current thread - Implements index_function_t -.
Definition functions.c:3092
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:1090
static int op_post(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Followup to newsgroup - Implements index_function_t -.
Definition functions.c:3639
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:3477
static int op_delete_thread(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Delete all messages in thread - Implements index_function_t -.
Definition functions.c:895
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:2731
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:1445
static int op_group_reply(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Reply to all recipients - Implements index_function_t -.
Definition functions.c:1265
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:3116
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:3318
static int op_main_close_all_threads(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Collapse all threads - Implements index_function_t -.
Definition functions.c:1599
static int op_main_open_all_threads(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Open all threads - Implements index_function_t -.
Definition functions.c:1652
static int op_end_cond(struct IndexFunctionData *fdata, const struct KeyEvent *event)
End of conditional execution (noop) - Implements index_function_t -.
Definition functions.c:1137
static int op_print(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Print the current entry - Implements index_function_t -.
Definition functions.c:2778
static int op_view_attachments(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Show MIME attachments - Implements index_function_t -.
Definition functions.c:3265
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:3162
static int op_main_change_folder(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Open a different folder - Implements index_function_t -.
Definition functions.c:1515
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:3859
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:2268
static int op_main_collapse_all(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Collapse/uncollapse all threads - Implements index_function_t -.
Definition functions.c:1581
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:2185
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:1997
static int op_autocrypt_acct_menu(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Manage autocrypt accounts - Implements index_function_t -.
Definition functions.c:3295
static int op_tag(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Tag the current entry - Implements index_function_t -.
Definition functions.c:3046
static int op_main_open_thread(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Open current thread - Implements index_function_t -.
Definition functions.c:1675
static int op_undelete(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Undelete the current entry - Implements index_function_t -.
Definition functions.c:3172
static int op_main_collapse_thread(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Collapse/uncollapse current thread - Implements index_function_t -.
Definition functions.c:1637
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:2142
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:1690
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:3683
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:2651
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:2351
static int op_undelete_thread(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Undelete all messages in thread - Implements index_function_t -.
Definition functions.c:3215
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:2460
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:2441
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:2387
static int op_main_change_group(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Open a different newsgroup - Implements index_function_t -.
Definition functions.c:3559
static int op_main_close_thread(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Collapse current thread - Implements index_function_t -.
Definition functions.c:1622
static int op_prev_entry(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Move to the previous entry - Implements index_function_t -.
Definition functions.c:2754
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:1185
static int op_main_modify_tags(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Modify (notmuch/imap) tags - Implements index_function_t -.
Definition functions.c:1859
#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:1434
bool mutt_link_threads(struct Email *parent, struct EmailArray *children, struct Mailbox *m)
Forcibly link threads together.
Definition thread.c:1835
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:1745
off_t mutt_set_vnum(struct Mailbox *m)
Set the virtual index number of all the messages in a mailbox.
Definition thread.c:1492
int mutt_aside_thread(struct Email *e, bool forwards, bool subthreads)
Find the next/previous (sub)thread.
Definition thread.c:1366
bool mutt_thread_can_collapse(struct Email *e)
Check whether a thread can be collapsed.
Definition thread.c:1905
struct HashTable * mutt_make_id_hash(struct Mailbox *m)
Create a Hash Table for Message-IDs.
Definition thread.c:1790
#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:364
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:809
static void update_thread_email(struct IndexPrivateData *priv, struct Email *email)
Focus a visible email in the current thread.
Definition functions.c:784
static const struct MenuFuncOp OpIndex[]
Functions for the Index Menu.
Definition functions.c:87
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:560
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:502
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:590
static const struct MenuFuncOp OpList[]
Functions for the List Dialog.
Definition functions.c:227
void index_init_keys(struct NeoMutt *n, struct SubMenu *sm_generic)
Initialise the Index Keybindings - Implements ::init_keys_api.
Definition functions.c:358
bool index_next_undeleted(struct MuttWindow *win_index)
Select the next undeleted Email (if possible)
Definition functions.c:466
struct MenuDefinition * index_get_menu_definition(void)
Get the Index Menu Definition.
Definition functions.c:4120
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:393
static const struct MenuOpSeq ListDefaultBindings[]
Key bindings for the List Dialog.
Definition functions.c:332
static const struct MenuOpSeq IndexDefaultBindings[]
Key bindings for the Index Menu.
Definition functions.c:241
static struct MuttThread * thread_target(struct Email *e, bool subthread)
Get the thread/subthread target for an email.
Definition functions.c:538
static bool prereq(struct IndexSharedData *shared, struct Menu *menu, CheckFlags checks)
Check the pre-requisites for a function.
Definition functions.c:3876
static const struct IndexFunction IndexFunctions[]
All the NeoMutt functions that the Index supports.
Definition functions.c:3925
ResolveMethod
How to advance the cursor.
Definition functions.c:348
@ RESOLVE_NEXT_SUBTHREAD
Next sibling sub-thread.
Definition functions.c:352
@ RESOLVE_NEXT_UNDELETED
Next undeleted email.
Definition functions.c:350
@ RESOLVE_NEXT_EMAIL
Next email, whatever its state.
Definition functions.c:349
@ RESOLVE_NEXT_THREAD
Next top-level thread.
Definition functions.c:351
static int op_main_next_new(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Definition functions.c:2064
Index functions.
GUI manage the main index (list of emails)
uint8_t CheckFlags
Definition lib.h:97
@ NT_INDEX_EMAIL
Email has changed.
Definition lib.h:81
CollapseMode
Action to perform on a Thread.
Definition lib.h:103
@ COLLAPSE_MODE_TOGGLE
Toggle collapsed state.
Definition lib.h:104
@ COLLAPSE_MODE_CLOSE
Collapse all threads.
Definition lib.h:105
@ COLLAPSE_MODE_OPEN
Open all threads.
Definition lib.h:106
@ CHECK_VISIBLE
Is the selected message visible in the index?
Definition lib.h:93
@ CHECK_NONE
No flags are set.
Definition lib.h:90
@ CHECK_READONLY
Is the mailbox readonly?
Definition lib.h:94
@ CHECK_MSGCOUNT
Are there any messages?
Definition lib.h:92
@ CHECK_IN_MAILBOX
Is there a mailbox open?
Definition lib.h:91
@ CHECK_ATTACH
Is the user in message-attach mode?
Definition lib.h:95
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:121
struct SubMenu * km_register_submenu(const struct MenuFuncOp functions[])
Register a submenu.
Definition init.c:87
struct MenuDefinition * km_register_menu(int menu, const char *name)
Register a menu.
Definition init.c:104
void km_menu_add_bindings(struct MenuDefinition *md, const struct MenuOpSeq bindings[])
Add Keybindings to a Menu.
Definition init.c:134
enum CommandResult km_bind(struct MenuDefinition *md, const char *key_str, int op, char *macro, char *desc, struct Buffer *err)
Set up a key binding.
Definition menu.c: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:179
int menu_get_index(struct Menu *menu)
Get the current selection in the Menu.
Definition menu.c:155
@ 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:169
@ MODULE_ID_INDEX
ModuleIndex, Index
Definition module_api.h:72
@ MODULE_ID_NNTP
ModuleNntp, Nntp
Definition module_api.h:81
void msgwin_clear_text(struct MuttWindow *win)
Clear the text in the Message Window.
Definition msgwin.c:554
Convenience wrapper for the library headers.
#define _(a)
Definition message.h:28
bool notify_send(struct Notify *notify, enum NotifyType event_type, int event_subtype, void *event_data)
Send out a notification message.
Definition notify.c:173
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition string.c:677
bool mutt_strn_equal(const char *a, const char *b, size_t num)
Check for equality of two strings (to a maximum), safely.
Definition string.c:429
size_t mutt_str_copy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition string.c:586
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition string.c:284
Many unsorted constants and some structs.
@ EVM_VIEW
View the message.
Definition mutt.h:76
@ EVM_EDIT
Edit the message.
Definition mutt.h:77
@ MUTT_UNDELETE
Messages to be un-deleted.
Definition mutt.h:95
@ MUTT_LIMIT
Messages in limited view.
Definition mutt.h:101
@ MUTT_UNTAG
Messages to be un-tagged.
Definition mutt.h:100
@ MUTT_READ
Messages that have been read.
Definition mutt.h:92
@ MUTT_PURGE
Messages to be purged (bypass trash)
Definition mutt.h:96
@ MUTT_TAG
Tagged messages.
Definition mutt.h:99
@ MUTT_FLAG
Flagged messages.
Definition mutt.h:98
@ MUTT_DELETE
Messages to be deleted.
Definition mutt.h:94
@ MUTT_NEW
New messages.
Definition mutt.h:89
#define PATH_MAX
Definition mutt.h:49
struct Mailbox * mutt_mailbox_next_unread(struct Mailbox *m_cur, struct Buffer *s)
Find next mailbox with unread mail.
struct Mailbox * mutt_mailbox_next(struct Mailbox *m_cur, struct Buffer *s)
Incoming folders completion routine.
bool mutt_mailbox_list(void)
Show a message with the list of mailboxes with new mail.
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:428
Some miscellaneous functions.
struct Email * mutt_get_virt_email(struct Mailbox *m, int vnum)
Get a virtual Email.
Definition mview.c:376
bool mutt_limit_current_thread(struct MailboxView *mv, struct Email *e)
Limit the email view to the current thread.
Definition mview.c:439
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:361
bool mview_has_limit(const struct MailboxView *mv)
Is a limit active?
Definition mview.c:397
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:1276
int mx_msg_close(struct Mailbox *m, struct Message **ptr)
Close a message.
Definition mx.c:1182
void mx_fastclose_mailbox(struct Mailbox *m, bool keep_account)
Free up memory associated with the Mailbox.
Definition mx.c:411
struct Mailbox * mx_mbox_find2(const char *path)
Find a Mailbox on an Account.
Definition mx.c:1615
struct Message * mx_msg_open(struct Mailbox *m, struct Email *e)
Return a stream pointer for a message.
Definition mx.c:1136
bool mx_tags_is_supported(struct Mailbox *m)
Return true if mailbox support tagging.
Definition mx.c:1313
int mx_tags_commit(struct Mailbox *m, struct Email *e, const char *tags)
Save tags to the Mailbox - Wrapper for MxOps::tags_commit()
Definition mx.c:1296
int mx_toggle_write(struct Mailbox *m)
Toggle the mailbox's readonly flag.
Definition mx.c:1821
enum MxStatus mx_mbox_sync(struct Mailbox *m)
Save changes to mailbox.
Definition mx.c:903
enum MxStatus mx_mbox_close(struct Mailbox *m)
Save changes and close mailbox.
Definition mx.c:595
API for mailboxes.
MxStatus
Return values from mbox_check(), mbox_check_stats(), mbox_sync(), and mbox_close()
Definition mxapi.h: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:663
@ 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:2215
int nntp_check_children(struct Mailbox *m, const char *msgid)
Fetch children of article with the Message-ID.
Definition nntp.c:2286
void nntp_mailbox(struct Mailbox *m, char *buf, size_t buflen)
Get first newsgroup with new messages.
Definition newsrc.c:1316
struct NntpMboxData * mutt_newsgroup_catchup(struct Mailbox *m, struct NntpAccountData *adata, char *group)
Catchup newsgroup.
Definition newsrc.c:1234
struct NntpAccountData * nntp_select_server(struct Mailbox *m, const char *server, bool leave_lock)
Open a connection to an NNTP server.
Definition newsrc.c:953
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:247
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:448
int external_pager(struct MailboxView *mv, struct Email *e, const char *command)
Display a message in an external program.
Definition message.c:297
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:462
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:529
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:1560
bool mutt_send_list_unsubscribe(struct Mailbox *m, struct Email *e)
Send a mailing-list unsubscription email.
Definition send.c:2985
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:2030
bool mutt_send_list_subscribe(struct Mailbox *m, struct Email *e)
Send a mailing-list subscription email.
Definition send.c:2956
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
struct SubMenu * sidebar_get_submenu(void)
Get the Sidebar SubMenu.
Definition functions.c:106
GUI display the mailboxes in a side panel.
#define ASSERT(COND)
Definition signal2.h:59
#define NONULL(x)
Definition string2.h:44
String manipulation buffer.
Definition buffer.h:36
size_t dsize
Length of data.
Definition buffer.h:39
char * data
Pointer to data.
Definition buffer.h:37
The envelope/body of an email.
Definition email.h:39
bool read
Email is read.
Definition email.h:50
bool visible
Is this message part of the view?
Definition email.h:121
struct Envelope * env
Envelope information.
Definition email.h:68
bool collapsed
Is this message part of a collapsed thread?
Definition email.h:120
SecurityFlags security
bit 0-10: flags, bit 11,12: application, bit 13: traditional pgp See: ncrypt/lib.h pgplib....
Definition email.h:43
struct Body * body
List of MIME parts.
Definition email.h:69
bool old
Email is seen, but unread.
Definition email.h:49
bool 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 * menu_index
Index menu definition.
Definition module_data.h:34
struct MenuDefinition * menu_list
Mailing-list action menu definition.
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 menu.h:77
Mapping between a function and an operation.
Definition menu.h:35
Mapping between an operation and a key sequence.
Definition menu.h:45
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 menu.h:65
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
@ MENU_LIST
Mailing-list actions.
Definition type.h:45