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