NeoMutt  2024-04-16-36-g75b6fb
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
dlg_index.c
Go to the documentation of this file.
1
60#include "config.h"
61#include <assert.h>
62#include <stdbool.h>
63#include <stdio.h>
64#include <string.h>
65#include "private.h"
66#include "mutt/lib.h"
67#include "config/lib.h"
68#include "email/lib.h"
69#include "core/lib.h"
70#include "conn/lib.h"
71#include "gui/lib.h"
72#include "lib.h"
73#include "color/lib.h"
74#include "expando/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 "functions.h"
82#include "globals.h"
83#include "hdrline.h"
84#include "hook.h"
85#include "mutt_logging.h"
86#include "mutt_mailbox.h"
87#include "mutt_thread.h"
88#include "mview.h"
89#include "mx.h"
90#include "nntp/adata.h"
91#include "private_data.h"
92#include "protos.h"
93#include "shared_data.h"
94#include "sort.h"
95#include "status.h"
96#ifdef USE_NOTMUCH
97#include "notmuch/lib.h"
98#endif
99#ifdef USE_INOTIFY
100#include "monitor.h"
101#endif
102
104static const struct Mapping IndexHelp[] = {
105 // clang-format off
106 { N_("Quit"), OP_QUIT },
107 { N_("Del"), OP_DELETE },
108 { N_("Undel"), OP_UNDELETE },
109 { N_("Save"), OP_SAVE },
110 { N_("Mail"), OP_MAIL },
111 { N_("Reply"), OP_REPLY },
112 { N_("Group"), OP_GROUP_REPLY },
113 { N_("Help"), OP_HELP },
114 { NULL, 0 },
115 // clang-format on
116};
117
119const struct Mapping IndexNewsHelp[] = {
120 // clang-format off
121 { N_("Quit"), OP_QUIT },
122 { N_("Del"), OP_DELETE },
123 { N_("Undel"), OP_UNDELETE },
124 { N_("Save"), OP_SAVE },
125 { N_("Post"), OP_POST },
126 { N_("Followup"), OP_FOLLOWUP },
127 { N_("Catchup"), OP_CATCHUP },
128 { N_("Help"), OP_HELP },
129 { NULL, 0 },
130 // clang-format on
131};
132
140bool check_acl(struct Mailbox *m, AclFlags acl, const char *msg)
141{
142 if (!m)
143 return false;
144
145 if (!(m->rights & acl))
146 {
147 /* L10N: %s is one of the CHECK_ACL entries below. */
148 mutt_error(_("%s: Operation not permitted by ACL"), msg);
149 return false;
150 }
151
152 return true;
153}
154
167void collapse_all(struct MailboxView *mv, struct Menu *menu, int toggle)
168{
169 if (!mv || !mv->mailbox || (mv->mailbox->msg_count == 0) || !menu)
170 return;
171
172 struct Email *e_cur = mutt_get_virt_email(mv->mailbox, menu_get_index(menu));
173 if (!e_cur)
174 return;
175
176 int final;
177
178 /* Figure out what the current message would be after folding / unfolding,
179 * so that we can restore the cursor in a sane way afterwards. */
180 if (e_cur->collapsed && toggle)
181 final = mutt_uncollapse_thread(e_cur);
182 else if (mutt_thread_can_collapse(e_cur))
183 final = mutt_collapse_thread(e_cur);
184 else
185 final = e_cur->vnum;
186
187 if (final == -1)
188 return;
189
190 struct Email *base = mutt_get_virt_email(mv->mailbox, final);
191 if (!base)
192 return;
193
194 /* Iterate all threads, perform collapse/uncollapse as needed */
195 mv->collapsed = toggle ? !mv->collapsed : true;
197
198 /* Restore the cursor */
200 menu->max = mv->mailbox->vcount;
201 for (int i = 0; i < mv->mailbox->vcount; i++)
202 {
203 struct Email *e = mutt_get_virt_email(mv->mailbox, i);
204 if (!e)
205 break;
206 if (e->index == base->index)
207 {
208 menu_set_index(menu, i);
209 break;
210 }
211 }
212
214}
215
221static void uncollapse_thread(struct MailboxView *mv, int index)
222{
223 if (!mv || !mv->mailbox)
224 return;
225
226 struct Mailbox *m = mv->mailbox;
227 struct Email *e = mutt_get_virt_email(m, index);
228 if (e && e->collapsed)
229 {
231 mutt_set_vnum(m);
232 }
233}
234
243int find_next_undeleted(struct MailboxView *mv, int msgno, bool uncollapse)
244{
245 if (!mv || !mv->mailbox)
246 return -1;
247
248 struct Mailbox *m = mv->mailbox;
249
250 int index = -1;
251 for (int i = msgno + 1; i < m->vcount; i++)
252 {
253 struct Email *e = mutt_get_virt_email(m, i);
254 if (!e)
255 continue;
256 if (!e->deleted)
257 {
258 index = i;
259 break;
260 }
261 }
262
263 if (uncollapse)
265
266 return index;
267}
268
277int find_previous_undeleted(struct MailboxView *mv, int msgno, bool uncollapse)
278{
279 if (!mv || !mv->mailbox)
280 return -1;
281
282 struct Mailbox *m = mv->mailbox;
283
284 int index = -1;
285 for (int i = msgno - 1; i >= 0; i--)
286 {
287 struct Email *e = mutt_get_virt_email(m, i);
288 if (!e)
289 continue;
290 if (!e->deleted)
291 {
292 index = i;
293 break;
294 }
295 }
296
297 if (uncollapse)
299
300 return index;
301}
302
312{
313 if (!mv)
314 return 0;
315
316 struct Mailbox *m = mv->mailbox;
317 if (!m || (m->msg_count == 0))
318 return 0;
319
320 int old = -1;
321 for (int i = 0; i < m->vcount; i++)
322 {
323 struct Email *e = mutt_get_virt_email(m, i);
324 if (!e)
325 continue;
326 if (!e->read && !e->deleted)
327 {
328 if (!e->old)
329 return i;
330 if (old == -1)
331 old = i;
332 }
333 }
334 if (old != -1)
335 return old;
336
337 /* If `$use_threads` is not threaded and `$sort` is reverse, the latest
338 * message is first. Otherwise, the latest message is first if exactly
339 * one of `$use_threads` and `$sort` are reverse.
340 */
341 enum SortType c_sort = cs_subset_sort(m->sub, "sort");
342 if ((c_sort & SORT_MASK) == SORT_THREADS)
343 c_sort = cs_subset_sort(m->sub, "sort_aux");
344 bool reverse = false;
345 switch (mutt_thread_style())
346 {
347 case UT_FLAT:
348 reverse = c_sort & SORT_REVERSE;
349 break;
350 case UT_THREADS:
351 reverse = c_sort & SORT_REVERSE;
352 break;
353 case UT_REVERSE:
354 reverse = !(c_sort & SORT_REVERSE);
355 break;
356 default:
357 assert(false);
358 }
359
360 if (reverse || (m->vcount == 0))
361 return 0;
362
363 return m->vcount - 1;
364}
365
371void resort_index(struct MailboxView *mv, struct Menu *menu)
372{
373 if (!mv || !mv->mailbox || !menu)
374 return;
375
376 struct Mailbox *m = mv->mailbox;
377 const int old_index = menu_get_index(menu);
378 struct Email *e_cur = mutt_get_virt_email(m, old_index);
379
380 int new_index = -1;
381 mutt_sort_headers(mv, false);
382
383 /* Restore the current message */
384 for (int i = 0; i < m->vcount; i++)
385 {
386 struct Email *e = mutt_get_virt_email(m, i);
387 if (!e)
388 continue;
389 if (e == e_cur)
390 {
391 new_index = i;
392 break;
393 }
394 }
395
396 if (mutt_using_threads() && (old_index < 0))
397 new_index = mutt_parent_message(e_cur, false);
398
399 if (old_index < 0)
400 new_index = find_first_message(mv);
401
402 menu->max = m->vcount;
403 menu_set_index(menu, new_index);
405}
406
413static void update_index_threaded(struct MailboxView *mv, enum MxStatus check, int oldcount)
414{
415 struct Email **save_new = NULL;
416 const bool lmt = mview_has_limit(mv);
417
418 struct Mailbox *m = mv->mailbox;
419 int num_new = MAX(0, m->msg_count - oldcount);
420
421 const bool c_uncollapse_new = cs_subset_bool(m->sub, "uncollapse_new");
422 /* save the list of new messages */
423 if ((check != MX_STATUS_REOPENED) && (oldcount > 0) &&
424 (lmt || c_uncollapse_new) && (num_new > 0))
425 {
426 save_new = mutt_mem_malloc(num_new * sizeof(struct Email *));
427 for (int i = oldcount; i < m->msg_count; i++)
428 save_new[i - oldcount] = m->emails[i];
429 }
430
431 /* Sort first to thread the new messages, because some patterns
432 * require the threading information.
433 *
434 * If the mailbox was reopened, need to rethread from scratch. */
436
437 if (lmt)
438 {
439 for (int i = 0; i < m->msg_count; i++)
440 {
441 struct Email *e = m->emails[i];
442
443 if ((e->limit_visited && e->visible) ||
445 MUTT_MATCH_FULL_ADDRESS, m, e, NULL))
446 {
447 /* vnum will get properly set by mutt_set_vnum(), which
448 * is called by mutt_sort_headers() just below. */
449 e->vnum = 1;
450 e->visible = true;
451 }
452 else
453 {
454 e->vnum = -1;
455 e->visible = false;
456 }
457
458 // mark email as visited so we don't re-apply the pattern next time
459 e->limit_visited = true;
460 }
461 /* Need a second sort to set virtual numbers and redraw the tree */
462 mutt_sort_headers(mv, false);
463 }
464
465 /* uncollapse threads with new mail */
466 if (c_uncollapse_new)
467 {
468 if (check == MX_STATUS_REOPENED)
469 {
470 mv->collapsed = false;
472 mutt_set_vnum(m);
473 }
474 else if (oldcount > 0)
475 {
476 for (int j = 0; j < num_new; j++)
477 {
478 if (save_new[j]->visible)
479 {
480 mutt_uncollapse_thread(save_new[j]);
481 }
482 }
483 mutt_set_vnum(m);
484 }
485 }
486
487 FREE(&save_new);
488}
489
495static void update_index_unthreaded(struct MailboxView *mv, enum MxStatus check)
496{
497 /* We are in a limited view. Check if the new message(s) satisfy
498 * the limit criteria. If they do, set their virtual msgno so that
499 * they will be visible in the limited view */
500 if (mview_has_limit(mv))
501 {
502 int padding = mx_msg_padding_size(mv->mailbox);
503 mv->mailbox->vcount = mv->vsize = 0;
504 for (int i = 0; i < mv->mailbox->msg_count; i++)
505 {
506 struct Email *e = mv->mailbox->emails[i];
507 if (!e)
508 break;
509
510 if ((e->limit_visited && e->visible) ||
512 MUTT_MATCH_FULL_ADDRESS, mv->mailbox, e, NULL))
513 {
514 assert(mv->mailbox->vcount < mv->mailbox->msg_count);
515 e->vnum = mv->mailbox->vcount;
516 mv->mailbox->v2r[mv->mailbox->vcount] = i;
517 e->visible = true;
518 mv->mailbox->vcount++;
519 struct Body *b = e->body;
520 mv->vsize += b->length + b->offset - b->hdr_offset + padding;
521 }
522 else
523 {
524 e->visible = false;
525 }
526
527 // mark email as visited so we don't re-apply the pattern next time
528 e->limit_visited = true;
529 }
530 }
531
532 /* if the mailbox was reopened, need to rethread from scratch */
534}
535
544void update_index(struct Menu *menu, struct MailboxView *mv, enum MxStatus check,
545 int oldcount, const struct IndexSharedData *shared)
546{
547 if (!menu || !mv)
548 return;
549
550 struct Mailbox *m = mv->mailbox;
551 if (mutt_using_threads())
552 update_index_threaded(mv, check, oldcount);
553 else
554 update_index_unthreaded(mv, check);
555
556 menu->max = m->vcount;
557 const int old_index = menu_get_index(menu);
558 int index = -1;
559 if (oldcount)
560 {
561 /* restore the current message to the message it was pointing to */
562 for (int i = 0; i < m->vcount; i++)
563 {
564 struct Email *e = mutt_get_virt_email(m, i);
565 if (!e)
566 continue;
567 if (index_shared_data_is_cur_email(shared, e))
568 {
569 index = i;
570 break;
571 }
572 }
573 }
574
575 if (index < 0)
576 {
577 index = (old_index < m->vcount) ? old_index : find_first_message(mv);
578 }
579 menu_set_index(menu, index);
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)
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 && (buf_is_empty(&shared->mailbox->pathbuf)))
621 {
622 mview_free(&shared->mailbox_view);
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 if (shared->mailbox->compress_info && (shared->mailbox->realpath[0] != '\0'))
633 new_last_folder = mutt_str_dup(shared->mailbox->realpath);
634 else
635 new_last_folder = mutt_str_dup(mailbox_path(shared->mailbox));
636 *oldcount = shared->mailbox->msg_count;
637
638 const enum MxStatus check = mx_mbox_close(shared->mailbox);
639 if (check == MX_STATUS_OK)
640 {
641 mview_free(&shared->mailbox_view);
642 if (shared->mailbox != m)
643 {
644 mailbox_free(&shared->mailbox);
645 }
646 }
647 else
648 {
649#ifdef USE_INOTIFY
650 if (monitor_remove_rc == 0)
651 mutt_monitor_add(NULL);
652#endif
653 if ((check == MX_STATUS_NEW_MAIL) || (check == MX_STATUS_REOPENED))
654 update_index(menu, shared->mailbox_view, check, *oldcount, shared);
655
656 FREE(&new_last_folder);
659 return;
660 }
662 LastFolder = new_last_folder;
663 }
665
666 /* If the `folder-hook` were to call `unmailboxes`, then the Mailbox (`m`)
667 * could be deleted, leaving `m` dangling. */
668 // TODO: Refactor this function to avoid the need for an observer
670 char *dup_path = mutt_str_dup(mailbox_path(m));
671 char *dup_name = mutt_str_dup(m->name);
672
673 mutt_folder_hook(dup_path, dup_name);
674 if (m)
675 {
676 /* `m` is still valid, but we won't need the observer again before the end
677 * of the function. */
679 }
680 else
681 {
682 // Recreate the Mailbox as the folder-hook might have invoked `mailboxes`
683 // and/or `unmailboxes`.
684 m = mx_path_resolve(dup_path);
685 }
686
687 FREE(&dup_path);
688 FREE(&dup_name);
689
690 if (!m)
691 return;
692
693 const OpenMailboxFlags flags = read_only ? MUTT_READONLY : MUTT_OPEN_NO_FLAGS;
694 if (mx_mbox_open(m, flags))
695 {
696 struct MailboxView *mv = mview_new(m, NeoMutt->notify);
697 index_shared_data_set_mview(shared, mv);
698
699 menu->max = m->msg_count;
701#ifdef USE_INOTIFY
702 mutt_monitor_add(NULL);
703#endif
704 }
705 else
706 {
707 index_shared_data_set_mview(shared, NULL);
709 }
710
711 const bool c_collapse_all = cs_subset_bool(shared->sub, "collapse_all");
712 if (mutt_using_threads() && c_collapse_all)
713 collapse_all(shared->mailbox_view, menu, 0);
714
716 /* force the mailbox check after we have changed the folder */
717 struct EventMailbox ev_m = { shared->mailbox };
721}
722
723#ifdef USE_NOTMUCH
734struct Mailbox *change_folder_notmuch(struct Menu *menu, char *buf, int buflen, int *oldcount,
735 struct IndexSharedData *shared, bool read_only)
736{
737 if (!nm_url_from_query(NULL, buf, buflen))
738 {
739 mutt_message(_("Failed to create query, aborting"));
740 return NULL;
741 }
742
743 struct Mailbox *m_query = mx_path_resolve(buf);
744 change_folder_mailbox(menu, m_query, oldcount, shared, read_only);
745 if (!shared->mailbox_view)
746 mailbox_free(&m_query);
747 return m_query;
748}
749#endif
750
759void change_folder_string(struct Menu *menu, struct Buffer *buf, int *oldcount,
760 struct IndexSharedData *shared, bool read_only)
761{
762 if (OptNews)
763 {
764 OptNews = false;
766 }
767 else
768 {
769 const char *const c_folder = cs_subset_string(shared->sub, "folder");
770 mx_path_canon(buf, c_folder, NULL);
771 }
772
774 if ((type == MUTT_MAILBOX_ERROR) || (type == MUTT_UNKNOWN))
775 {
776 // Look for a Mailbox by its description, before failing
777 struct Mailbox *m = mailbox_find_name(buf_string(buf));
778 if (m)
779 {
780 change_folder_mailbox(menu, m, oldcount, shared, read_only);
781 }
782 else
783 {
784 mutt_error(_("%s is not a mailbox"), buf_string(buf));
785 }
786 return;
787 }
788
789 struct Mailbox *m = mx_path_resolve(buf_string(buf));
790 change_folder_mailbox(menu, m, oldcount, shared, read_only);
791}
792
798int index_make_entry(struct Menu *menu, int line, int max_cols, struct Buffer *buf)
799{
800 if (!menu || !menu->mdata)
801 return 0;
802
803 struct IndexPrivateData *priv = menu->mdata;
804 struct IndexSharedData *shared = priv->shared;
805 struct Mailbox *m = shared->mailbox;
806 if (!shared->mailbox_view)
807 menu->current = -1;
808
809 if (!m || (line < 0) || (line >= m->email_max))
810 return 0;
811
812 struct Email *e = mutt_get_virt_email(m, line);
813 if (!e)
814 return 0;
815
817 struct MuttThread *tmp = NULL;
818
819 const enum UseThreads c_threads = mutt_thread_style();
820 if ((c_threads > UT_FLAT) && e->tree && e->thread)
821 {
822 flags |= MUTT_FORMAT_TREE; /* display the thread tree */
823 if (e->display_subject)
824 {
825 flags |= MUTT_FORMAT_FORCESUBJ;
826 }
827 else
828 {
829 const bool reverse = c_threads == UT_REVERSE;
830 int edgemsgno;
831 if (reverse)
832 {
833 if (menu->top + menu->page_len > menu->max)
834 edgemsgno = m->v2r[menu->max - 1];
835 else
836 edgemsgno = m->v2r[menu->top + menu->page_len - 1];
837 }
838 else
839 {
840 edgemsgno = m->v2r[menu->top];
841 }
842
843 for (tmp = e->thread->parent; tmp; tmp = tmp->parent)
844 {
845 if (!tmp->message)
846 continue;
847
848 /* if no ancestor is visible on current screen, provisionally force
849 * subject... */
850 if (reverse ? (tmp->message->msgno > edgemsgno) : (tmp->message->msgno < edgemsgno))
851 {
852 flags |= MUTT_FORMAT_FORCESUBJ;
853 break;
854 }
855 else if (tmp->message->vnum >= 0)
856 {
857 break;
858 }
859 }
860 if (flags & MUTT_FORMAT_FORCESUBJ)
861 {
862 for (tmp = e->thread->prev; tmp; tmp = tmp->prev)
863 {
864 if (!tmp->message)
865 continue;
866
867 /* ...but if a previous sibling is available, don't force it */
868 if (reverse ? (tmp->message->msgno > edgemsgno) : (tmp->message->msgno < edgemsgno))
869 {
870 break;
871 }
872 else if (tmp->message->vnum >= 0)
873 {
874 flags &= ~MUTT_FORMAT_FORCESUBJ;
875 break;
876 }
877 }
878 }
879 }
880 }
881
882 const struct Expando *c_index_format = cs_subset_expando(shared->sub, "index_format");
883 int msg_in_pager = shared->mailbox_view ? shared->mailbox_view->msg_in_pager : 0;
884
885 const bool c_arrow_cursor = cs_subset_bool(menu->sub, "arrow_cursor");
886 if (c_arrow_cursor)
887 {
888 const char *const c_arrow_string = cs_subset_string(menu->sub, "arrow_string");
889 max_cols -= (mutt_strwidth(c_arrow_string) + 1);
890 }
891
892 return mutt_make_string(buf, max_cols, c_index_format, m, msg_in_pager, e, flags, NULL);
893}
894
898const struct AttrColor *index_color(struct Menu *menu, int line)
899{
900 struct IndexPrivateData *priv = menu->mdata;
901 struct IndexSharedData *shared = priv->shared;
902 struct Mailbox *m = shared->mailbox;
903 if (!m || (line < 0))
904 return NULL;
905
906 struct Email *e = mutt_get_virt_email(m, line);
907 if (!e)
908 return NULL;
909
910 if (e->attr_color)
911 return e->attr_color;
912
914 return e->attr_color;
915}
916
930void mutt_draw_statusline(struct MuttWindow *win, int max_cols, const char *buf, size_t buflen)
931{
932 if (!buf || !stdscr)
933 return;
934
935 size_t i = 0;
936 size_t offset = 0;
937 bool found = false;
938 size_t chunks = 0;
939 size_t len = 0;
940
944 struct StatusSyntax
945 {
946 const struct AttrColor *attr_color;
947 int first;
948 int last;
949 } *syntax = NULL;
950
953 do
954 {
955 struct RegexColor *cl = NULL;
956 found = false;
957
958 if (!buf[offset])
959 break;
960
961 /* loop through each "color status regex" */
963 {
964 regmatch_t pmatch[cl->match + 1];
965 memset(pmatch, 0, (cl->match + 1) * sizeof(regmatch_t));
966
967 if (regexec(&cl->regex, buf + offset, cl->match + 1, pmatch, 0) != 0)
968 continue; /* regex doesn't match the status bar */
969
970 int first = pmatch[cl->match].rm_so + offset;
971 int last = pmatch[cl->match].rm_eo + offset;
972
973 if (first == last)
974 continue; /* ignore an empty regex */
975
976 if (!found)
977 {
978 chunks++;
979 mutt_mem_realloc(&syntax, chunks * sizeof(struct StatusSyntax));
980 }
981
982 i = chunks - 1;
983 if (!found || (first < syntax[i].first) ||
984 ((first == syntax[i].first) && (last > syntax[i].last)))
985 {
986 const struct AttrColor *ac_merge = merged_color_overlay(ac_base, &cl->attr_color);
987
988 syntax[i].attr_color = ac_merge;
989 syntax[i].first = first;
990 syntax[i].last = last;
991 }
992 found = true;
993 }
994
995 if (syntax)
996 {
997 offset = syntax[i].last;
998 }
999 } while (found);
1000
1001 /* Only 'len' bytes will fit into 'max_cols' screen columns */
1002 len = mutt_wstr_trunc(buf, buflen, max_cols, NULL);
1003
1004 offset = 0;
1005
1006 if ((chunks > 0) && (syntax[0].first > 0))
1007 {
1008 /* Text before the first highlight */
1009 mutt_window_addnstr(win, buf, MIN(len, syntax[0].first));
1010 mutt_curses_set_color(ac_base);
1011 if (len <= syntax[0].first)
1012 goto dsl_finish; /* no more room */
1013
1014 offset = syntax[0].first;
1015 }
1016
1017 for (i = 0; i < chunks; i++)
1018 {
1019 /* Highlighted text */
1020 mutt_curses_set_color(syntax[i].attr_color);
1021 mutt_window_addnstr(win, buf + offset, MIN(len, syntax[i].last) - offset);
1022 if (len <= syntax[i].last)
1023 goto dsl_finish; /* no more room */
1024
1025 size_t next;
1026 if ((i + 1) == chunks)
1027 {
1028 next = len;
1029 }
1030 else
1031 {
1032 next = MIN(len, syntax[i + 1].first);
1033 }
1034
1035 mutt_curses_set_color(ac_base);
1036 offset = syntax[i].last;
1037 mutt_window_addnstr(win, buf + offset, next - offset);
1038
1039 offset = next;
1040 if (offset >= len)
1041 goto dsl_finish; /* no more room */
1042 }
1043
1044 mutt_curses_set_color(ac_base);
1045 if (offset < len)
1046 {
1047 /* Text after the last highlight */
1048 mutt_window_addnstr(win, buf + offset, len - offset);
1049 }
1050
1051 int width = mutt_strwidth(buf);
1052 if (width < max_cols)
1053 {
1054 /* Pad the rest of the line with whitespace */
1055 mutt_paddstr(win, max_cols - width, "");
1056 }
1057dsl_finish:
1058 FREE(&syntax);
1059}
1060
1071struct Mailbox *dlg_index(struct MuttWindow *dlg, struct Mailbox *m_init)
1072{
1073 /* Make sure use_threads/sort/sort_aux are coherent */
1075
1076 struct IndexSharedData *shared = dlg->wdata;
1078
1079 struct MuttWindow *panel_index = window_find_child(dlg, WT_INDEX);
1080
1081 struct IndexPrivateData *priv = panel_index->wdata;
1082 priv->win_index = window_find_child(panel_index, WT_MENU);
1083
1084 int op = OP_NULL;
1085
1086 if (shared->mailbox && (shared->mailbox->type == MUTT_NNTP))
1087 dlg->help_data = IndexNewsHelp;
1088 else
1089 dlg->help_data = IndexHelp;
1090 dlg->help_menu = MENU_INDEX;
1091
1092 priv->menu = priv->win_index->wdata;
1094 priv->menu->color = index_color;
1095 priv->menu->max = shared->mailbox ? shared->mailbox->vcount : 0;
1097
1098 struct MuttWindow *old_focus = window_set_focus(priv->menu->win);
1099 mutt_window_reflow(NULL);
1100
1101 if (!shared->attach_msg)
1102 {
1103 /* force the mailbox check after we enter the folder */
1105 }
1106#ifdef USE_INOTIFY
1107 mutt_monitor_add(NULL);
1108#endif
1109
1110 const bool c_collapse_all = cs_subset_bool(shared->sub, "collapse_all");
1111 if (mutt_using_threads() && c_collapse_all)
1112 {
1113 collapse_all(shared->mailbox_view, priv->menu, 0);
1115 }
1116
1117 int rc = 0;
1118 do
1119 {
1120 /* Clear the tag prefix unless we just started it.
1121 * Don't clear the prefix on a timeout, but do clear on an abort */
1122 if (priv->tag_prefix && (op != OP_TAG_PREFIX) &&
1123 (op != OP_TAG_PREFIX_COND) && (op != OP_TIMEOUT))
1124 {
1125 priv->tag_prefix = false;
1126 }
1127
1128 /* check if we need to resort the index because just about
1129 * any 'op' below could do mutt_enter_command(), either here or
1130 * from any new priv->menu launched, and change $sort/$sort_aux */
1131 if (OptNeedResort && shared->mailbox && (shared->mailbox->msg_count != 0) &&
1132 (menu_get_index(priv->menu) >= 0))
1133 {
1134 resort_index(shared->mailbox_view, priv->menu);
1135 }
1136
1137 priv->menu->max = shared->mailbox ? shared->mailbox->vcount : 0;
1138 priv->oldcount = shared->mailbox ? shared->mailbox->msg_count : 0;
1139
1140 if (shared->mailbox && shared->mailbox_view)
1141 {
1143
1144 shared->mailbox_view->menu = priv->menu;
1145 /* check for new mail in the mailbox. If nonzero, then something has
1146 * changed about the file (either we got new mail or the file was
1147 * modified underneath us.) */
1148 enum MxStatus check = mx_mbox_check(shared->mailbox);
1149
1150 if (check == MX_STATUS_ERROR)
1151 {
1152 if (buf_is_empty(&shared->mailbox->pathbuf))
1153 {
1154 /* fatal error occurred */
1155 mview_free(&shared->mailbox_view);
1157 }
1158
1160 }
1161 else if ((check == MX_STATUS_NEW_MAIL) || (check == MX_STATUS_REOPENED) ||
1162 (check == MX_STATUS_FLAGS))
1163 {
1164 /* notify the user of new mail */
1165 if (check == MX_STATUS_REOPENED)
1166 {
1167 mutt_error(_("Mailbox was externally modified. Flags may be wrong."));
1168 }
1169 else if (check == MX_STATUS_NEW_MAIL)
1170 {
1171 for (size_t i = 0; i < shared->mailbox->msg_count; i++)
1172 {
1173 const struct Email *e = shared->mailbox->emails[i];
1174 if (e && !e->read && !e->old)
1175 {
1176 mutt_message(_("New mail in this mailbox"));
1177 const bool c_beep_new = cs_subset_bool(shared->sub, "beep_new");
1178 if (c_beep_new)
1179 mutt_beep(true);
1180 const struct Expando *c_new_mail_command =
1181 cs_subset_expando(shared->sub, "new_mail_command");
1182 if (c_new_mail_command)
1183 {
1184 struct Buffer *cmd = buf_pool_get();
1185 menu_status_line(cmd, shared, NULL, -1, c_new_mail_command);
1186 if (mutt_system(buf_string(cmd)) != 0)
1187 mutt_error(_("Error running \"%s\""), buf_string(cmd));
1188 buf_pool_release(&cmd);
1189 }
1190 break;
1191 }
1192 }
1193 }
1194 else if (check == MX_STATUS_FLAGS)
1195 {
1196 mutt_message(_("Mailbox was externally modified"));
1197 }
1198
1199 /* avoid the message being overwritten by mailbox */
1200 priv->do_mailbox_notify = false;
1201
1202 bool verbose = shared->mailbox->verbose;
1203 shared->mailbox->verbose = false;
1204 update_index(priv->menu, shared->mailbox_view, check, priv->oldcount, shared);
1205 shared->mailbox->verbose = verbose;
1206 priv->menu->max = shared->mailbox->vcount;
1209 }
1210
1212 menu_get_index(priv->menu)));
1213 }
1214
1215 if (!shared->attach_msg)
1216 {
1217 /* check for new mail in the incoming folders */
1219 if (priv->do_mailbox_notify)
1220 {
1221 if (mutt_mailbox_notify(shared->mailbox))
1222 {
1223 const bool c_beep_new = cs_subset_bool(shared->sub, "beep_new");
1224 if (c_beep_new)
1225 mutt_beep(true);
1226 const struct Expando *c_new_mail_command = cs_subset_expando(shared->sub, "new_mail_command");
1227 if (c_new_mail_command)
1228 {
1229 struct Buffer *cmd = buf_pool_get();
1230 menu_status_line(cmd, shared, priv->menu, -1, c_new_mail_command);
1231 if (mutt_system(buf_string(cmd)) != 0)
1232 mutt_error(_("Error running \"%s\""), buf_string(cmd));
1233 buf_pool_release(&cmd);
1234 }
1235 }
1236 }
1237 else
1238 {
1239 priv->do_mailbox_notify = true;
1240 }
1241 }
1242
1243 window_redraw(NULL);
1244
1245 /* give visual indication that the next command is a tag- command */
1246 if (priv->tag_prefix)
1247 {
1248 msgwin_set_text(NULL, "tag-", MT_COLOR_NORMAL);
1249 }
1250
1251 const bool c_arrow_cursor = cs_subset_bool(shared->sub, "arrow_cursor");
1252 const bool c_braille_friendly = cs_subset_bool(shared->sub, "braille_friendly");
1253 const int index = menu_get_index(priv->menu);
1254 if (c_arrow_cursor)
1255 {
1256 const char *const c_arrow_string = cs_subset_string(shared->sub, "arrow_string");
1257 const int arrow_width = mutt_strwidth(c_arrow_string);
1258 mutt_window_move(priv->menu->win, arrow_width, index - priv->menu->top);
1259 }
1260 else if (c_braille_friendly)
1261 {
1262 mutt_window_move(priv->menu->win, 0, index - priv->menu->top);
1263 }
1264 else
1265 {
1266 mutt_window_move(priv->menu->win, priv->menu->win->state.cols - 1,
1267 index - priv->menu->top);
1268 }
1269 mutt_refresh();
1270
1271 window_redraw(NULL);
1273
1274 if (op == OP_REPAINT)
1275 {
1276 /* force a real complete redraw. clrtobot() doesn't seem to be able
1277 * to handle every case without this. */
1278 msgwin_clear_text(NULL);
1279 mutt_refresh();
1280 continue;
1281 }
1282
1283 /* either user abort or timeout */
1284 if (op < OP_NULL)
1285 {
1286 if (priv->tag_prefix)
1287 msgwin_clear_text(NULL);
1288 continue;
1289 }
1290
1291 mutt_debug(LL_DEBUG1, "Got op %s (%d)\n", opcodes_get_name(op), op);
1292
1293 /* special handling for the priv->tag-prefix function */
1294 const bool c_auto_tag = cs_subset_bool(shared->sub, "auto_tag");
1295 if ((op == OP_TAG_PREFIX) || (op == OP_TAG_PREFIX_COND))
1296 {
1297 /* A second priv->tag-prefix command aborts */
1298 if (priv->tag_prefix)
1299 {
1300 priv->tag_prefix = false;
1301 msgwin_clear_text(NULL);
1302 continue;
1303 }
1304
1305 if (!shared->mailbox)
1306 {
1307 mutt_error(_("No mailbox is open"));
1308 continue;
1309 }
1310
1311 if (shared->mailbox->msg_tagged == 0)
1312 {
1313 if (op == OP_TAG_PREFIX)
1314 {
1315 mutt_error(_("No tagged messages"));
1316 }
1317 else if (op == OP_TAG_PREFIX_COND)
1318 {
1320 mutt_message(_("Nothing to do"));
1321 }
1322 continue;
1323 }
1324
1325 /* get the real command */
1326 priv->tag_prefix = true;
1327 continue;
1328 }
1329 else if (c_auto_tag && shared->mailbox && (shared->mailbox->msg_tagged != 0))
1330 {
1331 priv->tag_prefix = true;
1332 }
1333
1335
1336 OptNews = false; /* for any case */
1337
1338#ifdef USE_NOTMUCH
1339 nm_db_debug_check(shared->mailbox);
1340#endif
1341
1342 rc = index_function_dispatcher(priv->win_index, op);
1343
1344 if (rc == FR_UNKNOWN)
1345 rc = menu_function_dispatcher(priv->win_index, op);
1346
1347 if (rc == FR_UNKNOWN)
1348 {
1349 struct MuttWindow *win_sidebar = window_find_child(dlg, WT_SIDEBAR);
1350 rc = sb_function_dispatcher(win_sidebar, op);
1351 }
1352 if (rc == FR_UNKNOWN)
1353 rc = global_function_dispatcher(NULL, op);
1354
1355 if (rc == FR_UNKNOWN)
1357
1358#ifdef USE_NOTMUCH
1359 nm_db_debug_check(shared->mailbox);
1360#endif
1361 } while (rc != FR_DONE);
1362
1363 mview_free(&shared->mailbox_view);
1364 window_set_focus(old_focus);
1365
1366 return shared->mailbox;
1367}
1368
1374void mutt_set_header_color(struct Mailbox *m, struct Email *e)
1375{
1376 if (!e)
1377 return;
1378
1379 struct RegexColor *color = NULL;
1380 struct PatternCache cache = { 0 };
1381
1382 const struct AttrColor *ac_merge = NULL;
1384 {
1386 MUTT_MATCH_FULL_ADDRESS, m, e, &cache))
1387 {
1388 ac_merge = merged_color_overlay(ac_merge, &color->attr_color);
1389 }
1390 }
1391
1392 struct AttrColor *ac_normal = simple_color_get(MT_COLOR_NORMAL);
1393 if (ac_merge)
1394 ac_merge = merged_color_overlay(ac_normal, ac_merge);
1395 else
1396 ac_merge = ac_normal;
1397
1398 e->attr_color = ac_merge;
1399}
1400
1406{
1410
1411 struct IndexSharedData *shared = index_shared_data_new();
1412 notify_set_parent(shared->notify, dlg->notify);
1413
1414 dlg->wdata = shared;
1416
1417 const bool c_status_on_top = cs_subset_bool(NeoMutt->sub, "status_on_top");
1418
1419 struct MuttWindow *panel_index = ipanel_new(c_status_on_top, shared);
1420 struct MuttWindow *panel_pager = ppanel_new(c_status_on_top, shared);
1421
1422 mutt_window_add_child(dlg, panel_index);
1423 mutt_window_add_child(dlg, panel_pager);
1424
1425 return dlg;
1426}
1427
1433void index_change_folder(struct MuttWindow *dlg, struct Mailbox *m)
1434{
1435 if (!dlg || !m)
1436 return;
1437
1438 struct IndexSharedData *shared = dlg->wdata;
1439 if (!shared)
1440 return;
1441
1442 struct MuttWindow *panel_index = window_find_child(dlg, WT_INDEX);
1443 if (!panel_index)
1444 return;
1445
1446 struct IndexPrivateData *priv = panel_index->wdata;
1447 if (!priv)
1448 return;
1449
1450 change_folder_mailbox(priv->menu, m, &priv->oldcount, shared, false);
1451}
bool buf_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:290
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:184
struct AttrColor * simple_color_get(enum ColorId cid)
Get the colour of an object by its ID.
Definition: simple.c:88
@ MT_COLOR_STATUS
Status bar (takes a pattern)
Definition: color.h:75
@ MT_COLOR_NORMAL
Plain text.
Definition: color.h:59
@ MT_COLOR_INDEX
Index: default colour.
Definition: color.h:83
void mutt_pattern_free(struct PatternList **pat)
Free a Pattern.
Definition: compile.c:777
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:292
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:48
short cs_subset_sort(const struct ConfigSubset *sub, const char *name)
Get a sort config item by name.
Definition: helpers.c:267
const struct Expando * cs_subset_expando(const struct ConfigSubset *sub, const char *name)
Get an Expando config item by name.
Definition: config_type.c:358
Convenience wrapper for the config headers.
Connection Library.
Convenience wrapper for the core headers.
void mailbox_gc_run(void)
Run the garbage-collection.
Definition: mailbox.c:313
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:188
@ NT_MAILBOX_DELETE
Mailbox is about to be deleted.
Definition: mailbox.h:183
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox's path string.
Definition: mailbox.h:223
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
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:383
void mutt_paddstr(struct MuttWindow *win, int n, const char *s)
Display a string on screen, padded if necessary.
Definition: curs_lib.c:341
void mutt_refresh(void)
Force a refresh of the screen.
Definition: curs_lib.c:78
void mutt_beep(bool force)
Irritate the user.
Definition: curs_lib.c:68
size_t mutt_strwidth(const char *s)
Measure a string's width in screen cells.
Definition: curs_lib.c:443
@ FR_DONE
Exit the Dialog.
Definition: dispatcher.h:35
@ FR_UNKNOWN
Unknown function.
Definition: dispatcher.h:33
bool check_acl(struct Mailbox *m, AclFlags acl, const char *msg)
Check the ACLs for a function.
Definition: dlg_index.c:140
const struct Mapping IndexNewsHelp[]
Help Bar for the News Index dialog.
Definition: dlg_index.c:119
void change_folder_mailbox(struct Menu *menu, struct Mailbox *m, int *oldcount, struct IndexSharedData *shared, bool read_only)
Change to a different Mailbox by pointer.
Definition: dlg_index.c:613
struct Mailbox * change_folder_notmuch(struct Menu *menu, char *buf, int buflen, int *oldcount, struct IndexSharedData *shared, bool read_only)
Change to a different Notmuch Mailbox by string.
Definition: dlg_index.c:734
void mutt_draw_statusline(struct MuttWindow *win, int max_cols, const char *buf, size_t buflen)
Draw a highlighted status bar.
Definition: dlg_index.c:930
void update_index(struct Menu *menu, struct MailboxView *mv, enum MxStatus check, int oldcount, const struct IndexSharedData *shared)
Update the index.
Definition: dlg_index.c:544
void mutt_set_header_color(struct Mailbox *m, struct Email *e)
Select a colour for a message.
Definition: dlg_index.c:1374
void index_change_folder(struct MuttWindow *dlg, struct Mailbox *m)
Change the current folder, cautiously.
Definition: dlg_index.c:1433
int find_first_message(struct MailboxView *mv)
Get index of first new message.
Definition: dlg_index.c:311
static const struct Mapping IndexHelp[]
Help Bar for the Index dialog.
Definition: dlg_index.c:104
static void update_index_threaded(struct MailboxView *mv, enum MxStatus check, int oldcount)
Update the index (if threaded)
Definition: dlg_index.c:413
void resort_index(struct MailboxView *mv, struct Menu *menu)
Resort the index.
Definition: dlg_index.c:371
int find_next_undeleted(struct MailboxView *mv, int msgno, bool uncollapse)
Find the next undeleted email.
Definition: dlg_index.c:243
static void update_index_unthreaded(struct MailboxView *mv, enum MxStatus check)
Update the index (if unthreaded)
Definition: dlg_index.c:495
void collapse_all(struct MailboxView *mv, struct Menu *menu, int toggle)
Collapse/uncollapse all threads.
Definition: dlg_index.c:167
void change_folder_string(struct Menu *menu, struct Buffer *buf, int *oldcount, struct IndexSharedData *shared, bool read_only)
Change to a different Mailbox by string.
Definition: dlg_index.c:759
int find_previous_undeleted(struct MailboxView *mv, int msgno, bool uncollapse)
Find the previous undeleted email.
Definition: dlg_index.c:277
struct MuttWindow * index_pager_init(void)
Allocate the Windows for the Index/Pager.
Definition: dlg_index.c:1405
static void uncollapse_thread(struct MailboxView *mv, int index)
Open a collapsed thread.
Definition: dlg_index.c:221
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:1133
Parse Expando string.
int km_dokey(enum MenuType mtype, GetChFlags flags)
Determine what a keypress should do.
Definition: get.c:463
void mutt_flush_macro_to_endcond(void)
Drop a macro from the input buffer.
Definition: get.c:165
void km_error_key(enum MenuType mtype)
Handle an unbound key sequence.
Definition: get.c:293
bool OptNews
(pseudo) used to change reader mode
Definition: globals.c:70
char * LastFolder
Previously selected mailbox.
Definition: globals.c:44
char * CurrentFolder
Currently selected mailbox.
Definition: globals.c:43
bool OptNeedResort
(pseudo) used to force a re-sort
Definition: globals.c:69
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:172
int menu_function_dispatcher(struct MuttWindow *win, int op)
Perform a Menu function - Implements function_dispatcher_t -.
Definition: functions.c:318
int index_function_dispatcher(struct MuttWindow *win, int op)
Perform an Index function - Implements function_dispatcher_t -.
Definition: functions.c:3262
struct Mailbox * dlg_index(struct MuttWindow *dlg, struct Mailbox *m_init)
Display a list of emails -.
Definition: dlg_index.c:1071
#define mutt_error(...)
Definition: logging2.h:92
#define mutt_message(...)
Definition: logging2.h:91
#define mutt_debug(LEVEL,...)
Definition: logging2.h:89
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:898
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:798
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:278
Convenience wrapper for the gui headers.
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: hdrline.c:1797
String processing routines to generate the mail index.
void mutt_folder_hook(const char *path, const char *desc)
Perform a folder hook.
Definition: hook.c:623
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:235
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:264
struct IndexSharedData * index_shared_data_new(void)
Create new Index Data.
Definition: shared_data.c:307
void index_shared_data_set_mview(struct IndexSharedData *shared, struct MailboxView *mv)
Set the MailboxView for the Index and friends.
Definition: shared_data.c:160
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:184
struct MuttWindow * ipanel_new(bool status_on_top, struct IndexSharedData *shared)
Create the Windows for the Index panel.
Definition: ipanel.c:121
Manage keymappings.
#define GETCH_NO_FLAGS
No flags are set.
Definition: lib.h:51
@ LL_DEBUG5
Log at debug level 5.
Definition: logging2.h:47
@ LL_DEBUG1
Log at debug level 1.
Definition: logging2.h:43
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:45
#define MIN(a, b)
Definition: memory.h:32
#define MAX(a, b)
Definition: memory.h:31
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:184
int menu_get_index(struct Menu *menu)
Get the current selection in the Menu.
Definition: menu.c:160
MenuRedrawFlags menu_set_index(struct Menu *menu, int index)
Set the current selection in the Menu.
Definition: menu.c:174
const struct AttrColor * merged_color_overlay(const struct AttrColor *base, const struct AttrColor *over)
Combine two colours.
Definition: merged.c:107
int mutt_monitor_add(struct Mailbox *m)
Add a watch for a mailbox.
Definition: monitor.c:483
int mutt_monitor_remove(struct Mailbox *m)
Remove a watch for a mailbox.
Definition: monitor.c:527
Monitor files for changes.
void msgwin_clear_text(struct MuttWindow *win)
Clear the text in the Message Window.
Definition: msgwin.c:519
void msgwin_set_text(struct MuttWindow *win, const char *text, enum ColorId color)
Set the text for the Message Window.
Definition: msgwin.c:484
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:253
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:274
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)
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:168
bool mutt_mailbox_notify(struct Mailbox *m_cur)
Notify the user if there's new mail.
Definition: mutt_mailbox.c:234
Mailbox helper functions.
void mutt_thread_collapse(struct ThreadsContext *tctx, bool collapse)
Toggle collapse.
Definition: mutt_thread.c:1790
enum UseThreads mutt_thread_style(void)
Which threading style is active?
Definition: mutt_thread.c:83
off_t mutt_set_vnum(struct Mailbox *m)
Set the virtual index number of all the messages in a mailbox.
Definition: mutt_thread.c:1405
bool mutt_thread_can_collapse(struct Email *e)
Check whether a thread can be collapsed.
Definition: mutt_thread.c:1818
int mutt_parent_message(struct Email *e, bool find_root)
Find the parent of a message.
Definition: mutt_thread.c:1355
Create/manipulate threading in emails.
UseThreads
Which threading style is active, $use_threads.
Definition: mutt_thread.h:97
@ UT_FLAT
Unthreaded.
Definition: mutt_thread.h:99
@ UT_THREADS
Normal threading (root above subthreads)
Definition: mutt_thread.h:100
@ UT_REVERSE
Reverse threading (subthreads above root)
Definition: mutt_thread.h:101
#define mutt_using_threads()
Definition: mutt_thread.h:114
#define mutt_uncollapse_thread(e)
Definition: mutt_thread.h:108
#define mutt_collapse_thread(e)
Definition: mutt_thread.h:107
void window_redraw(struct MuttWindow *win)
Reflow, recalc and repaint a tree of Windows.
Definition: mutt_window.c:634
void mutt_window_reflow(struct MuttWindow *win)
Resize a Window and its children.
Definition: mutt_window.c:344
void mutt_window_add_child(struct MuttWindow *parent, struct MuttWindow *child)
Add a child to Window.
Definition: mutt_window.c:446
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:182
int mutt_window_move(struct MuttWindow *win, int col, int row)
Move the cursor in a Window.
Definition: mutt_window.c:297
struct MuttWindow * window_set_focus(struct MuttWindow *win)
Set the Window focus.
Definition: mutt_window.c:684
struct MuttWindow * window_find_child(struct MuttWindow *win, enum WindowType type)
Recursively find a child Window of a given type.
Definition: mutt_window.c:533
int mutt_window_addnstr(struct MuttWindow *win, const char *str, int num)
Write a partial string to a Window.
Definition: mutt_window.c:401
@ WT_DLG_INDEX
Index Dialog, dlg_index()
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:418
void mview_free(struct MailboxView **ptr)
Free a MailboxView.
Definition: mview.c:50
bool mview_has_limit(const struct MailboxView *mv)
Is a limit active?
Definition: mview.c:439
struct MailboxView * mview_new(struct Mailbox *m, struct Notify *parent)
Create a new MailboxView.
Definition: mview.c:91
View of a Mailbox.
int mx_msg_padding_size(struct Mailbox *m)
Bytes of padding between messages - Wrapper for MxOps::msg_padding_size()
Definition: mx.c:1503
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:1365
bool mx_mbox_open(struct Mailbox *m, OpenMailboxFlags flags)
Open a mailbox and parse it.
Definition: mx.c:286
enum MailboxType mx_path_probe(const char *path)
Find a mailbox that understands a path.
Definition: mx.c:1319
struct Mailbox * mx_path_resolve(const char *path)
Get a Mailbox for a path.
Definition: mx.c:1634
enum MxStatus mx_mbox_check(struct Mailbox *m)
Check for new mail - Wrapper for MxOps::mbox_check()
Definition: mx.c:1103
enum MxStatus mx_mbox_close(struct Mailbox *m)
Save changes and close mailbox.
Definition: mx.c:596
API for mailboxes.
#define MUTT_READONLY
Open in read-only mode.
Definition: mxapi.h:43
uint8_t OpenMailboxFlags
Flags for mutt_open_mailbox(), e.g. MUTT_NOSORT.
Definition: mxapi.h:39
#define MUTT_MAILBOX_CHECK_NO_FLAGS
No flags are set.
Definition: mxapi.h:53
#define MUTT_OPEN_NO_FLAGS
No flags are set.
Definition: mxapi.h:40
#define MUTT_MAILBOX_CHECK_FORCE
Ignore MailboxTime and check for new mail.
Definition: mxapi.h:54
MxStatus
Return values from mbox_check(), mbox_check_stats(), mbox_sync(), and mbox_close()
Definition: mxapi.h:63
@ MX_STATUS_ERROR
An error occurred.
Definition: mxapi.h:64
@ MX_STATUS_OK
No changes.
Definition: mxapi.h:65
@ MX_STATUS_FLAGS
Nondestructive flags change (IMAP)
Definition: mxapi.h:69
@ MX_STATUS_REOPENED
Mailbox was reopened.
Definition: mxapi.h:68
@ MX_STATUS_NEW_MAIL
New mail received in Mailbox.
Definition: mxapi.h:66
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:559
struct NntpAccountData * CurrentNewsSrv
Current NNTP news server.
Definition: nntp.c:77
@ 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:396
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:1579
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:36
#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:121
Private state data for the Pager.
Match patterns to emails.
#define MUTT_MATCH_FULL_ADDRESS
Match the full address.
Definition: lib.h:106
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:81
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition: pool.c:94
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
#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
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:70
SortType
Methods for sorting.
Definition: sort2.h:34
@ SORT_THREADS
Sort by email threads.
Definition: sort2.h:41
#define SORT_REVERSE
Reverse the order of the sort.
Definition: sort2.h:71
void mutt_sort_headers(struct MailboxView *mv, bool init)
Sort emails by their headers.
Definition: sort.c:350
Assorted sorting methods.
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:495
GUI display a user-configurable status line.
Key value store.
A curses colour and its attributes.
Definition: attr.h:66
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
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
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:104
bool visible
Is this message part of the view?
Definition: email.h:124
bool limit_visited
Has the limit pattern been applied to this message?
Definition: email.h:125
bool collapsed
Is this message part of a collapsed thread?
Definition: email.h:123
struct Body * body
List of MIME parts.
Definition: email.h:69
char * tree
Character string to print thread tree.
Definition: email.h:128
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:115
int vnum
Virtual message number.
Definition: email.h:117
int msgno
Number displayed to the user.
Definition: email.h:114
bool deleted
Email is deleted.
Definition: email.h:78
int index
The absolute (unsorted) message number.
Definition: email.h:113
struct MuttThread * thread
Thread of Emails.
Definition: email.h:122
An Event that happened to a Mailbox.
Definition: mailbox.h:199
struct Mailbox * mailbox
The Mailbox this Event relates to.
Definition: mailbox.h:200
Parsed Expando trees.
Definition: expando.h:41
Private state data for the Index.
Definition: private_data.h:35
struct MuttWindow * win_index
Window for the Index.
Definition: private_data.h:42
struct IndexSharedData * shared
Shared Index data.
Definition: private_data.h:40
bool tag_prefix
tag-prefix has been pressed
Definition: private_data.h:36
bool do_mailbox_notify
Do we need to notify the user of new mail?
Definition: private_data.h:38
struct Menu * menu
Menu controlling the index.
Definition: private_data.h:41
int oldcount
Old count of mails in the mailbox.
Definition: private_data.h:37
Data shared between Index, Pager and Sidebar.
Definition: shared_data.h:37
struct 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
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: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:119
int email_max
Size of emails array.
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:145
struct Buffer pathbuf
Path of the Mailbox.
Definition: mailbox.h:80
void * compress_info
Compressed mbox module private data.
Definition: mailbox.h:121
int msg_tagged
How many messages are tagged?
Definition: mailbox.h:94
bool verbose
Display status messages?
Definition: mailbox.h:117
struct ConfigSubset * sub
Inherited config items.
Definition: mailbox.h:83
Mapping between user-readable string and a constant.
Definition: mapping.h:33
Definition: lib.h:79
struct MuttWindow * win
Window holding the Menu.
Definition: lib.h:86
int current
Current entry.
Definition: lib.h:80
const struct AttrColor *(* color)(struct Menu *menu, int line)
Definition: lib.h:143
int top
Entry that is the top of the current page.
Definition: lib.h:90
int(* make_entry)(struct Menu *menu, int line, int max_cols, struct Buffer *buf)
Definition: lib.h:106
struct ConfigSubset * sub
Inherited config items.
Definition: lib.h:87
void * mdata
Private data.
Definition: lib.h:147
int max
Number of entries in the menu.
Definition: lib.h:81
int page_len
Number of entries per screen.
Definition: lib.h:84
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.
Definition: mutt_window.h:142
struct WindowState state
Current state of the Window.
Definition: mutt_window.h:127
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:159
int help_menu
Menu for key bindings, e.g. MENU_PAGER.
Definition: mutt_window.h:141
Container for Accounts, Notifications.
Definition: neomutt.h:41
struct Notify * notify
Notifications handler.
Definition: neomutt.h:42
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:45
struct Connection * conn
Connection to NNTP Server.
Definition: adata.h:62
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:117
A regular expression and a color to highlight a line.
Definition: regex4.h:36
regex_t regex
Compiled regex.
Definition: regex4.h:39
struct PatternList * color_pattern
Compiled pattern to speed up index color calculation.
Definition: regex4.h:41
struct AttrColor attr_color
Colour and attributes to apply.
Definition: regex4.h:37
int match
Substring to match, 0 for old behaviour.
Definition: regex4.h:40
struct PatternList * pattern
compiled search pattern
Definition: search_state.h:37
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:51