NeoMutt  2025-12-11-769-g906513
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
dlg_index.c
Go to the documentation of this file.
1
28
59
60#include "config.h"
61#include <stdbool.h>
62#include <string.h>
63#include "private.h"
64#include "mutt/lib.h"
65#include "config/lib.h"
66#include "email/lib.h"
67#include "core/lib.h"
68#include "conn/lib.h"
69#include "gui/lib.h"
70#include "mutt.h"
71#include "lib.h"
72#include "color/lib.h"
73#include "expando/lib.h"
74#include "hooks/lib.h"
75#include "key/lib.h"
76#include "menu/lib.h"
77#include "nntp/lib.h"
78#include "pager/lib.h"
79#include "pattern/lib.h"
80#include "sidebar/lib.h"
81#include "expando_index.h"
82#include "functions.h"
83#include "globals.h"
84#include "module_data.h"
85#include "mutt_logging.h"
86#include "mutt_mailbox.h"
87#include "mx.h"
88#include "nntp/adata.h"
89#include "nntp/module_data.h"
90#include "private_data.h"
91#include "shared_data.h"
92#include "status.h"
93#ifdef USE_NOTMUCH
94#include "notmuch/lib.h"
95#endif
96#ifdef USE_INOTIFY
97#include "monitor.h"
98#endif
99
101static const struct Mapping IndexHelp[] = {
102 // clang-format off
103 { N_("Quit"), OP_QUIT },
104 { N_("Del"), OP_DELETE },
105 { N_("Undel"), OP_UNDELETE },
106 { N_("Save"), OP_SAVE },
107 { N_("Mail"), OP_MAIL },
108 { N_("Reply"), OP_REPLY },
109 { N_("Group"), OP_GROUP_REPLY },
110 { N_("Help"), OP_HELP },
111 { NULL, 0 },
112 // clang-format on
113};
114
116const struct Mapping IndexNewsHelp[] = {
117 // clang-format off
118 { N_("Quit"), OP_QUIT },
119 { N_("Del"), OP_DELETE },
120 { N_("Undel"), OP_UNDELETE },
121 { N_("Save"), OP_SAVE },
122 { N_("Post"), OP_POST },
123 { N_("Followup"), OP_FOLLOWUP },
124 { N_("Catchup"), OP_CATCHUP },
125 { N_("Help"), OP_HELP },
126 { NULL, 0 },
127 // clang-format on
128};
129
137bool check_acl(struct Mailbox *m, AclFlags acl, const char *msg)
138{
139 if (!m)
140 return false;
141
142 if (!(m->rights & acl))
143 {
144 /* L10N: %s is one of the CHECK_ACL entries below. */
145 mutt_error(_("%s: Operation not permitted by ACL"), msg);
146 return false;
147 }
148
149 return true;
150}
151
161void collapse_all(struct MailboxView *mv, struct Menu *menu, enum CollapseMode mode)
162{
163 if (!mv || !mv->mailbox || (mv->mailbox->msg_count == 0) || !menu)
164 return;
165
166 struct Email *e_cur = mutt_get_virt_email(mv->mailbox, menu_get_index(menu));
167 if (!e_cur)
168 return;
169
170 int final = -1;
171
172 /* Figure out what the current message would be after folding / unfolding,
173 * so that we can restore the cursor in a sane way afterwards. */
174 switch (mode)
175 {
177 if (e_cur->collapsed)
178 final = mutt_uncollapse_thread(e_cur);
179 else if (mutt_thread_can_collapse(e_cur))
180 final = mutt_collapse_thread(e_cur);
181 else
182 final = e_cur->vnum;
183 break;
184
186 if (mutt_thread_can_collapse(e_cur))
187 final = mutt_collapse_thread(e_cur);
188 else
189 final = e_cur->vnum;
190 break;
191
193 if (e_cur->collapsed)
194 final = mutt_uncollapse_thread(e_cur);
195 else
196 final = e_cur->vnum;
197 break;
198 }
199
200 if (final == -1)
201 return;
202
203 struct Email *base = mutt_get_virt_email(mv->mailbox, final);
204 if (!base)
205 return;
206
207 /* Iterate all threads, perform collapse/uncollapse as needed */
208 if (mode == COLLAPSE_MODE_TOGGLE)
209 mv->collapsed = !mv->collapsed;
210 else
211 mv->collapsed = (mode == COLLAPSE_MODE_CLOSE);
213
214 /* Restore the cursor */
216 menu->max = mv->mailbox->vcount;
217 for (int i = 0; i < mv->mailbox->vcount; i++)
218 {
219 struct Email *e = mutt_get_virt_email(mv->mailbox, i);
220 if (!e)
221 break;
222 if (e->index == base->index)
223 {
224 menu_set_index(menu, i);
225 break;
226 }
227 }
228
230}
231
237static void uncollapse_thread(struct MailboxView *mv, int index)
238{
239 if (!mv || !mv->mailbox)
240 return;
241
242 struct Mailbox *m = mv->mailbox;
243 struct Email *e = mutt_get_virt_email(m, index);
244 if (e && e->collapsed)
245 {
247 mutt_set_vnum(m);
248 }
249}
250
259int find_next_undeleted(struct MailboxView *mv, int msgno, bool uncollapse)
260{
261 if (!mv || !mv->mailbox)
262 return -1;
263
264 struct Mailbox *m = mv->mailbox;
265
266 int index = -1;
267 for (int i = msgno + 1; i < m->vcount; i++)
268 {
269 struct Email *e = mutt_get_virt_email(m, i);
270 if (!e)
271 continue;
272 if (!e->deleted)
273 {
274 index = i;
275 break;
276 }
277 }
278
279 if (uncollapse)
281
282 return index;
283}
284
293int find_previous_undeleted(struct MailboxView *mv, int msgno, bool uncollapse)
294{
295 if (!mv || !mv->mailbox)
296 return -1;
297
298 struct Mailbox *m = mv->mailbox;
299
300 int index = -1;
301 for (int i = msgno - 1; i >= 0; i--)
302 {
303 struct Email *e = mutt_get_virt_email(m, i);
304 if (!e)
305 continue;
306 if (!e->deleted)
307 {
308 index = i;
309 break;
310 }
311 }
312
313 if (uncollapse)
315
316 return index;
317}
318
328{
329 if (!mv)
330 return 0;
331
332 struct Mailbox *m = mv->mailbox;
333 if (!m || (m->msg_count == 0))
334 return 0;
335
336 int old = -1;
337 for (int i = 0; i < m->vcount; i++)
338 {
339 struct Email *e = mutt_get_virt_email(m, i);
340 if (!e)
341 continue;
342 if (!e->read && !e->deleted)
343 {
344 if (!e->old)
345 return i;
346 if (old == -1)
347 old = i;
348 }
349 }
350 if (old != -1)
351 return old;
352
353 /* If `$use_threads` is not threaded and `$sort` is reverse, the latest
354 * message is first. Otherwise, the latest message is first if exactly
355 * one of `$use_threads` and `$sort` are reverse.
356 */
357 enum EmailSortType c_sort = cs_subset_sort(m->sub, "sort");
358 if ((c_sort & SORT_MASK) == EMAIL_SORT_THREADS)
359 c_sort = cs_subset_sort(m->sub, "sort_aux");
360 bool reverse = false;
361 switch (mutt_thread_style())
362 {
363 case UT_FLAT:
364 reverse = c_sort & SORT_REVERSE;
365 break;
366 case UT_THREADS:
367 reverse = c_sort & SORT_REVERSE;
368 break;
369 case UT_REVERSE:
370 reverse = !(c_sort & SORT_REVERSE);
371 break;
372 default:
373 ASSERT(false);
374 }
375
376 if (reverse || (m->vcount == 0))
377 return 0;
378
379 return m->vcount - 1;
380}
381
387void resort_index(struct MailboxView *mv, struct Menu *menu)
388{
389 if (!mv || !mv->mailbox || !menu)
390 return;
391
392 struct Mailbox *m = mv->mailbox;
393 const int old_index = menu_get_index(menu);
394 struct Email *e_cur = mutt_get_virt_email(m, old_index);
395
396 int new_index = -1;
397 mutt_sort_headers(mv, false);
398
399 /* Restore the current message */
400 for (int i = 0; i < m->vcount; i++)
401 {
402 struct Email *e = mutt_get_virt_email(m, i);
403 if (!e)
404 continue;
405 if (e == e_cur)
406 {
407 new_index = i;
408 break;
409 }
410 }
411
412 if (mutt_using_threads() && (old_index < 0))
413 new_index = mutt_parent_message(e_cur, false);
414
415 if (old_index < 0)
416 new_index = find_first_message(mv);
417
418 menu->max = m->vcount;
419 menu_set_index(menu, new_index);
421}
422
429static void update_index_threaded(struct MailboxView *mv, enum MxStatus check, int oldcount)
430{
431 struct Email **save_new = NULL;
432 const bool lmt = mview_has_limit(mv);
433
434 struct Mailbox *m = mv->mailbox;
435 int num_new = MAX(0, m->msg_count - oldcount);
436
437 const bool c_uncollapse_new = cs_subset_bool(m->sub, "uncollapse_new");
438 /* save the list of new messages */
439 if ((check != MX_STATUS_REOPENED) && (oldcount > 0) &&
440 (lmt || c_uncollapse_new) && (num_new > 0))
441 {
442 save_new = MUTT_MEM_MALLOC(num_new, struct Email *);
443 for (int i = oldcount; i < m->msg_count; i++)
444 save_new[i - oldcount] = m->emails[i];
445 }
446
447 /* Sort first to thread the new messages, because some patterns
448 * require the threading information.
449 *
450 * If the mailbox was reopened, need to rethread from scratch. */
452
453 if (lmt)
454 {
455 for (int i = 0; i < m->msg_count; i++)
456 {
457 struct Email *e = m->emails[i];
458 if (!e)
459 continue;
460
461 if ((e->limit_visited && e->visible) ||
463 MUTT_MATCH_FULL_ADDRESS, m, e, NULL))
464 {
465 /* vnum will get properly set by mutt_set_vnum(), which
466 * is called by mutt_sort_headers() just below. */
467 e->vnum = 1;
468 e->visible = true;
469 }
470 else
471 {
472 e->vnum = -1;
473 e->visible = false;
474 }
475
476 // mark email as visited so we don't re-apply the pattern next time
477 e->limit_visited = true;
478 }
479 /* Need a second sort to set virtual numbers and redraw the tree */
480 mutt_sort_headers(mv, false);
481 }
482
483 /* uncollapse threads with new mail */
484 if (c_uncollapse_new)
485 {
486 if (check == MX_STATUS_REOPENED)
487 {
488 mv->collapsed = false;
490 mutt_set_vnum(m);
491 }
492 else if (oldcount > 0)
493 {
494 for (int j = 0; j < num_new; j++)
495 {
496 if (save_new[j]->visible)
497 {
498 mutt_uncollapse_thread(save_new[j]);
499 }
500 }
501 mutt_set_vnum(m);
502 }
503 }
504
505 FREE(&save_new);
506}
507
513static void update_index_unthreaded(struct MailboxView *mv, enum MxStatus check)
514{
515 /* We are in a limited view. Check if the new message(s) satisfy
516 * the limit criteria. If they do, set their virtual msgno so that
517 * they will be visible in the limited view */
518 if (mview_has_limit(mv))
519 {
520 int padding = mx_msg_padding_size(mv->mailbox);
521 mv->mailbox->vcount = mv->vsize = 0;
522 for (int i = 0; i < mv->mailbox->msg_count; i++)
523 {
524 struct Email *e = mv->mailbox->emails[i];
525 if (!e)
526 break;
527
528 if ((e->limit_visited && e->visible) ||
530 MUTT_MATCH_FULL_ADDRESS, mv->mailbox, e, NULL))
531 {
533 e->vnum = mv->mailbox->vcount;
534 mv->mailbox->v2r[mv->mailbox->vcount] = i;
535 e->visible = true;
536 mv->mailbox->vcount++;
537 struct Body *b = e->body;
538 mv->vsize += b->length + b->offset - b->hdr_offset + padding;
539 }
540 else
541 {
542 e->visible = false;
543 }
544
545 // mark email as visited so we don't re-apply the pattern next time
546 e->limit_visited = true;
547 }
548 }
549
550 /* if the mailbox was reopened, need to rethread from scratch */
552}
553
562void update_index(struct Menu *menu, struct MailboxView *mv, enum MxStatus check,
563 int oldcount, const struct IndexSharedData *shared)
564{
565 if (!menu || !mv)
566 return;
567
568 struct Mailbox *m = mv->mailbox;
569 if (mutt_using_threads())
570 update_index_threaded(mv, check, oldcount);
571 else
572 update_index_unthreaded(mv, check);
573
574 menu->max = m->vcount;
575 const int old_index = menu_get_index(menu);
576 int index = -1;
577 if (oldcount)
578 {
579 /* restore the current message to the message it was pointing to */
580 for (int i = 0; i < m->vcount; i++)
581 {
582 struct Email *e = mutt_get_virt_email(m, i);
583 if (!e)
584 continue;
585 if (index_shared_data_is_cur_email(shared, e))
586 {
587 index = i;
588 break;
589 }
590 }
591 }
592
593 if (index < 0)
594 {
595 index = (old_index < m->vcount) ? old_index : find_first_message(mv);
596 }
597 menu_set_index(menu, index);
598}
599
606{
607 if (nc->event_type != NT_MAILBOX)
608 return 0;
609 if (!nc->global_data)
610 return -1;
612 return 0;
613
614 struct Mailbox **ptr = nc->global_data;
615 if (!*ptr)
616 return 0;
617
618 *ptr = NULL;
619 mutt_debug(LL_DEBUG5, "mailbox done\n");
620 return 0;
621}
622
631void change_folder_mailbox(struct Menu *menu, struct Mailbox *m, int *oldcount,
632 struct IndexSharedData *shared, bool read_only)
633{
634 if (!m)
635 return;
636
637 /* keepalive failure in mutt_enter_fname may kill connection. */
638 if (shared->mailbox && (buf_is_empty(&shared->mailbox->pathbuf)))
639 {
640 mview_free(&shared->mailbox_view);
641 mailbox_free(&shared->mailbox);
642 }
643
644 if (shared->mailbox)
645 {
646 char *new_last_folder = NULL;
647#ifdef USE_INOTIFY
648 int monitor_remove_rc = mutt_monitor_remove(NULL);
649#endif
650 if (shared->mailbox->compress_info && (shared->mailbox->realpath[0] != '\0'))
651 new_last_folder = mutt_str_dup(shared->mailbox->realpath);
652 else
653 new_last_folder = mutt_str_dup(mailbox_path(shared->mailbox));
654 *oldcount = shared->mailbox->msg_count;
655
656 const enum MxStatus check = mx_mbox_close(shared->mailbox);
657 if (check == MX_STATUS_OK)
658 {
659 mview_free(&shared->mailbox_view);
660 if (shared->mailbox != m)
661 {
662 mailbox_free(&shared->mailbox);
663 }
664 }
665 else
666 {
667#ifdef USE_INOTIFY
668 if (monitor_remove_rc == 0)
669 mutt_monitor_add(NULL);
670#endif
671 if ((check == MX_STATUS_NEW_MAIL) || (check == MX_STATUS_REOPENED))
672 update_index(menu, shared->mailbox_view, check, *oldcount, shared);
673
674 FREE(&new_last_folder);
677 return;
678 }
680 LastFolder = new_last_folder;
681 }
683
684 /* If the `folder-hook` were to call `unmailboxes`, then the Mailbox (`m`)
685 * could be deleted, leaving `m` dangling. */
686 // TODO: Refactor this function to avoid the need for an observer
688 char *dup_path = mutt_str_dup(mailbox_path(m));
689 char *dup_name = mutt_str_dup(m->name);
690
691 exec_folder_hook(dup_path, dup_name);
692 if (m)
693 {
694 /* `m` is still valid, but we won't need the observer again before the end
695 * of the function. */
697 }
698 else
699 {
700 // Recreate the Mailbox as the folder-hook might have invoked `mailboxes`
701 // and/or `unmailboxes`.
702 m = mx_path_resolve(dup_path);
703 }
704
705 FREE(&dup_path);
706 FREE(&dup_name);
707
708 if (!m)
709 return;
710
711 const OpenMailboxFlags flags = read_only ? MUTT_READONLY : MUTT_OPEN_NO_FLAGS;
712 if (mx_mbox_open(m, flags))
713 {
714 struct MailboxView *mv = mview_new(m, NeoMutt->notify);
715 index_shared_data_set_mview(shared, mv);
716
717 menu->max = m->msg_count;
719#ifdef USE_INOTIFY
720 mutt_monitor_add(NULL);
721#endif
722 }
723 else
724 {
725 index_shared_data_set_mview(shared, NULL);
727 }
728
729 const bool c_collapse_all = cs_subset_bool(shared->sub, "collapse_all");
730 if (mutt_using_threads() && c_collapse_all)
732
734 /* force the mailbox check after we have changed the folder */
735 struct EventMailbox ev_m = { shared->mailbox };
739}
740
741#ifdef USE_NOTMUCH
752struct Mailbox *change_folder_notmuch(struct Menu *menu, char *buf, int buflen, int *oldcount,
753 struct IndexSharedData *shared, bool read_only)
754{
755 if (!nm_url_from_query(NULL, buf, buflen))
756 {
757 mutt_message(_("Failed to create query, aborting"));
758 return NULL;
759 }
760
761 struct Mailbox *m_query = mx_path_resolve(buf);
762 change_folder_mailbox(menu, m_query, oldcount, shared, read_only);
763 if (!shared->mailbox_view)
764 mailbox_free(&m_query);
765 return m_query;
766}
767#endif
768
777void change_folder_string(struct Menu *menu, struct Buffer *buf, int *oldcount,
778 struct IndexSharedData *shared, bool read_only)
779{
781 if (OptNews)
782 {
783 OptNews = false;
784 nntp_expand_path(buf->data, buf->dsize, &mod_data->current_news_srv->conn->account);
785 }
786 else
787 {
788 const char *const c_folder = cs_subset_string(shared->sub, "folder");
789 mx_path_canon(buf, c_folder, NULL);
790 }
791
792 enum MailboxType type = mx_path_probe(buf_string(buf));
793 if ((type == MUTT_MAILBOX_ERROR) || (type == MUTT_UNKNOWN))
794 {
795 // Look for a Mailbox by its description, before failing
796 struct Mailbox *m = mailbox_find_name(buf_string(buf));
797 if (m)
798 {
799 change_folder_mailbox(menu, m, oldcount, shared, read_only);
800 }
801 else
802 {
803 mutt_error(_("%s is not a mailbox"), buf_string(buf));
804 }
805 return;
806 }
807
808 struct Mailbox *m = mx_path_resolve(buf_string(buf));
809 change_folder_mailbox(menu, m, oldcount, shared, read_only);
810}
811
824int mutt_make_string(struct Buffer *buf, size_t max_cols,
825 const struct Expando *exp, struct Mailbox *m, int inpgr,
826 struct Email *e, MuttFormatFlags flags, const char *progress)
827{
828 if (!exp)
829 return 0;
830
831 struct EmailFormatInfo efi = { 0 };
832
833 efi.email = e;
834 efi.mailbox = m;
835 efi.msg_in_pager = inpgr;
836 efi.pager_progress = progress;
837
838 return expando_filter(exp, IndexRenderCallbacks, &efi, flags, max_cols,
839 NeoMutt->env, buf);
840}
841
847int index_make_entry(struct Menu *menu, int line, int max_cols, struct Buffer *buf)
848{
849 if (!menu || !menu->mdata)
850 return 0;
851
852 struct IndexPrivateData *priv = menu->mdata;
853 struct IndexSharedData *shared = priv->shared;
854 struct Mailbox *m = shared->mailbox;
855 if (!shared->mailbox_view)
856 menu->current = -1;
857
858 if (!m || (line < 0) || (line >= m->email_max))
859 return 0;
860
861 struct Email *e = mutt_get_virt_email(m, line);
862 if (!e)
863 return 0;
864
866 struct MuttThread *tmp = NULL;
867
868 const enum UseThreads c_threads = mutt_thread_style();
869 if ((c_threads > UT_FLAT) && e->tree && e->thread)
870 {
871 flags |= MUTT_FORMAT_TREE; /* display the thread tree */
872 if (e->display_subject)
873 {
874 flags |= MUTT_FORMAT_FORCESUBJ;
875 }
876 else
877 {
878 const bool reverse = c_threads == UT_REVERSE;
879 int edgemsgno;
880 if (reverse)
881 {
882 if (menu->top + menu->page_len > menu->max)
883 edgemsgno = m->v2r[menu->max - 1];
884 else
885 edgemsgno = m->v2r[menu->top + menu->page_len - 1];
886 }
887 else
888 {
889 edgemsgno = m->v2r[menu->top];
890 }
891
892 for (tmp = e->thread->parent; tmp; tmp = tmp->parent)
893 {
894 if (!tmp->message)
895 continue;
896
897 /* if no ancestor is visible on current screen, provisionally force
898 * subject... */
899 if (reverse ? (tmp->message->msgno > edgemsgno) : (tmp->message->msgno < edgemsgno))
900 {
901 flags |= MUTT_FORMAT_FORCESUBJ;
902 break;
903 }
904 else if (tmp->message->vnum >= 0)
905 {
906 break;
907 }
908 }
909 if (flags & MUTT_FORMAT_FORCESUBJ)
910 {
911 for (tmp = e->thread->prev; tmp; tmp = tmp->prev)
912 {
913 if (!tmp->message)
914 continue;
915
916 /* ...but if a previous sibling is available, don't force it */
917 if (reverse ? (tmp->message->msgno > edgemsgno) : (tmp->message->msgno < edgemsgno))
918 {
919 break;
920 }
921 else if (tmp->message->vnum >= 0)
922 {
923 flags &= ~MUTT_FORMAT_FORCESUBJ;
924 break;
925 }
926 }
927 }
928 }
929 }
930
931 const struct Expando *c_index_format = cs_subset_expando(shared->sub, "index_format");
932 int msg_in_pager = shared->mailbox_view ? shared->mailbox_view->msg_in_pager : 0;
933
934 const bool c_arrow_cursor = cs_subset_bool(menu->sub, "arrow_cursor");
935 if (c_arrow_cursor)
936 {
937 const char *const c_arrow_string = cs_subset_string(menu->sub, "arrow_string");
938 if (max_cols > 0)
939 max_cols -= (mutt_strwidth(c_arrow_string) + 1);
940 }
941
942 return mutt_make_string(buf, max_cols, c_index_format, m, msg_in_pager, e, flags, NULL);
943}
944
948const struct AttrColor *index_color(struct Menu *menu, int line)
949{
950 struct IndexPrivateData *priv = menu->mdata;
951 struct IndexSharedData *shared = priv->shared;
952 struct Mailbox *m = shared->mailbox;
953 if (!m || (line < 0))
954 return NULL;
955
956 struct Email *e = mutt_get_virt_email(m, line);
957 if (!e)
958 return NULL;
959
960 if (e->attr_color)
961 return e->attr_color;
962
963 email_set_color(m, e);
964 return e->attr_color;
965}
966
980void mutt_draw_statusline(struct MuttWindow *win, int max_cols, const char *buf, size_t buflen)
981{
982 if (!buf || !stdscr)
983 return;
984
985 size_t i = 0;
986 size_t offset = 0;
987 bool found = false;
988 size_t chunks = 0;
989 size_t len = 0;
990
994 struct StatusSyntax
995 {
996 const struct AttrColor *attr_color;
997 int first;
998 int last;
999 } *syntax = NULL;
1000
1003 do
1004 {
1005 struct RegexColor *cl = NULL;
1006 found = false;
1007
1008 if (!buf[offset])
1009 break;
1010
1011 /* loop through each "color status regex" */
1013 {
1014 regmatch_t pmatch[cl->match + 1];
1015 memset(pmatch, 0, (cl->match + 1) * sizeof(regmatch_t));
1016
1017 if (regexec(&cl->regex, buf + offset, cl->match + 1, pmatch, 0) != 0)
1018 continue; /* regex doesn't match the status bar */
1019
1020 int first = pmatch[cl->match].rm_so + offset;
1021 int last = pmatch[cl->match].rm_eo + offset;
1022
1023 if (first == last)
1024 continue; /* ignore an empty regex */
1025
1026 if (!found)
1027 {
1028 chunks++;
1029 MUTT_MEM_REALLOC(&syntax, chunks, struct StatusSyntax);
1030 }
1031
1032 i = chunks - 1;
1033 if (!found || (first < syntax[i].first) ||
1034 ((first == syntax[i].first) && (last > syntax[i].last)))
1035 {
1036 const struct AttrColor *ac_merge = merged_color_overlay(ac_base, &cl->attr_color);
1037
1038 syntax[i].attr_color = ac_merge;
1039 syntax[i].first = first;
1040 syntax[i].last = last;
1041 }
1042 found = true;
1043 }
1044
1045 if (syntax)
1046 {
1047 offset = syntax[i].last;
1048 }
1049 } while (found);
1050
1051 /* Only 'len' bytes will fit into 'max_cols' screen columns */
1052 len = mutt_wstr_trunc(buf, buflen, max_cols, NULL);
1053
1054 offset = 0;
1055
1056 if ((chunks > 0) && (syntax[0].first > 0))
1057 {
1058 /* Text before the first highlight */
1059 mutt_window_addnstr(win, buf, MIN(len, syntax[0].first));
1060 mutt_curses_set_color(ac_base);
1061 if (len <= syntax[0].first)
1062 goto dsl_finish; /* no more room */
1063
1064 offset = syntax[0].first;
1065 }
1066
1067 for (i = 0; i < chunks; i++)
1068 {
1069 /* Highlighted text */
1070 mutt_curses_set_color(syntax[i].attr_color);
1071 mutt_window_addnstr(win, buf + offset, MIN(len, syntax[i].last) - offset);
1072 if (len <= syntax[i].last)
1073 goto dsl_finish; /* no more room */
1074
1075 size_t next;
1076 if ((i + 1) == chunks)
1077 {
1078 next = len;
1079 }
1080 else
1081 {
1082 next = MIN(len, syntax[i + 1].first);
1083 }
1084
1085 mutt_curses_set_color(ac_base);
1086 offset = syntax[i].last;
1087 mutt_window_addnstr(win, buf + offset, next - offset);
1088
1089 offset = next;
1090 if (offset >= len)
1091 goto dsl_finish; /* no more room */
1092 }
1093
1094 mutt_curses_set_color(ac_base);
1095 if (offset < len)
1096 {
1097 /* Text after the last highlight */
1098 mutt_window_addnstr(win, buf + offset, len - offset);
1099 }
1100
1101 int width = mutt_strwidth(buf);
1102 if (width < max_cols)
1103 {
1104 /* Pad the rest of the line with whitespace */
1105 mutt_paddstr(win, max_cols - width, "");
1106 }
1107dsl_finish:
1108 FREE(&syntax);
1109}
1110
1121struct Mailbox *dlg_index(struct MuttWindow *dlg, struct Mailbox *m_init)
1122{
1123 /* Make sure use_threads/sort/sort_aux are coherent */
1125
1126 struct IndexSharedData *shared = dlg->wdata;
1128
1129 struct MuttWindow *panel_index = window_find_child(dlg, WT_INDEX);
1130
1131 struct IndexPrivateData *priv = panel_index->wdata;
1132 priv->win_index = window_find_child(panel_index, WT_MENU);
1133
1134 int op = OP_NULL;
1135
1137 ASSERT(mod_data);
1138
1139 if (shared->mailbox && (shared->mailbox->type == MUTT_NNTP))
1140 dlg->help_data = IndexNewsHelp;
1141 else
1142 dlg->help_data = IndexHelp;
1143 dlg->help_md = mod_data->menu_index;
1144
1145 priv->menu = priv->win_index->wdata;
1147 priv->menu->color = index_color;
1148 priv->menu->max = shared->mailbox ? shared->mailbox->vcount : 0;
1150
1151 struct MuttWindow *old_focus = window_set_focus(priv->menu->win);
1152 mutt_window_reflow(NULL);
1153
1154 if (!shared->attach_msg)
1155 {
1156 /* force the mailbox check after we enter the folder */
1158 }
1159#ifdef USE_INOTIFY
1160 mutt_monitor_add(NULL);
1161#endif
1162
1163 const bool c_collapse_all = cs_subset_bool(shared->sub, "collapse_all");
1164 if (mutt_using_threads() && c_collapse_all)
1165 {
1168 }
1169
1170 int rc = 0;
1171 do
1172 {
1173 /* Clear the tag prefix unless we just started it.
1174 * Don't clear the prefix on a timeout, but do clear on an abort */
1175 if (priv->tag_prefix && (op != OP_TAG_PREFIX) &&
1176 (op != OP_TAG_PREFIX_COND) && (op != OP_TIMEOUT))
1177 {
1178 priv->tag_prefix = false;
1179 }
1180
1181 /* check if we need to resort the index because just about
1182 * any 'op' below could do mutt_enter_command(), either here or
1183 * from any new priv->menu launched, and change $sort/$sort_aux */
1184 if (OptNeedResort && shared->mailbox && (shared->mailbox->msg_count != 0) &&
1185 (menu_get_index(priv->menu) >= 0))
1186 {
1187 resort_index(shared->mailbox_view, priv->menu);
1188 }
1189
1190 priv->menu->max = shared->mailbox ? shared->mailbox->vcount : 0;
1191 priv->oldcount = shared->mailbox ? shared->mailbox->msg_count : 0;
1192
1193 if (shared->mailbox && shared->mailbox_view)
1194 {
1196
1197 shared->mailbox_view->menu = priv->menu;
1198 /* check for new mail in the mailbox. If nonzero, then something has
1199 * changed about the file (either we got new mail or the file was
1200 * modified underneath us.) */
1201 enum MxStatus check = mx_mbox_check(shared->mailbox);
1202
1203 if (check == MX_STATUS_ERROR)
1204 {
1205 if (buf_is_empty(&shared->mailbox->pathbuf))
1206 {
1207 /* fatal error occurred */
1208 mview_free(&shared->mailbox_view);
1210 }
1211
1213 }
1214 else if ((check == MX_STATUS_NEW_MAIL) || (check == MX_STATUS_REOPENED) ||
1215 (check == MX_STATUS_FLAGS))
1216 {
1217 /* notify the user of new mail */
1218 if (check == MX_STATUS_REOPENED)
1219 {
1220 mutt_error(_("Mailbox was externally modified. Flags may be wrong."));
1221 }
1222 else if (check == MX_STATUS_NEW_MAIL)
1223 {
1224 for (size_t i = 0; i < shared->mailbox->msg_count; i++)
1225 {
1226 const struct Email *e = shared->mailbox->emails[i];
1227 if (e && !e->read && !e->old)
1228 {
1229 mutt_message(_("New mail in this mailbox"));
1230 const bool c_beep_new = cs_subset_bool(shared->sub, "beep_new");
1231 if (c_beep_new)
1232 mutt_beep(true);
1233 const struct Expando *c_new_mail_command =
1234 cs_subset_expando(shared->sub, "new_mail_command");
1235 if (c_new_mail_command)
1236 {
1237 struct Buffer *cmd = buf_pool_get();
1238 menu_status_line(cmd, shared, NULL, -1, c_new_mail_command);
1239 if (mutt_system(buf_string(cmd)) != 0)
1240 mutt_error(_("Error running \"%s\""), buf_string(cmd));
1241 buf_pool_release(&cmd);
1242 }
1243 break;
1244 }
1245 }
1246 }
1247 else if (check == MX_STATUS_FLAGS)
1248 {
1249 mutt_message(_("Mailbox was externally modified"));
1250 }
1251
1252 /* avoid the message being overwritten by mailbox */
1253 priv->do_mailbox_notify = false;
1254
1255 bool verbose = shared->mailbox->verbose;
1256 shared->mailbox->verbose = false;
1257 update_index(priv->menu, shared->mailbox_view, check, priv->oldcount, shared);
1258 shared->mailbox->verbose = verbose;
1259 priv->menu->max = shared->mailbox->vcount;
1262 }
1263
1265 menu_get_index(priv->menu)));
1266 }
1267
1268 if (!shared->attach_msg)
1269 {
1270 /* check for new mail in the incoming folders */
1272 if (priv->do_mailbox_notify)
1273 {
1274 if (mutt_mailbox_notify(shared->mailbox))
1275 {
1276 const bool c_beep_new = cs_subset_bool(shared->sub, "beep_new");
1277 if (c_beep_new)
1278 mutt_beep(true);
1279 const struct Expando *c_new_mail_command = cs_subset_expando(shared->sub, "new_mail_command");
1280 if (c_new_mail_command)
1281 {
1282 struct Buffer *cmd = buf_pool_get();
1283 menu_status_line(cmd, shared, priv->menu, -1, c_new_mail_command);
1284 if (mutt_system(buf_string(cmd)) != 0)
1285 mutt_error(_("Error running \"%s\""), buf_string(cmd));
1286 buf_pool_release(&cmd);
1287 }
1288 }
1289 }
1290 else
1291 {
1292 priv->do_mailbox_notify = true;
1293 }
1294 }
1295
1296 window_redraw(NULL);
1297
1298 /* give visual indication that the next command is a tag- command */
1299 if (priv->tag_prefix)
1300 {
1301 msgwin_set_text(NULL, "tag-", MT_COLOR_NORMAL);
1302 }
1303
1304 const bool c_arrow_cursor = cs_subset_bool(shared->sub, "arrow_cursor");
1305 const bool c_braille_friendly = cs_subset_bool(shared->sub, "braille_friendly");
1306 const int index = menu_get_index(priv->menu);
1307 if (c_arrow_cursor)
1308 {
1309 const char *const c_arrow_string = cs_subset_string(shared->sub, "arrow_string");
1310 const int arrow_width = mutt_strwidth(c_arrow_string);
1311 mutt_window_move(priv->menu->win, index - priv->menu->top, arrow_width);
1312 }
1313 else if (c_braille_friendly)
1314 {
1315 mutt_window_move(priv->menu->win, index - priv->menu->top, 0);
1316 }
1317 else
1318 {
1319 mutt_window_move(priv->menu->win, index - priv->menu->top,
1320 priv->menu->win->state.cols - 1);
1321 }
1322 mutt_refresh();
1323
1324 window_redraw(NULL);
1325 struct KeyEvent event = km_dokey(mod_data->menu_index, GETCH_NO_FLAGS);
1326 op = event.op;
1327
1328 if (op == OP_REPAINT)
1329 {
1330 /* force a real complete redraw. clrtobot() doesn't seem to be able
1331 * to handle every case without this. */
1332 msgwin_clear_text(NULL);
1333 mutt_refresh();
1334 continue;
1335 }
1336
1337 /* either user abort or timeout */
1338 if (op < OP_NULL)
1339 {
1340 if (priv->tag_prefix)
1341 msgwin_clear_text(NULL);
1342 continue;
1343 }
1344
1345 mutt_debug(LL_DEBUG1, "Got op %s (%d)\n", opcodes_get_name(op), op);
1346
1347 /* special handling for the priv->tag-prefix function */
1348 const bool c_auto_tag = cs_subset_bool(shared->sub, "auto_tag");
1349 if ((op == OP_TAG_PREFIX) || (op == OP_TAG_PREFIX_COND))
1350 {
1351 /* A second priv->tag-prefix command aborts */
1352 if (priv->tag_prefix)
1353 {
1354 priv->tag_prefix = false;
1355 msgwin_clear_text(NULL);
1356 continue;
1357 }
1358
1359 if (!shared->mailbox)
1360 {
1361 mutt_error(_("No mailbox is open"));
1362 continue;
1363 }
1364
1365 if (shared->mailbox->msg_tagged == 0)
1366 {
1367 if (op == OP_TAG_PREFIX)
1368 {
1369 mutt_error(_("No tagged messages"));
1370 }
1371 else if (op == OP_TAG_PREFIX_COND)
1372 {
1374 mutt_message(_("Nothing to do"));
1375 }
1376 continue;
1377 }
1378
1379 /* get the real command */
1380 priv->tag_prefix = true;
1381 continue;
1382 }
1383 else if (c_auto_tag && shared->mailbox && (shared->mailbox->msg_tagged != 0))
1384 {
1385 priv->tag_prefix = true;
1386 }
1387
1389
1390 OptNews = false; /* for any case */
1391
1392#ifdef USE_NOTMUCH
1393 nm_db_debug_check(shared->mailbox);
1394#endif
1395
1396 rc = index_function_dispatcher(priv->win_index, &event);
1397
1398 if (rc == FR_UNKNOWN)
1399 rc = menu_function_dispatcher(priv->win_index, &event);
1400
1401 if (rc == FR_UNKNOWN)
1402 {
1403 struct MuttWindow *win_sidebar = window_find_child(dlg, WT_SIDEBAR);
1404 rc = sb_function_dispatcher(win_sidebar, &event);
1405 }
1406 if (rc == FR_UNKNOWN)
1407 rc = global_function_dispatcher(priv->menu->win, &event);
1408
1409 if (rc == FR_UNKNOWN)
1410 km_error_key(mod_data->menu_index);
1411
1412#ifdef USE_NOTMUCH
1413 nm_db_debug_check(shared->mailbox);
1414#endif
1415 } while (rc != FR_DONE);
1416
1417 mview_free(&shared->mailbox_view);
1418 window_set_focus(old_focus);
1419
1420 return shared->mailbox;
1421}
1422
1431void email_set_color(struct Mailbox *m, struct Email *e)
1432{
1433 if (!e)
1434 return;
1435
1436 struct RegexColor *color = NULL;
1437 struct PatternCache cache = { 0 };
1438
1439 const struct AttrColor *ac_merge = NULL;
1441 {
1443 MUTT_MATCH_FULL_ADDRESS, m, e, &cache))
1444 {
1445 ac_merge = merged_color_overlay(ac_merge, &color->attr_color);
1446 }
1447 }
1448
1449 struct AttrColor *ac_normal = simple_color_get(MT_COLOR_NORMAL);
1450 if (ac_merge)
1451 ac_merge = merged_color_overlay(ac_normal, ac_merge);
1452 else
1453 ac_merge = ac_normal;
1454
1455 e->attr_color = ac_merge;
1456}
1457
1463{
1467
1468 struct IndexSharedData *shared = index_shared_data_new();
1469 notify_set_parent(shared->notify, dlg->notify);
1470
1471 dlg->wdata = shared;
1473
1474 const bool c_status_on_top = cs_subset_bool(NeoMutt->sub, "status_on_top");
1475
1476 struct MuttWindow *panel_index = ipanel_new(c_status_on_top, shared);
1477 struct MuttWindow *panel_pager = ppanel_new(c_status_on_top, shared);
1478
1479 mutt_window_add_child(dlg, panel_index);
1480 mutt_window_add_child(dlg, panel_pager);
1481
1482 return dlg;
1483}
1484
1490void index_change_folder(struct MuttWindow *dlg, struct Mailbox *m)
1491{
1492 if (!dlg || !m)
1493 return;
1494
1495 struct IndexSharedData *shared = dlg->wdata;
1496 if (!shared)
1497 return;
1498
1499 struct MuttWindow *panel_index = window_find_child(dlg, WT_INDEX);
1500 if (!panel_index)
1501 return;
1502
1503 struct IndexPrivateData *priv = panel_index->wdata;
1504 if (!priv)
1505 return;
1506
1507 change_folder_mailbox(priv->menu, m, &priv->oldcount, shared, false);
1508}
bool buf_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition buffer.c:291
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition buffer.h:96
Color and attribute parsing.
struct RegexColorList * regex_colors_get_list(enum ColorId cid)
Return the RegexColorList for a Colour ID.
Definition regex.c:190
struct AttrColor * simple_color_get(enum ColorId cid)
Get the colour of an object by its ID.
Definition simple.c:97
@ MT_COLOR_STATUS
Status bar (takes a pattern)
Definition color.h:78
@ MT_COLOR_NORMAL
Plain text.
Definition color.h:53
@ MT_COLOR_INDEX
Index: default colour.
Definition color.h:86
void mutt_pattern_free(struct PatternList **pat)
Free a Pattern.
Definition compile.c:830
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
short cs_subset_sort(const struct ConfigSubset *sub, const char *name)
Get a sort config item by name.
Definition helpers.c:266
const struct Expando * cs_subset_expando(const struct ConfigSubset *sub, const char *name)
Get an Expando config item by name.
Convenience wrapper for the config headers.
#define SORT_MASK
Mask for the sort id.
Definition sort.h:39
#define SORT_REVERSE
Reverse the order of the sort.
Definition sort.h:40
Connection Library.
Convenience wrapper for the core headers.
void mailbox_gc_run(void)
Run the garbage-collection.
Definition mailbox.c:311
void mailbox_free(struct Mailbox **ptr)
Free a Mailbox.
Definition mailbox.c:90
struct Mailbox * mailbox_find_name(const char *name)
Find the mailbox with a given name.
Definition mailbox.c:187
@ NT_MAILBOX_DELETE
Mailbox is about to be deleted.
Definition mailbox.h:173
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox's path string.
Definition mailbox.h:213
uint16_t AclFlags
ACL Rights - These show permission to...
Definition mailbox.h:58
MailboxType
Supported mailbox formats.
Definition mailbox.h:40
@ MUTT_MAILBOX_ERROR
Error occurred examining Mailbox.
Definition mailbox.h:42
@ MUTT_NNTP
'NNTP' (Usenet) Mailbox type
Definition mailbox.h:48
@ MUTT_UNKNOWN
Mailbox wasn't recognised.
Definition mailbox.h:43
size_t mutt_wstr_trunc(const char *src, size_t maxlen, size_t maxwid, size_t *width)
Work out how to truncate a widechar string.
Definition curs_lib.c:386
void mutt_paddstr(struct MuttWindow *win, int n, const char *s)
Display a string on screen, padded if necessary.
Definition curs_lib.c:344
void mutt_refresh(void)
Force a refresh of the screen.
Definition curs_lib.c:79
void mutt_beep(bool force)
Irritate the user.
Definition curs_lib.c:69
size_t mutt_strwidth(const char *s)
Measure a string's width in screen cells.
Definition curs_lib.c:446
@ FR_DONE
Exit the Dialog.
Definition dispatcher.h:36
@ FR_UNKNOWN
Unknown function.
Definition dispatcher.h:34
bool check_acl(struct Mailbox *m, AclFlags acl, const char *msg)
Check the ACLs for a function.
Definition dlg_index.c:137
const struct Mapping IndexNewsHelp[]
Help Bar for the News Index dialog.
Definition dlg_index.c:116
void change_folder_mailbox(struct Menu *menu, struct Mailbox *m, int *oldcount, struct IndexSharedData *shared, bool read_only)
Change to a different Mailbox by pointer.
Definition dlg_index.c:631
struct Mailbox * change_folder_notmuch(struct Menu *menu, char *buf, int buflen, int *oldcount, struct IndexSharedData *shared, bool read_only)
Change to a different Notmuch Mailbox by string.
Definition dlg_index.c:752
void mutt_draw_statusline(struct MuttWindow *win, int max_cols, const char *buf, size_t buflen)
Draw a highlighted status bar.
Definition dlg_index.c:980
void email_set_color(struct Mailbox *m, struct Email *e)
Select an Index colour for an Email.
Definition dlg_index.c:1431
void update_index(struct Menu *menu, struct MailboxView *mv, enum MxStatus check, int oldcount, const struct IndexSharedData *shared)
Update the index.
Definition dlg_index.c:562
void index_change_folder(struct MuttWindow *dlg, struct Mailbox *m)
Change the current folder, cautiously.
Definition dlg_index.c:1490
int find_first_message(struct MailboxView *mv)
Get index of first new message.
Definition dlg_index.c:327
static const struct Mapping IndexHelp[]
Help Bar for the Index dialog.
Definition dlg_index.c:101
static void update_index_threaded(struct MailboxView *mv, enum MxStatus check, int oldcount)
Update the index (if threaded)
Definition dlg_index.c:429
void resort_index(struct MailboxView *mv, struct Menu *menu)
Resort the index.
Definition dlg_index.c:387
int find_next_undeleted(struct MailboxView *mv, int msgno, bool uncollapse)
Find the next undeleted email.
Definition dlg_index.c:259
static void update_index_unthreaded(struct MailboxView *mv, enum MxStatus check)
Update the index (if unthreaded)
Definition dlg_index.c:513
void change_folder_string(struct Menu *menu, struct Buffer *buf, int *oldcount, struct IndexSharedData *shared, bool read_only)
Change to a different Mailbox by string.
Definition dlg_index.c:777
int mutt_make_string(struct Buffer *buf, size_t max_cols, const struct Expando *exp, struct Mailbox *m, int inpgr, struct Email *e, MuttFormatFlags flags, const char *progress)
Create formatted strings using mailbox expandos.
Definition dlg_index.c:824
int find_previous_undeleted(struct MailboxView *mv, int msgno, bool uncollapse)
Find the previous undeleted email.
Definition dlg_index.c:293
struct MuttWindow * index_pager_init(void)
Allocate the Windows for the Index/Pager.
Definition dlg_index.c:1462
static void uncollapse_thread(struct MailboxView *mv, int index)
Open a collapsed thread.
Definition dlg_index.c:237
void collapse_all(struct MailboxView *mv, struct Menu *menu, enum CollapseMode mode)
Collapse/uncollapse all threads.
Definition dlg_index.c:161
Structs that make up an email.
void mutt_sort_headers(struct MailboxView *mv, bool init)
Sort emails by their headers.
Definition sort.c:354
bool OptNeedResort
(pseudo) used to force a re-sort
Definition globals.c:52
EmailSortType
Methods for sorting Emails.
Definition sort.h:53
@ EMAIL_SORT_THREADS
Sort by email threads.
Definition sort.h:62
int expando_filter(const struct Expando *exp, const struct ExpandoRenderCallback *erc, void *data, MuttFormatFlags flags, int max_cols, char **env_list, struct Buffer *buf)
Render an Expando and run the result through a filter.
Definition filter.c:139
Parse Expando string.
const struct ExpandoRenderCallback IndexRenderCallbacks[]
Callbacks for Index Expandos.
String processing routines to generate the mail index.
struct KeyEvent km_dokey(const struct MenuDefinition *md, GetChFlags flags)
Determine what a keypress should do.
Definition get.c:437
void km_error_key(const struct MenuDefinition *md)
Handle an unbound key sequence.
Definition get.c:287
void mutt_flush_macro_to_endcond(void)
Drop a macro from the input buffer.
Definition get.c:156
#define GETCH_NO_FLAGS
No flags are set.
Definition get.h:34
bool OptNews
(pseudo) used to change reader mode
Definition globals.c:53
char * LastFolder
Previously selected mailbox.
Definition globals.c:39
char * CurrentFolder
Currently selected mailbox.
Definition globals.c:38
Global variables.
int sb_function_dispatcher(struct MuttWindow *win, const struct KeyEvent *event)
Perform a Sidebar function - Implements function_dispatcher_t -.
Definition functions.c:622
int index_function_dispatcher(struct MuttWindow *win, const struct KeyEvent *event)
Perform an Index function - Implements function_dispatcher_t -.
Definition functions.c:3513
int global_function_dispatcher(struct MuttWindow *win, const struct KeyEvent *event)
Perform a Global function - Implements function_dispatcher_t -.
Definition global.c:182
int menu_function_dispatcher(struct MuttWindow *win, const struct KeyEvent *event)
Perform a Menu function - Implements function_dispatcher_t -.
Definition functions.c:324
struct Mailbox * dlg_index(struct MuttWindow *dlg, struct Mailbox *m_init)
Display a list of emails -.
Definition dlg_index.c:1121
#define mutt_error(...)
Definition logging2.h:94
#define mutt_message(...)
Definition logging2.h:93
#define mutt_debug(LEVEL,...)
Definition logging2.h:91
const struct AttrColor * index_color(struct Menu *menu, int line)
Calculate the colour for a line of the index - Implements Menu::color() -.
Definition dlg_index.c:948
int index_make_entry(struct Menu *menu, int line, int max_cols, struct Buffer *buf)
Format an Email for the Menu - Implements Menu::make_entry() -.
Definition dlg_index.c:847
static int index_mailbox_observer(struct NotifyCallback *nc)
Notification that a Mailbox has changed - Implements observer_t -.
Definition dlg_index.c:605
void index_shared_data_free(struct MuttWindow *win, void **ptr)
Free Shared Index Data - Implements MuttWindow::wdata_free() -.
Convenience wrapper for the gui headers.
void mutt_thread_collapse(struct ThreadsContext *tctx, bool collapse)
Toggle collapse.
Definition thread.c:1868
enum UseThreads mutt_thread_style(void)
Which threading style is active?
Definition thread.c:79
off_t mutt_set_vnum(struct Mailbox *m)
Set the virtual index number of all the messages in a mailbox.
Definition thread.c:1483
bool mutt_thread_can_collapse(struct Email *e)
Check whether a thread can be collapsed.
Definition thread.c:1896
int mutt_parent_message(struct Email *e, bool find_root)
Find the parent of a message.
Definition thread.c:1433
UseThreads
Which threading style is active, $use_threads.
Definition thread.h:96
@ UT_FLAT
Unthreaded.
Definition thread.h:98
@ UT_THREADS
Normal threading (root above subthreads)
Definition thread.h:99
@ UT_REVERSE
Reverse threading (subthreads above root)
Definition thread.h:100
#define mutt_using_threads()
Definition thread.h:113
#define mutt_uncollapse_thread(e)
Definition thread.h:107
#define mutt_collapse_thread(e)
Definition thread.h:106
void exec_folder_hook(const char *path, const char *desc)
Perform a folder hook.
Definition exec.c:64
Hook Commands.
Index functions.
GUI manage the main index (list of emails)
CollapseMode
Action to perform on a Thread.
Definition lib.h:90
@ COLLAPSE_MODE_TOGGLE
Toggle collapsed state.
Definition lib.h:91
@ COLLAPSE_MODE_CLOSE
Collapse all threads.
Definition lib.h:92
@ COLLAPSE_MODE_OPEN
Open all threads.
Definition lib.h:93
Index private Module data.
Private Index Functions.
Private state data for the Index.
void index_shared_data_set_email(struct IndexSharedData *shared, struct Email *e)
Set the current Email for the Index and friends.
bool index_shared_data_is_cur_email(const struct IndexSharedData *shared, const struct Email *e)
Check whether an email is the currently selected Email.
struct IndexSharedData * index_shared_data_new(void)
Create new Index Data.
void index_shared_data_set_mview(struct IndexSharedData *shared, struct MailboxView *mv)
Set the MailboxView for the Index and friends.
Data shared between Index, Pager and Sidebar.
void index_adjust_sort_threads(const struct ConfigSubset *sub)
Adjust use_threads/sort/sort_aux.
Definition index.c:185
struct MuttWindow * ipanel_new(bool status_on_top, struct IndexSharedData *shared)
Create the Windows for the Index panel.
Definition ipanel.c:121
Manage keymappings.
@ LL_DEBUG5
Log at debug level 5.
Definition logging2.h:49
@ LL_DEBUG1
Log at debug level 1.
Definition logging2.h:45
#define FREE(x)
Free memory and set the pointer to NULL.
Definition memory.h:68
#define MIN(a, b)
Return the minimum of two values.
Definition memory.h:40
#define MUTT_MEM_REALLOC(pptr, n, type)
Definition memory.h:55
#define MUTT_MEM_MALLOC(n, type)
Definition memory.h:53
#define MAX(a, b)
Return the maximum of two values.
Definition memory.h:38
GUI present the user with a selectable list.
#define MENU_REDRAW_FULL
Redraw everything.
Definition lib.h:60
#define MENU_REDRAW_INDEX
Redraw the index.
Definition lib.h:57
void menu_queue_redraw(struct Menu *menu, MenuRedrawFlags redraw)
Queue a request for a redraw.
Definition menu.c:189
int menu_get_index(struct Menu *menu)
Get the current selection in the Menu.
Definition menu.c:165
MenuRedrawFlags menu_set_index(struct Menu *menu, int index)
Set the current selection in the Menu.
Definition menu.c:179
const struct AttrColor * merged_color_overlay(const struct AttrColor *base, const struct AttrColor *over)
Combine two colours.
Definition merged.c:110
@ MODULE_ID_INDEX
ModuleIndex, Index
Definition module_api.h:72
@ MODULE_ID_NNTP
ModuleNntp, Nntp
Definition module_api.h:81
int mutt_monitor_add(struct Mailbox *m)
Add a watch for a mailbox.
Definition monitor.c:484
int mutt_monitor_remove(struct Mailbox *m)
Remove a watch for a mailbox.
Definition monitor.c:528
Monitor files for changes.
void msgwin_clear_text(struct MuttWindow *win)
Clear the text in the Message Window.
Definition msgwin.c:522
void msgwin_set_text(struct MuttWindow *win, const char *text, enum ColorId color)
Set the text for the Message Window.
Definition msgwin.c:487
Convenience wrapper for the library headers.
#define N_(a)
Definition message.h:32
#define _(a)
Definition message.h:28
bool notify_observer_remove(struct Notify *notify, const observer_t callback, const void *global_data)
Remove an observer from an object.
Definition notify.c:230
bool notify_observer_add(struct Notify *notify, enum NotifyType type, observer_t callback, void *global_data)
Add an observer to an object.
Definition notify.c:191
void notify_set_parent(struct Notify *notify, struct Notify *parent)
Set the parent notification handler.
Definition notify.c:95
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition string.c:257
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition string.c:284
Many unsorted constants and some structs.
int mutt_system(const char *cmd)
Run an external command.
Definition system.c:51
void mutt_curses_set_color(const struct AttrColor *ac)
Set the colour and attributes for text.
Definition mutt_curses.c:38
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
NeoMutt Logging.
int mutt_mailbox_check(struct Mailbox *m_cur, CheckStatsFlags flags)
Check all all Mailboxes for new mail.
bool mutt_mailbox_notify(struct Mailbox *m_cur)
Notify the user if there's new mail.
Mailbox helper functions.
void window_redraw(struct MuttWindow *win)
Reflow, recalc and repaint a tree of Windows.
void mutt_window_reflow(struct MuttWindow *win)
Resize a Window and its children.
void mutt_window_add_child(struct MuttWindow *parent, struct MuttWindow *child)
Add a child to Window.
struct MuttWindow * mutt_window_new(enum WindowType type, enum MuttWindowOrientation orient, enum MuttWindowSize size, int cols, int rows)
Create a new Window.
struct MuttWindow * window_set_focus(struct MuttWindow *win)
Set the Window focus.
int mutt_window_move(struct MuttWindow *win, int row, int col)
Move the cursor in a Window.
struct MuttWindow * window_find_child(struct MuttWindow *win, enum WindowType type)
Recursively find a child Window of a given type.
int mutt_window_addnstr(struct MuttWindow *win, const char *str, int num)
Write a partial string to a Window.
@ WT_DLG_INDEX
Index Dialog, dlg_index()
Definition mutt_window.h:86
@ WT_INDEX
A panel containing the Index Window.
Definition mutt_window.h:96
@ WT_SIDEBAR
Side panel containing Accounts or groups of data.
@ WT_MENU
An Window containing a Menu.
Definition mutt_window.h:97
@ MUTT_WIN_ORIENT_HORIZONTAL
Window uses all available horizontal space.
Definition mutt_window.h:39
#define MUTT_WIN_SIZE_UNLIMITED
Use as much space as possible.
Definition mutt_window.h:52
@ MUTT_WIN_SIZE_MAXIMISE
Window wants as much space as possible.
Definition mutt_window.h:48
struct Email * mutt_get_virt_email(struct Mailbox *m, int vnum)
Get a virtual Email.
Definition mview.c:415
void mview_free(struct MailboxView **ptr)
Free a MailboxView.
Definition mview.c:47
bool mview_has_limit(const struct MailboxView *mv)
Is a limit active?
Definition mview.c:436
struct MailboxView * mview_new(struct Mailbox *m, struct Notify *parent)
Create a new MailboxView.
Definition mview.c:88
int mx_msg_padding_size(struct Mailbox *m)
Bytes of padding between messages - Wrapper for MxOps::msg_padding_size()
Definition mx.c:1507
int mx_path_canon(struct Buffer *path, const char *folder, enum MailboxType *type)
Canonicalise a mailbox path - Wrapper for MxOps::path_canon()
Definition mx.c:1369
bool mx_mbox_open(struct Mailbox *m, OpenMailboxFlags flags)
Open a mailbox and parse it.
Definition mx.c:285
enum MailboxType mx_path_probe(const char *path)
Find a mailbox that understands a path.
Definition mx.c:1323
struct Mailbox * mx_path_resolve(const char *path)
Get a Mailbox for a path.
Definition mx.c:1647
enum MxStatus mx_mbox_check(struct Mailbox *m)
Check for new mail - Wrapper for MxOps::mbox_check()
Definition mx.c:1107
enum MxStatus mx_mbox_close(struct Mailbox *m)
Save changes and close mailbox.
Definition mx.c:595
API for mailboxes.
#define MUTT_READONLY
Open in read-only mode.
Definition mxapi.h:42
uint8_t OpenMailboxFlags
Flags for mutt_open_mailbox(), e.g. MUTT_NOSORT.
Definition mxapi.h:38
#define MUTT_MAILBOX_CHECK_NO_FLAGS
No flags are set.
Definition mxapi.h:49
#define MUTT_OPEN_NO_FLAGS
No flags are set.
Definition mxapi.h:39
#define MUTT_MAILBOX_CHECK_POSTPONED
Make sure the number of postponed messages is updated.
Definition mxapi.h:50
MxStatus
Return values from mbox_check(), mbox_check_stats(), mbox_sync(), and mbox_close()
Definition mxapi.h:59
@ MX_STATUS_ERROR
An error occurred.
Definition mxapi.h:60
@ MX_STATUS_OK
No changes.
Definition mxapi.h:61
@ MX_STATUS_FLAGS
Nondestructive flags change (IMAP)
Definition mxapi.h:65
@ MX_STATUS_REOPENED
Mailbox was reopened.
Definition mxapi.h:64
@ MX_STATUS_NEW_MAIL
New mail received in Mailbox.
Definition mxapi.h:62
void * neomutt_get_module_data(struct NeoMutt *n, enum ModuleId id)
Get the private data for a Module.
Definition neomutt.c:665
Nntp-specific Account data.
Usenet network mailbox type; talk to an NNTP server.
void nntp_expand_path(char *buf, size_t buflen, struct ConnAccount *acct)
Make fully qualified url from newsgroup name.
Definition newsrc.c:557
Nntp private Module data.
@ NT_MAILBOX
Mailbox has changed, NotifyMailbox, EventMailbox.
Definition notify_type.h:49
void nm_db_debug_check(struct Mailbox *m)
Check if the database is open.
Definition db.c:412
Notmuch virtual mailbox type.
char * nm_url_from_query(struct Mailbox *m, char *buf, size_t buflen)
Turn a query into a URL.
Definition notmuch.c:1615
const char * opcodes_get_name(int op)
Get the name of an opcode.
Definition opcodes.c:48
#define OP_TIMEOUT
1 second with no events
Definition opcodes.h:35
#define OP_REPAINT
Repaint is needed.
Definition opcodes.h:34
GUI display a file/email/help in a viewport with paging.
struct MuttWindow * ppanel_new(bool status_on_top, struct IndexSharedData *shared)
Create the Windows for the Pager panel.
Definition ppanel.c:133
bool mutt_pattern_exec(struct Pattern *pat, PatternExecFlags flags, struct Mailbox *m, struct Email *e, struct PatternCache *cache)
Match a pattern against an email header.
Definition exec.c:1151
Match patterns to emails.
#define MUTT_MATCH_FULL_ADDRESS
Match the full address.
Definition lib.h:107
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition pool.c:91
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition pool.c:111
#define STAILQ_FOREACH(var, head, field)
Definition queue.h:390
#define SLIST_FIRST(head)
Definition queue.h:227
#define MUTT_FORMAT_FORCESUBJ
Print the subject even if unchanged.
Definition render.h:34
#define MUTT_FORMAT_INDEX
This is a main index entry.
Definition render.h:38
#define MUTT_FORMAT_TREE
Draw the thread tree.
Definition render.h:35
#define MUTT_FORMAT_ARROWCURSOR
Reserve space for arrow_cursor.
Definition render.h:37
uint8_t MuttFormatFlags
Flags for expando_render(), e.g. MUTT_FORMAT_FORCESUBJ.
Definition render.h:32
GUI display the mailboxes in a side panel.
#define ASSERT(COND)
Definition signal2.h:59
void menu_status_line(struct Buffer *buf, struct IndexSharedData *shared, struct Menu *menu, int max_cols, const struct Expando *exp)
Create the status line.
Definition status.c:51
GUI display a user-configurable status line.
A curses colour and its attributes.
Definition attr.h:65
The body of an email.
Definition body.h:36
LOFF_T offset
offset where the actual data begins
Definition body.h:52
LOFF_T length
length (in bytes) of attachment
Definition body.h:53
long hdr_offset
Offset in stream where the headers begin.
Definition body.h:81
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
struct ConnAccount account
Account details: username, password, etc.
Definition connection.h:49
Data passed to index_format_str()
Definition private.h:37
struct Email * email
Current Email.
Definition private.h:40
struct Mailbox * mailbox
Current Mailbox.
Definition private.h:38
int msg_in_pager
Index of Email displayed in the Pager.
Definition private.h:39
const char * pager_progress
String representing Pager position through Email.
Definition private.h:41
The envelope/body of an email.
Definition email.h:39
bool read
Email is read.
Definition email.h:50
bool display_subject
Used for threading.
Definition email.h:101
bool visible
Is this message part of the view?
Definition email.h:121
bool limit_visited
Has the limit pattern been applied to this message?
Definition email.h:122
bool collapsed
Is this message part of a collapsed thread?
Definition email.h:120
struct Body * body
List of MIME parts.
Definition email.h:69
char * tree
Character string to print thread tree.
Definition email.h:125
bool old
Email is seen, but unread.
Definition email.h:49
LOFF_T offset
Where in the stream does this message begin?
Definition email.h:71
const struct AttrColor * attr_color
Color-pair to use when displaying in the index.
Definition email.h:112
int vnum
Virtual message number.
Definition email.h:114
int msgno
Number displayed to the user.
Definition email.h:111
bool deleted
Email is deleted.
Definition email.h:78
int index
The absolute (unsorted) message number.
Definition email.h:110
struct MuttThread * thread
Thread of Emails.
Definition email.h:119
An Event that happened to a Mailbox.
Definition mailbox.h:189
struct Mailbox * mailbox
The Mailbox this Event relates to.
Definition mailbox.h:190
Parsed Expando trees.
Definition expando.h:41
Index private Module data.
Definition module_data.h:32
struct MenuDefinition * menu_index
Index menu definition.
Definition module_data.h:34
Private state data for the Index.
struct MuttWindow * win_index
Window for the Index.
struct IndexSharedData * shared
Shared Index data.
bool tag_prefix
tag-prefix has been pressed
bool do_mailbox_notify
Do we need to notify the user of new mail?
struct Menu * menu
Menu controlling the index.
int oldcount
Old count of mails in the mailbox.
Data shared between Index, Pager and Sidebar.
Definition shared_data.h:37
struct Mailbox * mailbox
Current Mailbox.
Definition shared_data.h:41
bool attach_msg
Are we in "attach message" mode?
Definition shared_data.h:46
struct ConfigSubset * sub
Config set to use.
Definition shared_data.h:38
struct MailboxView * mailbox_view
Current Mailbox view.
Definition shared_data.h:40
struct SearchState * search_state
State of the current search.
Definition shared_data.h:45
struct Notify * notify
Notifications: NotifyIndex, IndexSharedData.
Definition shared_data.h:44
An event such as a keypress.
Definition get.h:50
int op
Function opcode, e.g. OP_HELP.
Definition get.h:52
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
off_t vsize
Size (in bytes) of the messages shown.
Definition mview.h:41
struct PatternList * limit_pattern
Compiled limit pattern.
Definition mview.h:43
struct ThreadsContext * threads
Threads context.
Definition mview.h:44
int msg_in_pager
Message currently shown in the pager.
Definition mview.h:45
struct Mailbox * mailbox
Current Mailbox.
Definition mview.h:51
A mailbox.
Definition mailbox.h:78
int vcount
The number of virtual messages.
Definition mailbox.h:98
char * realpath
Used for duplicate detection, context comparison, and the sidebar.
Definition mailbox.h:80
int * v2r
Mapping from virtual to real msgno.
Definition mailbox.h:97
int msg_count
Total number of messages.
Definition mailbox.h:87
AclFlags rights
ACL bits, see AclFlags.
Definition mailbox.h:118
int email_max
Size of emails array.
Definition mailbox.h:96
enum MailboxType type
Mailbox type.
Definition mailbox.h:101
struct Email ** emails
Array of Emails.
Definition mailbox.h:95
char * name
A short name for the Mailbox.
Definition mailbox.h:81
struct Notify * notify
Notifications: NotifyMailbox, EventMailbox.
Definition mailbox.h:144
struct Buffer pathbuf
Path of the Mailbox.
Definition mailbox.h:79
void * compress_info
Compressed mbox module private data.
Definition mailbox.h:120
int msg_tagged
How many messages are tagged?
Definition mailbox.h:93
bool verbose
Display status messages?
Definition mailbox.h:116
struct ConfigSubset * sub
Inherited config items.
Definition mailbox.h:82
Mapping between user-readable string and a constant.
Definition mapping.h:33
Definition lib.h:80
struct MuttWindow * win
Window holding the Menu.
Definition lib.h:88
int current
Current entry.
Definition lib.h:81
const struct AttrColor *(* color)(struct Menu *menu, int line)
Definition lib.h:145
int top
Entry that is the top of the current page.
Definition lib.h:92
int(* make_entry)(struct Menu *menu, int line, int max_cols, struct Buffer *buf)
Definition lib.h:108
struct ConfigSubset * sub
Inherited config items.
Definition lib.h:89
void * mdata
Private data.
Definition lib.h:149
int max
Number of entries in the menu.
Definition lib.h:82
int page_len
Number of entries per screen.
Definition lib.h:85
An Email conversation.
Definition thread.h:34
struct MuttThread * parent
Parent of this Thread.
Definition thread.h:44
struct MuttThread * prev
Previous sibling Thread.
Definition thread.h:47
struct Email * message
Email this Thread refers to.
Definition thread.h:49
const struct Mapping * help_data
Data for the Help Bar.
const struct MenuDefinition * help_md
Menu Definition for key bindings.
struct WindowState state
Current state of the Window.
void * wdata
Private data.
struct Notify * notify
Notifications: NotifyWindow, EventWindow.
void(* wdata_free)(struct MuttWindow *win, void **ptr)
Container for Accounts, Notifications.
Definition neomutt.h:41
char ** env
Private copy of the environment variables.
Definition neomutt.h:57
struct Notify * notify
Notifications handler.
Definition neomutt.h:45
struct ConfigSubset * sub
Inherited config items.
Definition neomutt.h:49
struct Connection * conn
Connection to NNTP Server.
Definition adata.h:63
Nntp private Module data.
Definition module_data.h:30
struct NntpAccountData * current_news_srv
Current NNTP news server.
Definition module_data.h:32
Data passed to a notification function.
Definition observer.h:34
enum NotifyType event_type
Send: Event type, e.g. NT_ACCOUNT.
Definition observer.h:36
int event_subtype
Send: Event subtype, e.g. NT_ACCOUNT_ADD.
Definition observer.h:37
void * global_data
Data from notify_observer_add()
Definition observer.h:39
Cache commonly-used patterns.
Definition lib.h:118
A regular expression and a color to highlight a line.
Definition regex4.h:35
regex_t regex
Compiled regex.
Definition regex4.h:38
struct PatternList * color_pattern
Compiled pattern to speed up index color calculation.
Definition regex4.h:40
struct AttrColor attr_color
Colour and attributes to apply.
Definition regex4.h:36
int match
Substring to match, 0 for old behaviour.
Definition regex4.h:39
struct PatternList * pattern
compiled search pattern
short cols
Number of columns, can be MUTT_WIN_SIZE_UNLIMITED.
Definition mutt_window.h:60