NeoMutt  2022-04-29-215-gc12b98
Teaching an old dog new tricks
DOXYGEN
dlg_index.c
Go to the documentation of this file.
1
55#include "config.h"
56#include <assert.h>
57#include <stdbool.h>
58#include <stdio.h>
59#include "private.h"
60#include "mutt/lib.h"
61#include "config/lib.h"
62#include "email/lib.h"
63#include "core/lib.h"
64#include "conn/lib.h"
65#include "gui/lib.h"
66#include "lib.h"
67#include "color/lib.h"
68#include "menu/lib.h"
69#include "pager/lib.h"
70#include "pattern/lib.h"
71#include "format_flags.h"
72#include "functions.h"
73#include "hdrline.h"
74#include "hook.h"
75#include "keymap.h"
76#include "mutt_globals.h"
77#include "mutt_logging.h"
78#include "mutt_mailbox.h"
79#include "mutt_thread.h"
80#include "mview.h"
81#include "mx.h"
82#include "opcodes.h"
83#include "options.h"
84#include "private_data.h"
85#include "protos.h"
86#include "shared_data.h"
87#include "sort.h"
88#include "status.h"
89#ifdef USE_NOTMUCH
90#include "notmuch/lib.h"
91#endif
92#ifdef USE_NNTP
93#include "nntp/lib.h"
94#include "nntp/adata.h" // IWYU pragma: keep
95#include "nntp/mdata.h" // IWYU pragma: keep
96#endif
97#ifdef USE_INOTIFY
98#include "monitor.h"
99#endif
100#ifdef USE_SIDEBAR
101#include "sidebar/lib.h"
102#endif
103
105static const struct Mapping IndexHelp[] = {
106 // clang-format off
107 { N_("Quit"), OP_QUIT },
108 { N_("Del"), OP_DELETE },
109 { N_("Undel"), OP_UNDELETE },
110 { N_("Save"), OP_SAVE },
111 { N_("Mail"), OP_MAIL },
112 { N_("Reply"), OP_REPLY },
113 { N_("Group"), OP_GROUP_REPLY },
114 { N_("Help"), OP_HELP },
115 { NULL, 0 },
116 // clang-format on
117};
118
119#ifdef USE_NNTP
121const struct Mapping IndexNewsHelp[] = {
122 // clang-format off
123 { N_("Quit"), OP_QUIT },
124 { N_("Del"), OP_DELETE },
125 { N_("Undel"), OP_UNDELETE },
126 { N_("Save"), OP_SAVE },
127 { N_("Post"), OP_POST },
128 { N_("Followup"), OP_FOLLOWUP },
129 { N_("Catchup"), OP_CATCHUP },
130 { N_("Help"), OP_HELP },
131 { NULL, 0 },
132 // clang-format on
133};
134#endif
135
143bool check_acl(struct Mailbox *m, AclFlags acl, const char *msg)
144{
145 if (!m)
146 return false;
147
148 if (!(m->rights & acl))
149 {
150 /* L10N: %s is one of the CHECK_ACL entries below. */
151 mutt_error(_("%s: Operation not permitted by ACL"), msg);
152 return false;
153 }
154
155 return true;
156}
157
170void collapse_all(struct MailboxView *mv, struct Menu *menu, int toggle)
171{
172 if (!mv || !mv->mailbox || (mv->mailbox->msg_count == 0) || !menu)
173 return;
174
175 struct Email *e_cur = mutt_get_virt_email(mv->mailbox, menu_get_index(menu));
176 if (!e_cur)
177 return;
178
179 int final;
180
181 /* Figure out what the current message would be after folding / unfolding,
182 * so that we can restore the cursor in a sane way afterwards. */
183 if (e_cur->collapsed && toggle)
184 final = mutt_uncollapse_thread(e_cur);
185 else if (mutt_thread_can_collapse(e_cur))
186 final = mutt_collapse_thread(e_cur);
187 else
188 final = e_cur->vnum;
189
190 if (final == -1)
191 return;
192
193 struct Email *base = mutt_get_virt_email(mv->mailbox, final);
194 if (!base)
195 return;
196
197 /* Iterate all threads, perform collapse/uncollapse as needed */
198 mv->collapsed = toggle ? !mv->collapsed : true;
200
201 /* Restore the cursor */
203 menu->max = mv->mailbox->vcount;
204 for (int i = 0; i < mv->mailbox->vcount; i++)
205 {
206 struct Email *e = mutt_get_virt_email(mv->mailbox, i);
207 if (!e)
208 break;
209 if (e->index == base->index)
210 {
211 menu_set_index(menu, i);
212 break;
213 }
214 }
215
217}
218
224static void uncollapse_thread(struct Mailbox *m, int index)
225{
226 struct Email *e = mutt_get_virt_email(m, index);
227 if (e && e->collapsed)
228 {
230 mutt_set_vnum(m);
231 }
232}
233
242int ci_next_undeleted(struct Mailbox *m, int msgno, bool uncollapse)
243{
244 if (!m)
245 return -1;
246
247 int index = -1;
248
249 for (int i = msgno + 1; i < m->vcount; i++)
250 {
251 struct Email *e = mutt_get_virt_email(m, i);
252 if (!e)
253 continue;
254 if (!e->deleted)
255 {
256 index = i;
257 break;
258 }
259 }
260
261 if (uncollapse)
263
264 return index;
265}
266
275int ci_previous_undeleted(struct Mailbox *m, int msgno, bool uncollapse)
276{
277 if (!m)
278 return -1;
279
280 int index = -1;
281
282 for (int i = msgno - 1; i >= 0; i--)
283 {
284 struct Email *e = mutt_get_virt_email(m, i);
285 if (!e)
286 continue;
287 if (!e->deleted)
288 {
289 index = i;
290 break;
291 }
292 }
293
294 if (uncollapse)
296
297 return index;
298}
299
309{
310 if (!m || (m->msg_count == 0))
311 return 0;
312
313 int old = -1;
314 for (int i = 0; i < m->vcount; i++)
315 {
316 struct Email *e = mutt_get_virt_email(m, i);
317 if (!e)
318 continue;
319 if (!e->read && !e->deleted)
320 {
321 if (!e->old)
322 return i;
323 if (old == -1)
324 old = i;
325 }
326 }
327 if (old != -1)
328 return old;
329
330 /* If `$use_threads` is not threaded and `$sort` is reverse, the latest
331 * message is first. Otherwise, the latest message is first if exactly
332 * one of `$use_threads` and `$sort` are reverse.
333 */
334 short c_sort = cs_subset_sort(m->sub, "sort");
335 if ((c_sort & SORT_MASK) == SORT_THREADS)
336 c_sort = cs_subset_sort(m->sub, "sort_aux");
337 bool reverse = false;
338 switch (mutt_thread_style())
339 {
340 case UT_FLAT:
341 reverse = c_sort & SORT_REVERSE;
342 break;
343 case UT_THREADS:
344 reverse = c_sort & SORT_REVERSE;
345 break;
346 case UT_REVERSE:
347 reverse = !(c_sort & SORT_REVERSE);
348 break;
349 default:
350 assert(false);
351 }
352
353 if (reverse || (m->vcount == 0))
354 return 0;
355
356 return m->vcount - 1;
357}
358
364void resort_index(struct MailboxView *mv, struct Menu *menu)
365{
366 if (!mv || !mv->mailbox || !menu)
367 return;
368
369 struct Mailbox *m = mv->mailbox;
370 const int old_index = menu_get_index(menu);
371 struct Email *e_cur = mutt_get_virt_email(m, old_index);
372
373 int new_index = -1;
374 mutt_sort_headers(m, mv->threads, false, &mv->vsize);
375
376 /* Restore the current message */
377 for (int i = 0; i < m->vcount; i++)
378 {
379 struct Email *e = mutt_get_virt_email(m, i);
380 if (!e)
381 continue;
382 if (e == e_cur)
383 {
384 new_index = i;
385 break;
386 }
387 }
388
389 if (mutt_using_threads() && (old_index < 0))
390 new_index = mutt_parent_message(e_cur, false);
391
392 if (old_index < 0)
393 new_index = ci_first_message(m);
394
395 menu->max = m->vcount;
396 menu_set_index(menu, new_index);
398}
399
406static void update_index_threaded(struct MailboxView *mv, enum MxStatus check, int oldcount)
407{
408 struct Email **save_new = NULL;
409 const bool lmt = mview_has_limit(mv);
410
411 struct Mailbox *m = mv->mailbox;
412 int num_new = MAX(0, m->msg_count - oldcount);
413
414 const bool c_uncollapse_new = cs_subset_bool(m->sub, "uncollapse_new");
415 /* save the list of new messages */
416 if ((check != MX_STATUS_REOPENED) && (oldcount > 0) &&
417 (lmt || c_uncollapse_new) && (num_new > 0))
418 {
419 save_new = mutt_mem_malloc(num_new * sizeof(struct Email *));
420 for (int i = oldcount; i < m->msg_count; i++)
421 save_new[i - oldcount] = m->emails[i];
422 }
423
424 /* Sort first to thread the new messages, because some patterns
425 * require the threading information.
426 *
427 * If the mailbox was reopened, need to rethread from scratch. */
428 mutt_sort_headers(m, mv->threads, (check == MX_STATUS_REOPENED), &mv->vsize);
429
430 if (lmt)
431 {
432 /* Because threading changes the order in m->emails, we don't
433 * know which emails are new. Hence, we need to re-apply the limit to the
434 * whole set.
435 */
436 for (int i = 0; i < m->msg_count; i++)
437 {
438 struct Email *e = m->emails[i];
439 if ((e->vnum != -1) || mutt_pattern_exec(SLIST_FIRST(mv->limit_pattern),
440 MUTT_MATCH_FULL_ADDRESS, m, e, NULL))
441 {
442 /* vnum will get properly set by mutt_set_vnum(), which
443 * is called by mutt_sort_headers() just below. */
444 e->vnum = 1;
445 e->visible = true;
446 }
447 else
448 {
449 e->vnum = -1;
450 e->visible = false;
451 }
452 }
453 /* Need a second sort to set virtual numbers and redraw the tree */
454 mutt_sort_headers(m, mv->threads, false, &mv->vsize);
455 }
456
457 /* uncollapse threads with new mail */
458 if (c_uncollapse_new)
459 {
460 if (check == MX_STATUS_REOPENED)
461 {
462 mv->collapsed = false;
464 mutt_set_vnum(m);
465 }
466 else if (oldcount > 0)
467 {
468 for (int j = 0; j < num_new; j++)
469 {
470 if (save_new[j]->visible)
471 {
472 mutt_uncollapse_thread(save_new[j]);
473 }
474 }
475 mutt_set_vnum(m);
476 }
477 }
478
479 FREE(&save_new);
480}
481
487static void update_index_unthreaded(struct MailboxView *mv, enum MxStatus check)
488{
489 /* We are in a limited view. Check if the new message(s) satisfy
490 * the limit criteria. If they do, set their virtual msgno so that
491 * they will be visible in the limited view */
492 if (mview_has_limit(mv))
493 {
494 int padding = mx_msg_padding_size(mv->mailbox);
495 mv->mailbox->vcount = mv->vsize = 0;
496 for (int i = 0; i < mv->mailbox->msg_count; i++)
497 {
498 struct Email *e = mv->mailbox->emails[i];
499 if (!e)
500 break;
502 MUTT_MATCH_FULL_ADDRESS, mv->mailbox, e, NULL))
503 {
504 assert(mv->mailbox->vcount < mv->mailbox->msg_count);
505 e->vnum = mv->mailbox->vcount;
506 mv->mailbox->v2r[mv->mailbox->vcount] = i;
507 e->visible = true;
508 mv->mailbox->vcount++;
509 struct Body *b = e->body;
510 mv->vsize += b->length + b->offset - b->hdr_offset + padding;
511 }
512 else
513 {
514 e->visible = false;
515 }
516 }
517 }
518
519 /* if the mailbox was reopened, need to rethread from scratch */
520 mutt_sort_headers(mv->mailbox, mv->threads, (check == MX_STATUS_REOPENED), &mv->vsize);
521}
522
531void update_index(struct Menu *menu, struct MailboxView *mv, enum MxStatus check,
532 int oldcount, const struct IndexSharedData *shared)
533{
534 if (!menu || !mv)
535 return;
536
537 struct Mailbox *m = mv->mailbox;
538 if (mutt_using_threads())
539 update_index_threaded(mv, check, oldcount);
540 else
541 update_index_unthreaded(mv, check);
542
543 const int old_index = menu_get_index(menu);
544 int index = -1;
545 if (oldcount)
546 {
547 /* restore the current message to the message it was pointing to */
548 for (int i = 0; i < m->vcount; i++)
549 {
550 struct Email *e = mutt_get_virt_email(m, i);
551 if (!e)
552 continue;
553 if (index_shared_data_is_cur_email(shared, e))
554 {
555 index = i;
556 break;
557 }
558 }
559 }
560
561 if (index < 0)
562 {
563 index = (old_index < m->vcount) ? old_index : ci_first_message(m);
564 }
565 menu_set_index(menu, index);
566}
567
576void mutt_update_index(struct Menu *menu, struct MailboxView *mv, enum MxStatus check,
577 int oldcount, struct IndexSharedData *shared)
578{
579 update_index(menu, mv, check, oldcount, shared);
580}
581
588{
589 if (nc->event_type != NT_MAILBOX)
590 return 0;
591 if (!nc->global_data)
592 return -1;
594 return 0;
595
596 struct Mailbox **ptr = nc->global_data;
597 if (!ptr || !*ptr)
598 return 0;
599
600 *ptr = NULL;
601 mutt_debug(LL_DEBUG5, "mailbox done\n");
602 return 0;
603}
604
613void change_folder_mailbox(struct Menu *menu, struct Mailbox *m, int *oldcount,
614 struct IndexSharedData *shared, bool read_only)
615{
616 if (!m)
617 return;
618
619 /* keepalive failure in mutt_enter_fname may kill connection. */
620 if (shared->mailbox && (mutt_buffer_is_empty(&shared->mailbox->pathbuf)))
621 {
622 mview_free(&shared->mailboxview);
623 mailbox_free(&shared->mailbox);
624 }
625
626 if (shared->mailbox)
627 {
628 char *new_last_folder = NULL;
629#ifdef USE_INOTIFY
630 int monitor_remove_rc = mutt_monitor_remove(NULL);
631#endif
632#ifdef USE_COMP_MBOX
633 if (shared->mailbox->compress_info && (shared->mailbox->realpath[0] != '\0'))
634 new_last_folder = mutt_str_dup(shared->mailbox->realpath);
635 else
636#endif
637 new_last_folder = mutt_str_dup(mailbox_path(shared->mailbox));
638 *oldcount = shared->mailbox->msg_count;
639
640 const enum MxStatus check = mx_mbox_close(shared->mailbox);
641 if (check == MX_STATUS_OK)
642 {
643 mview_free(&shared->mailboxview);
644 if (shared->mailbox != m)
645 {
646 mailbox_free(&shared->mailbox);
647 }
648 }
649 else
650 {
651#ifdef USE_INOTIFY
652 if (monitor_remove_rc == 0)
653 mutt_monitor_add(NULL);
654#endif
655 if ((check == MX_STATUS_NEW_MAIL) || (check == MX_STATUS_REOPENED))
656 update_index(menu, shared->mailboxview, check, *oldcount, shared);
657
658 FREE(&new_last_folder);
659 OptSearchInvalid = true;
661 return;
662 }
664 LastFolder = new_last_folder;
665 }
667
668 /* If the `folder-hook` were to call `unmailboxes`, then the Mailbox (`m`)
669 * could be deleted, leaving `m` dangling. */
670 // TODO: Refactor this function to avoid the need for an observer
672 char *dup_path = mutt_str_dup(mailbox_path(m));
673 char *dup_name = mutt_str_dup(m->name);
674
675 mutt_folder_hook(dup_path, dup_name);
676 if (m)
677 {
678 /* `m` is still valid, but we won't need the observer again before the end
679 * of the function. */
681 }
682 else
683 {
684 // Recreate the Mailbox as the folder-hook might have invoked `mailboxes`
685 // and/or `unmailboxes`.
686 m = mx_path_resolve(dup_path);
687 }
688
689 FREE(&dup_path);
690 FREE(&dup_name);
691
692 if (!m)
693 return;
694
695 const OpenMailboxFlags flags = read_only ? MUTT_READONLY : MUTT_OPEN_NO_FLAGS;
696 if (mx_mbox_open(m, flags))
697 {
698 struct MailboxView *mv = mview_new(m);
700
701 menu->max = m->msg_count;
703#ifdef USE_INOTIFY
704 mutt_monitor_add(NULL);
705#endif
706 }
707 else
708 {
709 index_shared_data_set_context(shared, NULL);
711 }
712
713 const bool c_collapse_all = cs_subset_bool(shared->sub, "collapse_all");
714 if (mutt_using_threads() && c_collapse_all)
715 collapse_all(shared->mailboxview, menu, 0);
716
718 /* force the mailbox check after we have changed the folder */
719 struct EventMailbox ev_m = { shared->mailbox };
722 OptSearchInvalid = true;
723}
724
725#ifdef USE_NOTMUCH
736struct Mailbox *change_folder_notmuch(struct Menu *menu, char *buf, int buflen, int *oldcount,
737 struct IndexSharedData *shared, bool read_only)
738{
739 if (!nm_url_from_query(NULL, buf, buflen))
740 {
741 mutt_message(_("Failed to create query, aborting"));
742 return NULL;
743 }
744
745 struct Mailbox *m_query = mx_path_resolve(buf);
746 change_folder_mailbox(menu, m_query, oldcount, shared, read_only);
747 return m_query;
748}
749#endif
750
760void change_folder_string(struct Menu *menu, char *buf, size_t buflen, int *oldcount,
761 struct IndexSharedData *shared, bool read_only)
762{
763#ifdef USE_NNTP
764 if (OptNews)
765 {
766 OptNews = false;
768 }
769 else
770#endif
771 {
772 const char *const c_folder = cs_subset_string(shared->sub, "folder");
773 mx_path_canon(buf, buflen, c_folder, NULL);
774 }
775
776 enum MailboxType type = mx_path_probe(buf);
777 if ((type == MUTT_MAILBOX_ERROR) || (type == MUTT_UNKNOWN))
778 {
779 // Look for a Mailbox by its description, before failing
780 struct Mailbox *m = mailbox_find_name(buf);
781 if (m)
782 {
783 change_folder_mailbox(menu, m, oldcount, shared, read_only);
784 }
785 else
786 mutt_error(_("%s is not a mailbox"), buf);
787 return;
788 }
789
790 struct Mailbox *m = mx_path_resolve(buf);
791 change_folder_mailbox(menu, m, oldcount, shared, read_only);
792}
793
797void index_make_entry(struct Menu *menu, char *buf, size_t buflen, int line)
798{
799 buf[0] = '\0';
800
801 if (!menu || !menu->mdata)
802 return;
803
804 struct IndexPrivateData *priv = menu->mdata;
805 struct IndexSharedData *shared = priv->shared;
806 struct Mailbox *m = shared->mailbox;
807 if (!shared->mailboxview)
808 menu->current = -1;
809
810 if (!m || (line < 0) || (line >= m->email_max))
811 return;
812
813 struct Email *e = mutt_get_virt_email(m, line);
814 if (!e)
815 return;
816
818 struct MuttThread *tmp = NULL;
819
820 const enum UseThreads c_threads = mutt_thread_style();
821 if ((c_threads > UT_FLAT) && e->tree && e->thread)
822 {
823 flags |= MUTT_FORMAT_TREE; /* display the thread tree */
824 if (e->display_subject)
825 flags |= MUTT_FORMAT_FORCESUBJ;
826 else
827 {
828 const bool reverse = c_threads == UT_REVERSE;
829 int edgemsgno;
830 if (reverse)
831 {
832 if (menu->top + menu->page_len > menu->max)
833 edgemsgno = m->v2r[menu->max - 1];
834 else
835 edgemsgno = m->v2r[menu->top + menu->page_len - 1];
836 }
837 else
838 edgemsgno = m->v2r[menu->top];
839
840 for (tmp = e->thread->parent; tmp; tmp = tmp->parent)
841 {
842 if (!tmp->message)
843 continue;
844
845 /* if no ancestor is visible on current screen, provisionally force
846 * subject... */
847 if (reverse ? (tmp->message->msgno > edgemsgno) : (tmp->message->msgno < edgemsgno))
848 {
849 flags |= MUTT_FORMAT_FORCESUBJ;
850 break;
851 }
852 else if (tmp->message->vnum >= 0)
853 break;
854 }
855 if (flags & MUTT_FORMAT_FORCESUBJ)
856 {
857 for (tmp = e->thread->prev; tmp; tmp = tmp->prev)
858 {
859 if (!tmp->message)
860 continue;
861
862 /* ...but if a previous sibling is available, don't force it */
863 if (reverse ? (tmp->message->msgno > edgemsgno) : (tmp->message->msgno < edgemsgno))
864 break;
865 else if (tmp->message->vnum >= 0)
866 {
867 flags &= ~MUTT_FORMAT_FORCESUBJ;
868 break;
869 }
870 }
871 }
872 }
873 }
874
875 const char *const c_index_format = cs_subset_string(shared->sub, "index_format");
876 int msg_in_pager = shared->mailboxview ? shared->mailboxview->msg_in_pager : 0;
877 mutt_make_string(buf, buflen, menu->win->state.cols, NONULL(c_index_format),
878 m, msg_in_pager, e, flags, NULL);
879}
880
884struct AttrColor *index_color(struct Menu *menu, int line)
885{
886 struct IndexPrivateData *priv = menu->mdata;
887 struct IndexSharedData *shared = priv->shared;
888 struct Mailbox *m = shared->mailbox;
889 if (!m || (line < 0))
890 return NULL;
891
892 struct Email *e = mutt_get_virt_email(m, line);
893 if (!e)
894 return NULL;
895
896 if (e->attr_color)
897 return e->attr_color;
898
900 return e->attr_color;
901}
902
916void mutt_draw_statusline(struct MuttWindow *win, int cols, const char *buf, size_t buflen)
917{
918 if (!buf || !stdscr)
919 return;
920
921 size_t i = 0;
922 size_t offset = 0;
923 bool found = false;
924 size_t chunks = 0;
925 size_t len = 0;
926
930 struct StatusSyntax
931 {
932 struct AttrColor *attr_color;
933 int first;
934 int last;
935 } *syntax = NULL;
936
939 do
940 {
941 struct RegexColor *cl = NULL;
942 found = false;
943
944 if (!buf[offset])
945 break;
946
947 /* loop through each "color status regex" */
949 {
950 regmatch_t pmatch[cl->match + 1];
951
952 if (regexec(&cl->regex, buf + offset, cl->match + 1, pmatch, 0) != 0)
953 continue; /* regex doesn't match the status bar */
954
955 int first = pmatch[cl->match].rm_so + offset;
956 int last = pmatch[cl->match].rm_eo + offset;
957
958 if (first == last)
959 continue; /* ignore an empty regex */
960
961 if (!found)
962 {
963 chunks++;
964 mutt_mem_realloc(&syntax, chunks * sizeof(struct StatusSyntax));
965 }
966
967 i = chunks - 1;
968 if (!found || (first < syntax[i].first) ||
969 ((first == syntax[i].first) && (last > syntax[i].last)))
970 {
971 struct AttrColor *ac_merge = merged_color_overlay(ac_base, &cl->attr_color);
972
973 syntax[i].attr_color = ac_merge;
974 syntax[i].first = first;
975 syntax[i].last = last;
976 }
977 found = true;
978 }
979
980 if (syntax)
981 {
982 offset = syntax[i].last;
983 }
984 } while (found);
985
986 /* Only 'len' bytes will fit into 'cols' screen columns */
987 len = mutt_wstr_trunc(buf, buflen, cols, NULL);
988
989 offset = 0;
990
991 if ((chunks > 0) && (syntax[0].first > 0))
992 {
993 /* Text before the first highlight */
994 mutt_window_addnstr(win, buf, MIN(len, syntax[0].first));
995 mutt_curses_set_color(ac_base);
996 if (len <= syntax[0].first)
997 goto dsl_finish; /* no more room */
998
999 offset = syntax[0].first;
1000 }
1001
1002 for (i = 0; i < chunks; i++)
1003 {
1004 /* Highlighted text */
1005 mutt_curses_set_color(syntax[i].attr_color);
1006 mutt_window_addnstr(win, buf + offset, MIN(len, syntax[i].last) - offset);
1007 if (len <= syntax[i].last)
1008 goto dsl_finish; /* no more room */
1009
1010 size_t next;
1011 if ((i + 1) == chunks)
1012 {
1013 next = len;
1014 }
1015 else
1016 {
1017 next = MIN(len, syntax[i + 1].first);
1018 }
1019
1020 mutt_curses_set_color(ac_base);
1021 offset = syntax[i].last;
1022 mutt_window_addnstr(win, buf + offset, next - offset);
1023
1024 offset = next;
1025 if (offset >= len)
1026 goto dsl_finish; /* no more room */
1027 }
1028
1029 mutt_curses_set_color(ac_base);
1030 if (offset < len)
1031 {
1032 /* Text after the last highlight */
1033 mutt_window_addnstr(win, buf + offset, len - offset);
1034 }
1035
1036 int width = mutt_strwidth(buf);
1037 if (width < cols)
1038 {
1039 /* Pad the rest of the line with whitespace */
1040 mutt_paddstr(win, cols - width, "");
1041 }
1042dsl_finish:
1043 FREE(&syntax);
1044}
1045
1052struct Mailbox *mutt_index_menu(struct MuttWindow *dlg, struct Mailbox *m_init)
1053{
1054 /* Make sure use_threads/sort/sort_aux are coherent */
1056
1057 struct IndexSharedData *shared = dlg->wdata;
1059
1060 struct MuttWindow *panel_index = window_find_child(dlg, WT_INDEX);
1061
1062 struct IndexPrivateData *priv = panel_index->wdata;
1063 priv->attach_msg = OptAttachMsg;
1064 priv->win_index = window_find_child(panel_index, WT_MENU);
1065
1066 int op = OP_NULL;
1067
1068#ifdef USE_NNTP
1069 if (shared->mailbox && (shared->mailbox->type == MUTT_NNTP))
1070 dlg->help_data = IndexNewsHelp;
1071 else
1072#endif
1073 dlg->help_data = IndexHelp;
1074 dlg->help_menu = MENU_INDEX;
1075
1076 priv->menu = priv->win_index->wdata;
1078 priv->menu->color = index_color;
1079 priv->menu->max = shared->mailbox ? shared->mailbox->vcount : 0;
1081 mutt_window_reflow(NULL);
1082
1083 if (!priv->attach_msg)
1084 {
1085 /* force the mailbox check after we enter the folder */
1087 }
1088#ifdef USE_INOTIFY
1089 mutt_monitor_add(NULL);
1090#endif
1091
1092 {
1093 const bool c_collapse_all = cs_subset_bool(shared->sub, "collapse_all");
1094 if (mutt_using_threads() && c_collapse_all)
1095 {
1096 collapse_all(shared->mailboxview, priv->menu, 0);
1098 }
1099 }
1100
1101 int rc = 0;
1102 do
1103 {
1104 /* Clear the tag prefix unless we just started it.
1105 * Don't clear the prefix on a timeout, but do clear on an abort */
1106 if (priv->tag && (op != OP_TAG_PREFIX) && (op != OP_TAG_PREFIX_COND) && (op != OP_TIMEOUT))
1107 {
1108 priv->tag = false;
1109 }
1110
1111 /* check if we need to resort the index because just about
1112 * any 'op' below could do mutt_enter_command(), either here or
1113 * from any new priv->menu launched, and change $sort/$sort_aux */
1114 if (OptNeedResort && shared->mailbox && (shared->mailbox->msg_count != 0) &&
1115 (menu_get_index(priv->menu) >= 0))
1116 {
1118 }
1119
1120 priv->menu->max = shared->mailbox ? shared->mailbox->vcount : 0;
1121 priv->oldcount = shared->mailbox ? shared->mailbox->msg_count : 0;
1122
1123 {
1126 {
1128 OptRedrawTree = false;
1129 }
1130 }
1131
1133 {
1135
1136 shared->mailboxview->menu = priv->menu;
1137 /* check for new mail in the mailbox. If nonzero, then something has
1138 * changed about the file (either we got new mail or the file was
1139 * modified underneath us.) */
1140 enum MxStatus check = mx_mbox_check(shared->mailbox);
1141
1142 if (check == MX_STATUS_ERROR)
1143 {
1145 {
1146 /* fatal error occurred */
1149 }
1150
1151 OptSearchInvalid = true;
1152 }
1153 else if ((check == MX_STATUS_NEW_MAIL) || (check == MX_STATUS_REOPENED) ||
1154 (check == MX_STATUS_FLAGS))
1155 {
1156 /* notify the user of new mail */
1157 if (check == MX_STATUS_REOPENED)
1158 {
1159 mutt_error(_("Mailbox was externally modified. Flags may be wrong."));
1160 }
1161 else if (check == MX_STATUS_NEW_MAIL)
1162 {
1163 for (size_t i = 0; i < shared->mailbox->msg_count; i++)
1164 {
1165 const struct Email *e = shared->mailbox->emails[i];
1166 if (e && !e->read && !e->old)
1167 {
1168 mutt_message(_("New mail in this mailbox"));
1169 const bool c_beep_new = cs_subset_bool(shared->sub, "beep_new");
1170 if (c_beep_new)
1171 mutt_beep(true);
1172 const char *const c_new_mail_command = cs_subset_string(shared->sub, "new_mail_command");
1173 if (c_new_mail_command)
1174 {
1175 char cmd[1024] = { 0 };
1176 menu_status_line(cmd, sizeof(cmd), shared, NULL, sizeof(cmd),
1177 NONULL(c_new_mail_command));
1178 if (mutt_system(cmd) != 0)
1179 mutt_error(_("Error running \"%s\""), cmd);
1180 }
1181 break;
1182 }
1183 }
1184 }
1185 else if (check == MX_STATUS_FLAGS)
1186 {
1187 mutt_message(_("Mailbox was externally modified"));
1188 }
1189
1190 /* avoid the message being overwritten by mailbox */
1191 priv->do_mailbox_notify = false;
1192
1193 bool verbose = shared->mailbox->verbose;
1194 shared->mailbox->verbose = false;
1195 update_index(priv->menu, shared->mailboxview, check, priv->oldcount, shared);
1196 shared->mailbox->verbose = verbose;
1197 priv->menu->max = shared->mailbox->vcount;
1199 OptSearchInvalid = true;
1200 }
1201
1203 menu_get_index(priv->menu)));
1204 }
1205
1206 if (!priv->attach_msg)
1207 {
1208 /* check for new mail in the incoming folders */
1209 priv->oldcount = priv->newcount;
1211 if (priv->do_mailbox_notify)
1212 {
1213 if (mutt_mailbox_notify(shared->mailbox))
1214 {
1215 const bool c_beep_new = cs_subset_bool(shared->sub, "beep_new");
1216 if (c_beep_new)
1217 mutt_beep(true);
1218 const char *const c_new_mail_command = cs_subset_string(shared->sub, "new_mail_command");
1219 if (c_new_mail_command)
1220 {
1221 char cmd[1024] = { 0 };
1222 menu_status_line(cmd, sizeof(cmd), shared, priv->menu, sizeof(cmd),
1223 NONULL(c_new_mail_command));
1224 if (mutt_system(cmd) != 0)
1225 mutt_error(_("Error running \"%s\""), cmd);
1226 }
1227 }
1228 }
1229 else
1230 priv->do_mailbox_notify = true;
1231 }
1232
1233 window_redraw(NULL);
1234
1235 /* give visual indication that the next command is a tag- command */
1236 if (priv->tag)
1238
1239 const bool c_arrow_cursor = cs_subset_bool(shared->sub, "arrow_cursor");
1240 const bool c_braille_friendly = cs_subset_bool(shared->sub, "braille_friendly");
1241 const int index = menu_get_index(priv->menu);
1242 if (c_arrow_cursor)
1243 {
1244 mutt_window_move(priv->menu->win, 2, index - priv->menu->top);
1245 }
1246 else if (c_braille_friendly)
1247 {
1248 mutt_window_move(priv->menu->win, 0, index - priv->menu->top);
1249 }
1250 else
1251 {
1252 mutt_window_move(priv->menu->win, priv->menu->win->state.cols - 1,
1253 index - priv->menu->top);
1254 }
1255 mutt_refresh();
1256
1257 if (SigWinch)
1258 {
1259 SigWinch = false;
1262 priv->menu->top = 0; /* so we scroll the right amount */
1263 /* force a real complete redraw. clrtobot() doesn't seem to be able
1264 * to handle every case without this. */
1265 clearok(stdscr, true);
1267 continue;
1268 }
1269
1270 window_redraw(NULL);
1271 op = km_dokey(MENU_INDEX);
1272
1273 /* either user abort or timeout */
1274 if (op < OP_NULL)
1275 {
1277 if (priv->tag)
1279 continue;
1280 }
1281
1282 mutt_debug(LL_DEBUG1, "Got op %s (%d)\n", opcodes_get_name(op), op);
1283
1284 /* special handling for the priv->tag-prefix function */
1285 const bool c_auto_tag = cs_subset_bool(shared->sub, "auto_tag");
1286 if ((op == OP_TAG_PREFIX) || (op == OP_TAG_PREFIX_COND))
1287 {
1288 /* A second priv->tag-prefix command aborts */
1289 if (priv->tag)
1290 {
1291 priv->tag = false;
1293 continue;
1294 }
1295
1296 if (!shared->mailbox)
1297 {
1298 mutt_error(_("No mailbox is open"));
1299 continue;
1300 }
1301
1302 if (shared->mailbox->msg_tagged == 0)
1303 {
1304 if (op == OP_TAG_PREFIX)
1305 mutt_error(_("No tagged messages"));
1306 else if (op == OP_TAG_PREFIX_COND)
1307 {
1309 mutt_message(_("Nothing to do"));
1310 }
1311 continue;
1312 }
1313
1314 /* get the real command */
1315 priv->tag = true;
1316 continue;
1317 }
1318 else if (c_auto_tag && shared->mailbox && (shared->mailbox->msg_tagged != 0))
1319 {
1320 priv->tag = true;
1321 }
1322
1324
1325#ifdef USE_NNTP
1326 OptNews = false; /* for any case */
1327#endif
1328
1329#ifdef USE_NOTMUCH
1330 nm_db_debug_check(shared->mailbox);
1331#endif
1332
1333 rc = index_function_dispatcher(priv->win_index, op);
1334
1335 if (rc == FR_UNKNOWN)
1336 rc = menu_function_dispatcher(priv->win_index, op);
1337
1338#ifdef USE_SIDEBAR
1339 if (rc == FR_UNKNOWN)
1340 {
1341 struct MuttWindow *win_sidebar = window_find_child(dlg, WT_SIDEBAR);
1342 rc = sb_function_dispatcher(win_sidebar, op);
1343 }
1344#endif
1345 if (rc == FR_UNKNOWN)
1346 rc = global_function_dispatcher(NULL, op);
1347
1348 if (rc == FR_UNKNOWN)
1350
1351#ifdef USE_NOTMUCH
1352 nm_db_debug_check(shared->mailbox);
1353#endif
1354 } while (rc != FR_DONE);
1355
1356 mview_free(&shared->mailboxview);
1357
1358 return shared->mailbox;
1359}
1360
1366void mutt_set_header_color(struct Mailbox *m, struct Email *e)
1367{
1368 if (!e)
1369 return;
1370
1371 struct RegexColor *color = NULL;
1372 struct PatternCache cache = { 0 };
1373
1374 struct AttrColor *ac_merge = NULL;
1376 {
1378 MUTT_MATCH_FULL_ADDRESS, m, e, &cache))
1379 {
1380 ac_merge = merged_color_overlay(ac_merge, &color->attr_color);
1381 }
1382 }
1383
1384 struct AttrColor *ac_normal = simple_color_get(MT_COLOR_NORMAL);
1385 if (ac_merge)
1386 ac_merge = merged_color_overlay(ac_normal, ac_merge);
1387 else
1388 ac_merge = ac_normal;
1389
1390 e->attr_color = ac_merge;
1391}
1392
1398{
1402
1403 struct IndexSharedData *shared = index_shared_data_new();
1404 notify_set_parent(shared->notify, dlg->notify);
1405
1406 dlg->wdata = shared;
1408
1409 const bool c_status_on_top = cs_subset_bool(NeoMutt->sub, "status_on_top");
1410
1411 struct MuttWindow *panel_index = ipanel_new(c_status_on_top, shared);
1412 struct MuttWindow *panel_pager = ppanel_new(c_status_on_top, shared);
1413
1414 mutt_window_add_child(dlg, panel_index);
1415 mutt_window_add_child(dlg, panel_pager);
1416
1417 dlg->focus = panel_index;
1418
1419 return dlg;
1420}
1421
1427void dlg_change_folder(struct MuttWindow *dlg, struct Mailbox *m)
1428{
1429 if (!dlg || !m)
1430 return;
1431
1432 struct IndexSharedData *shared = dlg->wdata;
1433 if (!shared)
1434 return;
1435
1436 struct MuttWindow *panel_index = window_find_child(dlg, WT_INDEX);
1437 if (!panel_index)
1438 return;
1439
1440 struct IndexPrivateData *priv = panel_index->wdata;
1441 if (!priv)
1442 return;
1443
1444 change_folder_mailbox(priv->menu, m, &priv->oldcount, shared, false);
1445}
bool mutt_buffer_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:260
Color and attribute parsing.
struct RegexColorList * regex_colors_get_list(enum ColorId cid)
Return the RegexColorList for a colour id.
Definition: regex.c:166
struct AttrColor * simple_color_get(enum ColorId cid)
Get the colour of an object by its ID.
Definition: simple.c:74
@ MT_COLOR_STATUS
Status bar (takes a pattern)
Definition: color.h:71
@ MT_COLOR_NORMAL
Plain text.
Definition: color.h:54
@ MT_COLOR_INDEX
Index: default colour (takes a pattern)
Definition: color.h:77
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
short cs_subset_sort(const struct ConfigSubset *sub, const char *name)
Get a sort config item by name.
Definition: helpers.c:292
Convenience wrapper for the config headers.
Connection Library.
Convenience wrapper for the core headers.
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:858
void mutt_paddstr(struct MuttWindow *win, int n, const char *s)
Display a string on screen, padded if necessary.
Definition: curs_lib.c:816
void mutt_refresh(void)
Force a refresh of the screen.
Definition: curs_lib.c:140
void mutt_flush_macro_to_endcond(void)
Drop a macro from the input buffer.
Definition: curs_lib.c:572
void mutt_beep(bool force)
Irritate the user.
Definition: curs_lib.c:130
size_t mutt_strwidth(const char *s)
Measure a string's width in screen cells.
Definition: curs_lib.c:907
@ FR_DONE
Exit the Dialog.
Definition: dispatcher.h:35
@ FR_UNKNOWN
Unknown function.
Definition: dispatcher.h:33
void mutt_update_index(struct Menu *menu, struct MailboxView *mv, enum MxStatus check, int oldcount, struct IndexSharedData *shared)
Update the index.
Definition: dlg_index.c:576
bool check_acl(struct Mailbox *m, AclFlags acl, const char *msg)
Check the ACLs for a function.
Definition: dlg_index.c:143
struct Mailbox * mutt_index_menu(struct MuttWindow *dlg, struct Mailbox *m_init)
Display a list of emails.
Definition: dlg_index.c:1052
const struct Mapping IndexNewsHelp[]
Help Bar for the News Index dialog.
Definition: dlg_index.c:121
void change_folder_mailbox(struct Menu *menu, struct Mailbox *m, int *oldcount, struct IndexSharedData *shared, bool read_only)
Change to a different Mailbox by pointer.
Definition: dlg_index.c:613
struct Mailbox * change_folder_notmuch(struct Menu *menu, char *buf, int buflen, int *oldcount, struct IndexSharedData *shared, bool read_only)
Change to a different Notmuch Mailbox by string.
Definition: dlg_index.c:736
void dlg_change_folder(struct MuttWindow *dlg, struct Mailbox *m)
Change the current folder, cautiously.
Definition: dlg_index.c:1427
int ci_next_undeleted(struct Mailbox *m, int msgno, bool uncollapse)
Find the next undeleted email.
Definition: dlg_index.c:242
int ci_previous_undeleted(struct Mailbox *m, int msgno, bool uncollapse)
Find the previous undeleted email.
Definition: dlg_index.c:275
void update_index(struct Menu *menu, struct MailboxView *mv, enum MxStatus check, int oldcount, const struct IndexSharedData *shared)
Update the index.
Definition: dlg_index.c:531
void change_folder_string(struct Menu *menu, char *buf, size_t buflen, int *oldcount, struct IndexSharedData *shared, bool read_only)
Change to a different Mailbox by string.
Definition: dlg_index.c:760
void mutt_set_header_color(struct Mailbox *m, struct Email *e)
Select a colour for a message.
Definition: dlg_index.c:1366
void mutt_draw_statusline(struct MuttWindow *win, int cols, const char *buf, size_t buflen)
Draw a highlighted status bar.
Definition: dlg_index.c:916
static const struct Mapping IndexHelp[]
Help Bar for the Index dialog.
Definition: dlg_index.c:105
static void update_index_threaded(struct MailboxView *mv, enum MxStatus check, int oldcount)
Update the index (if threaded)
Definition: dlg_index.c:406
static void uncollapse_thread(struct Mailbox *m, int index)
Open a collapsed thread.
Definition: dlg_index.c:224
void resort_index(struct MailboxView *mv, struct Menu *menu)
Resort the index.
Definition: dlg_index.c:364
int ci_first_message(struct Mailbox *m)
Get index of first new message.
Definition: dlg_index.c:308
static void update_index_unthreaded(struct MailboxView *mv, enum MxStatus check)
Update the index (if unthreaded)
Definition: dlg_index.c:487
void collapse_all(struct MailboxView *mv, struct Menu *menu, int toggle)
Collapse/uncollapse all threads.
Definition: dlg_index.c:170
struct MuttWindow * index_pager_init(void)
Allocate the Windows for the Index/Pager.
Definition: dlg_index.c:1397
Structs that make up an email.
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:1107
Flags to control mutt_expando_format()
#define MUTT_FORMAT_FORCESUBJ
Print the subject even if unchanged.
Definition: format_flags.h:31
#define MUTT_FORMAT_INDEX
This is a main index entry.
Definition: format_flags.h:36
#define MUTT_FORMAT_TREE
Draw the thread tree.
Definition: format_flags.h:32
#define MUTT_FORMAT_ARROWCURSOR
Reserve space for arrow_cursor.
Definition: format_flags.h:35
uint8_t MuttFormatFlags
Flags for mutt_expando_format(), e.g. MUTT_FORMAT_FORCESUBJ.
Definition: format_flags.h:29
int sb_function_dispatcher(struct MuttWindow *win, int op)
Perform a Sidebar function - Implements function_dispatcher_t -.
Definition: functions.c:375
int global_function_dispatcher(struct MuttWindow *win, int op)
Perform a Global function - Implements function_dispatcher_t -.
Definition: global.c:164
int menu_function_dispatcher(struct MuttWindow *win, int op)
Perform a Menu function - Implements function_dispatcher_t -.
Definition: functions.c:320
int index_function_dispatcher(struct MuttWindow *win, int op)
Perform an Index function - Implements function_dispatcher_t -.
Definition: functions.c:2831
#define mutt_error(...)
Definition: logging.h:87
#define mutt_message(...)
Definition: logging.h:86
#define mutt_debug(LEVEL,...)
Definition: logging.h:84
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:884
void index_make_entry(struct Menu *menu, char *buf, size_t buflen, int line)
Format a menu item for the index list - Implements Menu::make_entry() -.
Definition: dlg_index.c:797
static int index_mailbox_observer(struct NotifyCallback *nc)
Notification that a Mailbox has changed - Implements observer_t -.
Definition: dlg_index.c:587
void index_shared_data_free(struct MuttWindow *win, void **ptr)
Free Shared Index Data - Implements MuttWindow::wdata_free() -.
Definition: shared_data.c:273
Convenience wrapper for the gui headers.
void mutt_make_string(char *buf, size_t buflen, int cols, const char *s, struct Mailbox *m, int inpgr, struct Email *e, MuttFormatFlags flags, const char *progress)
Create formatted strings using mailbox expandos.
Definition: hdrline.c:1405
String processing routines to generate the mail index.
void mutt_timeout_hook(void)
Execute any timeout hooks.
Definition: hook.c:888
void mutt_folder_hook(const char *path, const char *desc)
Perform a folder hook.
Definition: hook.c:589
Parse and execute user-defined hooks.
void index_shared_data_set_email(struct IndexSharedData *shared, struct Email *e)
Set the current Email for the Index and friends.
Definition: shared_data.c:230
bool index_shared_data_is_cur_email(const struct IndexSharedData *shared, const struct Email *e)
Check whether an email is the currently selected Email.
Definition: shared_data.c:259
struct IndexSharedData * index_shared_data_new(void)
Create new Index Data.
Definition: shared_data.c:300
void index_shared_data_set_context(struct IndexSharedData *shared, struct MailboxView *mv)
Set the MailboxView for the Index and friends.
Definition: shared_data.c:157
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:181
struct MuttWindow * ipanel_new(bool status_on_top, struct IndexSharedData *shared)
Create the Windows for the Index panel.
Definition: ipanel.c:121
int km_dokey(enum MenuType mtype)
Determine what a keypress should do.
Definition: keymap.c:795
void km_error_key(enum MenuType mtype)
Handle an unbound key sequence.
Definition: keymap.c:1061
Manage keymappings.
@ LL_DEBUG5
Log at debug level 5.
Definition: logging.h:44
@ LL_DEBUG1
Log at debug level 1.
Definition: logging.h:40
void mailbox_gc_run(void)
Run the garbage-collection.
Definition: mailbox.c:296
void mailbox_free(struct Mailbox **ptr)
Free a Mailbox.
Definition: mailbox.c:87
struct Mailbox * mailbox_find_name(const char *name)
Find the mailbox with a given name.
Definition: mailbox.c:176
@ NT_MAILBOX_DELETE
Mailbox is about to be deleted.
Definition: mailbox.h:170
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox's path string.
Definition: mailbox.h:210
uint16_t AclFlags
ACL Rights - These show permission to...
Definition: mailbox.h:59
MailboxType
Supported mailbox formats.
Definition: mailbox.h:41
@ MUTT_MAILBOX_ERROR
Error occurred examining Mailbox.
Definition: mailbox.h:43
@ MUTT_NNTP
'NNTP' (Usenet) Mailbox type
Definition: mailbox.h:49
@ MUTT_UNKNOWN
Mailbox wasn't recognised.
Definition: mailbox.h:44
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:90
void mutt_mem_realloc(void *ptr, size_t size)
Resize a block of memory on the heap.
Definition: memory.c:114
#define FREE(x)
Definition: memory.h:43
#define MIN(a, b)
Definition: memory.h:31
#define MAX(a, b)
Definition: memory.h:30
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
void menu_queue_redraw(struct Menu *menu, MenuRedrawFlags redraw)
Queue a request for a redraw.
Definition: menu.c:178
int menu_get_index(struct Menu *menu)
Get the current selection in the Menu.
Definition: menu.c:154
MenuRedrawFlags menu_set_index(struct Menu *menu, int index)
Set the current selection in the Menu.
Definition: menu.c:168
struct AttrColor * merged_color_overlay(struct AttrColor *base, struct AttrColor *over)
Combine two colours.
Definition: merged.c:109
int mutt_monitor_add(struct Mailbox *m)
Add a watch for a mailbox.
Definition: monitor.c:481
int mutt_monitor_remove(struct Mailbox *m)
Remove a watch for a mailbox.
Definition: monitor.c:526
Monitor files for changes.
void msgwin_set_text(enum ColorId cid, const char *text)
Set the text for the Message Window.
Definition: msgwin.c:233
void msgwin_clear_text(void)
Clear the text in the Message Window.
Definition: msgwin.c:249
Convenience wrapper for the library headers.
#define N_(a)
Definition: message.h:32
#define _(a)
Definition: message.h:28
bool notify_observer_remove(struct Notify *notify, const observer_t callback, const void *global_data)
Remove an observer from an object.
Definition: notify.c:228
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:189
void notify_set_parent(struct Notify *notify, struct Notify *parent)
Set the parent notification handler.
Definition: notify.c:93
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:250
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:326
void mutt_curses_set_color(struct AttrColor *ac)
Set the colour and attributes for text.
Definition: mutt_curses.c:40
void mutt_resize_screen(void)
Update NeoMutt's opinion about the window size (CURSES)
Definition: resize.c:73
Hundreds of global variables to back the user variables.
char * LastFolder
Previously selected mailbox.
Definition: mutt_globals.h:55
char * CurrentFolder
Currently selected mailbox.
Definition: mutt_globals.h:54
SIG_ATOMIC_VOLATILE_T SigWinch
true after SIGWINCH is received
Definition: mutt_globals.h:70
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:74
NeoMutt Logging.
int mutt_mailbox_check(struct Mailbox *m_cur, CheckStatsFlags flags)
Check all all Mailboxes for new mail.
Definition: mutt_mailbox.c:156
bool mutt_mailbox_notify(struct Mailbox *m_cur)
Notify the user if there's new mail.
Definition: mutt_mailbox.c:230
Mailbox helper functions.
void mutt_thread_collapse(struct ThreadsContext *tctx, bool collapse)
Toggle collapse.
Definition: mutt_thread.c:1737
void mutt_draw_tree(struct ThreadsContext *tctx)
Draw a tree of threaded emails.
Definition: mutt_thread.c:384
enum UseThreads mutt_thread_style(void)
Which threading style is active?
Definition: mutt_thread.c:89
off_t mutt_set_vnum(struct Mailbox *m)
Set the virtual index number of all the messages in a mailbox.
Definition: mutt_thread.c:1363
bool mutt_thread_can_collapse(struct Email *e)
Check whether a thread can be collapsed.
Definition: mutt_thread.c:1765
int mutt_parent_message(struct Email *e, bool find_root)
Find the parent of a message.
Definition: mutt_thread.c:1313
Create/manipulate threading in emails.
UseThreads
Which threading style is active, $use_threads.
Definition: mutt_thread.h:83
@ UT_FLAT
Unthreaded.
Definition: mutt_thread.h:85
@ UT_THREADS
Normal threading (root above subthreads)
Definition: mutt_thread.h:86
@ UT_REVERSE
Reverse threading (subthreads above root)
Definition: mutt_thread.h:87
#define mutt_using_threads()
Definition: mutt_thread.h:100
#define mutt_uncollapse_thread(e)
Definition: mutt_thread.h:94
#define mutt_collapse_thread(e)
Definition: mutt_thread.h:93
void window_redraw(struct MuttWindow *win)
Reflow, recalc and repaint a tree of Windows.
Definition: mutt_window.c:604
void mutt_window_reflow(struct MuttWindow *win)
Resize a Window and its children.
Definition: mutt_window.c:340
void mutt_window_add_child(struct MuttWindow *parent, struct MuttWindow *child)
Add a child to Window.
Definition: mutt_window.c:439
struct MuttWindow * mutt_window_new(enum WindowType type, enum MuttWindowOrientation orient, enum MuttWindowSize size, int cols, int rows)
Create a new Window.
Definition: mutt_window.c:181
int mutt_window_move(struct MuttWindow *win, int col, int row)
Move the cursor in a Window.
Definition: mutt_window.c:293
struct MuttWindow * window_find_child(struct MuttWindow *win, enum WindowType type)
Recursively find a child Window of a given type.
Definition: mutt_window.c:522
int mutt_window_addnstr(struct MuttWindow *win, const char *str, int num)
Write a partial string to a Window.
Definition: mutt_window.c:394
void window_invalidate_all(void)
Mark all windows as in need of repaint.
Definition: mutt_window.c:742
@ WT_DLG_INDEX
Index Dialog, index_pager_init()
Definition: mutt_window.h:86
@ WT_INDEX
A panel containing the Index Window.
Definition: mutt_window.h:97
@ WT_SIDEBAR
Side panel containing Accounts or groups of data.
Definition: mutt_window.h:101
@ WT_MENU
An Window containing a Menu.
Definition: mutt_window.h:98
@ 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:414
void mview_free(struct MailboxView **ptr)
Free a MailboxView.
Definition: mview.c:49
struct MailboxView * mview_new(struct Mailbox *m)
Create a new MailboxView.
Definition: mview.c:77
bool mview_has_limit(const struct MailboxView *mv)
Is a limit active?
Definition: mview.c:435
The "currently-open" mailbox.
int mx_msg_padding_size(struct Mailbox *m)
Bytes of padding between messages - Wrapper for MxOps::msg_padding_size()
Definition: mx.c:1549
int mx_path_canon(char *buf, size_t buflen, const char *folder, enum MailboxType *type)
Canonicalise a mailbox path - Wrapper for MxOps::path_canon()
Definition: mx.c:1373
bool mx_mbox_open(struct Mailbox *m, OpenMailboxFlags flags)
Open a mailbox and parse it.
Definition: mx.c:304
enum MailboxType mx_path_probe(const char *path)
Find a mailbox that understands a path.
Definition: mx.c:1327
struct Mailbox * mx_path_resolve(const char *path)
Get a Mailbox for a path.
Definition: mx.c:1677
enum MxStatus mx_mbox_check(struct Mailbox *m)
Check for new mail - Wrapper for MxOps::mbox_check()
Definition: mx.c:1126
enum MxStatus mx_mbox_close(struct Mailbox *m)
Save changes and close mailbox.
Definition: mx.c:615
API for mailboxes.
#define MUTT_READONLY
Open in read-only mode.
Definition: mxapi.h:64
uint8_t OpenMailboxFlags
Flags for mutt_open_mailbox(), e.g. MUTT_NOSORT.
Definition: mxapi.h:60
#define MUTT_MAILBOX_CHECK_NO_FLAGS
No flags are set.
Definition: mxapi.h:74
#define MUTT_OPEN_NO_FLAGS
No flags are set.
Definition: mxapi.h:61
#define MUTT_MAILBOX_CHECK_FORCE
Ignore MailboxTime and check for new mail.
Definition: mxapi.h:75
MxStatus
Return values from mbox_check(), mbox_check_stats(), mbox_snc(), and mbox_close()
Definition: mxapi.h:84
@ MX_STATUS_ERROR
An error occurred.
Definition: mxapi.h:85
@ MX_STATUS_OK
No changes.
Definition: mxapi.h:86
@ MX_STATUS_FLAGS
Nondestructive flags change (IMAP)
Definition: mxapi.h:90
@ MX_STATUS_REOPENED
Mailbox was reopened.
Definition: mxapi.h:89
@ MX_STATUS_NEW_MAIL
New mail received in Mailbox.
Definition: mxapi.h:87
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:561
struct NntpAccountData * CurrentNewsSrv
Current NNTP news server.
Definition: nntp.c:77
Nntp-specific Mailbox 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:386
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:1555
const char * opcodes_get_name(int op)
Get the name of an opcode.
Definition: opcodes.c:46
All user-callable functions.
#define OP_TIMEOUT
Definition: opcodes.h:32
Handling of global boolean variables.
bool OptNews
(pseudo) used to change reader mode
Definition: options.h:50
bool OptAttachMsg
(pseudo) used by attach-message
Definition: options.h:37
bool OptSearchInvalid
(pseudo) used to invalidate the search pattern
Definition: options.h:57
bool OptNeedResort
(pseudo) used to force a re-sort
Definition: options.h:48
bool OptRedrawTree
(pseudo) redraw the thread tree
Definition: options.h:55
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:122
Private state data for the Pager.
Match patterns to emails.
#define MUTT_MATCH_FULL_ADDRESS
Match the full address.
Definition: lib.h:99
Prototypes for many functions.
int mutt_system(const char *cmd)
Run an external command.
Definition: system.c:51
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:352
#define SLIST_FIRST(head)
Definition: queue.h:229
Sidebar functions.
GUI display the mailboxes in a side panel.
GUI display the mailboxes in a side panel.
#define SORT_MASK
Mask for the sort id.
Definition: sort2.h:78
@ SORT_THREADS
Sort by email threads.
Definition: sort2.h:49
#define SORT_REVERSE
Reverse the order of the sort.
Definition: sort2.h:79
void mutt_sort_headers(struct Mailbox *m, struct ThreadsContext *threads, bool init, off_t *vsize)
Sort emails by their headers.
Definition: sort.c:356
Assorted sorting methods.
void menu_status_line(char *buf, size_t buflen, struct IndexSharedData *shared, struct Menu *menu, int cols, const char *fmt)
Create the status line.
Definition: status.c:445
GUI display a user-configurable status line.
Key value store.
#define NONULL(x)
Definition: string2.h:37
A curses colour and its attributes.
Definition: attr.h:35
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:80
struct ConnAccount account
Account details: username, password, etc.
Definition: connection.h:50
The envelope/body of an email.
Definition: email.h:37
bool read
Email is read.
Definition: email.h:48
bool display_subject
Used for threading.
Definition: email.h:101
bool visible
Is this message part of the view?
Definition: email.h:121
bool collapsed
Is this message part of a collapsed thread?
Definition: email.h:120
struct Body * body
List of MIME parts.
Definition: email.h:67
char * tree
Character string to print thread tree.
Definition: email.h:124
bool old
Email is seen, but unread.
Definition: email.h:47
struct AttrColor * attr_color
Color-pair to use when displaying in the index.
Definition: email.h:112
LOFF_T offset
Where in the stream does this message begin?
Definition: email.h:69
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:76
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:186
struct Mailbox * mailbox
The Mailbox this Event relates to.
Definition: mailbox.h:187
Private state data for the Index.
Definition: private_data.h:35
struct MuttWindow * win_index
Window for the Index.
Definition: private_data.h:44
int newcount
New count of Emails in the Mailbox.
Definition: private_data.h:38
struct IndexSharedData * shared
Shared Index data.
Definition: private_data.h:42
bool do_mailbox_notify
Do we need to notify the user of new mail?
Definition: private_data.h:39
bool attach_msg
Are we in "attach message" mode?
Definition: private_data.h:40
bool tag
tag-prefix has been pressed
Definition: private_data.h:36
struct Menu * menu
Menu controlling the index.
Definition: private_data.h:43
int oldcount
Old count of Emails in the Mailbox.
Definition: private_data.h:37
Data shared between Index, Pager and Sidebar.
Definition: shared_data.h:37
struct MailboxView * mailboxview
Current Mailbox view.
Definition: shared_data.h:39
struct Mailbox * mailbox
Current Mailbox.
Definition: shared_data.h:41
struct ConfigSubset * sub
Config set to use.
Definition: shared_data.h:38
struct Notify * notify
Notifications: NotifyIndex, IndexSharedData.
Definition: shared_data.h:44
The "current" mailbox.
Definition: mview.h:38
bool collapsed
Are all threads collapsed?
Definition: mview.h:47
struct Menu * menu
Needed for pattern compilation.
Definition: mview.h:45
off_t vsize
Size (in bytes) of the messages shown.
Definition: mview.h:39
struct PatternList * limit_pattern
Compiled limit pattern.
Definition: mview.h:41
struct ThreadsContext * threads
Threads context.
Definition: mview.h:42
int msg_in_pager
Message currently shown in the pager.
Definition: mview.h:43
struct Mailbox * mailbox
Current Mailbox.
Definition: mview.h:49
A mailbox.
Definition: mailbox.h:79
int vcount
The number of virtual messages.
Definition: mailbox.h:99
char * realpath
Used for duplicate detection, context comparison, and the sidebar.
Definition: mailbox.h:81
int * v2r
Mapping from virtual to real msgno.
Definition: mailbox.h:98
int msg_count
Total number of messages.
Definition: mailbox.h:88
AclFlags rights
ACL bits, see AclFlags.
Definition: mailbox.h:117
int email_max
Number of pointers in emails.
Definition: mailbox.h:97
enum MailboxType type
Mailbox type.
Definition: mailbox.h:102
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:144
struct Buffer pathbuf
Path of the Mailbox.
Definition: mailbox.h:80
void * compress_info
Compressed mbox module private data.
Definition: mailbox.h:120
int msg_tagged
How many messages are tagged?
Definition: mailbox.h:94
bool verbose
Display status messages?
Definition: mailbox.h:114
struct ConfigSubset * sub
Inherited config items.
Definition: mailbox.h:83
Mapping between user-readable string and a constant.
Definition: mapping.h:32
Definition: lib.h:69
struct MuttWindow * win
Window holding the Menu.
Definition: lib.h:76
void(* make_entry)(struct Menu *menu, char *buf, size_t buflen, int line)
Definition: lib.h:96
int current
Current entry.
Definition: lib.h:70
struct AttrColor *(* color)(struct Menu *menu, int line)
Definition: lib.h:133
int top
Entry that is the top of the current page.
Definition: lib.h:80
void * mdata
Private data.
Definition: lib.h:137
int max
Number of entries in the menu.
Definition: lib.h:71
int page_len
Number of entries per screen.
Definition: lib.h:74
An Email conversation.
Definition: thread.h:35
struct MuttThread * parent
Parent of this Thread.
Definition: thread.h:45
struct MuttThread * prev
Previous sibling Thread.
Definition: thread.h:48
struct Email * message
Email this Thread refers to.
Definition: thread.h:49
const struct Mapping * help_data
Data for the Help Bar.
Definition: mutt_window.h:142
struct WindowState state
Current state of the Window.
Definition: mutt_window.h:127
struct MuttWindow * focus
Focused Window.
Definition: mutt_window.h:140
void * wdata
Private data.
Definition: mutt_window.h:145
struct Notify * notify
Notifications: NotifyWindow, EventWindow.
Definition: mutt_window.h:138
void(* wdata_free)(struct MuttWindow *win, void **ptr)
Definition: mutt_window.h:160
int help_menu
Menu for key bindings, e.g. MENU_PAGER.
Definition: mutt_window.h:141
Container for Accounts, Notifications.
Definition: neomutt.h:37
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
struct Connection * conn
Connection to NNTP Server.
Definition: adata.h:63
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:110
A regular expression and a color to highlight a line.
Definition: regex4.h:37
regex_t regex
Compiled regex.
Definition: regex4.h:40
struct PatternList * color_pattern
Compiled pattern to speed up index color calculation.
Definition: regex4.h:42
struct AttrColor attr_color
Colour and attributes to apply.
Definition: regex4.h:38
int match
Substring to match, 0 for old behaviour.
Definition: regex4.h:41
short cols
Number of columns, can be MUTT_WIN_SIZE_UNLIMITED.
Definition: mutt_window.h:60
@ MENU_INDEX
Index panel (list of emails)
Definition: type.h:50