NeoMutt
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
functions.c
Go to the documentation of this file.
1
29#include "config.h"
30#ifdef _MAKEDOC
31#include "docs/makedoc_defs.h"
32#else
33#include <limits.h>
34#include <stdbool.h>
35#include <stdio.h>
36#include <string.h>
37#include "mutt/lib.h"
38#include "config/lib.h"
39#include "email/lib.h"
40#include "core/lib.h"
41#include "alias/lib.h"
42#include "gui/lib.h"
43#include "mutt.h"
44#include "lib.h"
45#include "attach/lib.h"
46#include "browser/lib.h"
47#include "editor/lib.h"
48#include "history/lib.h"
49#include "key/lib.h"
50#include "menu/lib.h"
51#include "ncrypt/lib.h"
52#include "pager/lib.h"
53#include "pattern/lib.h"
54#include "progress/lib.h"
55#include "question/lib.h"
56#include "send/lib.h"
57#include "external.h"
58#include "functions.h"
59#include "globals.h" // IWYU pragma: keep
60#include "hook.h"
61#include "mutt_header.h"
62#include "mutt_mailbox.h"
63#include "mutt_thread.h"
64#include "muttlib.h"
65#include "mview.h"
66#include "mx.h"
67#include "private_data.h"
68#include "protos.h"
69#include "shared_data.h"
70#include "sort.h"
71#ifdef USE_AUTOCRYPT
72#include "autocrypt/lib.h"
73#endif
74#ifdef USE_NOTMUCH
75#include "notmuch/lib.h"
76#endif
77#ifdef USE_IMAP
78#include "imap/lib.h"
79#endif
80#ifdef USE_NNTP
81#include "nntp/lib.h"
82#include "nntp/mdata.h"
83#endif
84#ifdef USE_POP
85#include "pop/lib.h"
86#endif
87#ifdef ENABLE_NLS
88#include <libintl.h>
89#endif
90#endif
91
93static const char *Not_available_in_this_menu = N_("Not available in this menu");
94
95// clang-format off
99const struct MenuFuncOp OpIndex[] = { /* map: index */
100 { "alias-dialog", OP_ALIAS_DIALOG },
101#ifdef USE_AUTOCRYPT
102 { "autocrypt-acct-menu", OP_AUTOCRYPT_ACCT_MENU },
103#endif
104 { "bounce-message", OP_BOUNCE_MESSAGE },
105 { "break-thread", OP_MAIN_BREAK_THREAD },
106#ifdef USE_NNTP
107 { "catchup", OP_CATCHUP },
108#endif
109 { "change-folder", OP_MAIN_CHANGE_FOLDER },
110 { "change-folder-readonly", OP_MAIN_CHANGE_FOLDER_READONLY },
111#ifdef USE_NNTP
112 { "change-newsgroup", OP_MAIN_CHANGE_GROUP },
113 { "change-newsgroup-readonly", OP_MAIN_CHANGE_GROUP_READONLY },
114#endif
115#ifdef USE_NOTMUCH
116 { "change-vfolder", OP_MAIN_CHANGE_VFOLDER },
117#endif
118 { "check-traditional-pgp", OP_CHECK_TRADITIONAL },
119 { "clear-flag", OP_MAIN_CLEAR_FLAG },
120 { "collapse-all", OP_MAIN_COLLAPSE_ALL },
121 { "collapse-thread", OP_MAIN_COLLAPSE_THREAD },
122 { "compose-to-sender", OP_COMPOSE_TO_SENDER },
123 { "copy-message", OP_COPY_MESSAGE },
124 { "create-alias", OP_CREATE_ALIAS },
125 { "decode-copy", OP_DECODE_COPY },
126 { "decode-save", OP_DECODE_SAVE },
127 { "decrypt-copy", OP_DECRYPT_COPY },
128 { "decrypt-save", OP_DECRYPT_SAVE },
129 { "delete-message", OP_DELETE },
130 { "delete-pattern", OP_MAIN_DELETE_PATTERN },
131 { "delete-subthread", OP_DELETE_SUBTHREAD },
132 { "delete-thread", OP_DELETE_THREAD },
133 { "display-address", OP_DISPLAY_ADDRESS },
134 { "display-message", OP_DISPLAY_MESSAGE },
135 { "display-toggle-weed", OP_DISPLAY_HEADERS },
136 { "edit", OP_EDIT_RAW_MESSAGE },
137 { "edit-label", OP_EDIT_LABEL },
138 { "edit-or-view-raw-message", OP_EDIT_OR_VIEW_RAW_MESSAGE },
139 { "edit-raw-message", OP_EDIT_RAW_MESSAGE },
140 { "edit-type", OP_ATTACHMENT_EDIT_TYPE },
141#ifdef USE_NOTMUCH
142 { "entire-thread", OP_MAIN_ENTIRE_THREAD },
143#endif
144 { "exit", OP_EXIT },
145 { "extract-keys", OP_EXTRACT_KEYS },
146#ifdef USE_POP
147 { "fetch-mail", OP_MAIN_FETCH_MAIL },
148#endif
149 { "flag-message", OP_FLAG_MESSAGE },
150#ifdef USE_NNTP
151 { "followup-message", OP_FOLLOWUP },
152#endif
153 { "forget-passphrase", OP_FORGET_PASSPHRASE },
154 { "forward-message", OP_FORWARD_MESSAGE },
155#ifdef USE_NNTP
156 { "forward-to-group", OP_FORWARD_TO_GROUP },
157 { "get-children", OP_GET_CHILDREN },
158 { "get-message", OP_GET_MESSAGE },
159 { "get-parent", OP_GET_PARENT },
160#endif
161 { "group-chat-reply", OP_GROUP_CHAT_REPLY },
162 { "group-reply", OP_GROUP_REPLY },
163#ifdef USE_IMAP
164 { "imap-fetch-mail", OP_MAIN_IMAP_FETCH },
165 { "imap-logout-all", OP_MAIN_IMAP_LOGOUT_ALL },
166#endif
167 { "limit", OP_MAIN_LIMIT },
168 { "limit-current-thread", OP_LIMIT_CURRENT_THREAD },
169 { "link-threads", OP_MAIN_LINK_THREADS },
170 { "list-reply", OP_LIST_REPLY },
171 { "list-subscribe", OP_LIST_SUBSCRIBE },
172 { "list-unsubscribe", OP_LIST_UNSUBSCRIBE },
173 { "mail", OP_MAIL },
174 { "mail-key", OP_MAIL_KEY },
175 { "mailbox-list", OP_MAILBOX_LIST },
176 { "mark-message", OP_MARK_MSG },
177 { "modify-labels", OP_MAIN_MODIFY_TAGS },
178 { "modify-labels-then-hide", OP_MAIN_MODIFY_TAGS_THEN_HIDE },
179 { "modify-tags", OP_MAIN_MODIFY_TAGS },
180 { "modify-tags-then-hide", OP_MAIN_MODIFY_TAGS_THEN_HIDE },
181 { "next-new", OP_MAIN_NEXT_NEW },
182 { "next-new-then-unread", OP_MAIN_NEXT_NEW_THEN_UNREAD },
183 { "next-subthread", OP_MAIN_NEXT_SUBTHREAD },
184 { "next-thread", OP_MAIN_NEXT_THREAD },
185 { "next-undeleted", OP_MAIN_NEXT_UNDELETED },
186 { "next-unread", OP_MAIN_NEXT_UNREAD },
187 { "next-unread-mailbox", OP_MAIN_NEXT_UNREAD_MAILBOX },
188 { "parent-message", OP_MAIN_PARENT_MESSAGE },
189 { "pipe-entry", OP_PIPE },
190 { "pipe-message", OP_PIPE },
191#ifdef USE_NNTP
192 { "post-message", OP_POST },
193#endif
194 { "previous-new", OP_MAIN_PREV_NEW },
195 { "previous-new-then-unread", OP_MAIN_PREV_NEW_THEN_UNREAD },
196 { "previous-subthread", OP_MAIN_PREV_SUBTHREAD },
197 { "previous-thread", OP_MAIN_PREV_THREAD },
198 { "previous-undeleted", OP_MAIN_PREV_UNDELETED },
199 { "previous-unread", OP_MAIN_PREV_UNREAD },
200 { "print-message", OP_PRINT },
201 { "purge-message", OP_PURGE_MESSAGE },
202 { "purge-thread", OP_PURGE_THREAD },
203 { "quasi-delete", OP_MAIN_QUASI_DELETE },
204 { "query", OP_QUERY },
205 { "quit", OP_QUIT },
206 { "read-subthread", OP_MAIN_READ_SUBTHREAD },
207 { "read-thread", OP_MAIN_READ_THREAD },
208 { "recall-message", OP_RECALL_MESSAGE },
209#ifdef USE_NNTP
210 { "reconstruct-thread", OP_RECONSTRUCT_THREAD },
211#endif
212 { "reply", OP_REPLY },
213 { "resend-message", OP_RESEND },
214 { "root-message", OP_MAIN_ROOT_MESSAGE },
215 { "save-message", OP_SAVE },
216 { "set-flag", OP_MAIN_SET_FLAG },
217 { "show-limit", OP_MAIN_SHOW_LIMIT },
218#ifdef USE_SIDEBAR
219 { "sidebar-first", OP_SIDEBAR_FIRST },
220 { "sidebar-last", OP_SIDEBAR_LAST },
221 { "sidebar-next", OP_SIDEBAR_NEXT },
222 { "sidebar-next-new", OP_SIDEBAR_NEXT_NEW },
223 { "sidebar-open", OP_SIDEBAR_OPEN },
224 { "sidebar-page-down", OP_SIDEBAR_PAGE_DOWN },
225 { "sidebar-page-up", OP_SIDEBAR_PAGE_UP },
226 { "sidebar-prev", OP_SIDEBAR_PREV },
227 { "sidebar-prev-new", OP_SIDEBAR_PREV_NEW },
228 { "sidebar-toggle-virtual", OP_SIDEBAR_TOGGLE_VIRTUAL },
229 { "sidebar-toggle-visible", OP_SIDEBAR_TOGGLE_VISIBLE },
230#endif
231 { "sort-mailbox", OP_SORT },
232 { "sort-reverse", OP_SORT_REVERSE },
233 { "sync-mailbox", OP_MAIN_SYNC_FOLDER },
234 { "tag-pattern", OP_MAIN_TAG_PATTERN },
235 { "tag-subthread", OP_TAG_SUBTHREAD },
236 { "tag-thread", OP_TAG_THREAD },
237 { "toggle-new", OP_TOGGLE_NEW },
238 { "toggle-read", OP_TOGGLE_READ },
239 { "toggle-write", OP_TOGGLE_WRITE },
240 { "undelete-message", OP_UNDELETE },
241 { "undelete-pattern", OP_MAIN_UNDELETE_PATTERN },
242 { "undelete-subthread", OP_UNDELETE_SUBTHREAD },
243 { "undelete-thread", OP_UNDELETE_THREAD },
244 { "untag-pattern", OP_MAIN_UNTAG_PATTERN },
245#ifdef USE_NOTMUCH
246 { "vfolder-from-query", OP_MAIN_VFOLDER_FROM_QUERY },
247 { "vfolder-from-query-readonly", OP_MAIN_VFOLDER_FROM_QUERY_READONLY },
248 { "vfolder-window-backward", OP_MAIN_WINDOWED_VFOLDER_BACKWARD },
249 { "vfolder-window-forward", OP_MAIN_WINDOWED_VFOLDER_FORWARD },
250 { "vfolder-window-reset", OP_MAIN_WINDOWED_VFOLDER_RESET },
251#endif
252 { "view-attachments", OP_VIEW_ATTACHMENTS },
253 { "view-raw-message", OP_VIEW_RAW_MESSAGE },
254 // Deprecated
255 { "buffy-list", OP_MAILBOX_LIST },
256 { NULL, 0 },
257};
258
262const struct MenuOpSeq IndexDefaultBindings[] = { /* map: index */
263 { OP_ATTACHMENT_EDIT_TYPE, "\005" }, // <Ctrl-E>
264#ifdef USE_AUTOCRYPT
265 { OP_AUTOCRYPT_ACCT_MENU, "A" },
266#endif
267 { OP_BOUNCE_MESSAGE, "b" },
268 { OP_CHECK_TRADITIONAL, "\033P" }, // <Alt-P>
269 { OP_COPY_MESSAGE, "C" },
270 { OP_CREATE_ALIAS, "a" },
271 { OP_DECODE_COPY, "\033C" }, // <Alt-C>
272 { OP_DECODE_SAVE, "\033s" }, // <Alt-s>
273 { OP_DELETE, "d" },
274 { OP_DELETE_SUBTHREAD, "\033d" }, // <Alt-d>
275 { OP_DELETE_THREAD, "\004" }, // <Ctrl-D>
276 { OP_DISPLAY_ADDRESS, "@" },
277 { OP_DISPLAY_HEADERS, "h" },
278 { OP_DISPLAY_MESSAGE, " " }, // <Space>
279 { OP_DISPLAY_MESSAGE, "<keypadenter>" },
280 { OP_DISPLAY_MESSAGE, "\n" }, // <Enter>
281 { OP_DISPLAY_MESSAGE, "\r" }, // <Return>
282 { OP_EDIT_LABEL, "Y" },
283 { OP_EDIT_OR_VIEW_RAW_MESSAGE, "e" },
284 { OP_EXIT, "x" },
285 { OP_EXTRACT_KEYS, "\013" }, // <Ctrl-K>
286 { OP_FLAG_MESSAGE, "F" },
287 { OP_FORGET_PASSPHRASE, "\006" }, // <Ctrl-F>
288 { OP_FORWARD_MESSAGE, "f" },
289 { OP_GROUP_REPLY, "g" },
290 { OP_LIST_REPLY, "L" },
291 { OP_MAIL, "m" },
292 { OP_MAILBOX_LIST, "." },
293 { OP_MAIL_KEY, "\033k" }, // <Alt-k>
294 { OP_MAIN_BREAK_THREAD, "#" },
295 { OP_MAIN_CHANGE_FOLDER, "c" },
296 { OP_MAIN_CHANGE_FOLDER_READONLY, "\033c" }, // <Alt-c>
297#ifdef USE_NNTP
298 { OP_MAIN_CHANGE_GROUP, "i" },
299 { OP_MAIN_CHANGE_GROUP_READONLY, "\033i" }, // <Alt-i>
300#endif
301 { OP_MAIN_CLEAR_FLAG, "W" },
302 { OP_MAIN_COLLAPSE_ALL, "\033V" }, // <Alt-V>
303 { OP_MAIN_COLLAPSE_THREAD, "\033v" }, // <Alt-v>
304 { OP_MAIN_DELETE_PATTERN, "D" },
305#ifdef USE_POP
306 { OP_MAIN_FETCH_MAIL, "G" },
307#endif
308 { OP_MAIN_LIMIT, "l" },
309 { OP_MAIN_LINK_THREADS, "&" },
310 { OP_MAIN_NEXT_NEW_THEN_UNREAD, "\t" }, // <Tab>
311 { OP_MAIN_NEXT_SUBTHREAD, "\033n" }, // <Alt-n>
312 { OP_MAIN_NEXT_THREAD, "\016" }, // <Ctrl-N>
313 { OP_MAIN_NEXT_UNDELETED, "<down>" },
314 { OP_MAIN_NEXT_UNDELETED, "j" },
315 { OP_MAIN_PARENT_MESSAGE, "P" },
316 { OP_MAIN_PREV_NEW_THEN_UNREAD, "\033\t" }, // <Alt->
317 { OP_MAIN_PREV_SUBTHREAD, "\033p" }, // <Alt-p>
318 { OP_MAIN_PREV_THREAD, "\020" }, // <Ctrl-P>
319 { OP_MAIN_PREV_UNDELETED, "<up>" },
320 { OP_MAIN_PREV_UNDELETED, "k" },
321 { OP_MAIN_READ_SUBTHREAD, "\033r" }, // <Alt-r>
322 { OP_MAIN_READ_THREAD, "\022" }, // <Ctrl-R>
323 { OP_MAIN_SET_FLAG, "w" },
324 { OP_MAIN_SHOW_LIMIT, "\033l" }, // <Alt-l>
325 { OP_MAIN_SYNC_FOLDER, "$" },
326 { OP_MAIN_TAG_PATTERN, "T" },
327 { OP_MAIN_UNDELETE_PATTERN, "U" },
328 { OP_MAIN_UNTAG_PATTERN, "\024" }, // <Ctrl-T>
329 { OP_MARK_MSG, "~" },
330 { OP_NEXT_ENTRY, "J" },
331 { OP_PIPE, "|" },
332 { OP_PREV_ENTRY, "K" },
333 { OP_PRINT, "p" },
334 { OP_QUERY, "Q" },
335 { OP_QUIT, "q" },
336 { OP_RECALL_MESSAGE, "R" },
337 { OP_REPLY, "r" },
338 { OP_RESEND, "\033e" }, // <Alt-e>
339 { OP_SAVE, "s" },
340 { OP_SHOW_LOG_MESSAGES, "M" },
341 { OP_SORT, "o" },
342 { OP_SORT_REVERSE, "O" },
343 { OP_TAG_THREAD, "\033t" }, // <Alt-t>
344 { OP_TOGGLE_NEW, "N" },
345 { OP_TOGGLE_WRITE, "%" },
346 { OP_UNDELETE, "u" },
347 { OP_UNDELETE_SUBTHREAD, "\033u" }, // <Alt-u>
348 { OP_UNDELETE_THREAD, "\025" }, // <Ctrl-U>
349 { OP_VIEW_ATTACHMENTS, "v" },
350 { 0, NULL },
351};
352// clang-format on
353
358{
363};
364
372static bool resolve_email(struct IndexPrivateData *priv,
373 struct IndexSharedData *shared, enum ResolveMethod rm)
374{
375 if (!priv || !priv->menu || !shared || !shared->mailbox || !shared->email)
376 return false;
377
378 const bool c_resolve = cs_subset_bool(shared->sub, "resolve");
379 if (!c_resolve)
380 return false;
381
382 int index = -1;
383 switch (rm)
384 {
386 index = menu_get_index(priv->menu) + 1;
387 break;
388
390 {
391 const bool uncollapse = mutt_using_threads() && !window_is_focused(priv->win_index);
392 index = find_next_undeleted(shared->mailbox_view, menu_get_index(priv->menu), uncollapse);
393 break;
394 }
395
397 index = mutt_next_thread(shared->email);
398 break;
399
401 index = mutt_next_subthread(shared->email);
402 break;
403 }
404
405 if ((index < 0) || (index >= shared->mailbox->vcount))
406 {
407 // Resolve failed
408 notify_send(shared->notify, NT_INDEX, NT_INDEX_EMAIL, NULL);
409 return false;
410 }
411
412 menu_set_index(priv->menu, index);
413 return true;
414}
415
421bool index_next_undeleted(struct MuttWindow *win_index)
422{
423 struct MuttWindow *dlg = dialog_find(win_index);
424 if (!dlg)
425 return false;
426
427 struct Menu *menu = win_index->wdata;
428 struct IndexSharedData *shared = dlg->wdata;
429 if (!shared)
430 return false;
431
432 struct IndexPrivateData *priv = win_index->parent->wdata;
433 const bool uncollapse = mutt_using_threads() && !window_is_focused(priv->win_index);
434
435 int index = find_next_undeleted(shared->mailbox_view, menu_get_index(menu), uncollapse);
436 if ((index < 0) || (index >= shared->mailbox->vcount))
437 {
438 // Selection failed
440 return false;
441 }
442
443 menu_set_index(menu, index);
444 return true;
445}
446
447// -----------------------------------------------------------------------------
448
453 struct IndexPrivateData *priv, int op)
454{
456 return FR_SUCCESS;
457}
458
463 struct IndexPrivateData *priv, int op)
464{
465 if (!shared->email)
466 return FR_NO_ACTION;
468
470 return FR_SUCCESS;
471}
472
477 struct IndexPrivateData *priv, int op)
478{
479 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
480 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
481 index_bounce_message(shared->mailbox, &ea);
482 ARRAY_FREE(&ea);
483
484 return FR_SUCCESS;
485}
486
490static int op_check_traditional(struct IndexSharedData *shared,
491 struct IndexPrivateData *priv, int op)
492{
494 return FR_NOT_IMPL;
495 if (!shared->email)
496 return FR_NO_ACTION;
497
498 if (priv->tag_prefix || !(shared->email->security & PGP_TRADITIONAL_CHECKED))
499 {
500 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
501 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
502 if (mutt_check_traditional_pgp(shared->mailbox, &ea))
504 ARRAY_FREE(&ea);
505 }
506
507 return FR_SUCCESS;
508}
509
513static int op_compose_to_sender(struct IndexSharedData *shared,
514 struct IndexPrivateData *priv, int op)
515{
516 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
517 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
518 int rc = mutt_send_message(SEND_TO_SENDER, NULL, NULL, shared->mailbox, &ea,
519 shared->sub);
520 ARRAY_FREE(&ea);
522
523 return (rc == -1) ? FR_ERROR : FR_SUCCESS;
524}
525
529static int op_create_alias(struct IndexSharedData *shared,
530 struct IndexPrivateData *priv, int op)
531{
532 struct AddressList *al = NULL;
533 if (shared->email && shared->email->env)
534 al = mutt_get_address(shared->email->env, NULL);
535 alias_create(al, shared->sub);
537
538 return FR_SUCCESS;
539}
540
548static int op_delete(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
549{
550 /* L10N: CHECK_ACL */
551 if (!check_acl(shared->mailbox, MUTT_ACL_DELETE, _("Can't delete message")))
552 return FR_ERROR;
553
554 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
555 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
556
557 mutt_emails_set_flag(shared->mailbox, &ea, MUTT_DELETE, true);
558 mutt_emails_set_flag(shared->mailbox, &ea, MUTT_PURGE, (op == OP_PURGE_MESSAGE));
559 const bool c_delete_untag = cs_subset_bool(shared->sub, "delete_untag");
560 if (c_delete_untag)
561 mutt_emails_set_flag(shared->mailbox, &ea, MUTT_TAG, false);
562 ARRAY_FREE(&ea);
563
564 if (priv->tag_prefix)
565 {
567 }
568 else
569 {
571 }
572
573 return FR_SUCCESS;
574}
575
584static int op_delete_thread(struct IndexSharedData *shared,
585 struct IndexPrivateData *priv, int op)
586{
587 /* L10N: CHECK_ACL */
588 /* L10N: Due to the implementation details we do not know whether we
589 delete zero, 1, 12, ... messages. So in English we use
590 "messages". Your language might have other means to express this. */
591 if (!check_acl(shared->mailbox, MUTT_ACL_DELETE, _("Can't delete messages")))
592 return FR_ERROR;
593 if (!shared->email)
594 return FR_NO_ACTION;
595
596 int subthread = (op == OP_DELETE_SUBTHREAD);
597 int rc = mutt_thread_set_flag(shared->mailbox, shared->email, MUTT_DELETE, true, subthread);
598 if (rc == -1)
599 return FR_ERROR;
600 if (op == OP_PURGE_THREAD)
601 {
602 rc = mutt_thread_set_flag(shared->mailbox, shared->email, MUTT_PURGE, true, subthread);
603 if (rc == -1)
604 return FR_ERROR;
605 }
606
607 const bool c_delete_untag = cs_subset_bool(shared->sub, "delete_untag");
608 if (c_delete_untag)
609 mutt_thread_set_flag(shared->mailbox, shared->email, MUTT_TAG, false, subthread);
610
613 return FR_SUCCESS;
614}
615
619static int op_display_address(struct IndexSharedData *shared,
620 struct IndexPrivateData *priv, int op)
621{
622 if (!shared->email)
623 return FR_NO_ACTION;
625
626 return FR_SUCCESS;
627}
628
636static int op_display_message(struct IndexSharedData *shared,
637 struct IndexPrivateData *priv, int op)
638{
639 if (!shared->email)
640 return FR_NO_ACTION;
641 /* toggle the weeding of headers so that a user can press the key
642 * again while reading the message. */
643 if (op == OP_DISPLAY_HEADERS)
644 {
645 bool_str_toggle(shared->sub, "weed", NULL);
646 notify_send(shared->notify, NT_INDEX, NT_INDEX_EMAIL, shared);
647 if (!window_is_focused(priv->win_index))
648 return FR_SUCCESS;
649 }
650
651 OptNeedResort = false;
652
653 if (mutt_using_threads() && shared->email->collapsed)
654 {
656 mutt_set_vnum(shared->mailbox);
657 const bool c_uncollapse_jump = cs_subset_bool(shared->sub, "uncollapse_jump");
658 if (c_uncollapse_jump)
660 }
661
662 const bool c_pgp_auto_decode = cs_subset_bool(shared->sub, "pgp_auto_decode");
663 if (c_pgp_auto_decode &&
664 (priv->tag_prefix || !(shared->email->security & PGP_TRADITIONAL_CHECKED)))
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 const int index = menu_get_index(priv->menu);
674
675 const char *const c_pager = pager_get_pager(NeoMutt->sub);
676 if (c_pager)
677 {
678 op = external_pager(shared->mailbox_view, shared->email, c_pager);
679 }
680 else
681 {
682 op = mutt_display_message(priv->win_index, shared);
683 }
684
686 if (op < OP_NULL)
687 {
688 OptNeedResort = false;
689 return FR_ERROR;
690 }
691
692 if (shared->mailbox)
693 {
695 shared->mailbox->msg_count, shared);
696 }
697
698 return op;
699}
700
704static int op_edit_label(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
705{
706 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
707 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
708 int num_changed = mutt_label_message(shared->mailbox_view, &ea);
709 ARRAY_FREE(&ea);
710
711 if (num_changed > 0)
712 {
713 shared->mailbox->changed = true;
715 /* L10N: This is displayed when the x-label on one or more
716 messages is edited. */
717 mutt_message(ngettext("%d label changed", "%d labels changed", num_changed), num_changed);
718
719 if (!priv->tag_prefix)
721 return FR_SUCCESS;
722 }
723
724 /* L10N: This is displayed when editing an x-label, but no messages
725 were updated. Possibly due to canceling at the prompt or if the new
726 label is the same as the old label. */
727 mutt_message(_("No labels changed"));
728 return FR_NO_ACTION;
729}
730
739static int op_edit_raw_message(struct IndexSharedData *shared,
740 struct IndexPrivateData *priv, int op)
741{
742 /* TODO split this into 3 cases? */
743 bool edit;
744 if (op == OP_EDIT_RAW_MESSAGE)
745 {
746 /* L10N: CHECK_ACL */
747 if (!check_acl(shared->mailbox, MUTT_ACL_INSERT, _("Can't edit message")))
748 return FR_ERROR;
749 edit = true;
750 }
751 else if (op == OP_EDIT_OR_VIEW_RAW_MESSAGE)
752 {
753 edit = !shared->mailbox->readonly && (shared->mailbox->rights & MUTT_ACL_INSERT);
754 }
755 else
756 {
757 edit = false;
758 }
759
760 if (!shared->email)
761 return FR_NO_ACTION;
762 const bool c_pgp_auto_decode = cs_subset_bool(shared->sub, "pgp_auto_decode");
763 if (c_pgp_auto_decode &&
764 (priv->tag_prefix || !(shared->email->security & PGP_TRADITIONAL_CHECKED)))
765 {
766 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
767 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
768 if (mutt_check_traditional_pgp(shared->mailbox, &ea))
770 ARRAY_FREE(&ea);
771 }
772 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
773 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
774 mutt_ev_message(shared->mailbox, &ea, edit ? EVM_EDIT : EVM_VIEW);
775 ARRAY_FREE(&ea);
777
778 return FR_SUCCESS;
779}
780
784static int op_end_cond(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
785{
786 return FR_SUCCESS;
787}
788
792static int op_exit(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
793{
794 if (shared->attach_msg)
795 return FR_DONE;
796
797 if (query_quadoption(_("Exit NeoMutt without saving?"), shared->sub, "quit") == MUTT_YES)
798 {
799 if (shared->mailbox_view)
800 {
801 mx_fastclose_mailbox(shared->mailbox, false);
802 mview_free(&shared->mailbox_view);
803 }
804 return FR_DONE;
805 }
806
807 return FR_NO_ACTION;
808}
809
813static int op_extract_keys(struct IndexSharedData *shared,
814 struct IndexPrivateData *priv, int op)
815{
816 if (!WithCrypto)
817 return FR_NOT_IMPL;
818 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
819 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
821 ARRAY_FREE(&ea);
823
824 return FR_SUCCESS;
825}
826
830static int op_flag_message(struct IndexSharedData *shared,
831 struct IndexPrivateData *priv, int op)
832{
833 /* L10N: CHECK_ACL */
834 if (!check_acl(shared->mailbox, MUTT_ACL_WRITE, _("Can't flag message")))
835 return FR_ERROR;
836
837 struct Mailbox *m = shared->mailbox;
838 if (priv->tag_prefix)
839 {
840 for (size_t i = 0; i < m->msg_count; i++)
841 {
842 struct Email *e = m->emails[i];
843 if (!e)
844 break;
845 if (message_is_tagged(e))
846 mutt_set_flag(m, e, MUTT_FLAG, !e->flagged, true);
847 }
848
850 }
851 else
852 {
853 if (!shared->email)
854 return FR_NO_ACTION;
855 mutt_set_flag(m, shared->email, MUTT_FLAG, !shared->email->flagged, true);
856
858 }
859
860 return FR_SUCCESS;
861}
862
866static int op_forget_passphrase(struct IndexSharedData *shared,
867 struct IndexPrivateData *priv, int op)
868{
870 return FR_SUCCESS;
871}
872
876static int op_forward_message(struct IndexSharedData *shared,
877 struct IndexPrivateData *priv, int op)
878{
879 if (!shared->email)
880 return FR_NO_ACTION;
881 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
882 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
883 const bool c_pgp_auto_decode = cs_subset_bool(shared->sub, "pgp_auto_decode");
884 if (c_pgp_auto_decode &&
885 (priv->tag_prefix || !(shared->email->security & PGP_TRADITIONAL_CHECKED)))
886 {
887 if (mutt_check_traditional_pgp(shared->mailbox, &ea))
889 }
890 int rc = mutt_send_message(SEND_FORWARD, NULL, NULL, shared->mailbox, &ea,
891 shared->sub);
892 ARRAY_FREE(&ea);
894
895 return (rc == -1) ? FR_ERROR : FR_SUCCESS;
896}
897
905static int op_group_reply(struct IndexSharedData *shared,
906 struct IndexPrivateData *priv, int op)
907{
908 SendFlags replyflags = SEND_REPLY;
909 if (op == OP_GROUP_REPLY)
910 replyflags |= SEND_GROUP_REPLY;
911 else
912 replyflags |= SEND_GROUP_CHAT_REPLY;
913 if (!shared->email)
914 return FR_NO_ACTION;
915 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
916 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
917 const bool c_pgp_auto_decode = cs_subset_bool(shared->sub, "pgp_auto_decode");
918 if (c_pgp_auto_decode &&
919 (priv->tag_prefix || !(shared->email->security & PGP_TRADITIONAL_CHECKED)))
920 {
921 if (mutt_check_traditional_pgp(shared->mailbox, &ea))
923 }
924 int rc = mutt_send_message(replyflags, NULL, NULL, shared->mailbox, &ea,
925 shared->sub);
926 ARRAY_FREE(&ea);
928
929 return (rc == -1) ? FR_ERROR : FR_SUCCESS;
930}
931
935static int op_jump(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
936{
937 int rc = FR_ERROR;
938 struct Buffer *buf = buf_pool_get();
939
940 const int digit = op - OP_JUMP;
941 if ((digit > 0) && (digit < 10))
942 {
943 mutt_unget_ch('0' + digit);
944 }
945
946 int msg_num = 0;
947 if ((mw_get_field(_("Jump to message: "), buf, MUTT_COMP_NO_FLAGS, HC_OTHER, NULL, NULL) != 0) ||
948 buf_is_empty(buf))
949 {
950 mutt_message(_("Nothing to do"));
951 rc = FR_NO_ACTION;
952 }
953 else if (!mutt_str_atoi_full(buf_string(buf), &msg_num))
954 {
955 mutt_warning(_("Argument must be a message number"));
956 }
957 else if ((msg_num < 1) || (msg_num > shared->mailbox->msg_count))
958 {
959 mutt_warning(_("Invalid message number"));
960 }
961 else if (!shared->mailbox->emails[msg_num - 1]->visible)
962 {
963 mutt_warning(_("That message is not visible"));
964 }
965 else
966 {
967 struct Email *e = shared->mailbox->emails[msg_num - 1];
968
969 if (mutt_messages_in_thread(shared->mailbox, e, MIT_POSITION) > 1)
970 {
972 mutt_set_vnum(shared->mailbox);
973 }
974 menu_set_index(priv->menu, e->vnum);
975 rc = FR_SUCCESS;
976 }
977
978 buf_pool_release(&buf);
979 return rc;
980}
981
985static int op_list_reply(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
986{
987 if (!shared->email)
988 return FR_NO_ACTION;
989 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
990 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
991 const bool c_pgp_auto_decode = cs_subset_bool(shared->sub, "pgp_auto_decode");
992 if (c_pgp_auto_decode &&
993 (priv->tag_prefix || !(shared->email->security & PGP_TRADITIONAL_CHECKED)))
994 {
995 if (mutt_check_traditional_pgp(shared->mailbox, &ea))
997 }
998 int rc = mutt_send_message(SEND_REPLY | SEND_LIST_REPLY, NULL, NULL,
999 shared->mailbox, &ea, shared->sub);
1000 ARRAY_FREE(&ea);
1002
1003 return (rc == -1) ? FR_ERROR : FR_SUCCESS;
1004}
1005
1009static int op_list_subscribe(struct IndexSharedData *shared,
1010 struct IndexPrivateData *priv, int op)
1011{
1012 return mutt_send_list_subscribe(shared->mailbox, shared->email) ? FR_SUCCESS : FR_NO_ACTION;
1013}
1014
1018static int op_list_unsubscribe(struct IndexSharedData *shared,
1019 struct IndexPrivateData *priv, int op)
1020{
1021 return mutt_send_list_unsubscribe(shared->mailbox, shared->email) ? FR_SUCCESS : FR_NO_ACTION;
1022}
1023
1027static int op_mail(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
1028{
1029 int rc = mutt_send_message(SEND_NO_FLAGS, NULL, NULL, shared->mailbox, NULL,
1030 shared->sub);
1032 return (rc == -1) ? FR_ERROR : FR_SUCCESS;
1033}
1034
1038static int op_mailbox_list(struct IndexSharedData *shared,
1039 struct IndexPrivateData *priv, int op)
1040{
1042 return FR_SUCCESS;
1043}
1044
1048static int op_mail_key(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
1049{
1050 if (!(WithCrypto & APPLICATION_PGP))
1051 return FR_NOT_IMPL;
1052 int rc = mutt_send_message(SEND_KEY, NULL, NULL, NULL, NULL, shared->sub);
1054
1055 return (rc == -1) ? FR_ERROR : FR_SUCCESS;
1056}
1057
1061static int op_main_break_thread(struct IndexSharedData *shared,
1062 struct IndexPrivateData *priv, int op)
1063{
1064 struct Mailbox *m = shared->mailbox;
1065 /* L10N: CHECK_ACL */
1066 if (!check_acl(m, MUTT_ACL_WRITE, _("Can't break thread")))
1067 return FR_ERROR;
1068
1069 struct Email *e = shared->email;
1070 if (!e)
1071 return FR_NO_ACTION;
1072
1073 if (!mutt_using_threads())
1074 {
1075 mutt_warning(_("Threading is not enabled"));
1076 return FR_NO_ACTION;
1077 }
1078
1079 struct MailboxView *mv = shared->mailbox_view;
1081 {
1082 {
1084 mutt_sort_headers(mv, true);
1085 menu_set_index(priv->menu, e->vnum);
1086 }
1087
1088 m->changed = true;
1089 mutt_message(_("Thread broken"));
1090
1092 }
1093 else
1094 {
1095 mutt_error(_("Thread can't be broken, message is not part of a thread"));
1096 }
1097
1098 return FR_SUCCESS;
1099}
1100
1109static int op_main_change_folder(struct IndexSharedData *shared,
1110 struct IndexPrivateData *priv, int op)
1111{
1112 struct Buffer *folderbuf = buf_pool_get();
1113 buf_alloc(folderbuf, PATH_MAX);
1114
1115 char *cp = NULL;
1116 bool read_only;
1117 const bool c_read_only = cs_subset_bool(shared->sub, "read_only");
1118 if (shared->attach_msg || c_read_only || (op == OP_MAIN_CHANGE_FOLDER_READONLY))
1119 {
1120 cp = _("Open mailbox in read-only mode");
1121 read_only = true;
1122 }
1123 else
1124 {
1125 cp = _("Open mailbox");
1126 read_only = false;
1127 }
1128
1129 const bool c_change_folder_next = cs_subset_bool(shared->sub, "change_folder_next");
1130 if (c_change_folder_next && shared->mailbox && !buf_is_empty(&shared->mailbox->pathbuf))
1131 {
1132 buf_strcpy(folderbuf, mailbox_path(shared->mailbox));
1133 buf_pretty_mailbox(folderbuf);
1134 }
1135 /* By default, fill buf with the next mailbox that contains unread mail */
1136 mutt_mailbox_next(shared->mailbox_view ? shared->mailbox : NULL, folderbuf);
1137
1138 if (mw_enter_fname(cp, folderbuf, true, shared->mailbox, false, NULL, NULL,
1139 MUTT_SEL_NO_FLAGS) == -1)
1140 {
1141 goto changefoldercleanup;
1142 }
1143
1144 /* Selected directory is okay, let's save it. */
1146
1147 if (buf_is_empty(folderbuf))
1148 {
1149 msgwin_clear_text(NULL);
1150 goto changefoldercleanup;
1151 }
1152
1153 struct Mailbox *m = mx_mbox_find2(buf_string(folderbuf));
1154 if (m)
1155 {
1156 change_folder_mailbox(priv->menu, m, &priv->oldcount, shared, read_only);
1157 }
1158 else
1159 {
1160 change_folder_string(priv->menu, folderbuf, &priv->oldcount, shared, read_only);
1161 }
1162
1163changefoldercleanup:
1164 buf_pool_release(&folderbuf);
1166
1167 return FR_SUCCESS;
1168}
1169
1173static int op_main_collapse_all(struct IndexSharedData *shared,
1174 struct IndexPrivateData *priv, int op)
1175{
1176 if (!mutt_using_threads())
1177 {
1178 mutt_error(_("Threading is not enabled"));
1179 return FR_ERROR;
1180 }
1181 collapse_all(shared->mailbox_view, priv->menu, 1);
1182
1183 return FR_SUCCESS;
1184}
1185
1190 struct IndexPrivateData *priv, int op)
1191{
1192 if (!mutt_using_threads())
1193 {
1194 mutt_error(_("Threading is not enabled"));
1195 return FR_ERROR;
1196 }
1197
1198 if (!shared->email)
1199 return FR_NO_ACTION;
1200
1201 if (shared->email->collapsed)
1202 {
1203 int index = mutt_uncollapse_thread(shared->email);
1204 mutt_set_vnum(shared->mailbox);
1205 const bool c_uncollapse_jump = cs_subset_bool(shared->sub, "uncollapse_jump");
1206 if (c_uncollapse_jump)
1207 index = mutt_thread_next_unread(shared->email);
1208 menu_set_index(priv->menu, index);
1209 }
1210 else if (mutt_thread_can_collapse(shared->email))
1211 {
1213 mutt_set_vnum(shared->mailbox);
1214 }
1215 else
1216 {
1217 mutt_error(_("Thread contains unread or flagged messages"));
1218 return FR_ERROR;
1219 }
1220
1222
1223 return FR_SUCCESS;
1224}
1225
1229static int op_main_delete_pattern(struct IndexSharedData *shared,
1230 struct IndexPrivateData *priv, int op)
1231{
1232 /* L10N: CHECK_ACL */
1233 /* L10N: Due to the implementation details we do not know whether we
1234 delete zero, 1, 12, ... messages. So in English we use
1235 "messages". Your language might have other means to express this. */
1236 if (!check_acl(shared->mailbox, MUTT_ACL_DELETE, _("Can't delete messages")))
1237 return FR_ERROR;
1238
1239 mutt_pattern_func(shared->mailbox_view, MUTT_DELETE, _("Delete messages matching: "));
1241
1242 return FR_SUCCESS;
1243}
1244
1253static int op_main_limit(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
1254{
1255 const bool lmt = mview_has_limit(shared->mailbox_view);
1256 int old_index = shared->email ? shared->email->index : -1;
1257 if (op == OP_TOGGLE_READ)
1258 {
1259 char buf2[1024];
1260
1261 if (!lmt || !mutt_strn_equal(shared->mailbox_view->pattern, "!~R!~D~s", 8))
1262 {
1263 snprintf(buf2, sizeof(buf2), "!~R!~D~s%s", lmt ? shared->mailbox_view->pattern : ".*");
1264 }
1265 else
1266 {
1267 mutt_str_copy(buf2, shared->mailbox_view->pattern + 8, sizeof(buf2));
1268 if ((*buf2 == '\0') || mutt_strn_equal(buf2, ".*", 2))
1269 snprintf(buf2, sizeof(buf2), "~A");
1270 }
1271 mutt_str_replace(&shared->mailbox_view->pattern, buf2);
1273 }
1274
1275 if (((op == OP_LIMIT_CURRENT_THREAD) &&
1276 mutt_limit_current_thread(shared->mailbox_view, shared->email)) ||
1277 (op == OP_TOGGLE_READ) ||
1278 ((op == OP_MAIN_LIMIT) && (mutt_pattern_func(shared->mailbox_view, MUTT_LIMIT,
1279 _("Limit to messages matching: ")) == 0)))
1280 {
1281 priv->menu->max = shared->mailbox->vcount;
1282 menu_set_index(priv->menu, 0);
1283 if (old_index >= 0)
1284 {
1285 /* try to find what used to be the current message */
1286 for (size_t i = 0; i < shared->mailbox->vcount; i++)
1287 {
1288 struct Email *e = mutt_get_virt_email(shared->mailbox, i);
1289 if (!e)
1290 continue;
1291 if (e->index == old_index)
1292 {
1293 menu_set_index(priv->menu, i);
1294 break;
1295 }
1296 }
1297 }
1298
1299 if ((shared->mailbox->msg_count != 0) && mutt_using_threads())
1300 {
1301 const bool c_collapse_all = cs_subset_bool(shared->sub, "collapse_all");
1302 if (c_collapse_all)
1303 collapse_all(shared->mailbox_view, priv->menu, 0);
1305 }
1307 }
1308 if (lmt)
1309 mutt_message(_("To view all messages, limit to \"all\""));
1310
1311 return FR_SUCCESS;
1312}
1313
1317static int op_main_link_threads(struct IndexSharedData *shared,
1318 struct IndexPrivateData *priv, int op)
1319{
1320 struct Mailbox *m = shared->mailbox;
1321 /* L10N: CHECK_ACL */
1322 if (!check_acl(m, MUTT_ACL_WRITE, _("Can't link threads")))
1323 return FR_ERROR;
1324
1325 struct Email *e = shared->email;
1326 if (!e)
1327 return FR_NO_ACTION;
1328
1329 enum FunctionRetval rc = FR_ERROR;
1330
1331 if (!mutt_using_threads())
1332 {
1333 mutt_error(_("Threading is not enabled"));
1334 }
1335 else if (!e->env->message_id)
1336 {
1337 mutt_error(_("No Message-ID: header available to link thread"));
1338 }
1339 else
1340 {
1341 struct MailboxView *mv = shared->mailbox_view;
1342 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
1343 ea_add_tagged(&ea, mv, NULL, true);
1344
1345 if (mutt_link_threads(e, &ea, m))
1346 {
1347 mutt_sort_headers(mv, true);
1348 menu_set_index(priv->menu, e->vnum);
1349
1350 m->changed = true;
1351 mutt_message(_("Threads linked"));
1352 rc = FR_SUCCESS;
1353 }
1354 else
1355 {
1356 mutt_error(_("No thread linked"));
1357 rc = FR_NO_ACTION;
1358 }
1359
1360 ARRAY_FREE(&ea);
1361 }
1362
1364 return rc;
1365}
1366
1374static int op_main_modify_tags(struct IndexSharedData *shared,
1375 struct IndexPrivateData *priv, int op)
1376{
1377 int rc = FR_ERROR;
1378 struct Buffer *buf = NULL;
1379
1380 if (!shared->mailbox)
1381 goto done;
1382 struct Mailbox *m = shared->mailbox;
1383 if (!mx_tags_is_supported(m))
1384 {
1385 mutt_message(_("Folder doesn't support tagging, aborting"));
1386 goto done;
1387 }
1388 if (!shared->email)
1389 {
1390 rc = FR_NO_ACTION;
1391 goto done;
1392 }
1393
1394 char *tags = NULL;
1395 if (!priv->tag_prefix)
1396 tags = driver_tags_get_with_hidden(&shared->email->tags);
1397 buf = buf_pool_get();
1398 int rc2 = mx_tags_edit(m, tags, buf);
1399 FREE(&tags);
1400 if (rc2 < 0)
1401 {
1402 goto done;
1403 }
1404 else if (rc2 == 0)
1405 {
1406 mutt_message(_("No tag specified, aborting"));
1407 goto done;
1408 }
1409
1410 if (priv->tag_prefix)
1411 {
1412 struct Progress *progress = NULL;
1413
1414 if (m->verbose)
1415 {
1416 progress = progress_new(_("Update tags..."), MUTT_PROGRESS_WRITE, m->msg_tagged);
1417 }
1418
1419#ifdef USE_NOTMUCH
1420 if (m->type == MUTT_NOTMUCH)
1421 nm_db_longrun_init(m, true);
1422#endif
1423 for (int px = 0, i = 0; i < m->msg_count; i++)
1424 {
1425 struct Email *e = m->emails[i];
1426 if (!e)
1427 break;
1428 if (!message_is_tagged(e))
1429 continue;
1430
1431 progress_update(progress, ++px, -1);
1432 mx_tags_commit(m, e, buf_string(buf));
1433 e->attr_color = NULL;
1434 if (op == OP_MAIN_MODIFY_TAGS_THEN_HIDE)
1435 {
1436 bool still_queried = false;
1437#ifdef USE_NOTMUCH
1438 if (m->type == MUTT_NOTMUCH)
1439 still_queried = nm_message_is_still_queried(m, e);
1440#endif
1441 e->quasi_deleted = !still_queried;
1442 m->changed = true;
1443 }
1444 }
1445 progress_free(&progress);
1446#ifdef USE_NOTMUCH
1447 if (m->type == MUTT_NOTMUCH)
1449#endif
1451 }
1452 else
1453 {
1454 if (mx_tags_commit(m, shared->email, buf_string(buf)))
1455 {
1456 mutt_message(_("Failed to modify tags, aborting"));
1457 goto done;
1458 }
1459 shared->email->attr_color = NULL;
1460 if (op == OP_MAIN_MODIFY_TAGS_THEN_HIDE)
1461 {
1462 bool still_queried = false;
1463#ifdef USE_NOTMUCH
1464 if (m->type == MUTT_NOTMUCH)
1465 still_queried = nm_message_is_still_queried(m, shared->email);
1466#endif
1467 shared->email->quasi_deleted = !still_queried;
1468 m->changed = true;
1469 }
1470
1472 }
1473 rc = FR_SUCCESS;
1474
1475done:
1476 buf_pool_release(&buf);
1477 return rc;
1478}
1479
1491static int op_main_next_new(struct IndexSharedData *shared,
1492 struct IndexPrivateData *priv, int op)
1493{
1494 int first_unread = -1;
1495 int first_new = -1;
1496
1497 const int saved_current = menu_get_index(priv->menu);
1498 int mcur = saved_current;
1499 int index = -1;
1500 const bool threaded = mutt_using_threads();
1501 for (size_t i = 0; i != shared->mailbox->vcount; i++)
1502 {
1503 if ((op == OP_MAIN_NEXT_NEW) || (op == OP_MAIN_NEXT_UNREAD) ||
1504 (op == OP_MAIN_NEXT_NEW_THEN_UNREAD))
1505 {
1506 mcur++;
1507 if (mcur > (shared->mailbox->vcount - 1))
1508 {
1509 mcur = 0;
1510 }
1511 }
1512 else
1513 {
1514 mcur--;
1515 if (mcur < 0)
1516 {
1517 mcur = shared->mailbox->vcount - 1;
1518 }
1519 }
1520
1521 struct Email *e = mutt_get_virt_email(shared->mailbox, mcur);
1522 if (!e)
1523 break;
1524 if (e->collapsed && threaded)
1525 {
1526 int unread = mutt_thread_contains_unread(e);
1527 if ((unread != 0) && (first_unread == -1))
1528 first_unread = mcur;
1529 if ((unread == 1) && (first_new == -1))
1530 first_new = mcur;
1531 }
1532 else if (!e->deleted && !e->read)
1533 {
1534 if (first_unread == -1)
1535 first_unread = mcur;
1536 if (!e->old && (first_new == -1))
1537 first_new = mcur;
1538 }
1539
1540 if (((op == OP_MAIN_NEXT_UNREAD) || (op == OP_MAIN_PREV_UNREAD)) && (first_unread != -1))
1541 {
1542 break;
1543 }
1544 if (((op == OP_MAIN_NEXT_NEW) || (op == OP_MAIN_PREV_NEW) ||
1545 (op == OP_MAIN_NEXT_NEW_THEN_UNREAD) || (op == OP_MAIN_PREV_NEW_THEN_UNREAD)) &&
1546 (first_new != -1))
1547 {
1548 break;
1549 }
1550 }
1551 if (((op == OP_MAIN_NEXT_NEW) || (op == OP_MAIN_PREV_NEW) ||
1552 (op == OP_MAIN_NEXT_NEW_THEN_UNREAD) || (op == OP_MAIN_PREV_NEW_THEN_UNREAD)) &&
1553 (first_new != -1))
1554 {
1555 index = first_new;
1556 }
1557 else if (((op == OP_MAIN_NEXT_UNREAD) || (op == OP_MAIN_PREV_UNREAD) ||
1558 (op == OP_MAIN_NEXT_NEW_THEN_UNREAD) || (op == OP_MAIN_PREV_NEW_THEN_UNREAD)) &&
1559 (first_unread != -1))
1560 {
1561 index = first_unread;
1562 }
1563
1564 if (index == -1)
1565 {
1566 menu_set_index(priv->menu, saved_current);
1567 if ((op == OP_MAIN_NEXT_NEW) || (op == OP_MAIN_PREV_NEW))
1568 {
1569 if (mview_has_limit(shared->mailbox_view))
1570 mutt_error(_("No new messages in this limited view"));
1571 else
1572 mutt_error(_("No new messages"));
1573 }
1574 else
1575 {
1576 if (mview_has_limit(shared->mailbox_view))
1577 mutt_error(_("No unread messages in this limited view"));
1578 else
1579 mutt_error(_("No unread messages"));
1580 }
1581 notify_send(shared->notify, NT_INDEX, NT_INDEX_EMAIL, NULL);
1582 return FR_ERROR;
1583 }
1584 else
1585 {
1586 menu_set_index(priv->menu, index);
1587 }
1588
1589 index = menu_get_index(priv->menu);
1590 if ((op == OP_MAIN_NEXT_NEW) || (op == OP_MAIN_NEXT_UNREAD) ||
1591 (op == OP_MAIN_NEXT_NEW_THEN_UNREAD))
1592 {
1593 if (saved_current > index)
1594 {
1595 mutt_message(_("Search wrapped to top"));
1596 }
1597 }
1598 else if (saved_current < index)
1599 {
1600 mutt_message(_("Search wrapped to bottom"));
1601 }
1602
1603 return FR_SUCCESS;
1604}
1605
1615static int op_main_next_thread(struct IndexSharedData *shared,
1616 struct IndexPrivateData *priv, int op)
1617{
1618 int index = -1;
1619 switch (op)
1620 {
1621 case OP_MAIN_NEXT_THREAD:
1622 index = mutt_next_thread(shared->email);
1623 break;
1624
1625 case OP_MAIN_NEXT_SUBTHREAD:
1626 index = mutt_next_subthread(shared->email);
1627 break;
1628
1629 case OP_MAIN_PREV_THREAD:
1630 index = mutt_previous_thread(shared->email);
1631 break;
1632
1633 case OP_MAIN_PREV_SUBTHREAD:
1635 break;
1636 }
1637
1638 if (index != -1)
1639 menu_set_index(priv->menu, index);
1640
1641 if (index < 0)
1642 {
1643 if ((op == OP_MAIN_NEXT_THREAD) || (op == OP_MAIN_NEXT_SUBTHREAD))
1644 mutt_error(_("No more threads"));
1645 else
1646 mutt_error(_("You are on the first thread"));
1647
1648 notify_send(shared->notify, NT_INDEX, NT_INDEX_EMAIL, NULL);
1649 }
1650
1651 return FR_SUCCESS;
1652}
1653
1657static int op_main_next_undeleted(struct IndexSharedData *shared,
1658 struct IndexPrivateData *priv, int op)
1659{
1660 int index = menu_get_index(priv->menu);
1661 if (index >= (shared->mailbox->vcount - 1))
1662 {
1663 notify_send(shared->notify, NT_INDEX, NT_INDEX_EMAIL, NULL);
1664 mutt_message(_("You are on the last message"));
1665 return FR_ERROR;
1666 }
1667
1668 const bool uncollapse = mutt_using_threads() && !window_is_focused(priv->win_index);
1669
1670 index = find_next_undeleted(shared->mailbox_view, index, uncollapse);
1671 if (index != -1)
1672 {
1673 menu_set_index(priv->menu, index);
1674 if (uncollapse)
1676 }
1677
1678 if (index == -1)
1679 {
1680 notify_send(shared->notify, NT_INDEX, NT_INDEX_EMAIL, NULL);
1681 mutt_error(_("No undeleted messages"));
1682 }
1683
1684 return FR_SUCCESS;
1685}
1686
1691 struct IndexPrivateData *priv, int op)
1692{
1693 struct Mailbox *m = shared->mailbox;
1694
1695 struct Buffer *folderbuf = buf_pool_get();
1696 buf_strcpy(folderbuf, mailbox_path(m));
1697 m = mutt_mailbox_next_unread(m, folderbuf);
1698 buf_pool_release(&folderbuf);
1699
1700 if (!m)
1701 {
1702 mutt_error(_("No mailboxes have new mail"));
1703 return FR_ERROR;
1704 }
1705
1706 change_folder_mailbox(priv->menu, m, &priv->oldcount, shared, false);
1707 return FR_SUCCESS;
1708}
1709
1713static int op_main_prev_undeleted(struct IndexSharedData *shared,
1714 struct IndexPrivateData *priv, int op)
1715{
1716 int index = menu_get_index(priv->menu);
1717 if (index < 1)
1718 {
1719 notify_send(shared->notify, NT_INDEX, NT_INDEX_EMAIL, NULL);
1720 mutt_message(_("You are on the first message"));
1721 return FR_ERROR;
1722 }
1723
1724 const bool uncollapse = mutt_using_threads() && !window_is_focused(priv->win_index);
1725
1726 index = find_previous_undeleted(shared->mailbox_view, index, uncollapse);
1727 if (index != -1)
1728 {
1729 menu_set_index(priv->menu, index);
1730 if (uncollapse)
1732 }
1733
1734 if (index == -1)
1735 {
1736 mutt_error(_("No undeleted messages"));
1737 notify_send(shared->notify, NT_INDEX, NT_INDEX_EMAIL, NULL);
1738 }
1739
1740 return FR_SUCCESS;
1741}
1742
1746static int op_main_quasi_delete(struct IndexSharedData *shared,
1747 struct IndexPrivateData *priv, int op)
1748{
1749 if (priv->tag_prefix)
1750 {
1751 struct Mailbox *m = shared->mailbox;
1752 for (size_t i = 0; i < m->msg_count; i++)
1753 {
1754 struct Email *e = m->emails[i];
1755 if (!e)
1756 break;
1757 if (message_is_tagged(e))
1758 {
1759 e->quasi_deleted = true;
1760 m->changed = true;
1761 }
1762 }
1763 }
1764 else
1765 {
1766 if (!shared->email)
1767 return FR_NO_ACTION;
1768 shared->email->quasi_deleted = true;
1769 shared->mailbox->changed = true;
1770 }
1771
1772 return FR_SUCCESS;
1773}
1774
1782static int op_main_read_thread(struct IndexSharedData *shared,
1783 struct IndexPrivateData *priv, int op)
1784{
1785 /* L10N: CHECK_ACL */
1786 /* L10N: Due to the implementation details we do not know whether we
1787 mark zero, 1, 12, ... messages as read. So in English we use
1788 "messages". Your language might have other means to express this. */
1789 if (!check_acl(shared->mailbox, MUTT_ACL_SEEN, _("Can't mark messages as read")))
1790 return FR_ERROR;
1791
1792 int rc = mutt_thread_set_flag(shared->mailbox, shared->email, MUTT_READ, true,
1793 (op != OP_MAIN_READ_THREAD));
1794 if (rc != -1)
1795 {
1796 const enum ResolveMethod rm = (op == OP_MAIN_READ_THREAD) ? RESOLVE_NEXT_THREAD :
1798 resolve_email(priv, shared, rm);
1800 }
1801
1802 return FR_SUCCESS;
1803}
1804
1812static int op_main_root_message(struct IndexSharedData *shared,
1813 struct IndexPrivateData *priv, int op)
1814{
1815 int index = mutt_parent_message(shared->email, op == OP_MAIN_ROOT_MESSAGE);
1816 if (index != -1)
1817 menu_set_index(priv->menu, index);
1818
1819 return FR_SUCCESS;
1820}
1821
1829static int op_main_set_flag(struct IndexSharedData *shared,
1830 struct IndexPrivateData *priv, int op)
1831{
1832 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
1833 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
1834
1835 if (mw_change_flag(shared->mailbox, &ea, (op == OP_MAIN_SET_FLAG)) == 0)
1836 {
1837 if (priv->tag_prefix)
1838 {
1840 }
1841 else
1842 {
1844 }
1845 }
1846 ARRAY_FREE(&ea);
1847
1848 return FR_SUCCESS;
1849}
1850
1854static int op_main_show_limit(struct IndexSharedData *shared,
1855 struct IndexPrivateData *priv, int op)
1856{
1857 if (mview_has_limit(shared->mailbox_view))
1858 {
1859 char buf2[256];
1860 /* L10N: ask for a limit to apply */
1861 snprintf(buf2, sizeof(buf2), _("Limit: %s"), shared->mailbox_view->pattern);
1862 mutt_message("%s", buf2);
1863 }
1864 else
1865 {
1866 mutt_message(_("No limit pattern is in effect"));
1867 }
1868
1869 return FR_SUCCESS;
1870}
1871
1875static int op_main_sync_folder(struct IndexSharedData *shared,
1876 struct IndexPrivateData *priv, int op)
1877{
1878 if (!shared->mailbox || (shared->mailbox->msg_count == 0) || shared->mailbox->readonly)
1879 return FR_NO_ACTION;
1880
1881 int ovc = shared->mailbox->vcount;
1882 int oc = shared->mailbox->msg_count;
1883 struct Email *e = NULL;
1884
1885 /* don't attempt to move the cursor if there are no visible messages in the current limit */
1886 int index = menu_get_index(priv->menu);
1887 if (index < shared->mailbox->vcount)
1888 {
1889 /* threads may be reordered, so figure out what header the cursor
1890 * should be on. */
1891 int newidx = index;
1892 if (!shared->email)
1893 return FR_NO_ACTION;
1894 if (shared->email->deleted)
1895 newidx = find_next_undeleted(shared->mailbox_view, index, false);
1896 if (newidx < 0)
1897 newidx = find_previous_undeleted(shared->mailbox_view, index, false);
1898 if (newidx >= 0)
1899 e = mutt_get_virt_email(shared->mailbox, newidx);
1900 }
1901
1902 enum MxStatus check = mx_mbox_sync(shared->mailbox);
1903 if (check == MX_STATUS_OK)
1904 {
1905 if (e && (shared->mailbox->vcount != ovc))
1906 {
1907 for (size_t i = 0; i < shared->mailbox->vcount; i++)
1908 {
1909 struct Email *e2 = mutt_get_virt_email(shared->mailbox, i);
1910 if (e2 == e)
1911 {
1912 menu_set_index(priv->menu, i);
1913 break;
1914 }
1915 }
1916 }
1918 }
1919 else if ((check == MX_STATUS_NEW_MAIL) || (check == MX_STATUS_REOPENED))
1920 {
1921 update_index(priv->menu, shared->mailbox_view, check, oc, shared);
1922 }
1923
1924 /* do a sanity check even if mx_mbox_sync failed. */
1925
1926 index = menu_get_index(priv->menu);
1927 if ((index < 0) || (shared->mailbox && (index >= shared->mailbox->vcount)))
1928 {
1930 }
1931
1932 /* check for a fatal error, or all messages deleted */
1933 if (shared->mailbox && buf_is_empty(&shared->mailbox->pathbuf))
1934 {
1935 mview_free(&shared->mailbox_view);
1936 }
1937
1938 priv->menu->max = shared->mailbox->vcount;
1940
1941 return FR_SUCCESS;
1942}
1943
1947static int op_main_tag_pattern(struct IndexSharedData *shared,
1948 struct IndexPrivateData *priv, int op)
1949{
1950 mutt_pattern_func(shared->mailbox_view, MUTT_TAG, _("Tag messages matching: "));
1952
1953 return FR_SUCCESS;
1954}
1955
1960 struct IndexPrivateData *priv, int op)
1961{
1962 /* L10N: CHECK_ACL */
1963 /* L10N: Due to the implementation details we do not know whether we
1964 undelete zero, 1, 12, ... messages. So in English we use
1965 "messages". Your language might have other means to express this. */
1966 if (!check_acl(shared->mailbox, MUTT_ACL_DELETE, _("Can't undelete messages")))
1967 return FR_ERROR;
1968
1970 _("Undelete messages matching: ")) == 0)
1971 {
1973 }
1974
1975 return FR_SUCCESS;
1976}
1977
1981static int op_main_untag_pattern(struct IndexSharedData *shared,
1982 struct IndexPrivateData *priv, int op)
1983{
1984 if (mutt_pattern_func(shared->mailbox_view, MUTT_UNTAG, _("Untag messages matching: ")) == 0)
1986
1987 return FR_SUCCESS;
1988}
1989
1993static int op_mark_msg(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
1994{
1995 if (!shared->email)
1996 return FR_NO_ACTION;
1997
1998 int rc = FR_SUCCESS;
1999
2000 if (shared->email->env->message_id)
2001 {
2002 struct Buffer *buf = buf_pool_get();
2003
2004 /* L10N: This is the prompt for <mark-message>. Whatever they
2005 enter will be prefixed by $mark_macro_prefix and will become
2006 a macro hotkey to jump to the currently selected message. */
2007 if ((mw_get_field(_("Enter macro stroke: "), buf, MUTT_COMP_NO_FLAGS,
2008 HC_OTHER, NULL, NULL) == 0) &&
2009 !buf_is_empty(buf))
2010 {
2011 const char *const c_mark_macro_prefix = cs_subset_string(shared->sub, "mark_macro_prefix");
2012 char str[256] = { 0 };
2013 snprintf(str, sizeof(str), "%s%s", c_mark_macro_prefix, buf_string(buf));
2014
2015 struct Buffer *msg_id = buf_pool_get();
2016 mutt_file_sanitize_regex(msg_id, shared->email->env->message_id);
2017 char macro[256] = { 0 };
2018 snprintf(macro, sizeof(macro), "<search>~i '%s'\n", buf_string(msg_id));
2019 buf_pool_release(&msg_id);
2020
2021 /* L10N: "message hotkey" is the key bindings menu description of a
2022 macro created by <mark-message>. */
2023 km_bind(str, MENU_INDEX, OP_MACRO, macro, _("message hotkey"));
2024
2025 /* L10N: This is echoed after <mark-message> creates a new hotkey
2026 macro. %s is the hotkey string ($mark_macro_prefix followed
2027 by whatever they typed at the prompt.) */
2028 buf_printf(buf, _("Message bound to %s"), str);
2029 mutt_message("%s", buf_string(buf));
2030 mutt_debug(LL_DEBUG1, "Mark: %s => %s\n", str, macro);
2031 buf_pool_release(&buf);
2032 }
2033 }
2034 else
2035 {
2036 /* L10N: This error is printed if <mark-message> can't find a
2037 Message-ID for the currently selected message in the index. */
2038 mutt_error(_("No message ID to macro"));
2039 rc = FR_ERROR;
2040 }
2041
2042 return rc;
2043}
2044
2048static int op_next_entry(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
2049{
2050 const int index = menu_get_index(priv->menu) + 1;
2051 if (index >= shared->mailbox->vcount)
2052 {
2053 mutt_message(_("You are on the last message"));
2054 notify_send(shared->notify, NT_INDEX, NT_INDEX_EMAIL, NULL);
2055 return FR_ERROR;
2056 }
2057 menu_set_index(priv->menu, index);
2058 return FR_SUCCESS;
2059}
2060
2064static int op_pipe(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
2065{
2066 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
2067 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
2068 mutt_pipe_message(shared->mailbox, &ea);
2069 ARRAY_FREE(&ea);
2070
2071#ifdef USE_IMAP
2072 /* in an IMAP folder index with imap_peek=no, piping could change
2073 * new or old messages status to read. Redraw what's needed. */
2074 const bool c_imap_peek = cs_subset_bool(shared->sub, "imap_peek");
2075 if ((shared->mailbox->type == MUTT_IMAP) && !c_imap_peek)
2076 {
2078 }
2079#endif
2080
2081 return FR_SUCCESS;
2082}
2083
2087static int op_prev_entry(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
2088{
2089 int index = menu_get_index(priv->menu);
2090 if (index < 1)
2091 {
2092 notify_send(shared->notify, NT_INDEX, NT_INDEX_EMAIL, NULL);
2093 mutt_message(_("You are on the first message"));
2094 return FR_ERROR;
2095 }
2096 menu_set_index(priv->menu, index - 1);
2097 return FR_SUCCESS;
2098}
2099
2103static int op_print(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
2104{
2105 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
2106 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
2107 mutt_print_message(shared->mailbox, &ea);
2108 ARRAY_FREE(&ea);
2109
2110#ifdef USE_IMAP
2111 /* in an IMAP folder index with imap_peek=no, printing could change
2112 * new or old messages status to read. Redraw what's needed. */
2113 const bool c_imap_peek = cs_subset_bool(shared->sub, "imap_peek");
2114 if ((shared->mailbox->type == MUTT_IMAP) && !c_imap_peek)
2115 {
2117 }
2118#endif
2119
2120 return FR_SUCCESS;
2121}
2122
2126static int op_query(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
2127{
2128 query_index(shared->mailbox, shared->sub);
2129 return FR_SUCCESS;
2130}
2131
2135static int op_quit(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
2136{
2137 if (shared->attach_msg)
2138 return FR_DONE;
2139
2140 if (query_quadoption(_("Quit NeoMutt?"), shared->sub, "quit") == MUTT_YES)
2141 {
2142 priv->oldcount = shared->mailbox ? shared->mailbox->msg_count : 0;
2143
2145 mutt_debug(LL_NOTIFY, "NT_GLOBAL_SHUTDOWN\n");
2147
2148 enum MxStatus check = MX_STATUS_OK;
2149 if (!shared->mailbox_view || ((check = mx_mbox_close(shared->mailbox)) == MX_STATUS_OK))
2150 {
2151 mview_free(&shared->mailbox_view);
2152 mailbox_free(&shared->mailbox);
2153 return FR_DONE;
2154 }
2155
2156 if ((check == MX_STATUS_NEW_MAIL) || (check == MX_STATUS_REOPENED))
2157 {
2158 update_index(priv->menu, shared->mailbox_view, check, priv->oldcount, shared);
2159 }
2160
2161 menu_queue_redraw(priv->menu, MENU_REDRAW_FULL); /* new mail arrived? */
2163 }
2164
2165 return FR_NO_ACTION;
2166}
2167
2171static int op_recall_message(struct IndexSharedData *shared,
2172 struct IndexPrivateData *priv, int op)
2173{
2174 int rc = mutt_send_message(SEND_POSTPONED, NULL, NULL, shared->mailbox, NULL,
2175 shared->sub);
2177 return (rc == -1) ? FR_ERROR : FR_SUCCESS;
2178}
2179
2183static int op_reply(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
2184{
2185 if (!shared->email)
2186 return FR_NO_ACTION;
2187 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
2188 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
2189 const bool c_pgp_auto_decode = cs_subset_bool(shared->sub, "pgp_auto_decode");
2190 if (c_pgp_auto_decode &&
2191 (priv->tag_prefix || !(shared->email->security & PGP_TRADITIONAL_CHECKED)))
2192 {
2193 if (mutt_check_traditional_pgp(shared->mailbox, &ea))
2195 }
2196 int rc = mutt_send_message(SEND_REPLY, NULL, NULL, shared->mailbox, &ea,
2197 shared->sub);
2198 ARRAY_FREE(&ea);
2200
2201 return (rc == -1) ? FR_ERROR : FR_SUCCESS;
2202}
2203
2207static int op_resend(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
2208{
2209 int rc = -1;
2210 if (priv->tag_prefix)
2211 {
2212 struct Mailbox *m = shared->mailbox;
2213 for (size_t i = 0; i < m->msg_count; i++)
2214 {
2215 struct Email *e = m->emails[i];
2216 if (!e)
2217 break;
2218 if (message_is_tagged(e))
2219 rc = mutt_resend_message(NULL, shared->mailbox, e, shared->sub);
2220 }
2221 }
2222 else
2223 {
2224 rc = mutt_resend_message(NULL, shared->mailbox, shared->email, shared->sub);
2225 }
2226
2228 return (rc == -1) ? FR_ERROR : FR_SUCCESS;
2229}
2230
2242static int op_save(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
2243{
2244 if (((op == OP_DECRYPT_COPY) || (op == OP_DECRYPT_SAVE)) && !WithCrypto)
2245 return FR_NOT_IMPL;
2246
2247 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
2248 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
2249
2250 const enum MessageSaveOpt save_opt = ((op == OP_SAVE) || (op == OP_DECODE_SAVE) ||
2251 (op == OP_DECRYPT_SAVE)) ?
2252 SAVE_MOVE :
2253 SAVE_COPY;
2254
2255 enum MessageTransformOpt transform_opt =
2256 ((op == OP_DECODE_SAVE) || (op == OP_DECODE_COPY)) ? TRANSFORM_DECODE :
2257 ((op == OP_DECRYPT_SAVE) || (op == OP_DECRYPT_COPY)) ? TRANSFORM_DECRYPT :
2259
2260 const int rc = mutt_save_message(shared->mailbox, &ea, save_opt, transform_opt);
2261 if ((rc == 0) && (save_opt == SAVE_MOVE))
2262 {
2263 if (priv->tag_prefix)
2264 {
2266 }
2267 else
2268 {
2270 }
2271 }
2272 ARRAY_FREE(&ea);
2273
2274 return (rc == -1) ? FR_ERROR : FR_SUCCESS;
2275}
2276
2286static int op_search(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
2287{
2289 switch (op)
2290 {
2291 case OP_SEARCH:
2292 flags |= SEARCH_PROMPT;
2293 shared->search_state->reverse = false;
2294 break;
2295 case OP_SEARCH_REVERSE:
2296 flags |= SEARCH_PROMPT;
2297 shared->search_state->reverse = true;
2298 break;
2299 case OP_SEARCH_NEXT:
2300 break;
2301 case OP_SEARCH_OPPOSITE:
2302 flags |= SEARCH_OPPOSITE;
2303 break;
2304 }
2305
2306 // Initiating a search can happen on an empty mailbox, but
2307 // searching for next/previous/... needs to be on a message and
2308 // thus a non-empty mailbox
2309 int index = menu_get_index(priv->menu);
2310 index = mutt_search_command(shared->mailbox_view, priv->menu, index,
2311 shared->search_state, flags);
2312 if (index != -1)
2313 menu_set_index(priv->menu, index);
2314
2315 return FR_SUCCESS;
2316}
2317
2325static int op_sort(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
2326{
2327 if (!mutt_select_sort(op == OP_SORT_REVERSE))
2328 return FR_ERROR;
2329
2330 if (shared->mailbox && (shared->mailbox->msg_count != 0))
2331 {
2332 resort_index(shared->mailbox_view, priv->menu);
2334 }
2335
2336 return FR_SUCCESS;
2337}
2338
2342static int op_tag(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
2343{
2344 const bool c_auto_tag = cs_subset_bool(shared->sub, "auto_tag");
2345 if (priv->tag_prefix && !c_auto_tag)
2346 {
2347 struct Mailbox *m = shared->mailbox;
2348 for (size_t i = 0; i < m->msg_count; i++)
2349 {
2350 struct Email *e = m->emails[i];
2351 if (!e)
2352 break;
2353 if (e->visible)
2354 mutt_set_flag(m, e, MUTT_TAG, false, true);
2355 }
2357 return FR_SUCCESS;
2358 }
2359
2360 if (!shared->email)
2361 return FR_NO_ACTION;
2362
2363 mutt_set_flag(shared->mailbox, shared->email, MUTT_TAG, !shared->email->tagged, true);
2364
2365 resolve_email(priv, shared, RESOLVE_NEXT_EMAIL);
2366 return FR_SUCCESS;
2367}
2368
2376static int op_tag_thread(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
2377{
2378 if (!shared->email)
2379 return FR_NO_ACTION;
2380
2381 int rc = mutt_thread_set_flag(shared->mailbox, shared->email, MUTT_TAG,
2382 !shared->email->tagged, (op != OP_TAG_THREAD));
2383 if (rc != -1)
2384 {
2385 const enum ResolveMethod rm = (op == OP_TAG_THREAD) ? RESOLVE_NEXT_THREAD :
2387 resolve_email(priv, shared, rm);
2389 }
2390
2391 return FR_SUCCESS;
2392}
2393
2397static int op_toggle_new(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
2398{
2399 /* L10N: CHECK_ACL */
2400 if (!check_acl(shared->mailbox, MUTT_ACL_SEEN, _("Can't toggle new")))
2401 return FR_ERROR;
2402
2403 struct Mailbox *m = shared->mailbox;
2404 if (priv->tag_prefix)
2405 {
2406 for (size_t i = 0; i < m->msg_count; i++)
2407 {
2408 struct Email *e = m->emails[i];
2409 if (!e)
2410 break;
2411 if (!message_is_tagged(e))
2412 continue;
2413
2414 if (e->read || e->old)
2415 mutt_set_flag(m, e, MUTT_NEW, true, true);
2416 else
2417 mutt_set_flag(m, e, MUTT_READ, true, true);
2418 }
2420 }
2421 else
2422 {
2423 if (!shared->email)
2424 return FR_NO_ACTION;
2425 if (shared->email->read || shared->email->old)
2426 mutt_set_flag(m, shared->email, MUTT_NEW, true, true);
2427 else
2428 mutt_set_flag(m, shared->email, MUTT_READ, true, true);
2429
2431 }
2432
2433 return FR_SUCCESS;
2434}
2435
2439static int op_toggle_write(struct IndexSharedData *shared,
2440 struct IndexPrivateData *priv, int op)
2441{
2442 mx_toggle_write(shared->mailbox);
2443 return FR_SUCCESS;
2444}
2445
2449static int op_undelete(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
2450{
2451 /* L10N: CHECK_ACL */
2452 if (!check_acl(shared->mailbox, MUTT_ACL_DELETE, _("Can't undelete message")))
2453 return FR_ERROR;
2454
2455 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
2456 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
2457
2458 mutt_emails_set_flag(shared->mailbox, &ea, MUTT_DELETE, false);
2459 mutt_emails_set_flag(shared->mailbox, &ea, MUTT_PURGE, false);
2460 ARRAY_FREE(&ea);
2461
2462 if (priv->tag_prefix)
2463 {
2465 }
2466 else
2467 {
2468 resolve_email(priv, shared, RESOLVE_NEXT_EMAIL);
2469 }
2470
2471 return FR_SUCCESS;
2472}
2473
2481static int op_undelete_thread(struct IndexSharedData *shared,
2482 struct IndexPrivateData *priv, int op)
2483{
2484 /* L10N: CHECK_ACL */
2485 /* L10N: Due to the implementation details we do not know whether we
2486 undelete zero, 1, 12, ... messages. So in English we use
2487 "messages". Your language might have other means to express this. */
2488 if (!check_acl(shared->mailbox, MUTT_ACL_DELETE, _("Can't undelete messages")))
2489 return FR_ERROR;
2490
2491 int rc = mutt_thread_set_flag(shared->mailbox, shared->email, MUTT_DELETE,
2492 false, (op != OP_UNDELETE_THREAD));
2493 if (rc != -1)
2494 {
2495 rc = mutt_thread_set_flag(shared->mailbox, shared->email, MUTT_PURGE, false,
2496 (op != OP_UNDELETE_THREAD));
2497 }
2498 if (rc != -1)
2499 {
2500 const enum ResolveMethod rm = (op == OP_UNDELETE_THREAD) ? RESOLVE_NEXT_THREAD :
2502 resolve_email(priv, shared, rm);
2504 }
2505
2506 return FR_SUCCESS;
2507}
2508
2512static int op_view_attachments(struct IndexSharedData *shared,
2513 struct IndexPrivateData *priv, int op)
2514{
2515 if (!shared->email)
2516 return FR_NO_ACTION;
2517
2518 enum FunctionRetval rc = FR_ERROR;
2519 struct Message *msg = mx_msg_open(shared->mailbox, shared->email);
2520 if (msg)
2521 {
2522 dlg_attachment(NeoMutt->sub, shared->mailbox_view, shared->email, msg->fp,
2523 shared->attach_msg);
2524 if (shared->email->attach_del)
2525 {
2526 shared->mailbox->changed = true;
2527 }
2528 mx_msg_close(shared->mailbox, &msg);
2529 rc = FR_SUCCESS;
2530 }
2532 return rc;
2533}
2534
2535// -----------------------------------------------------------------------------
2536
2537#ifdef USE_AUTOCRYPT
2541static int op_autocrypt_acct_menu(struct IndexSharedData *shared,
2542 struct IndexPrivateData *priv, int op)
2543{
2544 dlg_autocrypt();
2545 return FR_SUCCESS;
2546}
2547#endif
2548
2549#ifdef USE_IMAP
2553static int op_main_imap_fetch(struct IndexSharedData *shared,
2554 struct IndexPrivateData *priv, int op)
2555{
2556 if (!shared->mailbox || (shared->mailbox->type != MUTT_IMAP))
2557 return FR_NO_ACTION;
2558
2559 imap_check_mailbox(shared->mailbox, true);
2560 return FR_SUCCESS;
2561}
2562
2567 struct IndexPrivateData *priv, int op)
2568{
2569 if (shared->mailbox && (shared->mailbox->type == MUTT_IMAP))
2570 {
2571 const enum MxStatus check = mx_mbox_close(shared->mailbox);
2572 if (check == MX_STATUS_OK)
2573 {
2574 mview_free(&shared->mailbox_view);
2575 }
2576 else
2577 {
2578 if ((check == MX_STATUS_NEW_MAIL) || (check == MX_STATUS_REOPENED))
2579 {
2580 update_index(priv->menu, shared->mailbox_view, check, priv->oldcount, shared);
2581 }
2584 return FR_ERROR;
2585 }
2586 }
2588 mutt_message(_("Logged out of IMAP servers"));
2591
2592 return FR_SUCCESS;
2593}
2594#endif
2595
2596#ifdef USE_NNTP
2600static int op_catchup(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
2601{
2602 struct Mailbox *m = shared->mailbox;
2603 if (!m || (m->type != MUTT_NNTP))
2604 return FR_NO_ACTION;
2605
2606 struct NntpMboxData *mdata = m->mdata;
2607 if (mutt_newsgroup_catchup(m, mdata->adata, mdata->group))
2609
2610 return FR_SUCCESS;
2611}
2612
2620static int op_get_children(struct IndexSharedData *shared,
2621 struct IndexPrivateData *priv, int op)
2622{
2623 struct Mailbox *m = shared->mailbox;
2624 if (m->type != MUTT_NNTP)
2625 return FR_ERROR;
2626
2627 struct Email *e = shared->email;
2628 if (!e)
2629 return FR_NO_ACTION;
2630
2631 char buf[PATH_MAX] = { 0 };
2632 int oldmsgcount = m->msg_count;
2633 int oldindex = e->index;
2634 int rc = 0;
2635
2636 if (!e->env->message_id)
2637 {
2638 mutt_error(_("No Message-Id. Unable to perform operation."));
2639 return FR_ERROR;
2640 }
2641
2642 mutt_message(_("Fetching message headers..."));
2643 if (!m->id_hash)
2644 m->id_hash = mutt_make_id_hash(m);
2645 mutt_str_copy(buf, e->env->message_id, sizeof(buf));
2646
2647 /* trying to find msgid of the root message */
2648 if (op == OP_RECONSTRUCT_THREAD)
2649 {
2650 struct ListNode *ref = NULL;
2651 STAILQ_FOREACH(ref, &e->env->references, entries)
2652 {
2653 if (!mutt_hash_find(m->id_hash, ref->data))
2654 {
2655 rc = nntp_check_msgid(m, ref->data);
2656 if (rc < 0)
2657 return FR_ERROR;
2658 }
2659
2660 /* the last msgid in References is the root message */
2661 if (!STAILQ_NEXT(ref, entries))
2662 mutt_str_copy(buf, ref->data, sizeof(buf));
2663 }
2664 }
2665
2666 /* fetching all child messages */
2667 rc = nntp_check_children(m, buf);
2668
2669 /* at least one message has been loaded */
2670 if (m->msg_count > oldmsgcount)
2671 {
2672 bool verbose = m->verbose;
2673
2674 if (rc < 0)
2675 m->verbose = false;
2676
2677 struct MailboxView *mv = shared->mailbox_view;
2678 mutt_sort_headers(mv, (op == OP_RECONSTRUCT_THREAD));
2679 m->verbose = verbose;
2680
2681 /* if the root message was retrieved, move to it */
2682 struct Email *e2 = mutt_hash_find(m->id_hash, buf);
2683 if (e2)
2684 {
2685 menu_set_index(priv->menu, e2->vnum);
2686 }
2687 else
2688 {
2689 /* try to restore old position */
2690 for (int i = 0; i < m->msg_count; i++)
2691 {
2692 e2 = m->emails[i];
2693 if (!e2)
2694 break;
2695 if (e2->index == oldindex)
2696 {
2697 menu_set_index(priv->menu, e2->vnum);
2698 /* as an added courtesy, recenter the menu
2699 * with the current entry at the middle of the screen */
2701 }
2702 }
2703 }
2705 }
2706 else if (rc >= 0)
2707 {
2708 mutt_error(_("No deleted messages found in the thread"));
2709 }
2710
2711 return FR_SUCCESS;
2712}
2713
2721static int op_get_message(struct IndexSharedData *shared,
2722 struct IndexPrivateData *priv, int op)
2723{
2724 struct Mailbox *m = shared->mailbox;
2725 if (m->type != MUTT_NNTP)
2726 return FR_SUCCESS;
2727
2728 int rc = FR_ERROR;
2729 struct Buffer *buf = buf_pool_get();
2730
2731 if (op == OP_GET_MESSAGE)
2732 {
2733 if ((mw_get_field(_("Enter Message-Id: "), buf, MUTT_COMP_NO_FLAGS,
2734 HC_OTHER, NULL, NULL) != 0) ||
2735 buf_is_empty(buf))
2736 {
2737 goto done;
2738 }
2739 }
2740 else
2741 {
2742 struct Email *e = shared->email;
2743 if (!e || STAILQ_EMPTY(&e->env->references))
2744 {
2745 mutt_error(_("Article has no parent reference"));
2746 goto done;
2747 }
2748 buf_strcpy(buf, STAILQ_FIRST(&e->env->references)->data);
2749 }
2750
2751 if (!m->id_hash)
2752 m->id_hash = mutt_make_id_hash(m);
2753 struct Email *e = mutt_hash_find(m->id_hash, buf_string(buf));
2754 if (e)
2755 {
2756 if (e->vnum != -1)
2757 {
2758 menu_set_index(priv->menu, e->vnum);
2759 }
2760 else if (e->collapsed)
2761 {
2763 mutt_set_vnum(m);
2764 menu_set_index(priv->menu, e->vnum);
2765 }
2766 else
2767 {
2768 mutt_error(_("Message is not visible in limited view"));
2769 }
2770 }
2771 else
2772 {
2773 mutt_message(_("Fetching %s from server..."), buf_string(buf));
2774 int rc2 = nntp_check_msgid(m, buf_string(buf));
2775 if (rc2 == 0)
2776 {
2777 e = m->emails[m->msg_count - 1];
2778 struct MailboxView *mv = shared->mailbox_view;
2779 mutt_sort_headers(mv, false);
2780 menu_set_index(priv->menu, e->vnum);
2782 rc = FR_SUCCESS;
2783 }
2784 else if (rc2 > 0)
2785 {
2786 mutt_error(_("Article %s not found on the server"), buf_string(buf));
2787 }
2788 }
2789
2790done:
2791 buf_pool_release(&buf);
2792 return rc;
2793}
2794
2802static int op_main_change_group(struct IndexSharedData *shared,
2803 struct IndexPrivateData *priv, int op)
2804{
2805 struct Buffer *folderbuf = buf_pool_get();
2806 buf_alloc(folderbuf, PATH_MAX);
2807
2808 OptNews = false;
2809 bool read_only;
2810 char *cp = NULL;
2811 const bool c_read_only = cs_subset_bool(shared->sub, "read_only");
2812 if (shared->attach_msg || c_read_only || (op == OP_MAIN_CHANGE_GROUP_READONLY))
2813 {
2814 cp = _("Open newsgroup in read-only mode");
2815 read_only = true;
2816 }
2817 else
2818 {
2819 cp = _("Open newsgroup");
2820 read_only = false;
2821 }
2822
2823 const bool c_change_folder_next = cs_subset_bool(shared->sub, "change_folder_next");
2824 if (c_change_folder_next && shared->mailbox && !buf_is_empty(&shared->mailbox->pathbuf))
2825 {
2826 buf_strcpy(folderbuf, mailbox_path(shared->mailbox));
2827 buf_pretty_mailbox(folderbuf);
2828 }
2829
2830 OptNews = true;
2831 const char *const c_news_server = cs_subset_string(shared->sub, "news_server");
2832 CurrentNewsSrv = nntp_select_server(shared->mailbox, c_news_server, false);
2833 if (!CurrentNewsSrv)
2834 goto changefoldercleanup2;
2835
2836 nntp_mailbox(shared->mailbox, folderbuf->data, folderbuf->dsize);
2837
2838 if (mw_enter_fname(cp, folderbuf, true, shared->mailbox, false, NULL, NULL,
2839 MUTT_SEL_NO_FLAGS) == -1)
2840 {
2841 goto changefoldercleanup2;
2842 }
2843
2844 /* Selected directory is okay, let's save it. */
2846
2847 if (buf_is_empty(folderbuf))
2848 {
2849 msgwin_clear_text(NULL);
2850 goto changefoldercleanup2;
2851 }
2852
2853 struct Mailbox *m = mx_mbox_find2(buf_string(folderbuf));
2854 if (m)
2855 {
2856 change_folder_mailbox(priv->menu, m, &priv->oldcount, shared, read_only);
2857 }
2858 else
2859 {
2860 change_folder_string(priv->menu, folderbuf, &priv->oldcount, shared, read_only);
2861 }
2862 struct MuttWindow *dlg = dialog_find(priv->win_index);
2863 dlg->help_data = IndexNewsHelp;
2864
2865changefoldercleanup2:
2866 buf_pool_release(&folderbuf);
2867 return FR_SUCCESS;
2868}
2869
2877static int op_post(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
2878{
2879 if (!shared->email)
2880 return FR_NO_ACTION;
2881
2882 if ((op != OP_FOLLOWUP) || !shared->email->env->followup_to ||
2883 !mutt_istr_equal(shared->email->env->followup_to, "poster") ||
2884 (query_quadoption(_("Reply by mail as poster prefers?"), shared->sub,
2885 "followup_to_poster") != MUTT_YES))
2886 {
2887 if (shared->mailbox && (shared->mailbox->type == MUTT_NNTP) &&
2888 !((struct NntpMboxData *) shared->mailbox->mdata)->allowed &&
2889 (query_quadoption(_("Posting to this group not allowed, may be moderated. Continue?"),
2890 shared->sub, "post_moderated") != MUTT_YES))
2891 {
2892 return FR_ERROR;
2893 }
2894 if (op == OP_POST)
2895 {
2896 mutt_send_message(SEND_NEWS, NULL, NULL, shared->mailbox, NULL, shared->sub);
2897 }
2898 else
2899 {
2900 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
2901 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
2902 mutt_send_message(((op == OP_FOLLOWUP) ? SEND_REPLY : SEND_FORWARD) | SEND_NEWS,
2903 NULL, NULL, shared->mailbox, &ea, shared->sub);
2904 ARRAY_FREE(&ea);
2905 }
2907 return FR_SUCCESS;
2908 }
2909
2910 return op_reply(shared, priv, OP_REPLY);
2911}
2912#endif
2913
2914#ifdef USE_NOTMUCH
2918static int op_main_entire_thread(struct IndexSharedData *shared,
2919 struct IndexPrivateData *priv, int op)
2920{
2921 if (shared->mailbox->type != MUTT_NOTMUCH)
2922 {
2923 if (((shared->mailbox->type != MUTT_MH) && (shared->mailbox->type != MUTT_MAILDIR)) ||
2924 (!shared->email || !shared->email->env || !shared->email->env->message_id))
2925 {
2926 mutt_message(_("No virtual folder and no Message-Id, aborting"));
2927 return FR_ERROR;
2928 } // no virtual folder, but we have message-id, reconstruct thread on-the-fly
2929 char buf[PATH_MAX] = { 0 };
2930 strncpy(buf, "id:", sizeof(buf));
2931 int msg_id_offset = 0;
2932 if ((shared->email->env->message_id)[0] == '<')
2933 msg_id_offset = 1;
2934 mutt_str_cat(buf, sizeof(buf), (shared->email->env->message_id) + msg_id_offset);
2935 if (buf[strlen(buf) - 1] == '>')
2936 buf[strlen(buf) - 1] = '\0';
2937
2938 change_folder_notmuch(priv->menu, buf, sizeof(buf), &priv->oldcount, shared, false);
2939
2940 // If notmuch doesn't contain the message, we're left in an empty
2941 // vfolder. No messages are found, but nm_read_entire_thread assumes
2942 // a valid message-id and will throw a segfault.
2943 //
2944 // To prevent that, stay in the empty vfolder and print an error.
2945 if (shared->mailbox->msg_count == 0)
2946 {
2947 mutt_error(_("failed to find message in notmuch database. try running 'notmuch new'."));
2948 return FR_ERROR;
2949 }
2950 }
2951 priv->oldcount = shared->mailbox->msg_count;
2952 int index = menu_get_index(priv->menu);
2953 struct Email *e_oldcur = mutt_get_virt_email(shared->mailbox, index);
2954 if (!e_oldcur)
2955 return FR_ERROR;
2956
2957 if (nm_read_entire_thread(shared->mailbox, e_oldcur) < 0)
2958 {
2959 mutt_message(_("Failed to read thread, aborting"));
2960 return FR_ERROR;
2961 }
2962
2963 // nm_read_entire_thread() may modify msg_count and menu won't be updated.
2964 priv->menu->max = shared->mailbox->msg_count;
2965
2966 if (priv->oldcount < shared->mailbox->msg_count)
2967 {
2968 /* nm_read_entire_thread() triggers mutt_sort_headers() if necessary */
2969 index = e_oldcur->vnum;
2970 if (e_oldcur->collapsed || shared->mailbox_view->collapsed)
2971 {
2972 index = mutt_uncollapse_thread(e_oldcur);
2973 mutt_set_vnum(shared->mailbox);
2974 }
2975 menu_set_index(priv->menu, index);
2977 }
2978
2979 return FR_SUCCESS;
2980}
2981
2990 struct IndexPrivateData *priv, int op)
2991{
2992 int rc = FR_SUCCESS;
2993 struct Buffer *buf = buf_pool_get();
2994
2995 if ((mw_get_field("Query: ", buf, MUTT_COMP_NO_FLAGS, HC_OTHER,
2996 &CompleteNmQueryOps, NULL) != 0) ||
2997 buf_is_empty(buf))
2998 {
2999 mutt_message(_("No query, aborting"));
3000 rc = FR_NO_ACTION;
3001 goto done;
3002 }
3003
3004 // Keep copy of user's query to name the mailbox
3005 char *query_unencoded = buf_strdup(buf);
3006
3007 buf_alloc(buf, PATH_MAX);
3008 struct Mailbox *m_query = change_folder_notmuch(priv->menu, buf->data, buf->dsize,
3009 &priv->oldcount, shared,
3010 (op == OP_MAIN_VFOLDER_FROM_QUERY_READONLY));
3011 if (m_query)
3012 {
3013 FREE(&m_query->name);
3014 m_query->name = query_unencoded;
3015 query_unencoded = NULL;
3016 rc = FR_SUCCESS;
3017 }
3018 else
3019 {
3020 FREE(&query_unencoded);
3021 }
3022
3023done:
3024 buf_pool_release(&buf);
3025 return rc;
3026}
3027
3037 struct IndexPrivateData *priv, int op)
3038{
3039 // Common guard clauses.
3041 {
3042 mutt_message(_("Windowed queries disabled"));
3043 return FR_ERROR;
3044 }
3045 const char *const c_nm_query_window_current_search = cs_subset_string(shared->sub, "nm_query_window_current_search");
3046 if (!c_nm_query_window_current_search)
3047 {
3048 mutt_message(_("No notmuch vfolder currently loaded"));
3049 return FR_ERROR;
3050 }
3051
3052 // Call the specific operation.
3053 switch (op)
3054 {
3055 case OP_MAIN_WINDOWED_VFOLDER_BACKWARD:
3057 break;
3058 case OP_MAIN_WINDOWED_VFOLDER_FORWARD:
3060 break;
3061 case OP_MAIN_WINDOWED_VFOLDER_RESET:
3063 break;
3064 }
3065
3066 // Common query window folder change.
3067 char buf[PATH_MAX] = { 0 };
3068 mutt_str_copy(buf, c_nm_query_window_current_search, sizeof(buf));
3069 change_folder_notmuch(priv->menu, buf, sizeof(buf), &priv->oldcount, shared, false);
3070
3071 return FR_SUCCESS;
3072}
3073#endif
3074
3075#ifdef USE_POP
3079static int op_main_fetch_mail(struct IndexSharedData *shared,
3080 struct IndexPrivateData *priv, int op)
3081{
3084 return FR_SUCCESS;
3085}
3086#endif
3087
3088// -----------------------------------------------------------------------------
3089
3097static bool prereq(struct IndexSharedData *shared, struct Menu *menu, CheckFlags checks)
3098{
3099 bool result = true;
3100 struct MailboxView *mv = shared->mailbox_view;
3101
3102 if (checks & (CHECK_MSGCOUNT | CHECK_VISIBLE | CHECK_READONLY))
3103 checks |= CHECK_IN_MAILBOX;
3104
3105 if ((checks & CHECK_IN_MAILBOX) && (!mv || !mv->mailbox))
3106 {
3107 mutt_error(_("No mailbox is open"));
3108 result = false;
3109 }
3110
3111 if (result && (checks & CHECK_MSGCOUNT) && (mv->mailbox->msg_count == 0))
3112 {
3113 mutt_error(_("There are no messages"));
3114 result = false;
3115 }
3116
3117 int index = menu_get_index(menu);
3118 if (result && (checks & CHECK_VISIBLE) &&
3119 ((index < 0) || (index >= mv->mailbox->vcount)))
3120 {
3121 mutt_error(_("No visible messages"));
3122 result = false;
3123 }
3124
3125 if (result && (checks & CHECK_READONLY) && mv->mailbox->readonly)
3126 {
3127 mutt_error(_("Mailbox is read-only"));
3128 result = false;
3129 }
3130
3131 if (result && (checks & CHECK_ATTACH) && shared->attach_msg)
3132 {
3133 mutt_error(_("Function not permitted in attach-message mode"));
3134 result = false;
3135 }
3136
3137 if (!result)
3138 mutt_flushinp();
3139
3140 return result;
3141}
3142
3146static const struct IndexFunction IndexFunctions[] = {
3147 // clang-format off
3148 { OP_ALIAS_DIALOG, op_alias_dialog, CHECK_NO_FLAGS },
3153 { OP_COPY_MESSAGE, op_save, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3154 { OP_CREATE_ALIAS, op_create_alias, CHECK_NO_FLAGS },
3155 { OP_DECODE_COPY, op_save, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3156 { OP_DECODE_SAVE, op_save, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3157 { OP_DECRYPT_COPY, op_save, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3158 { OP_DECRYPT_SAVE, op_save, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3166 { OP_EDIT_OR_VIEW_RAW_MESSAGE, op_edit_raw_message, CHECK_ATTACH | CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3168 { OP_END_COND, op_end_cond, CHECK_NO_FLAGS },
3169 { OP_EXIT, op_exit, CHECK_NO_FLAGS },
3172 { OP_FORGET_PASSPHRASE, op_forget_passphrase, CHECK_NO_FLAGS },
3176 { OP_JUMP, op_jump, CHECK_IN_MAILBOX },
3177 { OP_JUMP_1, op_jump, CHECK_IN_MAILBOX },
3178 { OP_JUMP_2, op_jump, CHECK_IN_MAILBOX },
3179 { OP_JUMP_3, op_jump, CHECK_IN_MAILBOX },
3180 { OP_JUMP_4, op_jump, CHECK_IN_MAILBOX },
3181 { OP_JUMP_5, op_jump, CHECK_IN_MAILBOX },
3182 { OP_JUMP_6, op_jump, CHECK_IN_MAILBOX },
3183 { OP_JUMP_7, op_jump, CHECK_IN_MAILBOX },
3184 { OP_JUMP_8, op_jump, CHECK_IN_MAILBOX },
3185 { OP_JUMP_9, op_jump, CHECK_IN_MAILBOX },
3186 { OP_LIMIT_CURRENT_THREAD, op_main_limit, CHECK_IN_MAILBOX },
3190 { OP_MAIL, op_mail, CHECK_ATTACH },
3191 { OP_MAILBOX_LIST, op_mailbox_list, CHECK_NO_FLAGS },
3192 { OP_MAIL_KEY, op_mail_key, CHECK_ATTACH },
3194 { OP_MAIN_CHANGE_FOLDER, op_main_change_folder, CHECK_NO_FLAGS },
3195 { OP_MAIN_CHANGE_FOLDER_READONLY, op_main_change_folder, CHECK_NO_FLAGS },
3197 { OP_MAIN_COLLAPSE_ALL, op_main_collapse_all, CHECK_IN_MAILBOX },
3198 { OP_MAIN_COLLAPSE_THREAD, op_main_collapse_thread, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3199 { OP_MAIN_DELETE_PATTERN, op_main_delete_pattern, CHECK_ATTACH | CHECK_IN_MAILBOX | CHECK_READONLY },
3200 { OP_MAIN_LIMIT, op_main_limit, CHECK_IN_MAILBOX },
3203 { OP_MAIN_MODIFY_TAGS_THEN_HIDE, op_main_modify_tags, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_READONLY | CHECK_VISIBLE },
3205 { OP_MAIN_NEXT_NEW_THEN_UNREAD, op_main_next_new, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3206 { OP_MAIN_NEXT_SUBTHREAD, op_main_next_thread, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3209 { OP_MAIN_NEXT_UNREAD, op_main_next_new, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3210 { OP_MAIN_NEXT_UNREAD_MAILBOX, op_main_next_unread_mailbox, CHECK_IN_MAILBOX },
3211 { OP_MAIN_PARENT_MESSAGE, op_main_root_message, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3213 { OP_MAIN_PREV_NEW_THEN_UNREAD, op_main_next_new, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3214 { OP_MAIN_PREV_SUBTHREAD, op_main_next_thread, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3217 { OP_MAIN_PREV_UNREAD, op_main_next_new, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3223 { OP_MAIN_SHOW_LIMIT, op_main_show_limit, CHECK_IN_MAILBOX },
3224 { OP_MAIN_SYNC_FOLDER, op_main_sync_folder, CHECK_NO_FLAGS },
3225 { OP_MAIN_TAG_PATTERN, op_main_tag_pattern, CHECK_IN_MAILBOX },
3226 { OP_MAIN_UNDELETE_PATTERN, op_main_undelete_pattern, CHECK_IN_MAILBOX | CHECK_READONLY },
3227 { OP_MAIN_UNTAG_PATTERN, op_main_untag_pattern, CHECK_IN_MAILBOX },
3235 { OP_QUERY, op_query, CHECK_ATTACH },
3236 { OP_QUIT, op_quit, CHECK_NO_FLAGS },
3237 { OP_RECALL_MESSAGE, op_recall_message, CHECK_ATTACH },
3241 { OP_SEARCH, op_search, CHECK_IN_MAILBOX },
3242 { OP_SEARCH_NEXT, op_search, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3243 { OP_SEARCH_OPPOSITE, op_search, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3244 { OP_SEARCH_REVERSE, op_search, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3245 { OP_SORT, op_sort, CHECK_NO_FLAGS },
3246 { OP_SORT_REVERSE, op_sort, CHECK_NO_FLAGS },
3251 { OP_TOGGLE_READ, op_main_limit, CHECK_IN_MAILBOX },
3252 { OP_TOGGLE_WRITE, op_toggle_write, CHECK_IN_MAILBOX },
3258#ifdef USE_AUTOCRYPT
3259 { OP_AUTOCRYPT_ACCT_MENU, op_autocrypt_acct_menu, CHECK_NO_FLAGS },
3260#endif
3261#ifdef USE_IMAP
3262 { OP_MAIN_IMAP_FETCH, op_main_imap_fetch, CHECK_NO_FLAGS },
3263 { OP_MAIN_IMAP_LOGOUT_ALL, op_main_imap_logout_all, CHECK_NO_FLAGS },
3264#endif
3265#ifdef USE_NNTP
3268 { OP_FORWARD_TO_GROUP, op_post, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3272 { OP_MAIN_CHANGE_GROUP, op_main_change_group, CHECK_NO_FLAGS },
3273 { OP_MAIN_CHANGE_GROUP_READONLY, op_main_change_group, CHECK_NO_FLAGS },
3274 { OP_POST, op_post, CHECK_ATTACH | CHECK_IN_MAILBOX },
3276#endif
3277#ifdef USE_NOTMUCH
3278 { OP_MAIN_CHANGE_VFOLDER, op_main_change_folder, CHECK_NO_FLAGS },
3280 { OP_MAIN_VFOLDER_FROM_QUERY, op_main_vfolder_from_query, CHECK_NO_FLAGS },
3281 { OP_MAIN_VFOLDER_FROM_QUERY_READONLY, op_main_vfolder_from_query, CHECK_NO_FLAGS },
3282 { OP_MAIN_WINDOWED_VFOLDER_BACKWARD, op_main_windowed_vfolder, CHECK_IN_MAILBOX },
3283 { OP_MAIN_WINDOWED_VFOLDER_FORWARD, op_main_windowed_vfolder, CHECK_IN_MAILBOX },
3284 { OP_MAIN_WINDOWED_VFOLDER_RESET, op_main_windowed_vfolder, CHECK_IN_MAILBOX },
3285#endif
3286#ifdef USE_POP
3287 { OP_MAIN_FETCH_MAIL, op_main_fetch_mail, CHECK_ATTACH },
3288#endif
3289 { 0, NULL, CHECK_NO_FLAGS },
3290 // clang-format on
3291};
3292
3297{
3298 if (!win)
3299 {
3301 return FR_ERROR;
3302 }
3303
3304 struct MuttWindow *dlg = dialog_find(win);
3305 if (!dlg || !dlg->wdata || !win->parent || !win->parent->wdata)
3306 return FR_ERROR;
3307
3308 struct IndexPrivateData *priv = win->parent->wdata;
3309 struct IndexSharedData *shared = dlg->wdata;
3310
3311 int rc = FR_UNKNOWN;
3312 for (size_t i = 0; IndexFunctions[i].op != OP_NULL; i++)
3313 {
3314 const struct IndexFunction *fn = &IndexFunctions[i];
3315 if (fn->op == op)
3316 {
3317 if (!prereq(shared, priv->menu, fn->flags))
3318 {
3319 rc = FR_ERROR;
3320 break;
3321 }
3322 rc = fn->function(shared, priv, op);
3323 break;
3324 }
3325 }
3326
3327 if (rc == FR_UNKNOWN) // Not our function
3328 return rc;
3329
3330 const char *result = dispatcher_get_retval_name(rc);
3331 mutt_debug(LL_DEBUG1, "Handled %s (%d) -> %s\n", opcodes_get_name(op), op, NONULL(result));
3332
3333 return rc;
3334}
Email Aliases.
void alias_create(struct AddressList *al, const struct ConfigSubset *sub)
Create a new Alias from an Address.
Definition: alias.c:370
struct AddressList * mutt_get_address(struct Envelope *env, const char **prefix)
Get an Address from an Envelope.
Definition: alias.c:330
#define ARRAY_FREE(head)
Release all memory.
Definition: array.h:203
#define ARRAY_HEAD_INITIALIZER
Static initializer for arrays.
Definition: array.h:57
static const char * Not_available_in_this_menu
Error message for unavailable functions.
Definition: functions.c:55
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:214
Select a Mailbox from a list.
#define MUTT_SEL_NO_FLAGS
No flags are set.
Definition: lib.h:57
int buf_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:173
bool buf_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:303
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:407
char * buf_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition: buffer.c:542
void buf_alloc(struct Buffer *buf, size_t new_size)
Make sure a buffer can store at least new_size bytes.
Definition: buffer.c:349
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:93
void mutt_pattern_free(struct PatternList **pat)
Free a Pattern.
Definition: compile.c:778
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:292
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:48
Convenience wrapper for the config headers.
Convenience wrapper for the core headers.
void crypt_extract_keys_from_messages(struct Mailbox *m, struct EmailArray *ea)
Extract keys from a message.
Definition: crypt.c:847
void crypt_forget_passphrase(void)
Forget a passphrase and display a message.
Definition: crypt.c:93
int digit(const char *s)
void mutt_flushinp(void)
Empty all the keyboard buffers.
Definition: get.c:57
void mutt_unget_ch(int ch)
Return a keystroke to the input buffer.
Definition: get.c:114
struct MuttWindow * dialog_find(struct MuttWindow *win)
Find the parent Dialog of a Window.
Definition: dialog.c:89
const char * dispatcher_get_retval_name(int rv)
Get the name of a return value.
Definition: dispatcher.c:54
FunctionRetval
Possible return values for NeoMutt functions.
Definition: dispatcher.h:32
@ FR_SUCCESS
Valid function - successfully performed.
Definition: dispatcher.h:39
@ FR_DONE
Exit the Dialog.
Definition: dispatcher.h:35
@ FR_UNKNOWN
Unknown function.
Definition: dispatcher.h:33
@ FR_ERROR
Valid function - error occurred.
Definition: dispatcher.h:38
@ FR_NOT_IMPL
Invalid function - feature not enabled.
Definition: dispatcher.h:36
@ FR_NO_ACTION
Valid function - no action performed.
Definition: dispatcher.h:37
void alias_dialog(struct Mailbox *m, struct ConfigSubset *sub)
Open the aliases dialog.
Definition: dlg_alias.c:509
void mutt_browser_select_dir(const char *f)
Remember the last directory selected.
Definition: dlg_browser.c:1225
bool check_acl(struct Mailbox *m, AclFlags acl, const char *msg)
Check the ACLs for a function.
Definition: dlg_index.c:140
const struct Mapping IndexNewsHelp[]
Help Bar for the News Index dialog.
Definition: dlg_index.c:118
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:612
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:735
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:544
int find_first_message(struct MailboxView *mv)
Get index of first new message.
Definition: dlg_index.c:311
void resort_index(struct MailboxView *mv, struct Menu *menu)
Resort the index.
Definition: dlg_index.c:371
int find_next_undeleted(struct MailboxView *mv, int msgno, bool uncollapse)
Find the next undeleted email.
Definition: dlg_index.c:243
void collapse_all(struct MailboxView *mv, struct Menu *menu, int toggle)
Collapse/uncollapse all threads.
Definition: dlg_index.c:167
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:758
int find_previous_undeleted(struct MailboxView *mv, int msgno, bool uncollapse)
Find the previous undeleted email.
Definition: dlg_index.c:277
void query_index(struct Mailbox *m, struct ConfigSubset *sub)
Perform an Alias Query and display the results.
Definition: dlg_query.c:538
int mutt_ev_message(struct Mailbox *m, struct EmailArray *ea, enum EvMessage action)
Edit or view a message.
Definition: editmsg.c:279
Enter a string.
Structs that make up an email.
void mutt_print_message(struct Mailbox *m, struct EmailArray *ea)
Print a message.
Definition: external.c:440
bool mutt_select_sort(bool reverse)
Ask the user for a sort method.
Definition: external.c:478
void mutt_pipe_message(struct Mailbox *m, struct EmailArray *ea)
Pipe a message.
Definition: external.c:409
bool mutt_check_traditional_pgp(struct Mailbox *m, struct EmailArray *ea)
Check if a message has inline PGP content.
Definition: external.c:1219
void index_bounce_message(struct Mailbox *m, struct EmailArray *ea)
Bounce an email.
Definition: external.c:92
int mutt_save_message(struct Mailbox *m, struct EmailArray *ea, enum MessageSaveOpt save_opt, enum MessageTransformOpt transform_opt)
Save an email.
Definition: external.c:779
bool mutt_edit_content_type(struct Email *e, struct Body *b, FILE *fp)
Edit the content type of an attachment.
Definition: external.c:1078
void mutt_display_address(struct Envelope *env)
Display the address of a message.
Definition: external.c:662
Manage where the email is piped to external commands.
MessageTransformOpt
Message transformation option.
Definition: external.h:39
@ TRANSFORM_NONE
No transformation.
Definition: external.h:40
@ TRANSFORM_DECODE
Decode message.
Definition: external.h:42
@ TRANSFORM_DECRYPT
Decrypt message.
Definition: external.h:41
MessageSaveOpt
Message save option.
Definition: external.h:49
@ SAVE_MOVE
Move message to another mailbox, removing the original.
Definition: external.h:51
@ SAVE_COPY
Copy message, making a duplicate in another mailbox.
Definition: external.h:50
int mutt_file_sanitize_regex(struct Buffer *dest, const char *src)
Escape any regex-magic characters in a string.
Definition: file.c:709
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:53
void mutt_emails_set_flag(struct Mailbox *m, struct EmailArray *ea, enum MessageType flag, bool bf)
Set flag on messages.
Definition: flags.c:361
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:385
bool OptNews
(pseudo) used to change reader mode
Definition: globals.c:76
bool OptNeedResort
(pseudo) used to force a re-sort
Definition: globals.c:74
static int op_delete(struct AliasMenuData *mdata, int op)
delete the current entry - Implements alias_function_t -
Definition: functions.c:158
static int op_main_limit(struct AliasMenuData *mdata, int op)
show only messages matching a pattern - Implements alias_function_t -
Definition: functions.c:234
static int op_exit(struct AliasMenuData *mdata, int op)
exit this menu - Implements alias_function_t -
Definition: functions.c:190
static int op_query(struct AliasMenuData *mdata, int op)
query external program for addresses - Implements alias_function_t -
Definition: functions.c:256
static int op_search(struct AliasMenuData *mdata, int op)
search for a regular expression - Implements alias_function_t -
Definition: functions.c:309
static int op_create_alias(struct AliasMenuData *mdata, int op)
create an alias from a message sender - Implements alias_function_t -
Definition: functions.c:118
static int op_sort(struct AliasMenuData *mdata, int op)
sort aliases - Implements alias_function_t -
Definition: functions.c:346
static int op_forward_message(struct AttachPrivateData *priv, int op)
forward a message with comments - Implements attach_function_t -
Definition: functions.c:572
static int op_bounce_message(struct AttachPrivateData *priv, int op)
remail a message to another user - Implements attach_function_t -
Definition: functions.c:487
static int op_attachment_edit_type(struct AttachPrivateData *priv, int op)
edit attachment content type - Implements attach_function_t -
Definition: functions.c:353
static int op_extract_keys(struct AttachPrivateData *priv, int op)
extract supported public keys - Implements attach_function_t -
Definition: functions.c:549
static int op_reply(struct AttachPrivateData *priv, int op)
reply to a message - Implements attach_function_t -
Definition: functions.c:606
static int op_compose_to_sender(struct AttachPrivateData *priv, int op)
compose new message to the current message sender - Implements attach_function_t -
Definition: functions.c:515
static int op_forget_passphrase(struct AttachPrivateData *priv, int op)
wipe passphrases from memory - Implements attach_function_t -
Definition: functions.c:563
static int op_list_subscribe(struct AttachPrivateData *priv, int op)
subscribe to a mailing list - Implements attach_function_t -
Definition: functions.c:586
static int op_list_unsubscribe(struct AttachPrivateData *priv, int op)
unsubscribe from a mailing list - Implements attach_function_t -
Definition: functions.c:596
static int op_check_traditional(struct AttachPrivateData *priv, int op)
check for classic PGP - Implements attach_function_t -
Definition: functions.c:501
static int op_resend(struct AttachPrivateData *priv, int op)
use the current message as a template for a new one - Implements attach_function_t -
Definition: functions.c:629
static int op_catchup(struct BrowserPrivateData *priv, int op)
Mark all articles in newsgroup as read - Implements browser_function_t -.
Definition: functions.c:351
static int op_mailbox_list(struct BrowserPrivateData *priv, int op)
List mailboxes with new mail - Implements browser_function_t -.
Definition: functions.c:915
int index_function_dispatcher(struct MuttWindow *win, int op)
Perform an Index function - Implements function_dispatcher_t -.
Definition: functions.c:3296
void dlg_autocrypt(void)
Display the Autocrypt account Menu -.
void dlg_attachment(struct ConfigSubset *sub, struct MailboxView *mv, struct Email *e, FILE *fp, bool attach_msg)
Show the attachments in a Menu -.
Definition: dlg_attach.c:471
int mw_change_flag(struct Mailbox *m, struct EmailArray *ea, bool bf)
Change the flag on a Message -.
Definition: flags.c:454
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:251
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:275
static int op_quit(struct HistoryData *hd, int op)
Quit this menu - Implements history_function_t -.
Definition: functions.c:52
static int op_main_link_threads(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Link tagged message to the current one - Implements index_function_t -.
Definition: functions.c:1317
static int op_main_break_thread(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Break the thread in two - Implements index_function_t -.
Definition: functions.c:1061
static int op_main_root_message(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Jump to root message in thread - Implements index_function_t -.
Definition: functions.c:1812
static int op_main_delete_pattern(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Delete messages matching a pattern - Implements index_function_t -.
Definition: functions.c:1229
static int op_toggle_new(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Toggle a message's 'new' flag - Implements index_function_t -.
Definition: functions.c:2397
static int op_mail_key(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Mail a PGP public key - Implements index_function_t -.
Definition: functions.c:1048
static int op_display_message(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Display a message - Implements index_function_t -.
Definition: functions.c:636
static int op_main_next_undeleted(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Move to the next undeleted message - Implements index_function_t -.
Definition: functions.c:1657
static int op_main_fetch_mail(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Retrieve mail from POP server - Implements index_function_t -.
Definition: functions.c:3079
static int op_list_reply(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Reply to specified mailing list - Implements index_function_t -.
Definition: functions.c:985
static int op_delete_thread(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Delete all messages in thread - Implements index_function_t -.
Definition: functions.c:584
static int op_main_next_unread_mailbox(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Open next mailbox with unread mail - Implements index_function_t -.
Definition: functions.c:1690
static int op_pipe(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Pipe message/attachment to a shell command - Implements index_function_t -.
Definition: functions.c:2064
static int op_main_prev_undeleted(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Move to the previous undeleted message - Implements index_function_t -.
Definition: functions.c:1713
static int op_prev_entry(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Move to the previous entry - Implements index_function_t -.
Definition: functions.c:2087
static int op_next_entry(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Move to the next entry - Implements index_function_t -.
Definition: functions.c:2048
static int op_main_modify_tags(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Modify (notmuch/imap) tags - Implements index_function_t -.
Definition: functions.c:1374
static int op_main_sync_folder(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Save changes to mailbox - Implements index_function_t -.
Definition: functions.c:1875
static int op_autocrypt_acct_menu(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Manage autocrypt accounts - Implements index_function_t -.
Definition: functions.c:2541
static int op_end_cond(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
End of conditional execution (noop) - Implements index_function_t -.
Definition: functions.c:784
static int op_edit_raw_message(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Edit the raw message (edit and edit-raw-message are synonyms) - Implements index_function_t -.
Definition: functions.c:739
static int op_get_message(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Get parent of the current message - Implements index_function_t -.
Definition: functions.c:2721
static int op_main_next_new(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Jump to the next new message - Implements index_function_t -.
Definition: functions.c:1491
static int op_main_change_group(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Open a different newsgroup - Implements index_function_t -.
Definition: functions.c:2802
static int op_view_attachments(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Show MIME attachments - Implements index_function_t -.
Definition: functions.c:2512
static int op_main_vfolder_from_query(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Generate virtual folder from query - Implements index_function_t -.
Definition: functions.c:2989
static int op_flag_message(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Toggle a message's 'important' flag - Implements index_function_t -.
Definition: functions.c:830
static int op_main_imap_logout_all(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Logout from all IMAP servers - Implements index_function_t -.
Definition: functions.c:2566
static int op_main_read_thread(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Mark the current thread as read - Implements index_function_t -.
Definition: functions.c:1782
static int op_recall_message(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Recall a postponed message - Implements index_function_t -.
Definition: functions.c:2171
static int op_get_children(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Get all children of the current message - Implements index_function_t -.
Definition: functions.c:2620
static int op_toggle_write(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Toggle whether the mailbox will be rewritten - Implements index_function_t -.
Definition: functions.c:2439
static int op_save(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Make decrypted copy - Implements index_function_t -.
Definition: functions.c:2242
static int op_undelete_thread(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Undelete all messages in thread - Implements index_function_t -.
Definition: functions.c:2481
static int op_main_tag_pattern(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Tag messages matching a pattern - Implements index_function_t -.
Definition: functions.c:1947
static int op_main_untag_pattern(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Untag messages matching a pattern - Implements index_function_t -.
Definition: functions.c:1981
static int op_edit_label(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Add, change, or delete a message's label - Implements index_function_t -.
Definition: functions.c:704
static int op_main_entire_thread(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Read entire thread of the current message - Implements index_function_t -.
Definition: functions.c:2918
static int op_display_address(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Display full address of sender - Implements index_function_t -.
Definition: functions.c:619
static int op_post(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Followup to newsgroup - Implements index_function_t -.
Definition: functions.c:2877
static int op_tag(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Tag the current entry - Implements index_function_t -.
Definition: functions.c:2342
static int op_tag_thread(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Tag the current thread - Implements index_function_t -.
Definition: functions.c:2376
static int op_main_collapse_thread(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Collapse/uncollapse current thread - Implements index_function_t -.
Definition: functions.c:1189
static int op_alias_dialog(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Open the aliases dialog - Implements index_function_t -.
Definition: functions.c:452
static int op_main_imap_fetch(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Force retrieval of mail from IMAP server - Implements index_function_t -.
Definition: functions.c:2553
static int op_main_quasi_delete(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Delete from NeoMutt, don't touch on disk - Implements index_function_t -.
Definition: functions.c:1746
static int op_undelete(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Undelete the current entry - Implements index_function_t -.
Definition: functions.c:2449
static int op_main_collapse_all(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Collapse/uncollapse all threads - Implements index_function_t -.
Definition: functions.c:1173
static int op_jump(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Jump to an index number - Implements index_function_t -.
Definition: functions.c:935
static int op_main_undelete_pattern(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Undelete messages matching a pattern - Implements index_function_t -.
Definition: functions.c:1959
static int op_mark_msg(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Create a hotkey macro for the current message - Implements index_function_t -.
Definition: functions.c:1993
static int op_main_windowed_vfolder(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Shifts virtual folder time window - Implements index_function_t -.
Definition: functions.c:3036
static int op_main_set_flag(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Set a status flag on a message - Implements index_function_t -.
Definition: functions.c:1829
static int op_main_next_thread(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Jump to the next thread - Implements index_function_t -.
Definition: functions.c:1615
static int op_group_reply(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Reply to all recipients - Implements index_function_t -.
Definition: functions.c:905
static int op_main_show_limit(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Show currently active limit pattern - Implements index_function_t -.
Definition: functions.c:1854
static int op_main_change_folder(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Open a different folder - Implements index_function_t -.
Definition: functions.c:1109
static int op_mail(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Compose a new mail message - Implements index_function_t -.
Definition: functions.c:1027
static int op_print(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Print the current entry - Implements index_function_t -.
Definition: functions.c:2103
#define mutt_warning(...)
Definition: logging2.h:90
#define mutt_error(...)
Definition: logging2.h:92
#define mutt_message(...)
Definition: logging2.h:91
#define mutt_debug(LEVEL,...)
Definition: logging2.h:89
Convenience wrapper for the gui headers.
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:362
Read/write command history from/to a file.
@ HC_OTHER
Miscellaneous strings.
Definition: lib.h:54
void mutt_startup_shutdown_hook(HookFlags type)
Execute any startup/shutdown hooks.
Definition: hook.c:927
Parse and execute user-defined hooks.
#define MUTT_SHUTDOWN_HOOK
shutdown-hook: run when leaving NeoMutt
Definition: hook.h:58
IMAP network mailbox.
void imap_logout_all(void)
Close all open connections.
Definition: imap.c:546
enum MxStatus imap_check_mailbox(struct Mailbox *m, bool force)
Use the NOOP or IDLE command to poll for new mail.
Definition: imap.c:1019
const struct MenuFuncOp OpIndex[]
Functions for the Index Menu.
Definition: functions.c:99
bool index_next_undeleted(struct MuttWindow *win_index)
Select the next undeleted Email (if possible)
Definition: functions.c:421
static bool resolve_email(struct IndexPrivateData *priv, struct IndexSharedData *shared, enum ResolveMethod rm)
Pick the next Email to advance the cursor to.
Definition: functions.c:372
const struct MenuOpSeq IndexDefaultBindings[]
Key bindings for the Index Menu.
Definition: functions.c:262
static bool prereq(struct IndexSharedData *shared, struct Menu *menu, CheckFlags checks)
Check the pre-requisites for a function.
Definition: functions.c:3097
static const struct IndexFunction IndexFunctions[]
All the NeoMutt functions that the Index supports.
Definition: functions.c:3146
ResolveMethod
How to advance the cursor.
Definition: functions.c:358
@ RESOLVE_NEXT_SUBTHREAD
Next sibling sub-thread.
Definition: functions.c:362
@ RESOLVE_NEXT_UNDELETED
Next undeleted email.
Definition: functions.c:360
@ RESOLVE_NEXT_EMAIL
Next email, whatever its state.
Definition: functions.c:359
@ RESOLVE_NEXT_THREAD
Next top-level thread.
Definition: functions.c:361
uint8_t CheckFlags
Flags, e.g. CHECK_IN_MAILBOX.
Definition: lib.h:68
#define CHECK_NO_FLAGS
No flags are set.
Definition: lib.h:69
#define CHECK_ATTACH
Is the user in message-attach mode?
Definition: lib.h:74
#define CHECK_VISIBLE
Is the selected message visible in the index?
Definition: lib.h:72
#define CHECK_IN_MAILBOX
Is there a mailbox open?
Definition: lib.h:70
#define CHECK_READONLY
Is the mailbox readonly?
Definition: lib.h:73
#define CHECK_MSGCOUNT
Are there any messages?
Definition: lib.h:71
#define NT_INDEX_EMAIL
Email has changed.
Definition: lib.h:66
void index_shared_data_set_email(struct IndexSharedData *shared, struct Email *e)
Set the current Email for the Index and friends.
Definition: shared_data.c:234
Data shared between Index, Pager and Sidebar.
Manage keymappings.
enum CommandResult km_bind(char *s, enum MenuType menu, int op, char *macro, char *desc)
Bind a key to a macro.
Definition: parse.c:160
@ LL_DEBUG1
Log at debug level 1.
Definition: logging2.h:43
@ LL_NOTIFY
Log of notifications.
Definition: logging2.h:48
void mailbox_free(struct Mailbox **ptr)
Free a Mailbox.
Definition: mailbox.c:90
#define MUTT_ACL_INSERT
Add/copy into the mailbox (used when editing a message)
Definition: mailbox.h:66
#define MUTT_ACL_DELETE
Delete a message.
Definition: mailbox.h:63
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox's path string.
Definition: mailbox.h:210
#define MUTT_ACL_WRITE
Write to a message (for flagging or linking threads)
Definition: mailbox.h:71
@ MUTT_NOTMUCH
'Notmuch' (virtual) Mailbox type
Definition: mailbox.h:51
@ MUTT_MH
'MH' Mailbox type
Definition: mailbox.h:47
@ MUTT_NNTP
'NNTP' (Usenet) Mailbox type
Definition: mailbox.h:49
@ MUTT_IMAP
'IMAP' Mailbox type
Definition: mailbox.h:50
@ MUTT_MAILDIR
'Maildir' Mailbox type
Definition: mailbox.h:48
#define MUTT_ACL_SEEN
Change the 'seen' status of a message.
Definition: mailbox.h:70
#define FREE(x)
Definition: memory.h:45
GUI present the user with a selectable list.
#define MENU_REDRAW_FULL
Redraw everything.
Definition: lib.h:60
#define MENU_REDRAW_INDEX
Redraw the index.
Definition: lib.h:57
MenuRedrawFlags menu_current_middle(struct Menu *menu)
Move the current selection to the centre of the window.
Definition: move.c:464
void menu_queue_redraw(struct Menu *menu, MenuRedrawFlags redraw)
Queue a request for a redraw.
Definition: menu.c:180
int menu_get_index(struct Menu *menu)
Get the current selection in the Menu.
Definition: menu.c:156
#define MENU_REDRAW_CURRENT
Redraw the current line of the menu.
Definition: lib.h:59
MenuRedrawFlags menu_set_index(struct Menu *menu, int index)
Set the current selection in the Menu.
Definition: menu.c:170
void msgwin_clear_text(struct MuttWindow *win)
Clear the text in the Message Window.
Definition: msgwin.c:515
Convenience wrapper for the library headers.
#define N_(a)
Definition: message.h:32
#define _(a)
Definition: message.h:28
bool notify_send(struct Notify *notify, enum NotifyType event_type, int event_subtype, void *event_data)
Send out a notification message.
Definition: notify.c:173
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:810
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:497
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:653
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:327
char * mutt_str_cat(char *buf, size_t buflen, const char *s)
Concatenate two strings.
Definition: string.c:266
Many unsorted constants and some structs.
#define MUTT_COMP_NO_FLAGS
No flags are set.
Definition: mutt.h:55
@ MUTT_UNDELETE
Messages to be un-deleted.
Definition: mutt.h:75
@ MUTT_LIMIT
Messages in limited view.
Definition: mutt.h:81
@ MUTT_UNTAG
Messages to be un-tagged.
Definition: mutt.h:80
@ MUTT_READ
Messages that have been read.
Definition: mutt.h:72
@ MUTT_PURGE
Messages to be purged (bypass trash)
Definition: mutt.h:76
@ MUTT_TAG
Tagged messages.
Definition: mutt.h:79
@ MUTT_FLAG
Flagged messages.
Definition: mutt.h:78
@ MUTT_DELETE
Messages to be deleted.
Definition: mutt.h:74
@ MUTT_NEW
New messages.
Definition: mutt.h:69
#define PATH_MAX
Definition: mutt.h:41
int mutt_label_message(struct MailboxView *mv, struct EmailArray *ea)
Let the user label a message.
Definition: mutt_header.c:128
Representation of the email's header.
struct Mailbox * mutt_mailbox_next_unread(struct Mailbox *m_cur, struct Buffer *s)
Find next mailbox with unread mail.
Definition: mutt_mailbox.c:396
struct Mailbox * mutt_mailbox_next(struct Mailbox *m_cur, struct Buffer *s)
Incoming folders completion routine.
Definition: mutt_mailbox.c:370
bool mutt_mailbox_list(void)
List the mailboxes with new mail.
Definition: mutt_mailbox.c:249
Mailbox helper functions.
bool mutt_link_threads(struct Email *parent, struct EmailArray *children, struct Mailbox *m)
Forcibly link threads together.
Definition: mutt_thread.c:1744
void mutt_draw_tree(struct ThreadsContext *tctx)
Draw a tree of threaded emails.
Definition: mutt_thread.c:391
int mutt_messages_in_thread(struct Mailbox *m, struct Email *e, enum MessageInThread mit)
Count the messages in a thread.
Definition: mutt_thread.c:1654
off_t mutt_set_vnum(struct Mailbox *m)
Set the virtual index number of all the messages in a mailbox.
Definition: mutt_thread.c:1401
bool mutt_thread_can_collapse(struct Email *e)
Check whether a thread can be collapsed.
Definition: mutt_thread.c:1814
int mutt_parent_message(struct Email *e, bool find_root)
Find the parent of a message.
Definition: mutt_thread.c:1351
struct HashTable * mutt_make_id_hash(struct Mailbox *m)
Create a Hash Table for message-ids.
Definition: mutt_thread.c:1699
Create/manipulate threading in emails.
#define mutt_thread_next_unread(e)
Definition: mutt_thread.h:109
#define mutt_using_threads()
Definition: mutt_thread.h:112
#define mutt_previous_thread(e)
Definition: mutt_thread.h:119
#define mutt_uncollapse_thread(e)
Definition: mutt_thread.h:106
@ MIT_POSITION
Our position in the thread.
Definition: mutt_thread.h:88
#define mutt_next_subthread(e)
Definition: mutt_thread.h:120
#define mutt_thread_contains_unread(e)
Definition: mutt_thread.h:107
#define mutt_previous_subthread(e)
Definition: mutt_thread.h:121
#define mutt_next_thread(e)
Definition: mutt_thread.h:118
#define mutt_collapse_thread(e)
Definition: mutt_thread.h:105
bool window_is_focused(const struct MuttWindow *win)
Does the given Window have the focus?
Definition: mutt_window.c:654
struct MuttWindow * window_set_focus(struct MuttWindow *win)
Set the Window focus.
Definition: mutt_window.c:684
void buf_pretty_mailbox(struct Buffer *buf)
Shorten a mailbox path using '~' or '='.
Definition: muttlib.c:562
Some miscellaneous functions.
struct Email * mutt_get_virt_email(struct Mailbox *m, int vnum)
Get a virtual Email.
Definition: mview.c:419
bool mutt_limit_current_thread(struct MailboxView *mv, struct Email *e)
Limit the email view to the current thread.
Definition: mview.c:482
void mview_free(struct MailboxView **ptr)
Free a MailboxView.
Definition: mview.c:49
int ea_add_tagged(struct EmailArray *ea, struct MailboxView *mv, struct Email *e, bool use_tagged)
Get an array of the tagged Emails.
Definition: mview.c:379
bool message_is_tagged(struct Email *e)
Is a message in the index tagged (and within limit)
Definition: mview.c:365
bool mview_has_limit(const struct MailboxView *mv)
Is a limit active?
Definition: mview.c:440
View of a Mailbox.
int mx_tags_edit(struct Mailbox *m, const char *tags, struct Buffer *buf)
Start the tag editor of the mailbox.
Definition: mx.c:1296
int mx_msg_close(struct Mailbox *m, struct Message **ptr)
Close a message.
Definition: mx.c:1206
void mx_fastclose_mailbox(struct Mailbox *m, bool keep_account)
Free up memory associated with the Mailbox.
Definition: mx.c:430
struct Mailbox * mx_mbox_find2(const char *path)
Find a Mailbox on an Account.
Definition: mx.c:1666
struct Message * mx_msg_open(struct Mailbox *m, struct Email *e)
Return a stream pointer for a message.
Definition: mx.c:1160
bool mx_tags_is_supported(struct Mailbox *m)
Return true if mailbox support tagging.
Definition: mx.c:1333
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:1316
int mx_toggle_write(struct Mailbox *m)
Toggle the mailbox's readonly flag.
Definition: mx.c:1868
enum MxStatus mx_mbox_sync(struct Mailbox *m)
Save changes to mailbox.
Definition: mx.c:929
enum MxStatus mx_mbox_close(struct Mailbox *m)
Save changes and close mailbox.
Definition: mx.c:615
API for mailboxes.
MxStatus
Return values from mbox_check(), mbox_check_stats(), mbox_snc(), and mbox_close()
Definition: mxapi.h:63
@ MX_STATUS_OK
No changes.
Definition: mxapi.h:65
@ MX_STATUS_REOPENED
Mailbox was reopened.
Definition: mxapi.h:68
@ MX_STATUS_NEW_MAIL
New mail received in Mailbox.
Definition: mxapi.h:66
API for encryption/signing of emails.
#define PGP_TRADITIONAL_CHECKED
Email has a traditional (inline) signature.
Definition: lib.h:93
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: lib.h:91
#define WithCrypto
Definition: lib.h:117
@ NT_GLOBAL_SHUTDOWN
NeoMutt is about to close.
Definition: neomutt.h:60
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:2164
int nntp_check_children(struct Mailbox *m, const char *msgid)
Fetch children of article with the Message-ID.
Definition: nntp.c:2235
void nntp_mailbox(struct Mailbox *m, char *buf, size_t buflen)
Get first newsgroup with new messages.
Definition: newsrc.c:1382
struct NntpMboxData * mutt_newsgroup_catchup(struct Mailbox *m, struct NntpAccountData *adata, char *group)
Catchup newsgroup.
Definition: newsrc.c:1300
struct NntpAccountData * CurrentNewsSrv
Current NNTP news server.
Definition: nntp.c:77
struct NntpAccountData * nntp_select_server(struct Mailbox *m, const char *server, bool leave_lock)
Open a connection to an NNTP server.
Definition: newsrc.c:1021
Nntp-specific Mailbox data.
@ 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:249
void nm_db_longrun_done(struct Mailbox *m)
Finish a long transaction.
Definition: db.c:370
void nm_db_longrun_init(struct Mailbox *m, bool writable)
Start a long transaction.
Definition: db.c:355
Notmuch virtual mailbox type.
void nm_query_window_reset(void)
Resets the vfolder window position to the present.
Definition: notmuch.c:1672
int nm_read_entire_thread(struct Mailbox *m, struct Email *e)
Get the entire thread of an email.
Definition: notmuch.c:1498
void nm_query_window_backward(void)
Function to move the current search window backward in time.
Definition: notmuch.c:1661
bool nm_query_window_available(void)
Are windowed queries enabled for use?
Definition: notmuch.c:1624
bool nm_message_is_still_queried(struct Mailbox *m, struct Email *e)
Is a message still visible in the query?
Definition: notmuch.c:1684
void nm_query_window_forward(void)
Function to move the current search window forward in time.
Definition: notmuch.c:1641
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:103
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:457
int external_pager(struct MailboxView *mv, struct Email *e, const char *command)
Display a message in an external program.
Definition: message.c:311
Private state data for the Pager.
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:441
int mutt_pattern_func(struct MailboxView *mv, int op, char *prompt)
Perform some Pattern matching.
Definition: pattern.c:290
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:81
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition: pool.c:94
POP network mailbox.
void pop_fetch_mail(void)
Fetch messages and save them in $spool_file.
Definition: pop.c:511
Progress bar.
@ MUTT_PROGRESS_WRITE
Progress tracks elements, according to $write_inc
Definition: lib.h:50
void progress_free(struct Progress **ptr)
Free a Progress Bar.
Definition: progress.c:92
bool progress_update(struct Progress *progress, size_t pos, int percent)
Update the state of the progress bar.
Definition: progress.c:73
struct Progress * progress_new(const char *msg, enum ProgressType type, size_t size)
Create a new Progress Bar.
Definition: progress.c:124
Prototypes for many functions.
@ EVM_VIEW
View the message.
Definition: protos.h:52
@ EVM_EDIT
Edit the message.
Definition: protos.h:53
@ 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:369
#define STAILQ_FIRST(head)
Definition: queue.h:350
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:352
#define STAILQ_EMPTY(head)
Definition: queue.h:348
#define STAILQ_NEXT(elm, field)
Definition: queue.h:400
#define SEARCH_OPPOSITE
Search in the opposite direction.
Definition: search_state.h:45
uint8_t SearchFlags
Flags for a specific search, e.g. SEARCH_PROMPT.
Definition: search_state.h:42
#define SEARCH_NO_FLAGS
No flags are set.
Definition: search_state.h:43
#define SEARCH_PROMPT
Ask for search input.
Definition: search_state.h:44
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:1640
bool mutt_send_list_unsubscribe(struct Mailbox *m, struct Email *e)
Send a mailing-list unsubscription email.
Definition: send.c:3069
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:2127
bool mutt_send_list_subscribe(struct Mailbox *m, struct Email *e)
Send a mailing-list subscription email.
Definition: send.c:3040
#define SEND_GROUP_CHAT_REPLY
Reply to all recipients preserving To/Cc.
Definition: send.h:52
#define SEND_GROUP_REPLY
Reply to all.
Definition: send.h:41
#define SEND_LIST_REPLY
Reply to mailing list.
Definition: send.h:42
#define SEND_KEY
Mail a PGP public key.
Definition: send.h:46
#define SEND_POSTPONED
Recall a postponed email.
Definition: send.h:44
#define SEND_TO_SENDER
Compose new email to sender.
Definition: send.h:51
#define SEND_NO_FLAGS
No flags are set.
Definition: send.h:39
#define SEND_REPLY
Reply to sender.
Definition: send.h:40
#define SEND_NEWS
Reply to a news article.
Definition: send.h:53
#define SEND_FORWARD
Forward email.
Definition: send.h:43
uint16_t SendFlags
Flags for mutt_send_message(), e.g. SEND_REPLY.
Definition: send.h:38
Sidebar functions.
void mutt_sort_headers(struct MailboxView *mv, bool init)
Sort emails by their headers.
Definition: sort.c:352
Assorted sorting methods.
Key value store.
#define NONULL(x)
Definition: string2.h:37
String manipulation buffer.
Definition: buffer.h:34
size_t dsize
Length of data.
Definition: buffer.h:37
char * data
Pointer to data.
Definition: buffer.h:35
The envelope/body of an email.
Definition: email.h:37
bool read
Email is read.
Definition: email.h:48
bool visible
Is this message part of the view?
Definition: email.h:120
struct Envelope * env
Envelope information.
Definition: email.h:66
bool collapsed
Is this message part of a collapsed thread?
Definition: email.h:119
SecurityFlags security
bit 0-10: flags, bit 11,12: application, bit 13: traditional pgp See: ncrypt/lib.h pgplib....
Definition: email.h:41
struct Body * body
List of MIME parts.
Definition: email.h:67
bool old
Email is seen, but unread.
Definition: email.h:47
bool attach_del
Has an attachment marked for deletion.
Definition: email.h:98
bool flagged
Marked important?
Definition: email.h:45
bool threaded
Used for threading.
Definition: email.h:107
const struct AttrColor * attr_color
Color-pair to use when displaying in the index.
Definition: email.h:111
int vnum
Virtual message number.
Definition: email.h:113
struct TagList tags
For drivers that support server tagging.
Definition: email.h:70
bool deleted
Email is deleted.
Definition: email.h:76
int index
The absolute (unsorted) message number.
Definition: email.h:109
bool quasi_deleted
Deleted from neomutt, but not modified on disk.
Definition: email.h:102
bool tagged
Email is tagged.
Definition: email.h:106
char * followup_to
List of 'followup-to' fields.
Definition: envelope.h:81
char * message_id
Message ID.
Definition: envelope.h:73
struct ListHead references
message references (in reverse order)
Definition: envelope.h:85
struct ListHead in_reply_to
in-reply-to header content
Definition: envelope.h:86
A NeoMutt function.
Definition: functions.h:49
int op
Op code, e.g. OP_MAIN_LIMIT.
Definition: functions.h:50
index_function_t function
Function to call.
Definition: functions.h:51
int flags
Prerequisites for the function, e.g. CHECK_IN_MAILBOX.
Definition: functions.h:52
Private state data for the Index.
Definition: private_data.h:35
struct MuttWindow * win_index
Window for the Index.
Definition: private_data.h:43
struct IndexSharedData * shared
Shared Index data.
Definition: private_data.h:41
bool tag_prefix
tag-prefix has been pressed
Definition: private_data.h:36
struct Menu * menu
Menu controlling the index.
Definition: private_data.h:42
int oldcount
Old count of Emails in the Mailbox.
Definition: private_data.h:37
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
A List node for strings.
Definition: list.h:35
char * data
String.
Definition: list.h:36
View of a Mailbox.
Definition: mview.h:39
bool collapsed
Are all threads collapsed?
Definition: mview.h:48
struct Menu * menu
Needed for pattern compilation.
Definition: mview.h:46
struct ThreadsContext * threads
Threads context.
Definition: mview.h:43
struct Mailbox * mailbox
Current Mailbox.
Definition: mview.h:50
char * pattern
Limit pattern string.
Definition: mview.h:41
A mailbox.
Definition: mailbox.h:79
int vcount
The number of virtual messages.
Definition: mailbox.h:99
bool changed
Mailbox has been modified.
Definition: mailbox.h:109
int msg_count
Total number of messages.
Definition: mailbox.h:88
AclFlags rights
ACL bits, see AclFlags.
Definition: mailbox.h:118
enum MailboxType type
Mailbox type.
Definition: mailbox.h:102
void * mdata
Driver specific data.
Definition: mailbox.h:133
struct Email ** emails
Array of Emails.
Definition: mailbox.h:96
char * name
A short name for the Mailbox.
Definition: mailbox.h:82
struct HashTable * id_hash
Hash Table: "message-id" -> Email.
Definition: mailbox.h:124
struct Buffer pathbuf
Path of the Mailbox.
Definition: mailbox.h:80
bool readonly
Don't allow changes to the mailbox.
Definition: mailbox.h:115
int msg_tagged
How many messages are tagged?
Definition: mailbox.h:94
bool verbose
Display status messages?
Definition: mailbox.h:116
Mapping between a function and an operation.
Definition: lib.h:102
Mapping between an operation and a key sequence.
Definition: lib.h:111
Definition: lib.h:70
int max
Number of entries in the menu.
Definition: lib.h:72
A local copy of an email.
Definition: message.h:34
FILE * fp
pointer to the message data
Definition: message.h:35
const struct Mapping * help_data
Data for the Help Bar.
Definition: mutt_window.h:142
void * wdata
Private data.
Definition: mutt_window.h:145
struct MuttWindow * parent
Parent Window.
Definition: mutt_window.h:135
Container for Accounts, Notifications.
Definition: neomutt.h:41
struct Notify * notify
Notifications handler.
Definition: neomutt.h:42
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:45
NNTP-specific Mailbox data -.
Definition: mdata.h:34
bool reverse
search backwards
Definition: search_state.h:39
struct PatternList * pattern
compiled search pattern
Definition: search_state.h:36
char * driver_tags_get_with_hidden(struct TagList *list)
Get tags with hiddens.
Definition: tags.c:158
void mutt_break_thread(struct Email *e)
Break the email Thread.
Definition: thread.c:226
@ MENU_INDEX
Index panel (list of emails)
Definition: type.h:51