NeoMutt  2021-02-05-666-ge300cd
Teaching an old dog new tricks
DOXYGEN
dlg_index.c
Go to the documentation of this file.
1 
57 #include "config.h"
58 #include <assert.h>
59 #include <stdbool.h>
60 #include <stdio.h>
61 #include "private.h"
62 #include "config/lib.h"
63 #include "email/lib.h"
64 #include "core/lib.h"
65 #include "conn/lib.h"
66 #include "gui/lib.h"
67 #include "lib.h"
68 #include "menu/lib.h"
69 #include "pager/lib.h"
70 #include "pattern/lib.h"
71 #include "progress/lib.h"
72 #include "context.h"
73 #include "format_flags.h"
74 #include "functions.h"
75 #include "hdrline.h"
76 #include "hook.h"
77 #include "keymap.h"
78 #include "mutt_globals.h"
79 #include "mutt_logging.h"
80 #include "mutt_mailbox.h"
81 #include "mutt_thread.h"
82 #include "mx.h"
83 #include "opcodes.h"
84 #include "options.h"
85 #include "private_data.h"
86 #include "protos.h"
87 #include "shared_data.h"
88 #include "sort.h"
89 #include "status.h"
90 #ifdef USE_NOTMUCH
91 #include "notmuch/lib.h"
92 #endif
93 #ifdef USE_NNTP
94 #include "nntp/lib.h"
95 #include "nntp/adata.h" // IWYU pragma: keep
96 #include "nntp/mdata.h" // IWYU pragma: keep
97 #endif
98 #ifdef ENABLE_NLS
99 #include <libintl.h>
100 #endif
101 #ifdef USE_INOTIFY
102 #include "monitor.h"
103 #endif
104 
106 static const struct Mapping IndexHelp[] = {
107  // clang-format off
108  { N_("Quit"), OP_QUIT },
109  { N_("Del"), OP_DELETE },
110  { N_("Undel"), OP_UNDELETE },
111  { N_("Save"), OP_SAVE },
112  { N_("Mail"), OP_MAIL },
113  { N_("Reply"), OP_REPLY },
114  { N_("Group"), OP_GROUP_REPLY },
115  { N_("Help"), OP_HELP },
116  { NULL, 0 },
117  // clang-format on
118 };
119 
120 #ifdef USE_NNTP
121 const struct Mapping IndexNewsHelp[] = {
123  // clang-format off
124  { N_("Quit"), OP_QUIT },
125  { N_("Del"), OP_DELETE },
126  { N_("Undel"), OP_UNDELETE },
127  { N_("Save"), OP_SAVE },
128  { N_("Post"), OP_POST },
129  { N_("Followup"), OP_FOLLOWUP },
130  { N_("Catchup"), OP_CATCHUP },
131  { N_("Help"), OP_HELP },
132  { NULL, 0 },
133  // clang-format on
134 };
135 #endif
136 
144 bool check_acl(struct Mailbox *m, AclFlags acl, const char *msg)
145 {
146  if (!m)
147  return false;
148 
149  if (!(m->rights & acl))
150  {
151  /* L10N: %s is one of the CHECK_ACL entries below. */
152  mutt_error(_("%s: Operation not permitted by ACL"), msg);
153  return false;
154  }
155 
156  return true;
157 }
158 
171 void collapse_all(struct Context *ctx, struct Menu *menu, int toggle)
172 {
173  if (!ctx || !ctx->mailbox || (ctx->mailbox->msg_count == 0) || !menu)
174  return;
175 
176  struct Email *e_cur = mutt_get_virt_email(ctx->mailbox, menu_get_index(menu));
177  if (!e_cur)
178  return;
179 
180  int final;
181 
182  /* Figure out what the current message would be after folding / unfolding,
183  * so that we can restore the cursor in a sane way afterwards. */
184  if (e_cur->collapsed && toggle)
185  final = mutt_uncollapse_thread(e_cur);
186  else if (mutt_thread_can_collapse(e_cur))
187  final = mutt_collapse_thread(e_cur);
188  else
189  final = e_cur->vnum;
190 
191  if (final == -1)
192  return;
193 
194  struct Email *base = mutt_get_virt_email(ctx->mailbox, final);
195  if (!base)
196  return;
197 
198  /* Iterate all threads, perform collapse/uncollapse as needed */
199  ctx->collapsed = toggle ? !ctx->collapsed : true;
201 
202  /* Restore the cursor */
203  mutt_set_vnum(ctx->mailbox);
204  menu->max = ctx->mailbox->vcount;
205  for (int i = 0; i < ctx->mailbox->vcount; i++)
206  {
207  struct Email *e = mutt_get_virt_email(ctx->mailbox, i);
208  if (!e)
209  break;
210  if (e->index == base->index)
211  {
212  menu_set_index(menu, i);
213  break;
214  }
215  }
216 
218 }
219 
227 int ci_next_undeleted(struct Mailbox *m, int msgno)
228 {
229  if (!m)
230  return -1;
231 
232  for (int i = msgno + 1; i < m->vcount; i++)
233  {
234  struct Email *e = mutt_get_virt_email(m, i);
235  if (!e)
236  continue;
237  if (!e->deleted)
238  return i;
239  }
240  return -1;
241 }
242 
251 {
252  if (!m)
253  return -1;
254 
255  for (int i = msgno - 1; i >= 0; i--)
256  {
257  struct Email *e = mutt_get_virt_email(m, i);
258  if (!e)
259  continue;
260  if (!e->deleted)
261  return i;
262  }
263  return -1;
264 }
265 
274 int ci_first_message(struct Mailbox *m)
275 {
276  if (!m || (m->msg_count == 0))
277  return 0;
278 
279  int old = -1;
280  for (int i = 0; i < m->vcount; i++)
281  {
282  struct Email *e = mutt_get_virt_email(m, i);
283  if (!e)
284  continue;
285  if (!e->read && !e->deleted)
286  {
287  if (!e->old)
288  return i;
289  if (old == -1)
290  old = i;
291  }
292  }
293  if (old != -1)
294  return old;
295 
296  /* If `$use_threads` is not threaded and `$sort` is reverse, the latest
297  * message is first. Otherwise, the latest message is first if exactly
298  * one of `$use_threads` and `$sort` are reverse.
299  */
300  short c_sort = cs_subset_sort(m->sub, "sort");
301  if ((c_sort & SORT_MASK) == SORT_THREADS)
302  c_sort = cs_subset_sort(m->sub, "sort_aux");
303  bool reverse = false;
304  switch (mutt_thread_style())
305  {
306  case UT_FLAT:
307  reverse = c_sort & SORT_REVERSE;
308  break;
309  case UT_THREADS:
310  reverse = c_sort & SORT_REVERSE;
311  break;
312  case UT_REVERSE:
313  reverse = !(c_sort & SORT_REVERSE);
314  break;
315  default:
316  assert(false);
317  }
318 
319  if (reverse || (m->vcount == 0))
320  return 0;
321 
322  return m->vcount - 1;
323 }
324 
330 void resort_index(struct Context *ctx, struct Menu *menu)
331 {
332  if (!ctx || !ctx->mailbox || !menu)
333  return;
334 
335  struct Mailbox *m = ctx->mailbox;
336  const int old_index = menu_get_index(menu);
337  struct Email *e_cur = mutt_get_virt_email(m, old_index);
338 
339  int new_index = -1;
340  mutt_sort_headers(m, ctx->threads, false, &ctx->vsize);
341  /* Restore the current message */
342 
343  for (int i = 0; i < m->vcount; i++)
344  {
345  struct Email *e = mutt_get_virt_email(m, i);
346  if (!e)
347  continue;
348  if (e == e_cur)
349  {
350  new_index = i;
351  break;
352  }
353  }
354 
355  if (mutt_using_threads() && (old_index < 0))
356  new_index = mutt_parent_message(e_cur, false);
357 
358  if (old_index < 0)
359  new_index = ci_first_message(m);
360 
361  menu_set_index(menu, new_index);
363 }
364 
371 static void update_index_threaded(struct Context *ctx, enum MxStatus check, int oldcount)
372 {
373  struct Email **save_new = NULL;
374  const bool lmt = ctx_has_limit(ctx);
375 
376  struct Mailbox *m = ctx->mailbox;
377  int num_new = MAX(0, m->msg_count - oldcount);
378 
379  const bool c_uncollapse_new = cs_subset_bool(m->sub, "uncollapse_new");
380  /* save the list of new messages */
381  if ((check != MX_STATUS_REOPENED) && (oldcount > 0) &&
382  (lmt || c_uncollapse_new) && (num_new > 0))
383  {
384  save_new = mutt_mem_malloc(num_new * sizeof(struct Email *));
385  for (int i = oldcount; i < m->msg_count; i++)
386  save_new[i - oldcount] = m->emails[i];
387  }
388 
389  /* Sort first to thread the new messages, because some patterns
390  * require the threading information.
391  *
392  * If the mailbox was reopened, need to rethread from scratch. */
393  mutt_sort_headers(m, ctx->threads, (check == MX_STATUS_REOPENED), &ctx->vsize);
394 
395  if (lmt)
396  {
397  /* Because threading changes the order in m->emails, we don't
398  * know which emails are new. Hence, we need to re-apply the limit to the
399  * whole set.
400  */
401  for (int i = 0; i < m->msg_count; i++)
402  {
403  struct Email *e = m->emails[i];
404  if ((e->vnum != -1) || mutt_pattern_exec(SLIST_FIRST(ctx->limit_pattern),
405  MUTT_MATCH_FULL_ADDRESS, m, e, NULL))
406  {
407  /* vnum will get properly set by mutt_set_vnum(), which
408  * is called by mutt_sort_headers() just below. */
409  e->vnum = 1;
410  e->visible = true;
411  }
412  else
413  {
414  e->vnum = -1;
415  e->visible = false;
416  }
417  }
418  /* Need a second sort to set virtual numbers and redraw the tree */
419  mutt_sort_headers(m, ctx->threads, false, &ctx->vsize);
420  }
421 
422  /* uncollapse threads with new mail */
423  if (c_uncollapse_new)
424  {
425  if (check == MX_STATUS_REOPENED)
426  {
427  ctx->collapsed = false;
429  mutt_set_vnum(m);
430  }
431  else if (oldcount > 0)
432  {
433  for (int j = 0; j < num_new; j++)
434  {
435  if (save_new[j]->visible)
436  {
437  mutt_uncollapse_thread(save_new[j]);
438  }
439  }
440  mutt_set_vnum(m);
441  }
442  }
443 
444  FREE(&save_new);
445 }
446 
452 static void update_index_unthreaded(struct Context *ctx, enum MxStatus check)
453 {
454  /* We are in a limited view. Check if the new message(s) satisfy
455  * the limit criteria. If they do, set their virtual msgno so that
456  * they will be visible in the limited view */
457  if (ctx_has_limit(ctx))
458  {
459  int padding = mx_msg_padding_size(ctx->mailbox);
460  ctx->mailbox->vcount = ctx->vsize = 0;
461  for (int i = 0; i < ctx->mailbox->msg_count; i++)
462  {
463  struct Email *e = ctx->mailbox->emails[i];
464  if (!e)
465  break;
467  MUTT_MATCH_FULL_ADDRESS, ctx->mailbox, e, NULL))
468  {
469  assert(ctx->mailbox->vcount < ctx->mailbox->msg_count);
470  e->vnum = ctx->mailbox->vcount;
471  ctx->mailbox->v2r[ctx->mailbox->vcount] = i;
472  e->visible = true;
473  ctx->mailbox->vcount++;
474  struct Body *b = e->body;
475  ctx->vsize += b->length + b->offset - b->hdr_offset + padding;
476  }
477  else
478  {
479  e->visible = false;
480  }
481  }
482  }
483 
484  /* if the mailbox was reopened, need to rethread from scratch */
485  mutt_sort_headers(ctx->mailbox, ctx->threads, (check == MX_STATUS_REOPENED), &ctx->vsize);
486 }
487 
496 void update_index(struct Menu *menu, struct Context *ctx, enum MxStatus check,
497  int oldcount, const struct IndexSharedData *shared)
498 {
499  if (!menu || !ctx)
500  return;
501 
502  struct Mailbox *m = ctx->mailbox;
503  if (mutt_using_threads())
504  update_index_threaded(ctx, check, oldcount);
505  else
506  update_index_unthreaded(ctx, check);
507 
508  const int old_index = menu_get_index(menu);
509  int index = -1;
510  if (oldcount)
511  {
512  /* restore the current message to the message it was pointing to */
513  for (int i = 0; i < m->vcount; i++)
514  {
515  struct Email *e = mutt_get_virt_email(m, i);
516  if (!e)
517  continue;
518  if (index_shared_data_is_cur_email(shared, e))
519  {
520  index = i;
521  break;
522  }
523  }
524  }
525 
526  if (index < 0)
527  {
528  index = (old_index < m->vcount) ? old_index : ci_first_message(m);
529  }
530  menu_set_index(menu, index);
531 }
532 
541 void mutt_update_index(struct Menu *menu, struct Context *ctx, enum MxStatus check,
542  int oldcount, struct IndexSharedData *shared)
543 {
544  update_index(menu, ctx, check, oldcount, shared);
545 }
546 
553 {
554  if ((nc->event_type != NT_MAILBOX) || !nc->global_data)
555  return -1;
556 
557  if (nc->event_subtype != NT_MAILBOX_DELETE)
558  return 0;
559 
560  struct Mailbox **ptr = nc->global_data;
561  if (!ptr || !*ptr)
562  return 0;
563 
564  *ptr = NULL;
565  mutt_debug(LL_DEBUG5, "mailbox done\n");
566  return 0;
567 }
568 
577 void change_folder_mailbox(struct Menu *menu, struct Mailbox *m, int *oldcount,
578  struct IndexSharedData *shared, bool read_only)
579 {
580  if (!m)
581  return;
582 
583  /* keepalive failure in mutt_enter_fname may kill connection. */
584  if (shared->mailbox && (mutt_buffer_is_empty(&shared->mailbox->pathbuf)))
585  {
586  ctx_free(&shared->ctx);
587  }
588 
589  if (shared->mailbox)
590  {
591  char *new_last_folder = NULL;
592 #ifdef USE_INOTIFY
593  int monitor_remove_rc = mutt_monitor_remove(NULL);
594 #endif
595 #ifdef USE_COMP_MBOX
596  if (shared->mailbox->compress_info && (shared->mailbox->realpath[0] != '\0'))
597  new_last_folder = mutt_str_dup(shared->mailbox->realpath);
598  else
599 #endif
600  new_last_folder = mutt_str_dup(mailbox_path(shared->mailbox));
601  *oldcount = shared->mailbox->msg_count;
602 
603  const enum MxStatus check = mx_mbox_close(shared->mailbox);
604  if (check == MX_STATUS_OK)
605  {
606  ctx_free(&shared->ctx);
607  }
608  else
609  {
610 #ifdef USE_INOTIFY
611  if (monitor_remove_rc == 0)
612  mutt_monitor_add(NULL);
613 #endif
614  if ((check == MX_STATUS_NEW_MAIL) || (check == MX_STATUS_REOPENED))
615  update_index(menu, shared->ctx, check, *oldcount, shared);
616 
617  FREE(&new_last_folder);
618  OptSearchInvalid = true;
620  return;
621  }
622  FREE(&LastFolder);
623  LastFolder = new_last_folder;
624  }
626 
627  /* If the `folder-hook` were to call `unmailboxes`, then the Mailbox (`m`)
628  * could be deleted, leaving `m` dangling. */
629  // TODO: Refactor this function to avoid the need for an observer
631  char *dup_path = mutt_str_dup(mailbox_path(m));
632  char *dup_name = mutt_str_dup(m->name);
633 
634  mutt_folder_hook(dup_path, dup_name);
635  if (m)
636  {
637  /* `m` is still valid, but we won't need the observer again before the end
638  * of the function. */
640  }
641 
642  // Recreate the Mailbox as the folder-hook might have invoked `mailboxes`
643  // and/or `unmailboxes`.
644  m = mx_path_resolve(dup_path);
645  FREE(&dup_path);
646  FREE(&dup_name);
647 
648  if (!m)
649  return;
650 
652  if (mx_mbox_open(m, flags))
653  {
654  struct Context *ctx = ctx_new(m);
655  index_shared_data_set_context(shared, ctx);
656 
657  menu->max = m->msg_count;
658  menu_set_index(menu, ci_first_message(shared->mailbox));
659 #ifdef USE_INOTIFY
660  mutt_monitor_add(NULL);
661 #endif
662  }
663  else
664  {
665  index_shared_data_set_context(shared, NULL);
666  menu_set_index(menu, 0);
667  }
668 
669  const bool c_collapse_all = cs_subset_bool(shared->sub, "collapse_all");
670  if (mutt_using_threads() && c_collapse_all)
671  collapse_all(shared->ctx, menu, 0);
672 
673  struct MuttWindow *dlg = dialog_find(menu->win);
674  struct EventMailbox ev_m = { shared->mailbox };
675  mutt_debug(LL_NOTIFY, "NT_MAILBOX_SWITCH: %p\n", shared->mailbox);
677 
679  /* force the mailbox check after we have changed the folder */
682  OptSearchInvalid = true;
683 }
684 
685 #ifdef USE_NOTMUCH
686 
695 struct Mailbox *change_folder_notmuch(struct Menu *menu, char *buf, int buflen, int *oldcount,
696  struct IndexSharedData *shared, bool read_only)
697 {
698  if (!nm_url_from_query(NULL, buf, buflen))
699  {
700  mutt_message(_("Failed to create query, aborting"));
701  return NULL;
702  }
703 
704  struct Mailbox *m_query = mx_path_resolve(buf);
705  change_folder_mailbox(menu, m_query, oldcount, shared, read_only);
706  return m_query;
707 }
708 #endif
709 
720 void change_folder_string(struct Menu *menu, char *buf, size_t buflen, int *oldcount,
721  struct IndexSharedData *shared, bool *pager_return, bool read_only)
722 {
723 #ifdef USE_NNTP
724  if (OptNews)
725  {
726  OptNews = false;
727  nntp_expand_path(buf, buflen, &CurrentNewsSrv->conn->account);
728  }
729  else
730 #endif
731  {
732  const char *const c_folder = cs_subset_string(shared->sub, "folder");
733  mx_path_canon(buf, buflen, c_folder, NULL);
734  }
735 
736  enum MailboxType type = mx_path_probe(buf);
737  if ((type == MUTT_MAILBOX_ERROR) || (type == MUTT_UNKNOWN))
738  {
739  // Look for a Mailbox by its description, before failing
740  struct Mailbox *m = mailbox_find_name(buf);
741  if (m)
742  {
743  change_folder_mailbox(menu, m, oldcount, shared, read_only);
744  *pager_return = false;
745  }
746  else
747  mutt_error(_("%s is not a mailbox"), buf);
748  return;
749  }
750 
751  /* past this point, we don't return to the pager on error */
752  *pager_return = false;
753 
754  struct Mailbox *m = mx_path_resolve(buf);
755  change_folder_mailbox(menu, m, oldcount, shared, read_only);
756 }
757 
761 void index_make_entry(struct Menu *menu, char *buf, size_t buflen, int line)
762 {
763  buf[0] = '\0';
764 
765  struct IndexPrivateData *priv = menu->mdata;
766  struct IndexSharedData *shared = priv->shared;
767  struct Mailbox *m = shared->mailbox;
768 
769  if (!m || !menu || (line < 0) || (line >= m->email_max))
770  return;
771 
772  struct Email *e = mutt_get_virt_email(m, line);
773  if (!e)
774  return;
775 
777  struct MuttThread *tmp = NULL;
778 
779  const enum UseThreads c_threads = mutt_thread_style();
780  if ((c_threads > UT_FLAT) && e->tree)
781  {
782  flags |= MUTT_FORMAT_TREE; /* display the thread tree */
783  if (e->display_subject)
784  flags |= MUTT_FORMAT_FORCESUBJ;
785  else
786  {
787  const bool reverse = c_threads == UT_REVERSE;
788  int edgemsgno;
789  if (reverse)
790  {
791  if (menu->top + menu->pagelen > menu->max)
792  edgemsgno = m->v2r[menu->max - 1];
793  else
794  edgemsgno = m->v2r[menu->top + menu->pagelen - 1];
795  }
796  else
797  edgemsgno = m->v2r[menu->top];
798 
799  for (tmp = e->thread->parent; tmp; tmp = tmp->parent)
800  {
801  if (!tmp->message)
802  continue;
803 
804  /* if no ancestor is visible on current screen, provisionally force
805  * subject... */
806  if (reverse ? (tmp->message->msgno > edgemsgno) : (tmp->message->msgno < edgemsgno))
807  {
808  flags |= MUTT_FORMAT_FORCESUBJ;
809  break;
810  }
811  else if (tmp->message->vnum >= 0)
812  break;
813  }
814  if (flags & MUTT_FORMAT_FORCESUBJ)
815  {
816  for (tmp = e->thread->prev; tmp; tmp = tmp->prev)
817  {
818  if (!tmp->message)
819  continue;
820 
821  /* ...but if a previous sibling is available, don't force it */
822  if (reverse ? (tmp->message->msgno > edgemsgno) : (tmp->message->msgno < edgemsgno))
823  break;
824  else if (tmp->message->vnum >= 0)
825  {
826  flags &= ~MUTT_FORMAT_FORCESUBJ;
827  break;
828  }
829  }
830  }
831  }
832  }
833 
834  const char *const c_index_format =
835  cs_subset_string(shared->sub, "index_format");
836  mutt_make_string(buf, buflen, menu->win->state.cols, NONULL(c_index_format),
837  m, shared->ctx->msg_in_pager, e, flags, NULL);
838 }
839 
843 int index_color(struct Menu *menu, int line)
844 {
845  struct IndexPrivateData *priv = menu->mdata;
846  struct IndexSharedData *shared = priv->shared;
847  struct Mailbox *m = shared->mailbox;
848  if (!m || (line < 0))
849  return 0;
850 
851  struct Email *e = mutt_get_virt_email(m, line);
852  if (!e)
853  return 0;
854 
855  if (e->pair)
856  return e->pair;
857 
858  mutt_set_header_color(m, e);
859  return e->pair;
860 }
861 
875 void mutt_draw_statusline(struct MuttWindow *win, int cols, const char *buf, size_t buflen)
876 {
877  if (!buf || !stdscr)
878  return;
879 
880  size_t i = 0;
881  size_t offset = 0;
882  bool found = false;
883  size_t chunks = 0;
884  size_t len = 0;
885 
886  struct StatusSyntax
887  {
888  int color;
889  int first;
890  int last;
891  } *syntax = NULL;
892 
893  do
894  {
895  struct ColorLine *cl = NULL;
896  found = false;
897 
898  if (!buf[offset])
899  break;
900 
901  /* loop through each "color status regex" */
902  STAILQ_FOREACH(cl, mutt_color_status_line(), entries)
903  {
904  regmatch_t pmatch[cl->match + 1];
905 
906  if (regexec(&cl->regex, buf + offset, cl->match + 1, pmatch, 0) != 0)
907  continue; /* regex doesn't match the status bar */
908 
909  int first = pmatch[cl->match].rm_so + offset;
910  int last = pmatch[cl->match].rm_eo + offset;
911 
912  if (first == last)
913  continue; /* ignore an empty regex */
914 
915  if (!found)
916  {
917  chunks++;
918  mutt_mem_realloc(&syntax, chunks * sizeof(struct StatusSyntax));
919  }
920 
921  i = chunks - 1;
922  if (!found || (first < syntax[i].first) ||
923  ((first == syntax[i].first) && (last > syntax[i].last)))
924  {
925  syntax[i].color = cl->pair;
926  syntax[i].first = first;
927  syntax[i].last = last;
928  }
929  found = true;
930  }
931 
932  if (syntax)
933  {
934  offset = syntax[i].last;
935  }
936  } while (found);
937 
938  /* Only 'len' bytes will fit into 'cols' screen columns */
939  len = mutt_wstr_trunc(buf, buflen, cols, NULL);
940 
941  offset = 0;
942 
943  if ((chunks > 0) && (syntax[0].first > 0))
944  {
945  /* Text before the first highlight */
946  mutt_window_addnstr(win, buf, MIN(len, syntax[0].first));
947  attrset(mutt_color(MT_COLOR_STATUS));
948  if (len <= syntax[0].first)
949  goto dsl_finish; /* no more room */
950 
951  offset = syntax[0].first;
952  }
953 
954  for (i = 0; i < chunks; i++)
955  {
956  /* Highlighted text */
957  attrset(syntax[i].color);
958  mutt_window_addnstr(win, buf + offset, MIN(len, syntax[i].last) - offset);
959  if (len <= syntax[i].last)
960  goto dsl_finish; /* no more room */
961 
962  size_t next;
963  if ((i + 1) == chunks)
964  {
965  next = len;
966  }
967  else
968  {
969  next = MIN(len, syntax[i + 1].first);
970  }
971 
972  attrset(mutt_color(MT_COLOR_STATUS));
973  offset = syntax[i].last;
974  mutt_window_addnstr(win, buf + offset, next - offset);
975 
976  offset = next;
977  if (offset >= len)
978  goto dsl_finish; /* no more room */
979  }
980 
981  attrset(mutt_color(MT_COLOR_STATUS));
982  if (offset < len)
983  {
984  /* Text after the last highlight */
985  mutt_window_addnstr(win, buf + offset, len - offset);
986  }
987 
988  int width = mutt_strwidth(buf);
989  if (width < cols)
990  {
991  /* Pad the rest of the line with whitespace */
992  mutt_paddstr(win, cols - width, "");
993  }
994 dsl_finish:
995  FREE(&syntax);
996 }
997 
1001 static void index_custom_redraw(struct Menu *menu)
1002 {
1003  if (menu->redraw & MENU_REDRAW_FULL)
1004  menu_redraw_full(menu);
1005 
1006  struct IndexPrivateData *priv = menu->mdata;
1007  struct IndexSharedData *shared = priv->shared;
1008  struct Mailbox *m = shared->mailbox;
1009  const int index = menu_get_index(menu);
1010  if (m && m->emails && (index < m->vcount))
1011  {
1012  if (menu->redraw & MENU_REDRAW_INDEX)
1013  {
1014  menu_redraw_index(menu);
1015  }
1016  else if (menu->redraw & MENU_REDRAW_MOTION)
1017  menu_redraw_motion(menu);
1018  else if (menu->redraw & MENU_REDRAW_CURRENT)
1019  menu_redraw_current(menu);
1020  }
1021 
1022  menu->redraw = MENU_REDRAW_NO_FLAGS;
1023  mutt_debug(LL_DEBUG5, "repaint done\n");
1024 }
1025 
1035 struct Mailbox *mutt_index_menu(struct MuttWindow *dlg, struct Mailbox *m_init)
1036 {
1037  struct Context *ctx_old = Context;
1038  struct IndexSharedData *shared = dlg->wdata;
1039  index_shared_data_set_context(shared, ctx_new(m_init));
1040 
1041  struct MuttWindow *panel_index = window_find_child(dlg, WT_INDEX);
1042  struct MuttWindow *panel_pager = window_find_child(dlg, WT_PAGER);
1043 
1044  struct IndexPrivateData *priv = panel_index->wdata;
1045  priv->attach_msg = OptAttachMsg;
1046  priv->win_index = window_find_child(panel_index, WT_MENU);
1047  priv->win_ibar = window_find_child(panel_index, WT_STATUS_BAR);
1048  priv->win_pager = window_find_child(panel_pager, WT_CUSTOM);
1049  priv->win_pbar = window_find_child(panel_pager, WT_STATUS_BAR);
1050 
1051  int op = OP_NULL;
1052 
1053 #ifdef USE_NNTP
1054  if (shared->mailbox && (shared->mailbox->type == MUTT_NNTP))
1055  dlg->help_data = IndexNewsHelp;
1056  else
1057 #endif
1058  dlg->help_data = IndexHelp;
1059  dlg->help_menu = MENU_MAIN;
1060 
1061  priv->menu = priv->win_index->wdata;
1062  priv->menu->make_entry = index_make_entry;
1063  priv->menu->color = index_color;
1065  priv->menu->max = shared->mailbox ? shared->mailbox->vcount : 0;
1066  menu_set_index(priv->menu, ci_first_message(shared->mailbox));
1067  mutt_window_reflow(NULL);
1068 
1069  if (!priv->attach_msg)
1070  {
1071  /* force the mailbox check after we enter the folder */
1073  }
1074 #ifdef USE_INOTIFY
1075  mutt_monitor_add(NULL);
1076 #endif
1077 
1078  {
1079  const bool c_collapse_all = cs_subset_bool(shared->sub, "collapse_all");
1080  if (mutt_using_threads() && c_collapse_all)
1081  {
1082  collapse_all(shared->ctx, priv->menu, 0);
1084  }
1085  }
1086 
1087  while (true)
1088  {
1089  /* Clear the tag prefix unless we just started it. Don't clear
1090  * the prefix on a timeout (op==-2), but do clear on an abort (op==-1) */
1091  if (priv->tag && (op != OP_TAG_PREFIX) && (op != OP_TAG_PREFIX_COND) && (op != -2))
1092  priv->tag = false;
1093 
1094  /* check if we need to resort the index because just about
1095  * any 'op' below could do mutt_enter_command(), either here or
1096  * from any new priv->menu launched, and change $sort/$sort_aux */
1097  if (OptNeedResort && shared->mailbox && (shared->mailbox->msg_count != 0) &&
1098  (menu_get_index(priv->menu) >= 0))
1099  {
1100  resort_index(shared->ctx, priv->menu);
1101  }
1102 
1103  priv->menu->max = shared->mailbox ? shared->mailbox->vcount : 0;
1104  priv->oldcount = shared->mailbox ? shared->mailbox->msg_count : 0;
1105 
1106  {
1107  if (OptRedrawTree && shared->mailbox &&
1108  (shared->mailbox->msg_count != 0) && mutt_using_threads())
1109  {
1110  mutt_draw_tree(shared->ctx->threads);
1112  OptRedrawTree = false;
1113  }
1114  }
1115 
1116  if (shared->mailbox)
1117  {
1118  mailbox_gc_run();
1119 
1120  shared->ctx->menu = priv->menu;
1121  /* check for new mail in the mailbox. If nonzero, then something has
1122  * changed about the file (either we got new mail or the file was
1123  * modified underneath us.) */
1124  enum MxStatus check = mx_mbox_check(shared->mailbox);
1125 
1126  if (check == MX_STATUS_ERROR)
1127  {
1128  if (mutt_buffer_is_empty(&shared->mailbox->pathbuf))
1129  {
1130  /* fatal error occurred */
1131  ctx_free(&shared->ctx);
1133  }
1134 
1135  OptSearchInvalid = true;
1136  }
1137  else if ((check == MX_STATUS_NEW_MAIL) || (check == MX_STATUS_REOPENED) ||
1138  (check == MX_STATUS_FLAGS))
1139  {
1140  /* notify the user of new mail */
1141  if (check == MX_STATUS_REOPENED)
1142  {
1143  mutt_error(
1144  _("Mailbox was externally modified. Flags may be wrong."));
1145  }
1146  else if (check == MX_STATUS_NEW_MAIL)
1147  {
1148  for (size_t i = 0; i < shared->mailbox->msg_count; i++)
1149  {
1150  const struct Email *e = shared->mailbox->emails[i];
1151  if (e && !e->read && !e->old)
1152  {
1153  mutt_message(_("New mail in this mailbox"));
1154  const bool c_beep_new = cs_subset_bool(shared->sub, "beep_new");
1155  if (c_beep_new)
1156  mutt_beep(true);
1157  const char *const c_new_mail_command =
1158  cs_subset_string(shared->sub, "new_mail_command");
1159  if (c_new_mail_command)
1160  {
1161  char cmd[1024];
1162  menu_status_line(cmd, sizeof(cmd), shared, priv->menu,
1163  sizeof(cmd), NONULL(c_new_mail_command));
1164  if (mutt_system(cmd) != 0)
1165  mutt_error(_("Error running \"%s\""), cmd);
1166  }
1167  break;
1168  }
1169  }
1170  }
1171  else if (check == MX_STATUS_FLAGS)
1172  {
1173  mutt_message(_("Mailbox was externally modified"));
1174  }
1175 
1176  /* avoid the message being overwritten by mailbox */
1177  priv->do_mailbox_notify = false;
1178 
1179  bool verbose = shared->mailbox->verbose;
1180  shared->mailbox->verbose = false;
1181  update_index(priv->menu, shared->ctx, check, priv->oldcount, shared);
1182  shared->mailbox->verbose = verbose;
1183  priv->menu->max = shared->mailbox->vcount;
1185  OptSearchInvalid = true;
1186  }
1187 
1188  if (shared->mailbox)
1189  {
1191  shared, mutt_get_virt_email(shared->mailbox, menu_get_index(priv->menu)));
1192  }
1193  }
1194 
1195  if (!priv->attach_msg)
1196  {
1197  /* check for new mail in the incoming folders */
1198  priv->oldcount = priv->newcount;
1199  priv->newcount = mutt_mailbox_check(shared->mailbox, 0);
1200  if (priv->newcount != priv->oldcount)
1202  if (priv->do_mailbox_notify)
1203  {
1204  if (mutt_mailbox_notify(shared->mailbox))
1205  {
1207  const bool c_beep_new = cs_subset_bool(shared->sub, "beep_new");
1208  if (c_beep_new)
1209  mutt_beep(true);
1210  const char *const c_new_mail_command =
1211  cs_subset_string(shared->sub, "new_mail_command");
1212  if (c_new_mail_command)
1213  {
1214  char cmd[1024];
1215  menu_status_line(cmd, sizeof(cmd), shared, priv->menu, sizeof(cmd),
1216  NONULL(c_new_mail_command));
1217  if (mutt_system(cmd) != 0)
1218  mutt_error(_("Error running \"%s\""), cmd);
1219  }
1220  }
1221  }
1222  else
1223  priv->do_mailbox_notify = true;
1224  }
1225 
1226  if (op >= 0)
1228 
1229  if (priv->in_pager)
1230  {
1231  mutt_curses_set_cursor(MUTT_CURSOR_VISIBLE); /* fallback from the pager */
1232  }
1233  else
1234  {
1235  index_custom_redraw(priv->menu);
1236  window_redraw(NULL);
1237 
1238  /* give visual indication that the next command is a tag- command */
1239  if (priv->tag)
1241 
1242  const bool c_arrow_cursor = cs_subset_bool(shared->sub, "arrow_cursor");
1243  const bool c_braille_friendly =
1244  cs_subset_bool(shared->sub, "braille_friendly");
1245  const int index = menu_get_index(priv->menu);
1246  if (c_arrow_cursor)
1247  {
1248  mutt_window_move(priv->menu->win, 2, index - priv->menu->top);
1249  }
1250  else if (c_braille_friendly)
1251  {
1252  mutt_window_move(priv->menu->win, 0, index - priv->menu->top);
1253  }
1254  else
1255  {
1256  mutt_window_move(priv->menu->win, priv->menu->win->state.cols - 1,
1257  index - priv->menu->top);
1258  }
1259  mutt_refresh();
1260 
1261  if (SigWinch)
1262  {
1263  SigWinch = false;
1265  priv->menu->top = 0; /* so we scroll the right amount */
1266  /* force a real complete redraw. clrtobot() doesn't seem to be able
1267  * to handle every case without this. */
1268  clearok(stdscr, true);
1270  continue;
1271  }
1272 
1273  window_redraw(NULL);
1274  op = km_dokey(MENU_MAIN);
1275 
1276  /* either user abort or timeout */
1277  if (op < 0)
1278  {
1280  if (priv->tag)
1282  continue;
1283  }
1284 
1285  mutt_debug(LL_DEBUG1, "Got op %s (%d)\n", OpStrings[op][0], op);
1286 
1288 
1289  /* special handling for the priv->tag-prefix function */
1290  const bool c_auto_tag = cs_subset_bool(shared->sub, "auto_tag");
1291  if ((op == OP_TAG_PREFIX) || (op == OP_TAG_PREFIX_COND))
1292  {
1293  /* A second priv->tag-prefix command aborts */
1294  if (priv->tag)
1295  {
1296  priv->tag = false;
1298  continue;
1299  }
1300 
1301  if (!shared->mailbox)
1302  {
1303  mutt_error(_("No mailbox is open"));
1304  continue;
1305  }
1306 
1307  if (shared->mailbox->msg_tagged == 0)
1308  {
1309  if (op == OP_TAG_PREFIX)
1310  mutt_error(_("No tagged messages"));
1311  else if (op == OP_TAG_PREFIX_COND)
1312  {
1314  mutt_message(_("Nothing to do"));
1315  }
1316  continue;
1317  }
1318 
1319  /* get the real command */
1320  priv->tag = true;
1321  continue;
1322  }
1323  else if (c_auto_tag && shared->mailbox && (shared->mailbox->msg_tagged != 0))
1324  {
1325  priv->tag = true;
1326  }
1327 
1328  mutt_clear_error();
1329  }
1330 
1331 #ifdef USE_NNTP
1332  OptNews = false; /* for any case */
1333 #endif
1334 
1335 #ifdef USE_NOTMUCH
1336  nm_db_debug_check(shared->mailbox);
1337 #endif
1338 
1339  int rc = index_function_dispatcher(priv->win_index, op);
1340 
1341  if (rc == IR_CONTINUE)
1342  {
1343  op = OP_DISPLAY_MESSAGE;
1344  continue;
1345  }
1346 
1347  if (rc > 0)
1348  {
1349  op = rc;
1350  continue;
1351  }
1352 
1353  if ((rc == IR_UNKNOWN) && !priv->in_pager)
1355 
1356 #ifdef USE_NOTMUCH
1357  nm_db_debug_check(shared->mailbox);
1358 #endif
1359 
1360  if (priv->in_pager)
1361  {
1363  priv->in_pager = false;
1365  }
1366 
1367  if (rc == IR_DONE)
1368  break;
1369  }
1370 
1371  ctx_free(&shared->ctx);
1372  Context = ctx_old;
1373 
1374  return shared->mailbox;
1375 }
1376 
1382 void mutt_set_header_color(struct Mailbox *m, struct Email *e)
1383 {
1384  if (!e)
1385  return;
1386 
1387  struct ColorLine *color = NULL;
1388  struct PatternCache cache = { 0 };
1389 
1390  STAILQ_FOREACH(color, mutt_color_index(), entries)
1391  {
1393  MUTT_MATCH_FULL_ADDRESS, m, e, &cache))
1394  {
1395  e->pair = color->pair;
1396  return;
1397  }
1398  }
1400 }
1401 
1407 {
1408  struct MuttWindow *dlg =
1411 
1412  struct IndexSharedData *shared = index_shared_data_new();
1413  notify_set_parent(shared->notify, dlg->notify);
1414 
1415  dlg->wdata = shared;
1417 
1418  const bool c_status_on_top = cs_subset_bool(NeoMutt->sub, "status_on_top");
1419 
1420  struct MuttWindow *panel_index = ipanel_new(c_status_on_top, shared);
1421  struct MuttWindow *panel_pager = ppanel_new(c_status_on_top, shared);
1422 
1423  mutt_window_add_child(dlg, panel_index);
1424  mutt_window_add_child(dlg, panel_pager);
1425 
1426  dlg->focus = panel_index;
1427 
1428  return dlg;
1429 }
struct Email ** emails
Array of Emails.
Definition: mailbox.h:99
Convenience wrapper for the gui headers.
struct IndexSharedData * shared
Shared Index data.
Definition: private_data.h:43
The "current" mailbox.
Definition: context.h:37
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox&#39;s path string.
Definition: mailbox.h:215
Mailbox is about to be deleted.
Definition: mailbox.h:174
struct MuttWindow * window_find_child(struct MuttWindow *win, enum WindowType type)
Recursively find a child Window of a given type.
Definition: mutt_window.c:550
Manage keymappings.
enum MailboxType type
Mailbox type.
Definition: mailbox.h:105
uint8_t MuttFormatFlags
Flags for mutt_expando_format(), e.g. MUTT_FORMAT_FORCESUBJ.
Definition: format_flags.h:29
#define NONULL(x)
Definition: string2.h:37
int msg_count
Total number of messages.
Definition: mailbox.h:91
void mutt_thread_collapse(struct ThreadsContext *tctx, bool collapse)
toggle collapse
Definition: mutt_thread.c:1744
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
bool mx_mbox_open(struct Mailbox *m, OpenMailboxFlags flags)
Open a mailbox and parse it.
Definition: mx.c:304
int msg_in_pager
Message currently shown in the pager.
Definition: context.h:43
The envelope/body of an email.
Definition: email.h:37
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:228
struct Email * mutt_get_virt_email(struct Mailbox *m, int vnum)
Get a virtual Email.
Definition: context.c:412
void(* wdata_free)(struct MuttWindow *win, void **ptr)
Definition: mutt_window.h:160
#define MIN(a, b)
Definition: memory.h:31
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:695
Definition: lib.h:67
Data passed to a notification function.
Definition: observer.h:39
struct ConnAccount account
Account details: username, password, etc.
Definition: connection.h:40
struct Body * body
List of MIME parts.
Definition: email.h:91
Log of notifications.
Definition: logging.h:45
void mutt_clear_pager_position(void)
Reset the pager&#39;s viewing position.
Definition: dlg_pager.c:1995
&#39;NNTP&#39; (Usenet) Mailbox type
Definition: mailbox.h:52
Structs that make up an email.
struct Menu * menu
Menu controlling the index.
Definition: private_data.h:44
String processing routines to generate the mail index.
#define mutt_error(...)
Definition: logging.h:88
struct Mailbox * mailbox
The Mailbox this Event relates to.
Definition: mailbox.h:192
The "currently-open" mailbox.
#define mutt_uncollapse_thread(e)
Definition: mutt_thread.h:89
#define mutt_collapse_thread(e)
Definition: mutt_thread.h:88
bool tag
tag-prefix has been pressed
Definition: private_data.h:36
#define MUTT_FORMAT_FORCESUBJ
Print the subject even if unchanged.
Definition: format_flags.h:31
void update_index(struct Menu *menu, struct Context *ctx, enum MxStatus check, int oldcount, const struct IndexSharedData *shared)
Update the index.
Definition: dlg_index.c:496
int help_menu
Menu for key bindings, e.g. MENU_PAGER.
Definition: mutt_window.h:141
Private state data for the Index.
Definition: private_data.h:34
void mutt_sort_headers(struct Mailbox *m, struct ThreadsContext *threads, bool init, off_t *vsize)
Sort emails by their headers.
Definition: sort.c:356
struct MuttThread * thread
Thread of Emails.
Definition: email.h:95
struct ConfigSubset * sub
Config set to use.
Definition: shared_data.h:38
void mutt_update_index(struct Menu *menu, struct Context *ctx, enum MxStatus check, int oldcount, struct IndexSharedData *shared)
Update the index.
Definition: dlg_index.c:541
struct MuttWindow * win_pbar
Window for the Pager Bar.
Definition: private_data.h:48
int index_color(struct Menu *menu, int line)
Calculate the colour for a line of the index - Implements Menu::color() -.
Definition: dlg_index.c:843
void mutt_set_header_color(struct Mailbox *m, struct Email *e)
Select a colour for a message.
Definition: dlg_index.c:1382
int mutt_monitor_remove(struct Mailbox *m)
Remove a watch for a mailbox.
Definition: monitor.c:526
const struct Mapping IndexNewsHelp[]
Help Bar for the News Index dialog.
Definition: dlg_index.c:122
void index_shared_data_set_context(struct IndexSharedData *shared, struct Context *ctx)
Set the Context for the Index and friends.
Definition: shared_data.c:154
struct PatternList * color_pattern
Compiled pattern to speed up index color calculation.
Definition: color.h:104
void collapse_all(struct Context *ctx, struct Menu *menu, int toggle)
Collapse/uncollapse all threads.
Definition: dlg_index.c:171
void mutt_resize_screen(void)
Update NeoMutt&#39;s opinion about the window size (CURSES)
Definition: resize.c:101
char * realpath
Used for duplicate detection, context comparison, and the sidebar.
Definition: mailbox.h:84
NeoMutt Logging.
void menu_redraw_motion(struct Menu *menu)
Force the redraw of the list part of the menu.
Definition: draw.c:427
WHERE bool OptNeedResort
(pseudo) used to force a re-sort
Definition: options.h:42
#define MUTT_FORMAT_ARROWCURSOR
Reserve space for arrow_cursor.
Definition: format_flags.h:35
struct ThreadsContext * threads
Threads context.
Definition: context.h:42
MenuRedrawFlags redraw
When to redraw the screen.
Definition: lib.h:72
bool display_subject
Used for threading.
Definition: email.h:57
struct ColorLineList * mutt_color_index(void)
Return the ColorLineList for the index.
Definition: color.c:1445
int pair
Colour pair index.
Definition: color.h:107
Nondestructive flags change (IMAP)
Definition: mxapi.h:82
int newcount
New count of Emails in the Mailbox.
Definition: private_data.h:38
New mail received in Mailbox.
Definition: mxapi.h:79
int oldcount
Old count of Emails in the Mailbox.
Definition: private_data.h:37
bool ctx_has_limit(const struct Context *ctx)
Is a limit active?
Definition: context.c:433
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:370
LOFF_T offset
offset where the actual data begins
Definition: body.h:44
int ci_previous_undeleted(struct Mailbox *m, int msgno)
Find the previous undeleted email.
Definition: dlg_index.c:250
#define _(a)
Definition: message.h:28
Mailbox wasn&#39;t recognised.
Definition: mailbox.h:47
Error occurred examining Mailbox.
Definition: mailbox.h:46
Private state data for the Index.
Normal threading (root above subthreads)
Definition: mutt_thread.h:81
void window_redraw(struct MuttWindow *win)
Reflow, recalc and repaint a tree of Windows.
Definition: mutt_window.c:632
Data shared between Index, Pager and Sidebar.
Definition: shared_data.h:36
void index_shared_data_free(struct MuttWindow *win, void **ptr)
Free Index Data.
Definition: shared_data.c:273
struct MuttThread * parent
Parent of this Thread.
Definition: thread.h:45
Index functions.
enum UseThreads mutt_thread_style(void)
Which threading style is active?
Definition: mutt_thread.c:89
int attach_msg
Are we in "attach message" mode?
Definition: private_data.h:40
WHERE struct Context * Context
Definition: mutt_globals.h:40
enum MxStatus mx_mbox_close(struct Mailbox *m)
Save changes and close mailbox.
Definition: mx.c:610
An Event that happened to a Mailbox.
Definition: mailbox.h:190
int mutt_monitor_add(struct Mailbox *m)
Add a watch for a mailbox.
Definition: monitor.c:481
Flags to control mutt_expando_format()
All user-callable functions.
void msgwin_clear_text(void)
Clear the text in the Message Window.
Definition: msgwin.c:242
Container for Accounts, Notifications.
Definition: neomutt.h:36
struct Notify * notify
Notifications: NotifyIndex, IndexSharedData.
Definition: shared_data.h:44
int vcount
The number of virtual messages.
Definition: mailbox.h:102
The body of an email.
Definition: body.h:34
Status Bar containing extra info about the Index/Pager/etc.
Definition: mutt_window.h:102
Mailbox was reopened.
Definition: mxapi.h:81
Convenience wrapper for the config headers.
int mutt_window_move(struct MuttWindow *win, int col, int row)
Move the cursor in a Window.
Definition: mutt_window.c:310
void(* make_entry)(struct Menu *menu, char *buf, size_t buflen, int line)
Definition: lib.h:105
A panel containing the Index Window.
Definition: mutt_window.h:97
Assorted sorting methods.
struct MuttWindow * ppanel_new(bool status_on_top, struct IndexSharedData *shared)
Create the Windows for the Pager panel.
Definition: ppanel.c:121
int event_subtype
Send: Event subtype, e.g. NT_ACCOUNT_ADD.
Definition: observer.h:43
void mutt_beep(bool force)
Irritate the user.
Definition: curs_lib.c:105
enum NotifyType event_type
Send: Event type, e.g. NT_ACCOUNT.
Definition: observer.h:42
#define MAX(a, b)
Definition: memory.h:30
int match
Substring to match, 0 for old behaviour.
Definition: color.h:102
struct MuttWindow * focus
Focussed Window.
Definition: mutt_window.h:140
enum MxStatus mx_mbox_check(struct Mailbox *m)
Check for new mail - Wrapper for MxOps::mbox_check()
Definition: mx.c:1119
Progress bar.
void mutt_folder_hook(const char *path, const char *desc)
Perform a folder hook.
Definition: hook.c:529
bool read
Email is read.
Definition: email.h:51
char * name
A short name for the Mailbox.
Definition: mailbox.h:85
void mutt_curses_set_cursor(enum MuttCursorState state)
Set the cursor state.
Definition: mutt_curses.c:71
struct Notify * notify
Notifications: NotifyWindow, EventWindow.
Definition: mutt_window.h:138
struct MuttThread * prev
Previous sibling Thread.
Definition: thread.h:48
struct Mailbox * mailbox
Definition: context.h:49
Parse and execute user-defined hooks.
#define MUTT_FORMAT_TREE
Draw the thread tree.
Definition: format_flags.h:32
API for mailboxes.
bool old
Email is seen, but unread.
Definition: email.h:50
void mutt_flush_macro_to_endcond(void)
Drop a macro from the input buffer.
Definition: curs_lib.c:639
void change_folder_string(struct Menu *menu, char *buf, size_t buflen, int *oldcount, struct IndexSharedData *shared, bool *pager_return, bool read_only)
Change to a different Mailbox by string.
Definition: dlg_index.c:720
struct MuttWindow * win
Window holding the Menu.
Definition: lib.h:76
UseThreads
Which threading style is active, $use_threads.
Definition: mutt_thread.h:77
void resort_index(struct Context *ctx, struct Menu *menu)
Resort the index.
Definition: dlg_index.c:330
int ci_first_message(struct Mailbox *m)
Get index of first new message.
Definition: dlg_index.c:274
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:1409
Display a normal cursor.
Definition: mutt_curses.h:81
Convenience wrapper for the core headers.
void km_error_key(enum MenuType mtype)
Handle an unbound key sequence.
Definition: keymap.c:1144
bool mutt_mailbox_notify(struct Mailbox *m_cur)
Notify the user if there&#39;s new mail.
Definition: mutt_mailbox.c:209
struct Menu * menu
Needed for pattern compilation.
Definition: context.h:45
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:112
const char * OpStrings[][2]
Definition: opcodes.c:34
Window with a custom drawing function.
Definition: mutt_window.h:95
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
uint16_t AclFlags
ACL Rights - These show permission to...
Definition: mailbox.h:62
void * global_data
Data from notify_observer_add()
Definition: observer.h:45
Usenet network mailbox type; talk to an NNTP server.
void nm_db_debug_check(struct Mailbox *m)
Check if the database is open.
Definition: db.c:347
bool check_acl(struct Mailbox *m, AclFlags acl, const char *msg)
Check the ACLs for a function.
Definition: dlg_index.c:144
Plain text.
Definition: color.h:58
void mutt_mem_realloc(void *ptr, size_t size)
Resize a block of memory on the heap.
Definition: memory.c:114
struct Context * ctx
Current Mailbox view.
Definition: shared_data.h:39
short cs_subset_sort(const struct ConfigSubset *sub, const char *name)
Get a sort config item by name.
Definition: helpers.c:292
short cols
Number of columns, can be MUTT_WIN_SIZE_UNLIMITED.
Definition: mutt_window.h:60
off_t vsize
Size (in bytes) of the messages shown.
Definition: context.h:39
void mutt_refresh(void)
Force a refresh of the screen.
Definition: curs_lib.c:115
Prototypes for many functions.
static int index_mailbox_observer(struct NotifyCallback *nc)
Notification that a Mailbox has changed - Implements observer_t.
Definition: dlg_index.c:552
bool visible
Is this message part of the view?
Definition: email.h:74
Notmuch virtual mailbox type.
Sort by email threads.
Definition: sort2.h:49
struct Context * ctx_new(struct Mailbox *m)
Create a new Context.
Definition: context.c:77
struct WindowState state
Current state of the Window.
Definition: mutt_window.h:127
void * mdata
Private data.
Definition: lib.h:155
WHERE bool OptAttachMsg
(pseudo) used by attach-message
Definition: options.h:31
#define SLIST_FIRST(head)
Definition: queue.h:229
int email_max
Number of pointers in emails.
Definition: mailbox.h:100
struct Mailbox * mailbox_find_name(const char *name)
Find the mailbox with a given name.
Definition: mailbox.c:162
Create/manipulate threading in emails.
Return to the Pager.
Definition: functions.h:36
LOFF_T length
length (in bytes) of attachment
Definition: body.h:45
Status bar (takes a pattern)
Definition: color.h:75
A mailbox.
Definition: mailbox.h:81
struct ConfigSubset * sub
Inherited config items.
Definition: mailbox.h:86
int mutt_strwidth(const char *s)
Measure a string&#39;s width in screen cells.
Definition: curs_lib.c:983
int mutt_mailbox_check(struct Mailbox *m_cur, int force)
Check all all Mailboxes for new mail.
Definition: mutt_mailbox.c:137
#define MUTT_WIN_SIZE_UNLIMITED
Use as much space as possible.
Definition: mutt_window.h:52
int ci_next_undeleted(struct Mailbox *m, int msgno)
Find the next undeleted email.
Definition: dlg_index.c:227
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:90
int top
Entry that is the top of the current page.
Definition: lib.h:89
No changes.
Definition: mxapi.h:78
struct MuttWindow * index_pager_init(void)
Allocate the Windows for the Index/Pager.
Definition: dlg_index.c:1406
struct PatternList * limit_pattern
Compiled limit pattern.
Definition: context.h:41
static void index_custom_redraw(struct Menu *menu)
Redraw the index - Implements Menu::custom_redraw() -.
Definition: dlg_index.c:1001
const struct Mapping * help_data
Data for the Help Bar.
Definition: mutt_window.h:142
Match patterns to emails.
void mutt_draw_statusline(struct MuttWindow *win, int cols, const char *buf, size_t buflen)
Draw a highlighted status bar.
Definition: dlg_index.c:875
#define MUTT_READONLY
Open in read-only mode.
Definition: mxapi.h:63
int mutt_parent_message(struct Email *e, bool find_root)
Find the parent of a message.
Definition: mutt_thread.c:1320
Nntp-specific Mailbox data.
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:933
Exit the Index.
Definition: functions.h:37
struct MuttWindow * ipanel_new(bool status_on_top, struct IndexSharedData *shared)
Create the Windows for the Index panel.
Definition: ipanel.c:120
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:761
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
struct Mailbox * mutt_index_menu(struct MuttWindow *dlg, struct Mailbox *m_init)
Display a list of emails.
Definition: dlg_index.c:1035
bool collapsed
Is this message part of a collapsed thread?
Definition: email.h:73
bool verbose
Display status messages?
Definition: mailbox.h:118
uint8_t OpenMailboxFlags
Flags for mutt_open_mailbox(), e.g. MUTT_NOSORT.
Definition: mxapi.h:59
int msg_tagged
How many messages are tagged?
Definition: mailbox.h:97
int vnum
Virtual message number.
Definition: email.h:88
void(* custom_redraw)(struct Menu *menu)
Definition: lib.h:151
Index panel (list of emails)
Definition: type.h:50
WHERE bool OptSearchInvalid
(pseudo) used to invalidate the search pattern
Definition: options.h:51
AclFlags rights
ACL bits, see AclFlags.
Definition: mailbox.h:121
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:352
int pagelen
Number of entries per screen.
Definition: lib.h:74
char * tree
Character string to print thread tree.
Definition: email.h:94
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
WHERE bool OptRedrawTree
(pseudo) redraw the thread tree
Definition: options.h:49
#define mutt_debug(LEVEL,...)
Definition: logging.h:85
int mutt_color(enum ColorId id)
Return the color of an object.
Definition: color.c:1427
struct Email * message
Email this Thread refers to.
Definition: thread.h:49
static void update_index_threaded(struct Context *ctx, enum MxStatus check, int oldcount)
Update the index (if threaded)
Definition: dlg_index.c:371
WHERE char * LastFolder
Previously selected mailbox.
Definition: mutt_globals.h:51
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:257
#define MUTT_MAILBOX_CHECK_FORCE
Definition: mutt_mailbox.h:32
Unthreaded.
Definition: mutt_thread.h:80
int max
Number of entries in the menu.
Definition: lib.h:71
void mutt_window_add_child(struct MuttWindow *parent, struct MuttWindow *child)
Add a child to Window.
Definition: mutt_window.c:468
LOFF_T offset
Where in the stream does this message begin?
Definition: email.h:84
#define mutt_using_threads()
Definition: mutt_thread.h:95
GUI display a user-configurable status line.
An Email conversation.
Definition: thread.h:34
int 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:1097
int * v2r
Mapping from virtual to real msgno.
Definition: mailbox.h:101
uint8_t flags
e.g. MB_NORMAL
Definition: mailbox.h:134
struct Connection * conn
Definition: adata.h:63
A panel containing the Pager Window.
Definition: mutt_window.h:100
regex_t regex
Compiled regex.
Definition: color.h:101
#define MUTT_FORMAT_INDEX
This is a main index entry.
Definition: format_flags.h:36
enum MailboxType mx_path_probe(const char *path)
Find a mailbox that understands a path.
Definition: mx.c:1317
Unknown key.
Definition: functions.h:35
MailboxType
Supported mailbox formats.
Definition: mailbox.h:43
struct MuttWindow * win_index
Window for the Index.
Definition: private_data.h:45
Log at debug level 1.
Definition: logging.h:40
Window uses all available horizontal space.
Definition: mutt_window.h:39
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:446
bool collapsed
Are all threads collapsed?
Definition: context.h:47
void mailbox_gc_run(void)
Run the garbage-collection.
Definition: mailbox.c:278
bool deleted
Email is deleted.
Definition: email.h:45
struct ColorLineList * mutt_color_status_line(void)
Return the ColorLineList for the status_line.
Definition: color.c:1436
void mutt_window_reflow(struct MuttWindow *win)
Resize a Window and its children.
Definition: mutt_window.c:361
Current Mailbox has changed.
Definition: mailbox.h:182
struct MuttWindow * win_ibar
Window for the Index Bar (status)
Definition: private_data.h:46
void * compress_info
Compressed mbox module private data.
Definition: mailbox.h:124
void menu_redraw_index(struct Menu *menu)
Force the redraw of the index.
Definition: draw.c:371
WHERE char * CurrentFolder
Currently selected mailbox.
Definition: mutt_globals.h:50
Connection Library.
bool in_pager
Is the Pager active?
Definition: private_data.h:41
void mutt_timeout_hook(void)
Execute any timeout hooks.
Definition: hook.c:827
void menu_redraw_full(struct Menu *menu)
Force the redraw of the Menu.
Definition: draw.c:337
int index
The absolute (unsorted) message number.
Definition: email.h:86
#define mutt_message(...)
Definition: logging.h:87
#define FREE(x)
Definition: memory.h:40
struct Mailbox * mx_path_resolve(const char *path)
Get a Mailbox for a path.
Definition: mx.c:1668
Mailbox has changed, NotifyMailbox, EventMailbox.
Definition: notify_type.h:48
Mapping between user-readable string and a constant.
Definition: mapping.h:31
bool do_mailbox_notify
Do we need to notify the user of new mail?
Definition: private_data.h:39
int index_function_dispatcher(struct MuttWindow *win_index, int op)
Perform an Index function.
Definition: functions.c:2964
#define MUTT_OPEN_NO_FLAGS
No flags are set.
Definition: mxapi.h:60
Monitor files for changes.
Hide the cursor.
Definition: mutt_curses.h:80
void mutt_draw_tree(struct ThreadsContext *tctx)
Draw a tree of threaded emails.
Definition: mutt_thread.c:388
struct NntpAccountData * CurrentNewsSrv
Current NNTP news server.
Definition: nntp.c:78
static void update_index_unthreaded(struct Context *ctx, enum MxStatus check)
Update the index (if unthreaded)
Definition: dlg_index.c:452
int mutt_window_addnstr(struct MuttWindow *win, const char *str, int num)
Write a partial string to a Window.
Definition: mutt_window.c:415
bool notify_observer_remove(struct Notify *notify, observer_t callback, void *global_data)
Remove an observer from an object.
Definition: notify.c:228
void menu_redraw_current(struct Menu *menu)
Redraw the current menu.
Definition: draw.c:490
void notify_set_parent(struct Notify *notify, struct Notify *parent)
Set the parent notification handler.
Definition: notify.c:93
struct IndexSharedData * index_shared_data_new(void)
Create new Index Data.
Definition: shared_data.c:300
void ctx_free(struct Context **ptr)
Free a Context.
Definition: context.c:49
Hundreds of global variables to back the user variables.
Handling of global boolean variables.
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
int mx_msg_padding_size(struct Mailbox *m)
Bytes of padding between messages - Wrapper for MxOps::msg_padding_size()
Definition: mx.c:1540
struct Notify * notify
Notifications: NotifyMailbox, EventMailbox.
Definition: mailbox.h:148
long hdr_offset
Offset in stream where the headers begin.
Definition: body.h:42
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:180
struct Mailbox * mailbox
Current Mailbox.
Definition: shared_data.h:41
off_t mutt_set_vnum(struct Mailbox *m)
Set the virtual index number of all the messages in a mailbox.
Definition: mutt_thread.c:1370
Cache commonly-used patterns.
Definition: lib.h:105
int km_dokey(enum MenuType mtype)
Determine what a keypress should do.
Definition: keymap.c:635
Index Dialog, index_pager_init()
Definition: mutt_window.h:86
Log at debug level 5.
Definition: logging.h:44
Nntp-specific Account data.
struct Buffer pathbuf
Definition: mailbox.h:83
bool mutt_thread_can_collapse(struct Email *e)
Check whether a thread can be collapsed.
Definition: mutt_thread.c:1772
#define SORT_REVERSE
Reverse the order of the sort.
Definition: sort2.h:79
static const struct Mapping IndexHelp[]
Help Bar for the Index dialog.
Definition: dlg_index.c:106
void nntp_expand_path(char *buf, size_t buflen, struct ConnAccount *acct)
Make fully qualified url from newsgroup name.
Definition: newsrc.c:559
Window wants as much space as possible.
Definition: mutt_window.h:48
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:577
GUI display a file/email/help in a viewport with paging.
bool mutt_buffer_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:252
Reverse threading (subthreads above root)
Definition: mutt_thread.h:82
void * wdata
Private data.
Definition: mutt_window.h:145
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:1363
#define N_(a)
Definition: message.h:32
WHERE SIG_ATOMIC_VOLATILE_T SigWinch
true after SIGWINCH is received
Definition: mutt_globals.h:68
struct MuttWindow * dialog_find(struct MuttWindow *win)
Find the parent Dialog of a Window.
Definition: dialog.c:85
WHERE bool OptNews
(pseudo) used to change reader mode
Definition: options.h:44
#define MUTT_MATCH_FULL_ADDRESS
Match the full address.
Definition: lib.h:95
MxStatus
Return values from mbox_check(), mbox_check_stats(), mbox_snc(), and mbox_close() ...
Definition: mxapi.h:75
An Window containing a Menu.
Definition: mutt_window.h:98
int pair
Color-pair to use when displaying in the index.
Definition: email.h:80
Mailbox helper functions.
int mutt_system(const char *cmd)
Run an external command.
Definition: system.c:51
#define SORT_MASK
Mask for the sort id.
Definition: sort2.h:78
A regular expression and a color to highlight a line.
Definition: color.h:99
void mutt_paddstr(struct MuttWindow *win, int n, const char *s)
Display a string on screen, padded if necessary.
Definition: curs_lib.c:890
int msgno
Number displayed to the user.
Definition: email.h:87
Private Index Functions.
An error occurred.
Definition: mxapi.h:77
int(* color)(struct Menu *menu, int line)
Definition: lib.h:142
char * nm_url_from_query(struct Mailbox *m, char *buf, size_t buflen)
Turn a query into a URL.
Definition: notmuch.c:1564
struct MuttWindow * win_pager
Window for the Pager.
Definition: private_data.h:47
void msgwin_set_text(enum ColorId color, const char *text)
Set the text for the Message Window.
Definition: msgwin.c:223
bool notify_send(struct Notify *notify, enum NotifyType event_type, int event_subtype, void *event_data)
Send out a notification message.
Definition: notify.c:171
Data shared between Index, Pager and Sidebar.