NeoMutt  2025-12-11-980-ge38c27
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
functions.c
Go to the documentation of this file.
1
24
30
31#include "config.h"
32#include <limits.h>
33#include <stdbool.h>
34#include <stdio.h>
35#include "mutt/lib.h"
36#include "config/lib.h"
37#include "email/lib.h"
38#include "core/lib.h"
39#include "alias/lib.h"
40#include "gui/lib.h"
41#include "mutt.h"
42#include "functions.h"
43#include "lib.h"
44#include "attach/lib.h"
45#include "browser/lib.h"
46#include "editor/lib.h"
47#include "history/lib.h"
48#include "hooks/lib.h"
49#include "imap/lib.h"
50#include "key/lib.h"
51#include "menu/lib.h"
52#include "mlist/lib.h"
53#include "ncrypt/lib.h"
54#include "nntp/lib.h"
55#include "pager/lib.h"
56#include "pattern/lib.h"
57#include "pop/lib.h"
58#include "progress/lib.h"
59#include "question/lib.h"
60#include "send/lib.h"
61#include "sidebar/lib.h"
62#include "external.h"
63#include "globals.h"
64#include "module_data.h"
65#include "mutt_mailbox.h"
66#include "muttlib.h"
67#include "mx.h"
68#include "nntp/mdata.h"
69#include "nntp/module_data.h"
70#include "private_data.h"
71#include "shared_data.h"
72#ifdef USE_AUTOCRYPT
73#include "autocrypt/lib.h"
74#endif
75#ifdef USE_NOTMUCH
76#include "notmuch/lib.h"
77#endif
78#ifdef ENABLE_NLS
79#include <libintl.h>
80#endif
81
82static int op_jump(struct IndexFunctionData *fdata, const struct KeyEvent *event);
83
84// clang-format off
88static const struct MenuFuncOp OpIndex[] = { /* map: index */
89 { "alias-dialog", OP_ALIAS_DIALOG },
90#ifdef USE_AUTOCRYPT
91 { "autocrypt-acct-menu", OP_AUTOCRYPT_ACCT_MENU },
92#endif
93 { "bounce-message", OP_BOUNCE_MESSAGE },
94 { "break-thread", OP_MAIN_BREAK_THREAD },
95 { "catchup", OP_CATCHUP },
96 { "change-folder", OP_MAIN_CHANGE_FOLDER },
97 { "change-folder-readonly", OP_MAIN_CHANGE_FOLDER_READONLY },
98 { "change-newsgroup", OP_MAIN_CHANGE_GROUP },
99 { "change-newsgroup-readonly", OP_MAIN_CHANGE_GROUP_READONLY },
100#ifdef USE_NOTMUCH
101 { "change-vfolder", OP_MAIN_CHANGE_VFOLDER },
102#endif
103 { "check-traditional-pgp", OP_CHECK_TRADITIONAL },
104 { "clear-flag", OP_MAIN_CLEAR_FLAG },
105 { "close-all-threads", OP_MAIN_CLOSE_ALL_THREADS },
106 { "close-thread", OP_MAIN_CLOSE_THREAD },
107 { "collapse-all", OP_MAIN_COLLAPSE_ALL },
108 { "collapse-thread", OP_MAIN_COLLAPSE_THREAD },
109 { "compose-to-sender", OP_COMPOSE_TO_SENDER },
110 { "copy-message", OP_COPY_MESSAGE },
111 { "create-alias", OP_CREATE_ALIAS },
112 { "decode-copy", OP_DECODE_COPY },
113 { "decode-save", OP_DECODE_SAVE },
114 { "decrypt-copy", OP_DECRYPT_COPY },
115 { "decrypt-save", OP_DECRYPT_SAVE },
116 { "delete-message", OP_DELETE },
117 { "delete-pattern", OP_MAIN_DELETE_PATTERN },
118 { "delete-subthread", OP_DELETE_SUBTHREAD },
119 { "delete-thread", OP_DELETE_THREAD },
120 { "display-address", OP_DISPLAY_ADDRESS },
121 { "display-message", OP_DISPLAY_MESSAGE },
122 { "display-toggle-weed", OP_DISPLAY_HEADERS },
123 { "edit", OP_EDIT_RAW_MESSAGE },
124 { "edit-label", OP_EDIT_LABEL },
125 { "edit-or-view-raw-message", OP_EDIT_OR_VIEW_RAW_MESSAGE },
126 { "edit-raw-message", OP_EDIT_RAW_MESSAGE },
127 { "edit-type", OP_ATTACH_EDIT_TYPE },
128#ifdef USE_NOTMUCH
129 { "entire-thread", OP_MAIN_ENTIRE_THREAD },
130#endif
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 { "forward-message", OP_FORWARD_MESSAGE },
136 { "forward-to-group", OP_FORWARD_TO_GROUP },
137 { "get-children", OP_GET_CHILDREN },
138 { "get-message", OP_GET_MESSAGE },
139 { "get-parent", OP_GET_PARENT },
140 { "group-chat-reply", OP_GROUP_CHAT_REPLY },
141 { "group-reply", OP_GROUP_REPLY },
142 { "imap-fetch-mail", OP_MAIN_IMAP_FETCH },
143 { "imap-logout-all", OP_MAIN_IMAP_LOGOUT_ALL },
144 { "limit", OP_MAIN_LIMIT },
145 { "limit-current-thread", OP_LIMIT_CURRENT_THREAD },
146 { "link-threads", OP_MAIN_LINK_THREADS },
147 { "list-action", OP_LIST_ACTION },
148 { "list-reply", OP_LIST_REPLY },
149 { "list-subscribe", OP_LIST_SUBSCRIBE },
150 { "list-unsubscribe", OP_LIST_UNSUBSCRIBE },
151 { "mail", OP_MAIL },
152 { "mail-key", OP_MAIL_KEY },
153 { "mailbox-list", OP_MAILBOX_LIST },
154 { "mark-message", OP_MARK_MSG },
155 { "modify-labels", OP_MAIN_MODIFY_TAGS },
156 { "modify-labels-then-hide", OP_MAIN_MODIFY_TAGS_THEN_HIDE },
157 { "modify-tags", OP_MAIN_MODIFY_TAGS },
158 { "modify-tags-then-hide", OP_MAIN_MODIFY_TAGS_THEN_HIDE },
159 { "next-new", OP_MAIN_NEXT_NEW },
160 { "next-new-then-unread", OP_MAIN_NEXT_NEW_THEN_UNREAD },
161 { "next-subthread", OP_MAIN_NEXT_SUBTHREAD },
162 { "next-thread", OP_MAIN_NEXT_THREAD },
163 { "next-undeleted", OP_MAIN_NEXT_UNDELETED },
164 { "next-unread", OP_MAIN_NEXT_UNREAD },
165 { "next-unread-mailbox", OP_MAIN_NEXT_UNREAD_MAILBOX },
166 { "open-all-threads", OP_MAIN_OPEN_ALL_THREADS },
167 { "open-thread", OP_MAIN_OPEN_THREAD },
168 { "parent-message", OP_MAIN_PARENT_MESSAGE },
169 { "pipe-entry", OP_PIPE },
170 { "pipe-message", OP_PIPE },
171 { "post-message", OP_POST },
172 { "previous-new", OP_MAIN_PREV_NEW },
173 { "previous-new-then-unread", OP_MAIN_PREV_NEW_THEN_UNREAD },
174 { "previous-subthread", OP_MAIN_PREV_SUBTHREAD },
175 { "previous-thread", OP_MAIN_PREV_THREAD },
176 { "previous-undeleted", OP_MAIN_PREV_UNDELETED },
177 { "previous-unread", OP_MAIN_PREV_UNREAD },
178 { "previous-unread-mailbox", OP_MAIN_PREV_UNREAD_MAILBOX },
179 { "print-message", OP_PRINT },
180 { "purge-message", OP_PURGE_MESSAGE },
181 { "purge-thread", OP_PURGE_THREAD },
182 { "quasi-delete", OP_MAIN_QUASI_DELETE },
183 { "query", OP_QUERY },
184 { "read-subthread", OP_MAIN_READ_SUBTHREAD },
185 { "read-thread", OP_MAIN_READ_THREAD },
186 { "recall-message", OP_RECALL_MESSAGE },
187 { "reconstruct-thread", OP_RECONSTRUCT_THREAD },
188 { "reply", OP_REPLY },
189 { "resend-message", OP_RESEND },
190 { "root-message", OP_MAIN_ROOT_MESSAGE },
191 { "save-message", OP_SAVE },
192 { "set-flag", OP_MAIN_SET_FLAG },
193 { "show-limit", OP_MAIN_SHOW_LIMIT },
194 { "sort-mailbox", OP_SORT },
195 { "sort-reverse", OP_SORT_REVERSE },
196 { "sync-mailbox", OP_MAIN_SYNC_FOLDER },
197 { "tag-pattern", OP_MAIN_TAG_PATTERN },
198 { "tag-subthread", OP_TAG_SUBTHREAD },
199 { "tag-thread", OP_TAG_THREAD },
200 { "toggle-new", OP_TOGGLE_NEW },
201 { "toggle-read", OP_TOGGLE_READ },
202 { "toggle-write", OP_TOGGLE_WRITE },
203 { "undelete-message", OP_UNDELETE },
204 { "undelete-pattern", OP_MAIN_UNDELETE_PATTERN },
205 { "undelete-subthread", OP_UNDELETE_SUBTHREAD },
206 { "undelete-thread", OP_UNDELETE_THREAD },
207 { "untag-pattern", OP_MAIN_UNTAG_PATTERN },
208#ifdef USE_NOTMUCH
209 { "vfolder-from-query", OP_MAIN_VFOLDER_FROM_QUERY },
210 { "vfolder-from-query-readonly", OP_MAIN_VFOLDER_FROM_QUERY_READONLY },
211 { "vfolder-window-backward", OP_MAIN_WINDOWED_VFOLDER_BACKWARD },
212 { "vfolder-window-forward", OP_MAIN_WINDOWED_VFOLDER_FORWARD },
213 { "vfolder-window-reset", OP_MAIN_WINDOWED_VFOLDER_RESET },
214#endif
215 { "view-attachments", OP_VIEW_ATTACHMENTS },
216 { "view-raw-message", OP_VIEW_RAW_MESSAGE },
217 // Deprecated
218 { "buffy-list", OP_MAILBOX_LIST, MFF_DEPRECATED },
219 { NULL, 0 },
220};
221
225static const struct MenuOpSeq IndexDefaultBindings[] = { /* map: index */
226 { OP_ATTACH_EDIT_TYPE, "\005" }, // <Ctrl-E>
227#ifdef USE_AUTOCRYPT
228 { OP_AUTOCRYPT_ACCT_MENU, "A" },
229#endif
230 { OP_BOUNCE_MESSAGE, "b" },
231 { OP_CHECK_TRADITIONAL, "\033P" }, // <Alt-P>
232 { OP_COPY_MESSAGE, "C" },
233 { OP_CREATE_ALIAS, "a" },
234 { OP_DECODE_COPY, "\033C" }, // <Alt-C>
235 { OP_DECODE_SAVE, "\033s" }, // <Alt-s>
236 { OP_DELETE, "d" },
237 { OP_DELETE_SUBTHREAD, "\033d" }, // <Alt-d>
238 { OP_DELETE_THREAD, "\004" }, // <Ctrl-D>
239 { OP_DISPLAY_ADDRESS, "@" },
240 { OP_DISPLAY_HEADERS, "h" },
241 { OP_DISPLAY_MESSAGE, " " }, // <Space>
242 { OP_DISPLAY_MESSAGE, "<keypadenter>" },
243 { OP_DISPLAY_MESSAGE, "\n" }, // <Enter>
244 { OP_DISPLAY_MESSAGE, "\r" }, // <Return>
245 { OP_EDIT_LABEL, "Y" },
246 { OP_EDIT_OR_VIEW_RAW_MESSAGE, "e" },
247 { OP_EXIT, "x" },
248 { OP_EXTRACT_KEYS, "\013" }, // <Ctrl-K>
249 { OP_FLAG_MESSAGE, "F" },
250 { OP_FORGET_PASSPHRASE, "\006" }, // <Ctrl-F>
251 { OP_FORWARD_MESSAGE, "f" },
252 { OP_GROUP_REPLY, "g" },
253 { OP_LIST_ACTION, "\033L" }, // <Alt-L>
254 { OP_LIST_REPLY, "L" },
255 { OP_MAIL, "m" },
256 { OP_MAILBOX_LIST, "." },
257 { OP_MAIL_KEY, "\033k" }, // <Alt-k>
258 { OP_MAIN_BREAK_THREAD, "#" },
259 { OP_MAIN_CHANGE_FOLDER, "c" },
260 { OP_MAIN_CHANGE_FOLDER_READONLY, "\033c" }, // <Alt-c>
261 { OP_MAIN_CHANGE_GROUP, "i" },
262 { OP_MAIN_CHANGE_GROUP_READONLY, "\033i" }, // <Alt-i>
263 { OP_MAIN_CLEAR_FLAG, "W" },
264 { OP_MAIN_COLLAPSE_ALL, "\033V" }, // <Alt-V>
265 { OP_MAIN_COLLAPSE_THREAD, "\033v" }, // <Alt-v>
266 { OP_MAIN_DELETE_PATTERN, "D" },
267 { OP_MAIN_FETCH_MAIL, "G" },
268 { OP_MAIN_LIMIT, "l" },
269 { OP_MAIN_LINK_THREADS, "&" },
270 { OP_MAIN_NEXT_NEW_THEN_UNREAD, "\t" }, // <Tab>
271 { OP_MAIN_NEXT_SUBTHREAD, "\033n" }, // <Alt-n>
272 { OP_MAIN_NEXT_THREAD, "\016" }, // <Ctrl-N>
273 { OP_MAIN_NEXT_UNDELETED, "<down>" },
274 { OP_MAIN_NEXT_UNDELETED, "j" },
275 { OP_MAIN_PARENT_MESSAGE, "P" },
276 { OP_MAIN_PREV_NEW_THEN_UNREAD, "\033\t" }, // <Alt-Tab>
277 { OP_MAIN_PREV_SUBTHREAD, "\033p" }, // <Alt-p>
278 { OP_MAIN_PREV_THREAD, "\020" }, // <Ctrl-P>
279 { OP_MAIN_PREV_UNDELETED, "<up>" },
280 { OP_MAIN_PREV_UNDELETED, "k" },
281 { OP_MAIN_READ_SUBTHREAD, "\033r" }, // <Alt-r>
282 { OP_MAIN_READ_THREAD, "\022" }, // <Ctrl-R>
283 { OP_MAIN_SET_FLAG, "w" },
284 { OP_MAIN_SHOW_LIMIT, "\033l" }, // <Alt-l>
285 { OP_MAIN_SYNC_FOLDER, "$" },
286 { OP_MAIN_TAG_PATTERN, "T" },
287 { OP_MAIN_UNDELETE_PATTERN, "U" },
288 { OP_MAIN_UNTAG_PATTERN, "\024" }, // <Ctrl-T>
289 { OP_MARK_MSG, "~" },
290 { OP_NEXT_ENTRY, "J" },
291 { OP_PIPE, "|" },
292 { OP_PREV_ENTRY, "K" },
293 { OP_PRINT, "p" },
294 { OP_QUERY, "Q" },
295 { OP_QUIT, "q" },
296 { OP_RECALL_MESSAGE, "R" },
297 { OP_REPLY, "r" },
298 { OP_RESEND, "\033e" }, // <Alt-e>
299 { OP_SAVE, "s" },
300 { OP_SHOW_LOG_MESSAGES, "M" },
301 { OP_SORT, "o" },
302 { OP_SORT_REVERSE, "O" },
303 { OP_TAG_THREAD, "\033t" }, // <Alt-t>
304 { OP_TOGGLE_NEW, "N" },
305 { OP_TOGGLE_WRITE, "%" },
306 { OP_UNDELETE, "u" },
307 { OP_UNDELETE_SUBTHREAD, "\033u" }, // <Alt-u>
308 { OP_UNDELETE_THREAD, "\025" }, // <Ctrl-U>
309 { OP_VIEW_ATTACHMENTS, "v" },
310 { 0, NULL },
311};
312
323
327void index_init_keys(struct NeoMutt *n, struct SubMenu *sm_generic)
328{
329 struct MenuDefinition *md = NULL;
330 struct SubMenu *sm_index = NULL;
331 struct SubMenu *sm_sidebar = sidebar_get_submenu();
332
333 sm_index = km_register_submenu(OpIndex);
334 md = km_register_menu(MENU_INDEX, "index");
335 km_menu_add_submenu(md, sm_index);
336 km_menu_add_submenu(md, sm_sidebar);
337 km_menu_add_submenu(md, sm_generic);
339
341 ASSERT(mod_data);
342 mod_data->md_index = md;
343 mod_data->sm_index = sm_index;
344}
345
351{
353 ASSERT(mod_data);
354
355 return mod_data->sm_index;
356}
357
366static bool resolve_email(struct IndexPrivateData *priv, struct IndexSharedData *shared,
367 enum ResolveMethod rm, int count)
368{
369 if (!priv || !priv->menu || !shared || !shared->mailbox || !shared->email)
370 return false;
371
372 const bool c_resolve = cs_subset_bool(shared->sub, "resolve");
373 if (!c_resolve)
374 return false;
375
376 count = MAX(count, 1);
377 int index = menu_get_index(priv->menu);
378
379 switch (rm)
380 {
382 index = index + count;
383 break;
384
386 {
387 const bool uncollapse = mutt_using_threads() && !window_is_focused(priv->win_index);
388 for (int i = 0; i < count; i++)
389 {
390 int next = find_next_undeleted(shared->mailbox_view, index, uncollapse);
391 if (next < 0)
392 break;
393 index = next;
394 }
395 break;
396 }
397
399 for (int i = 0; i < count; i++)
400 {
401 struct Email *e = mutt_get_virt_email(shared->mailbox, index);
402 if (!e)
403 break;
404 int next = mutt_next_thread(e);
405 if (next < 0)
406 break;
407 index = next;
408 }
409 break;
410
412 for (int i = 0; i < count; i++)
413 {
414 struct Email *e = mutt_get_virt_email(shared->mailbox, index);
415 if (!e)
416 break;
417 int next = mutt_next_subthread(e);
418 if (next < 0)
419 break;
420 index = next;
421 }
422 break;
423 }
424
425 if (index < 0)
426 index = 0;
427 if (index >= shared->mailbox->vcount)
428 index = shared->mailbox->vcount - 1;
429
430 menu_set_index(priv->menu, index);
431 return true;
432}
433
439bool index_next_undeleted(struct MuttWindow *win_index)
440{
441 struct MuttWindow *dlg = dialog_find(win_index);
442 if (!dlg)
443 return false;
444
445 struct Menu *menu = win_index->wdata;
446 struct IndexSharedData *shared = dlg->wdata;
447 if (!shared)
448 return false;
449
450 struct IndexPrivateData *priv = win_index->parent->wdata;
451 const bool uncollapse = mutt_using_threads() && !window_is_focused(priv->win_index);
452
453 int index = find_next_undeleted(shared->mailbox_view, menu_get_index(menu), uncollapse);
454 if ((index < 0) || (index >= shared->mailbox->vcount))
455 {
456 // Selection failed
458 return false;
459 }
460
461 menu_set_index(menu, index);
462 return true;
463}
464
475static int ea_add_selection(struct EmailArray *ea, struct MailboxView *mv,
476 struct Email *e, bool use_tagged, int count)
477{
478 if (!ea)
479 return -1;
480
481 if (use_tagged)
482 return ea_add_tagged(ea, mv, e, true);
483
484 if (!mv || !mv->mailbox || !e)
485 return -1;
486
487 const int index = e->vnum;
488 if ((index < 0) || (index >= mv->mailbox->vcount))
489 return -1;
490
491 int n = (count > 1) ? count : 1;
492 if ((index + n) > mv->mailbox->vcount)
493 n = mv->mailbox->vcount - index;
494
495 for (int i = 0; i < n; i++)
496 {
497 struct Email *sel = mutt_get_virt_email(mv->mailbox, index + i);
498 if (sel)
499 ea_add_tagged(ea, mv, sel, false);
500 }
501
502 return ARRAY_SIZE(ea);
503}
504
511static struct MuttThread *thread_target(struct Email *e, bool subthread)
512{
513 if (!e || !e->thread)
514 return NULL;
515
516 struct MuttThread *thread = e->thread;
517 if (!subthread)
518 {
519 while (thread->parent)
520 thread = thread->parent;
521 }
522
523 return thread;
524}
525
533static bool ea_contains_thread_target(struct EmailArray *ea, struct Email *e, bool subthread)
534{
535 if (!ea || !e)
536 return false;
537
538 struct MuttThread *target = thread_target(e, subthread);
539 if (!target)
540 return false;
541
542 struct Email **ep = NULL;
543 ARRAY_FOREACH(ep, ea)
544 {
545 if (thread_target(*ep, subthread) == target)
546 return true;
547 }
548
549 return false;
550}
551
563static int ea_add_selection_threads(struct EmailArray *ea,
564 struct MailboxView *mv, struct Email *e,
565 bool use_tagged, bool subthread, int count)
566{
567 if (!ea)
568 return -1;
569
570 if (!use_tagged)
571 {
572 if (!mv || !mv->mailbox || !e)
573 return -1;
574
575 const int index = e->vnum;
576 if ((index < 0) || (index >= mv->mailbox->vcount))
577 return -1;
578
579 const int n = (count > 1) ? count : 1;
580 for (int i = index; (i < mv->mailbox->vcount) && (ARRAY_SIZE(ea) < n); i++)
581 {
582 struct Email *sel = mutt_get_virt_email(mv->mailbox, i);
583 if (!sel || ea_contains_thread_target(ea, sel, subthread))
584 continue;
585
586 ARRAY_ADD(ea, sel);
587 }
588 return ARRAY_SIZE(ea);
589 }
590
591 if (!mv || !mv->mailbox || !mv->mailbox->emails)
592 return -1;
593
594 struct Mailbox *m = mv->mailbox;
595 for (int i = 0; i < m->msg_count; i++)
596 {
597 struct Email *et = m->emails[i];
598 if (!et)
599 break;
600 if (!message_is_tagged(et))
601 continue;
602
603 if (!ea_contains_thread_target(ea, et, subthread))
604 ARRAY_ADD(ea, et);
605 }
606
607 return ARRAY_SIZE(ea);
608}
609
610// -----------------------------------------------------------------------------
611
615static int op_alias_dialog(struct IndexFunctionData *fdata, const struct KeyEvent *event)
616{
617 struct IndexSharedData *shared = fdata->shared;
618 alias_dialog(shared->mailbox, shared->sub);
619 return FR_SUCCESS;
620}
621
625static int op_attach_edit_type(struct IndexFunctionData *fdata, const struct KeyEvent *event)
626{
627 struct IndexSharedData *shared = fdata->shared;
628 struct IndexPrivateData *priv = fdata->priv;
629 if (!shared->email)
630 return FR_NO_ACTION;
632
634 return FR_SUCCESS;
635}
636
640static int op_bounce_message(struct IndexFunctionData *fdata, const struct KeyEvent *event)
641{
642 struct IndexSharedData *shared = fdata->shared;
643 struct IndexPrivateData *priv = fdata->priv;
644 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
645 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
646 index_bounce_message(shared->mailbox, &ea);
647 ARRAY_FREE(&ea);
648
649 return FR_SUCCESS;
650}
651
655static int op_check_traditional(struct IndexFunctionData *fdata, const struct KeyEvent *event)
656{
657 struct IndexSharedData *shared = fdata->shared;
658 struct IndexPrivateData *priv = fdata->priv;
660 return FR_NOT_IMPL;
661 if (!shared->email)
662 return FR_NO_ACTION;
663
665 {
666 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
667 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
668 if (mutt_check_traditional_pgp(shared->mailbox, &ea))
670 ARRAY_FREE(&ea);
671 }
672
673 return FR_SUCCESS;
674}
675
679static int op_compose_to_sender(struct IndexFunctionData *fdata, const struct KeyEvent *event)
680{
681 struct IndexSharedData *shared = fdata->shared;
682 struct IndexPrivateData *priv = fdata->priv;
683 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
684 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
685 int rc = mutt_send_message(SEND_TO_SENDER, NULL, NULL, shared->mailbox, &ea,
686 shared->sub);
687 ARRAY_FREE(&ea);
689
690 return (rc == -1) ? FR_ERROR : FR_SUCCESS;
691}
692
696static int op_create_alias(struct IndexFunctionData *fdata, const struct KeyEvent *event)
697{
698 struct IndexSharedData *shared = fdata->shared;
699 struct IndexPrivateData *priv = fdata->priv;
700 struct AddressList *al = NULL;
701 if (shared->email && shared->email->env)
702 al = mutt_get_address(shared->email->env, NULL);
703 alias_create(al, shared->sub);
705
706 return FR_SUCCESS;
707}
708
716static int op_delete(struct IndexFunctionData *fdata, const struct KeyEvent *event)
717{
718 struct IndexSharedData *shared = fdata->shared;
719 struct IndexPrivateData *priv = fdata->priv;
720 /* L10N: CHECK_ACL */
721 if (!check_acl(shared->mailbox, MUTT_ACL_DELETE, _("Can't delete message")))
722 return FR_ERROR;
723
724 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
725 ea_add_selection(&ea, shared->mailbox_view, shared->email, priv->tag_prefix,
726 event->count);
727 if (ARRAY_EMPTY(&ea))
728 {
729 ARRAY_FREE(&ea);
730 return FR_NO_ACTION;
731 }
732
733 mutt_emails_set_flag(shared->mailbox, &ea, MUTT_DELETE, true);
734 mutt_emails_set_flag(shared->mailbox, &ea, MUTT_PURGE, (event->op == OP_PURGE_MESSAGE));
735 const bool c_delete_untag = cs_subset_bool(shared->sub, "delete_untag");
736 if (c_delete_untag)
737 mutt_emails_set_flag(shared->mailbox, &ea, MUTT_TAG, false);
738 ARRAY_FREE(&ea);
739
740 if (priv->tag_prefix)
741 {
743 }
744 else
745 {
746 resolve_email(priv, shared, RESOLVE_NEXT_UNDELETED, 1);
747 }
748
749 return FR_SUCCESS;
750}
751
757static void update_thread_email(struct IndexPrivateData *priv, struct Email *email)
758{
759 if (!priv || !priv->menu || !email)
760 return;
761
762 int index = email->vnum;
763 if (index < 0)
764 {
765 struct MuttThread *thread = thread_target(email, false);
766 struct Email *e = find_virtual(thread, false);
767 if (e)
768 index = e->vnum;
769 }
770
771 if (index >= 0)
772 menu_set_index(priv->menu, index);
773}
774
783 struct EmailArray *ea, enum CollapseMode mode)
784{
785 struct IndexSharedData *shared = fdata->shared;
786 struct IndexPrivateData *priv = fdata->priv;
787 if (!mutt_using_threads())
788 {
789 mutt_warning(_("Threading is not enabled"));
790 return FR_ERROR;
791 }
792
793 if (!ea || ARRAY_EMPTY(ea))
794 return FR_NO_ACTION;
795
796 bool changed = false;
797 bool blocked = false;
798 struct Email **ep = NULL;
799 ARRAY_FOREACH(ep, ea)
800 {
801 struct Email *e = *ep;
802 if (!e)
803 continue;
804
805 switch (mode)
806 {
808 if (!e->collapsed)
809 continue;
811 changed = true;
812 break;
814 if (e->collapsed)
815 continue;
817 {
818 blocked = true;
819 continue;
820 }
822 changed = true;
823 break;
825 if (e->collapsed)
826 {
828 changed = true;
829 }
830 else if (mutt_thread_can_collapse(e))
831 {
833 changed = true;
834 }
835 else
836 {
837 blocked = true;
838 }
839 break;
840 }
841 }
842
843 if (!changed)
844 {
845 if (blocked)
846 {
847 mutt_warning(_("Thread contains unread or flagged messages"));
848 return FR_ERROR;
849 }
850 return FR_NO_ACTION;
851 }
852
853 mutt_set_vnum(shared->mailbox);
854 update_thread_email(priv, shared->email);
856 notify_send(shared->notify, NT_INDEX, NT_INDEX_EMAIL, NULL);
857 return FR_SUCCESS;
858}
859
868static int op_delete_thread(struct IndexFunctionData *fdata, const struct KeyEvent *event)
869{
870 struct IndexSharedData *shared = fdata->shared;
871 struct IndexPrivateData *priv = fdata->priv;
872 /* L10N: CHECK_ACL */
873 /* L10N: Due to the implementation details we do not know whether we
874 delete zero, 1, 12, ... messages. So in English we use
875 "messages". Your language might have other means to express this. */
876 if (!check_acl(shared->mailbox, MUTT_ACL_DELETE, _("Can't delete messages")))
877 return FR_ERROR;
878 if (!shared->email)
879 return FR_NO_ACTION;
880
881 const int op = event->op;
882 const bool subthread = (op == OP_DELETE_SUBTHREAD);
883 int rc = 0;
884 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
885 ea_add_selection_threads(&ea, shared->mailbox_view, shared->email,
886 priv->tag_prefix, subthread, event->count);
887
888 struct Email **ep = NULL;
889 ARRAY_FOREACH(ep, &ea)
890 {
891 rc = mutt_thread_set_flag(shared->mailbox, *ep, MUTT_DELETE, true, subthread);
892 if (rc == -1)
893 break;
894
895 if (op == OP_PURGE_THREAD)
896 {
897 rc = mutt_thread_set_flag(shared->mailbox, *ep, MUTT_PURGE, true, subthread);
898 if (rc == -1)
899 break;
900 }
901
902 const bool c_delete_untag = cs_subset_bool(shared->sub, "delete_untag");
903 if (c_delete_untag)
904 mutt_thread_set_flag(shared->mailbox, *ep, MUTT_TAG, false, subthread);
905 }
906 ARRAY_FREE(&ea);
907
908 if (rc == -1)
909 return FR_ERROR;
910
911 if (priv->tag_prefix)
912 {
914 return FR_SUCCESS;
915 }
916
917 resolve_email(priv, shared, RESOLVE_NEXT_UNDELETED, 1);
919 return FR_SUCCESS;
920}
921
925static int op_display_address(struct IndexFunctionData *fdata, const struct KeyEvent *event)
926{
927 struct IndexSharedData *shared = fdata->shared;
928 if (!shared->email)
929 return FR_NO_ACTION;
931
932 return FR_SUCCESS;
933}
934
943static int op_display_message(struct IndexFunctionData *fdata, const struct KeyEvent *event)
944{
945 struct IndexSharedData *shared = fdata->shared;
946 struct IndexPrivateData *priv = fdata->priv;
947 if (!shared->email)
948 return FR_NO_ACTION;
949
950 if (event->count > 0)
951 return op_jump(fdata, event);
952
953 int op = event->op;
954
955 if (op == OP_DISPLAY_MESSAGE)
956 {
957 if (!window_is_focused(priv->win_index))
958 return FR_SUCCESS;
959 }
960
962
963 /* toggle the weeding of headers so that a user can press the key
964 * again while reading the message. */
965 if (op == OP_DISPLAY_HEADERS)
966 {
967 bool_str_toggle(shared->sub, "weed", NULL);
969 if (!window_is_focused(priv->win_index))
970 return FR_SUCCESS;
971 }
972
973 OptNeedResort = false;
974
976 {
979 const bool c_uncollapse_jump = cs_subset_bool(shared->sub, "uncollapse_jump");
980 if (c_uncollapse_jump)
982 }
983
984 const bool c_pgp_auto_decode = cs_subset_bool(shared->sub, "pgp_auto_decode");
985 if (c_pgp_auto_decode &&
987 {
988 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
989 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
990 if (mutt_check_traditional_pgp(shared->mailbox, &ea))
992 ARRAY_FREE(&ea);
993 }
994 const int index = menu_get_index(priv->menu);
996
997 const char *const c_pager = pager_get_pager(fdata->n->sub);
998 if (c_pager)
999 {
1000 op = external_pager(shared->mailbox_view, shared->email, c_pager);
1001 }
1002 else
1003 {
1004 op = mutt_display_message(priv->win_index, shared);
1005 }
1006
1008 if (op < OP_NULL)
1009 {
1010 OptNeedResort = false;
1011 return FR_ERROR;
1012 }
1013
1014 if (shared->mailbox)
1015 {
1017 shared->mailbox->msg_count, shared);
1018 }
1019
1020 return op;
1021}
1022
1026static int op_edit_label(struct IndexFunctionData *fdata, const struct KeyEvent *event)
1027{
1028 struct IndexSharedData *shared = fdata->shared;
1029 struct IndexPrivateData *priv = fdata->priv;
1030 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
1031 ea_add_selection(&ea, shared->mailbox_view, shared->email, priv->tag_prefix,
1032 event->count);
1033 if (ARRAY_EMPTY(&ea))
1034 {
1035 ARRAY_FREE(&ea);
1036 return FR_NO_ACTION;
1037 }
1038 const int num = ARRAY_SIZE(&ea);
1039 int num_changed = mutt_label_message(shared->mailbox_view, &ea);
1040 ARRAY_FREE(&ea);
1041
1042 if (num_changed > 0)
1043 {
1044 shared->mailbox->changed = true;
1046 /* L10N: This is displayed when the x-label on one or more
1047 messages is edited. */
1048 mutt_message(ngettext("%d label changed", "%d labels changed", num_changed), num_changed);
1049
1050 if (!priv->tag_prefix)
1051 resolve_email(priv, shared, RESOLVE_NEXT_UNDELETED, num);
1052 return FR_SUCCESS;
1053 }
1054
1055 /* L10N: This is displayed when editing an x-label, but no messages
1056 were updated. Possibly due to canceling at the prompt or if the new
1057 label is the same as the old label. */
1058 mutt_message(_("No labels changed"));
1059 return FR_NO_ACTION;
1060}
1061
1070static int op_edit_raw_message(struct IndexFunctionData *fdata, const struct KeyEvent *event)
1071{
1072 struct IndexSharedData *shared = fdata->shared;
1073 struct IndexPrivateData *priv = fdata->priv;
1074 /* TODO split this into 3 cases? */
1075 bool edit;
1076 const int op = event->op;
1077 if (op == OP_EDIT_RAW_MESSAGE)
1078 {
1079 /* L10N: CHECK_ACL */
1080 if (!check_acl(shared->mailbox, MUTT_ACL_INSERT, _("Can't edit message")))
1081 return FR_ERROR;
1082 edit = true;
1083 }
1084 else if (op == OP_EDIT_OR_VIEW_RAW_MESSAGE)
1085 {
1087 }
1088 else
1089 {
1090 edit = false;
1091 }
1092
1093 if (!shared->email)
1094 return FR_NO_ACTION;
1095 const bool c_pgp_auto_decode = cs_subset_bool(shared->sub, "pgp_auto_decode");
1096 if (c_pgp_auto_decode &&
1098 {
1099 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
1100 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
1101 if (mutt_check_traditional_pgp(shared->mailbox, &ea))
1103 ARRAY_FREE(&ea);
1104 }
1105 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
1106 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
1107 mutt_ev_message(shared->mailbox, &ea, edit ? EVM_EDIT : EVM_VIEW);
1108 ARRAY_FREE(&ea);
1110
1111 return FR_SUCCESS;
1112}
1113
1117static int op_end_cond(struct IndexFunctionData *fdata, const struct KeyEvent *event)
1118{
1119 return FR_SUCCESS;
1120}
1121
1125static int op_exit(struct IndexFunctionData *fdata, const struct KeyEvent *event)
1126{
1127 struct IndexSharedData *shared = fdata->shared;
1128 if (shared->attach_msg)
1129 return FR_DONE;
1130
1131 if (query_quadoption(_("Exit NeoMutt without saving?"), shared->sub, "quit") == MUTT_YES)
1132 {
1133 if (shared->mailbox_view)
1134 {
1135 mx_fastclose_mailbox(shared->mailbox, false);
1136 mview_free(&shared->mailbox_view);
1137 }
1138 return FR_DONE;
1139 }
1140
1141 return FR_NO_ACTION;
1142}
1143
1147static int op_extract_keys(struct IndexFunctionData *fdata, const struct KeyEvent *event)
1148{
1149 struct IndexSharedData *shared = fdata->shared;
1150 struct IndexPrivateData *priv = fdata->priv;
1151 if (!WithCrypto)
1152 return FR_NOT_IMPL;
1153 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
1154 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
1156 ARRAY_FREE(&ea);
1158
1159 return FR_SUCCESS;
1160}
1161
1165static int op_flag_message(struct IndexFunctionData *fdata, const struct KeyEvent *event)
1166{
1167 struct IndexSharedData *shared = fdata->shared;
1168 struct IndexPrivateData *priv = fdata->priv;
1169 /* L10N: CHECK_ACL */
1170 if (!check_acl(shared->mailbox, MUTT_ACL_WRITE, _("Can't flag message")))
1171 return FR_ERROR;
1172
1173 struct Mailbox *m = shared->mailbox;
1174 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
1175 ea_add_selection(&ea, shared->mailbox_view, shared->email, priv->tag_prefix,
1176 event->count);
1177 if (ARRAY_EMPTY(&ea))
1178 {
1179 ARRAY_FREE(&ea);
1180 return FR_NO_ACTION;
1181 }
1182 const int num = ARRAY_SIZE(&ea);
1183
1184 struct Email **ep = NULL;
1185 ARRAY_FOREACH(ep, &ea)
1186 mutt_set_flag(m, *ep, MUTT_FLAG, !(*ep)->flagged, true);
1187 ARRAY_FREE(&ea);
1188
1189 if (priv->tag_prefix)
1190 {
1192 }
1193 else
1194 {
1195 resolve_email(priv, shared, RESOLVE_NEXT_UNDELETED, num);
1196 if (num > 1)
1198 }
1199
1200 return FR_SUCCESS;
1201}
1202
1206static int op_forward_message(struct IndexFunctionData *fdata, const struct KeyEvent *event)
1207{
1208 struct IndexSharedData *shared = fdata->shared;
1209 struct IndexPrivateData *priv = fdata->priv;
1210 if (!shared->email)
1211 return FR_NO_ACTION;
1212 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
1213 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
1214 const bool c_pgp_auto_decode = cs_subset_bool(shared->sub, "pgp_auto_decode");
1215 if (c_pgp_auto_decode &&
1216 (priv->tag_prefix || !(shared->email->security & PGP_TRADITIONAL_CHECKED)))
1217 {
1218 if (mutt_check_traditional_pgp(shared->mailbox, &ea))
1220 }
1221 int rc = mutt_send_message(SEND_FORWARD, NULL, NULL, shared->mailbox, &ea,
1222 shared->sub);
1223 ARRAY_FREE(&ea);
1225
1226 return (rc == -1) ? FR_ERROR : FR_SUCCESS;
1227}
1228
1236static int op_group_reply(struct IndexFunctionData *fdata, const struct KeyEvent *event)
1237{
1238 struct IndexSharedData *shared = fdata->shared;
1239 struct IndexPrivateData *priv = fdata->priv;
1240 SendFlags replyflags = SEND_REPLY;
1241 if (event->op == OP_GROUP_REPLY)
1242 replyflags |= SEND_GROUP_REPLY;
1243 else
1244 replyflags |= SEND_GROUP_CHAT_REPLY;
1245 if (!shared->email)
1246 return FR_NO_ACTION;
1247 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
1248 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
1249 const bool c_pgp_auto_decode = cs_subset_bool(shared->sub, "pgp_auto_decode");
1250 if (c_pgp_auto_decode &&
1251 (priv->tag_prefix || !(shared->email->security & PGP_TRADITIONAL_CHECKED)))
1252 {
1253 if (mutt_check_traditional_pgp(shared->mailbox, &ea))
1255 }
1256 int rc = mutt_send_message(replyflags, NULL, NULL, shared->mailbox, &ea,
1257 shared->sub);
1258 ARRAY_FREE(&ea);
1260
1261 return (rc == -1) ? FR_ERROR : FR_SUCCESS;
1262}
1263
1267static int op_jump(struct IndexFunctionData *fdata, const struct KeyEvent *event)
1268{
1269 struct IndexSharedData *shared = fdata->shared;
1270 struct IndexPrivateData *priv = fdata->priv;
1271 int rc = FR_ERROR;
1272 struct Buffer *buf = buf_pool_get();
1273
1274 int num = event->count;
1275 if (num == 0)
1276 {
1277 if ((mw_get_field(_("Jump to message: "), buf, MUTT_COMP_NONE, HC_OTHER, NULL, NULL) != 0) ||
1278 buf_is_empty(buf))
1279 {
1280 mutt_message(_("Nothing to do"));
1281 rc = FR_NO_ACTION;
1282 goto done;
1283 }
1284
1285 if (!mutt_str_atoi_full(buf_string(buf), &num))
1286 {
1287 mutt_warning(_("Argument must be a message number"));
1288 goto done;
1289 }
1290 }
1291
1292 if ((num < 1) || (num > shared->mailbox->msg_count))
1293 {
1294 mutt_warning(_("Invalid message number"));
1295 }
1296 else if (!shared->mailbox->emails[num - 1] ||
1297 !shared->mailbox->emails[num - 1]->visible)
1298 {
1299 mutt_warning(_("That message is not visible"));
1300 }
1301 else
1302 {
1303 struct Email *e = shared->mailbox->emails[num - 1];
1304
1305 if (mutt_messages_in_thread(shared->mailbox, e, MIT_POSITION) > 1)
1306 {
1308 mutt_set_vnum(shared->mailbox);
1309 }
1310 menu_set_index(priv->menu, e->vnum);
1311 rc = FR_SUCCESS;
1312 }
1313
1314done:
1315 buf_pool_release(&buf);
1316 return rc;
1317}
1318
1322static int op_list_action(struct IndexFunctionData *fdata, const struct KeyEvent *event)
1323{
1324 struct IndexSharedData *shared = fdata->shared;
1325 struct IndexPrivateData *priv = fdata->priv;
1326
1329 return FR_SUCCESS;
1330}
1331
1335static int op_list_reply(struct IndexFunctionData *fdata, const struct KeyEvent *event)
1336{
1337 struct IndexSharedData *shared = fdata->shared;
1338 struct IndexPrivateData *priv = fdata->priv;
1339 if (!shared->email)
1340 return FR_NO_ACTION;
1341 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
1342 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
1343 const bool c_pgp_auto_decode = cs_subset_bool(shared->sub, "pgp_auto_decode");
1344 if (c_pgp_auto_decode &&
1345 (priv->tag_prefix || !(shared->email->security & PGP_TRADITIONAL_CHECKED)))
1346 {
1347 if (mutt_check_traditional_pgp(shared->mailbox, &ea))
1349 }
1350 int rc = mutt_send_message(SEND_REPLY | SEND_LIST_REPLY, NULL, NULL,
1351 shared->mailbox, &ea, shared->sub);
1352 ARRAY_FREE(&ea);
1354
1355 return (rc == -1) ? FR_ERROR : FR_SUCCESS;
1356}
1357
1361static int op_list_subscribe(struct IndexFunctionData *fdata, const struct KeyEvent *event)
1362{
1363 struct IndexSharedData *shared = fdata->shared;
1364 return mutt_send_list_subscribe(shared->mailbox, shared->email) ? FR_SUCCESS : FR_ERROR;
1365}
1366
1370static int op_list_unsubscribe(struct IndexFunctionData *fdata, const struct KeyEvent *event)
1371{
1372 struct IndexSharedData *shared = fdata->shared;
1373 return mutt_send_list_unsubscribe(shared->mailbox, shared->email) ? FR_SUCCESS : FR_ERROR;
1374}
1375
1379static int op_mail(struct IndexFunctionData *fdata, const struct KeyEvent *event)
1380{
1381 struct IndexSharedData *shared = fdata->shared;
1382 struct IndexPrivateData *priv = fdata->priv;
1383 int rc = mutt_send_message(SEND_NONE, NULL, NULL, shared->mailbox, NULL,
1384 shared->sub);
1386 return (rc == -1) ? FR_ERROR : FR_SUCCESS;
1387}
1388
1392static int op_mailbox_list(struct IndexFunctionData *fdata, const struct KeyEvent *event)
1393{
1395 return FR_SUCCESS;
1396}
1397
1401static int op_mail_key(struct IndexFunctionData *fdata, const struct KeyEvent *event)
1402{
1403 struct IndexSharedData *shared = fdata->shared;
1404 struct IndexPrivateData *priv = fdata->priv;
1405 if (!(WithCrypto & APPLICATION_PGP))
1406 return FR_NOT_IMPL;
1407 int rc = mutt_send_message(SEND_KEY, NULL, NULL, NULL, NULL, shared->sub);
1409
1410 return (rc == -1) ? FR_ERROR : FR_SUCCESS;
1411}
1412
1416static int op_main_break_thread(struct IndexFunctionData *fdata, const struct KeyEvent *event)
1417{
1418 struct IndexSharedData *shared = fdata->shared;
1419 struct IndexPrivateData *priv = fdata->priv;
1420 struct Mailbox *m = shared->mailbox;
1421 /* L10N: CHECK_ACL */
1422 if (!check_acl(m, MUTT_ACL_WRITE, _("Can't break thread")))
1423 return FR_ERROR;
1424
1425 struct Email *e = shared->email;
1426 if (!e)
1427 return FR_NO_ACTION;
1428
1429 const bool has_repeat_count = (event->count > 0);
1430
1431 if (!mutt_using_threads())
1432 {
1433 mutt_warning(_("Threading is not enabled"));
1434 return FR_ERROR;
1435 }
1436
1437 struct MailboxView *mv = shared->mailbox_view;
1438 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
1439 if (ea_add_selection(&ea, mv, e, false, event->count) <= 0)
1440 {
1441 ARRAY_FREE(&ea);
1442 return FR_NO_ACTION;
1443 }
1444
1445 bool changed = false;
1446 struct Email **ep = NULL;
1447 ARRAY_FOREACH(ep, &ea)
1448 {
1449 e = *ep;
1450 if (!e || (STAILQ_EMPTY(&e->env->in_reply_to) && STAILQ_EMPTY(&e->env->references)))
1451 continue;
1452
1453 {
1455 changed = true;
1456 }
1457 }
1458 ARRAY_FREE(&ea);
1459
1460 if (changed)
1461 {
1462 mutt_sort_headers(mv, true);
1463 menu_set_index(priv->menu, shared->email->vnum);
1464 m->changed = true;
1465 mutt_message(_("Thread broken"));
1466
1468 }
1469 else if (!has_repeat_count)
1470 {
1471 mutt_error(_("Thread can't be broken, message is not part of a thread"));
1472 return FR_ERROR;
1473 }
1474
1475 return FR_SUCCESS;
1476}
1477
1486static int op_main_change_folder(struct IndexFunctionData *fdata, const struct KeyEvent *event)
1487{
1488 struct IndexSharedData *shared = fdata->shared;
1489 struct IndexPrivateData *priv = fdata->priv;
1490 struct Buffer *folderbuf = buf_pool_get();
1491 buf_alloc(folderbuf, PATH_MAX);
1492
1493 char *cp = NULL;
1494 bool read_only;
1495 const bool c_read_only = cs_subset_bool(shared->sub, "read_only");
1496 const int op = event->op;
1497 if (shared->attach_msg || c_read_only || (op == OP_MAIN_CHANGE_FOLDER_READONLY))
1498 {
1499 cp = _("Open mailbox in read-only mode");
1500 read_only = true;
1501 }
1502 else
1503 {
1504 cp = _("Open mailbox");
1505 read_only = false;
1506 }
1507
1508 const bool c_change_folder_next = cs_subset_bool(shared->sub, "change_folder_next");
1509 if (c_change_folder_next && shared->mailbox && !buf_is_empty(&shared->mailbox->pathbuf))
1510 {
1511 buf_strcpy(folderbuf, mailbox_path(shared->mailbox));
1512 pretty_mailbox(folderbuf);
1513 }
1514 /* By default, fill buf with the next mailbox that contains unread mail */
1515 mutt_mailbox_next(shared->mailbox_view ? shared->mailbox : NULL, folderbuf);
1516
1517 if (mw_enter_fname(cp, folderbuf, true, shared->mailbox, false, NULL, NULL,
1518 MUTT_SEL_NONE) == -1)
1519 {
1520 goto changefoldercleanup;
1521 }
1522
1523 /* Selected directory is okay, let's save it. */
1525
1526 if (buf_is_empty(folderbuf))
1527 {
1528 msgwin_clear_text(NULL);
1529 goto changefoldercleanup;
1530 }
1531
1532 struct Mailbox *m = mx_mbox_find2(buf_string(folderbuf));
1533 if (m)
1534 {
1535 change_folder_mailbox(priv->menu, m, &priv->oldcount, shared, read_only);
1536 }
1537 else
1538 {
1539 change_folder_string(priv->menu, folderbuf, &priv->oldcount, shared, read_only);
1540 }
1541
1542changefoldercleanup:
1543 buf_pool_release(&folderbuf);
1545
1546 return FR_SUCCESS;
1547}
1548
1552static int op_main_collapse_all(struct IndexFunctionData *fdata, const struct KeyEvent *event)
1553{
1554 struct IndexSharedData *shared = fdata->shared;
1555 struct IndexPrivateData *priv = fdata->priv;
1556 if (!mutt_using_threads())
1557 {
1558 mutt_warning(_("Threading is not enabled"));
1559 return FR_ERROR;
1560 }
1563
1564 return FR_SUCCESS;
1565}
1566
1571 const struct KeyEvent *event)
1572{
1573 struct IndexSharedData *shared = fdata->shared;
1574 struct IndexPrivateData *priv = fdata->priv;
1575 if (!mutt_using_threads())
1576 {
1577 mutt_warning(_("Threading is not enabled"));
1578 return FR_ERROR;
1579 }
1580
1582 return FR_NO_ACTION;
1583
1586
1587 return FR_SUCCESS;
1588}
1589
1593static int op_main_close_thread(struct IndexFunctionData *fdata, const struct KeyEvent *event)
1594{
1595 struct IndexSharedData *shared = fdata->shared;
1596 struct IndexPrivateData *priv = fdata->priv;
1597 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
1598 ea_add_selection_threads(&ea, shared->mailbox_view, shared->email,
1599 priv->tag_prefix, false, event->count);
1600 const int rc = op_main_change_thread(fdata, &ea, COLLAPSE_MODE_CLOSE);
1601 ARRAY_FREE(&ea);
1602 return rc;
1603}
1604
1608static int op_main_collapse_thread(struct IndexFunctionData *fdata, const struct KeyEvent *event)
1609{
1610 struct IndexSharedData *shared = fdata->shared;
1611 struct IndexPrivateData *priv = fdata->priv;
1612 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
1613 ea_add_selection_threads(&ea, shared->mailbox_view, shared->email,
1614 priv->tag_prefix, false, event->count);
1615 const int rc = op_main_change_thread(fdata, &ea, COLLAPSE_MODE_TOGGLE);
1616 ARRAY_FREE(&ea);
1617 return rc;
1618}
1619
1624 const struct KeyEvent *event)
1625{
1626 struct IndexSharedData *shared = fdata->shared;
1627 struct IndexPrivateData *priv = fdata->priv;
1628 if (!mutt_using_threads())
1629 {
1630 mutt_warning(_("Threading is not enabled"));
1631 return FR_ERROR;
1632 }
1633
1635 return FR_NO_ACTION;
1636
1639
1640 return FR_SUCCESS;
1641}
1642
1646static int op_main_open_thread(struct IndexFunctionData *fdata, const struct KeyEvent *event)
1647{
1648 struct IndexSharedData *shared = fdata->shared;
1649 struct IndexPrivateData *priv = fdata->priv;
1650 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
1651 ea_add_selection_threads(&ea, shared->mailbox_view, shared->email,
1652 priv->tag_prefix, false, event->count);
1653 const int rc = op_main_change_thread(fdata, &ea, COLLAPSE_MODE_OPEN);
1654 ARRAY_FREE(&ea);
1655 return rc;
1656}
1657
1661static int op_main_delete_pattern(struct IndexFunctionData *fdata, const struct KeyEvent *event)
1662{
1663 struct IndexSharedData *shared = fdata->shared;
1664 struct IndexPrivateData *priv = fdata->priv;
1665 /* L10N: CHECK_ACL */
1666 /* L10N: Due to the implementation details we do not know whether we
1667 delete zero, 1, 12, ... messages. So in English we use
1668 "messages". Your language might have other means to express this. */
1669 if (!check_acl(shared->mailbox, MUTT_ACL_DELETE, _("Can't delete messages")))
1670 return FR_ERROR;
1671
1672 mutt_pattern_func(shared->mailbox_view, MUTT_DELETE, _("Delete messages matching: "));
1674
1675 return FR_SUCCESS;
1676}
1677
1686static int op_main_limit(struct IndexFunctionData *fdata, const struct KeyEvent *event)
1687{
1688 struct IndexSharedData *shared = fdata->shared;
1689 struct IndexPrivateData *priv = fdata->priv;
1690 const bool lmt = mview_has_limit(shared->mailbox_view);
1691 int old_index = shared->email ? shared->email->index : -1;
1692 const int op = event->op;
1693 if (op == OP_TOGGLE_READ)
1694 {
1695 struct Buffer *buf2 = buf_pool_get();
1696
1697 if (!lmt || !mutt_strn_equal(shared->mailbox_view->pattern, "!~R!~D~s", 8))
1698 {
1699 buf_printf(buf2, "!~R!~D~s%s", lmt ? shared->mailbox_view->pattern : ".*");
1700 }
1701 else
1702 {
1703 const char *pat = shared->mailbox_view->pattern + 8;
1704 if ((*pat == '\0') || mutt_strn_equal(pat, ".*", 2))
1705 buf_strcpy(buf2, "~A");
1706 else
1707 buf_strcpy(buf2, pat);
1708 }
1710 buf_pool_release(&buf2);
1712 }
1713
1714 if (((op == OP_LIMIT_CURRENT_THREAD) &&
1715 mutt_limit_current_thread(shared->mailbox_view, shared->email)) ||
1716 (op == OP_TOGGLE_READ) ||
1717 ((op == OP_MAIN_LIMIT) && (mutt_pattern_func(shared->mailbox_view, MUTT_LIMIT,
1718 _("Limit to messages matching: ")) == 0)))
1719 {
1720 priv->menu->max = shared->mailbox->vcount;
1721 menu_set_index(priv->menu, 0);
1722 if (old_index >= 0)
1723 {
1724 /* try to find what used to be the current message */
1725 for (size_t i = 0; i < shared->mailbox->vcount; i++)
1726 {
1727 struct Email *e = mutt_get_virt_email(shared->mailbox, i);
1728 if (!e)
1729 continue;
1730 if (e->index == old_index)
1731 {
1732 menu_set_index(priv->menu, i);
1733 break;
1734 }
1735 }
1736 }
1737
1738 if ((shared->mailbox->msg_count != 0) && mutt_using_threads())
1739 {
1740 const bool c_collapse_all = cs_subset_bool(shared->sub, "collapse_all");
1741 if (c_collapse_all)
1744 }
1745 notify_send(shared->notify, NT_INDEX, NT_INDEX_EMAIL, NULL);
1747 }
1748 if (lmt)
1749 mutt_message(_("To view all messages, limit to \"all\""));
1750
1751 return FR_SUCCESS;
1752}
1753
1760static int op_main_link_threads(struct IndexFunctionData *fdata, const struct KeyEvent *event)
1761{
1762 struct IndexSharedData *shared = fdata->shared;
1763 struct IndexPrivateData *priv = fdata->priv;
1764 struct Mailbox *m = shared->mailbox;
1765 /* L10N: CHECK_ACL */
1766 if (!check_acl(m, MUTT_ACL_WRITE, _("Can't link threads")))
1767 return FR_ERROR;
1768
1769 struct Email *e = shared->email;
1770 if (!e)
1771 return FR_NO_ACTION;
1772
1773 enum FunctionRetval rc = FR_ERROR;
1774
1775 if (!mutt_using_threads())
1776 {
1777 mutt_warning(_("Threading is not enabled"));
1778 rc = FR_ERROR;
1779 }
1780 else if (!e->env->message_id)
1781 {
1782 mutt_error(_("No Message-ID: header available to link thread"));
1783 }
1784 else
1785 {
1786 struct MailboxView *mv = shared->mailbox_view;
1787 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
1788
1789 // If there's a repeat-count, use it.
1790 // If not, behave as if <tag-prefix> has been pressed.
1791 const bool tag_prefix = (event->count < 1);
1792 ea_add_selection(&ea, mv, e, tag_prefix, event->count);
1793
1794 if (!tag_prefix)
1795 {
1796 struct Email **ep = ARRAY_GET(&ea, 0);
1797 if (ep && (*ep == e))
1798 ARRAY_REMOVE(&ea, ep);
1799 }
1800
1801 if (mutt_link_threads(e, &ea, m))
1802 {
1803 mutt_sort_headers(mv, true);
1804 menu_set_index(priv->menu, e->vnum);
1805
1806 m->changed = true;
1807 mutt_message(_("Threads linked"));
1808 rc = FR_SUCCESS;
1809 }
1810 else
1811 {
1812 mutt_error(_("No thread linked"));
1813 rc = FR_ERROR;
1814 }
1815
1816 ARRAY_FREE(&ea);
1817 }
1818
1820 return rc;
1821}
1822
1830static int op_main_modify_tags(struct IndexFunctionData *fdata, const struct KeyEvent *event)
1831{
1832 struct IndexSharedData *shared = fdata->shared;
1833 struct IndexPrivateData *priv = fdata->priv;
1834 int rc = FR_ERROR;
1835 struct Buffer *buf = NULL;
1836 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
1837
1838 if (!shared->mailbox)
1839 goto done;
1840 struct Mailbox *m = shared->mailbox;
1841 if (!mx_tags_is_supported(m))
1842 {
1843 mutt_message(_("Folder doesn't support tagging, aborting"));
1844 goto done;
1845 }
1846 if (!shared->email)
1847 {
1848 rc = FR_NO_ACTION;
1849 goto done;
1850 }
1851
1852 const int op = event->op;
1853 struct Buffer *tags = buf_pool_get();
1854 if (!priv->tag_prefix)
1855 driver_tags_get_with_hidden(&shared->email->tags, tags);
1856 /* Prompt the user to edit the tag string */
1857 buf = buf_pool_get();
1858 int rc2 = mx_tags_edit(m, buf_string(tags), buf);
1859 buf_pool_release(&tags);
1860 if (rc2 < 0)
1861 {
1862 goto done;
1863 }
1864 else if (rc2 == 0)
1865 {
1866 mutt_message(_("No tag specified, aborting"));
1867 goto done;
1868 }
1869
1870 ea_add_selection(&ea, shared->mailbox_view, shared->email, priv->tag_prefix,
1871 event->count);
1872 const int num = ARRAY_SIZE(&ea);
1873
1874 if (priv->tag_prefix || (num > 1))
1875 {
1876 struct Progress *progress = NULL;
1877
1878 if (m->verbose)
1879 {
1880 progress = progress_new(MUTT_PROGRESS_WRITE, num);
1881 progress_set_message(progress, _("Update tags..."));
1882 }
1883
1884#ifdef USE_NOTMUCH
1885 if (m->type == MUTT_NOTMUCH)
1886 nm_db_longrun_init(m, true);
1887#endif
1888 struct Email **ep = NULL;
1889 int px = 0;
1890 ARRAY_FOREACH(ep, &ea)
1891 {
1892 struct Email *e = *ep;
1893
1894 progress_update(progress, ++px, -1);
1895 mx_tags_commit(m, e, buf_string(buf));
1896 e->attr_color = NULL;
1897 if (op == OP_MAIN_MODIFY_TAGS_THEN_HIDE)
1898 {
1899 bool still_queried = false;
1900#ifdef USE_NOTMUCH
1901 if (m->type == MUTT_NOTMUCH)
1902 still_queried = nm_message_is_still_queried(m, e);
1903#endif
1904 e->quasi_deleted = !still_queried;
1905 m->changed = true;
1906 }
1907 }
1908 progress_free(&progress);
1909#ifdef USE_NOTMUCH
1910 if (m->type == MUTT_NOTMUCH)
1912#endif
1914 if (!priv->tag_prefix)
1916 (op == OP_MAIN_MODIFY_TAGS_THEN_HIDE) ? 1 : num);
1917 }
1918 else
1919 {
1920 if (mx_tags_commit(m, shared->email, buf_string(buf)))
1921 {
1922 mutt_message(_("Failed to modify tags, aborting"));
1923 goto done;
1924 }
1925 shared->email->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, shared->email);
1932#endif
1933 shared->email->quasi_deleted = !still_queried;
1934 m->changed = true;
1935 }
1936
1938 (op == OP_MAIN_MODIFY_TAGS_THEN_HIDE) ? 1 : num);
1939 }
1940 rc = FR_SUCCESS;
1941
1942done:
1943 ARRAY_FREE(&ea);
1944 buf_pool_release(&buf);
1945 return rc;
1946}
1947
1968static int find_next_new_email(struct Mailbox *m, int start, bool forwards, int op)
1969{
1970 int first_unread = -1;
1971 int first_new = -1;
1972 int mcur = start;
1973 const bool threaded = mutt_using_threads();
1974
1975 for (int i = 0; i < m->vcount; i++)
1976 {
1977 if (forwards)
1978 {
1979 mcur++;
1980 if (mcur > (m->vcount - 1))
1981 mcur = 0;
1982 }
1983 else
1984 {
1985 mcur--;
1986 if (mcur < 0)
1987 mcur = m->vcount - 1;
1988 }
1989
1990 struct Email *e = mutt_get_virt_email(m, mcur);
1991 if (!e)
1992 break;
1993 if (e->collapsed && threaded)
1994 {
1995 int unread = mutt_thread_contains_unread(e);
1996 if ((unread != 0) && (first_unread == -1))
1997 first_unread = mcur;
1998 if ((unread == 1) && (first_new == -1))
1999 first_new = mcur;
2000 }
2001 else if (!e->deleted && !e->read)
2002 {
2003 if (first_unread == -1)
2004 first_unread = mcur;
2005 if (!e->old && (first_new == -1))
2006 first_new = mcur;
2007 }
2008
2009 if (((op == OP_MAIN_NEXT_UNREAD) || (op == OP_MAIN_PREV_UNREAD)) && (first_unread != -1))
2010 break;
2011 if (((op == OP_MAIN_NEXT_NEW) || (op == OP_MAIN_PREV_NEW) ||
2012 (op == OP_MAIN_NEXT_NEW_THEN_UNREAD) || (op == OP_MAIN_PREV_NEW_THEN_UNREAD)) &&
2013 (first_new != -1))
2014 {
2015 break;
2016 }
2017 }
2018
2019 if (((op == OP_MAIN_NEXT_NEW) || (op == OP_MAIN_PREV_NEW) ||
2020 (op == OP_MAIN_NEXT_NEW_THEN_UNREAD) || (op == OP_MAIN_PREV_NEW_THEN_UNREAD)) &&
2021 (first_new != -1))
2022 {
2023 return first_new;
2024 }
2025 if (((op == OP_MAIN_NEXT_UNREAD) || (op == OP_MAIN_PREV_UNREAD) ||
2026 (op == OP_MAIN_NEXT_NEW_THEN_UNREAD) || (op == OP_MAIN_PREV_NEW_THEN_UNREAD)) &&
2027 (first_unread != -1))
2028 {
2029 return first_unread;
2030 }
2031
2032 return -1;
2033}
2034
2035static int op_main_next_new(struct IndexFunctionData *fdata, const struct KeyEvent *event)
2036{
2037 struct IndexSharedData *shared = fdata->shared;
2038 struct IndexPrivateData *priv = fdata->priv;
2039
2040 const int saved_current = menu_get_index(priv->menu);
2041 const int op = event->op;
2042 const bool forwards = (op == OP_MAIN_NEXT_NEW) || (op == OP_MAIN_NEXT_UNREAD) ||
2043 (op == OP_MAIN_NEXT_NEW_THEN_UNREAD);
2044 const int count = event->count;
2045
2046 if (count > 0)
2047 {
2048 int cur = saved_current;
2049 int last_good = saved_current;
2050 for (int i = 0; i < count; i++)
2051 {
2052 int next = find_next_new_email(shared->mailbox, cur, forwards, op);
2053 if (next == -1)
2054 break;
2055 last_good = next;
2056 cur = next;
2057 }
2058 if (last_good != saved_current)
2059 menu_set_index(priv->menu, last_good);
2060 return FR_SUCCESS;
2061 }
2062
2063 int index = find_next_new_email(shared->mailbox, saved_current, forwards, op);
2064
2065 if (index == -1)
2066 {
2067 menu_set_index(priv->menu, saved_current);
2068 if ((op == OP_MAIN_NEXT_NEW) || (op == OP_MAIN_PREV_NEW))
2069 {
2071 mutt_error(_("No new messages in this limited view"));
2072 else
2073 mutt_error(_("No new messages"));
2074 }
2075 else
2076 {
2078 mutt_error(_("No unread messages in this limited view"));
2079 else
2080 mutt_error(_("No unread messages"));
2081 }
2083 return FR_ERROR;
2084 }
2085
2086 menu_set_index(priv->menu, index);
2087
2088 index = menu_get_index(priv->menu);
2089 if (forwards)
2090 {
2091 if (saved_current > index)
2092 {
2093 mutt_message(_("Search wrapped to top"));
2094 }
2095 }
2096 else if (saved_current < index)
2097 {
2098 mutt_message(_("Search wrapped to bottom"));
2099 }
2100
2101 return FR_SUCCESS;
2102}
2103
2113static int op_main_next_thread(struct IndexFunctionData *fdata, const struct KeyEvent *event)
2114{
2115 struct IndexSharedData *shared = fdata->shared;
2116 struct IndexPrivateData *priv = fdata->priv;
2117 const int op = event->op;
2118 const int count = event->count;
2119 const bool forwards = (op == OP_MAIN_NEXT_THREAD) || (op == OP_MAIN_NEXT_SUBTHREAD);
2120 const bool subthreads = (op == OP_MAIN_NEXT_SUBTHREAD) || (op == OP_MAIN_PREV_SUBTHREAD);
2121
2122 if (count > 0)
2123 {
2124 for (int i = 0; i < count; i++)
2125 {
2126 int index = mutt_aside_thread(shared->email, forwards, subthreads);
2127 if (index == -1)
2128 break;
2129 menu_set_index(priv->menu, index);
2130 }
2131 return FR_SUCCESS;
2132 }
2133
2134 int index = mutt_aside_thread(shared->email, forwards, subthreads);
2135
2136 if (index != -1)
2137 menu_set_index(priv->menu, index);
2138
2139 if (index < 0)
2140 {
2141 if (forwards)
2142 mutt_error(_("No more threads"));
2143 else
2144 mutt_error(_("You are on the first thread"));
2145
2147 return FR_ERROR;
2148 }
2149
2150 return FR_SUCCESS;
2151}
2152
2156static int op_main_next_undeleted(struct IndexFunctionData *fdata, const struct KeyEvent *event)
2157{
2158 struct IndexSharedData *shared = fdata->shared;
2159 struct IndexPrivateData *priv = fdata->priv;
2160 const int count = event->count;
2161 int index = menu_get_index(priv->menu);
2162
2163 if (count > 0)
2164 {
2165 const bool uncollapse = mutt_using_threads() && !window_is_focused(priv->win_index);
2166 int last_good = index;
2167 for (int i = 0; i < count; i++)
2168 {
2169 int next = find_next_undeleted(shared->mailbox_view, index, uncollapse);
2170 if (next == -1)
2171 break;
2172 last_good = next;
2173 index = next;
2174 }
2175 if (last_good != menu_get_index(priv->menu))
2176 {
2177 menu_set_index(priv->menu, last_good);
2178 if (uncollapse)
2180 }
2181 return FR_SUCCESS;
2182 }
2183
2184 if (index >= (shared->mailbox->vcount - 1))
2185 {
2187 mutt_message(_("You are on the last message"));
2188 return FR_ERROR;
2189 }
2190
2191 const bool uncollapse = mutt_using_threads() && !window_is_focused(priv->win_index);
2192
2193 index = find_next_undeleted(shared->mailbox_view, index, uncollapse);
2194 if (index != -1)
2195 {
2196 menu_set_index(priv->menu, index);
2197 if (uncollapse)
2199 }
2200
2201 if (index == -1)
2202 {
2204 mutt_error(_("No undeleted messages"));
2205 return FR_ERROR;
2206 }
2207
2208 return FR_SUCCESS;
2209}
2210
2215 const struct KeyEvent *event)
2216{
2217 struct IndexSharedData *shared = fdata->shared;
2218 struct IndexPrivateData *priv = fdata->priv;
2219 struct Mailbox *m = shared->mailbox;
2220
2221 struct Buffer *folderbuf = buf_pool_get();
2222 buf_strcpy(folderbuf, mailbox_path(m));
2223 m = mutt_mailbox_next_unread(m, folderbuf);
2224 buf_pool_release(&folderbuf);
2225
2226 if (!m)
2227 {
2228 mutt_error(_("No mailboxes have new mail"));
2229 return FR_ERROR;
2230 }
2231
2232 change_folder_mailbox(priv->menu, m, &priv->oldcount, shared, false);
2233 return FR_SUCCESS;
2234}
2235
2240 const struct KeyEvent *event)
2241{
2242 struct IndexSharedData *shared = fdata->shared;
2243 struct IndexPrivateData *priv = fdata->priv;
2244 struct Mailbox *m = shared->mailbox;
2245
2246 struct Buffer *folderbuf = buf_pool_get();
2247 buf_strcpy(folderbuf, mailbox_path(m));
2248 m = mutt_mailbox_prev_unread(m, folderbuf);
2249 buf_pool_release(&folderbuf);
2250
2251 if (!m)
2252 {
2253 mutt_error(_("No mailboxes have new mail"));
2254 return FR_ERROR;
2255 }
2256
2257 change_folder_mailbox(priv->menu, m, &priv->oldcount, shared, false);
2258 return FR_SUCCESS;
2259}
2260
2264static int op_main_prev_undeleted(struct IndexFunctionData *fdata, const struct KeyEvent *event)
2265{
2266 struct IndexSharedData *shared = fdata->shared;
2267 struct IndexPrivateData *priv = fdata->priv;
2268 const int count = event->count;
2269 int index = menu_get_index(priv->menu);
2270
2271 if (count > 0)
2272 {
2273 const bool uncollapse = mutt_using_threads() && !window_is_focused(priv->win_index);
2274 int last_good = index;
2275 for (int i = 0; i < count; i++)
2276 {
2277 int prev = find_previous_undeleted(shared->mailbox_view, index, uncollapse);
2278 if (prev == -1)
2279 break;
2280 last_good = prev;
2281 index = prev;
2282 }
2283 if (last_good != menu_get_index(priv->menu))
2284 {
2285 menu_set_index(priv->menu, last_good);
2286 if (uncollapse)
2288 }
2289 return FR_SUCCESS;
2290 }
2291
2292 if (index < 1)
2293 {
2295 mutt_message(_("You are on the first message"));
2296 return FR_ERROR;
2297 }
2298
2299 const bool uncollapse = mutt_using_threads() && !window_is_focused(priv->win_index);
2300
2301 index = find_previous_undeleted(shared->mailbox_view, index, uncollapse);
2302 if (index != -1)
2303 {
2304 menu_set_index(priv->menu, index);
2305 if (uncollapse)
2307 }
2308
2309 if (index == -1)
2310 {
2311 mutt_error(_("No undeleted messages"));
2313 return FR_ERROR;
2314 }
2315
2316 return FR_SUCCESS;
2317}
2318
2322static int op_main_quasi_delete(struct IndexFunctionData *fdata, const struct KeyEvent *event)
2323{
2324 struct IndexSharedData *shared = fdata->shared;
2325 struct IndexPrivateData *priv = fdata->priv;
2326 struct Mailbox *m = shared->mailbox;
2327 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
2328 ea_add_selection(&ea, shared->mailbox_view, shared->email, priv->tag_prefix,
2329 event->count);
2330 if (ARRAY_EMPTY(&ea))
2331 {
2332 ARRAY_FREE(&ea);
2333 return FR_NO_ACTION;
2334 }
2335 const int num = ARRAY_SIZE(&ea);
2336
2337 struct Email **ep = NULL;
2338 ARRAY_FOREACH(ep, &ea)
2339 {
2340 (*ep)->quasi_deleted = true;
2341 m->changed = true;
2342 }
2343 ARRAY_FREE(&ea);
2344
2345 if (priv->tag_prefix || (num > 1))
2347
2348 return FR_SUCCESS;
2349}
2350
2358static int op_main_read_thread(struct IndexFunctionData *fdata, const struct KeyEvent *event)
2359{
2360 struct IndexSharedData *shared = fdata->shared;
2361 struct IndexPrivateData *priv = fdata->priv;
2362 /* L10N: CHECK_ACL */
2363 /* L10N: Due to the implementation details we do not know whether we
2364 mark zero, 1, 12, ... messages as read. So in English we use
2365 "messages". Your language might have other means to express this. */
2366 if (!check_acl(shared->mailbox, MUTT_ACL_SEEN, _("Can't mark messages as read")))
2367 return FR_ERROR;
2368
2369 const int op = event->op;
2370 const bool subthread = (op != OP_MAIN_READ_THREAD);
2371 int rc = 0;
2372 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
2373 ea_add_selection_threads(&ea, shared->mailbox_view, shared->email,
2374 priv->tag_prefix, subthread, event->count);
2375 const int num = ARRAY_SIZE(&ea);
2376
2377 struct Email **ep = NULL;
2378 ARRAY_FOREACH(ep, &ea)
2379 {
2380 rc = mutt_thread_set_flag(shared->mailbox, *ep, MUTT_READ, true, subthread);
2381 if (rc == -1)
2382 break;
2383 }
2384 ARRAY_FREE(&ea);
2385
2386 if (rc == -1)
2387 return FR_ERROR;
2388
2389 if (priv->tag_prefix)
2390 {
2392 return FR_SUCCESS;
2393 }
2394
2395 const enum ResolveMethod rm = (op == OP_MAIN_READ_THREAD) ? RESOLVE_NEXT_THREAD :
2397 resolve_email(priv, shared, rm, num);
2399 return FR_SUCCESS;
2400}
2401
2412static int op_main_root_message(struct IndexFunctionData *fdata, const struct KeyEvent *event)
2413{
2414 struct IndexSharedData *shared = fdata->shared;
2415 struct IndexPrivateData *priv = fdata->priv;
2416 int count = event->op == OP_MAIN_ROOT_MESSAGE ? 0 : MAX(event->count, 1);
2417 int index = mutt_parent_message(shared->email, event->op == OP_MAIN_ROOT_MESSAGE, count);
2418 if (index != -1)
2419 menu_set_index(priv->menu, index);
2420
2421 return FR_SUCCESS;
2422}
2423
2431static int op_main_set_flag(struct IndexFunctionData *fdata, const struct KeyEvent *event)
2432{
2433 struct IndexSharedData *shared = fdata->shared;
2434 struct IndexPrivateData *priv = fdata->priv;
2435 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
2436 ea_add_selection(&ea, shared->mailbox_view, shared->email, priv->tag_prefix,
2437 event->count);
2438 if (ARRAY_EMPTY(&ea))
2439 {
2440 ARRAY_FREE(&ea);
2441 return FR_NO_ACTION;
2442 }
2443 const int num = ARRAY_SIZE(&ea);
2444
2445 if (mw_change_flag(shared->mailbox, &ea, (event->op == OP_MAIN_SET_FLAG)) == 0)
2446 {
2447 if (priv->tag_prefix)
2448 {
2450 }
2451 else
2452 {
2453 resolve_email(priv, shared, RESOLVE_NEXT_UNDELETED, num);
2454 if (num > 1)
2456 }
2457 }
2458 ARRAY_FREE(&ea);
2459
2460 return FR_SUCCESS;
2461}
2462
2466static int op_main_show_limit(struct IndexFunctionData *fdata, const struct KeyEvent *event)
2467{
2468 struct IndexSharedData *shared = fdata->shared;
2469 if (mview_has_limit(shared->mailbox_view))
2470 {
2471 struct Buffer *buf = buf_pool_get();
2472 /* L10N: ask for a limit to apply */
2473 buf_printf(buf, _("Limit: %s"), shared->mailbox_view->pattern);
2474 mutt_message("%s", buf_string(buf));
2475 buf_pool_release(&buf);
2476 }
2477 else
2478 {
2479 mutt_message(_("No limit pattern is in effect"));
2480 }
2481
2482 return FR_SUCCESS;
2483}
2484
2488static int op_main_sync_folder(struct IndexFunctionData *fdata, const struct KeyEvent *event)
2489{
2490 struct IndexSharedData *shared = fdata->shared;
2491 struct IndexPrivateData *priv = fdata->priv;
2493 return FR_NO_ACTION;
2494
2495 int ovc = shared->mailbox->vcount;
2496 int oc = shared->mailbox->msg_count;
2497 struct Email *e = NULL;
2498
2499 /* don't attempt to move the cursor if there are no visible messages in the current limit */
2500 int index = menu_get_index(priv->menu);
2501 if (index < shared->mailbox->vcount)
2502 {
2503 /* threads may be reordered, so figure out what header the cursor
2504 * should be on. */
2505 int newidx = index;
2506 if (!shared->email)
2507 return FR_NO_ACTION;
2508 if (shared->email->deleted)
2509 newidx = find_next_undeleted(shared->mailbox_view, index, false);
2510 if (newidx < 0)
2511 newidx = find_previous_undeleted(shared->mailbox_view, index, false);
2512 if (newidx >= 0)
2513 e = mutt_get_virt_email(shared->mailbox, newidx);
2514 }
2515
2516 enum MxStatus check = mx_mbox_sync(shared->mailbox);
2517 if (check == MX_STATUS_OK)
2518 {
2519 if (e && (shared->mailbox->vcount != ovc))
2520 {
2521 for (size_t i = 0; i < shared->mailbox->vcount; i++)
2522 {
2523 struct Email *e2 = mutt_get_virt_email(shared->mailbox, i);
2524 if (e2 == e)
2525 {
2526 menu_set_index(priv->menu, i);
2527 break;
2528 }
2529 }
2530 }
2532 }
2533 else if ((check == MX_STATUS_NEW_MAIL) || (check == MX_STATUS_REOPENED))
2534 {
2535 update_index(priv->menu, shared->mailbox_view, check, oc, shared);
2536 }
2537
2538 /* do a sanity check even if mx_mbox_sync failed. */
2539
2540 index = menu_get_index(priv->menu);
2541 if ((index < 0) || (shared->mailbox && (index >= shared->mailbox->vcount)))
2542 {
2544 }
2545
2546 /* check for a fatal error, or all messages deleted */
2547 if (shared->mailbox && buf_is_empty(&shared->mailbox->pathbuf))
2548 {
2549 mview_free(&shared->mailbox_view);
2550 }
2551
2552 if (shared->mailbox)
2553 {
2554 priv->menu->max = shared->mailbox->vcount;
2556
2557 struct EventMailbox ev_m = { shared->mailbox };
2559 }
2560 else
2561 {
2562 priv->menu->max = 0;
2564 }
2565
2566 return FR_SUCCESS;
2567}
2568
2572static int op_main_tag_pattern(struct IndexFunctionData *fdata, const struct KeyEvent *event)
2573{
2574 struct IndexSharedData *shared = fdata->shared;
2575 struct IndexPrivateData *priv = fdata->priv;
2576 mutt_pattern_func(shared->mailbox_view, MUTT_TAG, _("Tag messages matching: "));
2578
2579 return FR_SUCCESS;
2580}
2581
2586 const struct KeyEvent *event)
2587{
2588 struct IndexSharedData *shared = fdata->shared;
2589 struct IndexPrivateData *priv = fdata->priv;
2590 /* L10N: CHECK_ACL */
2591 /* L10N: Due to the implementation details we do not know whether we
2592 undelete zero, 1, 12, ... messages. So in English we use
2593 "messages". Your language might have other means to express this. */
2594 if (!check_acl(shared->mailbox, MUTT_ACL_DELETE, _("Can't undelete messages")))
2595 return FR_ERROR;
2596
2598 _("Undelete messages matching: ")) == 0)
2599 {
2601 }
2602
2603 return FR_SUCCESS;
2604}
2605
2609static int op_main_untag_pattern(struct IndexFunctionData *fdata, const struct KeyEvent *event)
2610{
2611 struct IndexSharedData *shared = fdata->shared;
2612 struct IndexPrivateData *priv = fdata->priv;
2613 if (mutt_pattern_func(shared->mailbox_view, MUTT_UNTAG, _("Untag messages matching: ")) == 0)
2615
2616 return FR_SUCCESS;
2617}
2618
2622static int op_mark_msg(struct IndexFunctionData *fdata, const struct KeyEvent *event)
2623{
2624 struct IndexSharedData *shared = fdata->shared;
2625 if (!shared->email)
2626 return FR_NO_ACTION;
2627
2628 int rc = FR_SUCCESS;
2629
2630 if (shared->email->env->message_id)
2631 {
2632 struct Buffer *buf = buf_pool_get();
2633
2634 /* L10N: This is the prompt for <mark-message>. Whatever they
2635 enter will be prefixed by $mark_macro_prefix and will become
2636 a macro hotkey to jump to the currently selected message. */
2637 if ((mw_get_field(_("Enter macro stroke: "), buf, MUTT_COMP_NONE, HC_OTHER,
2638 NULL, NULL) == 0) &&
2639 !buf_is_empty(buf))
2640 {
2641 const char *const c_mark_macro_prefix = cs_subset_string(shared->sub, "mark_macro_prefix");
2642 char str[256] = { 0 };
2643 snprintf(str, sizeof(str), "%s%s", c_mark_macro_prefix, buf_string(buf));
2644
2645 struct Buffer *msg_id = buf_pool_get();
2646 mutt_file_sanitize_regex(msg_id, shared->email->env->message_id);
2647 char macro[256] = { 0 };
2648 snprintf(macro, sizeof(macro), "<search>~i '%s'\n", buf_string(msg_id));
2649 buf_pool_release(&msg_id);
2650
2651 /* L10N: "message hotkey" is the key bindings menu description of a
2652 macro created by <mark-message>. */
2653 km_bind(fdata->mod_data->md_index, str, OP_MACRO, macro, _("message hotkey"), NULL);
2654
2655 /* L10N: This is echoed after <mark-message> creates a new hotkey
2656 macro. %s is the hotkey string ($mark_macro_prefix followed
2657 by whatever they typed at the prompt.) */
2658 buf_printf(buf, _("Message bound to %s"), str);
2659 mutt_message("%s", buf_string(buf));
2660 mutt_debug(LL_DEBUG1, "Mark: %s => %s\n", str, macro);
2661 }
2662 buf_pool_release(&buf);
2663 }
2664 else
2665 {
2666 /* L10N: This error is printed if <mark-message> can't find a
2667 Message-ID for the currently selected message in the index. */
2668 mutt_error(_("No message ID to macro"));
2669 rc = FR_ERROR;
2670 }
2671
2672 return rc;
2673}
2674
2678static int op_next_entry(struct IndexFunctionData *fdata, const struct KeyEvent *event)
2679{
2680 struct IndexSharedData *shared = fdata->shared;
2681 struct IndexPrivateData *priv = fdata->priv;
2682 int count = MAX(event->count, 1);
2683 int index = menu_get_index(priv->menu) + count;
2684
2685 if (index >= shared->mailbox->vcount)
2686 {
2687 index = shared->mailbox->vcount - 1;
2688 if (event->count == 0)
2689 {
2690 mutt_message(_("You are on the last message"));
2692 }
2693 }
2694
2695 menu_set_index(priv->menu, index);
2696 return FR_SUCCESS;
2697}
2698
2702static int op_pipe(struct IndexFunctionData *fdata, const struct KeyEvent *event)
2703{
2704 struct IndexSharedData *shared = fdata->shared;
2705 struct IndexPrivateData *priv = fdata->priv;
2706 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
2707 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
2708 mutt_pipe_message(shared->mailbox, &ea);
2709 ARRAY_FREE(&ea);
2710
2711 /* in an IMAP folder index with imap_peek=no, piping could change
2712 * new or old messages status to read. Redraw what's needed. */
2713 const bool c_imap_peek = cs_subset_bool(shared->sub, "imap_peek");
2714 if ((shared->mailbox->type == MUTT_IMAP) && !c_imap_peek)
2715 {
2717 }
2718
2719 return FR_SUCCESS;
2720}
2721
2725static int op_prev_entry(struct IndexFunctionData *fdata, const struct KeyEvent *event)
2726{
2727 struct IndexSharedData *shared = fdata->shared;
2728 struct IndexPrivateData *priv = fdata->priv;
2729 int count = MAX(event->count, 1);
2730 int index = menu_get_index(priv->menu) - count;
2731
2732 if (index < 0)
2733 {
2734 index = 0;
2735 if (event->count == 0)
2736 {
2738 mutt_message(_("You are on the first message"));
2739 }
2740 }
2741
2742 menu_set_index(priv->menu, index);
2743 return FR_SUCCESS;
2744}
2745
2749static int op_print(struct IndexFunctionData *fdata, const struct KeyEvent *event)
2750{
2751 struct IndexSharedData *shared = fdata->shared;
2752 struct IndexPrivateData *priv = fdata->priv;
2753 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
2754 ea_add_selection(&ea, shared->mailbox_view, shared->email, priv->tag_prefix,
2755 event->count);
2756 if (ARRAY_EMPTY(&ea))
2757 {
2758 ARRAY_FREE(&ea);
2759 return FR_NO_ACTION;
2760 }
2761 const int num = ARRAY_SIZE(&ea);
2762 const bool printed = mutt_print_message(shared->mailbox, &ea);
2763 ARRAY_FREE(&ea);
2764
2765 if (printed && !priv->tag_prefix)
2766 resolve_email(priv, shared, RESOLVE_NEXT_EMAIL, num);
2767
2768 /* in an IMAP folder index with imap_peek=no, printing could change
2769 * new or old messages status to read. Redraw what's needed. */
2770 const bool c_imap_peek = cs_subset_bool(shared->sub, "imap_peek");
2771 if (printed && (shared->mailbox->type == MUTT_IMAP) && !c_imap_peek)
2772 {
2773 menu_queue_redraw(priv->menu,
2774 ((priv->tag_prefix || (num > 1)) ? MENU_REDRAW_INDEX : MENU_REDRAW_CURRENT));
2775 }
2776
2777 return FR_SUCCESS;
2778}
2779
2783static int op_query(struct IndexFunctionData *fdata, const struct KeyEvent *event)
2784{
2785 struct IndexSharedData *shared = fdata->shared;
2786 query_index(shared->mailbox, shared->sub);
2787 return FR_SUCCESS;
2788}
2789
2793static int op_quit(struct IndexFunctionData *fdata, const struct KeyEvent *event)
2794{
2795 struct IndexSharedData *shared = fdata->shared;
2796 struct IndexPrivateData *priv = fdata->priv;
2797 if (shared->attach_msg)
2798 return FR_DONE;
2799
2800 if (query_quadoption(_("Quit NeoMutt?"), shared->sub, "quit") == MUTT_YES)
2801 {
2802 priv->oldcount = shared->mailbox ? shared->mailbox->msg_count : 0;
2803
2805 mutt_debug(LL_NOTIFY, "NT_GLOBAL_SHUTDOWN\n");
2807
2808 enum MxStatus check = MX_STATUS_OK;
2809 if (!shared->mailbox_view || ((check = mx_mbox_close(shared->mailbox)) == MX_STATUS_OK))
2810 {
2813 return FR_DONE;
2814 }
2815
2816 if ((check == MX_STATUS_NEW_MAIL) || (check == MX_STATUS_REOPENED))
2817 {
2818 update_index(priv->menu, shared->mailbox_view, check, priv->oldcount, shared);
2819 }
2820
2821 menu_queue_redraw(priv->menu, MENU_REDRAW_FULL); /* new mail arrived? */
2823 }
2824
2825 return FR_NO_ACTION;
2826}
2827
2831static int op_recall_message(struct IndexFunctionData *fdata, const struct KeyEvent *event)
2832{
2833 struct IndexSharedData *shared = fdata->shared;
2834 struct IndexPrivateData *priv = fdata->priv;
2835 int rc = mutt_send_message(SEND_POSTPONED, NULL, NULL, shared->mailbox, NULL,
2836 shared->sub);
2838 return (rc == -1) ? FR_ERROR : FR_SUCCESS;
2839}
2840
2844static int op_reply(struct IndexFunctionData *fdata, const struct KeyEvent *event)
2845{
2846 struct IndexSharedData *shared = fdata->shared;
2847 struct IndexPrivateData *priv = fdata->priv;
2848 if (!shared->email)
2849 return FR_NO_ACTION;
2850 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
2851 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
2852 const bool c_pgp_auto_decode = cs_subset_bool(shared->sub, "pgp_auto_decode");
2853 if (c_pgp_auto_decode &&
2854 (priv->tag_prefix || !(shared->email->security & PGP_TRADITIONAL_CHECKED)))
2855 {
2856 if (mutt_check_traditional_pgp(shared->mailbox, &ea))
2858 }
2859 int rc = mutt_send_message(SEND_REPLY, NULL, NULL, shared->mailbox, &ea,
2860 shared->sub);
2861 ARRAY_FREE(&ea);
2863
2864 return (rc == -1) ? FR_ERROR : FR_SUCCESS;
2865}
2866
2870static int op_resend(struct IndexFunctionData *fdata, const struct KeyEvent *event)
2871{
2872 struct IndexSharedData *shared = fdata->shared;
2873 struct IndexPrivateData *priv = fdata->priv;
2874 int rc = -1;
2875 if (priv->tag_prefix)
2876 {
2877 struct Mailbox *m = shared->mailbox;
2878 for (size_t i = 0; i < m->msg_count; i++)
2879 {
2880 struct Email *e = m->emails[i];
2881 if (!e)
2882 break;
2883 if (message_is_tagged(e))
2884 rc = mutt_resend_message(NULL, shared->mailbox, e, shared->sub);
2885 }
2886 }
2887 else
2888 {
2889 rc = mutt_resend_message(NULL, shared->mailbox, shared->email, shared->sub);
2890 }
2891
2893 return (rc == -1) ? FR_ERROR : FR_SUCCESS;
2894}
2895
2907static int op_save(struct IndexFunctionData *fdata, const struct KeyEvent *event)
2908{
2909 struct IndexSharedData *shared = fdata->shared;
2910 struct IndexPrivateData *priv = fdata->priv;
2911 const int op = event->op;
2912 if (((op == OP_DECRYPT_COPY) || (op == OP_DECRYPT_SAVE)) && !WithCrypto)
2913 return FR_NOT_IMPL;
2914
2915 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
2916 ea_add_selection(&ea, shared->mailbox_view, shared->email, priv->tag_prefix,
2917 event->count);
2918 if (ARRAY_EMPTY(&ea))
2919 {
2920 ARRAY_FREE(&ea);
2921 return FR_NO_ACTION;
2922 }
2923 const int num = ARRAY_SIZE(&ea);
2924
2925 const enum MessageSaveOpt save_opt = ((op == OP_SAVE) || (op == OP_DECODE_SAVE) ||
2926 (op == OP_DECRYPT_SAVE)) ?
2927 SAVE_MOVE :
2928 SAVE_COPY;
2929
2930 enum MessageTransformOpt transform_opt =
2931 ((op == OP_DECODE_SAVE) || (op == OP_DECODE_COPY)) ? TRANSFORM_DECODE :
2932 ((op == OP_DECRYPT_SAVE) || (op == OP_DECRYPT_COPY)) ? TRANSFORM_DECRYPT :
2934
2935 const int rc = mutt_save_message(shared->mailbox, &ea, save_opt, transform_opt);
2936 if ((rc == 0) && (save_opt == SAVE_MOVE) && !priv->tag_prefix)
2937 {
2938 resolve_email(priv, shared, RESOLVE_NEXT_UNDELETED, 1);
2939 }
2940 ARRAY_FREE(&ea);
2941
2942 if (priv->tag_prefix || (num > 1))
2944
2945 return (rc == -1) ? FR_ERROR : FR_SUCCESS;
2946}
2947
2957static int op_search(struct IndexFunctionData *fdata, const struct KeyEvent *event)
2958{
2959 struct IndexSharedData *shared = fdata->shared;
2960 struct IndexPrivateData *priv = fdata->priv;
2961 SearchFlags flags = SEARCH_NONE;
2962 switch (event->op)
2963 {
2964 case OP_SEARCH:
2965 flags |= SEARCH_PROMPT;
2966 shared->search_state->reverse = false;
2967 break;
2968 case OP_SEARCH_REVERSE:
2969 flags |= SEARCH_PROMPT;
2970 shared->search_state->reverse = true;
2971 break;
2972 case OP_SEARCH_NEXT:
2973 break;
2974 case OP_SEARCH_OPPOSITE:
2975 flags |= SEARCH_OPPOSITE;
2976 break;
2977 }
2978
2979 // Initiating a search can happen on an empty mailbox, but
2980 // searching for next/previous/... needs to be on a message and
2981 // thus a non-empty mailbox
2982 int index = menu_get_index(priv->menu);
2983 index = mutt_search_command(shared->mailbox_view, priv->menu, index,
2984 shared->search_state, flags);
2985 if (index != -1)
2986 menu_set_index(priv->menu, index);
2987
2988 return FR_SUCCESS;
2989}
2990
2998static int op_sort(struct IndexFunctionData *fdata, const struct KeyEvent *event)
2999{
3000 struct IndexSharedData *shared = fdata->shared;
3001 struct IndexPrivateData *priv = fdata->priv;
3002 if (!mutt_select_sort(event->op == OP_SORT_REVERSE))
3003 return FR_ERROR;
3004
3005 if (shared->mailbox && (shared->mailbox->msg_count != 0))
3006 {
3009 }
3010
3011 return FR_SUCCESS;
3012}
3013
3017static int op_tag(struct IndexFunctionData *fdata, const struct KeyEvent *event)
3018{
3019 struct IndexSharedData *shared = fdata->shared;
3020 struct IndexPrivateData *priv = fdata->priv;
3021 const bool c_auto_tag = cs_subset_bool(shared->sub, "auto_tag");
3022 if (priv->tag_prefix && !c_auto_tag)
3023 {
3024 struct Mailbox *m = shared->mailbox;
3025 for (size_t i = 0; i < m->msg_count; i++)
3026 {
3027 struct Email *e = m->emails[i];
3028 if (!e)
3029 break;
3030 if (e->visible)
3031 mutt_set_flag(m, e, MUTT_TAG, false, true);
3032 }
3034 return FR_SUCCESS;
3035 }
3036
3037 if (!shared->email)
3038 return FR_NO_ACTION;
3039
3040 int count = MAX(event->count, 1);
3041 int current_index = menu_get_index(priv->menu);
3042
3043 for (int i = 0; i < count && current_index + i < shared->mailbox->vcount; i++)
3044 {
3045 struct Email *e = mutt_get_virt_email(shared->mailbox, current_index + i);
3046 if (e)
3047 mutt_set_flag(shared->mailbox, e, MUTT_TAG, !e->tagged, true);
3048 }
3049
3050 if (count > 0)
3051 resolve_email(priv, shared, RESOLVE_NEXT_EMAIL, count);
3052
3053 return FR_SUCCESS;
3054}
3055
3063static int op_tag_thread(struct IndexFunctionData *fdata, const struct KeyEvent *event)
3064{
3065 struct IndexSharedData *shared = fdata->shared;
3066 struct IndexPrivateData *priv = fdata->priv;
3067 if (!shared->email)
3068 return FR_NO_ACTION;
3069
3070 const int op = event->op;
3072 !shared->email->tagged, (op != OP_TAG_THREAD));
3073 if (rc != -1)
3074 {
3075 const enum ResolveMethod rm = (op == OP_TAG_THREAD) ? RESOLVE_NEXT_THREAD :
3077 resolve_email(priv, shared, rm, 1);
3079 }
3080
3081 return FR_SUCCESS;
3082}
3083
3087static int op_toggle_new(struct IndexFunctionData *fdata, const struct KeyEvent *event)
3088{
3089 struct IndexSharedData *shared = fdata->shared;
3090 struct IndexPrivateData *priv = fdata->priv;
3091 /* L10N: CHECK_ACL */
3092 if (!check_acl(shared->mailbox, MUTT_ACL_SEEN, _("Can't toggle new")))
3093 return FR_ERROR;
3094
3095 struct Mailbox *m = shared->mailbox;
3096 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
3097 ea_add_selection(&ea, shared->mailbox_view, shared->email, priv->tag_prefix,
3098 event->count);
3099 if (ARRAY_EMPTY(&ea))
3100 {
3101 ARRAY_FREE(&ea);
3102 return FR_NO_ACTION;
3103 }
3104 const int num = ARRAY_SIZE(&ea);
3105
3106 struct Email **ep = NULL;
3107 ARRAY_FOREACH(ep, &ea)
3108 {
3109 if ((*ep)->read || (*ep)->old)
3110 mutt_set_flag(m, *ep, MUTT_NEW, true, true);
3111 else
3112 mutt_set_flag(m, *ep, MUTT_READ, true, true);
3113 }
3114 ARRAY_FREE(&ea);
3115
3116 if (priv->tag_prefix)
3117 {
3119 }
3120 else
3121 {
3122 resolve_email(priv, shared, RESOLVE_NEXT_UNDELETED, num);
3123 if (num > 1)
3125 }
3126
3127 return FR_SUCCESS;
3128}
3129
3133static int op_toggle_write(struct IndexFunctionData *fdata, const struct KeyEvent *event)
3134{
3135 struct IndexSharedData *shared = fdata->shared;
3136 mx_toggle_write(shared->mailbox);
3137 return FR_SUCCESS;
3138}
3139
3143static int op_undelete(struct IndexFunctionData *fdata, const struct KeyEvent *event)
3144{
3145 struct IndexSharedData *shared = fdata->shared;
3146 struct IndexPrivateData *priv = fdata->priv;
3147 /* L10N: CHECK_ACL */
3148 if (!check_acl(shared->mailbox, MUTT_ACL_DELETE, _("Can't undelete message")))
3149 return FR_ERROR;
3150
3151 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
3152 ea_add_selection(&ea, shared->mailbox_view, shared->email, priv->tag_prefix,
3153 event->count);
3154 if (ARRAY_EMPTY(&ea))
3155 {
3156 ARRAY_FREE(&ea);
3157 return FR_NO_ACTION;
3158 }
3159 const int num = ARRAY_SIZE(&ea);
3160
3161 mutt_emails_set_flag(shared->mailbox, &ea, MUTT_DELETE, false);
3162 mutt_emails_set_flag(shared->mailbox, &ea, MUTT_PURGE, false);
3163 ARRAY_FREE(&ea);
3164
3165 if (priv->tag_prefix)
3166 {
3168 }
3169 else
3170 {
3171 resolve_email(priv, shared, RESOLVE_NEXT_EMAIL, num);
3172 if (num > 1)
3174 }
3175
3176 return FR_SUCCESS;
3177}
3178
3186static int op_undelete_thread(struct IndexFunctionData *fdata, const struct KeyEvent *event)
3187{
3188 struct IndexSharedData *shared = fdata->shared;
3189 struct IndexPrivateData *priv = fdata->priv;
3190 /* L10N: CHECK_ACL */
3191 /* L10N: Due to the implementation details we do not know whether we
3192 undelete zero, 1, 12, ... messages. So in English we use
3193 "messages". Your language might have other means to express this. */
3194 if (!check_acl(shared->mailbox, MUTT_ACL_DELETE, _("Can't undelete messages")))
3195 return FR_ERROR;
3196
3197 const int op = event->op;
3198 const bool subthread = (op != OP_UNDELETE_THREAD);
3199 int rc = 0;
3200 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
3201 ea_add_selection_threads(&ea, shared->mailbox_view, shared->email,
3202 priv->tag_prefix, subthread, event->count);
3203 const int num = ARRAY_SIZE(&ea);
3204
3205 struct Email **ep = NULL;
3206 ARRAY_FOREACH(ep, &ea)
3207 {
3208 rc = mutt_thread_set_flag(shared->mailbox, *ep, MUTT_DELETE, false, subthread);
3209 if (rc == -1)
3210 break;
3211 rc = mutt_thread_set_flag(shared->mailbox, *ep, MUTT_PURGE, false, subthread);
3212 if (rc == -1)
3213 break;
3214 }
3215 ARRAY_FREE(&ea);
3216
3217 if (rc == -1)
3218 return FR_ERROR;
3219
3220 if (priv->tag_prefix)
3221 {
3223 return FR_SUCCESS;
3224 }
3225
3226 const enum ResolveMethod rm = (op == OP_UNDELETE_THREAD) ? RESOLVE_NEXT_THREAD :
3228 resolve_email(priv, shared, rm, num);
3230 return FR_SUCCESS;
3231}
3232
3236static int op_view_attachments(struct IndexFunctionData *fdata, const struct KeyEvent *event)
3237{
3238 struct IndexSharedData *shared = fdata->shared;
3239 struct IndexPrivateData *priv = fdata->priv;
3240 if (!shared->email)
3241 return FR_NO_ACTION;
3242
3243 enum FunctionRetval rc = FR_ERROR;
3244 struct Message *msg = mx_msg_open(shared->mailbox, shared->email);
3245 if (msg)
3246 {
3247 dlg_attach(fdata->n->sub, shared->mailbox_view, shared->email, msg->fp,
3248 shared->attach_msg);
3249 if (shared->email->attach_del)
3250 {
3251 shared->mailbox->changed = true;
3252 }
3253 mx_msg_close(shared->mailbox, &msg);
3254 rc = FR_SUCCESS;
3255 }
3257 return rc;
3258}
3259
3260// -----------------------------------------------------------------------------
3261
3262#ifdef USE_AUTOCRYPT
3266static int op_autocrypt_acct_menu(struct IndexFunctionData *fdata, const struct KeyEvent *event)
3267{
3268 dlg_autocrypt();
3269 return FR_SUCCESS;
3270}
3271#endif
3272
3276static int op_main_imap_fetch(struct IndexFunctionData *fdata, const struct KeyEvent *event)
3277{
3278 struct IndexSharedData *shared = fdata->shared;
3279 if (!shared->mailbox || (shared->mailbox->type != MUTT_IMAP))
3280 return FR_NO_ACTION;
3281
3282 imap_check_mailbox(shared->mailbox, true);
3283 return FR_SUCCESS;
3284}
3285
3289static int op_main_imap_logout_all(struct IndexFunctionData *fdata, const struct KeyEvent *event)
3290{
3291 struct IndexSharedData *shared = fdata->shared;
3292 struct IndexPrivateData *priv = fdata->priv;
3293 if (shared->mailbox && (shared->mailbox->type == MUTT_IMAP))
3294 {
3295 const enum MxStatus check = mx_mbox_close(shared->mailbox);
3296 if (check == MX_STATUS_OK)
3297 {
3299 }
3300 else
3301 {
3302 if ((check == MX_STATUS_NEW_MAIL) || (check == MX_STATUS_REOPENED))
3303 {
3304 update_index(priv->menu, shared->mailbox_view, check, priv->oldcount, shared);
3305 }
3308 return FR_ERROR;
3309 }
3310 }
3312 mutt_message(_("Logged out of IMAP servers"));
3315
3316 return FR_SUCCESS;
3317}
3318
3322static int op_catchup(struct IndexFunctionData *fdata, const struct KeyEvent *event)
3323{
3324 struct IndexSharedData *shared = fdata->shared;
3325 struct IndexPrivateData *priv = fdata->priv;
3326 struct Mailbox *m = shared->mailbox;
3327 if (!m || (m->type != MUTT_NNTP))
3328 return FR_NO_ACTION;
3329
3330 struct NntpMboxData *mdata = m->mdata;
3331 if (mutt_newsgroup_catchup(m, mdata->adata, mdata->group))
3333
3334 return FR_SUCCESS;
3335}
3336
3344static int op_get_children(struct IndexFunctionData *fdata, const struct KeyEvent *event)
3345{
3346 struct IndexSharedData *shared = fdata->shared;
3347 struct IndexPrivateData *priv = fdata->priv;
3348 struct Mailbox *m = shared->mailbox;
3349 if (m->type != MUTT_NNTP)
3350 return FR_ERROR;
3351
3352 struct Email *e = shared->email;
3353 if (!e)
3354 return FR_NO_ACTION;
3355
3356 char buf[PATH_MAX] = { 0 };
3357 int oldmsgcount = m->msg_count;
3358 int oldindex = e->index;
3359 int rc = 0;
3360
3361 if (!e->env->message_id)
3362 {
3363 mutt_error(_("No Message-ID. Unable to perform operation."));
3364 return FR_ERROR;
3365 }
3366
3367 mutt_message(_("Fetching message headers..."));
3368 if (!m->id_hash)
3369 m->id_hash = mutt_make_id_hash(m);
3370 mutt_str_copy(buf, e->env->message_id, sizeof(buf));
3371
3372 const int op = event->op;
3373 /* trying to find msgid of the root message */
3374 if (op == OP_RECONSTRUCT_THREAD)
3375 {
3376 struct ListNode *ref = NULL;
3377 STAILQ_FOREACH(ref, &e->env->references, entries)
3378 {
3379 if (!mutt_hash_find(m->id_hash, ref->data))
3380 {
3381 rc = nntp_check_msgid(m, ref->data);
3382 if (rc < 0)
3383 return FR_ERROR;
3384 }
3385
3386 /* the last msgid in References is the root message */
3387 if (!STAILQ_NEXT(ref, entries))
3388 mutt_str_copy(buf, ref->data, sizeof(buf));
3389 }
3390 }
3391
3392 /* fetching all child messages */
3393 rc = nntp_check_children(m, buf);
3394
3395 /* at least one message has been loaded */
3396 if (m->msg_count > oldmsgcount)
3397 {
3398 bool verbose = m->verbose;
3399
3400 if (rc < 0)
3401 m->verbose = false;
3402
3403 struct MailboxView *mv = shared->mailbox_view;
3404 mutt_sort_headers(mv, (op == OP_RECONSTRUCT_THREAD));
3405 m->verbose = verbose;
3406
3407 /* if the root message was retrieved, move to it */
3408 struct Email *e2 = mutt_hash_find(m->id_hash, buf);
3409 if (e2)
3410 {
3411 menu_set_index(priv->menu, e2->vnum);
3412 }
3413 else
3414 {
3415 /* try to restore old position */
3416 for (int i = 0; i < m->msg_count; i++)
3417 {
3418 e2 = m->emails[i];
3419 if (!e2)
3420 break;
3421 if (e2->index == oldindex)
3422 {
3423 menu_set_index(priv->menu, e2->vnum);
3424 /* as an added courtesy, recenter the menu
3425 * with the current entry at the middle of the screen */
3427 }
3428 }
3429 }
3431 }
3432 else if (rc >= 0)
3433 {
3434 mutt_error(_("No deleted messages found in the thread"));
3435 return FR_ERROR;
3436 }
3437
3438 return FR_SUCCESS;
3439}
3440
3448static int op_get_message(struct IndexFunctionData *fdata, const struct KeyEvent *event)
3449{
3450 struct IndexSharedData *shared = fdata->shared;
3451 struct IndexPrivateData *priv = fdata->priv;
3452 struct Mailbox *m = shared->mailbox;
3453 if (m->type != MUTT_NNTP)
3454 return FR_SUCCESS;
3455
3456 int rc = FR_ERROR;
3457 struct Buffer *buf = buf_pool_get();
3458
3459 const int op = event->op;
3460 if (op == OP_GET_MESSAGE)
3461 {
3462 if ((mw_get_field(_("Enter Message-ID: "), buf, MUTT_COMP_NONE, HC_OTHER, NULL, NULL) != 0) ||
3463 buf_is_empty(buf))
3464 {
3465 goto done;
3466 }
3467 }
3468 else
3469 {
3470 struct Email *e = shared->email;
3471 if (!e || STAILQ_EMPTY(&e->env->references))
3472 {
3473 mutt_error(_("Article has no parent reference"));
3474 goto done;
3475 }
3477 }
3478
3479 if (!m->id_hash)
3480 m->id_hash = mutt_make_id_hash(m);
3481 struct Email *e = mutt_hash_find(m->id_hash, buf_string(buf));
3482 if (e)
3483 {
3484 if (e->vnum != -1)
3485 {
3486 menu_set_index(priv->menu, e->vnum);
3487 }
3488 else if (e->collapsed)
3489 {
3491 mutt_set_vnum(m);
3492 menu_set_index(priv->menu, e->vnum);
3493 }
3494 else
3495 {
3496 mutt_error(_("Message is not visible in limited view"));
3497 }
3498 }
3499 else
3500 {
3501 mutt_message(_("Fetching %s from server..."), buf_string(buf));
3502 int rc2 = nntp_check_msgid(m, buf_string(buf));
3503 if (rc2 == 0)
3504 {
3505 e = m->emails[m->msg_count - 1];
3506 struct MailboxView *mv = shared->mailbox_view;
3507 mutt_sort_headers(mv, false);
3508 menu_set_index(priv->menu, e->vnum);
3510 rc = FR_SUCCESS;
3511 }
3512 else if (rc2 > 0)
3513 {
3514 mutt_error(_("Article %s not found on the server"), buf_string(buf));
3515 }
3516 }
3517
3518done:
3519 buf_pool_release(&buf);
3520 return rc;
3521}
3522
3530static int op_main_change_group(struct IndexFunctionData *fdata, const struct KeyEvent *event)
3531{
3533 struct IndexSharedData *shared = fdata->shared;
3534 struct IndexPrivateData *priv = fdata->priv;
3535 struct Buffer *folderbuf = buf_pool_get();
3536 buf_alloc(folderbuf, PATH_MAX);
3537
3538 OptNews = false;
3539 bool read_only;
3540 char *cp = NULL;
3541 const bool c_read_only = cs_subset_bool(shared->sub, "read_only");
3542 const int op = event->op;
3543 if (shared->attach_msg || c_read_only || (op == OP_MAIN_CHANGE_GROUP_READONLY))
3544 {
3545 cp = _("Open newsgroup in read-only mode");
3546 read_only = true;
3547 }
3548 else
3549 {
3550 cp = _("Open newsgroup");
3551 read_only = false;
3552 }
3553
3554 const bool c_change_folder_next = cs_subset_bool(shared->sub, "change_folder_next");
3555 if (c_change_folder_next && shared->mailbox && !buf_is_empty(&shared->mailbox->pathbuf))
3556 {
3557 buf_strcpy(folderbuf, mailbox_path(shared->mailbox));
3558 pretty_mailbox(folderbuf);
3559 }
3560
3561 OptNews = true;
3562 const char *const c_news_server = cs_subset_string(shared->sub, "news_server");
3563 if (!mod_data->current_news_srv)
3564 mod_data->current_news_srv = nntp_select_server(shared->mailbox, c_news_server, false);
3565 if (!mod_data->current_news_srv)
3566 goto changefoldercleanup2;
3567
3568 nntp_mailbox(shared->mailbox, folderbuf->data, folderbuf->dsize);
3569
3570 if (mw_enter_fname(cp, folderbuf, true, shared->mailbox, false, NULL, NULL,
3571 MUTT_SEL_NONE) == -1)
3572 {
3573 goto changefoldercleanup2;
3574 }
3575
3576 /* Selected directory is okay, let's save it. */
3578
3579 if (buf_is_empty(folderbuf))
3580 {
3581 msgwin_clear_text(NULL);
3582 goto changefoldercleanup2;
3583 }
3584
3585 struct Mailbox *m = mx_mbox_find2(buf_string(folderbuf));
3586 if (m)
3587 {
3588 change_folder_mailbox(priv->menu, m, &priv->oldcount, shared, read_only);
3589 }
3590 else
3591 {
3592 change_folder_string(priv->menu, folderbuf, &priv->oldcount, shared, read_only);
3593 }
3594 struct MuttWindow *dlg = dialog_find(priv->win_index);
3595 dlg->help_data = IndexNewsHelp;
3596
3597changefoldercleanup2:
3598 buf_pool_release(&folderbuf);
3599 return FR_SUCCESS;
3600}
3601
3610static int op_post(struct IndexFunctionData *fdata, const struct KeyEvent *event)
3611{
3612 struct IndexSharedData *shared = fdata->shared;
3613 struct IndexPrivateData *priv = fdata->priv;
3614 if (!shared->email)
3615 return FR_NO_ACTION;
3616
3617 const int op = event->op;
3618 if ((op != OP_FOLLOWUP) || !shared->email->env->followup_to ||
3619 !mutt_istr_equal(shared->email->env->followup_to, "poster") ||
3620 (query_quadoption(_("Reply by mail as poster prefers?"), shared->sub,
3621 "followup_to_poster") != MUTT_YES))
3622 {
3623 if (shared->mailbox && (shared->mailbox->type == MUTT_NNTP) &&
3624 !((struct NntpMboxData *) shared->mailbox->mdata)->allowed &&
3625 (query_quadoption(_("Posting to this group not allowed, may be moderated. Continue?"),
3626 shared->sub, "post_moderated") != MUTT_YES))
3627 {
3628 return FR_ERROR;
3629 }
3630 if (op == OP_POST)
3631 {
3632 mutt_send_message(SEND_NEWS, NULL, NULL, shared->mailbox, NULL, shared->sub);
3633 }
3634 else
3635 {
3636 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
3637 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
3638 mutt_send_message(((op == OP_FOLLOWUP) ? SEND_REPLY : SEND_FORWARD) | SEND_NEWS,
3639 NULL, NULL, shared->mailbox, &ea, shared->sub);
3640 ARRAY_FREE(&ea);
3641 }
3643 return FR_SUCCESS;
3644 }
3645
3646 struct KeyEvent event_r = { 0, OP_REPLY };
3647 return op_reply(fdata, &event_r);
3648}
3649
3650#ifdef USE_NOTMUCH
3654static int op_main_entire_thread(struct IndexFunctionData *fdata, const struct KeyEvent *event)
3655{
3656 struct IndexSharedData *shared = fdata->shared;
3657 struct IndexPrivateData *priv = fdata->priv;
3659 {
3660 if (!shared->email || !shared->email->env || !shared->email->env->message_id)
3661 {
3662 mutt_message(_("No virtual folder and no Message-ID, aborting"));
3663 return FR_ERROR;
3664 } // no virtual folder, but we have Message-ID, reconstruct thread on-the-fly
3665
3666 struct Buffer *buf = buf_pool_get();
3667 buf_alloc(buf, PATH_MAX);
3668 buf_addstr(buf, "id:");
3669
3670 int msg_id_offset = 0;
3671 if ((shared->email->env->message_id)[0] == '<')
3672 msg_id_offset = 1;
3673
3674 buf_addstr(buf, shared->email->env->message_id + msg_id_offset);
3675
3676 size_t len = buf_len(buf);
3677 ASSERT(len > 0);
3678 if (buf->data[len - 1] == '>')
3679 buf->data[len - 1] = '\0';
3680
3681 change_folder_notmuch(priv->menu, buf->data, buf->dsize, &priv->oldcount, shared, false);
3682 buf_pool_release(&buf);
3683
3684 // If notmuch doesn't contain the message, we're left in an empty
3685 // vfolder. No messages are found, but nm_read_entire_thread assumes
3686 // a valid Message-ID and will throw a segfault.
3687 //
3688 // To prevent that, stay in the empty vfolder and print an error.
3689 if (!shared->mailbox)
3690 return FR_ERROR;
3691
3692 if (shared->mailbox->msg_count == 0)
3693 {
3694 mutt_error(_("failed to find message in notmuch database. try running 'notmuch new'."));
3695 return FR_ERROR;
3696 }
3697 }
3698 priv->oldcount = shared->mailbox->msg_count;
3699 int index = menu_get_index(priv->menu);
3700 struct Email *e_oldcur = mutt_get_virt_email(shared->mailbox, index);
3701 if (!e_oldcur)
3702 return FR_ERROR;
3703
3704 if (nm_read_entire_thread(shared->mailbox, e_oldcur) < 0)
3705 {
3706 mutt_message(_("Failed to read thread, aborting"));
3707 return FR_ERROR;
3708 }
3709
3710 // nm_read_entire_thread() may modify msg_count and menu won't be updated.
3711 priv->menu->max = shared->mailbox->msg_count;
3712
3713 if (priv->oldcount < shared->mailbox->msg_count)
3714 {
3715 /* nm_read_entire_thread() triggers mutt_sort_headers() if necessary */
3716 index = e_oldcur->vnum;
3717 if (e_oldcur->collapsed || shared->mailbox_view->collapsed)
3718 {
3719 index = mutt_uncollapse_thread(e_oldcur);
3720 mutt_set_vnum(shared->mailbox);
3721 }
3722 menu_set_index(priv->menu, index);
3724 }
3725
3726 return FR_SUCCESS;
3727}
3728
3737 const struct KeyEvent *event)
3738{
3739 struct IndexSharedData *shared = fdata->shared;
3740 struct IndexPrivateData *priv = fdata->priv;
3741 int rc = FR_SUCCESS;
3742 struct Buffer *buf = buf_pool_get();
3743
3744 if ((mw_get_field("Query: ", buf, MUTT_COMP_NONE, HC_OTHER, &CompleteNmQueryOps, NULL) != 0) ||
3745 buf_is_empty(buf))
3746 {
3747 mutt_message(_("No query, aborting"));
3748 rc = FR_NO_ACTION;
3749 goto done;
3750 }
3751
3752 // Keep copy of user's query to name the mailbox
3753 char *query_unencoded = buf_strdup(buf);
3754
3755 buf_alloc(buf, PATH_MAX);
3756 const int op = event->op;
3757 struct Mailbox *m_query = change_folder_notmuch(priv->menu, buf->data, buf->dsize,
3758 &priv->oldcount, shared,
3759 (op == OP_MAIN_VFOLDER_FROM_QUERY_READONLY));
3760 if (m_query)
3761 {
3762 FREE(&m_query->name);
3763 m_query->name = query_unencoded;
3764 query_unencoded = NULL;
3765 rc = FR_SUCCESS;
3766 }
3767 else
3768 {
3769 FREE(&query_unencoded);
3770 }
3771
3772done:
3773 buf_pool_release(&buf);
3774 return rc;
3775}
3776
3786 const struct KeyEvent *event)
3787{
3788 struct IndexSharedData *shared = fdata->shared;
3789 struct IndexPrivateData *priv = fdata->priv;
3790 // Common guard clauses.
3792 {
3793 mutt_message(_("Windowed queries disabled"));
3794 return FR_ERROR;
3795 }
3796 const char *const c_nm_query_window_current_search = cs_subset_string(shared->sub, "nm_query_window_current_search");
3797 if (!c_nm_query_window_current_search)
3798 {
3799 mutt_message(_("No notmuch vfolder currently loaded"));
3800 return FR_ERROR;
3801 }
3802
3803 // Call the specific operation.
3804 switch (event->op)
3805 {
3806 case OP_MAIN_WINDOWED_VFOLDER_BACKWARD:
3808 break;
3809 case OP_MAIN_WINDOWED_VFOLDER_FORWARD:
3811 break;
3812 case OP_MAIN_WINDOWED_VFOLDER_RESET:
3814 break;
3815 }
3816
3817 // Common query window folder change.
3818 char buf[PATH_MAX] = { 0 };
3819 mutt_str_copy(buf, c_nm_query_window_current_search, sizeof(buf));
3820 change_folder_notmuch(priv->menu, buf, sizeof(buf), &priv->oldcount, shared, false);
3821
3822 return FR_SUCCESS;
3823}
3824#endif
3825
3829static int op_main_fetch_mail(struct IndexFunctionData *fdata, const struct KeyEvent *event)
3830{
3831 struct IndexPrivateData *priv = fdata->priv;
3834 return FR_SUCCESS;
3835}
3836
3837// -----------------------------------------------------------------------------
3838
3846static bool prereq(struct IndexSharedData *shared, struct Menu *menu, CheckFlags checks)
3847{
3848 bool result = true;
3849 struct MailboxView *mv = shared->mailbox_view;
3850
3851 if (checks & (CHECK_MSGCOUNT | CHECK_VISIBLE | CHECK_READONLY))
3852 checks |= CHECK_IN_MAILBOX;
3853
3854 if ((checks & CHECK_IN_MAILBOX) && (!mv || !mv->mailbox))
3855 {
3856 mutt_error(_("No mailbox is open"));
3857 result = false;
3858 }
3859
3860 if (result && (checks & CHECK_MSGCOUNT) && (mv->mailbox->msg_count == 0))
3861 {
3862 mutt_error(_("There are no messages"));
3863 result = false;
3864 }
3865
3866 int index = menu_get_index(menu);
3867 if (result && (checks & CHECK_VISIBLE) &&
3868 ((index < 0) || (index >= mv->mailbox->vcount)))
3869 {
3870 mutt_error(_("No visible messages"));
3871 result = false;
3872 }
3873
3874 if (result && (checks & CHECK_READONLY) && mv->mailbox->readonly)
3875 {
3876 mutt_error(_("Mailbox is read-only"));
3877 result = false;
3878 }
3879
3880 if (result && (checks & CHECK_ATTACH) && shared->attach_msg)
3881 {
3882 mutt_error(_("Function not permitted in attach-message mode"));
3883 result = false;
3884 }
3885
3886 if (!result)
3887 mutt_flushinp();
3888
3889 return result;
3890}
3891
3895static const struct IndexFunction IndexFunctions[] = {
3896 // clang-format off
3897 { OP_ALIAS_DIALOG, op_alias_dialog, CHECK_NONE },
3903 { OP_COPY_MESSAGE, op_save, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3904 { OP_CREATE_ALIAS, op_create_alias, CHECK_NONE },
3905 { OP_DECODE_COPY, op_save, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3906 { OP_DECODE_SAVE, op_save, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3907 { OP_DECRYPT_COPY, op_save, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3908 { OP_DECRYPT_SAVE, op_save, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3916 { OP_EDIT_OR_VIEW_RAW_MESSAGE, op_edit_raw_message, CHECK_ATTACH | CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3918 { OP_END_COND, op_end_cond, CHECK_NONE },
3919 { OP_EXIT, op_exit, CHECK_NONE },
3924 { OP_FORWARD_TO_GROUP, op_post, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3926 { OP_GET_MESSAGE, op_get_message, CHECK_ATTACH | CHECK_IN_MAILBOX },
3928 { OP_GENERIC_SELECT_ENTRY, op_display_message, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3931 { OP_JUMP, op_jump, CHECK_IN_MAILBOX },
3932 { OP_LIMIT_CURRENT_THREAD, op_main_limit, CHECK_IN_MAILBOX },
3937 { OP_MAIL, op_mail, CHECK_ATTACH },
3938 { OP_MAILBOX_LIST, op_mailbox_list, CHECK_NONE },
3939 { OP_MAIL_KEY, op_mail_key, CHECK_ATTACH },
3941 { OP_MAIN_CHANGE_FOLDER, op_main_change_folder, CHECK_NONE },
3942 { OP_MAIN_CHANGE_FOLDER_READONLY, op_main_change_folder, CHECK_NONE },
3943 { OP_MAIN_CHANGE_GROUP, op_main_change_group, CHECK_NONE },
3944 { OP_MAIN_CHANGE_GROUP_READONLY, op_main_change_group, CHECK_NONE },
3946 { OP_MAIN_CLOSE_ALL_THREADS, op_main_close_all_threads, CHECK_IN_MAILBOX },
3948 { OP_MAIN_COLLAPSE_ALL, op_main_collapse_all, CHECK_IN_MAILBOX },
3949 { OP_MAIN_COLLAPSE_THREAD, op_main_collapse_thread, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3950 { OP_MAIN_DELETE_PATTERN, op_main_delete_pattern, CHECK_ATTACH | CHECK_IN_MAILBOX | CHECK_READONLY },
3951 { OP_MAIN_FETCH_MAIL, op_main_fetch_mail, CHECK_ATTACH },
3952 { OP_MAIN_IMAP_FETCH, op_main_imap_fetch, CHECK_NONE },
3953 { OP_MAIN_IMAP_LOGOUT_ALL, op_main_imap_logout_all, CHECK_NONE },
3954 { OP_MAIN_LIMIT, op_main_limit, CHECK_IN_MAILBOX },
3957 { OP_MAIN_MODIFY_TAGS_THEN_HIDE, op_main_modify_tags, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_READONLY | CHECK_VISIBLE },
3959 { OP_MAIN_NEXT_NEW_THEN_UNREAD, op_main_next_new, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3960 { OP_MAIN_NEXT_SUBTHREAD, op_main_next_thread, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3963 { OP_MAIN_NEXT_UNREAD, op_main_next_new, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3964 { OP_MAIN_NEXT_UNREAD_MAILBOX, op_main_next_unread_mailbox, CHECK_IN_MAILBOX },
3965 { OP_MAIN_PREV_UNREAD_MAILBOX, op_main_prev_unread_mailbox, CHECK_IN_MAILBOX },
3966 { OP_MAIN_OPEN_ALL_THREADS, op_main_open_all_threads, CHECK_IN_MAILBOX },
3968 { OP_MAIN_PARENT_MESSAGE, op_main_root_message, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3970 { OP_MAIN_PREV_NEW_THEN_UNREAD, op_main_next_new, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3971 { OP_MAIN_PREV_SUBTHREAD, op_main_next_thread, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3974 { OP_MAIN_PREV_UNREAD, op_main_next_new, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3980 { OP_MAIN_SHOW_LIMIT, op_main_show_limit, CHECK_IN_MAILBOX },
3981 { OP_MAIN_SYNC_FOLDER, op_main_sync_folder, CHECK_NONE },
3982 { OP_MAIN_TAG_PATTERN, op_main_tag_pattern, CHECK_IN_MAILBOX },
3983 { OP_MAIN_UNDELETE_PATTERN, op_main_undelete_pattern, CHECK_IN_MAILBOX | CHECK_READONLY },
3984 { OP_MAIN_UNTAG_PATTERN, op_main_untag_pattern, CHECK_IN_MAILBOX },
3988 { OP_POST, op_post, CHECK_ATTACH | CHECK_IN_MAILBOX },
3993 { OP_QUERY, op_query, CHECK_ATTACH },
3994 { OP_QUIT, op_quit, CHECK_NONE },
3995 { OP_RECALL_MESSAGE, op_recall_message, CHECK_ATTACH },
4000 { OP_SEARCH, op_search, CHECK_IN_MAILBOX },
4001 { OP_SEARCH_NEXT, op_search, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
4002 { OP_SEARCH_OPPOSITE, op_search, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
4003 { OP_SEARCH_REVERSE, op_search, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
4004 { OP_SORT, op_sort, CHECK_NONE },
4005 { OP_SORT_REVERSE, op_sort, CHECK_NONE },
4010 { OP_TOGGLE_READ, op_main_limit, CHECK_IN_MAILBOX },
4011 { OP_TOGGLE_WRITE, op_toggle_write, CHECK_IN_MAILBOX },
4017#ifdef USE_AUTOCRYPT
4018 { OP_AUTOCRYPT_ACCT_MENU, op_autocrypt_acct_menu, CHECK_NONE },
4019#endif
4020#ifdef USE_NOTMUCH
4021 { OP_MAIN_CHANGE_VFOLDER, op_main_change_folder, CHECK_NONE },
4023 { OP_MAIN_VFOLDER_FROM_QUERY, op_main_vfolder_from_query, CHECK_NONE },
4024 { OP_MAIN_VFOLDER_FROM_QUERY_READONLY, op_main_vfolder_from_query, CHECK_NONE },
4025 { OP_MAIN_WINDOWED_VFOLDER_BACKWARD, op_main_windowed_vfolder, CHECK_IN_MAILBOX },
4026 { OP_MAIN_WINDOWED_VFOLDER_FORWARD, op_main_windowed_vfolder, CHECK_IN_MAILBOX },
4027 { OP_MAIN_WINDOWED_VFOLDER_RESET, op_main_windowed_vfolder, CHECK_IN_MAILBOX },
4028#endif
4029 { 0, NULL, CHECK_NONE },
4030 // clang-format on
4031};
4032
4036int index_function_dispatcher(struct MuttWindow *win, const struct KeyEvent *event)
4037{
4038 // The Dispatcher may be called on any Window in the Dialog
4039 struct MuttWindow *dlg = dialog_find(win);
4040 if (!event || !dlg || !dlg->wdata || !win->parent || !win->parent->wdata)
4041 {
4043 return FR_ERROR;
4044 }
4045
4046 const int op = event->op;
4047 struct IndexPrivateData *priv = win->parent->wdata;
4048 struct IndexSharedData *shared = dlg->wdata;
4049
4051
4052 struct IndexFunctionData fdata = {
4053 .n = NeoMutt,
4054 .mod_data = mod_data,
4055 .shared = shared,
4056 .priv = priv,
4057 };
4058
4059 int rc = FR_UNKNOWN;
4060 for (size_t i = 0; IndexFunctions[i].op != OP_NULL; i++)
4061 {
4062 const struct IndexFunction *fn = &IndexFunctions[i];
4063 if (fn->op == op)
4064 {
4065 if (!prereq(shared, priv->menu, fn->flags))
4066 {
4067 rc = FR_ERROR;
4068 break;
4069 }
4070 rc = fn->function(&fdata, event);
4071 break;
4072 }
4073 }
4074
4075 if (rc == FR_UNKNOWN) // Not our function
4076 return rc;
4077
4078 const char *result = dispatcher_get_retval_name(rc);
4079 mutt_debug(LL_DEBUG1, "Handled %s (%d) -> %s\n", opcodes_get_name(op), op, NONULL(result));
4080
4082 return rc;
4083}
4084
4090{
4092 ASSERT(mod_data);
4093
4094 return mod_data->md_index;
4095}
Email Aliases.
void alias_create(struct AddressList *al, const struct ConfigSubset *sub)
Create a new Alias from an Address.
Definition alias.c:369
struct AddressList * mutt_get_address(struct Envelope *env, const char **prefix)
Get an Address from an Envelope.
Definition alias.c:329
#define ARRAY_ADD(head, elem)
Add an element at the end of the array.
Definition array.h:157
#define ARRAY_REMOVE(head, elem)
Remove an entry from the array, shifting down the subsequent entries.
Definition array.h:355
#define ARRAY_FOREACH(elem, head)
Iterate over all elements of the array.
Definition array.h:223
#define ARRAY_EMPTY(head)
Check if an array is empty.
Definition array.h:74
#define ARRAY_SIZE(head)
The number of elements stored.
Definition array.h:87
#define ARRAY_FREE(head)
Release all memory.
Definition array.h:209
#define ARRAY_GET(head, idx)
Return the element at index.
Definition array.h:109
#define ARRAY_HEAD_INITIALIZER
Static initializer for arrays.
Definition array.h:58
GUI display the mailboxes in a side panel.
Autocrypt end-to-end encryption.
int bool_str_toggle(struct ConfigSubset *sub, const char *name, struct Buffer *err)
Toggle the value of a bool.
Definition bool.c:231
Select a Mailbox from a list.
@ MUTT_SEL_NONE
No flags are set.
Definition lib.h:59
int buf_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition buffer.c:168
size_t buf_len(const struct Buffer *buf)
Calculate the length of a Buffer.
Definition buffer.c:497
bool buf_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition buffer.c:298
size_t buf_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition buffer.c:233
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition buffer.c:401
char * buf_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition buffer.c:577
void buf_alloc(struct Buffer *buf, size_t new_size)
Make sure a buffer can store at least new_size bytes.
Definition buffer.c:342
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition buffer.h:96
@ CMD_SHUTDOWN_HOOK
:shutdown-hook
Definition command.h:113
@ CMD_MESSAGE_HOOK
:message-hook
Definition command.h:97
void mutt_pattern_free(struct PatternList **pat)
Free a Pattern.
Definition compile.c:836
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition helpers.c:291
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition helpers.c:47
Convenience wrapper for the config headers.
Convenience wrapper for the core headers.
void mailbox_free(struct Mailbox **ptr)
Free a Mailbox.
Definition mailbox.c:90
@ NT_MAILBOX_CHANGE
Mailbox has been changed.
Definition mailbox.h:178
@ MUTT_ACL_WRITE
Write to a message (for flagging or linking threads)
Definition mailbox.h:71
@ MUTT_ACL_INSERT
Add/copy into the mailbox (used when editing a message)
Definition mailbox.h:66
@ MUTT_ACL_DELETE
Delete a message.
Definition mailbox.h:63
@ MUTT_ACL_SEEN
Change the 'seen' status of a message.
Definition mailbox.h:70
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox's path string.
Definition mailbox.h:216
@ MUTT_NOTMUCH
'Notmuch' (virtual) Mailbox type
Definition mailbox.h:50
@ MUTT_NNTP
'NNTP' (Usenet) Mailbox type
Definition mailbox.h:48
@ MUTT_IMAP
'IMAP' Mailbox type
Definition mailbox.h:49
void crypt_extract_keys_from_messages(struct Mailbox *m, struct EmailArray *ea)
Extract keys from a message.
Definition crypt.c:864
struct MuttWindow * dialog_find(struct MuttWindow *win)
Find the parent Dialog of a Window.
Definition dialog.c:89
const char * dispatcher_get_retval_name(int rv)
Get the name of a return value.
Definition dispatcher.c:55
void dispatcher_flush_on_error(int rv)
Flush pending keys after a dispatch error.
Definition dispatcher.c:65
FunctionRetval
Possible return values for NeoMutt functions.
Definition dispatcher.h:33
@ FR_SUCCESS
Valid function - successfully performed.
Definition dispatcher.h:40
@ FR_DONE
Exit the Dialog.
Definition dispatcher.h:36
@ FR_UNKNOWN
Unknown function.
Definition dispatcher.h:34
@ FR_ERROR
Valid function - error occurred.
Definition dispatcher.h:39
@ FR_NOT_IMPL
Invalid function - feature not enabled.
Definition dispatcher.h:37
@ FR_NO_ACTION
Valid function - no action performed.
Definition dispatcher.h:38
void alias_dialog(struct Mailbox *m, struct ConfigSubset *sub)
Open the aliases dialog.
Definition dlg_alias.c: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:358
bool OptNeedResort
(pseudo) used to force a re-sort
Definition globals.c:52
void mutt_break_thread(struct Email *e)
Break the email Thread.
Definition thread.c:229
struct Email * find_virtual(struct MuttThread *cur, bool reverse)
Find an email with a Virtual message number.
Definition thread.c:124
bool mutt_select_sort(bool reverse)
Ask the user for a sort method.
Definition external.c:475
void mutt_pipe_message(struct Mailbox *m, struct EmailArray *ea)
Pipe a message.
Definition external.c:404
bool mutt_check_traditional_pgp(struct Mailbox *m, struct EmailArray *ea)
Check if a message has inline PGP content.
Definition external.c: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
struct SubMenu * sidebar_get_submenu(void)
Get the Sidebar SubMenu.
void mutt_flushinp(void)
MacroEvents moved to KeyModuleData UngetKeyEvents moved to KeyModuleData.
Definition get.c:81
@ MFF_DEPRECATED
Function is deprecated.
Definition get.h:67
bool OptNews
(pseudo) used to change reader mode
Definition globals.c:53
Global variables.
static int op_quit(struct AliasFunctionData *fdata, const struct KeyEvent *event)
Save changes and exit this dialog - Implements alias_function_t -.
Definition functions.c:308
static int op_main_limit(struct AliasFunctionData *fdata, const struct KeyEvent *event)
show only messages matching a pattern - Implements alias_function_t -
Definition functions.c:407
static int op_query(struct AliasFunctionData *fdata, const struct KeyEvent *event)
query external program for addresses - Implements alias_function_t -
Definition functions.c:465
static int op_create_alias(struct AliasFunctionData *fdata, const struct KeyEvent *event)
create an alias from a message sender - Implements alias_function_t -
Definition functions.c:148
static int op_jump(struct AliasFunctionData *fdata, const struct KeyEvent *event)
Jump to an index number - Implements alias_function_t -.
Definition functions.c:316
static int op_main_untag_pattern(struct AliasFunctionData *fdata, const struct KeyEvent *event)
Untag messages matching a pattern - Implements alias_function_t -.
Definition functions.c:444
static int op_main_tag_pattern(struct AliasFunctionData *fdata, const struct KeyEvent *event)
Tag messages matching a pattern - Implements alias_function_t -.
Definition functions.c:427
static int op_mail(struct AliasFunctionData *fdata, const struct KeyEvent *event)
mail the selected entries - Implements alias_function_t -
Definition functions.c:399
static int op_delete(struct AliasFunctionData *fdata, const struct KeyEvent *event)
delete the current entry - Implements alias_function_t -
Definition functions.c:270
static int op_search(struct AliasFunctionData *fdata, const struct KeyEvent *event)
search for a regular expression - Implements alias_function_t -
Definition functions.c:519
static int op_sort(struct AliasFunctionData *fdata, const struct KeyEvent *event)
sort aliases - Implements alias_function_t -
Definition functions.c:557
static int op_list_unsubscribe(struct AttachFunctionData *fdata, const struct KeyEvent *event)
unsubscribe from a mailing list - Implements attach_function_t -
Definition functions.c:670
static int op_attach_edit_type(struct AttachFunctionData *fdata, const struct KeyEvent *event)
edit attachment content type - Implements attach_function_t -
Definition functions.c:391
static int op_resend(struct AttachFunctionData *fdata, const struct KeyEvent *event)
use the current message as a template for a new one - Implements attach_function_t -
Definition functions.c:714
static int op_forward_message(struct AttachFunctionData *fdata, const struct KeyEvent *event)
forward a message with comments - Implements attach_function_t -
Definition functions.c:642
static int op_compose_to_sender(struct AttachFunctionData *fdata, const struct KeyEvent *event)
compose new message to the current message sender - Implements attach_function_t -
Definition functions.c:586
static int op_list_subscribe(struct AttachFunctionData *fdata, const struct KeyEvent *event)
subscribe to a mailing list - Implements attach_function_t -
Definition functions.c:658
static int op_check_traditional(struct AttachFunctionData *fdata, const struct KeyEvent *event)
check for classic PGP - Implements attach_function_t -
Definition functions.c:569
static int op_extract_keys(struct AttachFunctionData *fdata, const struct KeyEvent *event)
extract supported public keys - Implements attach_function_t -
Definition functions.c:624
static int op_reply(struct AttachFunctionData *fdata, const struct KeyEvent *event)
reply to a message - Implements attach_function_t -
Definition functions.c:688
static int op_bounce_message(struct AttachFunctionData *fdata, const struct KeyEvent *event)
remail a message to another user - Implements attach_function_t -
Definition functions.c:553
static int op_mailbox_list(struct BrowserPrivateData *priv, const struct KeyEvent *event)
List mailboxes with new mail - Implements browser_function_t -.
Definition functions.c:1130
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:468
int index_function_dispatcher(struct MuttWindow *win, const struct KeyEvent *event)
Perform an Index function - Implements function_dispatcher_t -.
Definition functions.c:4036
void dlg_mlist(struct Mailbox *m, struct Email *e)
Display mailing-list actions for an email -.
Definition dlg_mlist.c:118
void dlg_attach(struct ConfigSubset *sub, struct MailboxView *mv, struct Email *e, FILE *fp, bool attach_msg)
Show the attachments in a Menu -.
Definition dlg_attach.c:208
void dlg_autocrypt(void)
Display the Autocrypt account Menu -.
int mw_change_flag(struct Mailbox *m, struct EmailArray *ea, bool bf)
Change the flag on a Message -.
Definition flags.c:456
int mw_enter_fname(const char *prompt, struct Buffer *fname, bool mailbox, struct Mailbox *m, bool multiple, char ***files, int *numfiles, SelectFileFlags flags)
Ask the user to select a file -.
Definition curs_lib.c:237
int mw_get_field(const char *prompt, struct Buffer *buf, CompletionFlags complete, enum HistoryClass hclass, const struct CompleteOps *comp_api, void *cdata)
Ask the user for a string -.
Definition window.c:502
static int op_edit_label(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Add, change, or delete a message's label - Implements index_function_t -.
Definition functions.c:1026
static int op_display_address(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Display full address of sender - Implements index_function_t -.
Definition functions.c:925
static int op_next_entry(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Move to the next entry - Implements index_function_t -.
Definition functions.c:2678
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:2585
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:1760
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:3344
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:2264
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:3276
static int op_display_message(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Display a message - Implements index_function_t -.
Definition functions.c:943
static int op_list_reply(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Reply to specified mailing list - Implements index_function_t -.
Definition functions.c:1335
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:3736
static int op_save(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Make decrypted copy - Implements index_function_t -.
Definition functions.c:2907
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:2214
static int op_list_action(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Show mailing-list actions - Implements index_function_t -.
Definition functions.c:1322
static int op_mail_key(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Mail a PGP public key - Implements index_function_t -.
Definition functions.c:1401
static int op_alias_dialog(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Open the aliases dialog - Implements index_function_t -.
Definition functions.c:615
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:2466
static int op_exit(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Exit this menu - Implements index_function_t -.
Definition functions.c:1125
static int op_recall_message(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Recall a postponed message - Implements index_function_t -.
Definition functions.c:2831
static int op_main_sync_folder(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Save changes to mailbox - Implements index_function_t -.
Definition functions.c:2488
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:3785
static int op_tag_thread(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Tag the current thread - Implements index_function_t -.
Definition functions.c:3063
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:1070
static int op_post(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Followup to newsgroup - Implements index_function_t -.
Definition functions.c:3610
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:3448
static int op_delete_thread(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Delete all messages in thread - Implements index_function_t -.
Definition functions.c:868
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:2702
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:1416
static int op_group_reply(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Reply to all recipients - Implements index_function_t -.
Definition functions.c:1236
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:3087
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:3289
static int op_main_close_all_threads(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Collapse all threads - Implements index_function_t -.
Definition functions.c:1570
static int op_main_open_all_threads(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Open all threads - Implements index_function_t -.
Definition functions.c:1623
static int op_end_cond(struct IndexFunctionData *fdata, const struct KeyEvent *event)
End of conditional execution (noop) - Implements index_function_t -.
Definition functions.c:1117
static int op_print(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Print the current entry - Implements index_function_t -.
Definition functions.c:2749
static int op_view_attachments(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Show MIME attachments - Implements index_function_t -.
Definition functions.c:3236
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:3133
static int op_main_change_folder(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Open a different folder - Implements index_function_t -.
Definition functions.c:1486
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:3829
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:2239
static int op_main_collapse_all(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Collapse/uncollapse all threads - Implements index_function_t -.
Definition functions.c:1552
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:2156
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:1968
static int op_autocrypt_acct_menu(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Manage autocrypt accounts - Implements index_function_t -.
Definition functions.c:3266
static int op_tag(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Tag the current entry - Implements index_function_t -.
Definition functions.c:3017
static int op_main_open_thread(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Open current thread - Implements index_function_t -.
Definition functions.c:1646
static int op_undelete(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Undelete the current entry - Implements index_function_t -.
Definition functions.c:3143
static int op_main_collapse_thread(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Collapse/uncollapse current thread - Implements index_function_t -.
Definition functions.c:1608
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:2113
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:1661
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:3654
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:2622
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:2322
static int op_undelete_thread(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Undelete all messages in thread - Implements index_function_t -.
Definition functions.c:3186
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:2431
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:2412
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:2358
static int op_main_change_group(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Open a different newsgroup - Implements index_function_t -.
Definition functions.c:3530
static int op_main_close_thread(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Collapse current thread - Implements index_function_t -.
Definition functions.c:1593
static int op_prev_entry(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Move to the previous entry - Implements index_function_t -.
Definition functions.c:2725
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:1165
static int op_main_modify_tags(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Modify (notmuch/imap) tags - Implements index_function_t -.
Definition functions.c:1830
#define mutt_warning(...)
Definition logging2.h:92
#define mutt_error(...)
Definition logging2.h:94
#define mutt_message(...)
Definition logging2.h:93
#define mutt_debug(LEVEL,...)
Definition logging2.h:91
Convenience wrapper for the gui headers.
int mutt_parent_message(struct Email *e, bool find_root, int count)
Find the parent of a message.
Definition thread.c:1457
bool mutt_link_threads(struct Email *parent, struct EmailArray *children, struct Mailbox *m)
Forcibly link threads together.
Definition thread.c:1870
void mutt_draw_tree(struct ThreadsContext *tctx)
Draw a tree of threaded emails.
Definition thread.c:465
int mutt_messages_in_thread(struct Mailbox *m, struct Email *e, enum MessageInThread mit)
Count the messages in a thread.
Definition thread.c:1774
off_t mutt_set_vnum(struct Mailbox *m)
Set the virtual index number of all the messages in a mailbox.
Definition thread.c:1515
int mutt_aside_thread(struct Email *e, bool forwards, bool subthreads)
Find the next/previous (sub)thread.
Definition thread.c:1389
bool mutt_thread_can_collapse(struct Email *e)
Check whether a thread can be collapsed.
Definition thread.c:1940
struct HashTable * mutt_make_id_hash(struct Mailbox *m)
Create a Hash Table for Message-IDs.
Definition thread.c:1825
#define mutt_thread_next_unread(e)
Definition thread.h:116
#define mutt_using_threads()
Definition thread.h:119
#define mutt_uncollapse_thread(e)
Definition thread.h:113
@ MIT_POSITION
Our position in the thread.
Definition thread.h:95
#define mutt_next_subthread(e)
Definition thread.h:126
#define mutt_thread_contains_unread(e)
Definition thread.h:114
#define mutt_next_thread(e)
Definition thread.h:124
#define mutt_collapse_thread(e)
Definition thread.h:112
void * mutt_hash_find(const struct HashTable *table, const char *strkey)
Find the HashElem data in a Hash Table element using a key.
Definition hash.c:365
Read/write command history from/to a file.
@ HC_OTHER
Miscellaneous strings.
Definition lib.h:61
void exec_startup_shutdown_hook(enum CommandId id)
Execute any startup/shutdown hooks.
Definition exec.c:418
void exec_message_hook(struct Mailbox *m, struct Email *e, enum CommandId id)
Perform a message hook.
Definition exec.c:137
Hook Commands.
IMAP network mailbox.
void imap_logout_all(void)
Close all open connections.
Definition imap.c:667
enum MxStatus imap_check_mailbox(struct Mailbox *m, bool force)
Use the NOOP or IDLE command to poll for new mail.
Definition imap.c:1220
static int op_main_change_thread(struct IndexFunctionData *fdata, struct EmailArray *ea, enum CollapseMode mode)
Open/close/collapse a working set of threads.
Definition functions.c:782
static void update_thread_email(struct IndexPrivateData *priv, struct Email *email)
Focus a visible email in the current thread.
Definition functions.c:757
static const struct MenuFuncOp OpIndex[]
Functions for the Index Menu.
Definition functions.c:88
static bool ea_contains_thread_target(struct EmailArray *ea, struct Email *e, bool subthread)
Does the array already include this thread target?
Definition functions.c:533
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:475
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:563
void index_init_keys(struct NeoMutt *n, struct SubMenu *sm_generic)
Initialise the Index Keybindings - Implements ::init_keys_api.
Definition functions.c:327
bool index_next_undeleted(struct MuttWindow *win_index)
Select the next undeleted Email (if possible)
Definition functions.c:439
struct MenuDefinition * index_get_menu_definition(void)
Get the Index Menu Definition.
Definition functions.c:4089
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:366
struct SubMenu * index_get_submenu(void)
Get the Index SubMenu.
Definition functions.c:350
static const struct MenuOpSeq IndexDefaultBindings[]
Key bindings for the Index Menu.
Definition functions.c:225
static struct MuttThread * thread_target(struct Email *e, bool subthread)
Get the thread/subthread target for an email.
Definition functions.c:511
static bool prereq(struct IndexSharedData *shared, struct Menu *menu, CheckFlags checks)
Check the pre-requisites for a function.
Definition functions.c:3846
static const struct IndexFunction IndexFunctions[]
All the NeoMutt functions that the Index supports.
Definition functions.c:3895
ResolveMethod
How to advance the cursor.
Definition functions.c:317
@ RESOLVE_NEXT_SUBTHREAD
Next sibling sub-thread.
Definition functions.c:321
@ RESOLVE_NEXT_UNDELETED
Next undeleted email.
Definition functions.c:319
@ RESOLVE_NEXT_EMAIL
Next email, whatever its state.
Definition functions.c:318
@ RESOLVE_NEXT_THREAD
Next top-level thread.
Definition functions.c:320
static int op_main_next_new(struct IndexFunctionData *fdata, const struct KeyEvent *event)
Definition functions.c:2035
Index functions.
GUI manage the main index (list of emails)
uint8_t CheckFlags
Definition lib.h:96
@ NT_INDEX_EMAIL
Email has changed.
Definition lib.h:80
CollapseMode
Action to perform on a Thread.
Definition lib.h:102
@ COLLAPSE_MODE_TOGGLE
Toggle collapsed state.
Definition lib.h:103
@ COLLAPSE_MODE_CLOSE
Collapse all threads.
Definition lib.h:104
@ COLLAPSE_MODE_OPEN
Open all threads.
Definition lib.h:105
@ CHECK_VISIBLE
Is the selected message visible in the index?
Definition lib.h:92
@ CHECK_NONE
No flags are set.
Definition lib.h:89
@ CHECK_READONLY
Is the mailbox readonly?
Definition lib.h:93
@ CHECK_MSGCOUNT
Are there any messages?
Definition lib.h:91
@ CHECK_IN_MAILBOX
Is there a mailbox open?
Definition lib.h:90
@ CHECK_ATTACH
Is the user in message-attach mode?
Definition lib.h:94
Index private Module data.
Private state data for the Index.
void index_shared_data_set_email(struct IndexSharedData *shared, struct Email *e)
Set the current Email for the Index and friends.
Data shared between Index, Pager and Sidebar.
void km_menu_add_submenu(struct MenuDefinition *md, struct SubMenu *sm)
Add a SubMenu to a Menu Definition.
Definition init.c:123
struct SubMenu * km_register_submenu(const struct MenuFuncOp functions[])
Register a submenu.
Definition init.c:88
struct MenuDefinition * km_register_menu(int menu, const char *name)
Register a menu.
Definition init.c:105
void km_menu_add_bindings(struct MenuDefinition *md, const struct MenuOpSeq bindings[])
Add Keybindings to a Menu.
Definition init.c:136
enum CommandResult km_bind(const struct MenuDefinition *md, const char *key_str, int op, char *macro, char *desc, struct Buffer *err)
Set up a key binding.
Definition menu.c:52
Manage keymappings.
@ LL_DEBUG1
Log at debug level 1.
Definition logging2.h:45
@ LL_NOTIFY
Log of notifications.
Definition logging2.h:50
#define FREE(x)
Free memory and set the pointer to NULL.
Definition memory.h:68
#define MAX(a, b)
Return the maximum of two values.
Definition memory.h:38
GUI present the user with a selectable list.
MenuRedrawFlags menu_current_middle(struct Menu *menu)
Move the current selection to the centre of the window.
Definition move.c:486
void menu_queue_redraw(struct Menu *menu, MenuRedrawFlags redraw)
Queue a request for a redraw.
Definition menu.c:177
int menu_get_index(struct Menu *menu)
Get the current selection in the Menu.
Definition menu.c:153
@ MENU_REDRAW_INDEX
Redraw the index.
Definition lib.h:61
@ MENU_REDRAW_FULL
Redraw everything.
Definition lib.h:64
@ MENU_REDRAW_CURRENT
Redraw the current line of the menu.
Definition lib.h:63
MenuRedrawFlags menu_set_index(struct Menu *menu, int index)
Set the current selection in the Menu.
Definition menu.c:167
Mailing-list action dialog.
@ MODULE_ID_INDEX
ModuleIndex, Index
Definition module_api.h:73
@ MODULE_ID_NNTP
ModuleNntp, Nntp
Definition module_api.h:83
void msgwin_clear_text(struct MuttWindow *win)
Clear the text in the Message Window.
Definition msgwin.c:556
Convenience wrapper for the library headers.
#define _(a)
Definition message.h:28
bool notify_send(struct Notify *notify, enum NotifyType event_type, int event_subtype, void *event_data)
Send out a notification message.
Definition notify.c:173
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition string.c:678
bool mutt_strn_equal(const char *a, const char *b, size_t num)
Check for equality of two strings (to a maximum), safely.
Definition string.c:429
size_t mutt_str_copy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition string.c:587
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition string.c:284
Many unsorted constants and some structs.
@ EVM_VIEW
View the message.
Definition mutt.h:76
@ EVM_EDIT
Edit the message.
Definition mutt.h:77
@ MUTT_UNDELETE
Messages to be un-deleted.
Definition mutt.h:95
@ MUTT_LIMIT
Messages in limited view.
Definition mutt.h:101
@ MUTT_UNTAG
Messages to be un-tagged.
Definition mutt.h:100
@ MUTT_READ
Messages that have been read.
Definition mutt.h:92
@ MUTT_PURGE
Messages to be purged (bypass trash)
Definition mutt.h:96
@ MUTT_TAG
Tagged messages.
Definition mutt.h:99
@ MUTT_FLAG
Flagged messages.
Definition mutt.h:98
@ MUTT_DELETE
Messages to be deleted.
Definition mutt.h:94
@ MUTT_NEW
New messages.
Definition mutt.h:89
#define PATH_MAX
Definition mutt.h:49
struct Mailbox * mutt_mailbox_next_unread(struct Mailbox *m_cur, struct Buffer *s)
Find next mailbox with unread mail.
struct Mailbox * mutt_mailbox_next(struct Mailbox *m_cur, struct Buffer *s)
Incoming folders completion routine.
bool mutt_mailbox_list(void)
Show a message with the list of mailboxes with new mail.
struct Mailbox * mutt_mailbox_prev_unread(struct Mailbox *m_cur, struct Buffer *s)
Find previous mailbox with unread mail.
Mailbox helper functions.
bool window_is_focused(const struct MuttWindow *win)
Does the given Window have the focus?
struct MuttWindow * window_set_focus(struct MuttWindow *win)
Set the Window focus.
void pretty_mailbox(struct Buffer *buf)
Shorten a mailbox path using '~' or '='.
Definition muttlib.c:428
Some miscellaneous functions.
struct Email * mutt_get_virt_email(struct Mailbox *m, int vnum)
Get a virtual Email.
Definition mview.c:378
bool mutt_limit_current_thread(struct MailboxView *mv, struct Email *e)
Limit the email view to the current thread.
Definition mview.c:441
void mview_free(struct MailboxView **ptr)
Free a MailboxView.
Definition mview.c:47
bool message_is_tagged(struct Email *e)
Is a message in the index tagged (and within limit)
Definition mview.c:363
bool mview_has_limit(const struct MailboxView *mv)
Is a limit active?
Definition mview.c:399
int ea_add_tagged(struct EmailArray *ea, struct MailboxView *mv, struct Email *e, bool use_tagged)
Get an array of the tagged Emails.
Definition selection.c:128
int mx_tags_edit(struct Mailbox *m, const char *tags, struct Buffer *buf)
Start the tag editor of the mailbox.
Definition mx.c:1279
int mx_msg_close(struct Mailbox *m, struct Message **ptr)
Close a message.
Definition mx.c:1185
void mx_fastclose_mailbox(struct Mailbox *m, bool keep_account)
Free up memory associated with the Mailbox.
Definition mx.c:411
struct Mailbox * mx_mbox_find2(const char *path)
Find a Mailbox on an Account.
Definition mx.c:1618
struct Message * mx_msg_open(struct Mailbox *m, struct Email *e)
Return a stream pointer for a message.
Definition mx.c:1139
bool mx_tags_is_supported(struct Mailbox *m)
Return true if mailbox support tagging.
Definition mx.c:1316
int mx_tags_commit(struct Mailbox *m, struct Email *e, const char *tags)
Save tags to the Mailbox - Wrapper for MxOps::tags_commit()
Definition mx.c:1299
int mx_toggle_write(struct Mailbox *m)
Toggle the mailbox's readonly flag.
Definition mx.c:1824
enum MxStatus mx_mbox_sync(struct Mailbox *m)
Save changes to mailbox.
Definition mx.c:904
enum MxStatus mx_mbox_close(struct Mailbox *m)
Save changes and close mailbox.
Definition mx.c:595
API for mailboxes.
MxStatus
Return values from mbox_check(), mbox_check_stats(), mbox_sync(), and mbox_close()
Definition mxapi.h:70
@ MX_STATUS_OK
No changes.
Definition mxapi.h:72
@ MX_STATUS_REOPENED
Mailbox was reopened.
Definition mxapi.h:75
@ MX_STATUS_NEW_MAIL
New mail received in Mailbox.
Definition mxapi.h:73
API for encryption/signing of emails.
#define PGP_TRADITIONAL_CHECKED
Email has a traditional (inline) signature.
Definition lib.h:108
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition lib.h:106
#define WithCrypto
Definition lib.h:132
void * neomutt_get_module_data(struct NeoMutt *n, enum ModuleId id)
Get the private data for a Module.
Definition neomutt.c:666
@ NT_GLOBAL_SHUTDOWN
NeoMutt is about to close.
Definition neomutt.h:70
Usenet network mailbox type; talk to an NNTP server.
int nntp_check_msgid(struct Mailbox *m, const char *msgid)
Fetch article by Message-ID.
Definition nntp.c:2223
int nntp_check_children(struct Mailbox *m, const char *msgid)
Fetch children of article with the Message-ID.
Definition nntp.c:2294
void nntp_mailbox(struct Mailbox *m, char *buf, size_t buflen)
Get first newsgroup with new messages.
Definition newsrc.c:1321
struct NntpMboxData * mutt_newsgroup_catchup(struct Mailbox *m, struct NntpAccountData *adata, char *group)
Catchup newsgroup.
Definition newsrc.c:1239
struct NntpAccountData * nntp_select_server(struct Mailbox *m, const char *server, bool leave_lock)
Open a connection to an NNTP server.
Definition newsrc.c:957
Nntp-specific Mailbox data.
Nntp private Module data.
@ NT_MAILBOX
Mailbox has changed, NotifyMailbox, EventMailbox.
Definition notify_type.h:50
@ NT_INDEX
Index data has changed, NotifyIndex, IndexSharedData.
Definition notify_type.h:48
@ NT_GLOBAL
Not object-related, NotifyGlobal.
Definition notify_type.h:46
const struct CompleteOps CompleteNmQueryOps
Auto-Completion of NmQuerys.
Definition complete.c:284
void nm_db_longrun_done(struct Mailbox *m)
Finish a long transaction.
Definition db.c:393
void nm_db_longrun_init(struct Mailbox *m, bool writable)
Start a long transaction.
Definition db.c:378
Notmuch virtual mailbox type.
void nm_query_window_reset(void)
Resets the vfolder window position to the present.
Definition notmuch.c:1725
int nm_read_entire_thread(struct Mailbox *m, struct Email *e)
Get the entire thread of an email.
Definition notmuch.c:1550
void nm_query_window_backward(void)
Function to move the current search window backward in time.
Definition notmuch.c:1714
bool nm_query_window_available(void)
Are windowed queries enabled for use?
Definition notmuch.c:1677
bool nm_message_is_still_queried(struct Mailbox *m, struct Email *e)
Is a message still visible in the query?
Definition notmuch.c:1737
void nm_query_window_forward(void)
Function to move the current search window forward in time.
Definition notmuch.c:1694
const char * opcodes_get_name(int op)
Get the name of an opcode.
Definition opcodes.c:48
const char * pager_get_pager(struct ConfigSubset *sub)
Get the value of $pager.
Definition config.c:111
GUI display a file/email/help in a viewport with paging.
int mutt_display_message(struct MuttWindow *win_index, struct IndexSharedData *shared)
Display a message in the pager.
Definition message.c:447
int external_pager(struct MailboxView *mv, struct Email *e, const char *command)
Display a message in an external program.
Definition message.c:296
Match patterns to emails.
int mutt_search_command(struct MailboxView *mv, struct Menu *menu, int cur, struct SearchState *state, SearchFlags flags)
Perform a search.
Definition pattern.c: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:530
Progress Bar.
@ MUTT_PROGRESS_WRITE
Progress tracks elements, according to $write_inc
Definition lib.h:85
struct Progress * progress_new(enum ProgressType type, size_t size)
Create a new Progress Bar.
Definition progress.c:139
void progress_free(struct Progress **ptr)
Free a Progress Bar.
Definition progress.c:110
void progress_set_message(struct Progress *progress, const char *fmt,...) __attribute__((__format__(__printf__
bool progress_update(struct Progress *progress, size_t pos, int percent)
Update the state of the progress bar.
Definition progress.c:80
@ MUTT_YES
User answered 'Yes', or assume 'Yes'.
Definition quad.h:39
Ask the user a question.
enum QuadOption query_quadoption(const char *prompt, struct ConfigSubset *sub, const char *name)
Ask the user a quad-question.
Definition question.c:384
#define STAILQ_FIRST(head)
Definition queue.h:388
#define STAILQ_FOREACH(var, head, field)
Definition queue.h:390
#define STAILQ_EMPTY(head)
Definition queue.h:382
#define STAILQ_NEXT(elm, field)
Definition queue.h:439
uint8_t SearchFlags
@ SEARCH_NONE
No flags are set.
@ SEARCH_PROMPT
Ask for search input.
@ SEARCH_OPPOSITE
Search in the opposite direction.
Convenience wrapper for the send headers.
int mutt_resend_message(FILE *fp, struct Mailbox *m, struct Email *e_cur, struct ConfigSubset *sub)
Resend an email.
Definition send.c:1561
bool mutt_send_list_unsubscribe(struct Mailbox *m, struct Email *e)
Send a mailing-list unsubscription email.
Definition send.c:2986
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:2031
bool mutt_send_list_subscribe(struct Mailbox *m, struct Email *e)
Send a mailing-list subscription email.
Definition send.c:2957
uint32_t SendFlags
Definition send.h:64
@ SEND_KEY
Mail a PGP public key.
Definition send.h:52
@ SEND_GROUP_CHAT_REPLY
Reply to all recipients preserving To/Cc.
Definition send.h:58
@ SEND_REPLY
Reply to sender.
Definition send.h:46
@ SEND_NONE
No flags are set.
Definition send.h:45
@ SEND_FORWARD
Forward email.
Definition send.h:49
@ SEND_GROUP_REPLY
Reply to all.
Definition send.h:47
@ SEND_TO_SENDER
Compose new email to sender.
Definition send.h:57
@ SEND_LIST_REPLY
Reply to mailing list.
Definition send.h:48
@ SEND_NEWS
Reply to a news article.
Definition send.h:59
@ SEND_POSTPONED
Recall a postponed email.
Definition send.h:50
GUI display the mailboxes in a side panel.
#define ASSERT(COND)
Definition signal2.h:59
#define NONULL(x)
Definition string2.h:44
String manipulation buffer.
Definition buffer.h:36
size_t dsize
Length of data.
Definition buffer.h:39
char * data
Pointer to data.
Definition buffer.h:37
The envelope/body of an email.
Definition email.h:39
bool read
Email is read.
Definition email.h:50
bool visible
Is this message part of the view?
Definition email.h:121
struct Envelope * env
Envelope information.
Definition email.h:68
bool collapsed
Is this message part of a collapsed thread?
Definition email.h:120
SecurityFlags security
bit 0-10: flags, bit 11,12: application, bit 13: traditional pgp See: ncrypt/lib.h pgplib....
Definition email.h:43
struct Body * body
List of MIME parts.
Definition email.h:69
bool old
Email is seen, but unread.
Definition email.h:49
bool changed
Email has been edited.
Definition email.h:77
bool attach_del
Has an attachment marked for deletion.
Definition email.h:99
bool threaded
Used for threading.
Definition email.h:108
const struct AttrColor * attr_color
Color-pair to use when displaying in the index.
Definition email.h:112
int vnum
Virtual message number.
Definition email.h:114
struct TagList tags
For drivers that support server tagging.
Definition email.h:72
bool deleted
Email is deleted.
Definition email.h:78
int index
The absolute (unsorted) message number.
Definition email.h:110
bool quasi_deleted
Deleted from neomutt, but not modified on disk.
Definition email.h:103
bool tagged
Email is tagged.
Definition email.h:107
struct MuttThread * thread
Thread of Emails.
Definition email.h:119
char * followup_to
List of 'followup-to' fields.
Definition envelope.h:80
char * message_id
Message ID.
Definition envelope.h:73
struct ListHead references
message references (in reverse order)
Definition envelope.h:83
struct ListHead in_reply_to
in-reply-to header content
Definition envelope.h:84
An Event that happened to a Mailbox.
Definition mailbox.h:192
Data passed to Index worker functions.
Definition functions.h:35
struct IndexSharedData * shared
Shared Index data.
Definition functions.h:38
struct IndexPrivateData * priv
Private Index data.
Definition functions.h:39
struct IndexModuleData * mod_data
Index module data.
Definition functions.h:37
struct NeoMutt * n
NeoMutt application data.
Definition functions.h:36
A NeoMutt function.
Definition functions.h:62
int op
Op code, e.g. OP_MAIN_LIMIT.
Definition functions.h:63
index_function_t function
Function to call.
Definition functions.h:64
int flags
Prerequisites for the function, e.g. CHECK_IN_MAILBOX.
Definition functions.h:65
Index private Module data.
Definition module_data.h:32
struct MenuDefinition * md_index
Index Menu Definition.
Definition module_data.h:34
struct SubMenu * sm_index
Index functions.
Definition module_data.h:35
Private state data for the Index.
struct MuttWindow * win_index
Window for the Index.
struct IndexSharedData * shared
Shared Index data.
bool tag_prefix
tag-prefix has been pressed
struct Menu * menu
Menu controlling the index.
int oldcount
Old count of mails in the mailbox.
Data shared between Index, Pager and Sidebar.
Definition shared_data.h:37
struct Email * email
Currently selected Email.
Definition shared_data.h:42
struct Mailbox * mailbox
Current Mailbox.
Definition shared_data.h:41
bool attach_msg
Are we in "attach message" mode?
Definition shared_data.h:46
struct ConfigSubset * sub
Config set to use.
Definition shared_data.h:38
struct MailboxView * mailbox_view
Current Mailbox view.
Definition shared_data.h:40
struct SearchState * search_state
State of the current search.
Definition shared_data.h:45
struct Notify * notify
Notifications: NotifyIndex, IndexSharedData.
Definition shared_data.h:44
An event such as a keypress.
Definition get.h:75
int count
Optional count prefix, e.g. 3 for 3j
Definition get.h:78
int op
Function opcode, e.g. OP_HELP.
Definition get.h:77
A List node for strings.
Definition list.h:37
char * data
String.
Definition list.h:38
View of a Mailbox.
Definition mview.h:40
bool collapsed
Are all threads collapsed?
Definition mview.h:49
struct Menu * menu
Needed for pattern compilation.
Definition mview.h:47
struct ThreadsContext * threads
Threads context.
Definition mview.h:44
struct Mailbox * mailbox
Current Mailbox.
Definition mview.h:51
char * pattern
Limit pattern string.
Definition mview.h:42
A mailbox.
Definition mailbox.h:81
int vcount
The number of virtual messages.
Definition mailbox.h:101
bool changed
Mailbox has been modified.
Definition mailbox.h:112
int msg_count
Total number of messages.
Definition mailbox.h:90
AclFlags rights
ACL bits, see AclFlags.
Definition mailbox.h:121
enum MailboxType type
Mailbox type.
Definition mailbox.h:104
void * mdata
Driver specific data.
Definition mailbox.h:134
struct Email ** emails
Array of Emails.
Definition mailbox.h:98
char * name
A short name for the Mailbox.
Definition mailbox.h:84
struct Notify * notify
Notifications: NotifyMailbox, EventMailbox.
Definition mailbox.h:147
struct HashTable * id_hash
Hash Table: "Message-ID" -> Email.
Definition mailbox.h:125
struct Buffer pathbuf
Path of the Mailbox.
Definition mailbox.h:82
bool readonly
Don't allow changes to the mailbox.
Definition mailbox.h:118
bool verbose
Display status messages?
Definition mailbox.h:119
Functions for a Dialog or Window.
Definition menudef.h:44
Mapping between a function and an operation.
Definition menu.h:37
Mapping between an operation and a key sequence.
Definition menu.h:47
Definition lib.h:86
int max
Number of entries in the menu.
Definition lib.h:88
A local copy of an email.
Definition message.h:34
FILE * fp
pointer to the message data
Definition message.h:35
An Email conversation.
Definition thread.h:34
struct MuttThread * parent
Parent of this Thread.
Definition thread.h:44
const struct Mapping * help_data
Data for the Help Bar.
void * wdata
Private data.
struct MuttWindow * parent
Parent Window.
Container for Accounts, Notifications.
Definition neomutt.h:41
struct Notify * notify
Notifications handler.
Definition neomutt.h:45
struct ConfigSubset * sub
Inherited config items.
Definition neomutt.h:49
NNTP-specific Mailbox data -.
Definition mdata.h:34
Nntp private Module data.
Definition module_data.h:30
struct NntpAccountData * current_news_srv
Current NNTP news server.
Definition module_data.h:32
bool reverse
search backwards
struct PatternList * pattern
compiled search pattern
Collection of related functions.
Definition menudef.h:33
void driver_tags_get_with_hidden(struct TagList *tl, struct Buffer *tags)
Get all tags, also hidden ones, separated by space.
Definition tags.c:175
@ MENU_INDEX
Index panel (list of emails)
Definition type.h:45