NeoMutt  2024-03-23-147-g885fbc
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
functions.c
Go to the documentation of this file.
1
31#include "config.h"
32#ifdef _MAKEDOC
33#include "docs/makedoc_defs.h"
34#else
35#include <limits.h>
36#include <stdbool.h>
37#include <stdio.h>
38#include <string.h>
39#include "mutt/lib.h"
40#include "config/lib.h"
41#include "email/lib.h"
42#include "core/lib.h"
43#include "alias/lib.h"
44#include "gui/lib.h"
45#include "mutt.h"
46#include "lib.h"
47#include "attach/lib.h"
48#include "browser/lib.h"
49#include "editor/lib.h"
50#include "history/lib.h"
51#include "imap/lib.h"
52#include "key/lib.h"
53#include "menu/lib.h"
54#include "ncrypt/lib.h"
55#include "nntp/lib.h"
56#include "pager/lib.h"
57#include "pattern/lib.h"
58#include "pop/lib.h"
59#include "progress/lib.h"
60#include "question/lib.h"
61#include "send/lib.h"
62#include "external.h"
63#include "functions.h"
64#include "globals.h"
65#include "hook.h"
66#include "mutt_header.h"
67#include "mutt_mailbox.h"
68#include "mutt_thread.h"
69#include "muttlib.h"
70#include "mview.h"
71#include "mx.h"
72#include "nntp/mdata.h"
73#include "private_data.h"
74#include "protos.h"
75#include "shared_data.h"
76#include "sort.h"
77#ifdef USE_AUTOCRYPT
78#include "autocrypt/lib.h"
79#endif
80#ifdef USE_NOTMUCH
81#include "notmuch/lib.h"
82#endif
83#ifdef ENABLE_NLS
84#include <libintl.h>
85#endif
86#endif
87
89static const char *Not_available_in_this_menu = N_("Not available in this menu");
90
91// clang-format off
95const struct MenuFuncOp OpIndex[] = { /* map: index */
96 { "alias-dialog", OP_ALIAS_DIALOG },
97#ifdef USE_AUTOCRYPT
98 { "autocrypt-acct-menu", OP_AUTOCRYPT_ACCT_MENU },
99#endif
100 { "bounce-message", OP_BOUNCE_MESSAGE },
101 { "break-thread", OP_MAIN_BREAK_THREAD },
102 { "catchup", OP_CATCHUP },
103 { "change-folder", OP_MAIN_CHANGE_FOLDER },
104 { "change-folder-readonly", OP_MAIN_CHANGE_FOLDER_READONLY },
105 { "change-newsgroup", OP_MAIN_CHANGE_GROUP },
106 { "change-newsgroup-readonly", OP_MAIN_CHANGE_GROUP_READONLY },
107#ifdef USE_NOTMUCH
108 { "change-vfolder", OP_MAIN_CHANGE_VFOLDER },
109#endif
110 { "check-traditional-pgp", OP_CHECK_TRADITIONAL },
111 { "clear-flag", OP_MAIN_CLEAR_FLAG },
112 { "collapse-all", OP_MAIN_COLLAPSE_ALL },
113 { "collapse-thread", OP_MAIN_COLLAPSE_THREAD },
114 { "compose-to-sender", OP_COMPOSE_TO_SENDER },
115 { "copy-message", OP_COPY_MESSAGE },
116 { "create-alias", OP_CREATE_ALIAS },
117 { "decode-copy", OP_DECODE_COPY },
118 { "decode-save", OP_DECODE_SAVE },
119 { "decrypt-copy", OP_DECRYPT_COPY },
120 { "decrypt-save", OP_DECRYPT_SAVE },
121 { "delete-message", OP_DELETE },
122 { "delete-pattern", OP_MAIN_DELETE_PATTERN },
123 { "delete-subthread", OP_DELETE_SUBTHREAD },
124 { "delete-thread", OP_DELETE_THREAD },
125 { "display-address", OP_DISPLAY_ADDRESS },
126 { "display-message", OP_DISPLAY_MESSAGE },
127 { "display-toggle-weed", OP_DISPLAY_HEADERS },
128 { "edit", OP_EDIT_RAW_MESSAGE },
129 { "edit-label", OP_EDIT_LABEL },
130 { "edit-or-view-raw-message", OP_EDIT_OR_VIEW_RAW_MESSAGE },
131 { "edit-raw-message", OP_EDIT_RAW_MESSAGE },
132 { "edit-type", OP_ATTACHMENT_EDIT_TYPE },
133#ifdef USE_NOTMUCH
134 { "entire-thread", OP_MAIN_ENTIRE_THREAD },
135#endif
136 { "exit", OP_EXIT },
137 { "extract-keys", OP_EXTRACT_KEYS },
138 { "fetch-mail", OP_MAIN_FETCH_MAIL },
139 { "flag-message", OP_FLAG_MESSAGE },
140 { "followup-message", OP_FOLLOWUP },
141 { "forget-passphrase", OP_FORGET_PASSPHRASE },
142 { "forward-message", OP_FORWARD_MESSAGE },
143 { "forward-to-group", OP_FORWARD_TO_GROUP },
144 { "get-children", OP_GET_CHILDREN },
145 { "get-message", OP_GET_MESSAGE },
146 { "get-parent", OP_GET_PARENT },
147 { "group-chat-reply", OP_GROUP_CHAT_REPLY },
148 { "group-reply", OP_GROUP_REPLY },
149 { "imap-fetch-mail", OP_MAIN_IMAP_FETCH },
150 { "imap-logout-all", OP_MAIN_IMAP_LOGOUT_ALL },
151 { "limit", OP_MAIN_LIMIT },
152 { "limit-current-thread", OP_LIMIT_CURRENT_THREAD },
153 { "link-threads", OP_MAIN_LINK_THREADS },
154 { "list-reply", OP_LIST_REPLY },
155 { "list-subscribe", OP_LIST_SUBSCRIBE },
156 { "list-unsubscribe", OP_LIST_UNSUBSCRIBE },
157 { "mail", OP_MAIL },
158 { "mail-key", OP_MAIL_KEY },
159 { "mailbox-list", OP_MAILBOX_LIST },
160 { "mark-message", OP_MARK_MSG },
161 { "modify-labels", OP_MAIN_MODIFY_TAGS },
162 { "modify-labels-then-hide", OP_MAIN_MODIFY_TAGS_THEN_HIDE },
163 { "modify-tags", OP_MAIN_MODIFY_TAGS },
164 { "modify-tags-then-hide", OP_MAIN_MODIFY_TAGS_THEN_HIDE },
165 { "next-new", OP_MAIN_NEXT_NEW },
166 { "next-new-then-unread", OP_MAIN_NEXT_NEW_THEN_UNREAD },
167 { "next-subthread", OP_MAIN_NEXT_SUBTHREAD },
168 { "next-thread", OP_MAIN_NEXT_THREAD },
169 { "next-undeleted", OP_MAIN_NEXT_UNDELETED },
170 { "next-unread", OP_MAIN_NEXT_UNREAD },
171 { "next-unread-mailbox", OP_MAIN_NEXT_UNREAD_MAILBOX },
172 { "parent-message", OP_MAIN_PARENT_MESSAGE },
173 { "pipe-entry", OP_PIPE },
174 { "pipe-message", OP_PIPE },
175 { "post-message", OP_POST },
176 { "previous-new", OP_MAIN_PREV_NEW },
177 { "previous-new-then-unread", OP_MAIN_PREV_NEW_THEN_UNREAD },
178 { "previous-subthread", OP_MAIN_PREV_SUBTHREAD },
179 { "previous-thread", OP_MAIN_PREV_THREAD },
180 { "previous-undeleted", OP_MAIN_PREV_UNDELETED },
181 { "previous-unread", OP_MAIN_PREV_UNREAD },
182 { "print-message", OP_PRINT },
183 { "purge-message", OP_PURGE_MESSAGE },
184 { "purge-thread", OP_PURGE_THREAD },
185 { "quasi-delete", OP_MAIN_QUASI_DELETE },
186 { "query", OP_QUERY },
187 { "quit", OP_QUIT },
188 { "read-subthread", OP_MAIN_READ_SUBTHREAD },
189 { "read-thread", OP_MAIN_READ_THREAD },
190 { "recall-message", OP_RECALL_MESSAGE },
191 { "reconstruct-thread", OP_RECONSTRUCT_THREAD },
192 { "reply", OP_REPLY },
193 { "resend-message", OP_RESEND },
194 { "root-message", OP_MAIN_ROOT_MESSAGE },
195 { "save-message", OP_SAVE },
196 { "set-flag", OP_MAIN_SET_FLAG },
197 { "show-limit", OP_MAIN_SHOW_LIMIT },
198 { "sidebar-first", OP_SIDEBAR_FIRST },
199 { "sidebar-last", OP_SIDEBAR_LAST },
200 { "sidebar-next", OP_SIDEBAR_NEXT },
201 { "sidebar-next-new", OP_SIDEBAR_NEXT_NEW },
202 { "sidebar-open", OP_SIDEBAR_OPEN },
203 { "sidebar-page-down", OP_SIDEBAR_PAGE_DOWN },
204 { "sidebar-page-up", OP_SIDEBAR_PAGE_UP },
205 { "sidebar-prev", OP_SIDEBAR_PREV },
206 { "sidebar-prev-new", OP_SIDEBAR_PREV_NEW },
207 { "sidebar-toggle-virtual", OP_SIDEBAR_TOGGLE_VIRTUAL },
208 { "sidebar-toggle-visible", OP_SIDEBAR_TOGGLE_VISIBLE },
209 { "sort-mailbox", OP_SORT },
210 { "sort-reverse", OP_SORT_REVERSE },
211 { "sync-mailbox", OP_MAIN_SYNC_FOLDER },
212 { "tag-pattern", OP_MAIN_TAG_PATTERN },
213 { "tag-subthread", OP_TAG_SUBTHREAD },
214 { "tag-thread", OP_TAG_THREAD },
215 { "toggle-new", OP_TOGGLE_NEW },
216 { "toggle-read", OP_TOGGLE_READ },
217 { "toggle-write", OP_TOGGLE_WRITE },
218 { "undelete-message", OP_UNDELETE },
219 { "undelete-pattern", OP_MAIN_UNDELETE_PATTERN },
220 { "undelete-subthread", OP_UNDELETE_SUBTHREAD },
221 { "undelete-thread", OP_UNDELETE_THREAD },
222 { "untag-pattern", OP_MAIN_UNTAG_PATTERN },
223#ifdef USE_NOTMUCH
224 { "vfolder-from-query", OP_MAIN_VFOLDER_FROM_QUERY },
225 { "vfolder-from-query-readonly", OP_MAIN_VFOLDER_FROM_QUERY_READONLY },
226 { "vfolder-window-backward", OP_MAIN_WINDOWED_VFOLDER_BACKWARD },
227 { "vfolder-window-forward", OP_MAIN_WINDOWED_VFOLDER_FORWARD },
228 { "vfolder-window-reset", OP_MAIN_WINDOWED_VFOLDER_RESET },
229#endif
230 { "view-attachments", OP_VIEW_ATTACHMENTS },
231 { "view-raw-message", OP_VIEW_RAW_MESSAGE },
232 // Deprecated
233 { "buffy-list", OP_MAILBOX_LIST },
234 { NULL, 0 },
235};
236
240const struct MenuOpSeq IndexDefaultBindings[] = { /* map: index */
241 { OP_ATTACHMENT_EDIT_TYPE, "\005" }, // <Ctrl-E>
242#ifdef USE_AUTOCRYPT
243 { OP_AUTOCRYPT_ACCT_MENU, "A" },
244#endif
245 { OP_BOUNCE_MESSAGE, "b" },
246 { OP_CHECK_TRADITIONAL, "\033P" }, // <Alt-P>
247 { OP_COPY_MESSAGE, "C" },
248 { OP_CREATE_ALIAS, "a" },
249 { OP_DECODE_COPY, "\033C" }, // <Alt-C>
250 { OP_DECODE_SAVE, "\033s" }, // <Alt-s>
251 { OP_DELETE, "d" },
252 { OP_DELETE_SUBTHREAD, "\033d" }, // <Alt-d>
253 { OP_DELETE_THREAD, "\004" }, // <Ctrl-D>
254 { OP_DISPLAY_ADDRESS, "@" },
255 { OP_DISPLAY_HEADERS, "h" },
256 { OP_DISPLAY_MESSAGE, " " }, // <Space>
257 { OP_DISPLAY_MESSAGE, "<keypadenter>" },
258 { OP_DISPLAY_MESSAGE, "\n" }, // <Enter>
259 { OP_DISPLAY_MESSAGE, "\r" }, // <Return>
260 { OP_EDIT_LABEL, "Y" },
261 { OP_EDIT_OR_VIEW_RAW_MESSAGE, "e" },
262 { OP_EXIT, "x" },
263 { OP_EXTRACT_KEYS, "\013" }, // <Ctrl-K>
264 { OP_FLAG_MESSAGE, "F" },
265 { OP_FORGET_PASSPHRASE, "\006" }, // <Ctrl-F>
266 { OP_FORWARD_MESSAGE, "f" },
267 { OP_GROUP_REPLY, "g" },
268 { OP_LIST_REPLY, "L" },
269 { OP_MAIL, "m" },
270 { OP_MAILBOX_LIST, "." },
271 { OP_MAIL_KEY, "\033k" }, // <Alt-k>
272 { OP_MAIN_BREAK_THREAD, "#" },
273 { OP_MAIN_CHANGE_FOLDER, "c" },
274 { OP_MAIN_CHANGE_FOLDER_READONLY, "\033c" }, // <Alt-c>
275 { OP_MAIN_CHANGE_GROUP, "i" },
276 { OP_MAIN_CHANGE_GROUP_READONLY, "\033i" }, // <Alt-i>
277 { OP_MAIN_CLEAR_FLAG, "W" },
278 { OP_MAIN_COLLAPSE_ALL, "\033V" }, // <Alt-V>
279 { OP_MAIN_COLLAPSE_THREAD, "\033v" }, // <Alt-v>
280 { OP_MAIN_DELETE_PATTERN, "D" },
281 { OP_MAIN_FETCH_MAIL, "G" },
282 { OP_MAIN_LIMIT, "l" },
283 { OP_MAIN_LINK_THREADS, "&" },
284 { OP_MAIN_NEXT_NEW_THEN_UNREAD, "\t" }, // <Tab>
285 { OP_MAIN_NEXT_SUBTHREAD, "\033n" }, // <Alt-n>
286 { OP_MAIN_NEXT_THREAD, "\016" }, // <Ctrl-N>
287 { OP_MAIN_NEXT_UNDELETED, "<down>" },
288 { OP_MAIN_NEXT_UNDELETED, "j" },
289 { OP_MAIN_PARENT_MESSAGE, "P" },
290 { OP_MAIN_PREV_NEW_THEN_UNREAD, "\033\t" }, // <Alt->
291 { OP_MAIN_PREV_SUBTHREAD, "\033p" }, // <Alt-p>
292 { OP_MAIN_PREV_THREAD, "\020" }, // <Ctrl-P>
293 { OP_MAIN_PREV_UNDELETED, "<up>" },
294 { OP_MAIN_PREV_UNDELETED, "k" },
295 { OP_MAIN_READ_SUBTHREAD, "\033r" }, // <Alt-r>
296 { OP_MAIN_READ_THREAD, "\022" }, // <Ctrl-R>
297 { OP_MAIN_SET_FLAG, "w" },
298 { OP_MAIN_SHOW_LIMIT, "\033l" }, // <Alt-l>
299 { OP_MAIN_SYNC_FOLDER, "$" },
300 { OP_MAIN_TAG_PATTERN, "T" },
301 { OP_MAIN_UNDELETE_PATTERN, "U" },
302 { OP_MAIN_UNTAG_PATTERN, "\024" }, // <Ctrl-T>
303 { OP_MARK_MSG, "~" },
304 { OP_NEXT_ENTRY, "J" },
305 { OP_PIPE, "|" },
306 { OP_PREV_ENTRY, "K" },
307 { OP_PRINT, "p" },
308 { OP_QUERY, "Q" },
309 { OP_QUIT, "q" },
310 { OP_RECALL_MESSAGE, "R" },
311 { OP_REPLY, "r" },
312 { OP_RESEND, "\033e" }, // <Alt-e>
313 { OP_SAVE, "s" },
314 { OP_SHOW_LOG_MESSAGES, "M" },
315 { OP_SORT, "o" },
316 { OP_SORT_REVERSE, "O" },
317 { OP_TAG_THREAD, "\033t" }, // <Alt-t>
318 { OP_TOGGLE_NEW, "N" },
319 { OP_TOGGLE_WRITE, "%" },
320 { OP_UNDELETE, "u" },
321 { OP_UNDELETE_SUBTHREAD, "\033u" }, // <Alt-u>
322 { OP_UNDELETE_THREAD, "\025" }, // <Ctrl-U>
323 { OP_VIEW_ATTACHMENTS, "v" },
324 { 0, NULL },
325};
326// clang-format on
327
332{
337};
338
346static bool resolve_email(struct IndexPrivateData *priv,
347 struct IndexSharedData *shared, enum ResolveMethod rm)
348{
349 if (!priv || !priv->menu || !shared || !shared->mailbox || !shared->email)
350 return false;
351
352 const bool c_resolve = cs_subset_bool(shared->sub, "resolve");
353 if (!c_resolve)
354 return false;
355
356 int index = -1;
357 switch (rm)
358 {
360 index = menu_get_index(priv->menu) + 1;
361 break;
362
364 {
365 const bool uncollapse = mutt_using_threads() && !window_is_focused(priv->win_index);
366 index = find_next_undeleted(shared->mailbox_view, menu_get_index(priv->menu), uncollapse);
367 break;
368 }
369
371 index = mutt_next_thread(shared->email);
372 break;
373
375 index = mutt_next_subthread(shared->email);
376 break;
377 }
378
379 if ((index < 0) || (index >= shared->mailbox->vcount))
380 {
381 // Resolve failed
382 notify_send(shared->notify, NT_INDEX, NT_INDEX_EMAIL, NULL);
383 return false;
384 }
385
386 menu_set_index(priv->menu, index);
387 return true;
388}
389
395bool index_next_undeleted(struct MuttWindow *win_index)
396{
397 struct MuttWindow *dlg = dialog_find(win_index);
398 if (!dlg)
399 return false;
400
401 struct Menu *menu = win_index->wdata;
402 struct IndexSharedData *shared = dlg->wdata;
403 if (!shared)
404 return false;
405
406 struct IndexPrivateData *priv = win_index->parent->wdata;
407 const bool uncollapse = mutt_using_threads() && !window_is_focused(priv->win_index);
408
409 int index = find_next_undeleted(shared->mailbox_view, menu_get_index(menu), uncollapse);
410 if ((index < 0) || (index >= shared->mailbox->vcount))
411 {
412 // Selection failed
414 return false;
415 }
416
417 menu_set_index(menu, index);
418 return true;
419}
420
421// -----------------------------------------------------------------------------
422
427 struct IndexPrivateData *priv, int op)
428{
430 return FR_SUCCESS;
431}
432
437 struct IndexPrivateData *priv, int op)
438{
439 if (!shared->email)
440 return FR_NO_ACTION;
442
444 return FR_SUCCESS;
445}
446
451 struct IndexPrivateData *priv, int op)
452{
453 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
454 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
455 index_bounce_message(shared->mailbox, &ea);
456 ARRAY_FREE(&ea);
457
458 return FR_SUCCESS;
459}
460
464static int op_check_traditional(struct IndexSharedData *shared,
465 struct IndexPrivateData *priv, int op)
466{
468 return FR_NOT_IMPL;
469 if (!shared->email)
470 return FR_NO_ACTION;
471
472 if (priv->tag_prefix || !(shared->email->security & PGP_TRADITIONAL_CHECKED))
473 {
474 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
475 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
476 if (mutt_check_traditional_pgp(shared->mailbox, &ea))
478 ARRAY_FREE(&ea);
479 }
480
481 return FR_SUCCESS;
482}
483
487static int op_compose_to_sender(struct IndexSharedData *shared,
488 struct IndexPrivateData *priv, int op)
489{
490 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
491 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
492 int rc = mutt_send_message(SEND_TO_SENDER, NULL, NULL, shared->mailbox, &ea,
493 shared->sub);
494 ARRAY_FREE(&ea);
496
497 return (rc == -1) ? FR_ERROR : FR_SUCCESS;
498}
499
503static int op_create_alias(struct IndexSharedData *shared,
504 struct IndexPrivateData *priv, int op)
505{
506 struct AddressList *al = NULL;
507 if (shared->email && shared->email->env)
508 al = mutt_get_address(shared->email->env, NULL);
509 alias_create(al, shared->sub);
511
512 return FR_SUCCESS;
513}
514
522static int op_delete(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
523{
524 /* L10N: CHECK_ACL */
525 if (!check_acl(shared->mailbox, MUTT_ACL_DELETE, _("Can't delete message")))
526 return FR_ERROR;
527
528 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
529 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
530
531 mutt_emails_set_flag(shared->mailbox, &ea, MUTT_DELETE, true);
532 mutt_emails_set_flag(shared->mailbox, &ea, MUTT_PURGE, (op == OP_PURGE_MESSAGE));
533 const bool c_delete_untag = cs_subset_bool(shared->sub, "delete_untag");
534 if (c_delete_untag)
535 mutt_emails_set_flag(shared->mailbox, &ea, MUTT_TAG, false);
536 ARRAY_FREE(&ea);
537
538 if (priv->tag_prefix)
539 {
541 }
542 else
543 {
545 }
546
547 return FR_SUCCESS;
548}
549
558static int op_delete_thread(struct IndexSharedData *shared,
559 struct IndexPrivateData *priv, int op)
560{
561 /* L10N: CHECK_ACL */
562 /* L10N: Due to the implementation details we do not know whether we
563 delete zero, 1, 12, ... messages. So in English we use
564 "messages". Your language might have other means to express this. */
565 if (!check_acl(shared->mailbox, MUTT_ACL_DELETE, _("Can't delete messages")))
566 return FR_ERROR;
567 if (!shared->email)
568 return FR_NO_ACTION;
569
570 int subthread = (op == OP_DELETE_SUBTHREAD);
571 int rc = mutt_thread_set_flag(shared->mailbox, shared->email, MUTT_DELETE, true, subthread);
572 if (rc == -1)
573 return FR_ERROR;
574 if (op == OP_PURGE_THREAD)
575 {
576 rc = mutt_thread_set_flag(shared->mailbox, shared->email, MUTT_PURGE, true, subthread);
577 if (rc == -1)
578 return FR_ERROR;
579 }
580
581 const bool c_delete_untag = cs_subset_bool(shared->sub, "delete_untag");
582 if (c_delete_untag)
583 mutt_thread_set_flag(shared->mailbox, shared->email, MUTT_TAG, false, subthread);
584
587 return FR_SUCCESS;
588}
589
593static int op_display_address(struct IndexSharedData *shared,
594 struct IndexPrivateData *priv, int op)
595{
596 if (!shared->email)
597 return FR_NO_ACTION;
599
600 return FR_SUCCESS;
601}
602
610static int op_display_message(struct IndexSharedData *shared,
611 struct IndexPrivateData *priv, int op)
612{
613 if (!shared->email)
614 return FR_NO_ACTION;
615 /* toggle the weeding of headers so that a user can press the key
616 * again while reading the message. */
617 if (op == OP_DISPLAY_HEADERS)
618 {
619 bool_str_toggle(shared->sub, "weed", NULL);
620 notify_send(shared->notify, NT_INDEX, NT_INDEX_EMAIL, shared);
621 if (!window_is_focused(priv->win_index))
622 return FR_SUCCESS;
623 }
624
625 OptNeedResort = false;
626
627 if (mutt_using_threads() && shared->email->collapsed)
628 {
630 mutt_set_vnum(shared->mailbox);
631 const bool c_uncollapse_jump = cs_subset_bool(shared->sub, "uncollapse_jump");
632 if (c_uncollapse_jump)
634 }
635
636 const bool c_pgp_auto_decode = cs_subset_bool(shared->sub, "pgp_auto_decode");
637 if (c_pgp_auto_decode &&
638 (priv->tag_prefix || !(shared->email->security & PGP_TRADITIONAL_CHECKED)))
639 {
640 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
641 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
642 if (mutt_check_traditional_pgp(shared->mailbox, &ea))
644 ARRAY_FREE(&ea);
645 }
646 const int index = menu_get_index(priv->menu);
648
649 const char *const c_pager = pager_get_pager(NeoMutt->sub);
650 if (c_pager)
651 {
652 op = external_pager(shared->mailbox_view, shared->email, c_pager);
653 }
654 else
655 {
656 op = mutt_display_message(priv->win_index, shared);
657 }
658
660 if (op < OP_NULL)
661 {
662 OptNeedResort = false;
663 return FR_ERROR;
664 }
665
666 if (shared->mailbox)
667 {
669 shared->mailbox->msg_count, shared);
670 }
671
672 return op;
673}
674
678static int op_edit_label(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
679{
680 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
681 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
682 int num_changed = mutt_label_message(shared->mailbox_view, &ea);
683 ARRAY_FREE(&ea);
684
685 if (num_changed > 0)
686 {
687 shared->mailbox->changed = true;
689 /* L10N: This is displayed when the x-label on one or more
690 messages is edited. */
691 mutt_message(ngettext("%d label changed", "%d labels changed", num_changed), num_changed);
692
693 if (!priv->tag_prefix)
695 return FR_SUCCESS;
696 }
697
698 /* L10N: This is displayed when editing an x-label, but no messages
699 were updated. Possibly due to canceling at the prompt or if the new
700 label is the same as the old label. */
701 mutt_message(_("No labels changed"));
702 return FR_NO_ACTION;
703}
704
713static int op_edit_raw_message(struct IndexSharedData *shared,
714 struct IndexPrivateData *priv, int op)
715{
716 /* TODO split this into 3 cases? */
717 bool edit;
718 if (op == OP_EDIT_RAW_MESSAGE)
719 {
720 /* L10N: CHECK_ACL */
721 if (!check_acl(shared->mailbox, MUTT_ACL_INSERT, _("Can't edit message")))
722 return FR_ERROR;
723 edit = true;
724 }
725 else if (op == OP_EDIT_OR_VIEW_RAW_MESSAGE)
726 {
727 edit = !shared->mailbox->readonly && (shared->mailbox->rights & MUTT_ACL_INSERT);
728 }
729 else
730 {
731 edit = false;
732 }
733
734 if (!shared->email)
735 return FR_NO_ACTION;
736 const bool c_pgp_auto_decode = cs_subset_bool(shared->sub, "pgp_auto_decode");
737 if (c_pgp_auto_decode &&
738 (priv->tag_prefix || !(shared->email->security & PGP_TRADITIONAL_CHECKED)))
739 {
740 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
741 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
742 if (mutt_check_traditional_pgp(shared->mailbox, &ea))
744 ARRAY_FREE(&ea);
745 }
746 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
747 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
748 mutt_ev_message(shared->mailbox, &ea, edit ? EVM_EDIT : EVM_VIEW);
749 ARRAY_FREE(&ea);
751
752 return FR_SUCCESS;
753}
754
758static int op_end_cond(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
759{
760 return FR_SUCCESS;
761}
762
766static int op_exit(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
767{
768 if (shared->attach_msg)
769 return FR_DONE;
770
771 if (query_quadoption(_("Exit NeoMutt without saving?"), shared->sub, "quit") == MUTT_YES)
772 {
773 if (shared->mailbox_view)
774 {
775 mx_fastclose_mailbox(shared->mailbox, false);
776 mview_free(&shared->mailbox_view);
777 }
778 return FR_DONE;
779 }
780
781 return FR_NO_ACTION;
782}
783
787static int op_extract_keys(struct IndexSharedData *shared,
788 struct IndexPrivateData *priv, int op)
789{
790 if (!WithCrypto)
791 return FR_NOT_IMPL;
792 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
793 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
795 ARRAY_FREE(&ea);
797
798 return FR_SUCCESS;
799}
800
804static int op_flag_message(struct IndexSharedData *shared,
805 struct IndexPrivateData *priv, int op)
806{
807 /* L10N: CHECK_ACL */
808 if (!check_acl(shared->mailbox, MUTT_ACL_WRITE, _("Can't flag message")))
809 return FR_ERROR;
810
811 struct Mailbox *m = shared->mailbox;
812 if (priv->tag_prefix)
813 {
814 for (size_t i = 0; i < m->msg_count; i++)
815 {
816 struct Email *e = m->emails[i];
817 if (!e)
818 break;
819 if (message_is_tagged(e))
820 mutt_set_flag(m, e, MUTT_FLAG, !e->flagged, true);
821 }
822
824 }
825 else
826 {
827 if (!shared->email)
828 return FR_NO_ACTION;
829 mutt_set_flag(m, shared->email, MUTT_FLAG, !shared->email->flagged, true);
830
832 }
833
834 return FR_SUCCESS;
835}
836
840static int op_forget_passphrase(struct IndexSharedData *shared,
841 struct IndexPrivateData *priv, int op)
842{
844 return FR_SUCCESS;
845}
846
850static int op_forward_message(struct IndexSharedData *shared,
851 struct IndexPrivateData *priv, int op)
852{
853 if (!shared->email)
854 return FR_NO_ACTION;
855 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
856 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
857 const bool c_pgp_auto_decode = cs_subset_bool(shared->sub, "pgp_auto_decode");
858 if (c_pgp_auto_decode &&
859 (priv->tag_prefix || !(shared->email->security & PGP_TRADITIONAL_CHECKED)))
860 {
861 if (mutt_check_traditional_pgp(shared->mailbox, &ea))
863 }
864 int rc = mutt_send_message(SEND_FORWARD, NULL, NULL, shared->mailbox, &ea,
865 shared->sub);
866 ARRAY_FREE(&ea);
868
869 return (rc == -1) ? FR_ERROR : FR_SUCCESS;
870}
871
879static int op_group_reply(struct IndexSharedData *shared,
880 struct IndexPrivateData *priv, int op)
881{
882 SendFlags replyflags = SEND_REPLY;
883 if (op == OP_GROUP_REPLY)
884 replyflags |= SEND_GROUP_REPLY;
885 else
886 replyflags |= SEND_GROUP_CHAT_REPLY;
887 if (!shared->email)
888 return FR_NO_ACTION;
889 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
890 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
891 const bool c_pgp_auto_decode = cs_subset_bool(shared->sub, "pgp_auto_decode");
892 if (c_pgp_auto_decode &&
893 (priv->tag_prefix || !(shared->email->security & PGP_TRADITIONAL_CHECKED)))
894 {
895 if (mutt_check_traditional_pgp(shared->mailbox, &ea))
897 }
898 int rc = mutt_send_message(replyflags, NULL, NULL, shared->mailbox, &ea,
899 shared->sub);
900 ARRAY_FREE(&ea);
902
903 return (rc == -1) ? FR_ERROR : FR_SUCCESS;
904}
905
909static int op_jump(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
910{
911 int rc = FR_ERROR;
912 struct Buffer *buf = buf_pool_get();
913
914 const int digit = op - OP_JUMP;
915 if ((digit > 0) && (digit < 10))
916 {
917 mutt_unget_ch('0' + digit);
918 }
919
920 int msg_num = 0;
921 if ((mw_get_field(_("Jump to message: "), buf, MUTT_COMP_NO_FLAGS, HC_OTHER, NULL, NULL) != 0) ||
922 buf_is_empty(buf))
923 {
924 mutt_message(_("Nothing to do"));
925 rc = FR_NO_ACTION;
926 }
927 else if (!mutt_str_atoi_full(buf_string(buf), &msg_num))
928 {
929 mutt_warning(_("Argument must be a message number"));
930 }
931 else if ((msg_num < 1) || (msg_num > shared->mailbox->msg_count))
932 {
933 mutt_warning(_("Invalid message number"));
934 }
935 else if (!shared->mailbox->emails[msg_num - 1]->visible)
936 {
937 mutt_warning(_("That message is not visible"));
938 }
939 else
940 {
941 struct Email *e = shared->mailbox->emails[msg_num - 1];
942
943 if (mutt_messages_in_thread(shared->mailbox, e, MIT_POSITION) > 1)
944 {
946 mutt_set_vnum(shared->mailbox);
947 }
948 menu_set_index(priv->menu, e->vnum);
949 rc = FR_SUCCESS;
950 }
951
952 buf_pool_release(&buf);
953 return rc;
954}
955
959static int op_list_reply(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
960{
961 if (!shared->email)
962 return FR_NO_ACTION;
963 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
964 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
965 const bool c_pgp_auto_decode = cs_subset_bool(shared->sub, "pgp_auto_decode");
966 if (c_pgp_auto_decode &&
967 (priv->tag_prefix || !(shared->email->security & PGP_TRADITIONAL_CHECKED)))
968 {
969 if (mutt_check_traditional_pgp(shared->mailbox, &ea))
971 }
972 int rc = mutt_send_message(SEND_REPLY | SEND_LIST_REPLY, NULL, NULL,
973 shared->mailbox, &ea, shared->sub);
974 ARRAY_FREE(&ea);
976
977 return (rc == -1) ? FR_ERROR : FR_SUCCESS;
978}
979
983static int op_list_subscribe(struct IndexSharedData *shared,
984 struct IndexPrivateData *priv, int op)
985{
986 return mutt_send_list_subscribe(shared->mailbox, shared->email) ? FR_SUCCESS : FR_NO_ACTION;
987}
988
992static int op_list_unsubscribe(struct IndexSharedData *shared,
993 struct IndexPrivateData *priv, int op)
994{
996}
997
1001static int op_mail(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
1002{
1003 int rc = mutt_send_message(SEND_NO_FLAGS, NULL, NULL, shared->mailbox, NULL,
1004 shared->sub);
1006 return (rc == -1) ? FR_ERROR : FR_SUCCESS;
1007}
1008
1012static int op_mailbox_list(struct IndexSharedData *shared,
1013 struct IndexPrivateData *priv, int op)
1014{
1016 return FR_SUCCESS;
1017}
1018
1022static int op_mail_key(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
1023{
1024 if (!(WithCrypto & APPLICATION_PGP))
1025 return FR_NOT_IMPL;
1026 int rc = mutt_send_message(SEND_KEY, NULL, NULL, NULL, NULL, shared->sub);
1028
1029 return (rc == -1) ? FR_ERROR : FR_SUCCESS;
1030}
1031
1035static int op_main_break_thread(struct IndexSharedData *shared,
1036 struct IndexPrivateData *priv, int op)
1037{
1038 struct Mailbox *m = shared->mailbox;
1039 /* L10N: CHECK_ACL */
1040 if (!check_acl(m, MUTT_ACL_WRITE, _("Can't break thread")))
1041 return FR_ERROR;
1042
1043 struct Email *e = shared->email;
1044 if (!e)
1045 return FR_NO_ACTION;
1046
1047 if (!mutt_using_threads())
1048 {
1049 mutt_warning(_("Threading is not enabled"));
1050 return FR_NO_ACTION;
1051 }
1052
1053 struct MailboxView *mv = shared->mailbox_view;
1055 {
1056 {
1058 mutt_sort_headers(mv, true);
1059 menu_set_index(priv->menu, e->vnum);
1060 }
1061
1062 m->changed = true;
1063 mutt_message(_("Thread broken"));
1064
1066 }
1067 else
1068 {
1069 mutt_error(_("Thread can't be broken, message is not part of a thread"));
1070 }
1071
1072 return FR_SUCCESS;
1073}
1074
1083static int op_main_change_folder(struct IndexSharedData *shared,
1084 struct IndexPrivateData *priv, int op)
1085{
1086 struct Buffer *folderbuf = buf_pool_get();
1087 buf_alloc(folderbuf, PATH_MAX);
1088
1089 char *cp = NULL;
1090 bool read_only;
1091 const bool c_read_only = cs_subset_bool(shared->sub, "read_only");
1092 if (shared->attach_msg || c_read_only || (op == OP_MAIN_CHANGE_FOLDER_READONLY))
1093 {
1094 cp = _("Open mailbox in read-only mode");
1095 read_only = true;
1096 }
1097 else
1098 {
1099 cp = _("Open mailbox");
1100 read_only = false;
1101 }
1102
1103 const bool c_change_folder_next = cs_subset_bool(shared->sub, "change_folder_next");
1104 if (c_change_folder_next && shared->mailbox && !buf_is_empty(&shared->mailbox->pathbuf))
1105 {
1106 buf_strcpy(folderbuf, mailbox_path(shared->mailbox));
1107 buf_pretty_mailbox(folderbuf);
1108 }
1109 /* By default, fill buf with the next mailbox that contains unread mail */
1110 mutt_mailbox_next(shared->mailbox_view ? shared->mailbox : NULL, folderbuf);
1111
1112 if (mw_enter_fname(cp, folderbuf, true, shared->mailbox, false, NULL, NULL,
1113 MUTT_SEL_NO_FLAGS) == -1)
1114 {
1115 goto changefoldercleanup;
1116 }
1117
1118 /* Selected directory is okay, let's save it. */
1120
1121 if (buf_is_empty(folderbuf))
1122 {
1123 msgwin_clear_text(NULL);
1124 goto changefoldercleanup;
1125 }
1126
1127 struct Mailbox *m = mx_mbox_find2(buf_string(folderbuf));
1128 if (m)
1129 {
1130 change_folder_mailbox(priv->menu, m, &priv->oldcount, shared, read_only);
1131 }
1132 else
1133 {
1134 change_folder_string(priv->menu, folderbuf, &priv->oldcount, shared, read_only);
1135 }
1136
1137changefoldercleanup:
1138 buf_pool_release(&folderbuf);
1140
1141 return FR_SUCCESS;
1142}
1143
1147static int op_main_collapse_all(struct IndexSharedData *shared,
1148 struct IndexPrivateData *priv, int op)
1149{
1150 if (!mutt_using_threads())
1151 {
1152 mutt_error(_("Threading is not enabled"));
1153 return FR_ERROR;
1154 }
1155 collapse_all(shared->mailbox_view, priv->menu, 1);
1156
1157 return FR_SUCCESS;
1158}
1159
1164 struct IndexPrivateData *priv, int op)
1165{
1166 if (!mutt_using_threads())
1167 {
1168 mutt_error(_("Threading is not enabled"));
1169 return FR_ERROR;
1170 }
1171
1172 if (!shared->email)
1173 return FR_NO_ACTION;
1174
1175 if (shared->email->collapsed)
1176 {
1177 int index = mutt_uncollapse_thread(shared->email);
1178 mutt_set_vnum(shared->mailbox);
1179 const bool c_uncollapse_jump = cs_subset_bool(shared->sub, "uncollapse_jump");
1180 if (c_uncollapse_jump)
1181 index = mutt_thread_next_unread(shared->email);
1182 menu_set_index(priv->menu, index);
1183 }
1184 else if (mutt_thread_can_collapse(shared->email))
1185 {
1187 mutt_set_vnum(shared->mailbox);
1188 }
1189 else
1190 {
1191 mutt_error(_("Thread contains unread or flagged messages"));
1192 return FR_ERROR;
1193 }
1194
1196
1197 return FR_SUCCESS;
1198}
1199
1203static int op_main_delete_pattern(struct IndexSharedData *shared,
1204 struct IndexPrivateData *priv, int op)
1205{
1206 /* L10N: CHECK_ACL */
1207 /* L10N: Due to the implementation details we do not know whether we
1208 delete zero, 1, 12, ... messages. So in English we use
1209 "messages". Your language might have other means to express this. */
1210 if (!check_acl(shared->mailbox, MUTT_ACL_DELETE, _("Can't delete messages")))
1211 return FR_ERROR;
1212
1213 mutt_pattern_func(shared->mailbox_view, MUTT_DELETE, _("Delete messages matching: "));
1215
1216 return FR_SUCCESS;
1217}
1218
1227static int op_main_limit(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
1228{
1229 const bool lmt = mview_has_limit(shared->mailbox_view);
1230 int old_index = shared->email ? shared->email->index : -1;
1231 if (op == OP_TOGGLE_READ)
1232 {
1233 char buf2[1024] = { 0 };
1234
1235 if (!lmt || !mutt_strn_equal(shared->mailbox_view->pattern, "!~R!~D~s", 8))
1236 {
1237 snprintf(buf2, sizeof(buf2), "!~R!~D~s%s", lmt ? shared->mailbox_view->pattern : ".*");
1238 }
1239 else
1240 {
1241 mutt_str_copy(buf2, shared->mailbox_view->pattern + 8, sizeof(buf2));
1242 if ((*buf2 == '\0') || mutt_strn_equal(buf2, ".*", 2))
1243 snprintf(buf2, sizeof(buf2), "~A");
1244 }
1245 mutt_str_replace(&shared->mailbox_view->pattern, buf2);
1247 }
1248
1249 if (((op == OP_LIMIT_CURRENT_THREAD) &&
1250 mutt_limit_current_thread(shared->mailbox_view, shared->email)) ||
1251 (op == OP_TOGGLE_READ) ||
1252 ((op == OP_MAIN_LIMIT) && (mutt_pattern_func(shared->mailbox_view, MUTT_LIMIT,
1253 _("Limit to messages matching: ")) == 0)))
1254 {
1255 priv->menu->max = shared->mailbox->vcount;
1256 menu_set_index(priv->menu, 0);
1257 if (old_index >= 0)
1258 {
1259 /* try to find what used to be the current message */
1260 for (size_t i = 0; i < shared->mailbox->vcount; i++)
1261 {
1262 struct Email *e = mutt_get_virt_email(shared->mailbox, i);
1263 if (!e)
1264 continue;
1265 if (e->index == old_index)
1266 {
1267 menu_set_index(priv->menu, i);
1268 break;
1269 }
1270 }
1271 }
1272
1273 if ((shared->mailbox->msg_count != 0) && mutt_using_threads())
1274 {
1275 const bool c_collapse_all = cs_subset_bool(shared->sub, "collapse_all");
1276 if (c_collapse_all)
1277 collapse_all(shared->mailbox_view, priv->menu, 0);
1279 }
1281 }
1282 if (lmt)
1283 mutt_message(_("To view all messages, limit to \"all\""));
1284
1285 return FR_SUCCESS;
1286}
1287
1291static int op_main_link_threads(struct IndexSharedData *shared,
1292 struct IndexPrivateData *priv, int op)
1293{
1294 struct Mailbox *m = shared->mailbox;
1295 /* L10N: CHECK_ACL */
1296 if (!check_acl(m, MUTT_ACL_WRITE, _("Can't link threads")))
1297 return FR_ERROR;
1298
1299 struct Email *e = shared->email;
1300 if (!e)
1301 return FR_NO_ACTION;
1302
1303 enum FunctionRetval rc = FR_ERROR;
1304
1305 if (!mutt_using_threads())
1306 {
1307 mutt_error(_("Threading is not enabled"));
1308 }
1309 else if (!e->env->message_id)
1310 {
1311 mutt_error(_("No Message-ID: header available to link thread"));
1312 }
1313 else
1314 {
1315 struct MailboxView *mv = shared->mailbox_view;
1316 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
1317 ea_add_tagged(&ea, mv, NULL, true);
1318
1319 if (mutt_link_threads(e, &ea, m))
1320 {
1321 mutt_sort_headers(mv, true);
1322 menu_set_index(priv->menu, e->vnum);
1323
1324 m->changed = true;
1325 mutt_message(_("Threads linked"));
1326 rc = FR_SUCCESS;
1327 }
1328 else
1329 {
1330 mutt_error(_("No thread linked"));
1331 rc = FR_NO_ACTION;
1332 }
1333
1334 ARRAY_FREE(&ea);
1335 }
1336
1338 return rc;
1339}
1340
1348static int op_main_modify_tags(struct IndexSharedData *shared,
1349 struct IndexPrivateData *priv, int op)
1350{
1351 int rc = FR_ERROR;
1352 struct Buffer *buf = NULL;
1353
1354 if (!shared->mailbox)
1355 goto done;
1356 struct Mailbox *m = shared->mailbox;
1357 if (!mx_tags_is_supported(m))
1358 {
1359 mutt_message(_("Folder doesn't support tagging, aborting"));
1360 goto done;
1361 }
1362 if (!shared->email)
1363 {
1364 rc = FR_NO_ACTION;
1365 goto done;
1366 }
1367
1368 struct Buffer *tags = buf_pool_get();
1369 if (!priv->tag_prefix)
1370 driver_tags_get_with_hidden(&shared->email->tags, tags);
1371 buf = buf_pool_get();
1372 int rc2 = mx_tags_edit(m, buf_string(tags), buf);
1373 buf_pool_release(&tags);
1374 if (rc2 < 0)
1375 {
1376 goto done;
1377 }
1378 else if (rc2 == 0)
1379 {
1380 mutt_message(_("No tag specified, aborting"));
1381 goto done;
1382 }
1383
1384 if (priv->tag_prefix)
1385 {
1386 struct Progress *progress = NULL;
1387
1388 if (m->verbose)
1389 {
1391 progress_set_message(progress, _("Update tags..."));
1392 }
1393
1394#ifdef USE_NOTMUCH
1395 if (m->type == MUTT_NOTMUCH)
1396 nm_db_longrun_init(m, true);
1397#endif
1398 for (int px = 0, i = 0; i < m->msg_count; i++)
1399 {
1400 struct Email *e = m->emails[i];
1401 if (!e)
1402 break;
1403 if (!message_is_tagged(e))
1404 continue;
1405
1406 progress_update(progress, ++px, -1);
1407 mx_tags_commit(m, e, buf_string(buf));
1408 e->attr_color = NULL;
1409 if (op == OP_MAIN_MODIFY_TAGS_THEN_HIDE)
1410 {
1411 bool still_queried = false;
1412#ifdef USE_NOTMUCH
1413 if (m->type == MUTT_NOTMUCH)
1414 still_queried = nm_message_is_still_queried(m, e);
1415#endif
1416 e->quasi_deleted = !still_queried;
1417 m->changed = true;
1418 }
1419 }
1420 progress_free(&progress);
1421#ifdef USE_NOTMUCH
1422 if (m->type == MUTT_NOTMUCH)
1424#endif
1426 }
1427 else
1428 {
1429 if (mx_tags_commit(m, shared->email, buf_string(buf)))
1430 {
1431 mutt_message(_("Failed to modify tags, aborting"));
1432 goto done;
1433 }
1434 shared->email->attr_color = NULL;
1435 if (op == OP_MAIN_MODIFY_TAGS_THEN_HIDE)
1436 {
1437 bool still_queried = false;
1438#ifdef USE_NOTMUCH
1439 if (m->type == MUTT_NOTMUCH)
1440 still_queried = nm_message_is_still_queried(m, shared->email);
1441#endif
1442 shared->email->quasi_deleted = !still_queried;
1443 m->changed = true;
1444 }
1445
1447 }
1448 rc = FR_SUCCESS;
1449
1450done:
1451 buf_pool_release(&buf);
1452 return rc;
1453}
1454
1466static int op_main_next_new(struct IndexSharedData *shared,
1467 struct IndexPrivateData *priv, int op)
1468{
1469 int first_unread = -1;
1470 int first_new = -1;
1471
1472 const int saved_current = menu_get_index(priv->menu);
1473 int mcur = saved_current;
1474 int index = -1;
1475 const bool threaded = mutt_using_threads();
1476 for (size_t i = 0; i != shared->mailbox->vcount; i++)
1477 {
1478 if ((op == OP_MAIN_NEXT_NEW) || (op == OP_MAIN_NEXT_UNREAD) ||
1479 (op == OP_MAIN_NEXT_NEW_THEN_UNREAD))
1480 {
1481 mcur++;
1482 if (mcur > (shared->mailbox->vcount - 1))
1483 {
1484 mcur = 0;
1485 }
1486 }
1487 else
1488 {
1489 mcur--;
1490 if (mcur < 0)
1491 {
1492 mcur = shared->mailbox->vcount - 1;
1493 }
1494 }
1495
1496 struct Email *e = mutt_get_virt_email(shared->mailbox, mcur);
1497 if (!e)
1498 break;
1499 if (e->collapsed && threaded)
1500 {
1501 int unread = mutt_thread_contains_unread(e);
1502 if ((unread != 0) && (first_unread == -1))
1503 first_unread = mcur;
1504 if ((unread == 1) && (first_new == -1))
1505 first_new = mcur;
1506 }
1507 else if (!e->deleted && !e->read)
1508 {
1509 if (first_unread == -1)
1510 first_unread = mcur;
1511 if (!e->old && (first_new == -1))
1512 first_new = mcur;
1513 }
1514
1515 if (((op == OP_MAIN_NEXT_UNREAD) || (op == OP_MAIN_PREV_UNREAD)) && (first_unread != -1))
1516 {
1517 break;
1518 }
1519 if (((op == OP_MAIN_NEXT_NEW) || (op == OP_MAIN_PREV_NEW) ||
1520 (op == OP_MAIN_NEXT_NEW_THEN_UNREAD) || (op == OP_MAIN_PREV_NEW_THEN_UNREAD)) &&
1521 (first_new != -1))
1522 {
1523 break;
1524 }
1525 }
1526 if (((op == OP_MAIN_NEXT_NEW) || (op == OP_MAIN_PREV_NEW) ||
1527 (op == OP_MAIN_NEXT_NEW_THEN_UNREAD) || (op == OP_MAIN_PREV_NEW_THEN_UNREAD)) &&
1528 (first_new != -1))
1529 {
1530 index = first_new;
1531 }
1532 else if (((op == OP_MAIN_NEXT_UNREAD) || (op == OP_MAIN_PREV_UNREAD) ||
1533 (op == OP_MAIN_NEXT_NEW_THEN_UNREAD) || (op == OP_MAIN_PREV_NEW_THEN_UNREAD)) &&
1534 (first_unread != -1))
1535 {
1536 index = first_unread;
1537 }
1538
1539 if (index == -1)
1540 {
1541 menu_set_index(priv->menu, saved_current);
1542 if ((op == OP_MAIN_NEXT_NEW) || (op == OP_MAIN_PREV_NEW))
1543 {
1544 if (mview_has_limit(shared->mailbox_view))
1545 mutt_error(_("No new messages in this limited view"));
1546 else
1547 mutt_error(_("No new messages"));
1548 }
1549 else
1550 {
1551 if (mview_has_limit(shared->mailbox_view))
1552 mutt_error(_("No unread messages in this limited view"));
1553 else
1554 mutt_error(_("No unread messages"));
1555 }
1556 notify_send(shared->notify, NT_INDEX, NT_INDEX_EMAIL, NULL);
1557 return FR_ERROR;
1558 }
1559 else
1560 {
1561 menu_set_index(priv->menu, index);
1562 }
1563
1564 index = menu_get_index(priv->menu);
1565 if ((op == OP_MAIN_NEXT_NEW) || (op == OP_MAIN_NEXT_UNREAD) ||
1566 (op == OP_MAIN_NEXT_NEW_THEN_UNREAD))
1567 {
1568 if (saved_current > index)
1569 {
1570 mutt_message(_("Search wrapped to top"));
1571 }
1572 }
1573 else if (saved_current < index)
1574 {
1575 mutt_message(_("Search wrapped to bottom"));
1576 }
1577
1578 return FR_SUCCESS;
1579}
1580
1590static int op_main_next_thread(struct IndexSharedData *shared,
1591 struct IndexPrivateData *priv, int op)
1592{
1593 int index = -1;
1594 switch (op)
1595 {
1596 case OP_MAIN_NEXT_THREAD:
1597 index = mutt_next_thread(shared->email);
1598 break;
1599
1600 case OP_MAIN_NEXT_SUBTHREAD:
1601 index = mutt_next_subthread(shared->email);
1602 break;
1603
1604 case OP_MAIN_PREV_THREAD:
1605 index = mutt_previous_thread(shared->email);
1606 break;
1607
1608 case OP_MAIN_PREV_SUBTHREAD:
1610 break;
1611 }
1612
1613 if (index != -1)
1614 menu_set_index(priv->menu, index);
1615
1616 if (index < 0)
1617 {
1618 if ((op == OP_MAIN_NEXT_THREAD) || (op == OP_MAIN_NEXT_SUBTHREAD))
1619 mutt_error(_("No more threads"));
1620 else
1621 mutt_error(_("You are on the first thread"));
1622
1623 notify_send(shared->notify, NT_INDEX, NT_INDEX_EMAIL, NULL);
1624 }
1625
1626 return FR_SUCCESS;
1627}
1628
1632static int op_main_next_undeleted(struct IndexSharedData *shared,
1633 struct IndexPrivateData *priv, int op)
1634{
1635 int index = menu_get_index(priv->menu);
1636 if (index >= (shared->mailbox->vcount - 1))
1637 {
1638 notify_send(shared->notify, NT_INDEX, NT_INDEX_EMAIL, NULL);
1639 mutt_message(_("You are on the last message"));
1640 return FR_ERROR;
1641 }
1642
1643 const bool uncollapse = mutt_using_threads() && !window_is_focused(priv->win_index);
1644
1645 index = find_next_undeleted(shared->mailbox_view, index, uncollapse);
1646 if (index != -1)
1647 {
1648 menu_set_index(priv->menu, index);
1649 if (uncollapse)
1651 }
1652
1653 if (index == -1)
1654 {
1655 notify_send(shared->notify, NT_INDEX, NT_INDEX_EMAIL, NULL);
1656 mutt_error(_("No undeleted messages"));
1657 }
1658
1659 return FR_SUCCESS;
1660}
1661
1666 struct IndexPrivateData *priv, int op)
1667{
1668 struct Mailbox *m = shared->mailbox;
1669
1670 struct Buffer *folderbuf = buf_pool_get();
1671 buf_strcpy(folderbuf, mailbox_path(m));
1672 m = mutt_mailbox_next_unread(m, folderbuf);
1673 buf_pool_release(&folderbuf);
1674
1675 if (!m)
1676 {
1677 mutt_error(_("No mailboxes have new mail"));
1678 return FR_ERROR;
1679 }
1680
1681 change_folder_mailbox(priv->menu, m, &priv->oldcount, shared, false);
1682 return FR_SUCCESS;
1683}
1684
1688static int op_main_prev_undeleted(struct IndexSharedData *shared,
1689 struct IndexPrivateData *priv, int op)
1690{
1691 int index = menu_get_index(priv->menu);
1692 if (index < 1)
1693 {
1694 notify_send(shared->notify, NT_INDEX, NT_INDEX_EMAIL, NULL);
1695 mutt_message(_("You are on the first message"));
1696 return FR_ERROR;
1697 }
1698
1699 const bool uncollapse = mutt_using_threads() && !window_is_focused(priv->win_index);
1700
1701 index = find_previous_undeleted(shared->mailbox_view, index, uncollapse);
1702 if (index != -1)
1703 {
1704 menu_set_index(priv->menu, index);
1705 if (uncollapse)
1707 }
1708
1709 if (index == -1)
1710 {
1711 mutt_error(_("No undeleted messages"));
1712 notify_send(shared->notify, NT_INDEX, NT_INDEX_EMAIL, NULL);
1713 }
1714
1715 return FR_SUCCESS;
1716}
1717
1721static int op_main_quasi_delete(struct IndexSharedData *shared,
1722 struct IndexPrivateData *priv, int op)
1723{
1724 if (priv->tag_prefix)
1725 {
1726 struct Mailbox *m = shared->mailbox;
1727 for (size_t i = 0; i < m->msg_count; i++)
1728 {
1729 struct Email *e = m->emails[i];
1730 if (!e)
1731 break;
1732 if (message_is_tagged(e))
1733 {
1734 e->quasi_deleted = true;
1735 m->changed = true;
1736 }
1737 }
1738 }
1739 else
1740 {
1741 if (!shared->email)
1742 return FR_NO_ACTION;
1743 shared->email->quasi_deleted = true;
1744 shared->mailbox->changed = true;
1745 }
1746
1747 return FR_SUCCESS;
1748}
1749
1757static int op_main_read_thread(struct IndexSharedData *shared,
1758 struct IndexPrivateData *priv, int op)
1759{
1760 /* L10N: CHECK_ACL */
1761 /* L10N: Due to the implementation details we do not know whether we
1762 mark zero, 1, 12, ... messages as read. So in English we use
1763 "messages". Your language might have other means to express this. */
1764 if (!check_acl(shared->mailbox, MUTT_ACL_SEEN, _("Can't mark messages as read")))
1765 return FR_ERROR;
1766
1767 int rc = mutt_thread_set_flag(shared->mailbox, shared->email, MUTT_READ, true,
1768 (op != OP_MAIN_READ_THREAD));
1769 if (rc != -1)
1770 {
1771 const enum ResolveMethod rm = (op == OP_MAIN_READ_THREAD) ? RESOLVE_NEXT_THREAD :
1773 resolve_email(priv, shared, rm);
1775 }
1776
1777 return FR_SUCCESS;
1778}
1779
1787static int op_main_root_message(struct IndexSharedData *shared,
1788 struct IndexPrivateData *priv, int op)
1789{
1790 int index = mutt_parent_message(shared->email, op == OP_MAIN_ROOT_MESSAGE);
1791 if (index != -1)
1792 menu_set_index(priv->menu, index);
1793
1794 return FR_SUCCESS;
1795}
1796
1804static int op_main_set_flag(struct IndexSharedData *shared,
1805 struct IndexPrivateData *priv, int op)
1806{
1807 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
1808 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
1809
1810 if (mw_change_flag(shared->mailbox, &ea, (op == OP_MAIN_SET_FLAG)) == 0)
1811 {
1812 if (priv->tag_prefix)
1813 {
1815 }
1816 else
1817 {
1819 }
1820 }
1821 ARRAY_FREE(&ea);
1822
1823 return FR_SUCCESS;
1824}
1825
1829static int op_main_show_limit(struct IndexSharedData *shared,
1830 struct IndexPrivateData *priv, int op)
1831{
1832 if (mview_has_limit(shared->mailbox_view))
1833 {
1834 char buf2[256] = { 0 };
1835 /* L10N: ask for a limit to apply */
1836 snprintf(buf2, sizeof(buf2), _("Limit: %s"), shared->mailbox_view->pattern);
1837 mutt_message("%s", buf2);
1838 }
1839 else
1840 {
1841 mutt_message(_("No limit pattern is in effect"));
1842 }
1843
1844 return FR_SUCCESS;
1845}
1846
1850static int op_main_sync_folder(struct IndexSharedData *shared,
1851 struct IndexPrivateData *priv, int op)
1852{
1853 if (!shared->mailbox || (shared->mailbox->msg_count == 0) || shared->mailbox->readonly)
1854 return FR_NO_ACTION;
1855
1856 int ovc = shared->mailbox->vcount;
1857 int oc = shared->mailbox->msg_count;
1858 struct Email *e = NULL;
1859
1860 /* don't attempt to move the cursor if there are no visible messages in the current limit */
1861 int index = menu_get_index(priv->menu);
1862 if (index < shared->mailbox->vcount)
1863 {
1864 /* threads may be reordered, so figure out what header the cursor
1865 * should be on. */
1866 int newidx = index;
1867 if (!shared->email)
1868 return FR_NO_ACTION;
1869 if (shared->email->deleted)
1870 newidx = find_next_undeleted(shared->mailbox_view, index, false);
1871 if (newidx < 0)
1872 newidx = find_previous_undeleted(shared->mailbox_view, index, false);
1873 if (newidx >= 0)
1874 e = mutt_get_virt_email(shared->mailbox, newidx);
1875 }
1876
1877 enum MxStatus check = mx_mbox_sync(shared->mailbox);
1878 if (check == MX_STATUS_OK)
1879 {
1880 if (e && (shared->mailbox->vcount != ovc))
1881 {
1882 for (size_t i = 0; i < shared->mailbox->vcount; i++)
1883 {
1884 struct Email *e2 = mutt_get_virt_email(shared->mailbox, i);
1885 if (e2 == e)
1886 {
1887 menu_set_index(priv->menu, i);
1888 break;
1889 }
1890 }
1891 }
1893 }
1894 else if ((check == MX_STATUS_NEW_MAIL) || (check == MX_STATUS_REOPENED))
1895 {
1896 update_index(priv->menu, shared->mailbox_view, check, oc, shared);
1897 }
1898
1899 /* do a sanity check even if mx_mbox_sync failed. */
1900
1901 index = menu_get_index(priv->menu);
1902 if ((index < 0) || (shared->mailbox && (index >= shared->mailbox->vcount)))
1903 {
1905 }
1906
1907 /* check for a fatal error, or all messages deleted */
1908 if (shared->mailbox && buf_is_empty(&shared->mailbox->pathbuf))
1909 {
1910 mview_free(&shared->mailbox_view);
1911 }
1912
1913 priv->menu->max = shared->mailbox->vcount;
1915
1916 struct EventMailbox ev_m = { shared->mailbox };
1918
1919 return FR_SUCCESS;
1920}
1921
1925static int op_main_tag_pattern(struct IndexSharedData *shared,
1926 struct IndexPrivateData *priv, int op)
1927{
1928 mutt_pattern_func(shared->mailbox_view, MUTT_TAG, _("Tag messages matching: "));
1930
1931 return FR_SUCCESS;
1932}
1933
1938 struct IndexPrivateData *priv, int op)
1939{
1940 /* L10N: CHECK_ACL */
1941 /* L10N: Due to the implementation details we do not know whether we
1942 undelete zero, 1, 12, ... messages. So in English we use
1943 "messages". Your language might have other means to express this. */
1944 if (!check_acl(shared->mailbox, MUTT_ACL_DELETE, _("Can't undelete messages")))
1945 return FR_ERROR;
1946
1948 _("Undelete messages matching: ")) == 0)
1949 {
1951 }
1952
1953 return FR_SUCCESS;
1954}
1955
1959static int op_main_untag_pattern(struct IndexSharedData *shared,
1960 struct IndexPrivateData *priv, int op)
1961{
1962 if (mutt_pattern_func(shared->mailbox_view, MUTT_UNTAG, _("Untag messages matching: ")) == 0)
1964
1965 return FR_SUCCESS;
1966}
1967
1971static int op_mark_msg(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
1972{
1973 if (!shared->email)
1974 return FR_NO_ACTION;
1975
1976 int rc = FR_SUCCESS;
1977
1978 if (shared->email->env->message_id)
1979 {
1980 struct Buffer *buf = buf_pool_get();
1981
1982 /* L10N: This is the prompt for <mark-message>. Whatever they
1983 enter will be prefixed by $mark_macro_prefix and will become
1984 a macro hotkey to jump to the currently selected message. */
1985 if ((mw_get_field(_("Enter macro stroke: "), buf, MUTT_COMP_NO_FLAGS,
1986 HC_OTHER, NULL, NULL) == 0) &&
1987 !buf_is_empty(buf))
1988 {
1989 const char *const c_mark_macro_prefix = cs_subset_string(shared->sub, "mark_macro_prefix");
1990 char str[256] = { 0 };
1991 snprintf(str, sizeof(str), "%s%s", c_mark_macro_prefix, buf_string(buf));
1992
1993 struct Buffer *msg_id = buf_pool_get();
1994 mutt_file_sanitize_regex(msg_id, shared->email->env->message_id);
1995 char macro[256] = { 0 };
1996 snprintf(macro, sizeof(macro), "<search>~i '%s'\n", buf_string(msg_id));
1997 buf_pool_release(&msg_id);
1998
1999 /* L10N: "message hotkey" is the key bindings menu description of a
2000 macro created by <mark-message>. */
2001 km_bind(str, MENU_INDEX, OP_MACRO, macro, _("message hotkey"));
2002
2003 /* L10N: This is echoed after <mark-message> creates a new hotkey
2004 macro. %s is the hotkey string ($mark_macro_prefix followed
2005 by whatever they typed at the prompt.) */
2006 buf_printf(buf, _("Message bound to %s"), str);
2007 mutt_message("%s", buf_string(buf));
2008 mutt_debug(LL_DEBUG1, "Mark: %s => %s\n", str, macro);
2009 buf_pool_release(&buf);
2010 }
2011 }
2012 else
2013 {
2014 /* L10N: This error is printed if <mark-message> can't find a
2015 Message-ID for the currently selected message in the index. */
2016 mutt_error(_("No message ID to macro"));
2017 rc = FR_ERROR;
2018 }
2019
2020 return rc;
2021}
2022
2026static int op_next_entry(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
2027{
2028 const int index = menu_get_index(priv->menu) + 1;
2029 if (index >= shared->mailbox->vcount)
2030 {
2031 mutt_message(_("You are on the last message"));
2032 notify_send(shared->notify, NT_INDEX, NT_INDEX_EMAIL, NULL);
2033 return FR_ERROR;
2034 }
2035 menu_set_index(priv->menu, index);
2036 return FR_SUCCESS;
2037}
2038
2042static int op_pipe(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
2043{
2044 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
2045 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
2046 mutt_pipe_message(shared->mailbox, &ea);
2047 ARRAY_FREE(&ea);
2048
2049 /* in an IMAP folder index with imap_peek=no, piping could change
2050 * new or old messages status to read. Redraw what's needed. */
2051 const bool c_imap_peek = cs_subset_bool(shared->sub, "imap_peek");
2052 if ((shared->mailbox->type == MUTT_IMAP) && !c_imap_peek)
2053 {
2055 }
2056
2057 return FR_SUCCESS;
2058}
2059
2063static int op_prev_entry(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
2064{
2065 int index = menu_get_index(priv->menu);
2066 if (index < 1)
2067 {
2068 notify_send(shared->notify, NT_INDEX, NT_INDEX_EMAIL, NULL);
2069 mutt_message(_("You are on the first message"));
2070 return FR_ERROR;
2071 }
2072 menu_set_index(priv->menu, index - 1);
2073 return FR_SUCCESS;
2074}
2075
2079static int op_print(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
2080{
2081 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
2082 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
2083 mutt_print_message(shared->mailbox, &ea);
2084 ARRAY_FREE(&ea);
2085
2086 /* in an IMAP folder index with imap_peek=no, printing could change
2087 * new or old messages status to read. Redraw what's needed. */
2088 const bool c_imap_peek = cs_subset_bool(shared->sub, "imap_peek");
2089 if ((shared->mailbox->type == MUTT_IMAP) && !c_imap_peek)
2090 {
2092 }
2093
2094 return FR_SUCCESS;
2095}
2096
2100static int op_query(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
2101{
2102 query_index(shared->mailbox, shared->sub);
2103 return FR_SUCCESS;
2104}
2105
2109static int op_quit(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
2110{
2111 if (shared->attach_msg)
2112 return FR_DONE;
2113
2114 if (query_quadoption(_("Quit NeoMutt?"), shared->sub, "quit") == MUTT_YES)
2115 {
2116 priv->oldcount = shared->mailbox ? shared->mailbox->msg_count : 0;
2117
2119 mutt_debug(LL_NOTIFY, "NT_GLOBAL_SHUTDOWN\n");
2121
2122 enum MxStatus check = MX_STATUS_OK;
2123 if (!shared->mailbox_view || ((check = mx_mbox_close(shared->mailbox)) == MX_STATUS_OK))
2124 {
2125 mview_free(&shared->mailbox_view);
2126 mailbox_free(&shared->mailbox);
2127 return FR_DONE;
2128 }
2129
2130 if ((check == MX_STATUS_NEW_MAIL) || (check == MX_STATUS_REOPENED))
2131 {
2132 update_index(priv->menu, shared->mailbox_view, check, priv->oldcount, shared);
2133 }
2134
2135 menu_queue_redraw(priv->menu, MENU_REDRAW_FULL); /* new mail arrived? */
2137 }
2138
2139 return FR_NO_ACTION;
2140}
2141
2145static int op_recall_message(struct IndexSharedData *shared,
2146 struct IndexPrivateData *priv, int op)
2147{
2148 int rc = mutt_send_message(SEND_POSTPONED, NULL, NULL, shared->mailbox, NULL,
2149 shared->sub);
2151 return (rc == -1) ? FR_ERROR : FR_SUCCESS;
2152}
2153
2157static int op_reply(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
2158{
2159 if (!shared->email)
2160 return FR_NO_ACTION;
2161 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
2162 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
2163 const bool c_pgp_auto_decode = cs_subset_bool(shared->sub, "pgp_auto_decode");
2164 if (c_pgp_auto_decode &&
2165 (priv->tag_prefix || !(shared->email->security & PGP_TRADITIONAL_CHECKED)))
2166 {
2167 if (mutt_check_traditional_pgp(shared->mailbox, &ea))
2169 }
2170 int rc = mutt_send_message(SEND_REPLY, NULL, NULL, shared->mailbox, &ea,
2171 shared->sub);
2172 ARRAY_FREE(&ea);
2174
2175 return (rc == -1) ? FR_ERROR : FR_SUCCESS;
2176}
2177
2181static int op_resend(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
2182{
2183 int rc = -1;
2184 if (priv->tag_prefix)
2185 {
2186 struct Mailbox *m = shared->mailbox;
2187 for (size_t i = 0; i < m->msg_count; i++)
2188 {
2189 struct Email *e = m->emails[i];
2190 if (!e)
2191 break;
2192 if (message_is_tagged(e))
2193 rc = mutt_resend_message(NULL, shared->mailbox, e, shared->sub);
2194 }
2195 }
2196 else
2197 {
2198 rc = mutt_resend_message(NULL, shared->mailbox, shared->email, shared->sub);
2199 }
2200
2202 return (rc == -1) ? FR_ERROR : FR_SUCCESS;
2203}
2204
2216static int op_save(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
2217{
2218 if (((op == OP_DECRYPT_COPY) || (op == OP_DECRYPT_SAVE)) && !WithCrypto)
2219 return FR_NOT_IMPL;
2220
2221 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
2222 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
2223
2224 const enum MessageSaveOpt save_opt = ((op == OP_SAVE) || (op == OP_DECODE_SAVE) ||
2225 (op == OP_DECRYPT_SAVE)) ?
2226 SAVE_MOVE :
2227 SAVE_COPY;
2228
2229 enum MessageTransformOpt transform_opt =
2230 ((op == OP_DECODE_SAVE) || (op == OP_DECODE_COPY)) ? TRANSFORM_DECODE :
2231 ((op == OP_DECRYPT_SAVE) || (op == OP_DECRYPT_COPY)) ? TRANSFORM_DECRYPT :
2233
2234 const int rc = mutt_save_message(shared->mailbox, &ea, save_opt, transform_opt);
2235 if ((rc == 0) && (save_opt == SAVE_MOVE))
2236 {
2238 }
2239 ARRAY_FREE(&ea);
2240
2241 if (priv->tag_prefix)
2243
2244 return (rc == -1) ? FR_ERROR : FR_SUCCESS;
2245}
2246
2256static int op_search(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
2257{
2259 switch (op)
2260 {
2261 case OP_SEARCH:
2262 flags |= SEARCH_PROMPT;
2263 shared->search_state->reverse = false;
2264 break;
2265 case OP_SEARCH_REVERSE:
2266 flags |= SEARCH_PROMPT;
2267 shared->search_state->reverse = true;
2268 break;
2269 case OP_SEARCH_NEXT:
2270 break;
2271 case OP_SEARCH_OPPOSITE:
2272 flags |= SEARCH_OPPOSITE;
2273 break;
2274 }
2275
2276 // Initiating a search can happen on an empty mailbox, but
2277 // searching for next/previous/... needs to be on a message and
2278 // thus a non-empty mailbox
2279 int index = menu_get_index(priv->menu);
2280 index = mutt_search_command(shared->mailbox_view, priv->menu, index,
2281 shared->search_state, flags);
2282 if (index != -1)
2283 menu_set_index(priv->menu, index);
2284
2285 return FR_SUCCESS;
2286}
2287
2295static int op_sort(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
2296{
2297 if (!mutt_select_sort(op == OP_SORT_REVERSE))
2298 return FR_ERROR;
2299
2300 if (shared->mailbox && (shared->mailbox->msg_count != 0))
2301 {
2302 resort_index(shared->mailbox_view, priv->menu);
2304 }
2305
2306 return FR_SUCCESS;
2307}
2308
2312static int op_tag(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
2313{
2314 const bool c_auto_tag = cs_subset_bool(shared->sub, "auto_tag");
2315 if (priv->tag_prefix && !c_auto_tag)
2316 {
2317 struct Mailbox *m = shared->mailbox;
2318 for (size_t i = 0; i < m->msg_count; i++)
2319 {
2320 struct Email *e = m->emails[i];
2321 if (!e)
2322 break;
2323 if (e->visible)
2324 mutt_set_flag(m, e, MUTT_TAG, false, true);
2325 }
2327 return FR_SUCCESS;
2328 }
2329
2330 if (!shared->email)
2331 return FR_NO_ACTION;
2332
2333 mutt_set_flag(shared->mailbox, shared->email, MUTT_TAG, !shared->email->tagged, true);
2334
2335 resolve_email(priv, shared, RESOLVE_NEXT_EMAIL);
2336 return FR_SUCCESS;
2337}
2338
2346static int op_tag_thread(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
2347{
2348 if (!shared->email)
2349 return FR_NO_ACTION;
2350
2351 int rc = mutt_thread_set_flag(shared->mailbox, shared->email, MUTT_TAG,
2352 !shared->email->tagged, (op != OP_TAG_THREAD));
2353 if (rc != -1)
2354 {
2355 const enum ResolveMethod rm = (op == OP_TAG_THREAD) ? RESOLVE_NEXT_THREAD :
2357 resolve_email(priv, shared, rm);
2359 }
2360
2361 return FR_SUCCESS;
2362}
2363
2367static int op_toggle_new(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
2368{
2369 /* L10N: CHECK_ACL */
2370 if (!check_acl(shared->mailbox, MUTT_ACL_SEEN, _("Can't toggle new")))
2371 return FR_ERROR;
2372
2373 struct Mailbox *m = shared->mailbox;
2374 if (priv->tag_prefix)
2375 {
2376 for (size_t i = 0; i < m->msg_count; i++)
2377 {
2378 struct Email *e = m->emails[i];
2379 if (!e)
2380 break;
2381 if (!message_is_tagged(e))
2382 continue;
2383
2384 if (e->read || e->old)
2385 mutt_set_flag(m, e, MUTT_NEW, true, true);
2386 else
2387 mutt_set_flag(m, e, MUTT_READ, true, true);
2388 }
2390 }
2391 else
2392 {
2393 if (!shared->email)
2394 return FR_NO_ACTION;
2395 if (shared->email->read || shared->email->old)
2396 mutt_set_flag(m, shared->email, MUTT_NEW, true, true);
2397 else
2398 mutt_set_flag(m, shared->email, MUTT_READ, true, true);
2399
2401 }
2402
2403 return FR_SUCCESS;
2404}
2405
2409static int op_toggle_write(struct IndexSharedData *shared,
2410 struct IndexPrivateData *priv, int op)
2411{
2412 mx_toggle_write(shared->mailbox);
2413 return FR_SUCCESS;
2414}
2415
2419static int op_undelete(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
2420{
2421 /* L10N: CHECK_ACL */
2422 if (!check_acl(shared->mailbox, MUTT_ACL_DELETE, _("Can't undelete message")))
2423 return FR_ERROR;
2424
2425 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
2426 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
2427
2428 mutt_emails_set_flag(shared->mailbox, &ea, MUTT_DELETE, false);
2429 mutt_emails_set_flag(shared->mailbox, &ea, MUTT_PURGE, false);
2430 ARRAY_FREE(&ea);
2431
2432 if (priv->tag_prefix)
2433 {
2435 }
2436 else
2437 {
2438 resolve_email(priv, shared, RESOLVE_NEXT_EMAIL);
2439 }
2440
2441 return FR_SUCCESS;
2442}
2443
2451static int op_undelete_thread(struct IndexSharedData *shared,
2452 struct IndexPrivateData *priv, int op)
2453{
2454 /* L10N: CHECK_ACL */
2455 /* L10N: Due to the implementation details we do not know whether we
2456 undelete zero, 1, 12, ... messages. So in English we use
2457 "messages". Your language might have other means to express this. */
2458 if (!check_acl(shared->mailbox, MUTT_ACL_DELETE, _("Can't undelete messages")))
2459 return FR_ERROR;
2460
2461 int rc = mutt_thread_set_flag(shared->mailbox, shared->email, MUTT_DELETE,
2462 false, (op != OP_UNDELETE_THREAD));
2463 if (rc != -1)
2464 {
2465 rc = mutt_thread_set_flag(shared->mailbox, shared->email, MUTT_PURGE, false,
2466 (op != OP_UNDELETE_THREAD));
2467 }
2468 if (rc != -1)
2469 {
2470 const enum ResolveMethod rm = (op == OP_UNDELETE_THREAD) ? RESOLVE_NEXT_THREAD :
2472 resolve_email(priv, shared, rm);
2474 }
2475
2476 return FR_SUCCESS;
2477}
2478
2482static int op_view_attachments(struct IndexSharedData *shared,
2483 struct IndexPrivateData *priv, int op)
2484{
2485 if (!shared->email)
2486 return FR_NO_ACTION;
2487
2488 enum FunctionRetval rc = FR_ERROR;
2489 struct Message *msg = mx_msg_open(shared->mailbox, shared->email);
2490 if (msg)
2491 {
2492 dlg_attachment(NeoMutt->sub, shared->mailbox_view, shared->email, msg->fp,
2493 shared->attach_msg);
2494 if (shared->email->attach_del)
2495 {
2496 shared->mailbox->changed = true;
2497 }
2498 mx_msg_close(shared->mailbox, &msg);
2499 rc = FR_SUCCESS;
2500 }
2502 return rc;
2503}
2504
2505// -----------------------------------------------------------------------------
2506
2507#ifdef USE_AUTOCRYPT
2511static int op_autocrypt_acct_menu(struct IndexSharedData *shared,
2512 struct IndexPrivateData *priv, int op)
2513{
2514 dlg_autocrypt();
2515 return FR_SUCCESS;
2516}
2517#endif
2518
2522static int op_main_imap_fetch(struct IndexSharedData *shared,
2523 struct IndexPrivateData *priv, int op)
2524{
2525 if (!shared->mailbox || (shared->mailbox->type != MUTT_IMAP))
2526 return FR_NO_ACTION;
2527
2528 imap_check_mailbox(shared->mailbox, true);
2529 return FR_SUCCESS;
2530}
2531
2536 struct IndexPrivateData *priv, int op)
2537{
2538 if (shared->mailbox && (shared->mailbox->type == MUTT_IMAP))
2539 {
2540 const enum MxStatus check = mx_mbox_close(shared->mailbox);
2541 if (check == MX_STATUS_OK)
2542 {
2543 mview_free(&shared->mailbox_view);
2544 }
2545 else
2546 {
2547 if ((check == MX_STATUS_NEW_MAIL) || (check == MX_STATUS_REOPENED))
2548 {
2549 update_index(priv->menu, shared->mailbox_view, check, priv->oldcount, shared);
2550 }
2553 return FR_ERROR;
2554 }
2555 }
2557 mutt_message(_("Logged out of IMAP servers"));
2560
2561 return FR_SUCCESS;
2562}
2563
2567static int op_catchup(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
2568{
2569 struct Mailbox *m = shared->mailbox;
2570 if (!m || (m->type != MUTT_NNTP))
2571 return FR_NO_ACTION;
2572
2573 struct NntpMboxData *mdata = m->mdata;
2574 if (mutt_newsgroup_catchup(m, mdata->adata, mdata->group))
2576
2577 return FR_SUCCESS;
2578}
2579
2587static int op_get_children(struct IndexSharedData *shared,
2588 struct IndexPrivateData *priv, int op)
2589{
2590 struct Mailbox *m = shared->mailbox;
2591 if (m->type != MUTT_NNTP)
2592 return FR_ERROR;
2593
2594 struct Email *e = shared->email;
2595 if (!e)
2596 return FR_NO_ACTION;
2597
2598 char buf[PATH_MAX] = { 0 };
2599 int oldmsgcount = m->msg_count;
2600 int oldindex = e->index;
2601 int rc = 0;
2602
2603 if (!e->env->message_id)
2604 {
2605 mutt_error(_("No Message-Id. Unable to perform operation."));
2606 return FR_ERROR;
2607 }
2608
2609 mutt_message(_("Fetching message headers..."));
2610 if (!m->id_hash)
2611 m->id_hash = mutt_make_id_hash(m);
2612 mutt_str_copy(buf, e->env->message_id, sizeof(buf));
2613
2614 /* trying to find msgid of the root message */
2615 if (op == OP_RECONSTRUCT_THREAD)
2616 {
2617 struct ListNode *ref = NULL;
2618 STAILQ_FOREACH(ref, &e->env->references, entries)
2619 {
2620 if (!mutt_hash_find(m->id_hash, ref->data))
2621 {
2622 rc = nntp_check_msgid(m, ref->data);
2623 if (rc < 0)
2624 return FR_ERROR;
2625 }
2626
2627 /* the last msgid in References is the root message */
2628 if (!STAILQ_NEXT(ref, entries))
2629 mutt_str_copy(buf, ref->data, sizeof(buf));
2630 }
2631 }
2632
2633 /* fetching all child messages */
2634 rc = nntp_check_children(m, buf);
2635
2636 /* at least one message has been loaded */
2637 if (m->msg_count > oldmsgcount)
2638 {
2639 bool verbose = m->verbose;
2640
2641 if (rc < 0)
2642 m->verbose = false;
2643
2644 struct MailboxView *mv = shared->mailbox_view;
2645 mutt_sort_headers(mv, (op == OP_RECONSTRUCT_THREAD));
2646 m->verbose = verbose;
2647
2648 /* if the root message was retrieved, move to it */
2649 struct Email *e2 = mutt_hash_find(m->id_hash, buf);
2650 if (e2)
2651 {
2652 menu_set_index(priv->menu, e2->vnum);
2653 }
2654 else
2655 {
2656 /* try to restore old position */
2657 for (int i = 0; i < m->msg_count; i++)
2658 {
2659 e2 = m->emails[i];
2660 if (!e2)
2661 break;
2662 if (e2->index == oldindex)
2663 {
2664 menu_set_index(priv->menu, e2->vnum);
2665 /* as an added courtesy, recenter the menu
2666 * with the current entry at the middle of the screen */
2668 }
2669 }
2670 }
2672 }
2673 else if (rc >= 0)
2674 {
2675 mutt_error(_("No deleted messages found in the thread"));
2676 }
2677
2678 return FR_SUCCESS;
2679}
2680
2688static int op_get_message(struct IndexSharedData *shared,
2689 struct IndexPrivateData *priv, int op)
2690{
2691 struct Mailbox *m = shared->mailbox;
2692 if (m->type != MUTT_NNTP)
2693 return FR_SUCCESS;
2694
2695 int rc = FR_ERROR;
2696 struct Buffer *buf = buf_pool_get();
2697
2698 if (op == OP_GET_MESSAGE)
2699 {
2700 if ((mw_get_field(_("Enter Message-Id: "), buf, MUTT_COMP_NO_FLAGS,
2701 HC_OTHER, NULL, NULL) != 0) ||
2702 buf_is_empty(buf))
2703 {
2704 goto done;
2705 }
2706 }
2707 else
2708 {
2709 struct Email *e = shared->email;
2710 if (!e || STAILQ_EMPTY(&e->env->references))
2711 {
2712 mutt_error(_("Article has no parent reference"));
2713 goto done;
2714 }
2715 buf_strcpy(buf, STAILQ_FIRST(&e->env->references)->data);
2716 }
2717
2718 if (!m->id_hash)
2719 m->id_hash = mutt_make_id_hash(m);
2720 struct Email *e = mutt_hash_find(m->id_hash, buf_string(buf));
2721 if (e)
2722 {
2723 if (e->vnum != -1)
2724 {
2725 menu_set_index(priv->menu, e->vnum);
2726 }
2727 else if (e->collapsed)
2728 {
2730 mutt_set_vnum(m);
2731 menu_set_index(priv->menu, e->vnum);
2732 }
2733 else
2734 {
2735 mutt_error(_("Message is not visible in limited view"));
2736 }
2737 }
2738 else
2739 {
2740 mutt_message(_("Fetching %s from server..."), buf_string(buf));
2741 int rc2 = nntp_check_msgid(m, buf_string(buf));
2742 if (rc2 == 0)
2743 {
2744 e = m->emails[m->msg_count - 1];
2745 struct MailboxView *mv = shared->mailbox_view;
2746 mutt_sort_headers(mv, false);
2747 menu_set_index(priv->menu, e->vnum);
2749 rc = FR_SUCCESS;
2750 }
2751 else if (rc2 > 0)
2752 {
2753 mutt_error(_("Article %s not found on the server"), buf_string(buf));
2754 }
2755 }
2756
2757done:
2758 buf_pool_release(&buf);
2759 return rc;
2760}
2761
2769static int op_main_change_group(struct IndexSharedData *shared,
2770 struct IndexPrivateData *priv, int op)
2771{
2772 struct Buffer *folderbuf = buf_pool_get();
2773 buf_alloc(folderbuf, PATH_MAX);
2774
2775 OptNews = false;
2776 bool read_only;
2777 char *cp = NULL;
2778 const bool c_read_only = cs_subset_bool(shared->sub, "read_only");
2779 if (shared->attach_msg || c_read_only || (op == OP_MAIN_CHANGE_GROUP_READONLY))
2780 {
2781 cp = _("Open newsgroup in read-only mode");
2782 read_only = true;
2783 }
2784 else
2785 {
2786 cp = _("Open newsgroup");
2787 read_only = false;
2788 }
2789
2790 const bool c_change_folder_next = cs_subset_bool(shared->sub, "change_folder_next");
2791 if (c_change_folder_next && shared->mailbox && !buf_is_empty(&shared->mailbox->pathbuf))
2792 {
2793 buf_strcpy(folderbuf, mailbox_path(shared->mailbox));
2794 buf_pretty_mailbox(folderbuf);
2795 }
2796
2797 OptNews = true;
2798 const char *const c_news_server = cs_subset_string(shared->sub, "news_server");
2799 if (!CurrentNewsSrv)
2800 CurrentNewsSrv = nntp_select_server(shared->mailbox, c_news_server, false);
2801 if (!CurrentNewsSrv)
2802 goto changefoldercleanup2;
2803
2804 nntp_mailbox(shared->mailbox, folderbuf->data, folderbuf->dsize);
2805
2806 if (mw_enter_fname(cp, folderbuf, true, shared->mailbox, false, NULL, NULL,
2807 MUTT_SEL_NO_FLAGS) == -1)
2808 {
2809 goto changefoldercleanup2;
2810 }
2811
2812 /* Selected directory is okay, let's save it. */
2814
2815 if (buf_is_empty(folderbuf))
2816 {
2817 msgwin_clear_text(NULL);
2818 goto changefoldercleanup2;
2819 }
2820
2821 struct Mailbox *m = mx_mbox_find2(buf_string(folderbuf));
2822 if (m)
2823 {
2824 change_folder_mailbox(priv->menu, m, &priv->oldcount, shared, read_only);
2825 }
2826 else
2827 {
2828 change_folder_string(priv->menu, folderbuf, &priv->oldcount, shared, read_only);
2829 }
2830 struct MuttWindow *dlg = dialog_find(priv->win_index);
2831 dlg->help_data = IndexNewsHelp;
2832
2833changefoldercleanup2:
2834 buf_pool_release(&folderbuf);
2835 return FR_SUCCESS;
2836}
2837
2845static int op_post(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
2846{
2847 if (!shared->email)
2848 return FR_NO_ACTION;
2849
2850 if ((op != OP_FOLLOWUP) || !shared->email->env->followup_to ||
2851 !mutt_istr_equal(shared->email->env->followup_to, "poster") ||
2852 (query_quadoption(_("Reply by mail as poster prefers?"), shared->sub,
2853 "followup_to_poster") != MUTT_YES))
2854 {
2855 if (shared->mailbox && (shared->mailbox->type == MUTT_NNTP) &&
2856 !((struct NntpMboxData *) shared->mailbox->mdata)->allowed &&
2857 (query_quadoption(_("Posting to this group not allowed, may be moderated. Continue?"),
2858 shared->sub, "post_moderated") != MUTT_YES))
2859 {
2860 return FR_ERROR;
2861 }
2862 if (op == OP_POST)
2863 {
2864 mutt_send_message(SEND_NEWS, NULL, NULL, shared->mailbox, NULL, shared->sub);
2865 }
2866 else
2867 {
2868 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
2869 ea_add_tagged(&ea, shared->mailbox_view, shared->email, priv->tag_prefix);
2870 mutt_send_message(((op == OP_FOLLOWUP) ? SEND_REPLY : SEND_FORWARD) | SEND_NEWS,
2871 NULL, NULL, shared->mailbox, &ea, shared->sub);
2872 ARRAY_FREE(&ea);
2873 }
2875 return FR_SUCCESS;
2876 }
2877
2878 return op_reply(shared, priv, OP_REPLY);
2879}
2880
2881#ifdef USE_NOTMUCH
2885static int op_main_entire_thread(struct IndexSharedData *shared,
2886 struct IndexPrivateData *priv, int op)
2887{
2888 if (shared->mailbox->type != MUTT_NOTMUCH)
2889 {
2890 if (((shared->mailbox->type != MUTT_MH) && (shared->mailbox->type != MUTT_MAILDIR)) ||
2891 (!shared->email || !shared->email->env || !shared->email->env->message_id))
2892 {
2893 mutt_message(_("No virtual folder and no Message-Id, aborting"));
2894 return FR_ERROR;
2895 } // no virtual folder, but we have message-id, reconstruct thread on-the-fly
2896 char buf[PATH_MAX] = { 0 };
2897 strncpy(buf, "id:", sizeof(buf));
2898 int msg_id_offset = 0;
2899 if ((shared->email->env->message_id)[0] == '<')
2900 msg_id_offset = 1;
2901 mutt_str_cat(buf, sizeof(buf), (shared->email->env->message_id) + msg_id_offset);
2902 if (buf[strlen(buf) - 1] == '>')
2903 buf[strlen(buf) - 1] = '\0';
2904
2905 change_folder_notmuch(priv->menu, buf, sizeof(buf), &priv->oldcount, shared, false);
2906
2907 // If notmuch doesn't contain the message, we're left in an empty
2908 // vfolder. No messages are found, but nm_read_entire_thread assumes
2909 // a valid message-id and will throw a segfault.
2910 //
2911 // To prevent that, stay in the empty vfolder and print an error.
2912 if (shared->mailbox->msg_count == 0)
2913 {
2914 mutt_error(_("failed to find message in notmuch database. try running 'notmuch new'."));
2915 return FR_ERROR;
2916 }
2917 }
2918 priv->oldcount = shared->mailbox->msg_count;
2919 int index = menu_get_index(priv->menu);
2920 struct Email *e_oldcur = mutt_get_virt_email(shared->mailbox, index);
2921 if (!e_oldcur)
2922 return FR_ERROR;
2923
2924 if (nm_read_entire_thread(shared->mailbox, e_oldcur) < 0)
2925 {
2926 mutt_message(_("Failed to read thread, aborting"));
2927 return FR_ERROR;
2928 }
2929
2930 // nm_read_entire_thread() may modify msg_count and menu won't be updated.
2931 priv->menu->max = shared->mailbox->msg_count;
2932
2933 if (priv->oldcount < shared->mailbox->msg_count)
2934 {
2935 /* nm_read_entire_thread() triggers mutt_sort_headers() if necessary */
2936 index = e_oldcur->vnum;
2937 if (e_oldcur->collapsed || shared->mailbox_view->collapsed)
2938 {
2939 index = mutt_uncollapse_thread(e_oldcur);
2940 mutt_set_vnum(shared->mailbox);
2941 }
2942 menu_set_index(priv->menu, index);
2944 }
2945
2946 return FR_SUCCESS;
2947}
2948
2957 struct IndexPrivateData *priv, int op)
2958{
2959 int rc = FR_SUCCESS;
2960 struct Buffer *buf = buf_pool_get();
2961
2962 if ((mw_get_field("Query: ", buf, MUTT_COMP_NO_FLAGS, HC_OTHER,
2963 &CompleteNmQueryOps, NULL) != 0) ||
2964 buf_is_empty(buf))
2965 {
2966 mutt_message(_("No query, aborting"));
2967 rc = FR_NO_ACTION;
2968 goto done;
2969 }
2970
2971 // Keep copy of user's query to name the mailbox
2972 char *query_unencoded = buf_strdup(buf);
2973
2974 buf_alloc(buf, PATH_MAX);
2975 struct Mailbox *m_query = change_folder_notmuch(priv->menu, buf->data, buf->dsize,
2976 &priv->oldcount, shared,
2977 (op == OP_MAIN_VFOLDER_FROM_QUERY_READONLY));
2978 if (m_query)
2979 {
2980 FREE(&m_query->name);
2981 m_query->name = query_unencoded;
2982 query_unencoded = NULL;
2983 rc = FR_SUCCESS;
2984 }
2985 else
2986 {
2987 FREE(&query_unencoded);
2988 }
2989
2990done:
2991 buf_pool_release(&buf);
2992 return rc;
2993}
2994
3004 struct IndexPrivateData *priv, int op)
3005{
3006 // Common guard clauses.
3008 {
3009 mutt_message(_("Windowed queries disabled"));
3010 return FR_ERROR;
3011 }
3012 const char *const c_nm_query_window_current_search = cs_subset_string(shared->sub, "nm_query_window_current_search");
3013 if (!c_nm_query_window_current_search)
3014 {
3015 mutt_message(_("No notmuch vfolder currently loaded"));
3016 return FR_ERROR;
3017 }
3018
3019 // Call the specific operation.
3020 switch (op)
3021 {
3022 case OP_MAIN_WINDOWED_VFOLDER_BACKWARD:
3024 break;
3025 case OP_MAIN_WINDOWED_VFOLDER_FORWARD:
3027 break;
3028 case OP_MAIN_WINDOWED_VFOLDER_RESET:
3030 break;
3031 }
3032
3033 // Common query window folder change.
3034 char buf[PATH_MAX] = { 0 };
3035 mutt_str_copy(buf, c_nm_query_window_current_search, sizeof(buf));
3036 change_folder_notmuch(priv->menu, buf, sizeof(buf), &priv->oldcount, shared, false);
3037
3038 return FR_SUCCESS;
3039}
3040#endif
3041
3045static int op_main_fetch_mail(struct IndexSharedData *shared,
3046 struct IndexPrivateData *priv, int op)
3047{
3050 return FR_SUCCESS;
3051}
3052
3053// -----------------------------------------------------------------------------
3054
3062static bool prereq(struct IndexSharedData *shared, struct Menu *menu, CheckFlags checks)
3063{
3064 bool result = true;
3065 struct MailboxView *mv = shared->mailbox_view;
3066
3067 if (checks & (CHECK_MSGCOUNT | CHECK_VISIBLE | CHECK_READONLY))
3068 checks |= CHECK_IN_MAILBOX;
3069
3070 if ((checks & CHECK_IN_MAILBOX) && (!mv || !mv->mailbox))
3071 {
3072 mutt_error(_("No mailbox is open"));
3073 result = false;
3074 }
3075
3076 if (result && (checks & CHECK_MSGCOUNT) && (mv->mailbox->msg_count == 0))
3077 {
3078 mutt_error(_("There are no messages"));
3079 result = false;
3080 }
3081
3082 int index = menu_get_index(menu);
3083 if (result && (checks & CHECK_VISIBLE) &&
3084 ((index < 0) || (index >= mv->mailbox->vcount)))
3085 {
3086 mutt_error(_("No visible messages"));
3087 result = false;
3088 }
3089
3090 if (result && (checks & CHECK_READONLY) && mv->mailbox->readonly)
3091 {
3092 mutt_error(_("Mailbox is read-only"));
3093 result = false;
3094 }
3095
3096 if (result && (checks & CHECK_ATTACH) && shared->attach_msg)
3097 {
3098 mutt_error(_("Function not permitted in attach-message mode"));
3099 result = false;
3100 }
3101
3102 if (!result)
3103 mutt_flushinp();
3104
3105 return result;
3106}
3107
3111static const struct IndexFunction IndexFunctions[] = {
3112 // clang-format off
3113 { OP_ALIAS_DIALOG, op_alias_dialog, CHECK_NO_FLAGS },
3119 { OP_COPY_MESSAGE, op_save, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3120 { OP_CREATE_ALIAS, op_create_alias, CHECK_NO_FLAGS },
3121 { OP_DECODE_COPY, op_save, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3122 { OP_DECODE_SAVE, op_save, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3123 { OP_DECRYPT_COPY, op_save, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3124 { OP_DECRYPT_SAVE, op_save, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3132 { OP_EDIT_OR_VIEW_RAW_MESSAGE, op_edit_raw_message, CHECK_ATTACH | CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3134 { OP_END_COND, op_end_cond, CHECK_NO_FLAGS },
3135 { OP_EXIT, op_exit, CHECK_NO_FLAGS },
3139 { OP_FORGET_PASSPHRASE, op_forget_passphrase, CHECK_NO_FLAGS },
3141 { OP_FORWARD_TO_GROUP, op_post, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3145 { OP_GENERIC_SELECT_ENTRY, op_display_message, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3148 { OP_JUMP, op_jump, CHECK_IN_MAILBOX },
3149 { OP_JUMP_1, op_jump, CHECK_IN_MAILBOX },
3150 { OP_JUMP_2, op_jump, CHECK_IN_MAILBOX },
3151 { OP_JUMP_3, op_jump, CHECK_IN_MAILBOX },
3152 { OP_JUMP_4, op_jump, CHECK_IN_MAILBOX },
3153 { OP_JUMP_5, op_jump, CHECK_IN_MAILBOX },
3154 { OP_JUMP_6, op_jump, CHECK_IN_MAILBOX },
3155 { OP_JUMP_7, op_jump, CHECK_IN_MAILBOX },
3156 { OP_JUMP_8, op_jump, CHECK_IN_MAILBOX },
3157 { OP_JUMP_9, op_jump, CHECK_IN_MAILBOX },
3158 { OP_LIMIT_CURRENT_THREAD, op_main_limit, CHECK_IN_MAILBOX },
3162 { OP_MAIL, op_mail, CHECK_ATTACH },
3163 { OP_MAILBOX_LIST, op_mailbox_list, CHECK_NO_FLAGS },
3164 { OP_MAIL_KEY, op_mail_key, CHECK_ATTACH },
3166 { OP_MAIN_CHANGE_FOLDER, op_main_change_folder, CHECK_NO_FLAGS },
3167 { OP_MAIN_CHANGE_FOLDER_READONLY, op_main_change_folder, CHECK_NO_FLAGS },
3168 { OP_MAIN_CHANGE_GROUP, op_main_change_group, CHECK_NO_FLAGS },
3169 { OP_MAIN_CHANGE_GROUP_READONLY, op_main_change_group, CHECK_NO_FLAGS },
3171 { OP_MAIN_COLLAPSE_ALL, op_main_collapse_all, CHECK_IN_MAILBOX },
3172 { OP_MAIN_COLLAPSE_THREAD, op_main_collapse_thread, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3173 { OP_MAIN_DELETE_PATTERN, op_main_delete_pattern, CHECK_ATTACH | CHECK_IN_MAILBOX | CHECK_READONLY },
3174 { OP_MAIN_FETCH_MAIL, op_main_fetch_mail, CHECK_ATTACH },
3175 { OP_MAIN_IMAP_FETCH, op_main_imap_fetch, CHECK_NO_FLAGS },
3176 { OP_MAIN_IMAP_LOGOUT_ALL, op_main_imap_logout_all, CHECK_NO_FLAGS },
3177 { OP_MAIN_LIMIT, op_main_limit, CHECK_IN_MAILBOX },
3180 { OP_MAIN_MODIFY_TAGS_THEN_HIDE, op_main_modify_tags, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_READONLY | CHECK_VISIBLE },
3182 { OP_MAIN_NEXT_NEW_THEN_UNREAD, op_main_next_new, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3183 { OP_MAIN_NEXT_SUBTHREAD, op_main_next_thread, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3186 { OP_MAIN_NEXT_UNREAD, op_main_next_new, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3187 { OP_MAIN_NEXT_UNREAD_MAILBOX, op_main_next_unread_mailbox, CHECK_IN_MAILBOX },
3188 { OP_MAIN_PARENT_MESSAGE, op_main_root_message, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3190 { OP_MAIN_PREV_NEW_THEN_UNREAD, op_main_next_new, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3191 { OP_MAIN_PREV_SUBTHREAD, op_main_next_thread, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3194 { OP_MAIN_PREV_UNREAD, op_main_next_new, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3200 { OP_MAIN_SHOW_LIMIT, op_main_show_limit, CHECK_IN_MAILBOX },
3201 { OP_MAIN_SYNC_FOLDER, op_main_sync_folder, CHECK_NO_FLAGS },
3202 { OP_MAIN_TAG_PATTERN, op_main_tag_pattern, CHECK_IN_MAILBOX },
3203 { OP_MAIN_UNDELETE_PATTERN, op_main_undelete_pattern, CHECK_IN_MAILBOX | CHECK_READONLY },
3204 { OP_MAIN_UNTAG_PATTERN, op_main_untag_pattern, CHECK_IN_MAILBOX },
3208 { OP_POST, op_post, CHECK_ATTACH | CHECK_IN_MAILBOX },
3213 { OP_QUERY, op_query, CHECK_ATTACH },
3214 { OP_QUIT, op_quit, CHECK_NO_FLAGS },
3215 { OP_RECALL_MESSAGE, op_recall_message, CHECK_ATTACH },
3220 { OP_SEARCH, op_search, CHECK_IN_MAILBOX },
3221 { OP_SEARCH_NEXT, op_search, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3222 { OP_SEARCH_OPPOSITE, op_search, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3223 { OP_SEARCH_REVERSE, op_search, CHECK_IN_MAILBOX | CHECK_MSGCOUNT | CHECK_VISIBLE },
3224 { OP_SORT, op_sort, CHECK_NO_FLAGS },
3225 { OP_SORT_REVERSE, op_sort, CHECK_NO_FLAGS },
3230 { OP_TOGGLE_READ, op_main_limit, CHECK_IN_MAILBOX },
3231 { OP_TOGGLE_WRITE, op_toggle_write, CHECK_IN_MAILBOX },
3237#ifdef USE_AUTOCRYPT
3238 { OP_AUTOCRYPT_ACCT_MENU, op_autocrypt_acct_menu, CHECK_NO_FLAGS },
3239#endif
3240#ifdef USE_NOTMUCH
3241 { OP_MAIN_CHANGE_VFOLDER, op_main_change_folder, CHECK_NO_FLAGS },
3243 { OP_MAIN_VFOLDER_FROM_QUERY, op_main_vfolder_from_query, CHECK_NO_FLAGS },
3244 { OP_MAIN_VFOLDER_FROM_QUERY_READONLY, op_main_vfolder_from_query, CHECK_NO_FLAGS },
3245 { OP_MAIN_WINDOWED_VFOLDER_BACKWARD, op_main_windowed_vfolder, CHECK_IN_MAILBOX },
3246 { OP_MAIN_WINDOWED_VFOLDER_FORWARD, op_main_windowed_vfolder, CHECK_IN_MAILBOX },
3247 { OP_MAIN_WINDOWED_VFOLDER_RESET, op_main_windowed_vfolder, CHECK_IN_MAILBOX },
3248#endif
3249 { 0, NULL, CHECK_NO_FLAGS },
3250 // clang-format on
3251};
3252
3257{
3258 if (!win)
3259 {
3261 return FR_ERROR;
3262 }
3263
3264 struct MuttWindow *dlg = dialog_find(win);
3265 if (!dlg || !dlg->wdata || !win->parent || !win->parent->wdata)
3266 return FR_ERROR;
3267
3268 struct IndexPrivateData *priv = win->parent->wdata;
3269 struct IndexSharedData *shared = dlg->wdata;
3270
3271 int rc = FR_UNKNOWN;
3272 for (size_t i = 0; IndexFunctions[i].op != OP_NULL; i++)
3273 {
3274 const struct IndexFunction *fn = &IndexFunctions[i];
3275 if (fn->op == op)
3276 {
3277 if (!prereq(shared, priv->menu, fn->flags))
3278 {
3279 rc = FR_ERROR;
3280 break;
3281 }
3282 rc = fn->function(shared, priv, op);
3283 break;
3284 }
3285 }
3286
3287 if (rc == FR_UNKNOWN) // Not our function
3288 return rc;
3289
3290 const char *result = dispatcher_get_retval_name(rc);
3291 mutt_debug(LL_DEBUG1, "Handled %s (%d) -> %s\n", opcodes_get_name(op), op, NONULL(result));
3292
3293 return rc;
3294}
Email Aliases.
void alias_create(struct AddressList *al, const struct ConfigSubset *sub)
Create a new Alias from an Address.
Definition: alias.c:367
struct AddressList * mutt_get_address(struct Envelope *env, const char **prefix)
Get an Address from an Envelope.
Definition: alias.c:327
#define ARRAY_FREE(head)
Release all memory.
Definition: array.h:204
#define ARRAY_HEAD_INITIALIZER
Static initializer for arrays.
Definition: array.h:58
static const char * Not_available_in_this_menu
Error message for unavailable functions.
Definition: functions.c:55
GUI display the mailboxes in a side panel.
Autocrypt end-to-end encryption.
int bool_str_toggle(struct ConfigSubset *sub, const char *name, struct Buffer *err)
Toggle the value of a bool.
Definition: bool.c:224
Select a Mailbox from a list.
#define MUTT_SEL_NO_FLAGS
No flags are set.
Definition: lib.h:57
int buf_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:160
bool buf_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:290
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:394
char * buf_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition: buffer.c:570
void buf_alloc(struct Buffer *buf, size_t new_size)
Make sure a buffer can store at least new_size bytes.
Definition: buffer.c:336
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:96
void mutt_pattern_free(struct PatternList **pat)
Free a Pattern.
Definition: compile.c:777
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:292
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:48
Convenience wrapper for the config headers.
Convenience wrapper for the core headers.
void mailbox_free(struct Mailbox **ptr)
Free a Mailbox.
Definition: mailbox.c:90
@ NT_MAILBOX_CHANGE
Mailbox has been changed.
Definition: mailbox.h:185
#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:223
#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
void crypt_extract_keys_from_messages(struct Mailbox *m, struct EmailArray *ea)
Extract keys from a message.
Definition: crypt.c:844
void crypt_forget_passphrase(void)
Forget a passphrase and display a message.
Definition: crypt.c:90
int digit(const char *s)
void mutt_flushinp(void)
Empty all the keyboard buffers.
Definition: get.c:57
void mutt_unget_ch(int ch)
Return a keystroke to the input buffer.
Definition: get.c:114
struct MuttWindow * dialog_find(struct MuttWindow *win)
Find the parent Dialog of a Window.
Definition: dialog.c:89
const char * dispatcher_get_retval_name(int rv)
Get the name of a return value.
Definition: dispatcher.c:54
FunctionRetval
Possible return values for NeoMutt functions.
Definition: dispatcher.h:32
@ FR_SUCCESS
Valid function - successfully performed.
Definition: dispatcher.h:39
@ FR_DONE
Exit the Dialog.
Definition: dispatcher.h:35
@ FR_UNKNOWN
Unknown function.
Definition: dispatcher.h:33
@ FR_ERROR
Valid function - error occurred.
Definition: dispatcher.h:38
@ FR_NOT_IMPL
Invalid function - feature not enabled.
Definition: dispatcher.h:36
@ FR_NO_ACTION
Valid function - no action performed.
Definition: dispatcher.h:37
void alias_dialog(struct Mailbox *m, struct ConfigSubset *sub)
Open the aliases dialog.
Definition: dlg_alias.c:567
void mutt_browser_select_dir(const char *f)
Remember the last directory selected.
Definition: dlg_browser.c:1273
bool check_acl(struct Mailbox *m, AclFlags acl, const char *msg)
Check the ACLs for a function.
Definition: dlg_index.c:140
const struct Mapping IndexNewsHelp[]
Help Bar for the News Index dialog.
Definition: dlg_index.c:119
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:734
void update_index(struct Menu *menu, struct MailboxView *mv, enum MxStatus check, int oldcount, const struct IndexSharedData *shared)
Update the index.
Definition: dlg_index.c:544
int find_first_message(struct MailboxView *mv)
Get index of first new message.
Definition: dlg_index.c:311
void resort_index(struct MailboxView *mv, struct Menu *menu)
Resort the index.
Definition: dlg_index.c:371
int find_next_undeleted(struct MailboxView *mv, int msgno, bool uncollapse)
Find the next undeleted email.
Definition: dlg_index.c:243
void collapse_all(struct MailboxView *mv, struct Menu *menu, int toggle)
Collapse/uncollapse all threads.
Definition: dlg_index.c:167
void change_folder_string(struct Menu *menu, struct Buffer *buf, int *oldcount, struct IndexSharedData *shared, bool read_only)
Change to a different Mailbox by string.
Definition: dlg_index.c:759
int find_previous_undeleted(struct MailboxView *mv, int msgno, bool uncollapse)
Find the previous undeleted email.
Definition: dlg_index.c:277
void query_index(struct Mailbox *m, struct ConfigSubset *sub)
Perform an Alias Query and display the results.
Definition: dlg_query.c:562
int mutt_ev_message(struct Mailbox *m, struct EmailArray *ea, enum EvMessage action)
Edit or view a message.
Definition: editmsg.c:283
Edit a string.
Structs that make up an email.
void mutt_print_message(struct Mailbox *m, struct EmailArray *ea)
Print a message.
Definition: external.c:439
bool mutt_select_sort(bool reverse)
Ask the user for a sort method.
Definition: external.c:477
void mutt_pipe_message(struct Mailbox *m, struct EmailArray *ea)
Pipe a message.
Definition: external.c:408
bool mutt_check_traditional_pgp(struct Mailbox *m, struct EmailArray *ea)
Check if a message has inline PGP content.
Definition: external.c:1212
void index_bounce_message(struct Mailbox *m, struct EmailArray *ea)
Bounce an email.
Definition: external.c:91
int mutt_save_message(struct Mailbox *m, struct EmailArray *ea, enum MessageSaveOpt save_opt, enum MessageTransformOpt transform_opt)
Save an email.
Definition: external.c:779
bool mutt_edit_content_type(struct Email *e, struct Body *b, FILE *fp)
Edit the content type of an attachment.
Definition: external.c:1071
void mutt_display_address(struct Envelope *env)
Display the address of a message.
Definition: external.c:662
Manage where the email is piped to external commands.
MessageTransformOpt
Message transformation option.
Definition: external.h:41
@ TRANSFORM_NONE
No transformation.
Definition: external.h:42
@ TRANSFORM_DECODE
Decode message.
Definition: external.h:44
@ TRANSFORM_DECRYPT
Decrypt message.
Definition: external.h:43
MessageSaveOpt
Message save option.
Definition: external.h:51
@ SAVE_MOVE
Move message to another mailbox, removing the original.
Definition: external.h:53
@ SAVE_COPY
Copy message, making a duplicate in another mailbox.
Definition: external.h:52
int mutt_file_sanitize_regex(struct Buffer *dest, const char *src)
Escape any regex-magic characters in a string.
Definition: file.c:751
void mutt_set_flag(struct Mailbox *m, struct Email *e, enum MessageType flag, bool bf, bool upd_mbox)
Set a flag on an email.
Definition: flags.c:57
void mutt_emails_set_flag(struct Mailbox *m, struct EmailArray *ea, enum MessageType flag, bool bf)
Set flag on messages.
Definition: flags.c:361
int mutt_thread_set_flag(struct Mailbox *m, struct Email *e, enum MessageType flag, bool bf, bool subthread)
Set a flag on an entire thread.
Definition: flags.c:385
bool OptNews
(pseudo) used to change reader mode
Definition: globals.c:70
bool OptNeedResort
(pseudo) used to force a re-sort
Definition: globals.c:69
static int op_delete(struct AliasMenuData *mdata, int op)
delete the current entry - Implements alias_function_t -
Definition: functions.c:159
static int op_main_limit(struct AliasMenuData *mdata, int op)
show only messages matching a pattern - Implements alias_function_t -
Definition: functions.c:235
static int op_exit(struct AliasMenuData *mdata, int op)
exit this menu - Implements alias_function_t -
Definition: functions.c:191
static int op_query(struct AliasMenuData *mdata, int op)
query external program for addresses - Implements alias_function_t -
Definition: functions.c:257
static int op_search(struct AliasMenuData *mdata, int op)
search for a regular expression - Implements alias_function_t -
Definition: functions.c:310
static int op_create_alias(struct AliasMenuData *mdata, int op)
create an alias from a message sender - Implements alias_function_t -
Definition: functions.c:119
static int op_sort(struct AliasMenuData *mdata, int op)
sort aliases - Implements alias_function_t -
Definition: functions.c:347
static int op_forward_message(struct AttachPrivateData *priv, int op)
forward a message with comments - Implements attach_function_t -
Definition: functions.c:564
static int op_bounce_message(struct AttachPrivateData *priv, int op)
remail a message to another user - Implements attach_function_t -
Definition: functions.c:479
static int op_attachment_edit_type(struct AttachPrivateData *priv, int op)
edit attachment content type - Implements attach_function_t -
Definition: functions.c:345
static int op_extract_keys(struct AttachPrivateData *priv, int op)
extract supported public keys - Implements attach_function_t -
Definition: functions.c:541
static int op_reply(struct AttachPrivateData *priv, int op)
reply to a message - Implements attach_function_t -
Definition: functions.c:598
static int op_compose_to_sender(struct AttachPrivateData *priv, int op)
compose new message to the current message sender - Implements attach_function_t -
Definition: functions.c:507
static int op_forget_passphrase(struct AttachPrivateData *priv, int op)
wipe passphrases from memory - Implements attach_function_t -
Definition: functions.c:555
static int op_list_subscribe(struct AttachPrivateData *priv, int op)
subscribe to a mailing list - Implements attach_function_t -
Definition: functions.c:578
static int op_list_unsubscribe(struct AttachPrivateData *priv, int op)
unsubscribe from a mailing list - Implements attach_function_t -
Definition: functions.c:588
static int op_check_traditional(struct AttachPrivateData *priv, int op)
check for classic PGP - Implements attach_function_t -
Definition: functions.c:493
static int op_resend(struct AttachPrivateData *priv, int op)
use the current message as a template for a new one - Implements attach_function_t -
Definition: functions.c:621
static int op_catchup(struct BrowserPrivateData *priv, int op)
Mark all articles in newsgroup as read - Implements browser_function_t -.
Definition: functions.c:302
static int op_mailbox_list(struct BrowserPrivateData *priv, int op)
List mailboxes with new mail - Implements browser_function_t -.
Definition: functions.c:837
int index_function_dispatcher(struct MuttWindow *win, int op)
Perform an Index function - Implements function_dispatcher_t -.
Definition: functions.c:3256
void dlg_autocrypt(void)
Display the Autocrypt account Menu -.
void dlg_attachment(struct ConfigSubset *sub, struct MailboxView *mv, struct Email *e, FILE *fp, bool attach_msg)
Show the attachments in a Menu -.
Definition: dlg_attach.c:539
int mw_change_flag(struct Mailbox *m, struct EmailArray *ea, bool bf)
Change the flag on a Message -.
Definition: flags.c:454
int mw_enter_fname(const char *prompt, struct Buffer *fname, bool mailbox, struct Mailbox *m, bool multiple, char ***files, int *numfiles, SelectFileFlags flags)
Ask the user to select a file -.
Definition: curs_lib.c:236
int mw_get_field(const char *prompt, struct Buffer *buf, CompletionFlags complete, enum HistoryClass hclass, const struct CompleteOps *comp_api, void *cdata)
Ask the user for a string -.
Definition: window.c:274
static int op_quit(struct HistoryData *hd, int op)
Quit this menu - Implements history_function_t -.
Definition: functions.c:52
static int op_main_link_threads(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Link tagged message to the current one - Implements index_function_t -.
Definition: functions.c:1291
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:1035
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:1787
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:1203
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:2367
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:1022
static int op_display_message(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Display a message - Implements index_function_t -.
Definition: functions.c:610
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:1632
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:3045
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:959
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:558
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:1665
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:2042
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:1688
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:2063
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:2026
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:1348
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:1850
static int op_autocrypt_acct_menu(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Manage autocrypt accounts - Implements index_function_t -.
Definition: functions.c:2511
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:758
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:713
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:2688
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:1466
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:2769
static int op_view_attachments(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Show MIME attachments - Implements index_function_t -.
Definition: functions.c:2482
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:2956
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:804
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:2535
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:1757
static int op_recall_message(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Recall a postponed message - Implements index_function_t -.
Definition: functions.c:2145
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:2587
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:2409
static int op_save(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Make decrypted copy - Implements index_function_t -.
Definition: functions.c:2216
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:2451
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: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:1959
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:678
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:2885
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:593
static int op_post(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Followup to newsgroup - Implements index_function_t -.
Definition: functions.c:2845
static int op_tag(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Tag the current entry - Implements index_function_t -.
Definition: functions.c:2312
static int op_tag_thread(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Tag the current thread - Implements index_function_t -.
Definition: functions.c:2346
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:1163
static int op_alias_dialog(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Open the aliases dialog - Implements index_function_t -.
Definition: functions.c:426
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:2522
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:1721
static int op_undelete(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Undelete the current entry - Implements index_function_t -.
Definition: functions.c:2419
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:1147
static int op_jump(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Jump to an index number - Implements index_function_t -.
Definition: functions.c:909
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:1937
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:1971
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:3003
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:1804
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:1590
static int op_group_reply(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Reply to all recipients - Implements index_function_t -.
Definition: functions.c:879
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:1829
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:1083
static int op_mail(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Compose a new mail message - Implements index_function_t -.
Definition: functions.c:1001
static int op_print(struct IndexSharedData *shared, struct IndexPrivateData *priv, int op)
Print the current entry - Implements index_function_t -.
Definition: functions.c:2079
#define mutt_warning(...)
Definition: logging2.h:90
#define mutt_error(...)
Definition: logging2.h:92
#define mutt_message(...)
Definition: logging2.h:91
#define mutt_debug(LEVEL,...)
Definition: logging2.h:89
Convenience wrapper for the gui headers.
void * mutt_hash_find(const struct HashTable *table, const char *strkey)
Find the HashElem data in a Hash Table element using a key.
Definition: hash.c:362
Read/write command history from/to a file.
@ HC_OTHER
Miscellaneous strings.
Definition: lib.h:56
void mutt_startup_shutdown_hook(HookFlags type)
Execute any startup/shutdown hooks.
Definition: hook.c:956
Parse and execute user-defined hooks.
#define MUTT_SHUTDOWN_HOOK
shutdown-hook: run when leaving NeoMutt
Definition: hook.h:55
IMAP network mailbox.
void imap_logout_all(void)
Close all open connections.
Definition: imap.c:555
enum MxStatus imap_check_mailbox(struct Mailbox *m, bool force)
Use the NOOP or IDLE command to poll for new mail.
Definition: imap.c:1031
const struct MenuFuncOp OpIndex[]
Functions for the Index Menu.
Definition: functions.c:95
bool index_next_undeleted(struct MuttWindow *win_index)
Select the next undeleted Email (if possible)
Definition: functions.c:395
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:346
const struct MenuOpSeq IndexDefaultBindings[]
Key bindings for the Index Menu.
Definition: functions.c:240
static bool prereq(struct IndexSharedData *shared, struct Menu *menu, CheckFlags checks)
Check the pre-requisites for a function.
Definition: functions.c:3062
static const struct IndexFunction IndexFunctions[]
All the NeoMutt functions that the Index supports.
Definition: functions.c:3111
ResolveMethod
How to advance the cursor.
Definition: functions.c:332
@ RESOLVE_NEXT_SUBTHREAD
Next sibling sub-thread.
Definition: functions.c:336
@ RESOLVE_NEXT_UNDELETED
Next undeleted email.
Definition: functions.c:334
@ RESOLVE_NEXT_EMAIL
Next email, whatever its state.
Definition: functions.c:333
@ RESOLVE_NEXT_THREAD
Next top-level thread.
Definition: functions.c:335
uint8_t CheckFlags
Flags, e.g. CHECK_IN_MAILBOX.
Definition: lib.h:67
#define CHECK_NO_FLAGS
No flags are set.
Definition: lib.h:68
#define CHECK_ATTACH
Is the user in message-attach mode?
Definition: lib.h:73
#define CHECK_VISIBLE
Is the selected message visible in the index?
Definition: lib.h:71
#define CHECK_IN_MAILBOX
Is there a mailbox open?
Definition: lib.h:69
#define CHECK_READONLY
Is the mailbox readonly?
Definition: lib.h:72
#define CHECK_MSGCOUNT
Are there any messages?
Definition: lib.h:70
#define NT_INDEX_EMAIL
Email has changed.
Definition: lib.h:65
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:235
Data shared between Index, Pager and Sidebar.
Manage keymappings.
enum CommandResult km_bind(char *s, enum MenuType menu, int op, char *macro, char *desc)
Bind a key to a macro.
Definition: parse.c:160
@ LL_DEBUG1
Log at debug level 1.
Definition: logging2.h:43
@ LL_NOTIFY
Log of notifications.
Definition: logging2.h:48
#define FREE(x)
Definition: memory.h:45
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:184
int menu_get_index(struct Menu *menu)
Get the current selection in the Menu.
Definition: menu.c:160
#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:174
void msgwin_clear_text(struct MuttWindow *win)
Clear the text in the Message Window.
Definition: msgwin.c:519
Convenience wrapper for the library headers.
#define N_(a)
Definition: message.h:32
#define _(a)
Definition: message.h:28
bool notify_send(struct Notify *notify, enum NotifyType event_type, int event_subtype, void *event_data)
Send out a notification message.
Definition: notify.c:173
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:721
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:474
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:630
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:329
char * mutt_str_cat(char *buf, size_t buflen, const char *s)
Concatenate two strings.
Definition: string.c:268
Many unsorted constants and some structs.
#define MUTT_COMP_NO_FLAGS
No flags are set.
Definition: mutt.h:56
@ MUTT_UNDELETE
Messages to be un-deleted.
Definition: mutt.h:76
@ MUTT_LIMIT
Messages in limited view.
Definition: mutt.h:82
@ MUTT_UNTAG
Messages to be un-tagged.
Definition: mutt.h:81
@ MUTT_READ
Messages that have been read.
Definition: mutt.h:73
@ MUTT_PURGE
Messages to be purged (bypass trash)
Definition: mutt.h:77
@ MUTT_TAG
Tagged messages.
Definition: mutt.h:80
@ MUTT_FLAG
Flagged messages.
Definition: mutt.h:79
@ MUTT_DELETE
Messages to be deleted.
Definition: mutt.h:75
@ MUTT_NEW
New messages.
Definition: mutt.h:70
#define PATH_MAX
Definition: mutt.h:42
int mutt_label_message(struct MailboxView *mv, struct EmailArray *ea)
Let the user label a message.
Definition: mutt_header.c:130
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:385
struct Mailbox * mutt_mailbox_next(struct Mailbox *m_cur, struct Buffer *s)
Incoming folders completion routine.
Definition: mutt_mailbox.c:359
bool mutt_mailbox_list(void)
Show a message with the list of mailboxes with new mail.
Definition: mutt_mailbox.c:247
Mailbox helper functions.
bool mutt_link_threads(struct Email *parent, struct EmailArray *children, struct Mailbox *m)
Forcibly link threads together.
Definition: mutt_thread.c:1748
void mutt_draw_tree(struct ThreadsContext *tctx)
Draw a tree of threaded emails.
Definition: mutt_thread.c:395
int mutt_messages_in_thread(struct Mailbox *m, struct Email *e, enum MessageInThread mit)
Count the messages in a thread.
Definition: mutt_thread.c:1658
off_t mutt_set_vnum(struct Mailbox *m)
Set the virtual index number of all the messages in a mailbox.
Definition: mutt_thread.c:1405
bool mutt_thread_can_collapse(struct Email *e)
Check whether a thread can be collapsed.
Definition: mutt_thread.c:1818
int mutt_parent_message(struct Email *e, bool find_root)
Find the parent of a message.
Definition: mutt_thread.c:1355
struct HashTable * mutt_make_id_hash(struct Mailbox *m)
Create a Hash Table for message-ids.
Definition: mutt_thread.c:1703
Create/manipulate threading in emails.
#define mutt_thread_next_unread(e)
Definition: mutt_thread.h:111
#define mutt_using_threads()
Definition: mutt_thread.h:114
#define mutt_previous_thread(e)
Definition: mutt_thread.h:121
#define mutt_uncollapse_thread(e)
Definition: mutt_thread.h:108
@ MIT_POSITION
Our position in the thread.
Definition: mutt_thread.h:90
#define mutt_next_subthread(e)
Definition: mutt_thread.h:122
#define mutt_thread_contains_unread(e)
Definition: mutt_thread.h:109
#define mutt_previous_subthread(e)
Definition: mutt_thread.h:123
#define mutt_next_thread(e)
Definition: mutt_thread.h:120
#define mutt_collapse_thread(e)
Definition: mutt_thread.h:107
bool window_is_focused(const struct MuttWindow *win)
Does the given Window have the focus?
Definition: mutt_window.c:654
struct MuttWindow * window_set_focus(struct MuttWindow *win)
Set the Window focus.
Definition: mutt_window.c:684
void buf_pretty_mailbox(struct Buffer *buf)
Shorten a mailbox path using '~' or '='.
Definition: muttlib.c:554
Some miscellaneous functions.
struct Email * mutt_get_virt_email(struct Mailbox *m, int vnum)
Get a virtual Email.
Definition: mview.c:418
bool mutt_limit_current_thread(struct MailboxView *mv, struct Email *e)
Limit the email view to the current thread.
Definition: mview.c:481
void mview_free(struct MailboxView **ptr)
Free a MailboxView.
Definition: mview.c:50
int ea_add_tagged(struct EmailArray *ea, struct MailboxView *mv, struct Email *e, bool use_tagged)
Get an array of the tagged Emails.
Definition: mview.c:378
bool message_is_tagged(struct Email *e)
Is a message in the index tagged (and within limit)
Definition: mview.c:364
bool mview_has_limit(const struct MailboxView *mv)
Is a limit active?
Definition: mview.c:439
View of a Mailbox.
int mx_tags_edit(struct Mailbox *m, const char *tags, struct Buffer *buf)
Start the tag editor of the mailbox.
Definition: mx.c:1272
int mx_msg_close(struct Mailbox *m, struct Message **ptr)
Close a message.
Definition: mx.c:1178
void mx_fastclose_mailbox(struct Mailbox *m, bool keep_account)
Free up memory associated with the Mailbox.
Definition: mx.c:412
struct Mailbox * mx_mbox_find2(const char *path)
Find a Mailbox on an Account.
Definition: mx.c:1603
struct Message * mx_msg_open(struct Mailbox *m, struct Email *e)
Return a stream pointer for a message.
Definition: mx.c:1132
bool mx_tags_is_supported(struct Mailbox *m)
Return true if mailbox support tagging.
Definition: mx.c:1309
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:1292
int mx_toggle_write(struct Mailbox *m)
Toggle the mailbox's readonly flag.
Definition: mx.c:1805
enum MxStatus mx_mbox_sync(struct Mailbox *m)
Save changes to mailbox.
Definition: mx.c:904
enum MxStatus mx_mbox_close(struct Mailbox *m)
Save changes and close mailbox.
Definition: mx.c:596
API for mailboxes.
MxStatus
Return values from mbox_check(), mbox_check_stats(), mbox_sync(), and mbox_close()
Definition: mxapi.h:63
@ MX_STATUS_OK
No changes.
Definition: mxapi.h:65
@ MX_STATUS_REOPENED
Mailbox was reopened.
Definition: mxapi.h:68
@ MX_STATUS_NEW_MAIL
New mail received in Mailbox.
Definition: mxapi.h:66
API for encryption/signing of emails.
#define PGP_TRADITIONAL_CHECKED
Email has a traditional (inline) signature.
Definition: lib.h: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:60
Usenet network mailbox type; talk to an NNTP server.
int nntp_check_msgid(struct Mailbox *m, const char *msgid)
Fetch article by Message-ID.
Definition: nntp.c:2167
int nntp_check_children(struct Mailbox *m, const char *msgid)
Fetch children of article with the Message-ID.
Definition: nntp.c:2238
void nntp_mailbox(struct Mailbox *m, char *buf, size_t buflen)
Get first newsgroup with new messages.
Definition: newsrc.c:1432
struct NntpMboxData * mutt_newsgroup_catchup(struct Mailbox *m, struct NntpAccountData *adata, char *group)
Catchup newsgroup.
Definition: newsrc.c:1350
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:1070
Nntp-specific Mailbox data.
@ NT_MAILBOX
Mailbox has changed, NotifyMailbox, EventMailbox.
Definition: notify_type.h:49
@ NT_INDEX
Index data has changed, NotifyIndex, IndexSharedData.
Definition: notify_type.h:48
@ NT_GLOBAL
Not object-related, NotifyGlobal.
Definition: notify_type.h:46
const struct CompleteOps CompleteNmQueryOps
Auto-Completion of NmQuerys.
Definition: complete.c:247
void nm_db_longrun_done(struct Mailbox *m)
Finish a long transaction.
Definition: db.c:378
void nm_db_longrun_init(struct Mailbox *m, bool writable)
Start a long transaction.
Definition: db.c:363
Notmuch virtual mailbox type.
void nm_query_window_reset(void)
Resets the vfolder window position to the present.
Definition: notmuch.c:1686
int nm_read_entire_thread(struct Mailbox *m, struct Email *e)
Get the entire thread of an email.
Definition: notmuch.c:1514
void nm_query_window_backward(void)
Function to move the current search window backward in time.
Definition: notmuch.c:1675
bool nm_query_window_available(void)
Are windowed queries enabled for use?
Definition: notmuch.c:1638
bool nm_message_is_still_queried(struct Mailbox *m, struct Email *e)
Is a message still visible in the query?
Definition: notmuch.c:1698
void nm_query_window_forward(void)
Function to move the current search window forward in time.
Definition: notmuch.c:1655
const char * opcodes_get_name(int op)
Get the name of an opcode.
Definition: opcodes.c:48
const char * pager_get_pager(struct ConfigSubset *sub)
Get the value of $pager.
Definition: config.c:108
GUI display a file/email/help in a viewport with paging.
int mutt_display_message(struct MuttWindow *win_index, struct IndexSharedData *shared)
Display a message in the pager.
Definition: message.c:447
int external_pager(struct MailboxView *mv, struct Email *e, const char *command)
Display a message in an external program.
Definition: message.c:300
Private state data for the Pager.
Match patterns to emails.
int mutt_search_command(struct MailboxView *mv, struct Menu *menu, int cur, struct SearchState *state, SearchFlags flags)
Perform a search.
Definition: pattern.c:456
int mutt_pattern_func(struct MailboxView *mv, int op, char *prompt)
Perform some Pattern matching.
Definition: pattern.c:289
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:81
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition: pool.c:94
POP network mailbox.
void pop_fetch_mail(void)
Fetch messages and save them in $spool_file.
Definition: pop.c:513
Progress Bar.
@ MUTT_PROGRESS_WRITE
Progress tracks elements, according to $write_inc
Definition: lib.h:83
struct Progress * progress_new(enum ProgressType type, size_t size)
Create a new Progress Bar.
Definition: progress.c:139
void progress_free(struct Progress **ptr)
Free a Progress Bar.
Definition: progress.c:110
void progress_set_message(struct Progress *progress, const char *fmt,...) __attribute__((__format__(__printf__
bool progress_update(struct Progress *progress, size_t pos, int percent)
Update the state of the progress bar.
Definition: progress.c:80
Prototypes for many functions.
@ EVM_VIEW
View the message.
Definition: protos.h:53
@ EVM_EDIT
Edit the message.
Definition: protos.h:54
@ MUTT_YES
User answered 'Yes', or assume 'Yes'.
Definition: quad.h:39
Ask the user a question.
enum QuadOption query_quadoption(const char *prompt, struct ConfigSubset *sub, const char *name)
Ask the user a quad-question.
Definition: question.c:366
#define STAILQ_FIRST(head)
Definition: queue.h:350
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:352
#define STAILQ_EMPTY(head)
Definition: queue.h:348
#define STAILQ_NEXT(elm, field)
Definition: queue.h:400
#define SEARCH_OPPOSITE
Search in the opposite direction.
Definition: search_state.h:46
uint8_t SearchFlags
Flags for a specific search, e.g. SEARCH_PROMPT.
Definition: search_state.h:43
#define SEARCH_NO_FLAGS
No flags are set.
Definition: search_state.h:44
#define SEARCH_PROMPT
Ask for search input.
Definition: search_state.h:45
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:1635
bool mutt_send_list_unsubscribe(struct Mailbox *m, struct Email *e)
Send a mailing-list unsubscription email.
Definition: send.c:3057
int mutt_send_message(SendFlags flags, struct Email *e_templ, const char *tempfile, struct Mailbox *m, struct EmailArray *ea, struct ConfigSubset *sub)
Send an email.
Definition: send.c:2120
bool mutt_send_list_subscribe(struct Mailbox *m, struct Email *e)
Send a mailing-list subscription email.
Definition: send.c:3028
#define SEND_GROUP_CHAT_REPLY
Reply to all recipients preserving To/Cc.
Definition: send.h:54
uint32_t SendFlags
Flags for mutt_send_message(), e.g. SEND_REPLY.
Definition: send.h:40
#define SEND_GROUP_REPLY
Reply to all.
Definition: send.h:43
#define SEND_LIST_REPLY
Reply to mailing list.
Definition: send.h:44
#define SEND_KEY
Mail a PGP public key.
Definition: send.h:48
#define SEND_POSTPONED
Recall a postponed email.
Definition: send.h:46
#define SEND_TO_SENDER
Compose new email to sender.
Definition: send.h:53
#define SEND_NO_FLAGS
No flags are set.
Definition: send.h:41
#define SEND_REPLY
Reply to sender.
Definition: send.h:42
#define SEND_NEWS
Reply to a news article.
Definition: send.h:55
#define SEND_FORWARD
Forward email.
Definition: send.h:45
Sidebar functions.
void mutt_sort_headers(struct MailboxView *mv, bool init)
Sort emails by their headers.
Definition: sort.c:350
Assorted sorting methods.
Key value store.
#define NONULL(x)
Definition: string2.h:37
String manipulation buffer.
Definition: buffer.h:36
size_t dsize
Length of data.
Definition: buffer.h:39
char * data
Pointer to data.
Definition: buffer.h:37
The envelope/body of an email.
Definition: email.h:39
bool read
Email is read.
Definition: email.h:50
bool visible
Is this message part of the view?
Definition: email.h:124
struct Envelope * env
Envelope information.
Definition: email.h:68
bool collapsed
Is this message part of a collapsed thread?
Definition: email.h:123
SecurityFlags security
bit 0-10: flags, bit 11,12: application, bit 13: traditional pgp See: ncrypt/lib.h pgplib....
Definition: email.h:43
struct Body * body
List of MIME parts.
Definition: email.h:69
bool old
Email is seen, but unread.
Definition: email.h:49
bool attach_del
Has an attachment marked for deletion.
Definition: email.h:102
bool flagged
Marked important?
Definition: email.h:47
bool threaded
Used for threading.
Definition: email.h:111
const struct AttrColor * attr_color
Color-pair to use when displaying in the index.
Definition: email.h:115
int vnum
Virtual message number.
Definition: email.h:117
struct TagList tags
For drivers that support server tagging.
Definition: email.h:72
bool deleted
Email is deleted.
Definition: email.h:78
int index
The absolute (unsorted) message number.
Definition: email.h:113
bool quasi_deleted
Deleted from neomutt, but not modified on disk.
Definition: email.h:106
bool tagged
Email is tagged.
Definition: email.h:110
char * followup_to
List of 'followup-to' fields.
Definition: envelope.h:80
char * message_id
Message ID.
Definition: envelope.h:73
struct ListHead references
message references (in reverse order)
Definition: envelope.h:83
struct ListHead in_reply_to
in-reply-to header content
Definition: envelope.h:84
An Event that happened to a Mailbox.
Definition: mailbox.h:199
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:42
struct IndexSharedData * shared
Shared Index data.
Definition: private_data.h:40
bool tag_prefix
tag-prefix has been pressed
Definition: private_data.h:36
struct Menu * menu
Menu controlling the index.
Definition: private_data.h:41
int oldcount
Old count of mails in the mailbox.
Definition: private_data.h:37
Data shared between Index, Pager and Sidebar.
Definition: shared_data.h:37
struct Email * email
Currently selected Email.
Definition: shared_data.h:42
struct Mailbox * mailbox
Current Mailbox.
Definition: shared_data.h:41
bool attach_msg
Are we in "attach message" mode?
Definition: shared_data.h:46
struct ConfigSubset * sub
Config set to use.
Definition: shared_data.h:38
struct MailboxView * mailbox_view
Current Mailbox view.
Definition: shared_data.h:40
struct SearchState * search_state
State of the current search.
Definition: shared_data.h:45
struct Notify * notify
Notifications: NotifyIndex, IndexSharedData.
Definition: shared_data.h:44
A List node for strings.
Definition: list.h:35
char * data
String.
Definition: list.h:36
View of a Mailbox.
Definition: mview.h:40
bool collapsed
Are all threads collapsed?
Definition: mview.h:49
struct Menu * menu
Needed for pattern compilation.
Definition: mview.h:47
struct ThreadsContext * threads
Threads context.
Definition: mview.h:44
struct Mailbox * mailbox
Current Mailbox.
Definition: mview.h:51
char * pattern
Limit pattern string.
Definition: mview.h:42
A mailbox.
Definition: mailbox.h: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:119
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 Notify * notify
Notifications: NotifyMailbox, EventMailbox.
Definition: mailbox.h:145
struct HashTable * id_hash
Hash Table: "message-id" -> Email.
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:116
int msg_tagged
How many messages are tagged?
Definition: mailbox.h:94
bool verbose
Display status messages?
Definition: mailbox.h:117
Mapping between a function and an operation.
Definition: lib.h:101
Mapping between an operation and a key sequence.
Definition: lib.h:110
Definition: lib.h:79
int max
Number of entries in the menu.
Definition: lib.h:81
A local copy of an email.
Definition: message.h:34
FILE * fp
pointer to the message data
Definition: message.h:35
const struct Mapping * help_data
Data for the Help Bar.
Definition: mutt_window.h:142
void * wdata
Private data.
Definition: mutt_window.h:145
struct MuttWindow * parent
Parent Window.
Definition: mutt_window.h:135
Container for Accounts, Notifications.
Definition: neomutt.h:41
struct Notify * notify
Notifications handler.
Definition: neomutt.h:42
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:45
NNTP-specific Mailbox data -.
Definition: mdata.h:34
bool reverse
search backwards
Definition: search_state.h:40
struct PatternList * pattern
compiled search pattern
Definition: search_state.h:37
void driver_tags_get_with_hidden(struct TagList *tl, struct Buffer *tags)
Get all tags, also hidden ones, separated by space.
Definition: tags.c:174
void mutt_break_thread(struct Email *e)
Break the email Thread.
Definition: thread.c:229
@ MENU_INDEX
Index panel (list of emails)
Definition: type.h:51