NeoMutt  2022-04-29-215-gc12b98
Teaching an old dog new tricks
DOXYGEN
functions.c
Go to the documentation of this file.
1
29#include "config.h"
30#include <limits.h>
31#include <stdbool.h>
32#include <stdio.h>
33#include <string.h>
34#include "mutt/lib.h"
35#include "config/lib.h"
36#include "email/lib.h"
37#include "core/lib.h"
38#include "alias/lib.h"
39#include "gui/lib.h"
40#include "mutt.h"
41#include "functions.h"
42#include "lib.h"
43#include "attach/lib.h"
44#include "browser/lib.h"
45#include "enter/lib.h"
46#include "menu/lib.h"
47#include "ncrypt/lib.h"
48#include "pager/lib.h"
49#include "pattern/lib.h"
50#include "progress/lib.h"
51#include "question/lib.h"
52#include "send/lib.h"
53#include "commands.h"
54#include "hook.h"
55#include "keymap.h"
56#include "mutt_header.h"
57#include "mutt_mailbox.h"
58#include "mutt_thread.h"
59#include "muttlib.h"
60#include "mview.h"
61#include "mx.h"
62#include "opcodes.h"
63#include "options.h"
64#include "private_data.h"
65#include "protos.h"
66#include "shared_data.h"
67#include "sort.h"
68#ifdef USE_AUTOCRYPT
69#include "autocrypt/lib.h"
70#endif
71#ifdef USE_NOTMUCH
72#include "notmuch/lib.h"
73#endif
74#ifdef USE_IMAP
75#include "imap/lib.h"
76#endif
77#ifdef USE_NNTP
78#include "nntp/lib.h"
79#include "nntp/mdata.h" // IWYU pragma: keep
80#endif
81#ifdef USE_POP
82#include "pop/lib.h"
83#endif
84#ifdef ENABLE_NLS
85#include <libintl.h>
86#endif
87
88static const char *Not_available_in_this_menu = N_("Not available in this menu");
89
94{
99};
100
108static bool resolve_email(struct IndexPrivateData *priv,
109 struct IndexSharedData *shared, enum ResolveMethod rm)
110{
111 if (!priv || !priv->menu || !shared || !shared->mailbox || !shared->email)
112 return false;
113
114 const bool c_resolve = cs_subset_bool(shared->sub, "resolve");
115 if (!c_resolve)
116 return false;
117
118 int index = -1;
119 switch (rm)
120 {
122 index = menu_get_index(priv->menu) + 1;
123 break;
124
126 {
127 const bool uncollapse = mutt_using_threads() && !window_is_focused(priv->win_index);
128 index = ci_next_undeleted(shared->mailbox, menu_get_index(priv->menu), uncollapse);
129 break;
130 }
131
133 index = mutt_next_thread(shared->email);
134 break;
135
137 index = mutt_next_subthread(shared->email);
138 break;
139 }
140
141 if ((index < 0) || (index >= shared->mailbox->vcount))
142 {
143 // Resolve failed
144 notify_send(shared->notify, NT_INDEX, NT_INDEX_EMAIL, NULL);
145 return false;
146 }
147
148 menu_set_index(priv->menu, index);
149 return true;
150}
151
157bool index_next_undeleted(struct MuttWindow *win_index)
158{
159 struct MuttWindow *dlg = dialog_find(win_index);
160 if (!dlg)
161 return false;
162
163 struct Menu *menu = win_index->wdata;
164 struct IndexSharedData *shared = dlg->wdata;
165 if (!shared)
166 return false;
167
168 struct IndexPrivateData *priv = win_index->parent->wdata;
169 const bool uncollapse = mutt_using_threads() && !window_is_focused(priv->win_index);
170
171 int index = ci_next_undeleted(shared->mailbox, menu_get_index(menu), uncollapse);
172 if ((index < 0) || (index >= shared->mailbox->vcount))
173 {
174 // Selection failed
176 return false;
177 }
178
179 menu_set_index(menu, index);
180 return true;
181}
182
183// -----------------------------------------------------------------------------
184
189 struct IndexPrivateData *priv, int op)
190{
192 return FR_SUCCESS;
193}
194
199 struct IndexPrivateData *priv, int op)
200{
201 if (!shared->email)
202 return FR_NO_ACTION;
204
206 return FR_SUCCESS;
207}
208
213 struct IndexPrivateData *priv, int op)
214{
215 struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
216 el_add_tagged(&el, shared->mailboxview, shared->email, priv->tag);
217 ci_bounce_message(shared->mailbox, &el);
218 emaillist_clear(&el);
219
220 return FR_SUCCESS;
221}
222
226static int op_check_traditional(struct IndexSharedData *shared,
227 struct IndexPrivateData *priv, int op)
228{
230 return FR_NOT_IMPL;
231 if (!shared->email)
232 return FR_NO_ACTION;
233
234 if (priv->tag || !(shared->email->security & PGP_TRADITIONAL_CHECKED))
235 {
236 struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
237 el_add_tagged(&el, shared->mailboxview, shared->email, priv->tag);
238 if (mutt_check_traditional_pgp(shared->mailbox, &el))
240 emaillist_clear(&el);
241 }
242
243 return FR_SUCCESS;
244}
245
249static int op_compose_to_sender(struct IndexSharedData *shared,
250 struct IndexPrivateData *priv, int op)
251{
252 struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
253 el_add_tagged(&el, shared->mailboxview, shared->email, priv->tag);
254 int rc = mutt_send_message(SEND_TO_SENDER, NULL, NULL, shared->mailbox, &el,
255 shared->sub);
256 emaillist_clear(&el);
258
259 return (rc == -1) ? FR_ERROR : FR_SUCCESS;
260}
261
265static int op_create_alias(struct IndexSharedData *shared,
266 struct IndexPrivateData *priv, int op)
267{
268 struct AddressList *al = NULL;
269 if (shared->email && shared->email->env)
270 al = mutt_get_address(shared->email->env, NULL);
271 alias_create(al, shared->sub);
273
274 return FR_SUCCESS;
275}
276
284static int op_delete(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
285{
286 /* L10N: CHECK_ACL */
287 if (!check_acl(shared->mailbox, MUTT_ACL_DELETE, _("Can't delete message")))
288 return FR_ERROR;
289
290 struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
291 el_add_tagged(&el, shared->mailboxview, shared->email, priv->tag);
292
293 mutt_emails_set_flag(shared->mailbox, &el, MUTT_DELETE, true);
294 mutt_emails_set_flag(shared->mailbox, &el, MUTT_PURGE, (op == OP_PURGE_MESSAGE));
295 const bool c_delete_untag = cs_subset_bool(shared->sub, "delete_untag");
296 if (c_delete_untag)
297 mutt_emails_set_flag(shared->mailbox, &el, MUTT_TAG, false);
298 emaillist_clear(&el);
299
300 if (priv->tag)
301 {
303 }
304 else
305 {
307 }
308
309 return FR_SUCCESS;
310}
311
320static int op_delete_thread(struct IndexSharedData *shared,
321 struct IndexPrivateData *priv, int op)
322{
323 /* L10N: CHECK_ACL */
324 /* L10N: Due to the implementation details we do not know whether we
325 delete zero, 1, 12, ... messages. So in English we use
326 "messages". Your language might have other means to express this. */
327 if (!check_acl(shared->mailbox, MUTT_ACL_DELETE, _("Can't delete messages")))
328 return FR_ERROR;
329 if (!shared->email)
330 return FR_NO_ACTION;
331
332 int subthread = (op == OP_DELETE_SUBTHREAD);
333 int rc = mutt_thread_set_flag(shared->mailbox, shared->email, MUTT_DELETE, true, subthread);
334 if (rc == -1)
335 return FR_ERROR;
336 if (op == OP_PURGE_THREAD)
337 {
338 rc = mutt_thread_set_flag(shared->mailbox, shared->email, MUTT_PURGE, true, subthread);
339 if (rc == -1)
340 return FR_ERROR;
341 }
342
343 const bool c_delete_untag = cs_subset_bool(shared->sub, "delete_untag");
344 if (c_delete_untag)
345 mutt_thread_set_flag(shared->mailbox, shared->email, MUTT_TAG, false, subthread);
346
349 return FR_SUCCESS;
350}
351
355static int op_display_address(struct IndexSharedData *shared,
356 struct IndexPrivateData *priv, int op)
357{
358 if (!shared->email)
359 return FR_NO_ACTION;
361
362 return FR_SUCCESS;
363}
364
372static int op_display_message(struct IndexSharedData *shared,
373 struct IndexPrivateData *priv, int op)
374{
375 if (!shared->email)
376 return FR_NO_ACTION;
377 /* toggle the weeding of headers so that a user can press the key
378 * again while reading the message. */
379 if (op == OP_DISPLAY_HEADERS)
380 {
381 bool_str_toggle(shared->sub, "weed", NULL);
382 notify_send(shared->notify, NT_INDEX, NT_INDEX_EMAIL, shared);
383 if (!window_is_focused(priv->win_index))
384 return FR_SUCCESS;
385 }
386
387 OptNeedResort = false;
388
389 if (mutt_using_threads() && shared->email->collapsed)
390 {
392 mutt_set_vnum(shared->mailbox);
393 const bool c_uncollapse_jump = cs_subset_bool(shared->sub, "uncollapse_jump");
394 if (c_uncollapse_jump)
396 }
397
398 const bool c_pgp_auto_decode = cs_subset_bool(shared->sub, "pgp_auto_decode");
399 if (c_pgp_auto_decode && (priv->tag || !(shared->email->security & PGP_TRADITIONAL_CHECKED)))
400 {
401 struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
402 el_add_tagged(&el, shared->mailboxview, shared->email, priv->tag);
403 if (mutt_check_traditional_pgp(shared->mailbox, &el))
405 emaillist_clear(&el);
406 }
407 const int index = menu_get_index(priv->menu);
409
410 const char *const c_pager = cs_subset_string(NeoMutt->sub, "pager");
411 if (c_pager && !mutt_str_equal(c_pager, "builtin"))
412 {
413 op = external_pager(shared->mailbox, shared->email, c_pager);
414 }
415 else
416 {
417 op = mutt_display_message(priv->win_index, shared);
418 }
419
421 if (op < OP_NULL)
422 {
423 OptNeedResort = false;
424 return FR_ERROR;
425 }
426
427 if (shared->mailbox)
428 {
430 shared->mailbox->msg_count, shared);
431 }
432
433 return op;
434}
435
439static int op_edit_label(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
440{
441 struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
442 el_add_tagged(&el, shared->mailboxview, shared->email, priv->tag);
443 int num_changed = mutt_label_message(shared->mailbox, &el);
444 emaillist_clear(&el);
445
446 if (num_changed > 0)
447 {
448 shared->mailbox->changed = true;
450 /* L10N: This is displayed when the x-label on one or more
451 messages is edited. */
452 mutt_message(ngettext("%d label changed", "%d labels changed", num_changed), num_changed);
453
454 if (!priv->tag)
456 return FR_SUCCESS;
457 }
458
459 /* L10N: This is displayed when editing an x-label, but no messages
460 were updated. Possibly due to canceling at the prompt or if the new
461 label is the same as the old label. */
462 mutt_message(_("No labels changed"));
463 return FR_NO_ACTION;
464}
465
474static int op_edit_raw_message(struct IndexSharedData *shared,
475 struct IndexPrivateData *priv, int op)
476{
477 /* TODO split this into 3 cases? */
478 bool edit;
479 if (op == OP_EDIT_RAW_MESSAGE)
480 {
481 /* L10N: CHECK_ACL */
482 if (!check_acl(shared->mailbox, MUTT_ACL_INSERT, _("Can't edit message")))
483 return FR_ERROR;
484 edit = true;
485 }
486 else if (op == OP_EDIT_OR_VIEW_RAW_MESSAGE)
487 edit = !shared->mailbox->readonly && (shared->mailbox->rights & MUTT_ACL_INSERT);
488 else
489 edit = false;
490
491 if (!shared->email)
492 return FR_NO_ACTION;
493 const bool c_pgp_auto_decode = cs_subset_bool(shared->sub, "pgp_auto_decode");
494 if (c_pgp_auto_decode && (priv->tag || !(shared->email->security & PGP_TRADITIONAL_CHECKED)))
495 {
496 struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
497 el_add_tagged(&el, shared->mailboxview, shared->email, priv->tag);
498 if (mutt_check_traditional_pgp(shared->mailbox, &el))
500 emaillist_clear(&el);
501 }
502 struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
503 el_add_tagged(&el, shared->mailboxview, shared->email, priv->tag);
504 mutt_ev_message(shared->mailbox, &el, edit ? EVM_EDIT : EVM_VIEW);
505 emaillist_clear(&el);
507
508 return FR_SUCCESS;
509}
510
514static int op_end_cond(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
515{
516 return FR_SUCCESS;
517}
518
522static int op_exit(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
523{
524 if (priv->attach_msg)
525 return FR_DONE;
526
527 const enum QuadOption c_quit = cs_subset_quad(shared->sub, "quit");
528 if (query_quadoption(c_quit, _("Exit NeoMutt without saving?")) == MUTT_YES)
529 {
530 if (shared->mailboxview)
531 {
532 mx_fastclose_mailbox(shared->mailbox, false);
533 mview_free(&shared->mailboxview);
534 }
535 return FR_DONE;
536 }
537
538 return FR_NO_ACTION;
539}
540
544static int op_extract_keys(struct IndexSharedData *shared,
545 struct IndexPrivateData *priv, int op)
546{
547 if (!WithCrypto)
548 return FR_NOT_IMPL;
549 struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
550 el_add_tagged(&el, shared->mailboxview, shared->email, priv->tag);
552 emaillist_clear(&el);
554
555 return FR_SUCCESS;
556}
557
561static int op_flag_message(struct IndexSharedData *shared,
562 struct IndexPrivateData *priv, int op)
563{
564 /* L10N: CHECK_ACL */
565 if (!check_acl(shared->mailbox, MUTT_ACL_WRITE, _("Can't flag message")))
566 return FR_ERROR;
567
568 struct Mailbox *m = shared->mailbox;
569 if (priv->tag)
570 {
571 for (size_t i = 0; i < m->msg_count; i++)
572 {
573 struct Email *e = m->emails[i];
574 if (!e)
575 break;
576 if (message_is_tagged(e))
577 mutt_set_flag(m, e, MUTT_FLAG, !e->flagged);
578 }
579
581 }
582 else
583 {
584 if (!shared->email)
585 return FR_NO_ACTION;
586 mutt_set_flag(m, shared->email, MUTT_FLAG, !shared->email->flagged);
587
589 }
590
591 return FR_SUCCESS;
592}
593
597static int op_forget_passphrase(struct IndexSharedData *shared,
598 struct IndexPrivateData *priv, int op)
599{
601 return FR_SUCCESS;
602}
603
607static int op_forward_message(struct IndexSharedData *shared,
608 struct IndexPrivateData *priv, int op)
609{
610 if (!shared->email)
611 return FR_NO_ACTION;
612 struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
613 el_add_tagged(&el, shared->mailboxview, shared->email, priv->tag);
614 const bool c_pgp_auto_decode = cs_subset_bool(shared->sub, "pgp_auto_decode");
615 if (c_pgp_auto_decode && (priv->tag || !(shared->email->security & PGP_TRADITIONAL_CHECKED)))
616 {
617 if (mutt_check_traditional_pgp(shared->mailbox, &el))
619 }
620 int rc = mutt_send_message(SEND_FORWARD, NULL, NULL, shared->mailbox, &el,
621 shared->sub);
622 emaillist_clear(&el);
624
625 return (rc == -1) ? FR_ERROR : FR_SUCCESS;
626}
627
635static int op_group_reply(struct IndexSharedData *shared,
636 struct IndexPrivateData *priv, int op)
637{
638 SendFlags replyflags = SEND_REPLY;
639 if (op == OP_GROUP_REPLY)
640 replyflags |= SEND_GROUP_REPLY;
641 else
642 replyflags |= SEND_GROUP_CHAT_REPLY;
643 if (!shared->email)
644 return FR_NO_ACTION;
645 struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
646 el_add_tagged(&el, shared->mailboxview, shared->email, priv->tag);
647 const bool c_pgp_auto_decode = cs_subset_bool(shared->sub, "pgp_auto_decode");
648 if (c_pgp_auto_decode && (priv->tag || !(shared->email->security & PGP_TRADITIONAL_CHECKED)))
649 {
650 if (mutt_check_traditional_pgp(shared->mailbox, &el))
652 }
653 int rc = mutt_send_message(replyflags, NULL, NULL, shared->mailbox, &el,
654 shared->sub);
655 emaillist_clear(&el);
657
658 return (rc == -1) ? FR_ERROR : FR_SUCCESS;
659}
660
664static int op_jump(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
665{
666 int rc = FR_ERROR;
667 struct Buffer *buf = mutt_buffer_pool_get();
668
669 const int digit = op - OP_JUMP;
670 if (digit > 0 && digit < 10)
671 {
672 mutt_unget_ch('0' + digit);
673 }
674
675 int msg_num = 0;
676 if ((mutt_buffer_get_field(_("Jump to message: "), buf, MUTT_COMP_NO_FLAGS,
677 false, NULL, NULL, NULL) != 0) ||
679 {
680 mutt_message(_("Nothing to do"));
681 rc = FR_NO_ACTION;
682 }
683 else if (!mutt_str_atoi_full(mutt_buffer_string(buf), &msg_num))
684 {
685 mutt_warning(_("Argument must be a message number"));
686 }
687 else if ((msg_num < 1) || (msg_num > shared->mailbox->msg_count))
688 {
689 mutt_warning(_("Invalid message number"));
690 }
691 else if (!shared->mailbox->emails[msg_num - 1]->visible)
692 {
693 mutt_warning(_("That message is not visible"));
694 }
695 else
696 {
697 struct Email *e = shared->mailbox->emails[msg_num - 1];
698
699 if (mutt_messages_in_thread(shared->mailbox, e, MIT_POSITION) > 1)
700 {
702 mutt_set_vnum(shared->mailbox);
703 }
704 menu_set_index(priv->menu, e->vnum);
705 rc = FR_SUCCESS;
706 }
707
709 return rc;
710}
711
715static int op_list_reply(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
716{
717 if (!shared->email)
718 return FR_NO_ACTION;
719 struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
720 el_add_tagged(&el, shared->mailboxview, shared->email, priv->tag);
721 const bool c_pgp_auto_decode = cs_subset_bool(shared->sub, "pgp_auto_decode");
722 if (c_pgp_auto_decode && (priv->tag || !(shared->email->security & PGP_TRADITIONAL_CHECKED)))
723 {
724 if (mutt_check_traditional_pgp(shared->mailbox, &el))
726 }
727 int rc = mutt_send_message(SEND_REPLY | SEND_LIST_REPLY, NULL, NULL,
728 shared->mailbox, &el, shared->sub);
729 emaillist_clear(&el);
731
732 return (rc == -1) ? FR_ERROR : FR_SUCCESS;
733}
734
738static int op_list_subscribe(struct IndexSharedData *shared,
739 struct IndexPrivateData *priv, int op)
740{
741 return mutt_send_list_subscribe(shared->mailbox, shared->email) ? FR_SUCCESS : FR_NO_ACTION;
742}
743
747static int op_list_unsubscribe(struct IndexSharedData *shared,
748 struct IndexPrivateData *priv, int op)
749{
751}
752
756static int op_mail(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
757{
758 int rc = mutt_send_message(SEND_NO_FLAGS, NULL, NULL, shared->mailbox, NULL,
759 shared->sub);
761 return (rc == -1) ? FR_ERROR : FR_SUCCESS;
762}
763
767static int op_mailbox_list(struct IndexSharedData *shared,
768 struct IndexPrivateData *priv, int op)
769{
771 return FR_SUCCESS;
772}
773
777static int op_mail_key(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
778{
780 return FR_NOT_IMPL;
781 int rc = mutt_send_message(SEND_KEY, NULL, NULL, NULL, NULL, shared->sub);
783
784 return (rc == -1) ? FR_ERROR : FR_SUCCESS;
785}
786
790static int op_main_break_thread(struct IndexSharedData *shared,
791 struct IndexPrivateData *priv, int op)
792{
793 /* L10N: CHECK_ACL */
794 if (!check_acl(shared->mailbox, MUTT_ACL_WRITE, _("Can't break thread")))
795 return FR_ERROR;
796 if (!shared->email)
797 return FR_NO_ACTION;
798
799 if (!mutt_using_threads())
800 mutt_error(_("Threading is not enabled"));
801 else if (!STAILQ_EMPTY(&shared->email->env->in_reply_to) ||
802 !STAILQ_EMPTY(&shared->email->env->references))
803 {
804 {
805 mutt_break_thread(shared->email);
806 mutt_sort_headers(shared->mailbox, shared->mailboxview->threads, true,
807 &shared->mailboxview->vsize);
808 menu_set_index(priv->menu, shared->email->vnum);
809 }
810
811 shared->mailbox->changed = true;
812 mutt_message(_("Thread broken"));
813
815 }
816 else
817 {
818 mutt_error(_("Thread can't be broken, message is not part of a thread"));
819 }
820
821 return FR_SUCCESS;
822}
823
832static int op_main_change_folder(struct IndexSharedData *shared,
833 struct IndexPrivateData *priv, int op)
834{
835 struct Buffer *folderbuf = mutt_buffer_pool_get();
836 mutt_buffer_alloc(folderbuf, PATH_MAX);
837
838 char *cp = NULL;
839 bool read_only;
840 const bool c_read_only = cs_subset_bool(shared->sub, "read_only");
841 if (priv->attach_msg || c_read_only || (op == OP_MAIN_CHANGE_FOLDER_READONLY))
842 {
843 cp = _("Open mailbox in read-only mode");
844 read_only = true;
845 }
846 else
847 {
848 cp = _("Open mailbox");
849 read_only = false;
850 }
851
852 const bool c_change_folder_next = cs_subset_bool(shared->sub, "change_folder_next");
853 if (c_change_folder_next && shared->mailbox &&
855 {
856 mutt_buffer_strcpy(folderbuf, mailbox_path(shared->mailbox));
858 }
859 /* By default, fill buf with the next mailbox that contains unread mail */
860 mutt_mailbox_next(shared->mailboxview ? shared->mailbox : NULL, folderbuf);
861
862 if (mutt_buffer_enter_fname(cp, folderbuf, true, shared->mailbox, false, NULL,
863 NULL, MUTT_SEL_NO_FLAGS) == -1)
864 {
865 goto changefoldercleanup;
866 }
867
868 /* Selected directory is okay, let's save it. */
870
871 if (mutt_buffer_is_empty(folderbuf))
872 {
874 goto changefoldercleanup;
875 }
876
877 struct Mailbox *m = mx_mbox_find2(mutt_buffer_string(folderbuf));
878 if (m)
879 {
880 change_folder_mailbox(priv->menu, m, &priv->oldcount, shared, read_only);
881 }
882 else
883 {
884 change_folder_string(priv->menu, folderbuf->data, folderbuf->dsize,
885 &priv->oldcount, shared, read_only);
886 }
887
888changefoldercleanup:
889 mutt_buffer_pool_release(&folderbuf);
891
892 return FR_SUCCESS;
893}
894
898static int op_main_collapse_all(struct IndexSharedData *shared,
899 struct IndexPrivateData *priv, int op)
900{
901 if (!mutt_using_threads())
902 {
903 mutt_error(_("Threading is not enabled"));
904 return FR_ERROR;
905 }
906 collapse_all(shared->mailboxview, priv->menu, 1);
907
908 return FR_SUCCESS;
909}
910
914static int op_main_collapse_thread(struct IndexSharedData *shared,
915 struct IndexPrivateData *priv, int op)
916{
917 if (!mutt_using_threads())
918 {
919 mutt_error(_("Threading is not enabled"));
920 return FR_ERROR;
921 }
922
923 if (!shared->email)
924 return FR_NO_ACTION;
925
926 if (shared->email->collapsed)
927 {
928 int index = mutt_uncollapse_thread(shared->email);
929 mutt_set_vnum(shared->mailbox);
930 const bool c_uncollapse_jump = cs_subset_bool(shared->sub, "uncollapse_jump");
931 if (c_uncollapse_jump)
932 index = mutt_thread_next_unread(shared->email);
933 menu_set_index(priv->menu, index);
934 }
935 else if (mutt_thread_can_collapse(shared->email))
936 {
938 mutt_set_vnum(shared->mailbox);
939 }
940 else
941 {
942 mutt_error(_("Thread contains unread or flagged messages"));
943 return FR_ERROR;
944 }
945
947
948 return FR_SUCCESS;
949}
950
954static int op_main_delete_pattern(struct IndexSharedData *shared,
955 struct IndexPrivateData *priv, int op)
956{
957 /* L10N: CHECK_ACL */
958 /* L10N: Due to the implementation details we do not know whether we
959 delete zero, 1, 12, ... messages. So in English we use
960 "messages". Your language might have other means to express this. */
961 if (!check_acl(shared->mailbox, MUTT_ACL_DELETE, _("Can't delete messages")))
962 return FR_ERROR;
963
964 mutt_pattern_func(shared->mailboxview, MUTT_DELETE, _("Delete messages matching: "));
966
967 return FR_SUCCESS;
968}
969
978static int op_main_limit(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
979{
980 const bool lmt = mview_has_limit(shared->mailboxview);
981 int old_index = shared->email ? shared->email->index : -1;
982 if (op == OP_TOGGLE_READ)
983 {
984 char buf2[1024];
985
986 if (!lmt || !mutt_strn_equal(shared->mailboxview->pattern, "!~R!~D~s", 8))
987 {
988 snprintf(buf2, sizeof(buf2), "!~R!~D~s%s", lmt ? shared->mailboxview->pattern : ".*");
989 }
990 else
991 {
992 mutt_str_copy(buf2, shared->mailboxview->pattern + 8, sizeof(buf2));
993 if ((*buf2 == '\0') || mutt_strn_equal(buf2, ".*", 2))
994 snprintf(buf2, sizeof(buf2), "~A");
995 }
996 mutt_str_replace(&shared->mailboxview->pattern, buf2);
998 }
999
1000 if (((op == OP_LIMIT_CURRENT_THREAD) &&
1001 mutt_limit_current_thread(shared->mailboxview, shared->email)) ||
1002 (op == OP_TOGGLE_READ) ||
1003 ((op == OP_MAIN_LIMIT) && (mutt_pattern_func(shared->mailboxview, MUTT_LIMIT,
1004 _("Limit to messages matching: ")) == 0)))
1005 {
1006 if (old_index >= 0)
1007 {
1008 priv->menu->max = shared->mailbox->vcount;
1009 /* try to find what used to be the current message */
1010 menu_set_index(priv->menu, 0);
1011 for (size_t i = 0; i < shared->mailbox->vcount; i++)
1012 {
1013 struct Email *e = mutt_get_virt_email(shared->mailbox, i);
1014 if (!e)
1015 continue;
1016 if (e->index == old_index)
1017 {
1018 menu_set_index(priv->menu, i);
1019 break;
1020 }
1021 }
1022 }
1023
1024 if ((shared->mailbox->msg_count != 0) && mutt_using_threads())
1025 {
1026 const bool c_collapse_all = cs_subset_bool(shared->sub, "collapse_all");
1027 if (c_collapse_all)
1028 collapse_all(shared->mailboxview, priv->menu, 0);
1030 }
1032 }
1033 if (lmt)
1034 mutt_message(_("To view all messages, limit to \"all\""));
1035
1036 return FR_SUCCESS;
1037}
1038
1042static int op_main_link_threads(struct IndexSharedData *shared,
1043 struct IndexPrivateData *priv, int op)
1044{
1045 /* L10N: CHECK_ACL */
1046 if (!check_acl(shared->mailbox, MUTT_ACL_WRITE, _("Can't link threads")))
1047 return FR_ERROR;
1048 if (!shared->email)
1049 return FR_NO_ACTION;
1050
1051 enum FunctionRetval rc = FR_ERROR;
1052
1053 if (!mutt_using_threads())
1054 mutt_error(_("Threading is not enabled"));
1055 else if (!shared->email->env->message_id)
1056 mutt_error(_("No Message-ID: header available to link thread"));
1057 else
1058 {
1059 struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
1060 el_add_tagged(&el, shared->mailboxview, NULL, true);
1061
1062 if (mutt_link_threads(shared->email, &el, shared->mailbox))
1063 {
1064 mutt_sort_headers(shared->mailbox, shared->mailboxview->threads, true,
1065 &shared->mailboxview->vsize);
1066 menu_set_index(priv->menu, shared->email->vnum);
1067
1068 shared->mailbox->changed = true;
1069 mutt_message(_("Threads linked"));
1070 rc = FR_SUCCESS;
1071 }
1072 else
1073 {
1074 mutt_error(_("No thread linked"));
1075 rc = FR_NO_ACTION;
1076 }
1077
1078 emaillist_clear(&el);
1079 }
1080
1082 return rc;
1083}
1084
1092static int op_main_modify_tags(struct IndexSharedData *shared,
1093 struct IndexPrivateData *priv, int op)
1094{
1095 int rc = FR_ERROR;
1096 struct Buffer *buf = NULL;
1097
1098 if (!shared->mailbox)
1099 goto done;
1100 struct Mailbox *m = shared->mailbox;
1101 if (!mx_tags_is_supported(m))
1102 {
1103 mutt_message(_("Folder doesn't support tagging, aborting"));
1104 goto done;
1105 }
1106 if (!shared->email)
1107 {
1108 rc = FR_NO_ACTION;
1109 goto done;
1110 }
1111
1112 char *tags = NULL;
1113 if (!priv->tag)
1114 tags = driver_tags_get_with_hidden(&shared->email->tags);
1115 buf = mutt_buffer_pool_get();
1116 int rc2 = mx_tags_edit(m, tags, buf);
1117 FREE(&tags);
1118 if (rc2 < 0)
1119 {
1120 goto done;
1121 }
1122 else if (rc2 == 0)
1123 {
1124 mutt_message(_("No tag specified, aborting"));
1125 goto done;
1126 }
1127
1128 if (priv->tag)
1129 {
1130 struct Progress *progress = NULL;
1131
1132 if (m->verbose)
1133 {
1134 progress = progress_new(_("Update tags..."), MUTT_PROGRESS_WRITE, m->msg_tagged);
1135 }
1136
1137#ifdef USE_NOTMUCH
1138 if (m->type == MUTT_NOTMUCH)
1139 nm_db_longrun_init(m, true);
1140#endif
1141 for (int px = 0, i = 0; i < m->msg_count; i++)
1142 {
1143 struct Email *e = m->emails[i];
1144 if (!e)
1145 break;
1146 if (!message_is_tagged(e))
1147 continue;
1148
1149 if (m->verbose)
1150 progress_update(progress, ++px, -1);
1152 e->attr_color = NULL;
1153 if (op == OP_MAIN_MODIFY_TAGS_THEN_HIDE)
1154 {
1155 bool still_queried = false;
1156#ifdef USE_NOTMUCH
1157 if (m->type == MUTT_NOTMUCH)
1158 still_queried = nm_message_is_still_queried(m, e);
1159#endif
1160 e->quasi_deleted = !still_queried;
1161 m->changed = true;
1162 }
1163 }
1164 progress_free(&progress);
1165#ifdef USE_NOTMUCH
1166 if (m->type == MUTT_NOTMUCH)
1168#endif
1170 }
1171 else
1172 {
1173 if (mx_tags_commit(m, shared->email, mutt_buffer_string(buf)))
1174 {
1175 mutt_message(_("Failed to modify tags, aborting"));
1176 goto done;
1177 }
1178 shared->email->attr_color = NULL;
1179 if (op == OP_MAIN_MODIFY_TAGS_THEN_HIDE)
1180 {
1181 bool still_queried = false;
1182#ifdef USE_NOTMUCH
1183 if (m->type == MUTT_NOTMUCH)
1184 still_queried = nm_message_is_still_queried(m, shared->email);
1185#endif
1186 shared->email->quasi_deleted = !still_queried;
1187 m->changed = true;
1188 }
1189
1191 }
1192 rc = FR_SUCCESS;
1193
1194done:
1196 return rc;
1197}
1198
1210static int op_main_next_new(struct IndexSharedData *shared,
1211 struct IndexPrivateData *priv, int op)
1212{
1213 int first_unread = -1;
1214 int first_new = -1;
1215
1216 const int saved_current = menu_get_index(priv->menu);
1217 int mcur = saved_current;
1218 int index = -1;
1219 const bool threaded = mutt_using_threads();
1220 for (size_t i = 0; i != shared->mailbox->vcount; i++)
1221 {
1222 if ((op == OP_MAIN_NEXT_NEW) || (op == OP_MAIN_NEXT_UNREAD) ||
1223 (op == OP_MAIN_NEXT_NEW_THEN_UNREAD))
1224 {
1225 mcur++;
1226 if (mcur > (shared->mailbox->vcount - 1))
1227 {
1228 mcur = 0;
1229 }
1230 }
1231 else
1232 {
1233 mcur--;
1234 if (mcur < 0)
1235 {
1236 mcur = shared->mailbox->vcount - 1;
1237 }
1238 }
1239
1240 struct Email *e = mutt_get_virt_email(shared->mailbox, mcur);
1241 if (!e)
1242 break;
1243 if (e->collapsed && threaded)
1244 {
1245 int unread = mutt_thread_contains_unread(e);
1246 if ((unread != 0) && (first_unread == -1))
1247 first_unread = mcur;
1248 if ((unread == 1) && (first_new == -1))
1249 first_new = mcur;
1250 }
1251 else if (!e->deleted && !e->read)
1252 {
1253 if (first_unread == -1)
1254 first_unread = mcur;
1255 if (!e->old && (first_new == -1))
1256 first_new = mcur;
1257 }
1258
1259 if (((op == OP_MAIN_NEXT_UNREAD) || (op == OP_MAIN_PREV_UNREAD)) && (first_unread != -1))
1260 {
1261 break;
1262 }
1263 if (((op == OP_MAIN_NEXT_NEW) || (op == OP_MAIN_PREV_NEW) ||
1264 (op == OP_MAIN_NEXT_NEW_THEN_UNREAD) || (op == OP_MAIN_PREV_NEW_THEN_UNREAD)) &&
1265 (first_new != -1))
1266 {
1267 break;
1268 }
1269 }
1270 if (((op == OP_MAIN_NEXT_NEW) || (op == OP_MAIN_PREV_NEW) ||
1271 (op == OP_MAIN_NEXT_NEW_THEN_UNREAD) || (op == OP_MAIN_PREV_NEW_THEN_UNREAD)) &&
1272 (first_new != -1))
1273 {
1274 index = first_new;
1275 }
1276 else if (((op == OP_MAIN_NEXT_UNREAD) || (op == OP_MAIN_PREV_UNREAD) ||
1277 (op == OP_MAIN_NEXT_NEW_THEN_UNREAD) || (op == OP_MAIN_PREV_NEW_THEN_UNREAD)) &&
1278 (first_unread != -1))
1279 {
1280 index = first_unread;
1281 }
1282
1283 if (index == -1)
1284 {
1285 menu_set_index(priv->menu, saved_current);
1286 if ((op == OP_MAIN_NEXT_NEW) || (op == OP_MAIN_PREV_NEW))
1287 {
1288 if (mview_has_limit(shared->mailboxview))
1289 mutt_error(_("No new messages in this limited view"));
1290 else
1291 mutt_error(_("No new messages"));
1292 }
1293 else
1294 {
1295 if (mview_has_limit(shared->mailboxview))
1296 mutt_error(_("No unread messages in this limited view"));
1297 else
1298 mutt_error(_("No unread messages"));
1299 }
1300 notify_send(shared->notify, NT_INDEX, NT_INDEX_EMAIL, NULL);
1301 return FR_ERROR;
1302 }
1303 else
1304 {
1305 menu_set_index(priv->menu, index);
1306 }
1307
1308 index = menu_get_index(priv->menu);
1309 if ((op == OP_MAIN_NEXT_NEW) || (op == OP_MAIN_NEXT_UNREAD) ||
1310 (op == OP_MAIN_NEXT_NEW_THEN_UNREAD))
1311 {
1312 if (saved_current > index)
1313 {
1314 mutt_message(_("Search wrapped to top"));
1315 }
1316 }
1317 else if (saved_current < index)
1318 {
1319 mutt_message(_("Search wrapped to bottom"));
1320 }
1321
1322 return FR_SUCCESS;
1323}
1324
1334static int op_main_next_thread(struct IndexSharedData *shared,
1335 struct IndexPrivateData *priv, int op)
1336{
1337 int index = -1;
1338 switch (op)
1339 {
1340 case OP_MAIN_NEXT_THREAD:
1341 index = mutt_next_thread(shared->email);
1342 break;
1343
1344 case OP_MAIN_NEXT_SUBTHREAD:
1345 index = mutt_next_subthread(shared->email);
1346 break;
1347
1348 case OP_MAIN_PREV_THREAD:
1349 index = mutt_previous_thread(shared->email);
1350 break;
1351
1352 case OP_MAIN_PREV_SUBTHREAD:
1354 break;
1355 }
1356
1357 if (index != -1)
1358 menu_set_index(priv->menu, index);
1359
1360 if (index < 0)
1361 {
1362 if ((op == OP_MAIN_NEXT_THREAD) || (op == OP_MAIN_NEXT_SUBTHREAD))
1363 mutt_error(_("No more threads"));
1364 else
1365 mutt_error(_("You are on the first thread"));
1366
1367 notify_send(shared->notify, NT_INDEX, NT_INDEX_EMAIL, NULL);
1368 }
1369
1370 return FR_SUCCESS;
1371}
1372
1376static int op_main_next_undeleted(struct IndexSharedData *shared,
1377 struct IndexPrivateData *priv, int op)
1378{
1379 int index = menu_get_index(priv->menu);
1380 if (index >= (shared->mailbox->vcount - 1))
1381 {
1382 notify_send(shared->notify, NT_INDEX, NT_INDEX_EMAIL, NULL);
1383 mutt_message(_("You are on the last message"));
1384 return FR_ERROR;
1385 }
1386
1387 const bool uncollapse = mutt_using_threads() && !window_is_focused(priv->win_index);
1388
1389 index = ci_next_undeleted(shared->mailbox, index, uncollapse);
1390 if (index != -1)
1391 {
1392 menu_set_index(priv->menu, index);
1393 if (uncollapse)
1395 }
1396
1397 if (index == -1)
1398 {
1399 notify_send(shared->notify, NT_INDEX, NT_INDEX_EMAIL, NULL);
1400 mutt_error(_("No undeleted messages"));
1401 }
1402
1403 return FR_SUCCESS;
1404}
1405
1410 struct IndexPrivateData *priv, int op)
1411{
1412 struct Mailbox *m = shared->mailbox;
1413
1414 struct Buffer *folderbuf = mutt_buffer_pool_get();
1415 mutt_buffer_strcpy(folderbuf, mailbox_path(m));
1416 m = mutt_mailbox_next_unread(m, folderbuf);
1417 mutt_buffer_pool_release(&folderbuf);
1418
1419 if (!m)
1420 {
1421 mutt_error(_("No mailboxes have new mail"));
1422 return FR_ERROR;
1423 }
1424
1425 change_folder_mailbox(priv->menu, m, &priv->oldcount, shared, false);
1426 return FR_SUCCESS;
1427}
1428
1432static int op_main_prev_undeleted(struct IndexSharedData *shared,
1433 struct IndexPrivateData *priv, int op)
1434{
1435 int index = menu_get_index(priv->menu);
1436 if (index < 1)
1437 {
1438 notify_send(shared->notify, NT_INDEX, NT_INDEX_EMAIL, NULL);
1439 mutt_message(_("You are on the first message"));
1440 return FR_ERROR;
1441 }
1442
1443 const bool uncollapse = mutt_using_threads() && !window_is_focused(priv->win_index);
1444
1445 index = ci_previous_undeleted(shared->mailbox, index, uncollapse);
1446 if (index != -1)
1447 {
1448 menu_set_index(priv->menu, index);
1449 if (uncollapse)
1451 }
1452
1453 if (index == -1)
1454 {
1455 mutt_error(_("No undeleted messages"));
1456 notify_send(shared->notify, NT_INDEX, NT_INDEX_EMAIL, NULL);
1457 }
1458
1459 return FR_SUCCESS;
1460}
1461
1465static int op_main_quasi_delete(struct IndexSharedData *shared,
1466 struct IndexPrivateData *priv, int op)
1467{
1468 if (priv->tag)
1469 {
1470 struct Mailbox *m = shared->mailbox;
1471 for (size_t i = 0; i < m->msg_count; i++)
1472 {
1473 struct Email *e = m->emails[i];
1474 if (!e)
1475 break;
1476 if (message_is_tagged(e))
1477 {
1478 e->quasi_deleted = true;
1479 m->changed = true;
1480 }
1481 }
1482 }
1483 else
1484 {
1485 if (!shared->email)
1486 return FR_NO_ACTION;
1487 shared->email->quasi_deleted = true;
1488 shared->mailbox->changed = true;
1489 }
1490
1491 return FR_SUCCESS;
1492}
1493
1501static int op_main_read_thread(struct IndexSharedData *shared,
1502 struct IndexPrivateData *priv, int op)
1503{
1504 /* L10N: CHECK_ACL */
1505 /* L10N: Due to the implementation details we do not know whether we
1506 mark zero, 1, 12, ... messages as read. So in English we use
1507 "messages". Your language might have other means to express this. */
1508 if (!check_acl(shared->mailbox, MUTT_ACL_SEEN, _("Can't mark messages as read")))
1509 return FR_ERROR;
1510
1511 int rc = mutt_thread_set_flag(shared->mailbox, shared->email, MUTT_READ, true,
1512 (op != OP_MAIN_READ_THREAD));
1513 if (rc != -1)
1514 {
1515 const enum ResolveMethod rm = (op == OP_MAIN_READ_THREAD) ? RESOLVE_NEXT_THREAD :
1517 resolve_email(priv, shared, rm);
1519 }
1520
1521 return FR_SUCCESS;
1522}
1523
1531static int op_main_root_message(struct IndexSharedData *shared,
1532 struct IndexPrivateData *priv, int op)
1533{
1534 int index = mutt_parent_message(shared->email, op == OP_MAIN_ROOT_MESSAGE);
1535 if (index != -1)
1536 menu_set_index(priv->menu, index);
1537
1538 return FR_SUCCESS;
1539}
1540
1548static int op_main_set_flag(struct IndexSharedData *shared,
1549 struct IndexPrivateData *priv, int op)
1550{
1551 /* check_acl(MUTT_ACL_WRITE); */
1552 struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
1553 el_add_tagged(&el, shared->mailboxview, shared->email, priv->tag);
1554
1555 if (mutt_change_flag(shared->mailbox, &el, (op == OP_MAIN_SET_FLAG)) == 0)
1556 {
1557 if (priv->tag)
1558 {
1560 }
1561 else
1562 {
1564 }
1565 }
1566 emaillist_clear(&el);
1567
1568 return FR_SUCCESS;
1569}
1570
1574static int op_main_show_limit(struct IndexSharedData *shared,
1575 struct IndexPrivateData *priv, int op)
1576{
1577 if (!mview_has_limit(shared->mailboxview))
1578 mutt_message(_("No limit pattern is in effect"));
1579 else
1580 {
1581 char buf2[256];
1582 /* L10N: ask for a limit to apply */
1583 snprintf(buf2, sizeof(buf2), _("Limit: %s"), shared->mailboxview->pattern);
1584 mutt_message("%s", buf2);
1585 }
1586
1587 return FR_SUCCESS;
1588}
1589
1593static int op_main_sync_folder(struct IndexSharedData *shared,
1594 struct IndexPrivateData *priv, int op)
1595{
1596 if (!shared->mailbox || (shared->mailbox->msg_count == 0) || shared->mailbox->readonly)
1597 return FR_NO_ACTION;
1598
1599 int ovc = shared->mailbox->vcount;
1600 int oc = shared->mailbox->msg_count;
1601 struct Email *e = NULL;
1602
1603 /* don't attempt to move the cursor if there are no visible messages in the current limit */
1604 int index = menu_get_index(priv->menu);
1605 if (index < shared->mailbox->vcount)
1606 {
1607 /* threads may be reordered, so figure out what header the cursor
1608 * should be on. */
1609 int newidx = index;
1610 if (!shared->email)
1611 return FR_NO_ACTION;
1612 if (shared->email->deleted)
1613 newidx = ci_next_undeleted(shared->mailbox, index, false);
1614 if (newidx < 0)
1615 newidx = ci_previous_undeleted(shared->mailbox, index, false);
1616 if (newidx >= 0)
1617 e = mutt_get_virt_email(shared->mailbox, newidx);
1618 }
1619
1620 enum MxStatus check = mx_mbox_sync(shared->mailbox);
1621 if (check == MX_STATUS_OK)
1622 {
1623 if (e && (shared->mailbox->vcount != ovc))
1624 {
1625 for (size_t i = 0; i < shared->mailbox->vcount; i++)
1626 {
1627 struct Email *e2 = mutt_get_virt_email(shared->mailbox, i);
1628 if (e2 == e)
1629 {
1630 menu_set_index(priv->menu, i);
1631 break;
1632 }
1633 }
1634 }
1635 OptSearchInvalid = true;
1636 }
1637 else if ((check == MX_STATUS_NEW_MAIL) || (check == MX_STATUS_REOPENED))
1638 {
1639 update_index(priv->menu, shared->mailboxview, check, oc, shared);
1640 }
1641
1642 /* do a sanity check even if mx_mbox_sync failed. */
1643
1644 index = menu_get_index(priv->menu);
1645 if ((index < 0) || (shared->mailbox && (index >= shared->mailbox->vcount)))
1646 {
1648 }
1649
1650 /* check for a fatal error, or all messages deleted */
1651 if (shared->mailbox && mutt_buffer_is_empty(&shared->mailbox->pathbuf))
1652 {
1653 mview_free(&shared->mailboxview);
1654 }
1655
1656 priv->menu->max = shared->mailbox->vcount;
1658
1659 return FR_SUCCESS;
1660}
1661
1665static int op_main_tag_pattern(struct IndexSharedData *shared,
1666 struct IndexPrivateData *priv, int op)
1667{
1668 mutt_pattern_func(shared->mailboxview, MUTT_TAG, _("Tag messages matching: "));
1670
1671 return FR_SUCCESS;
1672}
1673
1678 struct IndexPrivateData *priv, int op)
1679{
1680 /* L10N: CHECK_ACL */
1681 /* L10N: Due to the implementation details we do not know whether we
1682 undelete zero, 1, 12, ... messages. So in English we use
1683 "messages". Your language might have other means to express this. */
1684 if (!check_acl(shared->mailbox, MUTT_ACL_DELETE, _("Can't undelete messages")))
1685 return FR_ERROR;
1686
1688 _("Undelete messages matching: ")) == 0)
1689 {
1691 }
1692
1693 return FR_SUCCESS;
1694}
1695
1699static int op_main_untag_pattern(struct IndexSharedData *shared,
1700 struct IndexPrivateData *priv, int op)
1701{
1702 if (mutt_pattern_func(shared->mailboxview, MUTT_UNTAG, _("Untag messages matching: ")) == 0)
1704
1705 return FR_SUCCESS;
1706}
1707
1711static int op_mark_msg(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
1712{
1713 if (!shared->email)
1714 return FR_NO_ACTION;
1715
1716 int rc = FR_SUCCESS;
1717
1718 if (shared->email->env->message_id)
1719 {
1720 struct Buffer *buf = mutt_buffer_pool_get();
1721
1722 /* L10N: This is the prompt for <mark-message>. Whatever they
1723 enter will be prefixed by $mark_macro_prefix and will become
1724 a macro hotkey to jump to the currently selected message. */
1725 if ((mutt_buffer_get_field(_("Enter macro stroke: "), buf, MUTT_COMP_NO_FLAGS,
1726 false, NULL, NULL, NULL) == 0) &&
1728 {
1729 const char *const c_mark_macro_prefix = cs_subset_string(shared->sub, "mark_macro_prefix");
1730 char str[256] = { 0 };
1731 snprintf(str, sizeof(str), "%s%s", c_mark_macro_prefix, mutt_buffer_string(buf));
1732
1733 struct Buffer *msg_id = mutt_buffer_pool_get();
1734 mutt_file_sanitize_regex(msg_id, shared->email->env->message_id);
1735 char macro[256] = { 0 };
1736 snprintf(macro, sizeof(macro), "<search>~i '%s'\n", mutt_buffer_string(msg_id));
1737 mutt_buffer_pool_release(&msg_id);
1738
1739 /* L10N: "message hotkey" is the key bindings menu description of a
1740 macro created by <mark-message>. */
1741 km_bind(str, MENU_INDEX, OP_MACRO, macro, _("message hotkey"));
1742
1743 /* L10N: This is echoed after <mark-message> creates a new hotkey
1744 macro. %s is the hotkey string ($mark_macro_prefix followed
1745 by whatever they typed at the prompt.) */
1746 mutt_buffer_printf(buf, _("Message bound to %s"), str);
1748 mutt_debug(LL_DEBUG1, "Mark: %s => %s\n", str, macro);
1750 }
1751 }
1752 else
1753 {
1754 /* L10N: This error is printed if <mark-message> can't find a
1755 Message-ID for the currently selected message in the index. */
1756 mutt_error(_("No message ID to macro"));
1757 rc = FR_ERROR;
1758 }
1759
1760 return rc;
1761}
1762
1766static int op_next_entry(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
1767{
1768 const int index = menu_get_index(priv->menu) + 1;
1769 if (index >= shared->mailbox->vcount)
1770 {
1771 mutt_message(_("You are on the last message"));
1772 notify_send(shared->notify, NT_INDEX, NT_INDEX_EMAIL, NULL);
1773 return FR_ERROR;
1774 }
1775 menu_set_index(priv->menu, index);
1776 return FR_SUCCESS;
1777}
1778
1782static int op_pipe(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
1783{
1784 struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
1785 el_add_tagged(&el, shared->mailboxview, shared->email, priv->tag);
1786 mutt_pipe_message(shared->mailbox, &el);
1787 emaillist_clear(&el);
1788
1789#ifdef USE_IMAP
1790 /* in an IMAP folder index with imap_peek=no, piping could change
1791 * new or old messages status to read. Redraw what's needed. */
1792 const bool c_imap_peek = cs_subset_bool(shared->sub, "imap_peek");
1793 if ((shared->mailbox->type == MUTT_IMAP) && !c_imap_peek)
1794 {
1796 }
1797#endif
1798
1799 return FR_SUCCESS;
1800}
1801
1805static int op_prev_entry(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
1806{
1807 int index = menu_get_index(priv->menu);
1808 if (index < 1)
1809 {
1810 notify_send(shared->notify, NT_INDEX, NT_INDEX_EMAIL, NULL);
1811 mutt_message(_("You are on the first message"));
1812 return FR_ERROR;
1813 }
1814 menu_set_index(priv->menu, index - 1);
1815 return FR_SUCCESS;
1816}
1817
1821static int op_print(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
1822{
1823 struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
1824 el_add_tagged(&el, shared->mailboxview, shared->email, priv->tag);
1825 mutt_print_message(shared->mailbox, &el);
1826 emaillist_clear(&el);
1827
1828#ifdef USE_IMAP
1829 /* in an IMAP folder index with imap_peek=no, printing could change
1830 * new or old messages status to read. Redraw what's needed. */
1831 const bool c_imap_peek = cs_subset_bool(shared->sub, "imap_peek");
1832 if ((shared->mailbox->type == MUTT_IMAP) && !c_imap_peek)
1833 {
1835 }
1836#endif
1837
1838 return FR_SUCCESS;
1839}
1840
1844static int op_query(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
1845{
1846 query_index(shared->mailbox, shared->sub);
1847 return FR_SUCCESS;
1848}
1849
1853static int op_quit(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
1854{
1855 if (priv->attach_msg)
1856 return FR_DONE;
1857
1858 const enum QuadOption c_quit = cs_subset_quad(shared->sub, "quit");
1859 if (query_quadoption(c_quit, _("Quit NeoMutt?")) == MUTT_YES)
1860 {
1861 priv->oldcount = shared->mailbox ? shared->mailbox->msg_count : 0;
1862
1864 mutt_debug(LL_NOTIFY, "NT_GLOBAL_SHUTDOWN\n");
1866
1867 enum MxStatus check = MX_STATUS_OK;
1868 if (!shared->mailboxview || ((check = mx_mbox_close(shared->mailbox)) == MX_STATUS_OK))
1869 {
1870 mview_free(&shared->mailboxview);
1871 mailbox_free(&shared->mailbox);
1872 return FR_DONE;
1873 }
1874
1875 if ((check == MX_STATUS_NEW_MAIL) || (check == MX_STATUS_REOPENED))
1876 {
1877 update_index(priv->menu, shared->mailboxview, check, priv->oldcount, shared);
1878 }
1879
1880 menu_queue_redraw(priv->menu, MENU_REDRAW_FULL); /* new mail arrived? */
1881 OptSearchInvalid = true;
1882 }
1883
1884 return FR_NO_ACTION;
1885}
1886
1890static int op_recall_message(struct IndexSharedData *shared,
1891 struct IndexPrivateData *priv, int op)
1892{
1893 int rc = mutt_send_message(SEND_POSTPONED, NULL, NULL, shared->mailbox, NULL,
1894 shared->sub);
1896 return (rc == -1) ? FR_ERROR : FR_SUCCESS;
1897}
1898
1902static int op_reply(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
1903{
1904 if (!shared->email)
1905 return FR_NO_ACTION;
1906 struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
1907 el_add_tagged(&el, shared->mailboxview, shared->email, priv->tag);
1908 const bool c_pgp_auto_decode = cs_subset_bool(shared->sub, "pgp_auto_decode");
1909 if (c_pgp_auto_decode && (priv->tag || !(shared->email->security & PGP_TRADITIONAL_CHECKED)))
1910 {
1911 if (mutt_check_traditional_pgp(shared->mailbox, &el))
1913 }
1914 int rc = mutt_send_message(SEND_REPLY, NULL, NULL, shared->mailbox, &el,
1915 shared->sub);
1916 emaillist_clear(&el);
1918
1919 return (rc == -1) ? FR_ERROR : FR_SUCCESS;
1920}
1921
1925static int op_resend(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
1926{
1927 int rc = -1;
1928 if (priv->tag)
1929 {
1930 struct Mailbox *m = shared->mailbox;
1931 for (size_t i = 0; i < m->msg_count; i++)
1932 {
1933 struct Email *e = m->emails[i];
1934 if (!e)
1935 break;
1936 if (message_is_tagged(e))
1937 rc = mutt_resend_message(NULL, shared->mailbox, e, shared->sub);
1938 }
1939 }
1940 else
1941 {
1942 rc = mutt_resend_message(NULL, shared->mailbox, shared->email, shared->sub);
1943 }
1944
1946 return (rc == -1) ? FR_ERROR : FR_SUCCESS;
1947}
1948
1960static int op_save(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
1961{
1962 if (((op == OP_DECRYPT_COPY) || (op == OP_DECRYPT_SAVE)) && !WithCrypto)
1963 return FR_NOT_IMPL;
1964
1965 struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
1966 el_add_tagged(&el, shared->mailboxview, shared->email, priv->tag);
1967
1968 const enum MessageSaveOpt save_opt = ((op == OP_SAVE) || (op == OP_DECODE_SAVE) ||
1969 (op == OP_DECRYPT_SAVE)) ?
1970 SAVE_MOVE :
1971 SAVE_COPY;
1972
1973 enum MessageTransformOpt transform_opt =
1974 ((op == OP_DECODE_SAVE) || (op == OP_DECODE_COPY)) ? TRANSFORM_DECODE :
1975 ((op == OP_DECRYPT_SAVE) || (op == OP_DECRYPT_COPY)) ? TRANSFORM_DECRYPT :
1977
1978 const int rc = mutt_save_message(shared->mailbox, &el, save_opt, transform_opt);
1979 if ((rc == 0) && (save_opt == SAVE_MOVE))
1980 {
1981 if (priv->tag)
1982 {
1984 }
1985 else
1986 {
1988 }
1989 }
1990 emaillist_clear(&el);
1991
1992 return (rc == -1) ? FR_ERROR : FR_SUCCESS;
1993}
1994
2004static int op_search(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
2005{
2006 // Initiating a search can happen on an empty mailbox, but
2007 // searching for next/previous/... needs to be on a message and
2008 // thus a non-empty mailbox
2009 int index = menu_get_index(priv->menu);
2010 index = mutt_search_command(shared->mailbox, priv->menu, index, op);
2011 if (index != -1)
2012 menu_set_index(priv->menu, index);
2013
2014 return FR_SUCCESS;
2015}
2016
2024static int op_sort(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
2025{
2026 if (!mutt_select_sort(op == OP_SORT_REVERSE))
2027 return FR_ERROR;
2028
2029 if (shared->mailbox && (shared->mailbox->msg_count != 0))
2030 {
2031 resort_index(shared->mailboxview, priv->menu);
2032 OptSearchInvalid = true;
2033 }
2034
2035 return FR_SUCCESS;
2036}
2037
2041static int op_tag(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
2042{
2043 const bool c_auto_tag = cs_subset_bool(shared->sub, "auto_tag");
2044 if (priv->tag && !c_auto_tag)
2045 {
2046 struct Mailbox *m = shared->mailbox;
2047 for (size_t i = 0; i < m->msg_count; i++)
2048 {
2049 struct Email *e = m->emails[i];
2050 if (!e)
2051 break;
2052 if (e->visible)
2053 mutt_set_flag(m, e, MUTT_TAG, false);
2054 }
2056 return FR_SUCCESS;
2057 }
2058
2059 if (!shared->email)
2060 return FR_NO_ACTION;
2061
2062 mutt_set_flag(shared->mailbox, shared->email, MUTT_TAG, !shared->email->tagged);
2063
2064 resolve_email(priv, shared, RESOLVE_NEXT_EMAIL);
2065 return FR_SUCCESS;
2066}
2067
2075static int op_tag_thread(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
2076{
2077 if (!shared->email)
2078 return FR_NO_ACTION;
2079
2080 int rc = mutt_thread_set_flag(shared->mailbox, shared->email, MUTT_TAG,
2081 !shared->email->tagged, (op != OP_TAG_THREAD));
2082 if (rc != -1)
2083 {
2084 const enum ResolveMethod rm = (op == OP_TAG_THREAD) ? RESOLVE_NEXT_THREAD :
2086 resolve_email(priv, shared, rm);
2088 }
2089
2090 return FR_SUCCESS;
2091}
2092
2096static int op_toggle_new(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
2097{
2098 /* L10N: CHECK_ACL */
2099 if (!check_acl(shared->mailbox, MUTT_ACL_SEEN, _("Can't toggle new")))
2100 return FR_ERROR;
2101
2102 struct Mailbox *m = shared->mailbox;
2103 if (priv->tag)
2104 {
2105 for (size_t i = 0; i < m->msg_count; i++)
2106 {
2107 struct Email *e = m->emails[i];
2108 if (!e)
2109 break;
2110 if (!message_is_tagged(e))
2111 continue;
2112
2113 if (e->read || e->old)
2114 mutt_set_flag(m, e, MUTT_NEW, true);
2115 else
2116 mutt_set_flag(m, e, MUTT_READ, true);
2117 }
2119 }
2120 else
2121 {
2122 if (!shared->email)
2123 return FR_NO_ACTION;
2124 if (shared->email->read || shared->email->old)
2125 mutt_set_flag(m, shared->email, MUTT_NEW, true);
2126 else
2127 mutt_set_flag(m, shared->email, MUTT_READ, true);
2128
2130 }
2131
2132 return FR_SUCCESS;
2133}
2134
2138static int op_toggle_write(struct IndexSharedData *shared,
2139 struct IndexPrivateData *priv, int op)
2140{
2141 mx_toggle_write(shared->mailbox);
2142 return FR_SUCCESS;
2143}
2144
2148static int op_undelete(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
2149{
2150 /* L10N: CHECK_ACL */
2151 if (!check_acl(shared->mailbox, MUTT_ACL_DELETE, _("Can't undelete message")))
2152 return FR_ERROR;
2153
2154 struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
2155 el_add_tagged(&el, shared->mailboxview, shared->email, priv->tag);
2156
2157 mutt_emails_set_flag(shared->mailbox, &el, MUTT_DELETE, false);
2158 mutt_emails_set_flag(shared->mailbox, &el, MUTT_PURGE, false);
2159 emaillist_clear(&el);
2160
2161 if (priv->tag)
2162 {
2164 }
2165 else
2166 {
2167 resolve_email(priv, shared, RESOLVE_NEXT_EMAIL);
2168 }
2169
2170 return FR_SUCCESS;
2171}
2172
2180static int op_undelete_thread(struct IndexSharedData *shared,
2181 struct IndexPrivateData *priv, int op)
2182{
2183 /* L10N: CHECK_ACL */
2184 /* L10N: Due to the implementation details we do not know whether we
2185 undelete zero, 1, 12, ... messages. So in English we use
2186 "messages". Your language might have other means to express this. */
2187 if (!check_acl(shared->mailbox, MUTT_ACL_DELETE, _("Can't undelete messages")))
2188 return FR_ERROR;
2189
2190 int rc = mutt_thread_set_flag(shared->mailbox, shared->email, MUTT_DELETE,
2191 false, (op != OP_UNDELETE_THREAD));
2192 if (rc != -1)
2193 {
2194 rc = mutt_thread_set_flag(shared->mailbox, shared->email, MUTT_PURGE, false,
2195 (op != OP_UNDELETE_THREAD));
2196 }
2197 if (rc != -1)
2198 {
2199 const enum ResolveMethod rm = (op == OP_UNDELETE_THREAD) ? RESOLVE_NEXT_THREAD :
2201 resolve_email(priv, shared, rm);
2203 }
2204
2205 return FR_SUCCESS;
2206}
2207
2211static int op_view_attachments(struct IndexSharedData *shared,
2212 struct IndexPrivateData *priv, int op)
2213{
2214 if (!shared->email)
2215 return FR_NO_ACTION;
2216
2217 enum FunctionRetval rc = FR_ERROR;
2218 struct Message *msg = mx_msg_open(shared->mailbox, shared->email->msgno);
2219 if (msg)
2220 {
2221 dlg_select_attachment(NeoMutt->sub, shared->mailbox, shared->email, msg->fp);
2222 if (shared->email->attach_del)
2223 {
2224 shared->mailbox->changed = true;
2225 }
2226 mx_msg_close(shared->mailbox, &msg);
2227 rc = FR_SUCCESS;
2228 }
2230 return rc;
2231}
2232
2233// -----------------------------------------------------------------------------
2234
2235#ifdef USE_AUTOCRYPT
2239static int op_autocrypt_acct_menu(struct IndexSharedData *shared,
2240 struct IndexPrivateData *priv, int op)
2241{
2243 return FR_SUCCESS;
2244}
2245#endif
2246
2247#ifdef USE_IMAP
2251static int op_main_imap_fetch(struct IndexSharedData *shared,
2252 struct IndexPrivateData *priv, int op)
2253{
2254 if (!shared->mailbox || (shared->mailbox->type != MUTT_IMAP))
2255 return FR_NO_ACTION;
2256
2257 imap_check_mailbox(shared->mailbox, true);
2258 return FR_SUCCESS;
2259}
2260
2265 struct IndexPrivateData *priv, int op)
2266{
2267 if (shared->mailbox && (shared->mailbox->type == MUTT_IMAP))
2268 {
2269 const enum MxStatus check = mx_mbox_close(shared->mailbox);
2270 if (check == MX_STATUS_OK)
2271 {
2272 mview_free(&shared->mailboxview);
2273 }
2274 else
2275 {
2276 if ((check == MX_STATUS_NEW_MAIL) || (check == MX_STATUS_REOPENED))
2277 {
2278 update_index(priv->menu, shared->mailboxview, check, priv->oldcount, shared);
2279 }
2280 OptSearchInvalid = true;
2282 return FR_ERROR;
2283 }
2284 }
2286 mutt_message(_("Logged out of IMAP servers"));
2287 OptSearchInvalid = true;
2289
2290 return FR_SUCCESS;
2291}
2292#endif
2293
2294#ifdef USE_NNTP
2298static int op_catchup(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
2299{
2300 if (!shared->mailbox || (shared->mailbox->type != MUTT_NNTP))
2301 return FR_NO_ACTION;
2302
2303 struct NntpMboxData *mdata = shared->mailbox->mdata;
2304 if (mutt_newsgroup_catchup(shared->mailbox, mdata->adata, mdata->group))
2306
2307 return FR_SUCCESS;
2308}
2309
2317static int op_get_children(struct IndexSharedData *shared,
2318 struct IndexPrivateData *priv, int op)
2319{
2320 if (shared->mailbox->type != MUTT_NNTP)
2321 return FR_ERROR;
2322
2323 if (!shared->email)
2324 return FR_NO_ACTION;
2325
2326 char buf[PATH_MAX] = { 0 };
2327 int oldmsgcount = shared->mailbox->msg_count;
2328 int oldindex = shared->email->index;
2329 int rc = 0;
2330
2331 if (!shared->email->env->message_id)
2332 {
2333 mutt_error(_("No Message-Id. Unable to perform operation."));
2334 return FR_ERROR;
2335 }
2336
2337 mutt_message(_("Fetching message headers..."));
2338 if (!shared->mailbox->id_hash)
2339 shared->mailbox->id_hash = mutt_make_id_hash(shared->mailbox);
2340 mutt_str_copy(buf, shared->email->env->message_id, sizeof(buf));
2341
2342 /* trying to find msgid of the root message */
2343 if (op == OP_RECONSTRUCT_THREAD)
2344 {
2345 struct ListNode *ref = NULL;
2346 STAILQ_FOREACH(ref, &shared->email->env->references, entries)
2347 {
2348 if (!mutt_hash_find(shared->mailbox->id_hash, ref->data))
2349 {
2350 rc = nntp_check_msgid(shared->mailbox, ref->data);
2351 if (rc < 0)
2352 return FR_ERROR;
2353 }
2354
2355 /* the last msgid in References is the root message */
2356 if (!STAILQ_NEXT(ref, entries))
2357 mutt_str_copy(buf, ref->data, sizeof(buf));
2358 }
2359 }
2360
2361 /* fetching all child messages */
2362 rc = nntp_check_children(shared->mailbox, buf);
2363
2364 /* at least one message has been loaded */
2365 if (shared->mailbox->msg_count > oldmsgcount)
2366 {
2367 bool verbose = shared->mailbox->verbose;
2368
2369 if (rc < 0)
2370 shared->mailbox->verbose = false;
2371 mutt_sort_headers(shared->mailbox, shared->mailboxview->threads,
2372 (op == OP_RECONSTRUCT_THREAD), &shared->mailboxview->vsize);
2373 shared->mailbox->verbose = verbose;
2374
2375 /* if the root message was retrieved, move to it */
2376 struct Email *e = mutt_hash_find(shared->mailbox->id_hash, buf);
2377 if (e)
2378 menu_set_index(priv->menu, e->vnum);
2379 else
2380 {
2381 /* try to restore old position */
2382 for (int i = 0; i < shared->mailbox->msg_count; i++)
2383 {
2384 e = shared->mailbox->emails[i];
2385 if (!e)
2386 break;
2387 if (e->index == oldindex)
2388 {
2389 menu_set_index(priv->menu, e->vnum);
2390 /* as an added courtesy, recenter the menu
2391 * with the current entry at the middle of the screen */
2393 }
2394 }
2395 }
2397 }
2398 else if (rc >= 0)
2399 {
2400 mutt_error(_("No deleted messages found in the thread"));
2401 }
2402
2403 return FR_SUCCESS;
2404}
2405
2413static int op_get_message(struct IndexSharedData *shared,
2414 struct IndexPrivateData *priv, int op)
2415{
2416 if (shared->mailbox->type != MUTT_NNTP)
2417 return FR_SUCCESS;
2418
2419 int rc = FR_ERROR;
2420 struct Buffer *buf = mutt_buffer_pool_get();
2421
2422 if (op == OP_GET_MESSAGE)
2423 {
2424 if ((mutt_buffer_get_field(_("Enter Message-Id: "), buf, MUTT_COMP_NO_FLAGS,
2425 false, NULL, NULL, NULL) != 0) ||
2427 {
2428 goto done;
2429 }
2430 }
2431 else
2432 {
2433 if (!shared->email || STAILQ_EMPTY(&shared->email->env->references))
2434 {
2435 mutt_error(_("Article has no parent reference"));
2436 goto done;
2437 }
2438 mutt_buffer_strcpy(buf, STAILQ_FIRST(&shared->email->env->references)->data);
2439 }
2440
2441 if (!shared->mailbox->id_hash)
2442 shared->mailbox->id_hash = mutt_make_id_hash(shared->mailbox);
2443 struct Email *e = mutt_hash_find(shared->mailbox->id_hash, mutt_buffer_string(buf));
2444 if (e)
2445 {
2446 if (e->vnum != -1)
2447 {
2448 menu_set_index(priv->menu, e->vnum);
2449 }
2450 else if (e->collapsed)
2451 {
2453 mutt_set_vnum(shared->mailbox);
2454 menu_set_index(priv->menu, e->vnum);
2455 }
2456 else
2457 {
2458 mutt_error(_("Message is not visible in limited view"));
2459 }
2460 }
2461 else
2462 {
2463 mutt_message(_("Fetching %s from server..."), mutt_buffer_string(buf));
2464 int rc2 = nntp_check_msgid(shared->mailbox, mutt_buffer_string(buf));
2465 if (rc2 == 0)
2466 {
2467 e = shared->mailbox->emails[shared->mailbox->msg_count - 1];
2468 mutt_sort_headers(shared->mailbox, shared->mailboxview->threads, false,
2469 &shared->mailboxview->vsize);
2470 menu_set_index(priv->menu, e->vnum);
2472 rc = FR_SUCCESS;
2473 }
2474 else if (rc2 > 0)
2475 {
2476 mutt_error(_("Article %s not found on the server"), mutt_buffer_string(buf));
2477 }
2478 }
2479
2480done:
2482 return rc;
2483}
2484
2492static int op_main_change_group(struct IndexSharedData *shared,
2493 struct IndexPrivateData *priv, int op)
2494{
2495 struct Buffer *folderbuf = mutt_buffer_pool_get();
2496 mutt_buffer_alloc(folderbuf, PATH_MAX);
2497
2498 OptNews = false;
2499 bool read_only;
2500 char *cp = NULL;
2501 const bool c_read_only = cs_subset_bool(shared->sub, "read_only");
2502 if (priv->attach_msg || c_read_only || (op == OP_MAIN_CHANGE_GROUP_READONLY))
2503 {
2504 cp = _("Open newsgroup in read-only mode");
2505 read_only = true;
2506 }
2507 else
2508 {
2509 cp = _("Open newsgroup");
2510 read_only = false;
2511 }
2512
2513 const bool c_change_folder_next = cs_subset_bool(shared->sub, "change_folder_next");
2514 if (c_change_folder_next && shared->mailbox &&
2516 {
2517 mutt_buffer_strcpy(folderbuf, mailbox_path(shared->mailbox));
2518 mutt_buffer_pretty_mailbox(folderbuf);
2519 }
2520
2521 OptNews = true;
2522 const char *const c_news_server = cs_subset_string(shared->sub, "news_server");
2523 CurrentNewsSrv = nntp_select_server(shared->mailbox, c_news_server, false);
2524 if (!CurrentNewsSrv)
2525 goto changefoldercleanup2;
2526
2527 nntp_mailbox(shared->mailbox, folderbuf->data, folderbuf->dsize);
2528
2529 if (mutt_buffer_enter_fname(cp, folderbuf, true, shared->mailbox, false, NULL,
2530 NULL, MUTT_SEL_NO_FLAGS) == -1)
2531 {
2532 goto changefoldercleanup2;
2533 }
2534
2535 /* Selected directory is okay, let's save it. */
2537
2538 if (mutt_buffer_is_empty(folderbuf))
2539 {
2541 goto changefoldercleanup2;
2542 }
2543
2544 struct Mailbox *m = mx_mbox_find2(mutt_buffer_string(folderbuf));
2545 if (m)
2546 {
2547 change_folder_mailbox(priv->menu, m, &priv->oldcount, shared, read_only);
2548 }
2549 else
2550 {
2551 change_folder_string(priv->menu, folderbuf->data, folderbuf->dsize,
2552 &priv->oldcount, shared, read_only);
2553 }
2554 struct MuttWindow *dlg = dialog_find(priv->win_index);
2555 dlg->help_data = IndexNewsHelp;
2556
2557changefoldercleanup2:
2558 mutt_buffer_pool_release(&folderbuf);
2559 return FR_SUCCESS;
2560}
2561
2569static int op_post(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
2570{
2571 if (!shared->email)
2572 return FR_NO_ACTION;
2573
2574 const enum QuadOption c_followup_to_poster = cs_subset_quad(shared->sub, "followup_to_poster");
2575 if ((op != OP_FOLLOWUP) || !shared->email->env->followup_to ||
2576 !mutt_istr_equal(shared->email->env->followup_to, "poster") ||
2577 (query_quadoption(c_followup_to_poster, _("Reply by mail as poster prefers?")) != MUTT_YES))
2578 {
2579 const enum QuadOption c_post_moderated = cs_subset_quad(shared->sub, "post_moderated");
2580 if (shared->mailbox && (shared->mailbox->type == MUTT_NNTP) &&
2581 !((struct NntpMboxData *) shared->mailbox->mdata)->allowed &&
2582 (query_quadoption(c_post_moderated, _("Posting to this group not allowed, may be moderated. Continue?")) !=
2583 MUTT_YES))
2584 {
2585 return FR_ERROR;
2586 }
2587 if (op == OP_POST)
2588 mutt_send_message(SEND_NEWS, NULL, NULL, shared->mailbox, NULL, shared->sub);
2589 else
2590 {
2591 struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
2592 el_add_tagged(&el, shared->mailboxview, shared->email, priv->tag);
2593 mutt_send_message(((op == OP_FOLLOWUP) ? SEND_REPLY : SEND_FORWARD) | SEND_NEWS,
2594 NULL, NULL, shared->mailbox, &el, shared->sub);
2595 emaillist_clear(&el);
2596 }
2598 return FR_SUCCESS;
2599 }
2600
2601 return op_reply(shared, priv, OP_REPLY);
2602}
2603#endif
2604
2605#ifdef USE_NOTMUCH
2609static int op_main_entire_thread(struct IndexSharedData *shared,
2610 struct IndexPrivateData *priv, int op)
2611{
2612 if (shared->mailbox->type != MUTT_NOTMUCH)
2613 {
2614 if (((shared->mailbox->type != MUTT_MH) && (shared->mailbox->type != MUTT_MAILDIR)) ||
2615 (!shared->email || !shared->email->env || !shared->email->env->message_id))
2616 {
2617 mutt_message(_("No virtual folder and no Message-Id, aborting"));
2618 return FR_ERROR;
2619 } // no virtual folder, but we have message-id, reconstruct thread on-the-fly
2620 char buf[PATH_MAX] = { 0 };
2621 strncpy(buf, "id:", sizeof(buf));
2622 int msg_id_offset = 0;
2623 if ((shared->email->env->message_id)[0] == '<')
2624 msg_id_offset = 1;
2625 mutt_str_cat(buf, sizeof(buf), (shared->email->env->message_id) + msg_id_offset);
2626 if (buf[strlen(buf) - 1] == '>')
2627 buf[strlen(buf) - 1] = '\0';
2628
2629 change_folder_notmuch(priv->menu, buf, sizeof(buf), &priv->oldcount, shared, false);
2630
2631 // If notmuch doesn't contain the message, we're left in an empty
2632 // vfolder. No messages are found, but nm_read_entire_thread assumes
2633 // a valid message-id and will throw a segfault.
2634 //
2635 // To prevent that, stay in the empty vfolder and print an error.
2636 if (shared->mailbox->msg_count == 0)
2637 {
2638 mutt_error(_("failed to find message in notmuch database. try running 'notmuch new'."));
2639 return FR_ERROR;
2640 }
2641 }
2642 priv->oldcount = shared->mailbox->msg_count;
2643 int index = menu_get_index(priv->menu);
2644 struct Email *e_oldcur = mutt_get_virt_email(shared->mailbox, index);
2645 if (nm_read_entire_thread(shared->mailbox, e_oldcur) < 0)
2646 {
2647 mutt_message(_("Failed to read thread, aborting"));
2648 return FR_ERROR;
2649 }
2650
2651 // nm_read_entire_thread() may modify msg_count and menu won't be updated.
2652 priv->menu->max = shared->mailbox->msg_count;
2653
2654 if (priv->oldcount < shared->mailbox->msg_count)
2655 {
2656 /* nm_read_entire_thread() triggers mutt_sort_headers() if necessary */
2657 index = e_oldcur->vnum;
2658 if (e_oldcur->collapsed || shared->mailboxview->collapsed)
2659 {
2660 index = mutt_uncollapse_thread(e_oldcur);
2661 mutt_set_vnum(shared->mailbox);
2662 }
2663 menu_set_index(priv->menu, index);
2665 }
2666
2667 return FR_SUCCESS;
2668}
2669
2678 struct IndexPrivateData *priv, int op)
2679{
2680 int rc = FR_SUCCESS;
2681 struct Buffer *buf = mutt_buffer_pool_get();
2682
2683 if ((mutt_buffer_get_field("Query: ", buf, MUTT_COMP_NM_QUERY, false, NULL, NULL, NULL) != 0) ||
2685 {
2686 mutt_message(_("No query, aborting"));
2687 rc = FR_NO_ACTION;
2688 goto done;
2689 }
2690
2691 // Keep copy of user's query to name the mailbox
2692 char *query_unencoded = mutt_buffer_strdup(buf);
2693
2695 struct Mailbox *m_query = change_folder_notmuch(priv->menu, buf->data, buf->dsize,
2696 &priv->oldcount, shared,
2697 (op == OP_MAIN_VFOLDER_FROM_QUERY_READONLY));
2698 if (m_query)
2699 {
2700 FREE(&m_query->name);
2701 m_query->name = query_unencoded;
2702 query_unencoded = NULL;
2703 rc = FR_SUCCESS;
2704 }
2705 else
2706 {
2707 FREE(&query_unencoded);
2708 }
2709
2710done:
2712 return rc;
2713}
2714
2724 struct IndexPrivateData *priv, int op)
2725{
2726 // Common guard clauses.
2728 {
2729 mutt_message(_("Windowed queries disabled"));
2730 return FR_ERROR;
2731 }
2732 const char *const c_nm_query_window_current_search = cs_subset_string(shared->sub, "nm_query_window_current_search");
2733 if (!c_nm_query_window_current_search)
2734 {
2735 mutt_message(_("No notmuch vfolder currently loaded"));
2736 return FR_ERROR;
2737 }
2738
2739 // Call the specific operation.
2740 switch (op)
2741 {
2742 case OP_MAIN_WINDOWED_VFOLDER_BACKWARD:
2744 break;
2745 case OP_MAIN_WINDOWED_VFOLDER_FORWARD:
2747 break;
2748 case OP_MAIN_WINDOWED_VFOLDER_RESET:
2750 break;
2751 }
2752
2753 // Common query window folder change.
2754 char buf[PATH_MAX] = { 0 };
2755 mutt_str_copy(buf, c_nm_query_window_current_search, sizeof(buf));
2756 change_folder_notmuch(priv->menu, buf, sizeof(buf), &priv->oldcount, shared, false);
2757
2758 return FR_SUCCESS;
2759}
2760#endif
2761
2762#ifdef USE_POP
2766static int op_main_fetch_mail(struct IndexSharedData *shared,
2767 struct IndexPrivateData *priv, int op)
2768{
2771 return FR_SUCCESS;
2772}
2773#endif
2774
2775// -----------------------------------------------------------------------------
2776
2784bool prereq(struct MailboxView *mv, struct Menu *menu, CheckFlags checks)
2785{
2786 bool result = true;
2787
2788 if (checks & (CHECK_MSGCOUNT | CHECK_VISIBLE | CHECK_READONLY))
2789 checks |= CHECK_IN_MAILBOX;
2790
2791 if ((checks & CHECK_IN_MAILBOX) && (!mv || !mv->mailbox))
2792 {
2793 mutt_error(_("No mailbox is open"));
2794 result = false;
2795 }
2796
2797 if (result && (checks & CHECK_MSGCOUNT) && (mv->mailbox->msg_count == 0))
2798 {
2799 mutt_error(_("There are no messages"));
2800 result = false;
2801 }
2802
2803 int index = menu_get_index(menu);
2804 if (result && (checks & CHECK_VISIBLE) && (index >= mv->mailbox->vcount))
2805 {
2806 mutt_error(_("No visible messages"));
2807 result = false;
2808 }
2809
2810 if (result && (checks & CHECK_READONLY) && mv->mailbox->readonly)
2811 {
2812 mutt_error(_("Mailbox is read-only"));
2813 result = false;
2814 }
2815
2816 if (result && (checks & CHECK_ATTACH) && OptAttachMsg)
2817 {
2818 mutt_error(_("Function not permitted in attach-message mode"));
2819 result = false;
2820 }
2821
2822 if (!result)
2823 mutt_flushinp();
2824
2825 return result;
2826}
2827
2832{
2833 if (!win)
2834 {
2836 return FR_ERROR;
2837 }
2838
2839 struct IndexPrivateData *priv = win->parent->wdata;
2840 if (!priv)
2841 return FR_ERROR;
2842
2843 struct MuttWindow *dlg = dialog_find(win);
2844 if (!dlg || !dlg->wdata)
2845 return FR_ERROR;
2846
2847 struct IndexSharedData *shared = dlg->wdata;
2848
2849 int rc = FR_UNKNOWN;
2850 for (size_t i = 0; IndexFunctions[i].op != OP_NULL; i++)
2851 {
2852 const struct IndexFunction *fn = &IndexFunctions[i];
2853 if (fn->op == op)
2854 {
2855 if (!prereq(shared->mailboxview, priv->menu, fn->flags))
2856 {
2857 rc = FR_ERROR;
2858 break;
2859 }
2860 rc = fn->function(shared, priv, op);
2861 break;
2862 }
2863 }
2864
2865 if (rc == FR_UNKNOWN) // Not our function
2866 return rc;
2867
2868 const char *result = dispacher_get_retval_name(rc);
2869 mutt_debug(LL_DEBUG1, "Handled %s (%d) -> %s\n", opcodes_get_name(op), op, NONULL(result));
2870
2871 return rc;
2872}
2873
2878 // clang-format off
2879 { OP_ALIAS_DIALOG, op_alias_dialog, CHECK_NO_FLAGS },
2884 { OP_COPY_MESSAGE, op_save, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
2885 { OP_CREATE_ALIAS, op_create_alias, CHECK_NO_FLAGS },
2886 { OP_DECODE_COPY, op_save, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
2887 { OP_DECODE_SAVE, op_save, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
2888 { OP_DECRYPT_COPY, op_save, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
2889 { OP_DECRYPT_SAVE, op_save, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
2897 { OP_EDIT_OR_VIEW_RAW_MESSAGE, op_edit_raw_message, CHECK_ATTACH | CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
2899 { OP_END_COND, op_end_cond, CHECK_NO_FLAGS },
2900 { OP_EXIT, op_exit, CHECK_NO_FLAGS },
2903 { OP_FORGET_PASSPHRASE, op_forget_passphrase, CHECK_NO_FLAGS },
2907 { OP_JUMP, op_jump, CHECK_IN_MAILBOX },
2908 { OP_JUMP_1, op_jump, CHECK_IN_MAILBOX },
2909 { OP_JUMP_2, op_jump, CHECK_IN_MAILBOX },
2910 { OP_JUMP_3, op_jump, CHECK_IN_MAILBOX },
2911 { OP_JUMP_4, op_jump, CHECK_IN_MAILBOX },
2912 { OP_JUMP_5, op_jump, CHECK_IN_MAILBOX },
2913 { OP_JUMP_6, op_jump, CHECK_IN_MAILBOX },
2914 { OP_JUMP_7, op_jump, CHECK_IN_MAILBOX },
2915 { OP_JUMP_8, op_jump, CHECK_IN_MAILBOX },
2916 { OP_JUMP_9, op_jump, CHECK_IN_MAILBOX },
2917 { OP_LIMIT_CURRENT_THREAD, op_main_limit, CHECK_IN_MAILBOX },
2921 { OP_MAIL, op_mail, CHECK_ATTACH },
2922 { OP_MAILBOX_LIST, op_mailbox_list, CHECK_NO_FLAGS },
2923 { OP_MAIL_KEY, op_mail_key, CHECK_ATTACH },
2925 { OP_MAIN_CHANGE_FOLDER, op_main_change_folder, CHECK_NO_FLAGS },
2926 { OP_MAIN_CHANGE_FOLDER_READONLY, op_main_change_folder, CHECK_NO_FLAGS },
2928 { OP_MAIN_COLLAPSE_ALL, op_main_collapse_all, CHECK_IN_MAILBOX },
2929 { OP_MAIN_COLLAPSE_THREAD, op_main_collapse_thread, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
2930 { OP_MAIN_DELETE_PATTERN, op_main_delete_pattern, CHECK_ATTACH | CHECK_IN_MAILBOX | CHECK_READONLY },
2931 { OP_MAIN_LIMIT, op_main_limit, CHECK_IN_MAILBOX },
2934 { OP_MAIN_MODIFY_TAGS_THEN_HIDE, op_main_modify_tags, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_READONLY | CHECK_VISIBLE },
2936 { OP_MAIN_NEXT_NEW_THEN_UNREAD, op_main_next_new, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
2937 { OP_MAIN_NEXT_SUBTHREAD, op_main_next_thread, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
2940 { OP_MAIN_NEXT_UNREAD, op_main_next_new, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
2941 { OP_MAIN_NEXT_UNREAD_MAILBOX, op_main_next_unread_mailbox, CHECK_IN_MAILBOX },
2942 { OP_MAIN_PARENT_MESSAGE, op_main_root_message, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
2944 { OP_MAIN_PREV_NEW_THEN_UNREAD, op_main_next_new, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
2945 { OP_MAIN_PREV_SUBTHREAD, op_main_next_thread, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
2948 { OP_MAIN_PREV_UNREAD, op_main_next_new, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
2954 { OP_MAIN_SHOW_LIMIT, op_main_show_limit, CHECK_IN_MAILBOX },
2955 { OP_MAIN_SYNC_FOLDER, op_main_sync_folder, CHECK_NO_FLAGS },
2956 { OP_MAIN_TAG_PATTERN, op_main_tag_pattern, CHECK_IN_MAILBOX },
2957 { OP_MAIN_UNDELETE_PATTERN, op_main_undelete_pattern, CHECK_IN_MAILBOX | CHECK_READONLY },
2958 { OP_MAIN_UNTAG_PATTERN, op_main_untag_pattern, CHECK_IN_MAILBOX },
2966 { OP_QUERY, op_query, CHECK_ATTACH },
2967 { OP_QUIT, op_quit, CHECK_NO_FLAGS },
2968 { OP_RECALL_MESSAGE, op_recall_message, CHECK_ATTACH },
2972 { OP_SEARCH, op_search, CHECK_IN_MAILBOX },
2973 { OP_SEARCH_NEXT, op_search, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
2974 { OP_SEARCH_OPPOSITE, op_search, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
2975 { OP_SEARCH_REVERSE, op_search, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
2976 { OP_SORT, op_sort, CHECK_NO_FLAGS },
2977 { OP_SORT_REVERSE, op_sort, CHECK_NO_FLAGS },
2982 { OP_TOGGLE_READ, op_main_limit, CHECK_IN_MAILBOX },
2983 { OP_TOGGLE_WRITE, op_toggle_write, CHECK_IN_MAILBOX },
2989#ifdef USE_AUTOCRYPT
2990 { OP_AUTOCRYPT_ACCT_MENU, op_autocrypt_acct_menu, CHECK_NO_FLAGS },
2991#endif
2992#ifdef USE_IMAP
2993 { OP_MAIN_IMAP_FETCH, op_main_imap_fetch, CHECK_NO_FLAGS },
2994 { OP_MAIN_IMAP_LOGOUT_ALL, op_main_imap_logout_all, CHECK_NO_FLAGS },
2995#endif
2996#ifdef USE_NNTP
2999 { OP_FORWARD_TO_GROUP, op_post, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3003 { OP_MAIN_CHANGE_GROUP, op_main_change_group, CHECK_NO_FLAGS },
3004 { OP_MAIN_CHANGE_GROUP_READONLY, op_main_change_group, CHECK_NO_FLAGS },
3005 { OP_POST, op_post, CHECK_ATTACH | CHECK_IN_MAILBOX },
3007#endif
3008#ifdef USE_NOTMUCH
3009 { OP_MAIN_CHANGE_VFOLDER, op_main_change_folder, CHECK_NO_FLAGS },
3011 { OP_MAIN_VFOLDER_FROM_QUERY, op_main_vfolder_from_query, CHECK_NO_FLAGS },
3012 { OP_MAIN_VFOLDER_FROM_QUERY_READONLY, op_main_vfolder_from_query, CHECK_NO_FLAGS },
3013 { OP_MAIN_WINDOWED_VFOLDER_BACKWARD, op_main_windowed_vfolder, CHECK_IN_MAILBOX },
3014 { OP_MAIN_WINDOWED_VFOLDER_FORWARD, op_main_windowed_vfolder, CHECK_IN_MAILBOX },
3015 { OP_MAIN_WINDOWED_VFOLDER_RESET, op_main_windowed_vfolder, CHECK_IN_MAILBOX },
3016#endif
3017#ifdef USE_POP
3018 { OP_MAIN_FETCH_MAIL, op_main_fetch_mail, CHECK_ATTACH },
3019#endif
3020 { 0, NULL, CHECK_NO_FLAGS },
3021 // clang-format on
3022};
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
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:55
void mutt_browser_select_dir(const char *f)
Remember the last directory selected.
Definition: browser.c:1068
void mutt_buffer_alloc(struct Buffer *buf, size_t new_size)
Make sure a buffer can store at least new_size bytes.
Definition: buffer.c:275
bool mutt_buffer_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:260
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:327
int mutt_buffer_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:168
char * mutt_buffer_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition: buffer.c:447
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:77
bool mutt_select_sort(bool reverse)
Ask the user for a sort method.
Definition: commands.c:495
void mutt_print_message(struct Mailbox *m, struct EmailList *el)
Print a message.
Definition: commands.c:453
int mutt_save_message(struct Mailbox *m, struct EmailList *el, enum MessageSaveOpt save_opt, enum MessageTransformOpt transform_opt)
Save an email.
Definition: commands.c:813
void ci_bounce_message(struct Mailbox *m, struct EmailList *el)
Bounce an email.
Definition: commands.c:91
bool mutt_edit_content_type(struct Email *e, struct Body *b, FILE *fp)
Edit the content type of an attachment.
Definition: commands.c:1105
bool mutt_check_traditional_pgp(struct Mailbox *m, struct EmailList *el)
Check if a message has inline PGP content.
Definition: commands.c:1247
void mutt_pipe_message(struct Mailbox *m, struct EmailList *el)
Pipe a message.
Definition: commands.c:422
void mutt_display_address(struct Envelope *env)
Display the address of a message.
Definition: commands.c:696
Manage where the email is piped to external commands.
MessageTransformOpt
Message transformation option.
Definition: commands.h:39
@ TRANSFORM_NONE
No transformation.
Definition: commands.h:40
@ TRANSFORM_DECODE
Decode message.
Definition: commands.h:42
@ TRANSFORM_DECRYPT
Decrypt message.
Definition: commands.h:41
MessageSaveOpt
Message save option.
Definition: commands.h:49
@ SAVE_MOVE
Move message to another mailbox, removing the original.
Definition: commands.h:51
@ SAVE_COPY
Copy message, making a duplicate in another mailbox.
Definition: commands.h:50
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
enum QuadOption cs_subset_quad(const struct ConfigSubset *sub, const char *name)
Get a quad-value config item by name.
Definition: helpers.c:218
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
Convenience wrapper for the config headers.
Convenience wrapper for the core headers.
void crypt_forget_passphrase(void)
Forget a passphrase and display a message.
Definition: crypt.c:92
void crypt_extract_keys_from_messages(struct Mailbox *m, struct EmailList *el)
Extract keys from a message.
Definition: crypt.c:838
int digit(const char *s)
void mutt_flushinp(void)
Empty all the keyboard buffers.
Definition: curs_lib.c:592
int mutt_buffer_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:445
void mutt_unget_ch(int ch)
Return a keystroke to the input buffer.
Definition: curs_lib.c:521
struct MuttWindow * dialog_find(struct MuttWindow *win)
Find the parent Dialog of a Window.
Definition: dialog.c:83
const char * dispacher_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:498
void dlg_select_attachment(struct ConfigSubset *sub, struct Mailbox *m, struct Email *e, FILE *fp)
Show the attachments in a Menu.
Definition: dlg_attach.c:449
void dlg_select_autocrypt_account(void)
Display the Autocrypt account Menu.
bool check_acl(struct Mailbox *m, AclFlags acl, const char *msg)
Check the ACLs for a function.
Definition: dlg_index.c:143
const struct Mapping IndexNewsHelp[]
Help Bar for the News Index dialog.
Definition: dlg_index.c:121
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:613
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:736
int ci_next_undeleted(struct Mailbox *m, int msgno, bool uncollapse)
Find the next undeleted email.
Definition: dlg_index.c:242
int ci_previous_undeleted(struct Mailbox *m, int msgno, bool uncollapse)
Find the previous undeleted email.
Definition: dlg_index.c:275
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:531
void change_folder_string(struct Menu *menu, char *buf, size_t buflen, int *oldcount, struct IndexSharedData *shared, bool read_only)
Change to a different Mailbox by string.
Definition: dlg_index.c:760
void resort_index(struct MailboxView *mv, struct Menu *menu)
Resort the index.
Definition: dlg_index.c:364
int ci_first_message(struct Mailbox *m)
Get index of first new message.
Definition: dlg_index.c:308
void collapse_all(struct MailboxView *mv, struct Menu *menu, int toggle)
Collapse/uncollapse all threads.
Definition: dlg_index.c:170
void query_index(struct Mailbox *m, struct ConfigSubset *sub)
Perform an Alias Query and display the results.
Definition: dlg_query.c:532
int mutt_ev_message(struct Mailbox *m, struct EmailList *el, enum EvMessage action)
Edit or view a message.
Definition: editmsg.c:277
void emaillist_clear(struct EmailList *el)
Drop a private list of Emails.
Definition: email.c:138
Structs that make up an email.
Enter a string.
int mutt_buffer_get_field(const char *field, struct Buffer *buf, CompletionFlags complete, bool multiple, struct Mailbox *m, char ***files, int *numfiles)
Ask the user for a string.
Definition: window.c:180
int mutt_file_sanitize_regex(struct Buffer *dest, const char *src)
Escape any regex-magic characters in a string.
Definition: file.c:666
void mutt_emails_set_flag(struct Mailbox *m, struct EmailList *el, enum MessageType flag, bool bf)
Set flag on messages.
Definition: flags.c:355
int mutt_change_flag(struct Mailbox *m, struct EmailList *el, bool bf)
Change the flag on a Message.
Definition: flags.c:437
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:378
int index_function_dispatcher(struct MuttWindow *win, int op)
Perform an Index function - Implements function_dispatcher_t -.
Definition: functions.c:2831
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:1042
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:790
static int op_main_limit(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Limit view to current thread - Implements index_function_t -.
Definition: functions.c:978
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:1531
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:954
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:2096
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:777
static int op_display_message(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Display a message - Implements index_function_t -.
Definition: functions.c:372
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:1376
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:2766
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:715
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:320
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:1409
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:1782
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:1432
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:1805
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:1766
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:1092
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:1593
static int op_autocrypt_acct_menu(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Manage autocrypt accounts - Implements index_function_t -.
Definition: functions.c:2239
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:514
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:474
static int op_search(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Search for a regular expression - Implements index_function_t -.
Definition: functions.c:2004
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:2413
static int op_list_subscribe(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Subscribe to a mailing list - Implements index_function_t -.
Definition: functions.c:738
static int op_extract_keys(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Extract supported public keys - Implements index_function_t -.
Definition: functions.c:544
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:1210
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:2492
static int op_delete(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Delete the current entry - Implements index_function_t -.
Definition: functions.c:284
static int op_view_attachments(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Show MIME attachments - Implements index_function_t -.
Definition: functions.c:2211
static int op_sort(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Sort messages - Implements index_function_t -.
Definition: functions.c:2024
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:2677
static int op_reply(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Reply to a message - Implements index_function_t -.
Definition: functions.c:1902
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:561
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:2264
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:1501
static int op_recall_message(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Recall a postponed message - Implements index_function_t -.
Definition: functions.c:1890
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:2317
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:2138
static int op_save(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Make decrypted copy - Implements index_function_t -.
Definition: functions.c:1960
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:2180
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:1665
static int op_resend(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Use the current message as a template for a new one - Implements index_function_t -.
Definition: functions.c:1925
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:1699
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:439
static int op_bounce_message(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Remail a message to another user - Implements index_function_t -.
Definition: functions.c:212
static int op_compose_to_sender(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Compose new message to the current message sender - Implements index_function_t -.
Definition: functions.c:249
static int op_forward_message(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Forward a message with comments - Implements index_function_t -.
Definition: functions.c:607
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:2609
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:355
static int op_post(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Followup to newsgroup - Implements index_function_t -.
Definition: functions.c:2569
static int op_tag(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Tag the current entry - Implements index_function_t -.
Definition: functions.c:2041
static int op_tag_thread(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Tag the current thread - Implements index_function_t -.
Definition: functions.c:2075
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:914
static int op_attachment_edit_type(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Edit attachment content type - Implements index_function_t -.
Definition: functions.c:198
static int op_alias_dialog(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Open the aliases dialog - Implements index_function_t -.
Definition: functions.c:188
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:2251
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:1465
static int op_list_unsubscribe(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Unsubscribe from mailing list - Implements index_function_t -.
Definition: functions.c:747
static int op_undelete(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Undelete the current entry - Implements index_function_t -.
Definition: functions.c:2148
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:898
static int op_exit(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Exit this menu - Implements index_function_t -.
Definition: functions.c:522
static int op_jump(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Jump to an index number - Implements index_function_t -.
Definition: functions.c:664
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:1677
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:1711
static int op_check_traditional(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Check for classic PGP - Implements index_function_t -.
Definition: functions.c:226
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:2723
static int op_mailbox_list(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
List mailboxes with new mail - Implements index_function_t -.
Definition: functions.c:767
static int op_query(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Query external program for addresses - Implements index_function_t -.
Definition: functions.c:1844
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:1548
static int op_forget_passphrase(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Wipe passphrases from memory - Implements index_function_t -.
Definition: functions.c:597
static int op_catchup(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Mark all articles in newsgroup as read - Implements index_function_t -.
Definition: functions.c:2298
static int op_quit(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Save changes to mailbox and quit - Implements index_function_t -.
Definition: functions.c:1853
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:1334
static int op_group_reply(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Reply to all recipients - Implements index_function_t -.
Definition: functions.c:635
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:1574
static int op_create_alias(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Create an alias from a message sender - Implements index_function_t -.
Definition: functions.c:265
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:832
static int op_mail(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Compose a new mail message - Implements index_function_t -.
Definition: functions.c:756
static int op_print(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Print the current entry - Implements index_function_t -.
Definition: functions.c:1821
#define mutt_warning(...)
Definition: logging.h:85
#define mutt_error(...)
Definition: logging.h:87
#define mutt_message(...)
Definition: logging.h:86
#define mutt_debug(LEVEL,...)
Definition: logging.h:84
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
void mutt_startup_shutdown_hook(HookFlags type)
Execute any startup/shutdown hooks.
Definition: hook.c:924
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:562
enum MxStatus imap_check_mailbox(struct Mailbox *m, bool force)
Use the NOOP or IDLE command to poll for new mail.
Definition: imap.c:1106
static const char * Not_available_in_this_menu
Definition: functions.c:88
bool index_next_undeleted(struct MuttWindow *win_index)
Select the next undeleted Email (if possible)
Definition: functions.c:157
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:108
struct IndexFunction IndexFunctions[]
All the NeoMutt functions that the Index supports.
Definition: functions.c:2877
bool prereq(struct MailboxView *mv, struct Menu *menu, CheckFlags checks)
Check the pre-requisites for a function.
Definition: functions.c:2784
ResolveMethod
How to advance the cursor.
Definition: functions.c:94
@ RESOLVE_NEXT_SUBTHREAD
Next sibling sub-thread.
Definition: functions.c:98
@ RESOLVE_NEXT_UNDELETED
Next undeleted email.
Definition: functions.c:96
@ RESOLVE_NEXT_EMAIL
Next email, whatever its state.
Definition: functions.c:95
@ RESOLVE_NEXT_THREAD
Next top-level thread.
Definition: functions.c:97
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
int mx_toggle_write(struct Mailbox *m)
Toggle the mailbox's readonly flag.
Definition: mx.c:1848
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:230
Data shared between Index, Pager and Sidebar.
enum CommandResult km_bind(char *s, enum MenuType mtype, int op, char *macro, char *desc)
Bind a key to a macro.
Definition: keymap.c:458
Manage keymappings.
@ LL_DEBUG1
Log at debug level 1.
Definition: logging.h:40
@ LL_NOTIFY
Log of notifications.
Definition: logging.h:45
void mailbox_free(struct Mailbox **ptr)
Free a Mailbox.
Definition: mailbox.c:87
#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:43
GUI present the user with a selectable list.
#define MENU_REDRAW_FULL
Redraw everything.
Definition: lib.h:59
#define MENU_REDRAW_INDEX
Redraw the index.
Definition: lib.h:56
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:178
int menu_get_index(struct Menu *menu)
Get the current selection in the Menu.
Definition: menu.c:154
#define MENU_REDRAW_CURRENT
Redraw the current line of the menu.
Definition: lib.h:58
MenuRedrawFlags menu_set_index(struct Menu *menu, int index)
Set the current selection in the Menu.
Definition: menu.c:168
void msgwin_clear_text(void)
Clear the text in the Message Window.
Definition: msgwin.c:249
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:171
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:819
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:807
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:496
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:652
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:326
char * mutt_str_cat(char *buf, size_t buflen, const char *s)
Concatenate two strings.
Definition: string.c:265
Many unsorted constants and some structs.
#define MUTT_COMP_NO_FLAGS
No flags are set.
Definition: mutt.h:52
@ MUTT_UNDELETE
Messages to be un-deleted.
Definition: mutt.h:96
@ MUTT_LIMIT
Messages in limited view.
Definition: mutt.h:102
@ MUTT_UNTAG
Messages to be un-tagged.
Definition: mutt.h:101
@ MUTT_READ
Messages that have been read.
Definition: mutt.h:93
@ MUTT_PURGE
Messages to be purged (bypass trash)
Definition: mutt.h:97
@ MUTT_TAG
Tagged messages.
Definition: mutt.h:100
@ MUTT_FLAG
Flagged messages.
Definition: mutt.h:99
@ MUTT_DELETE
Messages to be deleted.
Definition: mutt.h:95
@ MUTT_NEW
New messages.
Definition: mutt.h:90
#define MUTT_COMP_NM_QUERY
Notmuch query mode.
Definition: mutt.h:59
#define PATH_MAX
Definition: mutt.h:40
int mutt_label_message(struct Mailbox *m, struct EmailList *el)
Let the user label a message.
Definition: mutt_header.c:124
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:404
struct Mailbox * mutt_mailbox_next(struct Mailbox *m_cur, struct Buffer *s)
Incoming folders completion routine.
Definition: mutt_mailbox.c:378
bool mutt_mailbox_list(void)
List the mailboxes with new mail.
Definition: mutt_mailbox.c:243
Mailbox helper functions.
void mutt_draw_tree(struct ThreadsContext *tctx)
Draw a tree of threaded emails.
Definition: mutt_thread.c:384
int mutt_messages_in_thread(struct Mailbox *m, struct Email *e, enum MessageInThread mit)
Count the messages in a thread.
Definition: mutt_thread.c:1608
bool mutt_link_threads(struct Email *parent, struct EmailList *children, struct Mailbox *m)
Forcibly link threads together.
Definition: mutt_thread.c:1696
off_t mutt_set_vnum(struct Mailbox *m)
Set the virtual index number of all the messages in a mailbox.
Definition: mutt_thread.c:1363
bool mutt_thread_can_collapse(struct Email *e)
Check whether a thread can be collapsed.
Definition: mutt_thread.c:1765
int mutt_parent_message(struct Email *e, bool find_root)
Find the parent of a message.
Definition: mutt_thread.c:1313
struct HashTable * mutt_make_id_hash(struct Mailbox *m)
Create a Hash Table for message-ids.
Definition: mutt_thread.c:1651
Create/manipulate threading in emails.
#define mutt_thread_next_unread(e)
Definition: mutt_thread.h:97
#define mutt_using_threads()
Definition: mutt_thread.h:100
#define mutt_previous_thread(e)
Definition: mutt_thread.h:107
#define mutt_uncollapse_thread(e)
Definition: mutt_thread.h:94
@ MIT_POSITION
Our position in the thread.
Definition: mutt_thread.h:76
#define mutt_next_subthread(e)
Definition: mutt_thread.h:108
#define mutt_thread_contains_unread(e)
Definition: mutt_thread.h:95
#define mutt_previous_subthread(e)
Definition: mutt_thread.h:109
#define mutt_next_thread(e)
Definition: mutt_thread.h:106
#define mutt_collapse_thread(e)
Definition: mutt_thread.h:93
bool window_is_focused(const struct MuttWindow *win)
Does the given Window have the focus?
Definition: mutt_window.c:629
struct MuttWindow * window_set_focus(struct MuttWindow *win)
Set the Window focus.
Definition: mutt_window.c:659
void mutt_buffer_pretty_mailbox(struct Buffer *buf)
Shorten a mailbox path using '~' or '='.
Definition: muttlib.c:599
Some miscellaneous functions.
int el_add_tagged(struct EmailList *el, struct MailboxView *mv, struct Email *e, bool use_tagged)
Get a list of the tagged Emails.
Definition: mview.c:366
struct Email * mutt_get_virt_email(struct Mailbox *m, int vnum)
Get a virtual Email.
Definition: mview.c:414
void mview_free(struct MailboxView **ptr)
Free a MailboxView.
Definition: mview.c:49
bool message_is_tagged(struct Email *e)
Is a message in the index tagged (and within limit)
Definition: mview.c:352
bool mview_has_limit(const struct MailboxView *mv)
Is a limit active?
Definition: mview.c:435
The "currently-open" mailbox.
int mx_tags_edit(struct Mailbox *m, const char *tags, struct Buffer *buf)
Start the tag editor of the mailbox.
Definition: mx.c:1280
int mx_msg_close(struct Mailbox *m, struct Message **msg)
Close a message.
Definition: mx.c:1193
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:1649
bool mx_tags_is_supported(struct Mailbox *m)
Return true if mailbox support tagging.
Definition: mx.c:1317
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:1300
struct Message * mx_msg_open(struct Mailbox *m, int msgno)
Return a stream pointer for a message.
Definition: mx.c:1147
enum MxStatus mx_mbox_sync(struct Mailbox *m)
Save changes to mailbox.
Definition: mx.c:919
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:84
@ MX_STATUS_OK
No changes.
Definition: mxapi.h:86
@ MX_STATUS_REOPENED
Mailbox was reopened.
Definition: mxapi.h:89
@ MX_STATUS_NEW_MAIL
New mail received in Mailbox.
Definition: mxapi.h:87
API for encryption/signing of emails.
#define PGP_TRADITIONAL_CHECKED
Email has a traditional (inline) signature.
Definition: lib.h:92
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: lib.h:90
#define WithCrypto
Definition: lib.h:116
@ NT_GLOBAL_SHUTDOWN
NeoMutt is about to close.
Definition: neomutt.h:53
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:2133
int nntp_check_children(struct Mailbox *m, const char *msgid)
Fetch children of article with the Message-ID.
Definition: nntp.c:2203
void nntp_mailbox(struct Mailbox *m, char *buf, size_t buflen)
Get first newsgroup with new messages.
Definition: newsrc.c:1405
struct NntpMboxData * mutt_newsgroup_catchup(struct Mailbox *m, struct NntpAccountData *adata, char *group)
Catchup newsgroup.
Definition: newsrc.c:1323
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:1019
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
void nm_db_longrun_done(struct Mailbox *m)
Finish a long transaction.
Definition: db.c:368
void nm_db_longrun_init(struct Mailbox *m, bool writable)
Start a long transaction.
Definition: db.c:353
Notmuch virtual mailbox type.
void nm_query_window_reset(void)
Resets the vfolder window position to the present.
Definition: notmuch.c:1662
int nm_read_entire_thread(struct Mailbox *m, struct Email *e)
Get the entire thread of an email.
Definition: notmuch.c:1488
void nm_query_window_backward(void)
Function to move the current search window backward in time.
Definition: notmuch.c:1651
bool nm_query_window_available(void)
Are windowed queries enabled for use?
Definition: notmuch.c:1614
bool nm_message_is_still_queried(struct Mailbox *m, struct Email *e)
Is a message still visible in the query?
Definition: notmuch.c:1674
void nm_query_window_forward(void)
Function to move the current search window forward in time.
Definition: notmuch.c:1631
const char * opcodes_get_name(int op)
Get the name of an opcode.
Definition: opcodes.c:46
All user-callable functions.
Handling of global boolean variables.
bool OptNews
(pseudo) used to change reader mode
Definition: options.h:50
bool OptAttachMsg
(pseudo) used by attach-message
Definition: options.h:37
bool OptSearchInvalid
(pseudo) used to invalidate the search pattern
Definition: options.h:57
bool OptNeedResort
(pseudo) used to force a re-sort
Definition: options.h:48
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:449
int external_pager(struct Mailbox *m, 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.
bool mutt_limit_current_thread(struct MailboxView *mv, struct Email *e)
Limit the email view to the current thread.
Definition: pattern.c:195
int mutt_pattern_func(struct MailboxView *mv, int op, char *prompt)
Perform some Pattern matching.
Definition: pattern.c:343
int mutt_search_command(struct Mailbox *m, struct Menu *menu, int cur, int op)
Perform a search.
Definition: pattern.c:492
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
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:86
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:118
Prototypes for many functions.
@ EVM_VIEW
View the message.
Definition: protos.h:52
@ EVM_EDIT
Edit the message.
Definition: protos.h:53
#define mutt_set_flag(m, e, flag, bf)
Definition: protos.h:63
QuadOption
Possible values for a quad-option.
Definition: quad.h:36
@ MUTT_YES
User answered 'Yes', or assume 'Yes'.
Definition: quad.h:39
Ask the user a question.
enum QuadOption query_quadoption(enum QuadOption opt, const char *prompt)
Ask the user a quad-question.
Definition: question.c:386
#define STAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:324
#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
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:1638
int mutt_send_message(SendFlags flags, struct Email *e_templ, const char *tempfile, struct Mailbox *m, struct EmailList *el, struct ConfigSubset *sub)
Send an email.
Definition: send.c:2126
bool mutt_send_list_unsubscribe(struct Mailbox *m, struct Email *e)
Send a mailing-list unsubscription email.
Definition: send.c:3064
bool mutt_send_list_subscribe(struct Mailbox *m, struct Email *e)
Send a mailing-list subscription email.
Definition: send.c:3035
#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 Mailbox *m, struct ThreadsContext *threads, bool init, off_t *vsize)
Sort emails by their headers.
Definition: sort.c:356
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:121
struct Envelope * env
Envelope information.
Definition: email.h:66
bool collapsed
Is this message part of a collapsed thread?
Definition: email.h:120
SecurityFlags security
bit 0-10: flags, bit 11,12: application, bit 13: traditional pgp See: ncrypt/lib.h pgplib....
Definition: email.h:41
struct Body * body
List of MIME parts.
Definition: email.h:67
bool old
Email is seen, but unread.
Definition: email.h:47
struct AttrColor * attr_color
Color-pair to use when displaying in the index.
Definition: email.h:112
bool attach_del
Has an attachment marked for deletion.
Definition: email.h:99
bool flagged
Marked important?
Definition: email.h:45
bool threaded
Used for threading.
Definition: email.h:108
int vnum
Virtual message number.
Definition: email.h:114
struct TagList tags
For drivers that support server tagging.
Definition: email.h:70
int msgno
Number displayed to the user.
Definition: email.h:111
bool deleted
Email is deleted.
Definition: email.h:76
int index
The absolute (unsorted) message number.
Definition: email.h:110
bool quasi_deleted
Deleted from neomutt, but not modified on disk.
Definition: email.h:103
bool tagged
Email is tagged.
Definition: email.h:107
char * followup_to
List of 'followup-to' fields.
Definition: envelope.h: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:44
struct IndexSharedData * shared
Shared Index data.
Definition: private_data.h:42
bool attach_msg
Are we in "attach message" mode?
Definition: private_data.h:40
bool tag
tag-prefix has been pressed
Definition: private_data.h:36
struct Menu * menu
Menu controlling the index.
Definition: private_data.h:43
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 MailboxView * mailboxview
Current Mailbox view.
Definition: shared_data.h:39
struct Email * email
Currently selected Email.
Definition: shared_data.h:42
struct Mailbox * mailbox
Current Mailbox.
Definition: shared_data.h:41
struct ConfigSubset * sub
Config set to use.
Definition: shared_data.h:38
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
The "current" mailbox.
Definition: mview.h:38
bool collapsed
Are all threads collapsed?
Definition: mview.h:47
off_t vsize
Size (in bytes) of the messages shown.
Definition: mview.h:39
struct ThreadsContext * threads
Threads context.
Definition: mview.h:42
struct Mailbox * mailbox
Current Mailbox.
Definition: mview.h:49
char * pattern
Limit pattern string.
Definition: mview.h:40
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:110
int msg_count
Total number of messages.
Definition: mailbox.h:88
AclFlags rights
ACL bits, see AclFlags.
Definition: mailbox.h:117
enum MailboxType type
Mailbox type.
Definition: mailbox.h:102
void * mdata
Driver specific data.
Definition: mailbox.h:132
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 by msg id.
Definition: mailbox.h:123
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:114
Definition: lib.h:69
int max
Number of entries in the menu.
Definition: lib.h:71
A local copy of an email.
Definition: mxapi.h:43
FILE * fp
pointer to the message data
Definition: mxapi.h:44
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:37
struct Notify * notify
Notifications handler.
Definition: neomutt.h:38
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
NNTP-specific Mailbox data -.
Definition: mdata.h:33
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:233
@ MENU_INDEX
Index panel (list of emails)
Definition: type.h:50