NeoMutt  2019-12-07-168-gc45f47
Teaching an old dog new tricks
DOXYGEN
index.c
Go to the documentation of this file.
1 
29 #include "config.h"
30 #include <assert.h>
31 #include <ctype.h>
32 #include <limits.h>
33 #include <regex.h>
34 #include <stdbool.h>
35 #include <stdint.h>
36 #include <stdio.h>
37 #include <string.h>
38 #include "mutt/lib.h"
39 #include "config/lib.h"
40 #include "email/lib.h"
41 #include "core/lib.h"
42 #include "conn/lib.h"
43 #include "gui/lib.h"
44 #include "mutt.h"
45 #include "index.h"
46 #include "alias.h"
47 #include "browser.h"
48 #include "commands.h"
49 #include "context.h"
50 #include "format_flags.h"
51 #include "globals.h"
52 #include "hdrline.h"
53 #include "hook.h"
54 #include "keymap.h"
55 #include "mutt_header.h"
56 #include "mutt_logging.h"
57 #include "mutt_mailbox.h"
58 #include "mutt_menu.h"
59 #include "mutt_thread.h"
60 #include "muttlib.h"
61 #include "mx.h"
62 #include "opcodes.h"
63 #include "options.h"
64 #include "pager.h"
65 #include "pattern.h"
66 #include "progress.h"
67 #include "protos.h"
68 #include "query.h"
69 #include "recvattach.h"
70 #include "score.h"
71 #include "send.h"
72 #include "sort.h"
73 #include "status.h"
74 #include "ncrypt/lib.h"
75 #ifdef USE_SIDEBAR
76 #include "sidebar.h"
77 #endif
78 #ifdef USE_POP
79 #include "pop/lib.h"
80 #endif
81 #ifdef USE_IMAP
82 #include "imap/lib.h"
83 #endif
84 #ifdef USE_NOTMUCH
85 #include "notmuch/lib.h"
86 #endif
87 #ifdef USE_NNTP
88 #include "nntp/lib.h"
89 #endif
90 #ifdef ENABLE_NLS
91 #include <libintl.h>
92 #endif
93 #ifdef USE_INOTIFY
94 #include "monitor.h"
95 #endif
96 #ifdef USE_AUTOCRYPT
97 #include "autocrypt/lib.h"
98 #endif
99 
100 /* These Config Variables are only used in index.c */
109 
110 static const struct Mapping IndexHelp[] = {
111  { N_("Quit"), OP_QUIT },
112  { N_("Del"), OP_DELETE },
113  { N_("Undel"), OP_UNDELETE },
114  { N_("Save"), OP_SAVE },
115  { N_("Mail"), OP_MAIL },
116  { N_("Reply"), OP_REPLY },
117  { N_("Group"), OP_GROUP_REPLY },
118  { N_("Help"), OP_HELP },
119  { NULL, 0 },
120 };
121 
122 #ifdef USE_NNTP
123 struct Mapping IndexNewsHelp[] = {
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 };
134 #endif
135 
136 #define UNREAD(email) mutt_thread_contains_unread(Context, email)
137 #define FLAGGED(email) mutt_thread_contains_flagged(Context, email)
138 
139 #define CAN_COLLAPSE(email) \
140  ((C_CollapseUnread || !UNREAD(email)) && (C_CollapseFlagged || !FLAGGED(email)))
141 
142 // clang-format off
146 typedef uint8_t CheckFlags;
147 #define CHECK_NO_FLAGS 0
148 #define CHECK_IN_MAILBOX (1 << 0)
149 #define CHECK_MSGCOUNT (1 << 1)
150 #define CHECK_VISIBLE (1 << 2)
151 #define CHECK_READONLY (1 << 3)
152 #define CHECK_ATTACH (1 << 4)
153 // clang-format on
154 
162 static struct Email *get_cur_email(struct Context *ctx, struct Menu *menu)
163 {
164  if (!ctx || !ctx->mailbox || !menu)
165  return NULL;
166 
167  return mutt_get_virt_email(ctx->mailbox, menu->current);
168 }
169 
177 static bool prereq(struct Context *ctx, struct Menu *menu, CheckFlags checks)
178 {
179  bool result = true;
180 
181  if (checks & (CHECK_MSGCOUNT | CHECK_VISIBLE | CHECK_READONLY))
182  checks |= CHECK_IN_MAILBOX;
183 
184  if ((checks & CHECK_IN_MAILBOX) && (!ctx || !ctx->mailbox))
185  {
186  mutt_error(_("No mailbox is open"));
187  result = false;
188  }
189 
190  if (result && (checks & CHECK_MSGCOUNT) && (ctx->mailbox->msg_count == 0))
191  {
192  mutt_error(_("There are no messages"));
193  result = false;
194  }
195 
196  if (result && (checks & CHECK_VISIBLE) && (menu->current >= ctx->mailbox->vcount))
197  {
198  mutt_error(_("No visible messages"));
199  result = false;
200  }
201 
202  if (result && (checks & CHECK_READONLY) && ctx->mailbox->readonly)
203  {
204  mutt_error(_("Mailbox is read-only"));
205  result = false;
206  }
207 
208  if (result && (checks & CHECK_ATTACH) && OptAttachMsg)
209  {
210  mutt_error(_("Function not permitted in attach-message mode"));
211  result = false;
212  }
213 
214  if (!result)
215  mutt_flushinp();
216 
217  return result;
218 }
219 
227 static bool check_acl(struct Context *ctx, AclFlags acl, const char *msg)
228 {
229  if (!ctx || !ctx->mailbox)
230  return false;
231 
232  if (!(ctx->mailbox->rights & acl))
233  {
234  /* L10N: %s is one of the CHECK_ACL entries below. */
235  mutt_error(_("%s: Operation not permitted by ACL"), msg);
236  return false;
237  }
238 
239  return true;
240 }
241 
254 static void collapse_all(struct Context *ctx, struct Menu *menu, int toggle)
255 {
256  if (!ctx || !ctx->mailbox || (ctx->mailbox->msg_count == 0) || !menu)
257  return;
258 
259  struct Email *e_cur = get_cur_email(ctx, menu);
260  if (!e_cur)
261  return;
262 
263  struct MuttThread *thread = NULL, *top = NULL;
264  int final;
265 
266  /* Figure out what the current message would be after folding / unfolding,
267  * so that we can restore the cursor in a sane way afterwards. */
268  if (e_cur->collapsed && toggle)
269  final = mutt_uncollapse_thread(ctx, e_cur);
270  else if (CAN_COLLAPSE(e_cur))
271  final = mutt_collapse_thread(ctx, e_cur);
272  else
273  final = e_cur->vnum;
274 
275  if (final == -1)
276  return;
277 
278  struct Email *base = mutt_get_virt_email(ctx->mailbox, final);
279  if (!base)
280  return;
281 
282  /* Iterate all threads, perform collapse/uncollapse as needed */
283  top = ctx->tree;
284  ctx->collapsed = toggle ? !ctx->collapsed : true;
285  struct Email *e = NULL;
286  while ((thread = top))
287  {
288  while (!thread->message)
289  thread = thread->child;
290  e = thread->message;
291 
292  if (e->collapsed != ctx->collapsed)
293  {
294  if (e->collapsed)
295  mutt_uncollapse_thread(ctx, e);
296  else if (CAN_COLLAPSE(e))
297  mutt_collapse_thread(ctx, e);
298  }
299  top = top->next;
300  }
301 
302  /* Restore the cursor */
303  mutt_set_vnum(ctx);
304  for (int i = 0; i < ctx->mailbox->vcount; i++)
305  {
306  e = mutt_get_virt_email(ctx->mailbox, i);
307  if (!e)
308  break;
309  if (e->index == base->index)
310  {
311  menu->current = i;
312  break;
313  }
314  }
315 
317 }
318 
326 static int ci_next_undeleted(struct Context *ctx, int msgno)
327 {
328  if (!ctx || !ctx->mailbox)
329  return -1;
330 
331  for (int i = msgno + 1; i < ctx->mailbox->vcount; i++)
332  {
333  struct Email *e = mutt_get_virt_email(ctx->mailbox, i);
334  if (!e)
335  continue;
336  if (!e->deleted)
337  return i;
338  }
339  return -1;
340 }
341 
349 static int ci_previous_undeleted(struct Context *ctx, int msgno)
350 {
351  if (!ctx || !ctx->mailbox)
352  return -1;
353 
354  for (int i = msgno - 1; i >= 0; i--)
355  {
356  struct Email *e = mutt_get_virt_email(ctx->mailbox, i);
357  if (!e)
358  continue;
359  if (!e->deleted)
360  return i;
361  }
362  return -1;
363 }
364 
373 static int ci_first_message(struct Context *ctx)
374 {
375  if (!ctx || !ctx->mailbox || (ctx->mailbox->msg_count == 0))
376  return 0;
377 
378  int old = -1;
379  for (int i = 0; i < ctx->mailbox->vcount; i++)
380  {
381  struct Email *e = mutt_get_virt_email(ctx->mailbox, i);
382  if (!e)
383  continue;
384  if (!e->read && !e->deleted)
385  {
386  if (!e->old)
387  return i;
388  if (old == -1)
389  old = i;
390  }
391  }
392  if (old != -1)
393  return old;
394 
395  /* If C_Sort is reverse and not threaded, the latest message is first.
396  * If C_Sort is threaded, the latest message is first if exactly one
397  * of C_Sort and C_SortAux are reverse. */
398  if (((C_Sort & SORT_REVERSE) && ((C_Sort & SORT_MASK) != SORT_THREADS)) ||
399  (((C_Sort & SORT_MASK) == SORT_THREADS) && ((C_Sort ^ C_SortAux) & SORT_REVERSE)))
400  {
401  return 0;
402  }
403  else
404  {
405  return ctx->mailbox->vcount ? ctx->mailbox->vcount - 1 : 0;
406  }
407 
408  return 0;
409 }
410 
419 static int mx_toggle_write(struct Mailbox *m)
420 {
421  if (!m)
422  return -1;
423 
424  if (m->readonly)
425  {
426  mutt_error(_("Can't toggle write on a readonly mailbox"));
427  return -1;
428  }
429 
430  if (m->dontwrite)
431  {
432  m->dontwrite = false;
433  mutt_message(_("Changes to folder will be written on folder exit"));
434  }
435  else
436  {
437  m->dontwrite = true;
438  mutt_message(_("Changes to folder will not be written"));
439  }
440 
441  return 0;
442 }
443 
449 static void resort_index(struct Context *ctx, struct Menu *menu)
450 {
451  if (!ctx || !ctx->mailbox)
452  return;
453 
454  struct Email *e_cur = get_cur_email(ctx, menu);
455 
456  menu->current = -1;
457  mutt_sort_headers(ctx, false);
458  /* Restore the current message */
459 
460  for (int i = 0; i < ctx->mailbox->vcount; i++)
461  {
462  struct Email *e = mutt_get_virt_email(ctx->mailbox, i);
463  if (!e)
464  continue;
465  if (e == e_cur)
466  {
467  menu->current = i;
468  break;
469  }
470  }
471 
472  if (((C_Sort & SORT_MASK) == SORT_THREADS) && (menu->current < 0))
473  menu->current = mutt_parent_message(ctx, e_cur, false);
474 
475  if (menu->current < 0)
476  menu->current = ci_first_message(ctx);
477 
478  menu->redraw |= REDRAW_INDEX | REDRAW_STATUS;
479 }
480 
487 static void update_index_threaded(struct Context *ctx, int check, int oldcount)
488 {
489  struct Email **save_new = NULL;
490 
491  /* save the list of new messages */
492  if ((check != MUTT_REOPENED) && oldcount && (ctx->pattern || C_UncollapseNew))
493  {
494  save_new = mutt_mem_malloc(sizeof(struct Email *) * (ctx->mailbox->msg_count - oldcount));
495  for (int i = oldcount; i < ctx->mailbox->msg_count; i++)
496  save_new[i - oldcount] = ctx->mailbox->emails[i];
497  }
498 
499  /* Sort first to thread the new messages, because some patterns
500  * require the threading information.
501  *
502  * If the mailbox was reopened, need to rethread from scratch. */
503  mutt_sort_headers(ctx, (check == MUTT_REOPENED));
504 
505  if (ctx->pattern)
506  {
507  for (int i = (check == MUTT_REOPENED) ? 0 : oldcount; i < ctx->mailbox->msg_count; i++)
508  {
509  struct Email *e = NULL;
510 
511  if ((check != MUTT_REOPENED) && oldcount)
512  e = save_new[i - oldcount];
513  else
514  e = ctx->mailbox->emails[i];
515 
517  MUTT_MATCH_FULL_ADDRESS, ctx->mailbox, e, NULL))
518  {
519  /* vnum will get properly set by mutt_set_vnum(), which
520  * is called by mutt_sort_headers() just below. */
521  e->vnum = 1;
522  e->limited = true;
523  }
524  }
525  /* Need a second sort to set virtual numbers and redraw the tree */
526  mutt_sort_headers(ctx, false);
527  }
528 
529  /* uncollapse threads with new mail */
530  if (C_UncollapseNew)
531  {
532  if (check == MUTT_REOPENED)
533  {
534  ctx->collapsed = false;
535 
536  for (struct MuttThread *h = ctx->tree; h; h = h->next)
537  {
538  struct MuttThread *j = h;
539  for (; !j->message; j = j->child)
540  ;
542  }
543  mutt_set_vnum(ctx);
544  }
545  else if (oldcount)
546  {
547  for (int j = 0; j < (ctx->mailbox->msg_count - oldcount); j++)
548  {
549  if (!ctx->pattern || save_new[j]->limited)
550  {
551  mutt_uncollapse_thread(ctx, save_new[j]);
552  }
553  }
554  mutt_set_vnum(ctx);
555  }
556  }
557 
558  FREE(&save_new);
559 }
560 
567 static void update_index_unthreaded(struct Context *ctx, int check, int oldcount)
568 {
569  /* We are in a limited view. Check if the new message(s) satisfy
570  * the limit criteria. If they do, set their virtual msgno so that
571  * they will be visible in the limited view */
572  if (ctx->pattern)
573  {
574  int padding = mx_msg_padding_size(ctx->mailbox);
575  for (int i = (check == MUTT_REOPENED) ? 0 : oldcount; i < ctx->mailbox->msg_count; i++)
576  {
577  if (i == 0)
578  {
579  ctx->mailbox->vcount = 0;
580  ctx->vsize = 0;
581  }
582 
583  struct Email *e = ctx->mailbox->emails[i];
584  if (!e)
585  break;
587  MUTT_MATCH_FULL_ADDRESS, ctx->mailbox, e, NULL))
588  {
589  assert(ctx->mailbox->vcount < ctx->mailbox->msg_count);
590  e->vnum = ctx->mailbox->vcount;
591  ctx->mailbox->v2r[ctx->mailbox->vcount] = i;
592  e->limited = true;
593  ctx->mailbox->vcount++;
594  struct Body *b = e->content;
595  ctx->vsize += b->length + b->offset - b->hdr_offset + padding;
596  }
597  }
598  }
599 
600  /* if the mailbox was reopened, need to rethread from scratch */
601  mutt_sort_headers(ctx, (check == MUTT_REOPENED));
602 }
603 
612 void update_index(struct Menu *menu, struct Context *ctx, int check, int oldcount, int index_hint)
613 {
614  if (!menu || !ctx)
615  return;
616 
617  /* take note of the current message */
618  if (oldcount)
619  {
620  if (menu->current < ctx->mailbox->vcount)
621  menu->oldcurrent = index_hint;
622  else
623  oldcount = 0; /* invalid message number! */
624  }
625 
626  if ((C_Sort & SORT_MASK) == SORT_THREADS)
627  update_index_threaded(ctx, check, oldcount);
628  else
629  update_index_unthreaded(ctx, check, oldcount);
630 
631  menu->current = -1;
632  if (oldcount)
633  {
634  /* restore the current message to the message it was pointing to */
635  for (int i = 0; i < ctx->mailbox->vcount; i++)
636  {
637  struct Email *e = mutt_get_virt_email(ctx->mailbox, i);
638  if (!e)
639  continue;
640  if (e->index == menu->oldcurrent)
641  {
642  menu->current = i;
643  break;
644  }
645  }
646  }
647 
648  if (menu->current < 0)
650 }
651 
658 {
659  if (!nc->global_data)
660  return -1;
661  if ((nc->event_type != NT_MAILBOX) || (nc->event_subtype != NT_MAILBOX_CLOSED))
662  return 0;
663 
664  struct Mailbox **ptr = nc->global_data;
665  if (!ptr || !*ptr)
666  return 0;
667 
668  *ptr = NULL;
669  return 0;
670 }
671 
685 static int main_change_folder(struct Menu *menu, int op, struct Mailbox *m,
686  char *buf, size_t buflen, int *oldcount,
687  int *index_hint, bool *pager_return)
688 {
689 #ifdef USE_NNTP
690  if (OptNews)
691  {
692  OptNews = false;
693  nntp_expand_path(buf, buflen, &CurrentNewsSrv->conn->account);
694  }
695  else
696 #endif
697  {
698  mx_path_canon(buf, buflen, C_Folder, NULL);
699  }
700 
701  enum MailboxType magic = mx_path_probe(buf);
702  if ((magic == MUTT_MAILBOX_ERROR) || (magic == MUTT_UNKNOWN))
703  {
704  // Try to see if the buffer matches a description before we bail.
705  // We'll receive a non-null pointer if there is a corresponding mailbox.
706  m = mailbox_find_name(buf);
707  if (m)
708  {
709  mutt_str_strfcpy(buf, mailbox_path(m), buflen);
710  }
711  else
712  {
713  // Bail.
714  mutt_error(_("%s is not a mailbox"), buf);
715  return -1;
716  }
717  }
718 
719  /* past this point, we don't return to the pager on error */
720  if (pager_return)
721  *pager_return = false;
722 
723  /* keepalive failure in mutt_enter_fname may kill connection. */
725  ctx_free(&Context);
726 
727  if (Context && Context->mailbox)
728  {
729  char *new_last_folder = NULL;
730 #ifdef USE_INOTIFY
731  int monitor_remove_rc = mutt_monitor_remove(NULL);
732 #endif
733 #ifdef USE_COMPRESSED
734  if (Context->mailbox->compress_info && (Context->mailbox->realpath[0] != '\0'))
735  new_last_folder = mutt_str_strdup(Context->mailbox->realpath);
736  else
737 #endif
738  new_last_folder = mutt_str_strdup(mailbox_path(Context->mailbox));
739  *oldcount = Context->mailbox->msg_count;
740 
741  int check = mx_mbox_close(&Context);
742  if (check != 0)
743  {
744 #ifdef USE_INOTIFY
745  if (monitor_remove_rc == 0)
746  mutt_monitor_add(NULL);
747 #endif
748  if ((check == MUTT_NEW_MAIL) || (check == MUTT_REOPENED))
749  update_index(menu, Context, check, *oldcount, *index_hint);
750 
751  FREE(&new_last_folder);
752  OptSearchInvalid = true;
753  menu->redraw |= REDRAW_INDEX | REDRAW_STATUS;
754  return 0;
755  }
756  FREE(&LastFolder);
757  LastFolder = new_last_folder;
758  }
760 
761  mutt_sleep(0);
762 
763  if (m)
764  {
765  /* If the `folder-hook` were to call `unmailboxes`, then the Mailbox (`m`)
766  * could be deleted, leaving `m` dangling. */
767  // TODO: Refactor this function to avoid the need for an observer
769  }
770  mutt_folder_hook(buf, m ? m->name : NULL);
771  if (m)
772  {
773  /* `m` is still valid, but we won't need the observer again before the end
774  * of the function. */
776  }
777 
779  if (C_ReadOnly || (op == OP_MAIN_CHANGE_FOLDER_READONLY))
780  flags = MUTT_READONLY;
781 #ifdef USE_NOTMUCH
782  if (op == OP_MAIN_VFOLDER_FROM_QUERY_READONLY)
783  flags = MUTT_READONLY;
784 #endif
785 
786  bool free_m = false;
787  if (!m)
788  {
789  m = mx_path_resolve(buf);
790  free_m = true;
791  }
792  Context = mx_mbox_open(m, flags);
793  if (Context)
794  {
796 #ifdef USE_INOTIFY
797  mutt_monitor_add(NULL);
798 #endif
799  }
800  else
801  {
802  menu->current = 0;
803  if (free_m)
804  mailbox_free(&m);
805  }
806 
807  if (((C_Sort & SORT_MASK) == SORT_THREADS) && C_CollapseAll)
808  collapse_all(Context, menu, 0);
809 
810 #ifdef USE_SIDEBAR
812 #endif
813 
815  mutt_mailbox_check(Context ? Context->mailbox : NULL, MUTT_MAILBOX_CHECK_FORCE); /* force the mailbox check after we have changed the folder */
816  menu->redraw = REDRAW_FULL;
817  OptSearchInvalid = true;
818 
819  return 0;
820 }
821 
825 void index_make_entry(char *buf, size_t buflen, struct Menu *menu, int line)
826 {
827  if (!Context || !Context->mailbox || !menu || (line < 0) ||
828  (line >= Context->mailbox->email_max))
829  return;
830 
831  struct Email *e = mutt_get_virt_email(Context->mailbox, line);
832  if (!e)
833  return;
834 
836  struct MuttThread *tmp = NULL;
837 
838  if (((C_Sort & SORT_MASK) == SORT_THREADS) && e->tree)
839  {
840  flags |= MUTT_FORMAT_TREE; /* display the thread tree */
841  if (e->display_subject)
842  flags |= MUTT_FORMAT_FORCESUBJ;
843  else
844  {
845  const int reverse = C_Sort & SORT_REVERSE;
846  int edgemsgno;
847  if (reverse)
848  {
849  if (menu->top + menu->pagelen > menu->max)
850  edgemsgno = Context->mailbox->v2r[menu->max - 1];
851  else
852  edgemsgno = Context->mailbox->v2r[menu->top + menu->pagelen - 1];
853  }
854  else
855  edgemsgno = Context->mailbox->v2r[menu->top];
856 
857  for (tmp = e->thread->parent; tmp; tmp = tmp->parent)
858  {
859  if (!tmp->message)
860  continue;
861 
862  /* if no ancestor is visible on current screen, provisionally force
863  * subject... */
864  if (reverse ? (tmp->message->msgno > edgemsgno) : (tmp->message->msgno < edgemsgno))
865  {
866  flags |= MUTT_FORMAT_FORCESUBJ;
867  break;
868  }
869  else if (tmp->message->vnum >= 0)
870  break;
871  }
872  if (flags & MUTT_FORMAT_FORCESUBJ)
873  {
874  for (tmp = e->thread->prev; tmp; tmp = tmp->prev)
875  {
876  if (!tmp->message)
877  continue;
878 
879  /* ...but if a previous sibling is available, don't force it */
880  if (reverse ? (tmp->message->msgno > edgemsgno) : (tmp->message->msgno < edgemsgno))
881  break;
882  else if (tmp->message->vnum >= 0)
883  {
884  flags &= ~MUTT_FORMAT_FORCESUBJ;
885  break;
886  }
887  }
888  }
889  }
890  }
891 
892  mutt_make_string_flags(buf, buflen, menu->win_index->state.cols,
893  NONULL(C_IndexFormat), Context, Context->mailbox, e, flags);
894 }
895 
900 {
901  if (!Context || !Context->mailbox || (line < 0))
902  return 0;
903 
904  struct Email *e = mutt_get_virt_email(Context->mailbox, line);
905  if (!e)
906  return 0;
907 
908  if (e->pair)
909  return e->pair;
910 
912  return e->pair;
913 }
914 
927 void mutt_draw_statusline(int cols, const char *buf, size_t buflen)
928 {
929  if (!buf)
930  return;
931 
932  size_t i = 0;
933  size_t offset = 0;
934  bool found = false;
935  size_t chunks = 0;
936  size_t len = 0;
937 
938  struct StatusSyntax
939  {
940  int color;
941  int first;
942  int last;
943  } *syntax = NULL;
944 
945  if (!buf || !stdscr)
946  return;
947 
948  do
949  {
950  struct ColorLine *cl = NULL;
951  found = false;
952 
953  if (!buf[offset])
954  break;
955 
956  /* loop through each "color status regex" */
957  STAILQ_FOREACH(cl, &Colors->status_list, entries)
958  {
959  regmatch_t pmatch[cl->match + 1];
960 
961  if (regexec(&cl->regex, buf + offset, cl->match + 1, pmatch, 0) != 0)
962  continue; /* regex doesn't match the status bar */
963 
964  int first = pmatch[cl->match].rm_so + offset;
965  int last = pmatch[cl->match].rm_eo + offset;
966 
967  if (first == last)
968  continue; /* ignore an empty regex */
969 
970  if (!found)
971  {
972  chunks++;
973  mutt_mem_realloc(&syntax, chunks * sizeof(struct StatusSyntax));
974  }
975 
976  i = chunks - 1;
977  if (!found || (first < syntax[i].first) ||
978  ((first == syntax[i].first) && (last > syntax[i].last)))
979  {
980  syntax[i].color = cl->pair;
981  syntax[i].first = first;
982  syntax[i].last = last;
983  }
984  found = true;
985  }
986 
987  if (syntax)
988  {
989  offset = syntax[i].last;
990  }
991  } while (found);
992 
993  /* Only 'len' bytes will fit into 'cols' screen columns */
994  len = mutt_wstr_trunc(buf, buflen, cols, NULL);
995 
996  offset = 0;
997 
998  if ((chunks > 0) && (syntax[0].first > 0))
999  {
1000  /* Text before the first highlight */
1001  mutt_window_addnstr(buf, MIN(len, syntax[0].first));
1002  attrset(Colors->defs[MT_COLOR_STATUS]);
1003  if (len <= syntax[0].first)
1004  goto dsl_finish; /* no more room */
1005 
1006  offset = syntax[0].first;
1007  }
1008 
1009  for (i = 0; i < chunks; i++)
1010  {
1011  /* Highlighted text */
1012  attrset(syntax[i].color);
1013  mutt_window_addnstr(buf + offset, MIN(len, syntax[i].last) - offset);
1014  if (len <= syntax[i].last)
1015  goto dsl_finish; /* no more room */
1016 
1017  size_t next;
1018  if ((i + 1) == chunks)
1019  {
1020  next = len;
1021  }
1022  else
1023  {
1024  next = MIN(len, syntax[i + 1].first);
1025  }
1026 
1027  attrset(Colors->defs[MT_COLOR_STATUS]);
1028  offset = syntax[i].last;
1029  mutt_window_addnstr(buf + offset, next - offset);
1030 
1031  offset = next;
1032  if (offset >= len)
1033  goto dsl_finish; /* no more room */
1034  }
1035 
1036  attrset(Colors->defs[MT_COLOR_STATUS]);
1037  if (offset < len)
1038  {
1039  /* Text after the last highlight */
1040  mutt_window_addnstr(buf + offset, len - offset);
1041  }
1042 
1043  int width = mutt_strwidth(buf);
1044  if (width < cols)
1045  {
1046  /* Pad the rest of the line with whitespace */
1047  mutt_paddstr(cols - width, "");
1048  }
1049 dsl_finish:
1050  FREE(&syntax);
1051 }
1052 
1056 static void index_custom_redraw(struct Menu *menu)
1057 {
1058  if (menu->redraw & REDRAW_FULL)
1059  {
1060  menu_redraw_full(menu);
1061  mutt_show_error();
1062  }
1063 
1064 #ifdef USE_SIDEBAR
1065  if (menu->redraw & REDRAW_SIDEBAR)
1066  menu_redraw_sidebar(menu);
1067 #endif
1068 
1069  if (Context && Context->mailbox && Context->mailbox->emails &&
1070  !(menu->current >= Context->mailbox->vcount))
1071  {
1072  menu_check_recenter(menu);
1073 
1074  if (menu->redraw & REDRAW_INDEX)
1075  {
1076  menu_redraw_index(menu);
1077  menu->redraw |= REDRAW_STATUS;
1078  }
1079  else if (menu->redraw & (REDRAW_MOTION_RESYNC | REDRAW_MOTION))
1080  menu_redraw_motion(menu);
1081  else if (menu->redraw & REDRAW_CURRENT)
1082  menu_redraw_current(menu);
1083  }
1084 
1085  if (menu->redraw & REDRAW_STATUS)
1086  {
1087  char buf[1024];
1088  menu_status_line(buf, sizeof(buf), menu, NONULL(C_StatusFormat));
1089  mutt_window_move(menu->win_ibar, 0, 0);
1091  mutt_draw_statusline(menu->win_ibar->state.cols, buf, sizeof(buf));
1093  menu->redraw &= ~REDRAW_STATUS;
1094  if (C_TsEnabled && TsSupported)
1095  {
1096  menu_status_line(buf, sizeof(buf), menu, NONULL(C_TsStatusFormat));
1097  mutt_ts_status(buf);
1098  menu_status_line(buf, sizeof(buf), menu, NONULL(C_TsIconFormat));
1099  mutt_ts_icon(buf);
1100  }
1101  }
1102 
1103  menu->redraw = REDRAW_NO_FLAGS;
1104 }
1105 
1114 int mutt_index_menu(struct MuttWindow *dlg)
1115 {
1116  char buf[PATH_MAX], helpstr[1024];
1117  OpenMailboxFlags flags;
1118  int op = OP_NULL;
1119  bool done = false; /* controls when to exit the "event" loop */
1120  bool tag = false; /* has the tag-prefix command been pressed? */
1121  int newcount = -1;
1122  int oldcount = -1;
1123  int index_hint = 0; /* used to restore cursor position */
1124  bool do_mailbox_notify = true;
1125  int close = 0; /* did we OP_QUIT or OP_EXIT out of this menu? */
1126  int attach_msg = OptAttachMsg;
1127  bool in_pager = false; /* set when pager redirects a function through the index */
1128 
1129  struct MuttWindow *win_index = mutt_window_find(dlg, WT_INDEX);
1130  struct MuttWindow *win_ibar = mutt_window_find(dlg, WT_INDEX_BAR);
1131  struct MuttWindow *win_pager = mutt_window_find(dlg, WT_PAGER);
1132  struct MuttWindow *win_pbar = mutt_window_find(dlg, WT_PAGER_BAR);
1133 
1134  struct Menu *menu = mutt_menu_new(MENU_MAIN);
1135  menu->pagelen = win_index->state.rows;
1136  menu->win_index = win_index;
1137  menu->win_ibar = win_ibar;
1138 
1140  menu->menu_color = index_color;
1141  menu->current = ci_first_message(Context);
1142  menu->help = mutt_compile_help(
1143  helpstr, sizeof(helpstr), MENU_MAIN,
1144 #ifdef USE_NNTP
1146  IndexNewsHelp :
1147 #endif
1148  IndexHelp);
1150  mutt_menu_push_current(menu);
1151  mutt_window_reflow(NULL);
1152 
1153  if (!attach_msg)
1154  {
1155  /* force the mailbox check after we enter the folder */
1157  }
1158 #ifdef USE_INOTIFY
1159  mutt_monitor_add(NULL);
1160 #endif
1161 
1162  if (((C_Sort & SORT_MASK) == SORT_THREADS) && C_CollapseAll)
1163  {
1164  collapse_all(Context, menu, 0);
1165  menu->redraw = REDRAW_FULL;
1166  }
1167 
1168  while (true)
1169  {
1170  /* Clear the tag prefix unless we just started it. Don't clear
1171  * the prefix on a timeout (op==-2), but do clear on an abort (op==-1) */
1172  if (tag && (op != OP_TAG_PREFIX) && (op != OP_TAG_PREFIX_COND) && (op != -2))
1173  tag = false;
1174 
1175  /* check if we need to resort the index because just about
1176  * any 'op' below could do mutt_enter_command(), either here or
1177  * from any new menu launched, and change $sort/$sort_aux */
1178  if (OptNeedResort && Context && Context->mailbox &&
1179  (Context->mailbox->msg_count != 0) && (menu->current >= 0))
1180  resort_index(Context, menu);
1181 
1182  menu->max = (Context && Context->mailbox) ? Context->mailbox->vcount : 0;
1183  oldcount = (Context && Context->mailbox) ? Context->mailbox->msg_count : 0;
1184 
1185  if (OptRedrawTree && Context && Context->mailbox &&
1186  (Context->mailbox->msg_count != 0) && ((C_Sort & SORT_MASK) == SORT_THREADS))
1187  {
1189  menu->redraw |= REDRAW_STATUS;
1190  OptRedrawTree = false;
1191  }
1192 
1193  if (Context)
1194  Context->menu = menu;
1195 
1196  if (Context && Context->mailbox && !attach_msg)
1197  {
1198  /* check for new mail in the mailbox. If nonzero, then something has
1199  * changed about the file (either we got new mail or the file was
1200  * modified underneath us.) */
1201 
1202  struct Email *e_cur = get_cur_email(Context, menu);
1203  index_hint = e_cur ? e_cur->index : 0;
1204 
1205  int check = mx_mbox_check(Context->mailbox, &index_hint);
1206  if (check < 0)
1207  {
1209  {
1210  /* fatal error occurred */
1211  ctx_free(&Context);
1212  menu->redraw = REDRAW_FULL;
1213  }
1214 
1215  OptSearchInvalid = true;
1216  }
1217  else if ((check == MUTT_NEW_MAIL) || (check == MUTT_REOPENED) || (check == MUTT_FLAGS))
1218  {
1219  /* notify the user of new mail */
1220  if (check == MUTT_REOPENED)
1221  {
1222  mutt_error(
1223  _("Mailbox was externally modified. Flags may be wrong."));
1224  }
1225  else if (check == MUTT_NEW_MAIL)
1226  {
1227  for (size_t i = 0; i < Context->mailbox->msg_count; i++)
1228  {
1229  const struct Email *e = Context->mailbox->emails[i];
1230  if (e && !e->read && !e->old)
1231  {
1232  mutt_message(_("New mail in this mailbox"));
1233  if (C_BeepNew)
1234  mutt_beep(true);
1235  if (C_NewMailCommand)
1236  {
1237  char cmd[1024];
1238  menu_status_line(cmd, sizeof(cmd), menu, NONULL(C_NewMailCommand));
1239  if (mutt_system(cmd) != 0)
1240  mutt_error(_("Error running \"%s\""), cmd);
1241  }
1242  break;
1243  }
1244  }
1245  }
1246  else if (check == MUTT_FLAGS)
1247  mutt_message(_("Mailbox was externally modified"));
1248 
1249  /* avoid the message being overwritten by mailbox */
1250  do_mailbox_notify = false;
1251 
1252  if (Context && Context->mailbox)
1253  {
1254  bool q = Context->mailbox->quiet;
1255  Context->mailbox->quiet = true;
1256  update_index(menu, Context, check, oldcount, index_hint);
1257  Context->mailbox->quiet = q;
1258  menu->max = Context->mailbox->vcount;
1259  }
1260  else
1261  {
1262  menu->max = 0;
1263  }
1264 
1265  menu->redraw = REDRAW_FULL;
1266 
1267  OptSearchInvalid = true;
1268  }
1269  }
1270 
1271  if (!attach_msg)
1272  {
1273  /* check for new mail in the incoming folders */
1274  oldcount = newcount;
1275  newcount = mutt_mailbox_check(Context ? Context->mailbox : NULL, 0);
1276  if (newcount != oldcount)
1277  menu->redraw |= REDRAW_STATUS;
1278  if (do_mailbox_notify)
1279  {
1280  if (mutt_mailbox_notify(Context ? Context->mailbox : NULL))
1281  {
1282  menu->redraw |= REDRAW_STATUS;
1283  if (C_BeepNew)
1284  mutt_beep(true);
1285  if (C_NewMailCommand)
1286  {
1287  char cmd[1024];
1288  menu_status_line(cmd, sizeof(cmd), menu, NONULL(C_NewMailCommand));
1289  if (mutt_system(cmd) != 0)
1290  mutt_error(_("Error running \"%s\""), cmd);
1291  }
1292  }
1293  }
1294  else
1295  do_mailbox_notify = true;
1296  }
1297 
1298  if (op >= 0)
1300 
1301  if (!in_pager)
1302  {
1303  index_custom_redraw(menu);
1304 
1305  /* give visual indication that the next command is a tag- command */
1306  if (tag)
1307  {
1308  mutt_window_mvaddstr(MuttMessageWindow, 0, 0, "tag-");
1310  }
1311 
1312  if (menu->current < menu->max)
1313  menu->oldcurrent = menu->current;
1314  else
1315  menu->oldcurrent = -1;
1316 
1317  if (C_ArrowCursor)
1318  mutt_window_move(menu->win_index, menu->current - menu->top + menu->offset, 2);
1319  else if (C_BrailleFriendly)
1320  mutt_window_move(menu->win_index, menu->current - menu->top + menu->offset, 0);
1321  else
1322  {
1323  mutt_window_move(menu->win_index, menu->current - menu->top + menu->offset,
1324  menu->win_index->state.cols - 1);
1325  }
1326  mutt_refresh();
1327 
1328  if (SigWinch)
1329  {
1330  SigWinch = 0;
1332  menu->top = 0; /* so we scroll the right amount */
1333  /* force a real complete redraw. clrtobot() doesn't seem to be able
1334  * to handle every case without this. */
1335  clearok(stdscr, true);
1336  continue;
1337  }
1338 
1339  op = km_dokey(MENU_MAIN);
1340 
1341  mutt_debug(LL_DEBUG3, "[%d]: Got op %d\n", __LINE__, op);
1342 
1343  /* either user abort or timeout */
1344  if (op < 0)
1345  {
1347  if (tag)
1349  continue;
1350  }
1351 
1353 
1354  /* special handling for the tag-prefix function */
1355  if ((op == OP_TAG_PREFIX) || (op == OP_TAG_PREFIX_COND))
1356  {
1357  /* A second tag-prefix command aborts */
1358  if (tag)
1359  {
1360  tag = false;
1362  continue;
1363  }
1364 
1365  if (!Context || !Context->mailbox)
1366  {
1367  mutt_error(_("No mailbox is open"));
1368  continue;
1369  }
1370 
1371  if (Context->mailbox->msg_tagged == 0)
1372  {
1373  if (op == OP_TAG_PREFIX)
1374  mutt_error(_("No tagged messages"));
1375  else if (op == OP_TAG_PREFIX_COND)
1376  {
1378  mutt_message(_("Nothing to do"));
1379  }
1380  continue;
1381  }
1382 
1383  /* get the real command */
1384  tag = true;
1385  continue;
1386  }
1387  else if (C_AutoTag && Context && Context->mailbox &&
1388  (Context->mailbox->msg_tagged != 0))
1389  tag = true;
1390 
1391  mutt_clear_error();
1392  }
1393  else
1394  {
1395  if (menu->current < menu->max)
1396  menu->oldcurrent = menu->current;
1397  else
1398  menu->oldcurrent = -1;
1399 
1400  mutt_curses_set_cursor(MUTT_CURSOR_VISIBLE); /* fallback from the pager */
1401  }
1402 
1403 #ifdef USE_NNTP
1404  OptNews = false; /* for any case */
1405 #endif
1406 
1407 #ifdef USE_NOTMUCH
1408  if (Context)
1410 #endif
1411 
1412  switch (op)
1413  {
1414  /* ----------------------------------------------------------------------
1415  * movement commands
1416  */
1417 
1418  case OP_BOTTOM_PAGE:
1419  menu_bottom_page(menu);
1420  break;
1421  case OP_CURRENT_BOTTOM:
1422  menu_current_bottom(menu);
1423  break;
1424  case OP_CURRENT_MIDDLE:
1425  menu_current_middle(menu);
1426  break;
1427  case OP_CURRENT_TOP:
1428  menu_current_top(menu);
1429  break;
1430  case OP_FIRST_ENTRY:
1431  menu_first_entry(menu);
1432  break;
1433  case OP_HALF_DOWN:
1434  menu_half_down(menu);
1435  break;
1436  case OP_HALF_UP:
1437  menu_half_up(menu);
1438  break;
1439  case OP_LAST_ENTRY:
1440  menu_last_entry(menu);
1441  break;
1442  case OP_MIDDLE_PAGE:
1443  menu_middle_page(menu);
1444  break;
1445  case OP_NEXT_LINE:
1446  menu_next_line(menu);
1447  break;
1448  case OP_NEXT_PAGE:
1449  menu_next_page(menu);
1450  break;
1451  case OP_PREV_LINE:
1452  menu_prev_line(menu);
1453  break;
1454  case OP_PREV_PAGE:
1455  menu_prev_page(menu);
1456  break;
1457  case OP_TOP_PAGE:
1458  menu_top_page(menu);
1459  break;
1460 
1461 #ifdef USE_NNTP
1462  case OP_GET_PARENT:
1464  break;
1465  /* fallthrough */
1466 
1467  case OP_GET_MESSAGE:
1469  break;
1470  if (Context->mailbox->magic == MUTT_NNTP)
1471  {
1472  if (op == OP_GET_MESSAGE)
1473  {
1474  buf[0] = '\0';
1475  if ((mutt_get_field(_("Enter Message-Id: "), buf, sizeof(buf),
1476  MUTT_COMP_NO_FLAGS) != 0) ||
1477  !buf[0])
1478  {
1479  break;
1480  }
1481  }
1482  else
1483  {
1484  struct Email *e_cur = get_cur_email(Context, menu);
1485  if (!e_cur || STAILQ_EMPTY(&e_cur->env->references))
1486  {
1487  mutt_error(_("Article has no parent reference"));
1488  break;
1489  }
1490  mutt_str_strfcpy(buf, STAILQ_FIRST(&e_cur->env->references)->data, sizeof(buf));
1491  }
1492  if (!Context->mailbox->id_hash)
1494  struct Email *e = mutt_hash_find(Context->mailbox->id_hash, buf);
1495  if (e)
1496  {
1497  if (e->vnum != -1)
1498  {
1499  menu->current = e->vnum;
1500  menu->redraw = REDRAW_MOTION_RESYNC;
1501  }
1502  else if (e->collapsed)
1503  {
1506  menu->current = e->vnum;
1507  menu->redraw = REDRAW_MOTION_RESYNC;
1508  }
1509  else
1510  mutt_error(_("Message is not visible in limited view"));
1511  }
1512  else
1513  {
1514  mutt_message(_("Fetching %s from server..."), buf);
1515  int rc = nntp_check_msgid(Context->mailbox, buf);
1516  if (rc == 0)
1517  {
1519  mutt_sort_headers(Context, false);
1520  menu->current = e->vnum;
1521  menu->redraw = REDRAW_FULL;
1522  }
1523  else if (rc > 0)
1524  mutt_error(_("Article %s not found on the server"), buf);
1525  }
1526  }
1527  break;
1528 
1529  case OP_GET_CHILDREN:
1530  case OP_RECONSTRUCT_THREAD:
1531  {
1532  if (!prereq(Context, menu,
1534  {
1535  break;
1536  }
1537  if (Context->mailbox->magic != MUTT_NNTP)
1538  break;
1539 
1540  struct Email *e_cur = get_cur_email(Context, menu);
1541  if (!e_cur)
1542  break;
1543 
1544  int oldmsgcount = Context->mailbox->msg_count;
1545  int oldindex = e_cur->index;
1546  int rc = 0;
1547 
1548  if (!e_cur->env->message_id)
1549  {
1550  mutt_error(_("No Message-Id. Unable to perform operation."));
1551  break;
1552  }
1553 
1554  mutt_message(_("Fetching message headers..."));
1555  if (!Context->mailbox->id_hash)
1557  mutt_str_strfcpy(buf, e_cur->env->message_id, sizeof(buf));
1558 
1559  /* trying to find msgid of the root message */
1560  if (op == OP_RECONSTRUCT_THREAD)
1561  {
1562  struct ListNode *ref = NULL;
1563  STAILQ_FOREACH(ref, &e_cur->env->references, entries)
1564  {
1565  if (!mutt_hash_find(Context->mailbox->id_hash, ref->data))
1566  {
1567  rc = nntp_check_msgid(Context->mailbox, ref->data);
1568  if (rc < 0)
1569  break;
1570  }
1571 
1572  /* the last msgid in References is the root message */
1573  if (!STAILQ_NEXT(ref, entries))
1574  mutt_str_strfcpy(buf, ref->data, sizeof(buf));
1575  }
1576  }
1577 
1578  /* fetching all child messages */
1579  if (rc >= 0)
1580  rc = nntp_check_children(Context->mailbox, buf);
1581 
1582  /* at least one message has been loaded */
1583  if (Context->mailbox->msg_count > oldmsgcount)
1584  {
1585  struct Email *e_oldcur = get_cur_email(Context, menu);
1586  bool quiet = Context->mailbox->quiet;
1587 
1588  if (rc < 0)
1589  Context->mailbox->quiet = true;
1590  mutt_sort_headers(Context, (op == OP_RECONSTRUCT_THREAD));
1591  Context->mailbox->quiet = quiet;
1592 
1593  /* Similar to OP_MAIN_ENTIRE_THREAD, keep displaying the old message, but
1594  * update the index */
1595  if (in_pager)
1596  {
1597  menu->current = e_oldcur->vnum;
1598  menu->redraw = REDRAW_STATUS | REDRAW_INDEX;
1599  op = OP_DISPLAY_MESSAGE;
1600  continue;
1601  }
1602 
1603  /* if the root message was retrieved, move to it */
1604  struct Email *e = mutt_hash_find(Context->mailbox->id_hash, buf);
1605  if (e)
1606  menu->current = e->vnum;
1607  else
1608  {
1609  /* try to restore old position */
1610  for (int i = 0; i < Context->mailbox->msg_count; i++)
1611  {
1612  e = Context->mailbox->emails[i];
1613  if (!e)
1614  break;
1615  if (e->index == oldindex)
1616  {
1617  menu->current = e->vnum;
1618  /* as an added courtesy, recenter the menu
1619  * with the current entry at the middle of the screen */
1620  menu_check_recenter(menu);
1621  menu_current_middle(menu);
1622  }
1623  }
1624  }
1625  menu->redraw = REDRAW_FULL;
1626  }
1627  else if (rc >= 0)
1628  {
1629  mutt_error(_("No deleted messages found in the thread"));
1630  /* Similar to OP_MAIN_ENTIRE_THREAD, keep displaying the old message, but
1631  * update the index */
1632  if (in_pager)
1633  {
1634  op = OP_DISPLAY_MESSAGE;
1635  continue;
1636  }
1637  }
1638  break;
1639  }
1640 #endif
1641 
1642  case OP_JUMP:
1643  {
1644  int msg_num = 0;
1646  break;
1647  if (isdigit(LastKey))
1649  buf[0] = '\0';
1650  if ((mutt_get_field(_("Jump to message: "), buf, sizeof(buf), MUTT_COMP_NO_FLAGS) != 0) ||
1651  (buf[0] == '\0'))
1652  {
1653  mutt_error(_("Nothing to do"));
1654  }
1655  else if (mutt_str_atoi(buf, &msg_num) < 0)
1656  mutt_error(_("Argument must be a message number"));
1657  else if ((msg_num < 1) || (msg_num > Context->mailbox->msg_count))
1658  mutt_error(_("Invalid message number"));
1659  else if (!message_is_visible(Context, Context->mailbox->emails[msg_num - 1]))
1660  mutt_error(_("That message is not visible"));
1661  else
1662  {
1663  struct Email *e = Context->mailbox->emails[msg_num - 1];
1664 
1665  if (mutt_messages_in_thread(Context->mailbox, e, 1) > 1)
1666  {
1669  }
1670  menu->current = e->vnum;
1671  }
1672 
1673  if (in_pager)
1674  {
1675  op = OP_DISPLAY_MESSAGE;
1676  continue;
1677  }
1678  else
1679  menu->redraw = REDRAW_FULL;
1680 
1681  break;
1682  }
1683 
1684  /* --------------------------------------------------------------------
1685  * 'index' specific commands
1686  */
1687 
1688  case OP_MAIN_DELETE_PATTERN:
1689  if (!prereq(Context, menu,
1691  {
1692  break;
1693  }
1694  /* L10N: CHECK_ACL */
1695  /* L10N: Due to the implementation details we do not know whether we
1696  delete zero, 1, 12, ... messages. So in English we use
1697  "messages". Your language might have other means to express this. */
1698  if (!check_acl(Context, MUTT_ACL_DELETE, _("Can't delete messages")))
1699  break;
1700 
1701  mutt_pattern_func(MUTT_DELETE, _("Delete messages matching: "));
1702  menu->redraw |= REDRAW_INDEX | REDRAW_STATUS;
1703  break;
1704 
1705 #ifdef USE_POP
1706  case OP_MAIN_FETCH_MAIL:
1707  if (!prereq(Context, menu, CHECK_ATTACH))
1708  break;
1709  pop_fetch_mail();
1710  menu->redraw = REDRAW_FULL;
1711  break;
1712 #endif /* USE_POP */
1713 
1714  case OP_SHOW_LOG_MESSAGES:
1715  {
1716  char tempfile[PATH_MAX];
1717  mutt_mktemp(tempfile, sizeof(tempfile));
1718 
1719  FILE *fp = mutt_file_fopen(tempfile, "a+");
1720  if (!fp)
1721  {
1722  mutt_perror("fopen");
1723  break;
1724  }
1725 
1726  log_queue_save(fp);
1727  mutt_file_fclose(&fp);
1728 
1729  mutt_do_pager("messages", tempfile, MUTT_PAGER_LOGS, NULL);
1730  break;
1731  }
1732 
1733  case OP_HELP:
1734  mutt_help(MENU_MAIN, win_index->state.cols);
1735  menu->redraw = REDRAW_FULL;
1736  break;
1737 
1738  case OP_MAIN_SHOW_LIMIT:
1739  if (!prereq(Context, menu, CHECK_IN_MAILBOX))
1740  break;
1741  if (!Context->pattern)
1742  mutt_message(_("No limit pattern is in effect"));
1743  else
1744  {
1745  char buf2[256];
1746  /* L10N: ask for a limit to apply */
1747  snprintf(buf2, sizeof(buf2), _("Limit: %s"), Context->pattern);
1748  mutt_message("%s", buf2);
1749  }
1750  break;
1751 
1752  case OP_LIMIT_CURRENT_THREAD:
1753  case OP_MAIN_LIMIT:
1754  case OP_TOGGLE_READ:
1755  {
1756  if (!prereq(Context, menu, CHECK_IN_MAILBOX))
1757  break;
1758  struct Email *e_cur = get_cur_email(Context, menu);
1759  menu->oldcurrent = e_cur ? e_cur->index : -1;
1760  if (op == OP_TOGGLE_READ)
1761  {
1762  char buf2[1024];
1763 
1764  if (!Context->pattern || (strncmp(Context->pattern, "!~R!~D~s", 8) != 0))
1765  {
1766  snprintf(buf2, sizeof(buf2), "!~R!~D~s%s",
1767  Context->pattern ? Context->pattern : ".*");
1768  }
1769  else
1770  {
1771  mutt_str_strfcpy(buf2, Context->pattern + 8, sizeof(buf2));
1772  if (!*buf2 || (strncmp(buf2, ".*", 2) == 0))
1773  snprintf(buf2, sizeof(buf2), "~A");
1774  }
1775  FREE(&Context->pattern);
1776  Context->pattern = mutt_str_strdup(buf2);
1778  }
1779 
1780  if (((op == OP_LIMIT_CURRENT_THREAD) && mutt_limit_current_thread(e_cur)) ||
1781  (op == OP_TOGGLE_READ) ||
1782  ((op == OP_MAIN_LIMIT) &&
1784  _("Limit to messages matching: ")) == 0)))
1785  {
1786  if (menu->oldcurrent >= 0)
1787  {
1788  /* try to find what used to be the current message */
1789  menu->current = -1;
1790  for (size_t i = 0; i < Context->mailbox->vcount; i++)
1791  {
1792  struct Email *e = mutt_get_virt_email(Context->mailbox, i);
1793  if (!e)
1794  continue;
1795  if (e->index == menu->oldcurrent)
1796  {
1797  menu->current = i;
1798  break;
1799  }
1800  }
1801  if (menu->current < 0)
1802  menu->current = 0;
1803  }
1804  else
1805  menu->current = 0;
1806  if ((Context->mailbox->msg_count != 0) && ((C_Sort & SORT_MASK) == SORT_THREADS))
1807  {
1808  if (C_CollapseAll)
1809  collapse_all(Context, menu, 0);
1811  }
1812  menu->redraw = REDRAW_FULL;
1813  }
1814  if (Context->pattern)
1815  mutt_message(_("To view all messages, limit to \"all\""));
1816  break;
1817  }
1818 
1819  case OP_QUIT:
1820  close = op;
1821  if (attach_msg)
1822  {
1823  done = true;
1824  break;
1825  }
1826 
1827  if (query_quadoption(C_Quit, _("Quit NeoMutt?")) == MUTT_YES)
1828  {
1829  int check;
1830 
1831  oldcount = (Context && Context->mailbox) ? Context->mailbox->msg_count : 0;
1832 
1835 
1836  if (!Context || ((check = mx_mbox_close(&Context)) == 0))
1837  done = true;
1838  else
1839  {
1840  if ((check == MUTT_NEW_MAIL) || (check == MUTT_REOPENED))
1841  update_index(menu, Context, check, oldcount, index_hint);
1842 
1843  menu->redraw = REDRAW_FULL; /* new mail arrived? */
1844  OptSearchInvalid = true;
1845  }
1846  }
1847  break;
1848 
1849  case OP_REDRAW:
1850  mutt_window_reflow(NULL);
1851  clearok(stdscr, true);
1852  menu->redraw = REDRAW_FULL;
1853  break;
1854 
1855  case OP_SEARCH:
1856  case OP_SEARCH_REVERSE:
1857  case OP_SEARCH_NEXT:
1858  case OP_SEARCH_OPPOSITE:
1860  break;
1861  menu->current = mutt_search_command(menu->current, op);
1862  if (menu->current == -1)
1863  menu->current = menu->oldcurrent;
1864  else
1865  menu->redraw = REDRAW_MOTION;
1866  break;
1867 
1868  case OP_SORT:
1869  case OP_SORT_REVERSE:
1870  if (mutt_select_sort((op == OP_SORT_REVERSE)) == 0)
1871  {
1872  if (Context && Context->mailbox && (Context->mailbox->msg_count != 0))
1873  {
1874  resort_index(Context, menu);
1875  OptSearchInvalid = true;
1876  }
1877  if (in_pager)
1878  {
1879  op = OP_DISPLAY_MESSAGE;
1880  continue;
1881  }
1882  menu->redraw |= REDRAW_STATUS;
1883  }
1884  break;
1885 
1886  case OP_TAG:
1887  {
1889  break;
1890  if (tag && !C_AutoTag)
1891  {
1892  struct Mailbox *m = Context->mailbox;
1893  for (size_t i = 0; i < m->msg_count; i++)
1894  {
1895  struct Email *e = m->emails[i];
1896  if (!e)
1897  break;
1898  if (message_is_visible(Context, e))
1899  mutt_set_flag(m, e, MUTT_TAG, false);
1900  }
1901  menu->redraw |= REDRAW_STATUS | REDRAW_INDEX;
1902  }
1903  else
1904  {
1905  struct Email *e_cur = get_cur_email(Context, menu);
1906  if (!e_cur)
1907  break;
1908  mutt_set_flag(Context->mailbox, e_cur, MUTT_TAG, !e_cur->tagged);
1909 
1910  Context->last_tag = e_cur->tagged ?
1911  e_cur :
1912  (((Context->last_tag == e_cur) && !e_cur->tagged) ?
1913  NULL :
1914  Context->last_tag);
1915 
1916  menu->redraw |= REDRAW_STATUS;
1917  if (C_Resolve && (menu->current < Context->mailbox->vcount - 1))
1918  {
1919  menu->current++;
1920  menu->redraw |= REDRAW_MOTION_RESYNC;
1921  }
1922  else
1923  menu->redraw |= REDRAW_CURRENT;
1924  }
1925  break;
1926  }
1927 
1928  case OP_MAIN_TAG_PATTERN:
1930  break;
1931  mutt_pattern_func(MUTT_TAG, _("Tag messages matching: "));
1932  menu->redraw |= REDRAW_INDEX | REDRAW_STATUS;
1933  break;
1934 
1935  case OP_MAIN_UNDELETE_PATTERN:
1937  break;
1938  /* L10N: CHECK_ACL */
1939  /* L10N: Due to the implementation details we do not know whether we
1940  undelete zero, 1, 12, ... messages. So in English we use
1941  "messages". Your language might have other means to express this. */
1942  if (!check_acl(Context, MUTT_ACL_DELETE, _("Can't undelete messages")))
1943  break;
1944 
1946  _("Undelete messages matching: ")) == 0)
1947  {
1948  menu->redraw |= REDRAW_INDEX | REDRAW_STATUS;
1949  }
1950  break;
1951 
1952  case OP_MAIN_UNTAG_PATTERN:
1954  break;
1955  if (mutt_pattern_func(MUTT_UNTAG, _("Untag messages matching: ")) == 0)
1956  menu->redraw |= REDRAW_INDEX | REDRAW_STATUS;
1957  break;
1958 
1959  case OP_COMPOSE_TO_SENDER:
1960  {
1962  break;
1963  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
1964  struct Email *e_cur = get_cur_email(Context, menu);
1965  el_add_tagged(&el, Context, e_cur, tag);
1966  ci_send_message(SEND_TO_SENDER, NULL, NULL, Context, &el);
1967  emaillist_clear(&el);
1968  menu->redraw = REDRAW_FULL;
1969  break;
1970  }
1971 
1972  /* --------------------------------------------------------------------
1973  * The following operations can be performed inside of the pager.
1974  */
1975 
1976 #ifdef USE_IMAP
1977  case OP_MAIN_IMAP_FETCH:
1978  if (Context && Context->mailbox && (Context->mailbox->magic == MUTT_IMAP))
1980  break;
1981 
1982  case OP_MAIN_IMAP_LOGOUT_ALL:
1983  if (Context && Context->mailbox && (Context->mailbox->magic == MUTT_IMAP))
1984  {
1985  int check = mx_mbox_close(&Context);
1986  if (check != 0)
1987  {
1988  if ((check == MUTT_NEW_MAIL) || (check == MUTT_REOPENED))
1989  update_index(menu, Context, check, oldcount, index_hint);
1990  OptSearchInvalid = true;
1991  menu->redraw = REDRAW_FULL;
1992  break;
1993  }
1994  }
1995  imap_logout_all();
1996  mutt_message(_("Logged out of IMAP servers"));
1997  OptSearchInvalid = true;
1998  menu->redraw = REDRAW_FULL;
1999  break;
2000 #endif
2001 
2002  case OP_MAIN_SYNC_FOLDER:
2003  if (!Context || !Context->mailbox || (Context->mailbox->msg_count == 0))
2004  break;
2005 
2007  break;
2008  {
2009  int ovc = Context->mailbox->vcount;
2010  int oc = Context->mailbox->msg_count;
2011  struct Email *e = NULL;
2012 
2013  /* don't attempt to move the cursor if there are no visible messages in the current limit */
2014  if (menu->current < Context->mailbox->vcount)
2015  {
2016  /* threads may be reordered, so figure out what header the cursor
2017  * should be on. */
2018  int newidx = menu->current;
2019  struct Email *e_cur = get_cur_email(Context, menu);
2020  if (!e_cur)
2021  break;
2022  if (e_cur->deleted)
2023  newidx = ci_next_undeleted(Context, menu->current);
2024  if (newidx < 0)
2025  newidx = ci_previous_undeleted(Context, menu->current);
2026  if (newidx >= 0)
2027  e = mutt_get_virt_email(Context->mailbox, newidx);
2028  }
2029 
2030  int check = mx_mbox_sync(Context->mailbox, &index_hint);
2031  if (check == 0)
2032  {
2033  if (e && (Context->mailbox->vcount != ovc))
2034  {
2035  for (size_t i = 0; i < Context->mailbox->vcount; i++)
2036  {
2037  struct Email *e2 = mutt_get_virt_email(Context->mailbox, i);
2038  if (e2 == e)
2039  {
2040  menu->current = i;
2041  break;
2042  }
2043  }
2044  }
2045  OptSearchInvalid = true;
2046  }
2047  else if ((check == MUTT_NEW_MAIL) || (check == MUTT_REOPENED))
2048  update_index(menu, Context, check, oc, index_hint);
2049 
2050  /* do a sanity check even if mx_mbox_sync failed. */
2051 
2052  if ((menu->current < 0) || (Context && Context->mailbox &&
2053  (menu->current >= Context->mailbox->vcount)))
2054  {
2055  menu->current = ci_first_message(Context);
2056  }
2057  }
2058 
2059  /* check for a fatal error, or all messages deleted */
2060  if (Context && Context->mailbox &&
2062  ctx_free(&Context);
2063 
2064  /* if we were in the pager, redisplay the message */
2065  if (in_pager)
2066  {
2067  op = OP_DISPLAY_MESSAGE;
2068  continue;
2069  }
2070  else
2071  menu->redraw = REDRAW_FULL;
2072  break;
2073 
2074  case OP_MAIN_QUASI_DELETE:
2076  break;
2077  if (tag)
2078  {
2079  struct Mailbox *m = Context->mailbox;
2080  for (size_t i = 0; i < m->msg_count; i++)
2081  {
2082  struct Email *e = m->emails[i];
2083  if (!e)
2084  break;
2085  if (message_is_tagged(Context, e))
2086  {
2087  e->quasi_deleted = true;
2088  m->changed = true;
2089  }
2090  }
2091  }
2092  else
2093  {
2094  struct Email *e_cur = get_cur_email(Context, menu);
2095  if (!e_cur)
2096  break;
2097  e_cur->quasi_deleted = true;
2098  Context->mailbox->changed = true;
2099  }
2100  break;
2101 
2102 #ifdef USE_NOTMUCH
2103  case OP_MAIN_ENTIRE_THREAD:
2104  {
2106  break;
2107  struct Email *e_cur = get_cur_email(Context, menu);
2108  if (Context->mailbox->magic != MUTT_NOTMUCH)
2109  {
2111  (!e_cur || !e_cur->env || !e_cur->env->message_id))
2112  {
2113  mutt_message(_("No virtual folder and no Message-Id, aborting"));
2114  break;
2115  } // no virtual folder, but we have message-id, reconstruct thread on-the-fly
2116  strncpy(buf, "id:", sizeof(buf));
2117  int msg_id_offset = 0;
2118  if ((e_cur->env->message_id)[0] == '<')
2119  msg_id_offset = 1;
2120  mutt_str_strcat(buf, sizeof(buf), (e_cur->env->message_id) + msg_id_offset);
2121  if (buf[strlen(buf) - 1] == '>')
2122  buf[strlen(buf) - 1] = '\0';
2123  if (!nm_uri_from_query(Context->mailbox, buf, sizeof(buf)))
2124  {
2125  mutt_message(_("Failed to create query, aborting"));
2126  break;
2127  }
2128 
2129  main_change_folder(menu, op, NULL, buf, sizeof(buf), &oldcount, &index_hint, NULL);
2130 
2131  // If notmuch doesn't contain the message, we're left in an empty
2132  // vfolder. No messages are found, but nm_read_entire_thread assumes
2133  // a valid message-id and will throw a segfault.
2134  //
2135  // To prevent that, stay in the empty vfolder and print an error.
2136  if (Context->mailbox->msg_count == 0)
2137  {
2138  mutt_error(_("failed to find message in notmuch database. try "
2139  "running 'notmuch new'."));
2140  break;
2141  }
2142  }
2143  oldcount = Context->mailbox->msg_count;
2144  struct Email *e_oldcur = e_cur;
2145  if (nm_read_entire_thread(Context->mailbox, e_cur) < 0)
2146  {
2147  mutt_message(_("Failed to read thread, aborting"));
2148  break;
2149  }
2150  if (oldcount < Context->mailbox->msg_count)
2151  {
2152  /* nm_read_entire_thread() triggers mutt_sort_headers() if necessary */
2153  menu->current = e_oldcur->vnum;
2154  menu->redraw = REDRAW_STATUS | REDRAW_INDEX;
2155 
2156  if (e_oldcur->collapsed || Context->collapsed)
2157  {
2158  menu->current = mutt_uncollapse_thread(Context, e_cur);
2160  }
2161  }
2162  if (in_pager)
2163  {
2164  op = OP_DISPLAY_MESSAGE;
2165  continue;
2166  }
2167  break;
2168  }
2169 
2170 #endif
2171  case OP_MAIN_MODIFY_TAGS:
2172  case OP_MAIN_MODIFY_TAGS_THEN_HIDE:
2173  {
2174  if (!Context || !Context->mailbox)
2175  break;
2176  struct Mailbox *m = Context->mailbox;
2177  if (!mx_tags_is_supported(m))
2178  {
2179  mutt_message(_("Folder doesn't support tagging, aborting"));
2180  break;
2181  }
2183  break;
2184  struct Email *e_cur = get_cur_email(Context, menu);
2185  if (!e_cur)
2186  break;
2187  char *tags = NULL;
2188  if (!tag)
2189  tags = driver_tags_get_with_hidden(&e_cur->tags);
2190  int rc = mx_tags_edit(m, tags, buf, sizeof(buf));
2191  FREE(&tags);
2192  if (rc < 0)
2193  break;
2194  else if (rc == 0)
2195  {
2196  mutt_message(_("No tag specified, aborting"));
2197  break;
2198  }
2199 
2200  if (tag)
2201  {
2202  struct Progress progress;
2203 
2204  if (!m->quiet)
2205  {
2206  mutt_progress_init(&progress, _("Update tags..."),
2208  }
2209 
2210 #ifdef USE_NOTMUCH
2211  if (m->magic == MUTT_NOTMUCH)
2212  nm_db_longrun_init(m, true);
2213 #endif
2214  for (int px = 0, i = 0; i < m->msg_count; i++)
2215  {
2216  struct Email *e = m->emails[i];
2217  if (!e)
2218  break;
2219  if (!message_is_tagged(Context, e))
2220  continue;
2221 
2222  if (!m->quiet)
2223  mutt_progress_update(&progress, ++px, -1);
2224  mx_tags_commit(m, e, buf);
2225  if (op == OP_MAIN_MODIFY_TAGS_THEN_HIDE)
2226  {
2227  bool still_queried = false;
2228 #ifdef USE_NOTMUCH
2229  if (m->magic == MUTT_NOTMUCH)
2230  still_queried = nm_message_is_still_queried(m, e);
2231 #endif
2232  e->quasi_deleted = !still_queried;
2233  m->changed = true;
2234  }
2235  }
2236 #ifdef USE_NOTMUCH
2237  if (m->magic == MUTT_NOTMUCH)
2238  nm_db_longrun_done(m);
2239 #endif
2240  menu->redraw = REDRAW_STATUS | REDRAW_INDEX;
2241  }
2242  else
2243  {
2244  if (mx_tags_commit(m, e_cur, buf))
2245  {
2246  mutt_message(_("Failed to modify tags, aborting"));
2247  break;
2248  }
2249  if (op == OP_MAIN_MODIFY_TAGS_THEN_HIDE)
2250  {
2251  bool still_queried = false;
2252 #ifdef USE_NOTMUCH
2253  if (m->magic == MUTT_NOTMUCH)
2254  still_queried = nm_message_is_still_queried(m, e_cur);
2255 #endif
2256  e_cur->quasi_deleted = !still_queried;
2257  m->changed = true;
2258  }
2259  if (in_pager)
2260  {
2261  op = OP_DISPLAY_MESSAGE;
2262  continue;
2263  }
2264  if (C_Resolve)
2265  {
2266  menu->current = ci_next_undeleted(Context, menu->current);
2267  if (menu->current == -1)
2268  {
2269  menu->current = menu->oldcurrent;
2270  menu->redraw = REDRAW_CURRENT;
2271  }
2272  else
2273  menu->redraw = REDRAW_MOTION_RESYNC;
2274  }
2275  else
2276  menu->redraw = REDRAW_CURRENT;
2277  }
2278  menu->redraw |= REDRAW_STATUS;
2279  break;
2280  }
2281 
2282  case OP_CHECK_STATS:
2283  mutt_check_stats();
2284  break;
2285 
2286 #ifdef USE_NOTMUCH
2287  case OP_MAIN_VFOLDER_FROM_QUERY:
2288  case OP_MAIN_VFOLDER_FROM_QUERY_READONLY:
2289  {
2290  buf[0] = '\0';
2291  if ((mutt_get_field("Query: ", buf, sizeof(buf), MUTT_NM_QUERY) != 0) || !buf[0])
2292  {
2293  mutt_message(_("No query, aborting"));
2294  break;
2295  }
2296 
2297  // Keep copy of user's querying to name mailbox.
2298  char *query_unencoded = mutt_str_strdup(buf);
2299 
2300  if (nm_uri_from_query(NULL, buf, sizeof(buf)))
2301  {
2302  // Create mailbox and set name.
2303  struct Mailbox *m_new_vfolder = mx_path_resolve(buf);
2304  m_new_vfolder->name = query_unencoded;
2305  query_unencoded = NULL;
2306 
2307  main_change_folder(menu, op, m_new_vfolder, buf, sizeof(buf),
2308  &oldcount, &index_hint, NULL);
2309  }
2310  else
2311  {
2312  FREE(&query_unencoded);
2313  mutt_message(_("Failed to create query, aborting"));
2314  }
2315 
2316  break;
2317  }
2318  case OP_MAIN_WINDOWED_VFOLDER_BACKWARD:
2319  if (!prereq(Context, menu, CHECK_IN_MAILBOX))
2320  break;
2321  mutt_debug(LL_DEBUG2, "OP_MAIN_WINDOWED_VFOLDER_BACKWARD\n");
2322  if (C_NmQueryWindowDuration <= 0)
2323  {
2324  mutt_message(_("Windowed queries disabled"));
2325  break;
2326  }
2328  {
2329  mutt_message(_("No notmuch vfolder currently loaded"));
2330  break;
2331  }
2334  if (!nm_uri_from_query(Context->mailbox, buf, sizeof(buf)))
2335  mutt_message(_("Failed to create query, aborting"));
2336  else
2337  main_change_folder(menu, op, NULL, buf, sizeof(buf), &oldcount, &index_hint, NULL);
2338  break;
2339 
2340  case OP_MAIN_WINDOWED_VFOLDER_FORWARD:
2341  if (!prereq(Context, menu, CHECK_IN_MAILBOX))
2342  break;
2343  if (C_NmQueryWindowDuration <= 0)
2344  {
2345  mutt_message(_("Windowed queries disabled"));
2346  break;
2347  }
2349  {
2350  mutt_message(_("No notmuch vfolder currently loaded"));
2351  break;
2352  }
2355  if (!nm_uri_from_query(Context->mailbox, buf, sizeof(buf)))
2356  mutt_message(_("Failed to create query, aborting"));
2357  else
2358  {
2359  mutt_debug(LL_DEBUG2, "nm: + windowed query (%s)\n", buf);
2360  main_change_folder(menu, op, NULL, buf, sizeof(buf), &oldcount, &index_hint, NULL);
2361  }
2362  break;
2363 
2364  case OP_MAIN_CHANGE_VFOLDER:
2365 #endif
2366 
2367 #ifdef USE_SIDEBAR
2368  case OP_SIDEBAR_OPEN:
2369 #endif
2370  case OP_MAIN_CHANGE_FOLDER:
2371  case OP_MAIN_NEXT_UNREAD_MAILBOX:
2372  case OP_MAIN_CHANGE_FOLDER_READONLY:
2373 #ifdef USE_NNTP
2374  case OP_MAIN_CHANGE_GROUP:
2375  case OP_MAIN_CHANGE_GROUP_READONLY:
2376 #endif
2377  {
2378  bool pager_return = true; /* return to display message in pager */
2379 
2380  struct Buffer *folderbuf = mutt_buffer_pool_get();
2381  mutt_buffer_alloc(folderbuf, PATH_MAX);
2382  struct Mailbox *m = NULL;
2383  char *cp = NULL;
2384 #ifdef USE_NNTP
2385  OptNews = false;
2386 #endif
2387  if (attach_msg || C_ReadOnly ||
2388 #ifdef USE_NNTP
2389  (op == OP_MAIN_CHANGE_GROUP_READONLY) ||
2390 #endif
2391  (op == OP_MAIN_CHANGE_FOLDER_READONLY))
2392  {
2393  flags = MUTT_READONLY;
2394  }
2395  else
2396  flags = MUTT_OPEN_NO_FLAGS;
2397 
2398  if (flags)
2399  cp = _("Open mailbox in read-only mode");
2400  else
2401  cp = _("Open mailbox");
2402 
2403  if ((op == OP_MAIN_NEXT_UNREAD_MAILBOX) && Context && Context->mailbox &&
2405  {
2407  mutt_buffer_pretty_mailbox(folderbuf);
2408  mutt_mailbox_next_buffer(Context ? Context->mailbox : NULL, folderbuf);
2409  if (mutt_buffer_is_empty(folderbuf))
2410  {
2411  mutt_error(_("No mailboxes have new mail"));
2412  goto changefoldercleanup;
2413  }
2414  }
2415 #ifdef USE_SIDEBAR
2416  else if (op == OP_SIDEBAR_OPEN)
2417  {
2418  m = mutt_sb_get_highlight();
2419  if (!m)
2420  goto changefoldercleanup;
2421  mutt_buffer_strcpy(folderbuf, mailbox_path(m));
2422 
2423  /* Mark the selected dir for the neomutt browser */
2425  }
2426 #endif
2427  else
2428  {
2431  {
2433  mutt_buffer_pretty_mailbox(folderbuf);
2434  }
2435 #ifdef USE_NNTP
2436  if ((op == OP_MAIN_CHANGE_GROUP) || (op == OP_MAIN_CHANGE_GROUP_READONLY))
2437  {
2438  OptNews = true;
2440  C_NewsServer, false);
2441  if (!CurrentNewsSrv)
2442  goto changefoldercleanup;
2443  if (flags)
2444  cp = _("Open newsgroup in read-only mode");
2445  else
2446  cp = _("Open newsgroup");
2447  nntp_mailbox(Context ? Context->mailbox : NULL, folderbuf->data,
2448  folderbuf->dsize);
2449  }
2450  else
2451 #endif
2452  {
2453  /* By default, fill buf with the next mailbox that contains unread
2454  * mail */
2455  mutt_mailbox_next_buffer(Context ? Context->mailbox : NULL, folderbuf);
2456  }
2457 
2458  if (mutt_buffer_enter_fname(cp, folderbuf, true) == -1)
2459  {
2460  goto changefoldercleanup;
2461  }
2462 
2463  /* Selected directory is okay, let's save it. */
2464  mutt_browser_select_dir(mutt_b2s(folderbuf));
2465 
2466  if (mutt_buffer_is_empty(folderbuf))
2467  {
2469  goto changefoldercleanup;
2470  }
2471  }
2472 
2473  if (!m)
2474  m = mx_mbox_find2(mutt_b2s(folderbuf));
2475 
2476  main_change_folder(menu, op, m, folderbuf->data, folderbuf->dsize,
2477  &oldcount, &index_hint, &pager_return);
2478 #ifdef USE_NNTP
2479  /* mutt_mailbox_check() must be done with mail-reader mode! */
2480  menu->help = mutt_compile_help(helpstr, sizeof(helpstr), MENU_MAIN,
2481  (Context && Context->mailbox &&
2482  (Context->mailbox->magic == MUTT_NNTP)) ?
2483  IndexNewsHelp :
2484  IndexHelp);
2485 #endif
2486  mutt_buffer_expand_path(folderbuf);
2487 #ifdef USE_SIDEBAR
2489 #endif
2490  goto changefoldercleanup;
2491 
2492  changefoldercleanup:
2493  mutt_buffer_pool_release(&folderbuf);
2494  if (in_pager && pager_return)
2495  {
2496  op = OP_DISPLAY_MESSAGE;
2497  continue;
2498  }
2499  break;
2500  }
2501 
2502  case OP_DISPLAY_MESSAGE:
2503  case OP_DISPLAY_HEADERS: /* don't weed the headers */
2504  {
2506  break;
2507  struct Email *e_cur = get_cur_email(Context, menu);
2508  if (!e_cur)
2509  break;
2510  /* toggle the weeding of headers so that a user can press the key
2511  * again while reading the message. */
2512  if (op == OP_DISPLAY_HEADERS)
2513  bool_str_toggle(NeoMutt->sub, "weed", NULL);
2514 
2515  OptNeedResort = false;
2516 
2517  if (((C_Sort & SORT_MASK) == SORT_THREADS) && e_cur->collapsed)
2518  {
2521  if (C_UncollapseJump)
2522  menu->current = mutt_thread_next_unread(Context, e_cur);
2523  }
2524 
2525  if (C_PgpAutoDecode && (tag || !(e_cur->security & PGP_TRADITIONAL_CHECKED)))
2526  {
2527  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
2528  el_add_tagged(&el, Context, e_cur, tag);
2529  mutt_check_traditional_pgp(&el, &menu->redraw);
2530  emaillist_clear(&el);
2531  }
2532  e_cur = get_cur_email(Context, menu);
2533  if (!e_cur)
2534  break;
2535  int hint = e_cur->index;
2536 
2537  op = mutt_display_message(win_index, win_ibar, win_pager, win_pbar,
2538  Context->mailbox, e_cur);
2539  if (op < 0)
2540  {
2541  OptNeedResort = false;
2542  break;
2543  }
2544 
2545  /* This is used to redirect a single operation back here afterwards. If
2546  * mutt_display_message() returns 0, then this flag and pager state will
2547  * be cleaned up after this switch statement. */
2548  in_pager = true;
2549  menu->oldcurrent = menu->current;
2550  if (Context && Context->mailbox)
2552  continue;
2553  }
2554 
2555  case OP_EXIT:
2556  close = op;
2557  if ((!in_pager) && attach_msg)
2558  {
2559  done = true;
2560  break;
2561  }
2562 
2563  if ((!in_pager) &&
2564  (query_quadoption(C_Quit, _("Exit NeoMutt without saving?")) == MUTT_YES))
2565  {
2566  if (Context)
2567  {
2569  ctx_free(&Context);
2570  }
2571  done = true;
2572  }
2573  break;
2574 
2575  case OP_MAIN_BREAK_THREAD:
2576  {
2578  break;
2579  /* L10N: CHECK_ACL */
2580  if (!check_acl(Context, MUTT_ACL_WRITE, _("Can't break thread")))
2581  break;
2582  struct Email *e_cur = get_cur_email(Context, menu);
2583  if (!e_cur)
2584  break;
2585 
2586  if ((C_Sort & SORT_MASK) != SORT_THREADS)
2587  mutt_error(_("Threading is not enabled"));
2588  else if (!STAILQ_EMPTY(&e_cur->env->in_reply_to) ||
2589  !STAILQ_EMPTY(&e_cur->env->references))
2590  {
2591  {
2592  struct Email *e_oldcur = e_cur;
2593 
2594  mutt_break_thread(e_cur);
2595  mutt_sort_headers(Context, true);
2596  menu->current = e_oldcur->vnum;
2597  }
2598 
2599  Context->mailbox->changed = true;
2600  mutt_message(_("Thread broken"));
2601 
2602  if (in_pager)
2603  {
2604  op = OP_DISPLAY_MESSAGE;
2605  continue;
2606  }
2607  else
2608  menu->redraw |= REDRAW_INDEX;
2609  }
2610  else
2611  {
2612  mutt_error(
2613  _("Thread can't be broken, message is not part of a thread"));
2614  }
2615  break;
2616  }
2617 
2618  case OP_MAIN_LINK_THREADS:
2619  {
2621  break;
2622  /* L10N: CHECK_ACL */
2623  if (!check_acl(Context, MUTT_ACL_WRITE, _("Can't link threads")))
2624  break;
2625  struct Email *e_cur = get_cur_email(Context, menu);
2626  if (!e_cur)
2627  break;
2628 
2629  if ((C_Sort & SORT_MASK) != SORT_THREADS)
2630  mutt_error(_("Threading is not enabled"));
2631  else if (!e_cur->env->message_id)
2632  mutt_error(_("No Message-ID: header available to link thread"));
2633  else if (!tag && (!Context->last_tag || !Context->last_tag->tagged))
2634  mutt_error(_("First, please tag a message to be linked here"));
2635  else
2636  {
2637  struct Email *e_oldcur = e_cur;
2638  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
2639  el_add_tagged(&el, Context, Context->last_tag, tag);
2640 
2641  if (mutt_link_threads(e_cur, &el, Context->mailbox))
2642  {
2643  mutt_sort_headers(Context, true);
2644  menu->current = e_oldcur->vnum;
2645 
2646  Context->mailbox->changed = true;
2647  mutt_message(_("Threads linked"));
2648  }
2649  else
2650  mutt_error(_("No thread linked"));
2651 
2652  emaillist_clear(&el);
2653  }
2654 
2655  if (in_pager)
2656  {
2657  op = OP_DISPLAY_MESSAGE;
2658  continue;
2659  }
2660  else
2661  menu->redraw |= REDRAW_STATUS | REDRAW_INDEX;
2662 
2663  break;
2664  }
2665 
2666  case OP_EDIT_TYPE:
2667  {
2669  break;
2670  struct Email *e_cur = get_cur_email(Context, menu);
2671  if (!e_cur)
2672  break;
2673  mutt_edit_content_type(e_cur, e_cur->content, NULL);
2674  /* if we were in the pager, redisplay the message */
2675  if (in_pager)
2676  {
2677  op = OP_DISPLAY_MESSAGE;
2678  continue;
2679  }
2680  else
2681  menu->redraw = REDRAW_CURRENT;
2682  break;
2683  }
2684 
2685  case OP_MAIN_NEXT_UNDELETED:
2687  break;
2688  if (menu->current >= (Context->mailbox->vcount - 1))
2689  {
2690  if (!in_pager)
2691  mutt_message(_("You are on the last message"));
2692  break;
2693  }
2694  menu->current = ci_next_undeleted(Context, menu->current);
2695  if (menu->current == -1)
2696  {
2697  menu->current = menu->oldcurrent;
2698  if (!in_pager)
2699  mutt_error(_("No undeleted messages"));
2700  }
2701  else if (in_pager)
2702  {
2703  op = OP_DISPLAY_MESSAGE;
2704  continue;
2705  }
2706  else
2707  menu->redraw = REDRAW_MOTION;
2708  break;
2709 
2710  case OP_NEXT_ENTRY:
2712  break;
2713  if (menu->current >= (Context->mailbox->vcount - 1))
2714  {
2715  if (!in_pager)
2716  mutt_message(_("You are on the last message"));
2717  break;
2718  }
2719  menu->current++;
2720  if (in_pager)
2721  {
2722  op = OP_DISPLAY_MESSAGE;
2723  continue;
2724  }
2725  else
2726  menu->redraw = REDRAW_MOTION;
2727  break;
2728 
2729  case OP_MAIN_PREV_UNDELETED:
2731  break;
2732  if (menu->current < 1)
2733  {
2734  mutt_message(_("You are on the first message"));
2735  break;
2736  }
2737  menu->current = ci_previous_undeleted(Context, menu->current);
2738  if (menu->current == -1)
2739  {
2740  menu->current = menu->oldcurrent;
2741  if (!in_pager)
2742  mutt_error(_("No undeleted messages"));
2743  }
2744  else if (in_pager)
2745  {
2746  op = OP_DISPLAY_MESSAGE;
2747  continue;
2748  }
2749  else
2750  menu->redraw = REDRAW_MOTION;
2751  break;
2752 
2753  case OP_PREV_ENTRY:
2755  break;
2756  if (menu->current < 1)
2757  {
2758  if (!in_pager)
2759  mutt_message(_("You are on the first message"));
2760  break;
2761  }
2762  menu->current--;
2763  if (in_pager)
2764  {
2765  op = OP_DISPLAY_MESSAGE;
2766  continue;
2767  }
2768  else
2769  menu->redraw = REDRAW_MOTION;
2770  break;
2771 
2772  case OP_DECRYPT_COPY:
2773  case OP_DECRYPT_SAVE:
2774  if (!WithCrypto)
2775  break;
2776  /* fallthrough */
2777  case OP_COPY_MESSAGE:
2778  case OP_SAVE:
2779  case OP_DECODE_COPY:
2780  case OP_DECODE_SAVE:
2781  {
2783  break;
2784  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
2785  struct Email *e_cur = get_cur_email(Context, menu);
2786  el_add_tagged(&el, Context, e_cur, tag);
2787 
2788  const bool delete_original =
2789  (op == OP_SAVE) || (op == OP_DECODE_SAVE) || (op == OP_DECRYPT_SAVE);
2790  const bool decode = (op == OP_DECODE_SAVE) || (op == OP_DECODE_COPY);
2791  const bool decrypt = (op == OP_DECRYPT_SAVE) || (op == OP_DECRYPT_COPY);
2792 
2793  if ((mutt_save_message(Context->mailbox, &el, delete_original, decode, decrypt) == 0) &&
2794  delete_original)
2795  {
2796  menu->redraw |= REDRAW_STATUS;
2797  if (tag)
2798  menu->redraw |= REDRAW_INDEX;
2799  else if (C_Resolve)
2800  {
2801  menu->current = ci_next_undeleted(Context, menu->current);
2802  if (menu->current == -1)
2803  {
2804  menu->current = menu->oldcurrent;
2805  menu->redraw |= REDRAW_CURRENT;
2806  }
2807  else
2808  menu->redraw |= REDRAW_MOTION_RESYNC;
2809  }
2810  else
2811  menu->redraw |= REDRAW_CURRENT;
2812  }
2813  emaillist_clear(&el);
2814  break;
2815  }
2816 
2817  case OP_MAIN_NEXT_NEW:
2818  case OP_MAIN_NEXT_UNREAD:
2819  case OP_MAIN_PREV_NEW:
2820  case OP_MAIN_PREV_UNREAD:
2821  case OP_MAIN_NEXT_NEW_THEN_UNREAD:
2822  case OP_MAIN_PREV_NEW_THEN_UNREAD:
2823  {
2825  break;
2826 
2827  int first_unread = -1;
2828  int first_new = -1;
2829 
2830  const int saved_current = menu->current;
2831  int cur = menu->current;
2832  menu->current = -1;
2833  for (size_t i = 0; i != Context->mailbox->vcount; i++)
2834  {
2835  if ((op == OP_MAIN_NEXT_NEW) || (op == OP_MAIN_NEXT_UNREAD) ||
2836  (op == OP_MAIN_NEXT_NEW_THEN_UNREAD))
2837  {
2838  cur++;
2839  if (cur > (Context->mailbox->vcount - 1))
2840  {
2841  cur = 0;
2842  }
2843  }
2844  else
2845  {
2846  cur--;
2847  if (cur < 0)
2848  {
2849  cur = Context->mailbox->vcount - 1;
2850  }
2851  }
2852 
2853  struct Email *e = mutt_get_virt_email(Context->mailbox, cur);
2854  if (!e)
2855  break;
2856  if (e->collapsed && ((C_Sort & SORT_MASK) == SORT_THREADS))
2857  {
2858  if ((UNREAD(e) != 0) && (first_unread == -1))
2859  first_unread = cur;
2860  if ((UNREAD(e) == 1) && (first_new == -1))
2861  first_new = cur;
2862  }
2863  else if (!e->deleted && !e->read)
2864  {
2865  if (first_unread == -1)
2866  first_unread = cur;
2867  if (!e->old && (first_new == -1))
2868  first_new = cur;
2869  }
2870 
2871  if (((op == OP_MAIN_NEXT_UNREAD) || (op == OP_MAIN_PREV_UNREAD)) &&
2872  (first_unread != -1))
2873  break;
2874  if (((op == OP_MAIN_NEXT_NEW) || (op == OP_MAIN_PREV_NEW) ||
2875  (op == OP_MAIN_NEXT_NEW_THEN_UNREAD) || (op == OP_MAIN_PREV_NEW_THEN_UNREAD)) &&
2876  (first_new != -1))
2877  {
2878  break;
2879  }
2880  }
2881  if (((op == OP_MAIN_NEXT_NEW) || (op == OP_MAIN_PREV_NEW) ||
2882  (op == OP_MAIN_NEXT_NEW_THEN_UNREAD) || (op == OP_MAIN_PREV_NEW_THEN_UNREAD)) &&
2883  (first_new != -1))
2884  {
2885  menu->current = first_new;
2886  }
2887  else if (((op == OP_MAIN_NEXT_UNREAD) || (op == OP_MAIN_PREV_UNREAD) ||
2888  (op == OP_MAIN_NEXT_NEW_THEN_UNREAD) || (op == OP_MAIN_PREV_NEW_THEN_UNREAD)) &&
2889  (first_unread != -1))
2890  {
2891  menu->current = first_unread;
2892  }
2893 
2894  if (menu->current == -1)
2895  {
2896  menu->current = menu->oldcurrent;
2897  if ((op == OP_MAIN_NEXT_NEW) || (op == OP_MAIN_PREV_NEW))
2898  {
2899  if (Context->pattern)
2900  mutt_error(_("No new messages in this limited view"));
2901  else
2902  mutt_error(_("No new messages"));
2903  }
2904  else
2905  {
2906  if (Context->pattern)
2907  mutt_error(_("No unread messages in this limited view"));
2908  else
2909  mutt_error(_("No unread messages"));
2910  }
2911  break;
2912  }
2913 
2914  if ((op == OP_MAIN_NEXT_NEW) || (op == OP_MAIN_NEXT_UNREAD) ||
2915  (op == OP_MAIN_NEXT_NEW_THEN_UNREAD))
2916  {
2917  if (saved_current > menu->current)
2918  {
2919  mutt_message(_("Search wrapped to top"));
2920  }
2921  }
2922  else if (saved_current < menu->current)
2923  {
2924  mutt_message(_("Search wrapped to bottom"));
2925  }
2926 
2927  if (in_pager)
2928  {
2929  op = OP_DISPLAY_MESSAGE;
2930  continue;
2931  }
2932  else
2933  menu->redraw = REDRAW_MOTION;
2934  break;
2935  }
2936  case OP_FLAG_MESSAGE:
2937  {
2939  break;
2940  /* L10N: CHECK_ACL */
2941  if (!check_acl(Context, MUTT_ACL_WRITE, _("Can't flag message")))
2942  break;
2943 
2944  struct Mailbox *m = Context->mailbox;
2945  if (tag)
2946  {
2947  for (size_t i = 0; i < m->msg_count; i++)
2948  {
2949  struct Email *e = m->emails[i];
2950  if (!e)
2951  break;
2952  if (message_is_tagged(Context, e))
2953  mutt_set_flag(m, e, MUTT_FLAG, !e->flagged);
2954  }
2955 
2956  menu->redraw |= REDRAW_INDEX;
2957  }
2958  else
2959  {
2960  struct Email *e_cur = get_cur_email(Context, menu);
2961  if (!e_cur)
2962  break;
2963  mutt_set_flag(m, e_cur, MUTT_FLAG, !e_cur->flagged);
2964  if (C_Resolve)
2965  {
2966  menu->current = ci_next_undeleted(Context, menu->current);
2967  if (menu->current == -1)
2968  {
2969  menu->current = menu->oldcurrent;
2970  menu->redraw |= REDRAW_CURRENT;
2971  }
2972  else
2973  menu->redraw |= REDRAW_MOTION_RESYNC;
2974  }
2975  else
2976  menu->redraw |= REDRAW_CURRENT;
2977  }
2978  menu->redraw |= REDRAW_STATUS;
2979  break;
2980  }
2981 
2982  case OP_TOGGLE_NEW:
2983  {
2985  break;
2986  /* L10N: CHECK_ACL */
2987  if (!check_acl(Context, MUTT_ACL_SEEN, _("Can't toggle new")))
2988  break;
2989 
2990  struct Mailbox *m = Context->mailbox;
2991  if (tag)
2992  {
2993  for (size_t i = 0; i < m->msg_count; i++)
2994  {
2995  struct Email *e = m->emails[i];
2996  if (!e)
2997  break;
2998  if (!message_is_tagged(Context, e))
2999  continue;
3000 
3001  if (e->read || e->old)
3002  mutt_set_flag(m, e, MUTT_NEW, true);
3003  else
3004  mutt_set_flag(m, e, MUTT_READ, true);
3005  }
3006  menu->redraw |= REDRAW_STATUS | REDRAW_INDEX;
3007  }
3008  else
3009  {
3010  struct Email *e_cur = get_cur_email(Context, menu);
3011  if (!e_cur)
3012  break;
3013  if (e_cur->read || e_cur->old)
3014  mutt_set_flag(m, e_cur, MUTT_NEW, true);
3015  else
3016  mutt_set_flag(m, e_cur, MUTT_READ, true);
3017 
3018  if (C_Resolve)
3019  {
3020  menu->current = ci_next_undeleted(Context, menu->current);
3021  if (menu->current == -1)
3022  {
3023  menu->current = menu->oldcurrent;
3024  menu->redraw |= REDRAW_CURRENT;
3025  }
3026  else
3027  menu->redraw |= REDRAW_MOTION_RESYNC;
3028  }
3029  else
3030  menu->redraw |= REDRAW_CURRENT;
3031  menu->redraw |= REDRAW_STATUS;
3032  }
3033  break;
3034  }
3035 
3036  case OP_TOGGLE_WRITE:
3037  if (!prereq(Context, menu, CHECK_IN_MAILBOX))
3038  break;
3039  if (mx_toggle_write(Context->mailbox) == 0)
3040  {
3041  if (in_pager)
3042  {
3043  op = OP_DISPLAY_MESSAGE;
3044  continue;
3045  }
3046  else
3047  menu->redraw |= REDRAW_STATUS;
3048  }
3049  break;
3050 
3051  case OP_MAIN_NEXT_THREAD:
3052  case OP_MAIN_NEXT_SUBTHREAD:
3053  case OP_MAIN_PREV_THREAD:
3054  case OP_MAIN_PREV_SUBTHREAD:
3055  {
3057  break;
3058 
3059  struct Email *e_cur = get_cur_email(Context, menu);
3060  switch (op)
3061  {
3062  case OP_MAIN_NEXT_THREAD:
3063  menu->current = mutt_next_thread(e_cur);
3064  break;
3065 
3066  case OP_MAIN_NEXT_SUBTHREAD:
3067  menu->current = mutt_next_subthread(e_cur);
3068  break;
3069 
3070  case OP_MAIN_PREV_THREAD:
3071  menu->current = mutt_previous_thread(e_cur);
3072  break;
3073 
3074  case OP_MAIN_PREV_SUBTHREAD:
3075  menu->current = mutt_previous_subthread(e_cur);
3076  break;
3077  }
3078 
3079  if (menu->current < 0)
3080  {
3081  menu->current = menu->oldcurrent;
3082  if ((op == OP_MAIN_NEXT_THREAD) || (op == OP_MAIN_NEXT_SUBTHREAD))
3083  mutt_error(_("No more threads"));
3084  else
3085  mutt_error(_("You are on the first thread"));
3086  }
3087  else if (in_pager)
3088  {
3089  op = OP_DISPLAY_MESSAGE;
3090  continue;
3091  }
3092  else
3093  menu->redraw = REDRAW_MOTION;
3094  break;
3095  }
3096 
3097  case OP_MAIN_ROOT_MESSAGE:
3098  case OP_MAIN_PARENT_MESSAGE:
3099  {
3101  break;
3102 
3103  struct Email *e_cur = get_cur_email(Context, menu);
3104  menu->current = mutt_parent_message(Context, e_cur, op == OP_MAIN_ROOT_MESSAGE);
3105  if (menu->current < 0)
3106  {
3107  menu->current = menu->oldcurrent;
3108  }
3109  else if (in_pager)
3110  {
3111  op = OP_DISPLAY_MESSAGE;
3112  continue;
3113  }
3114  else
3115  menu->redraw = REDRAW_MOTION;
3116  break;
3117  }
3118 
3119  case OP_MAIN_SET_FLAG:
3120  case OP_MAIN_CLEAR_FLAG:
3121  {
3123  break;
3124  /* check_acl(MUTT_ACL_WRITE); */
3125 
3126  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3127  struct Email *e_cur = get_cur_email(Context, menu);
3128  el_add_tagged(&el, Context, e_cur, tag);
3129 
3130  if (mutt_change_flag(Context->mailbox, &el, (op == OP_MAIN_SET_FLAG)) == 0)
3131  {
3132  menu->redraw |= REDRAW_STATUS;
3133  if (tag)
3134  menu->redraw |= REDRAW_INDEX;
3135  else if (C_Resolve)
3136  {
3137  menu->current = ci_next_undeleted(Context, menu->current);
3138  if (menu->current == -1)
3139  {
3140  menu->current = menu->oldcurrent;
3141  menu->redraw |= REDRAW_CURRENT;
3142  }
3143  else
3144  menu->redraw |= REDRAW_MOTION_RESYNC;
3145  }
3146  else
3147  menu->redraw |= REDRAW_CURRENT;
3148  }
3149  emaillist_clear(&el);
3150  break;
3151  }
3152 
3153  case OP_MAIN_COLLAPSE_THREAD:
3154  {
3156  break;
3157 
3158  if ((C_Sort & SORT_MASK) != SORT_THREADS)
3159  {
3160  mutt_error(_("Threading is not enabled"));
3161  break;
3162  }
3163 
3164  struct Email *e_cur = get_cur_email(Context, menu);
3165  if (!e_cur)
3166  break;
3167 
3168  if (e_cur->collapsed)
3169  {
3170  menu->current = mutt_uncollapse_thread(Context, e_cur);
3172  if (C_UncollapseJump)
3173  menu->current = mutt_thread_next_unread(Context, e_cur);
3174  }
3175  else if (CAN_COLLAPSE(e_cur))
3176  {
3177  menu->current = mutt_collapse_thread(Context, e_cur);
3179  }
3180  else
3181  {
3182  mutt_error(_("Thread contains unread or flagged messages"));
3183  break;
3184  }
3185 
3186  menu->redraw = REDRAW_INDEX | REDRAW_STATUS;
3187 
3188  break;
3189  }
3190 
3191  case OP_MAIN_COLLAPSE_ALL:
3193  break;
3194 
3195  if ((C_Sort & SORT_MASK) != SORT_THREADS)
3196  {
3197  mutt_error(_("Threading is not enabled"));
3198  break;
3199  }
3200  collapse_all(Context, menu, 1);
3201  break;
3202 
3203  /* --------------------------------------------------------------------
3204  * These functions are invoked directly from the internal-pager
3205  */
3206 
3207  case OP_BOUNCE_MESSAGE:
3208  {
3210  break;
3211  struct Email *e_cur = get_cur_email(Context, menu);
3212 
3213  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3214  el_add_tagged(&el, Context, e_cur, tag);
3216  emaillist_clear(&el);
3217  break;
3218  }
3219 
3220  case OP_CREATE_ALIAS:
3221  {
3222  struct Email *e_cur = get_cur_email(Context, menu);
3223 
3224  mutt_alias_create(e_cur ? e_cur->env : NULL, NULL);
3225  menu->redraw |= REDRAW_CURRENT;
3226  break;
3227  }
3228 
3229  case OP_QUERY:
3230  if (!prereq(Context, menu, CHECK_ATTACH))
3231  break;
3232  mutt_query_menu(NULL, 0);
3233  break;
3234 
3235  case OP_PURGE_MESSAGE:
3236  case OP_DELETE:
3237  {
3239  break;
3240  /* L10N: CHECK_ACL */
3241  if (!check_acl(Context, MUTT_ACL_DELETE, _("Can't delete message")))
3242  break;
3243 
3244  struct Email *e_cur = get_cur_email(Context, menu);
3245  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3246  el_add_tagged(&el, Context, e_cur, tag);
3247 
3249  mutt_emails_set_flag(Context->mailbox, &el, MUTT_PURGE, (op == OP_PURGE_MESSAGE));
3250  if (C_DeleteUntag)
3252  emaillist_clear(&el);
3253 
3254  if (tag)
3255  {
3256  menu->redraw |= REDRAW_INDEX;
3257  }
3258  else
3259  {
3260  if (C_Resolve)
3261  {
3262  menu->current = ci_next_undeleted(Context, menu->current);
3263  if (menu->current == -1)
3264  {
3265  menu->current = menu->oldcurrent;
3266  menu->redraw |= REDRAW_CURRENT;
3267  }
3268  else if (in_pager)
3269  {
3270  op = OP_DISPLAY_MESSAGE;
3271  continue;
3272  }
3273  else
3274  menu->redraw |= REDRAW_MOTION_RESYNC;
3275  }
3276  else
3277  menu->redraw |= REDRAW_CURRENT;
3278  }
3279  menu->redraw |= REDRAW_STATUS;
3280  break;
3281  }
3282 
3283  case OP_DELETE_THREAD:
3284  case OP_DELETE_SUBTHREAD:
3285  case OP_PURGE_THREAD:
3286  {
3288  break;
3289  /* L10N: CHECK_ACL */
3290  /* L10N: Due to the implementation details we do not know whether we
3291  delete zero, 1, 12, ... messages. So in English we use
3292  "messages". Your language might have other means to express this. */
3293  if (!check_acl(Context, MUTT_ACL_DELETE, _("Can't delete messages")))
3294  break;
3295  struct Email *e_cur = get_cur_email(Context, menu);
3296  if (!e_cur)
3297  break;
3298 
3299  int subthread = (op == OP_DELETE_SUBTHREAD);
3300  int rc = mutt_thread_set_flag(e_cur, MUTT_DELETE, true, subthread);
3301  if (rc == -1)
3302  break;
3303  if (op == OP_PURGE_THREAD)
3304  {
3305  rc = mutt_thread_set_flag(e_cur, MUTT_PURGE, true, subthread);
3306  if (rc == -1)
3307  break;
3308  }
3309 
3310  if (C_DeleteUntag)
3311  mutt_thread_set_flag(e_cur, MUTT_TAG, false, subthread);
3312  if (C_Resolve)
3313  {
3314  menu->current = ci_next_undeleted(Context, menu->current);
3315  if (menu->current == -1)
3316  menu->current = menu->oldcurrent;
3317  }
3318  menu->redraw |= REDRAW_INDEX | REDRAW_STATUS;
3319  break;
3320  }
3321 
3322 #ifdef USE_NNTP
3323  case OP_CATCHUP:
3325  break;
3326  if (Context && (Context->mailbox->magic == MUTT_NNTP))
3327  {
3328  struct NntpMboxData *mdata = Context->mailbox->mdata;
3329  if (mutt_newsgroup_catchup(Context->mailbox, mdata->adata, mdata->group))
3330  menu->redraw = REDRAW_INDEX | REDRAW_STATUS;
3331  }
3332  break;
3333 #endif
3334 
3335  case OP_DISPLAY_ADDRESS:
3336  {
3338  break;
3339  struct Email *e_cur = get_cur_email(Context, menu);
3340  if (!e_cur)
3341  break;
3342  mutt_display_address(e_cur->env);
3343  break;
3344  }
3345 
3346  case OP_ENTER_COMMAND:
3348  if (Context)
3350  break;
3351 
3352  case OP_EDIT_OR_VIEW_RAW_MESSAGE:
3353  case OP_EDIT_RAW_MESSAGE:
3354  case OP_VIEW_RAW_MESSAGE:
3355  {
3356  /* TODO split this into 3 cases? */
3358  break;
3359  bool edit;
3360  if (op == OP_EDIT_RAW_MESSAGE)
3361  {
3362  if (!prereq(Context, menu, CHECK_READONLY))
3363  break;
3364  /* L10N: CHECK_ACL */
3365  if (!check_acl(Context, MUTT_ACL_INSERT, _("Can't edit message")))
3366  break;
3367  edit = true;
3368  }
3369  else if (op == OP_EDIT_OR_VIEW_RAW_MESSAGE)
3371  else
3372  edit = false;
3373 
3374  struct Email *e_cur = get_cur_email(Context, menu);
3375  if (!e_cur)
3376  break;
3377  if (C_PgpAutoDecode && (tag || !(e_cur->security & PGP_TRADITIONAL_CHECKED)))
3378  {
3379  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3380  el_add_tagged(&el, Context, e_cur, tag);
3381  mutt_check_traditional_pgp(&el, &menu->redraw);
3382  emaillist_clear(&el);
3383  }
3384  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3385  el_add_tagged(&el, Context, e_cur, tag);
3386  mutt_ev_message(Context->mailbox, &el, edit ? EVM_EDIT : EVM_VIEW);
3387  emaillist_clear(&el);
3388  menu->redraw = REDRAW_FULL;
3389 
3390  break;
3391  }
3392 
3393  case OP_FORWARD_MESSAGE:
3394  {
3396  break;
3397  struct Email *e_cur = get_cur_email(Context, menu);
3398  if (!e_cur)
3399  break;
3400  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3401  el_add_tagged(&el, Context, e_cur, tag);
3402  if (C_PgpAutoDecode && (tag || !(e_cur->security & PGP_TRADITIONAL_CHECKED)))
3403  {
3404  mutt_check_traditional_pgp(&el, &menu->redraw);
3405  }
3406  ci_send_message(SEND_FORWARD, NULL, NULL, Context, &el);
3407  emaillist_clear(&el);
3408  menu->redraw = REDRAW_FULL;
3409  break;
3410  }
3411 
3412  case OP_FORGET_PASSPHRASE:
3414  break;
3415 
3416  case OP_GROUP_REPLY:
3417  case OP_GROUP_CHAT_REPLY:
3418  {
3419  SendFlags replyflags = SEND_REPLY;
3420  if (op == OP_GROUP_REPLY)
3421  replyflags |= SEND_GROUP_REPLY;
3422  else
3423  replyflags |= SEND_GROUP_CHAT_REPLY;
3425  break;
3426  struct Email *e_cur = get_cur_email(Context, menu);
3427  if (!e_cur)
3428  break;
3429  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3430  el_add_tagged(&el, Context, e_cur, tag);
3431  if (C_PgpAutoDecode && (tag || !(e_cur->security & PGP_TRADITIONAL_CHECKED)))
3432  {
3433  mutt_check_traditional_pgp(&el, &menu->redraw);
3434  }
3435  ci_send_message(replyflags, NULL, NULL, Context, &el);
3436  emaillist_clear(&el);
3437  menu->redraw = REDRAW_FULL;
3438  break;
3439  }
3440 
3441  case OP_EDIT_LABEL:
3442  {
3444  break;
3445 
3446  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3447  struct Email *e_cur = get_cur_email(Context, menu);
3448  el_add_tagged(&el, Context, e_cur, tag);
3449  int num_changed = mutt_label_message(Context->mailbox, &el);
3450  emaillist_clear(&el);
3451 
3452  if (num_changed > 0)
3453  {
3454  Context->mailbox->changed = true;
3455  menu->redraw = REDRAW_FULL;
3456  /* L10N: This is displayed when the x-label on one or more
3457  messages is edited. */
3458  mutt_message(ngettext("%d label changed", "%d labels changed", num_changed),
3459  num_changed);
3460  }
3461  else
3462  {
3463  /* L10N: This is displayed when editing an x-label, but no messages
3464  were updated. Possibly due to canceling at the prompt or if the new
3465  label is the same as the old label. */
3466  mutt_message(_("No labels changed"));
3467  }
3468  break;
3469  }
3470 
3471  case OP_LIST_REPLY:
3472  {
3474  break;
3475  struct Email *e_cur = get_cur_email(Context, menu);
3476  if (!e_cur)
3477  break;
3478  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3479  el_add_tagged(&el, Context, e_cur, tag);
3480  if (C_PgpAutoDecode && (tag || !(e_cur->security & PGP_TRADITIONAL_CHECKED)))
3481  {
3482  mutt_check_traditional_pgp(&el, &menu->redraw);
3483  }
3484  ci_send_message(SEND_REPLY | SEND_LIST_REPLY, NULL, NULL, Context, &el);
3485  emaillist_clear(&el);
3486  menu->redraw = REDRAW_FULL;
3487  break;
3488  }
3489 
3490  case OP_MAIL:
3491  if (!prereq(Context, menu, CHECK_ATTACH))
3492  break;
3493  ci_send_message(SEND_NO_FLAGS, NULL, NULL, Context, NULL);
3494  menu->redraw = REDRAW_FULL;
3495  break;
3496 
3497  case OP_MAIL_KEY:
3498  if (!(WithCrypto & APPLICATION_PGP))
3499  break;
3500  if (!prereq(Context, menu, CHECK_ATTACH))
3501  break;
3502  ci_send_message(SEND_KEY, NULL, NULL, NULL, NULL);
3503  menu->redraw = REDRAW_FULL;
3504  break;
3505 
3506  case OP_EXTRACT_KEYS:
3507  {
3508  if (!WithCrypto)
3509  break;
3511  break;
3512  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3513  struct Email *e_cur = get_cur_email(Context, menu);
3514  el_add_tagged(&el, Context, e_cur, tag);
3516  emaillist_clear(&el);
3517  menu->redraw = REDRAW_FULL;
3518  break;
3519  }
3520 
3521  case OP_CHECK_TRADITIONAL:
3522  {
3523  if (!(WithCrypto & APPLICATION_PGP))
3524  break;
3526  break;
3527  struct Email *e_cur = get_cur_email(Context, menu);
3528  if (!e_cur)
3529  break;
3530  if (tag || !(e_cur->security & PGP_TRADITIONAL_CHECKED))
3531  {
3532  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3533  el_add_tagged(&el, Context, e_cur, tag);
3534  mutt_check_traditional_pgp(&el, &menu->redraw);
3535  emaillist_clear(&el);
3536  }
3537 
3538  if (in_pager)
3539  {
3540  op = OP_DISPLAY_MESSAGE;
3541  continue;
3542  }
3543  break;
3544  }
3545 
3546  case OP_PIPE:
3547  {
3549  break;
3550  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3551  struct Email *e_cur = get_cur_email(Context, menu);
3552  el_add_tagged(&el, Context, e_cur, tag);
3554  emaillist_clear(&el);
3555 
3556 #ifdef USE_IMAP
3557  /* in an IMAP folder index with imap_peek=no, piping could change
3558  * new or old messages status to read. Redraw what's needed. */
3559  if ((Context->mailbox->magic == MUTT_IMAP) && !C_ImapPeek)
3560  {
3561  menu->redraw |= (tag ? REDRAW_INDEX : REDRAW_CURRENT) | REDRAW_STATUS;
3562  }
3563 #endif
3564  break;
3565  }
3566 
3567  case OP_PRINT:
3568  {
3570  break;
3571  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3572  struct Email *e_cur = get_cur_email(Context, menu);
3573  el_add_tagged(&el, Context, e_cur, tag);
3575  emaillist_clear(&el);
3576 
3577 #ifdef USE_IMAP
3578  /* in an IMAP folder index with imap_peek=no, printing could change
3579  * new or old messages status to read. Redraw what's needed. */
3580  if ((Context->mailbox->magic == MUTT_IMAP) && !C_ImapPeek)
3581  {
3582  menu->redraw |= (tag ? REDRAW_INDEX : REDRAW_CURRENT) | REDRAW_STATUS;
3583  }
3584 #endif
3585  break;
3586  }
3587 
3588  case OP_MAIN_READ_THREAD:
3589  case OP_MAIN_READ_SUBTHREAD:
3590  {
3592  break;
3593  /* L10N: CHECK_ACL */
3594  /* L10N: Due to the implementation details we do not know whether we
3595  mark zero, 1, 12, ... messages as read. So in English we use
3596  "messages". Your language might have other means to express this. */
3597  if (!check_acl(Context, MUTT_ACL_SEEN, _("Can't mark messages as read")))
3598  break;
3599 
3600  struct Email *e_cur = get_cur_email(Context, menu);
3601  int rc = mutt_thread_set_flag(e_cur, MUTT_READ, true, (op != OP_MAIN_READ_THREAD));
3602  if (rc != -1)
3603  {
3604  if (C_Resolve)
3605  {
3606  menu->current = ((op == OP_MAIN_READ_THREAD) ? mutt_next_thread(e_cur) :
3607  mutt_next_subthread(e_cur));
3608  if (menu->current == -1)
3609  {
3610  menu->current = menu->oldcurrent;
3611  }
3612  else if (in_pager)
3613  {
3614  op = OP_DISPLAY_MESSAGE;
3615  continue;
3616  }
3617  }
3618  menu->redraw |= REDRAW_INDEX | REDRAW_STATUS;
3619  }
3620  break;
3621  }
3622 
3623  case OP_MARK_MSG:
3624  {
3626  break;
3627  struct Email *e_cur = get_cur_email(Context, menu);
3628  if (!e_cur)
3629  break;
3630  if (e_cur->env->message_id)
3631  {
3632  char buf2[128];
3633 
3634  buf2[0] = '\0';
3635  /* L10N: This is the prompt for <mark-message>. Whatever they
3636  enter will be prefixed by $mark_macro_prefix and will become
3637  a macro hotkey to jump to the currently selected message. */
3638  if (!mutt_get_field(_("Enter macro stroke: "), buf2, sizeof(buf2), MUTT_CLEAR) &&
3639  buf2[0])
3640  {
3641  char str[256], macro[256];
3642  snprintf(str, sizeof(str), "%s%s", C_MarkMacroPrefix, buf2);
3643  snprintf(macro, sizeof(macro), "<search>~i \"%s\"\n", e_cur->env->message_id);
3644  /* L10N: "message hotkey" is the key bindings menu description of a
3645  macro created by <mark-message>. */
3646  km_bind(str, MENU_MAIN, OP_MACRO, macro, _("message hotkey"));
3647 
3648  /* L10N: This is echoed after <mark-message> creates a new hotkey
3649  macro. %s is the hotkey string ($mark_macro_prefix followed
3650  by whatever they typed at the prompt.) */
3651  snprintf(buf2, sizeof(buf2), _("Message bound to %s"), str);
3652  mutt_message(buf2);
3653  mutt_debug(LL_DEBUG1, "Mark: %s => %s\n", str, macro);
3654  }
3655  }
3656  else
3657  {
3658  /* L10N: This error is printed if <mark-message> can't find a
3659  Message-ID for the currently selected message in the index. */
3660  mutt_error(_("No message ID to macro"));
3661  }
3662  break;
3663  }
3664 
3665  case OP_RECALL_MESSAGE:
3666  if (!prereq(Context, menu, CHECK_ATTACH))
3667  break;
3668  ci_send_message(SEND_POSTPONED, NULL, NULL, Context, NULL);
3669  menu->redraw = REDRAW_FULL;
3670  break;
3671 
3672  case OP_RESEND:
3674  break;
3675 
3676  if (tag)
3677  {
3678  struct Mailbox *m = Context->mailbox;
3679  for (size_t i = 0; i < m->msg_count; i++)
3680  {
3681  struct Email *e = m->emails[i];
3682  if (!e)
3683  break;
3684  if (message_is_tagged(Context, e))
3685  mutt_resend_message(NULL, Context, e);
3686  }
3687  }
3688  else
3689  {
3690  struct Email *e_cur = get_cur_email(Context, menu);
3691  mutt_resend_message(NULL, Context, e_cur);
3692  }
3693 
3694  menu->redraw = REDRAW_FULL;
3695  break;
3696 
3697 #ifdef USE_NNTP
3698  case OP_FOLLOWUP:
3699  case OP_FORWARD_TO_GROUP:
3701  break;
3702  /* fallthrough */
3703 
3704  case OP_POST:
3705  {
3707  break;
3708  struct Email *e_cur = get_cur_email(Context, menu);
3709  if (!e_cur)
3710  break;
3711  if ((op != OP_FOLLOWUP) || !e_cur->env->followup_to ||
3712  (mutt_str_strcasecmp(e_cur->env->followup_to, "poster") != 0) ||
3714  _("Reply by mail as poster prefers?")) != MUTT_YES))
3715  {
3716  if (Context && (Context->mailbox->magic == MUTT_NNTP) &&
3717  !((struct NntpMboxData *) Context->mailbox->mdata)->allowed && (query_quadoption(C_PostModerated, _("Posting to this group not allowed, may be moderated. Continue?")) != MUTT_YES))
3718  {
3719  break;
3720  }
3721  if (op == OP_POST)
3722  ci_send_message(SEND_NEWS, NULL, NULL, Context, NULL);
3723  else
3724  {
3726  break;
3727  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3728  el_add_tagged(&el, Context, e_cur, tag);
3729  ci_send_message(((op == OP_FOLLOWUP) ? SEND_REPLY : SEND_FORWARD) | SEND_NEWS,
3730  NULL, NULL, Context, &el);
3731  emaillist_clear(&el);
3732  }
3733  menu->redraw = REDRAW_FULL;
3734  break;
3735  }
3736  }
3737 #endif
3738  /* fallthrough */
3739  case OP_REPLY:
3740  {
3742  break;
3743  struct Email *e_cur = get_cur_email(Context, menu);
3744  if (!e_cur)
3745  break;
3746  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3747  el_add_tagged(&el, Context, e_cur, tag);
3748  if (C_PgpAutoDecode && (tag || !(e_cur->security & PGP_TRADITIONAL_CHECKED)))
3749  {
3750  mutt_check_traditional_pgp(&el, &menu->redraw);
3751  }
3752  ci_send_message(SEND_REPLY, NULL, NULL, Context, &el);
3753  emaillist_clear(&el);
3754  menu->redraw = REDRAW_FULL;
3755  break;
3756  }
3757 
3758  case OP_SHELL_ESCAPE:
3760  break;
3761 
3762  case OP_TAG_THREAD:
3763  case OP_TAG_SUBTHREAD:
3764  {
3766  break;
3767  struct Email *e_cur = get_cur_email(Context, menu);
3768  if (!e_cur)
3769  break;
3770 
3771  int rc = mutt_thread_set_flag(e_cur, MUTT_TAG, !e_cur->tagged, (op != OP_TAG_THREAD));
3772  if (rc != -1)
3773  {
3774  if (C_Resolve)
3775  {
3776  if (op == OP_TAG_THREAD)
3777  menu->current = mutt_next_thread(e_cur);
3778  else
3779  menu->current = mutt_next_subthread(e_cur);
3780 
3781  if (menu->current == -1)
3782  menu->current = menu->oldcurrent;
3783  }
3784  menu->redraw |= REDRAW_INDEX | REDRAW_STATUS;
3785  }
3786  break;
3787  }
3788 
3789  case OP_UNDELETE:
3790  {
3792  break;
3793  /* L10N: CHECK_ACL */
3794  if (!check_acl(Context, MUTT_ACL_DELETE, _("Can't undelete message")))
3795  break;
3796 
3797  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3798  struct Email *e_cur = get_cur_email(Context, menu);
3799  el_add_tagged(&el, Context, e_cur, tag);
3800 
3803  emaillist_clear(&el);
3804 
3805  if (tag)
3806  {
3807  menu->redraw |= REDRAW_INDEX;
3808  }
3809  else
3810  {
3811  if (C_Resolve && (menu->current < (Context->mailbox->vcount - 1)))
3812  {
3813  menu->current++;
3814  menu->redraw |= REDRAW_MOTION_RESYNC;
3815  }
3816  else
3817  menu->redraw |= REDRAW_CURRENT;
3818  }
3819 
3820  menu->redraw |= REDRAW_STATUS;
3821  break;
3822  }
3823 
3824  case OP_UNDELETE_THREAD:
3825  case OP_UNDELETE_SUBTHREAD:
3826  {
3828  break;
3829  /* L10N: CHECK_ACL */
3830  /* L10N: Due to the implementation details we do not know whether we
3831  undelete zero, 1, 12, ... messages. So in English we use
3832  "messages". Your language might have other means to express this. */
3833  if (!check_acl(Context, MUTT_ACL_DELETE, _("Can't undelete messages")))
3834  break;
3835 
3836  struct Email *e_cur = get_cur_email(Context, menu);
3837  int rc = mutt_thread_set_flag(e_cur, MUTT_DELETE, false, (op != OP_UNDELETE_THREAD));
3838  if (rc != -1)
3839  {
3840  rc = mutt_thread_set_flag(e_cur, MUTT_PURGE, false, (op != OP_UNDELETE_THREAD));
3841  }
3842  if (rc != -1)
3843  {
3844  if (C_Resolve)
3845  {
3846  if (op == OP_UNDELETE_THREAD)
3847  menu->current = mutt_next_thread(e_cur);
3848  else
3849  menu->current = mutt_next_subthread(e_cur);
3850 
3851  if (menu->current == -1)
3852  menu->current = menu->oldcurrent;
3853  }
3854  menu->redraw |= REDRAW_INDEX | REDRAW_STATUS;
3855  }
3856  break;
3857  }
3858 
3859  case OP_VERSION:
3861  break;
3862 
3863  case OP_MAILBOX_LIST:
3865  break;
3866 
3867  case OP_VIEW_ATTACHMENTS:
3869  break;
3870  struct Email *e_cur = get_cur_email(Context, menu);
3871  if (!e_cur)
3872  break;
3873  mutt_view_attachments(e_cur);
3874  if (e_cur->attach_del)
3875  Context->mailbox->changed = true;
3876  menu->redraw = REDRAW_FULL;
3877  break;
3878 
3879  case OP_END_COND:
3880  break;
3881 
3882  case OP_WHAT_KEY:
3883  mutt_what_key();
3884  break;
3885 
3886 #ifdef USE_SIDEBAR
3887  case OP_SIDEBAR_NEXT:
3888  case OP_SIDEBAR_NEXT_NEW:
3889  case OP_SIDEBAR_PAGE_DOWN:
3890  case OP_SIDEBAR_PAGE_UP:
3891  case OP_SIDEBAR_PREV:
3892  case OP_SIDEBAR_PREV_NEW:
3894  break;
3895 
3896  case OP_SIDEBAR_TOGGLE_VISIBLE:
3897  bool_str_toggle(NeoMutt->sub, "sidebar_visible", NULL);
3898  mutt_window_reflow(NULL);
3899  break;
3900 #endif
3901 
3902 #ifdef USE_AUTOCRYPT
3903  case OP_AUTOCRYPT_ACCT_MENU:
3905  break;
3906 #endif
3907 
3908  default:
3909  if (!in_pager)
3911  }
3912 
3913 #ifdef USE_NOTMUCH
3914  if (Context)
3916 #endif
3917 
3918  if (in_pager)
3919  {
3921  in_pager = false;
3922  menu->redraw = REDRAW_FULL;
3923  }
3924 
3925  if (done)
3926  break;
3927  }
3928 
3929  mutt_menu_pop_current(menu);
3930  mutt_menu_free(&menu);
3931  return close;
3932 }
3933 
3939 void mutt_set_header_color(struct Mailbox *m, struct Email *e)
3940 {
3941  if (!e)
3942  return;
3943 
3944  struct ColorLine *color = NULL;
3945  struct PatternCache cache = { 0 };
3946 
3947  STAILQ_FOREACH(color, &Colors->index_list, entries)
3948  {
3950  MUTT_MATCH_FULL_ADDRESS, m, e, &cache))
3951  {
3952  e->pair = color->pair;
3953  return;
3954  }
3955  }
3957 }
3958 
3963 {
3964  if (!nc->event_data)
3965  return -1;
3966  if (nc->event_type != NT_CONFIG)
3967  return 0;
3968 
3969  struct EventConfig *ec = nc->event_data;
3970 
3971  if (mutt_str_strcmp(ec->name, "reply_regex") != 0)
3972  return 0;
3973 
3974  if (!Context || !Context->mailbox)
3975  return 0;
3976 
3977  regmatch_t pmatch[1];
3978  struct Mailbox *m = Context->mailbox;
3979 
3980  for (int i = 0; i < m->msg_count; i++)
3981  {
3982  struct Email *e = m->emails[i];
3983  if (!e)
3984  break;
3985  struct Envelope *env = e->env;
3986  if (!env || !env->subject)
3987  continue;
3988 
3989  if (mutt_regex_capture(C_ReplyRegex, env->subject, 1, pmatch))
3990  {
3991  env->real_subj = env->subject + pmatch[0].rm_eo;
3992  continue;
3993  }
3994 
3995  env->real_subj = env->subject;
3996  }
3997 
3998  OptResortInit = true; /* trigger a redraw of the index */
3999  return 0;
4000 }
4001 
4007 {
4008  struct MuttWindow *dlg =
4011  dlg->type = WT_DIALOG;
4012  struct MuttWindow *cont_right =
4015  cont_right->type = WT_CONTAINER;
4016  struct MuttWindow *panel_index =
4019  panel_index->type = WT_CONTAINER;
4020  struct MuttWindow *panel_pager =
4023  panel_pager->type = WT_CONTAINER;
4024  panel_pager->state.visible = false; // The Pager and Pager Bar are initially hidden
4025 
4026  struct MuttWindow *win_index =
4029  win_index->type = WT_INDEX;
4030  struct MuttWindow *win_pbar = mutt_window_new(
4032  win_pbar->type = WT_PAGER_BAR;
4033  struct MuttWindow *win_pager =
4036  win_pager->type = WT_PAGER;
4037  struct MuttWindow *win_sidebar =
4040  win_sidebar->type = WT_SIDEBAR;
4041  win_sidebar->state.visible = C_SidebarVisible && (C_SidebarWidth > 0);
4042  struct MuttWindow *win_ibar = mutt_window_new(
4044  win_ibar->type = WT_INDEX_BAR;
4045 
4046  if (C_SidebarOnRight)
4047  {
4048  mutt_window_add_child(dlg, cont_right);
4049  mutt_window_add_child(dlg, win_sidebar);
4050  }
4051  else
4052  {
4053  mutt_window_add_child(dlg, win_sidebar);
4054  mutt_window_add_child(dlg, cont_right);
4055  }
4056 
4057  mutt_window_add_child(cont_right, panel_index);
4058  if (C_StatusOnTop)
4059  {
4060  mutt_window_add_child(panel_index, win_ibar);
4061  mutt_window_add_child(panel_index, win_index);
4062  }
4063  else
4064  {
4065  mutt_window_add_child(panel_index, win_index);
4066  mutt_window_add_child(panel_index, win_ibar);
4067  }
4068 
4069  mutt_window_add_child(cont_right, panel_pager);
4070  if (C_StatusOnTop)
4071  {
4072  mutt_window_add_child(panel_pager, win_pbar);
4073  mutt_window_add_child(panel_pager, win_pager);
4074  }
4075  else
4076  {
4077  mutt_window_add_child(panel_pager, win_pager);
4078  mutt_window_add_child(panel_pager, win_pbar);
4079  }
4080 
4082 
4083  return dlg;
4084 }
4085 
4091 {
4092  if (!dlg)
4093  return;
4094 
4095  struct MuttWindow *win_sidebar = mutt_window_find(dlg, WT_SIDEBAR);
4096  if (!win_sidebar)
4097  return;
4098 
4100 }
4101 
4106 {
4107  if (!nc->event_data || !nc->global_data)
4108  return -1;
4109  if (nc->event_type != NT_CONFIG)
4110  return 0;
4111 
4112  struct EventConfig *ec = nc->event_data;
4113  struct MuttWindow *dlg = nc->global_data;
4114 
4115  struct MuttWindow *win_index = mutt_window_find(dlg, WT_INDEX);
4116  struct MuttWindow *win_pager = mutt_window_find(dlg, WT_PAGER);
4117  if (!win_index || !win_pager)
4118  return -1;
4119 
4120  if (mutt_str_strcmp(ec->name, "status_on_top") == 0)
4121  {
4122  struct MuttWindow *parent = win_index->parent;
4123  if (!parent)
4124  return -1;
4125  struct MuttWindow *first = TAILQ_FIRST(&parent->children);
4126  if (!first)
4127  return -1;
4128 
4129  if ((C_StatusOnTop && (first == win_index)) || (!C_StatusOnTop && (first != win_index)))
4130  {
4131  // Swap the Index and the Index Bar Windows
4132  TAILQ_REMOVE(&parent->children, first, entries);
4133  TAILQ_INSERT_TAIL(&parent->children, first, entries);
4134  }
4135 
4136  parent = win_pager->parent;
4137  first = TAILQ_FIRST(&parent->children);
4138 
4139  if ((C_StatusOnTop && (first == win_pager)) || (!C_StatusOnTop && (first != win_pager)))
4140  {
4141  // Swap the Pager and Pager Bar Windows
4142  TAILQ_REMOVE(&parent->children, first, entries);
4143  TAILQ_INSERT_TAIL(&parent->children, first, entries);
4144  }
4145  goto reflow;
4146  }
4147 
4148  if (mutt_str_strcmp(ec->name, "pager_index_lines") == 0)
4149  {
4150  struct MuttWindow *parent = win_pager->parent;
4151  if (parent->state.visible)
4152  {
4153  int vcount = (Context && Context->mailbox) ? Context->mailbox->vcount : 0;
4154  win_index->req_rows = MIN(C_PagerIndexLines, vcount);
4155  win_index->size = MUTT_WIN_SIZE_FIXED;
4156 
4157  win_index->parent->size = MUTT_WIN_SIZE_MINIMISE;
4158  win_index->parent->state.visible = (C_PagerIndexLines != 0);
4159  }
4160  else
4161  {
4162  win_index->req_rows = MUTT_WIN_SIZE_UNLIMITED;
4163  win_index->size = MUTT_WIN_SIZE_MAXIMISE;
4164 
4165  win_index->parent->size = MUTT_WIN_SIZE_MAXIMISE;
4166  win_index->parent->state.visible = true;
4167  }
4168  }
4169 
4170 reflow:
4171  mutt_window_reflow(dlg);
4172  return 0;
4173 }
int km_dokey(enum MenuType menu)
Determine what a keypress should do.
Definition: keymap.c:617
struct ColorLineList status_list
List of colours applied to the status bar.
Definition: color.h:142
void mutt_mailbox_next_buffer(struct Mailbox *m_cur, struct Buffer *s)
incoming folders completion routine
Definition: mutt_mailbox.c:318
struct Email ** emails
Array of Emails.
Definition: mailbox.h:98
Convenience wrapper for the gui headers.
#define MUTT_OPEN_NO_FLAGS
No flags are set.
Definition: mx.h:52
struct MuttThread * next
Next sibling Thread.
Definition: thread.h:47
int mutt_save_message(struct Mailbox *m, struct EmailList *el, bool delete_original, bool decode, bool decrypt)
Save an email.
Definition: commands.c:1023
The "current" mailbox.
Definition: context.h:36
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox&#39;s path string.
Definition: mailbox.h:191
WHERE bool C_StatusOnTop
Config: Display the status bar at the top.
Definition: globals.h:255
void nm_query_window_forward(void)
Function to move the current search window forward in time.
WHERE char * C_TsIconFormat
Config: printf-like format string for the terminal&#39;s icon title.
Definition: globals.h:147
int mutt_pattern_func(int op, char *prompt)
Perform some Pattern matching.
Definition: pattern.c:2550
int mutt_thread_set_flag(struct Email *e, int flag, bool bf, bool subthread)
Set a flag on an entire thread.
Definition: flags.c:374
#define REDRAW_FULL
Redraw everything.
Definition: mutt_menu.h:47
bool message_is_tagged(struct Context *ctx, struct Email *e)
Is a message in the index tagged (and within limit)
Definition: context.c:352
Manage keymappings.
uint8_t MuttFormatFlags
Flags for mutt_expando_format(), e.g. MUTT_FORMAT_FORCESUBJ.
Definition: format_flags.h:29
bool mutt_mailbox_list(void)
List the mailboxes with new mail.
Definition: mutt_mailbox.c:230
#define NONULL(x)
Definition: string2.h:37
int msg_count
Total number of messages.
Definition: mailbox.h:90
#define mutt_set_flag(m, e, flag, bf)
Definition: protos.h:70
Representation of the email&#39;s header.
#define WithCrypto
Definition: lib.h:161
int mutt_str_atoi(const char *str, int *dst)
Convert ASCII string to an integer.
Definition: string.c:262
#define SEND_TO_SENDER
Compose new email to sender.
Definition: send.h:100
IMAP network mailbox.
void mutt_pipe_message(struct Mailbox *m, struct EmailList *el)
Pipe a message.
Definition: commands.c:697
The envelope/body of an email.
Definition: email.h:37
#define MUTT_CLEAR
Clear input if printable character is pressed.
Definition: mutt.h:68
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
struct Email * mutt_get_virt_email(struct Mailbox *m, int vnum)
Get a virtual Email.
Definition: context.c:414
#define TAILQ_FIRST(head)
Definition: queue.h:716
#define MIN(a, b)
Definition: memory.h:31
#define mutt_perror(...)
Definition: logging.h:85
#define MUTT_SHUTDOWN_HOOK
shutdown-hook: run when leaving NeoMutt
Definition: hook.h:65
void mutt_set_vnum(struct Context *ctx)
Set the virtual index number of all the messages in a mailbox.
Definition: mutt_thread.c:1197
GUI selectable list of items.
Definition: mutt_menu.h:82
WHERE bool C_BeepNew
Config: Make a noise when new mail arrives.
Definition: globals.h:204
static int ci_previous_undeleted(struct Context *ctx, int msgno)
Find the previous undeleted email.
Definition: index.c:349
Data passed to a notification function.
Definition: observer.h:40
int mx_mbox_check(struct Mailbox *m, int *index_hint)
Check for new mail - Wrapper for MxOps::mbox_check()
Definition: mx.c:1096
struct ConnAccount account
Definition: connection.h:36
void nm_query_window_backward(void)
Function to move the current search window backward in time.
&#39;NNTP&#39; (Usenet) Mailbox type
Definition: mailbox.h:51
int mx_mbox_close(struct Context **ptr)
Save changes and close mailbox.
Definition: mx.c:591
Structs that make up an email.
String processing routines to generate the mail index.
struct MuttThread * tree
Top of thread tree.
Definition: context.h:42
The "currently-open" mailbox.
Autocrypt end-to-end encryption.
bool C_UncollapseJump
Config: When opening a thread, jump to the next unread message.
Definition: index.c:107
Dialog (nested Windows) displayed to the user.
Definition: mutt_window.h:68
Pager Bar containing status info about the Pager.
Definition: mutt_window.h:75
enum QuadOption query_quadoption(enum QuadOption opt, const char *prompt)
Ask the user a quad-question.
Definition: init.c:1109
#define MUTT_FORMAT_FORCESUBJ
Print the subject even if unchanged.
Definition: format_flags.h:31
GUI manage the main index (list of emails)
#define mutt_message(...)
Definition: logging.h:83
uint8_t CheckFlags
typedef CheckFlags - Checks to perform before running a function
Definition: index.c:146
void mutt_check_rescore(struct Mailbox *m)
Do the emails need to have their scores recalculated?
Definition: score.c:70
Window uses all available vertical space.
Definition: mutt_window.h:33
int oldcurrent
For driver use only.
Definition: mutt_menu.h:109
User answered &#39;Yes&#39;, or assume &#39;Yes&#39;.
Definition: quad.h:40
struct MuttThread * thread
Thread of Emails.
Definition: email.h:94
WHERE unsigned char C_Quit
Config: Prompt before exiting NeoMutt.
Definition: globals.h:184
void mutt_display_address(struct Envelope *env)
Display the address of a message.
Definition: commands.c:906
int mx_path_canon(char *buf, size_t buflen, const char *folder, enum MailboxType *magic)
Canonicalise a mailbox path - Wrapper for MxOps::path_canon()
Definition: mx.c:1350
void mutt_curses_set_color(enum ColorId color)
Set the current colour for text.
Definition: mutt_curses.c:55
struct NntpAccountData * adata
Definition: lib.h:155
void mutt_emails_set_flag(struct Mailbox *m, struct EmailList *el, int flag, bool bf)
Set flag on messages.
Definition: flags.c:353
static void index_custom_redraw(struct Menu *menu)
Redraw the index - Implements Menu::menu_custom_redraw()
Definition: index.c:1056
#define mutt_thread_next_unread(ctx, e)
Definition: mutt_thread.h:62
int * defs
Array of all fixed colours, see enum ColorId.
Definition: color.h:132
Progress tracks elements, according to C_WriteInc.
Definition: progress.h:42
Messages in limited view.
Definition: mutt.h:109
WHERE unsigned char C_FollowupToPoster
Config: (nntp) Reply to the poster if &#39;poster&#39; is in the &#39;Followup-To&#39; header.
Definition: globals.h:190
void mutt_view_attachments(struct Email *e)
Show the attachments in a Menu.
Definition: recvattach.c:1410
void mutt_flushinp(void)
Empty all the keyboard buffers.
Definition: curs_lib.c:892
int mutt_monitor_remove(struct Mailbox *m)
Remove a watch for a mailbox.
Definition: monitor.c:523
bool attach_del
Has an attachment marked for deletion.
Definition: email.h:49
bool mutt_limit_current_thread(struct Email *e)
Limit the email view to the current thread.
Definition: pattern.c:2503
#define SEND_FORWARD
Forward email.
Definition: send.h:91
struct MuttWindow * mutt_window_find(struct MuttWindow *root, enum WindowType type)
Find a Window of a given type.
Definition: mutt_window.c:575
void mutt_window_clrtoeol(struct MuttWindow *win)
Clear to the end of the line.
Definition: mutt_window.c:135
struct PatternList * color_pattern
Compiled pattern to speed up index color calculation.
Definition: color.h:41
void mutt_resize_screen(void)
Update NeoMutt&#39;s opinion about the window size (CURSES)
Definition: resize.c:100
char * realpath
Used for duplicate detection, context comparison, and the sidebar.
Definition: mailbox.h:83
NeoMutt Logging.
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
#define CHECK_ATTACH
Is the user in message-attach mode?
Definition: index.c:152
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 Body * content
List of MIME parts.
Definition: email.h:90
void index_make_entry(char *buf, size_t buflen, struct Menu *menu, int line)
Format a menu item for the index list - Implements Menu::menu_make_entry()
Definition: index.c:825
void mutt_check_stats(void)
Forcibly update mailbox stats.
Definition: commands.c:1392
#define mutt_next_subthread(e)
Definition: mutt_thread.h:67
void * mutt_hash_find(const struct Hash *table, const char *strkey)
Find the HashElem data in a Hash table element using a key.
Definition: hash.c:378
void crypt_forget_passphrase(void)
Forget a passphrase and display a message.
Definition: crypt.c:103
bool mutt_link_threads(struct Email *parent, struct EmailList *children, struct Mailbox *m)
Forcibly link threads together.
Definition: mutt_thread.c:1501
WHERE char * C_NmQueryWindowCurrentSearch
Config: (notmuch) Current search parameters.
Definition: globals.h:169
static bool check_acl(struct Context *ctx, AclFlags acl, const char *msg)
Check the ACLs for a function.
Definition: index.c:227
A config-change event.
Definition: subset.h:68
bool display_subject
Used for threading.
Definition: email.h:57
#define MUTT_NM_QUERY
Notmuch query mode.
Definition: mutt.h:72
int pair
Colour pair index.
Definition: color.h:44
Invisible shaping container Window.
Definition: mutt_window.h:69
void mutt_enter_command(void)
enter a neomutt command
Definition: commands.c:860
String manipulation buffer.
Definition: buffer.h:33
#define MUTT_ACL_INSERT
Add/copy into the mailbox (used when editing a message)
Definition: mailbox.h:68
int nntp_check_msgid(struct Mailbox *m, const char *msgid)
Fetch article by Message-ID.
Definition: nntp.c:2228
static int ci_next_undeleted(struct Context *ctx, int msgno)
Find the next undeleted email.
Definition: index.c:326
Messages to be un-deleted.
Definition: mutt.h:103
Flagged messages.
Definition: mutt.h:106
LOFF_T offset
offset where the actual data begins
Definition: body.h:44
void mutt_unget_event(int ch, int op)
Return a keystroke to the input buffer.
Definition: curs_lib.c:807
WHERE bool C_ImapPeek
Config: (imap) Don&#39;t mark messages as read when fetching them from the server.
Definition: globals.h:226
#define _(a)
Definition: message.h:28
Mailbox wasn&#39;t recognised.
Definition: mailbox.h:46
Error occurred examining Mailbox.
Definition: mailbox.h:45
static void update_index_unthreaded(struct Context *ctx, int check, int oldcount)
Update the index (if unthreaded)
Definition: index.c:567
char * real_subj
Offset of the real subject.
Definition: envelope.h:67
WHERE bool C_BrailleFriendly
Config: Move the cursor to the beginning of the line.
Definition: globals.h:205
int index_color(int line)
Calculate the colour for a line of the index - Implements Menu::menu_color()
Definition: index.c:899
struct Context * mx_mbox_open(struct Mailbox *m, OpenMailboxFlags flags)
Open a mailbox and parse it.
Definition: mx.c:253
void menu_status_line(char *buf, size_t buflen, struct Menu *menu, const char *p)
Create the status line.
Definition: status.c:409
bool mutt_check_traditional_pgp(struct EmailList *el, MuttRedrawFlags *redraw)
Check if a message has inline PGP content.
Definition: commands.c:1376
WHERE char * LastFolder
Previously selected mailbox.
Definition: globals.h:55
struct MuttThread * parent
Parent of this Thread.
Definition: thread.h:45
Messages to be purged (bypass trash)
Definition: mutt.h:104
A division of the screen.
Definition: mutt_window.h:86
char * C_MarkMacroPrefix
Config: Prefix for macros using &#39;<mark-message>&#39;.
Definition: index.c:105
bool C_CollapseAll
Config: Collapse all threads when entering a folder.
Definition: index.c:102
Index panel (list of emails)
Definition: keymap.h:77
uint8_t OpenMailboxFlags
Flags for mutt_open_mailbox(), e.g. MUTT_NOSORT.
Definition: mx.h:51
WHERE char * C_StatusFormat
Config: printf-like format string for the index&#39;s status line.
Definition: globals.h:145
#define MUTT_READONLY
Open in read-only mode.
Definition: mx.h:55
uint16_t SendFlags
Flags for ci_send_message(), e.g. SEND_REPLY.
Definition: send.h:86
int mutt_monitor_add(struct Mailbox *m)
Add a watch for a mailbox.
Definition: monitor.c:478
struct Mailbox * mx_mbox_find2(const char *path)
Find a Mailbox on an Account.
Definition: mx.c:1617
Flags to control mutt_expando_format()
All user-callable functions.
#define SEND_POSTPONED
Recall a postponed email.
Definition: send.h:92
WHERE bool C_TsEnabled
Config: Allow NeoMutt to set the terminal status line and icon.
Definition: globals.h:258
struct NntpAccountData * nntp_select_server(struct Mailbox *m, char *server, bool leave_lock)
Open a connection to an NNTP server.
Definition: newsrc.c:1013
Container for Accounts, Notifications.
Definition: neomutt.h:35
A progress bar.
Definition: progress.h:49
void mutt_buffer_pretty_mailbox(struct Buffer *buf)
Shorten a mailbox path using &#39;~&#39; or &#39;=&#39;.
Definition: muttlib.c:702
void(* menu_make_entry)(char *buf, size_t buflen, struct Menu *menu, int line)
Format a item for a menu.
Definition: mutt_menu.h:120
Mailbox was closed.
Definition: mailbox.h:169
Representation of a single alias to an email address.
#define MUTT_ACL_DELETE
Delete a message.
Definition: mailbox.h:65
bool notify_observer_add(struct Notify *notify, observer_t callback, void *global_data)
Add an observer to an object.
Definition: notify.c:154
#define mutt_get_field(field, buf, buflen, complete)
Definition: curs_lib.h:90
#define mutt_collapse_thread(ctx, e)
Definition: mutt_thread.h:57
int vcount
The number of virtual messages.
Definition: mailbox.h:101
The body of an email.
Definition: body.h:34
#define REDRAW_SIDEBAR
Redraw the sidebar.
Definition: mutt_menu.h:51
Convenience wrapper for the config headers.
void mutt_paddstr(int n, const char *s)
Display a string on screen, padded if necessary.
Definition: curs_lib.c:1239
GUI component for displaying/selecting items from a list.
An Index Window containing a selection list.
Definition: mutt_window.h:72
Prepare and send an email.
Hundreds of global variables to back the user variables.
void imap_logout_all(void)
close all open connections
Definition: imap.c:694
Assorted sorting methods.
void mutt_print_message(struct Mailbox *m, struct EmailList *el)
Print a message.
Definition: commands.c:719
#define SEND_NO_FLAGS
No flags are set.
Definition: send.h:87
Routines for querying and external address book.
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:97
enum NotifyType event_type
Send: Event type, e.g. NT_ACCOUNT.
Definition: observer.h:42
Some miscellaneous functions.
int match
Substring to match, 0 for old behaviour.
Definition: color.h:39
int mutt_dlg_index_observer(struct NotifyCallback *nc)
Listen for config changes affecting the Index/Pager - Implements observer_t()
Definition: index.c:4105
#define mutt_previous_thread(e)
Definition: mutt_thread.h:66
void mutt_folder_hook(const char *path, const char *desc)
Perform a folder hook.
Definition: hook.c:507
size_t dsize
Length of data.
Definition: buffer.h:37
int mutt_window_addnstr(const char *str, int num)
Write a partial string to a Window.
Definition: mutt_window.c:410
bool tagged
Email is tagged.
Definition: email.h:44
#define CHECK_VISIBLE
Is the selected message visible in the index?
Definition: index.c:150
bool read
Email is read.
Definition: email.h:51
void mutt_progress_update(struct Progress *progress, size_t pos, int percent)
Update the state of the progress bar.
Definition: progress.c:212
char * name
A short name for the Mailbox.
Definition: mailbox.h:84
void mutt_startup_shutdown_hook(HookFlags type)
Execute any startup/shutdown hooks.
Definition: hook.c:851
void mutt_sleep(short s)
Sleep for a while.
Definition: muttlib.c:1544
void mutt_curses_set_cursor(enum MuttCursorState state)
Set the cursor state.
Definition: mutt_curses.c:76
struct ListHead in_reply_to
in-reply-to header content
Definition: envelope.h:82
char * message_id
Message ID.
Definition: envelope.h:69
struct MuttThread * prev
Previous sibling Thread.
Definition: thread.h:48
struct Mailbox * mailbox
Definition: context.h:50
Parse and execute user-defined hooks.
#define MUTT_FORMAT_TREE
Draw the thread tree.
Definition: format_flags.h:32
Many unsorted constants and some structs.
Log at debug level 2.
Definition: logging.h:41
API for mailboxes.
#define CHECK_IN_MAILBOX
Is there a mailbox open?
Definition: index.c:148
bool old
Email is seen, but unread.
Definition: email.h:50
void mailbox_free(struct Mailbox **ptr)
Free a Mailbox.
Definition: mailbox.c:60
void mutt_make_string_flags(char *buf, size_t buflen, int cols, const char *s, struct Context *ctx, struct Mailbox *m, struct Email *e, MuttFormatFlags flags)
Create formatted strings using mailbox expandos.
Definition: hdrline.c:1505
static bool prereq(struct Context *ctx, struct Menu *menu, CheckFlags checks)
Check the pre-requisites for a function.
Definition: index.c:177
void mutt_flush_macro_to_endcond(void)
Drop a macro from the input buffer.
Definition: curs_lib.c:863
#define MUTT_COMP_NO_FLAGS
No flags are set.
Definition: mutt.h:62
enum MailboxType magic
Mailbox type.
Definition: mailbox.h:104
struct MuttWindow * win_ibar
Definition: mutt_menu.h:96
bool readonly
Don&#39;t allow changes to the mailbox.
Definition: mailbox.h:118
bool nm_message_is_still_queried(struct Mailbox *m, struct Email *e)
Is a message still visible in the query?
void mutt_window_clearline(struct MuttWindow *win, int row)
Clear a row of a Window.
Definition: mutt_window.c:113
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:152
int mutt_parent_message(struct Context *ctx, struct Email *e, bool find_root)
Find the parent of a message.
Definition: mutt_thread.c:1148
void mutt_what_key(void)
Ask the user to press a key.
Definition: keymap.c:1578
struct Envelope * env
Envelope information.
Definition: email.h:89
Display a normal cursor.
Definition: mutt_curses.h:82
int LastKey
contains the last key the user pressed
Definition: keymap.c:145
Convenience wrapper for the core headers.
int mx_tags_commit(struct Mailbox *m, struct Email *e, char *tags)
Save tags to the Mailbox - Wrapper for MxOps::tags_commit()
Definition: mx.c:1283
bool mutt_mailbox_notify(struct Mailbox *m_cur)
Notify the user if there&#39;s new mail.
Definition: mutt_mailbox.c:217
void mx_fastclose_mailbox(struct Mailbox *m)
free up memory associated with the Mailbox
Definition: mx.c:412
void mutt_shell_escape(void)
invoke a command in a subshell
Definition: commands.c:832
char * group
Definition: lib.h:142
int mutt_display_message(struct MuttWindow *win_index, struct MuttWindow *win_ibar, struct MuttWindow *win_pager, struct MuttWindow *win_pbar, struct Mailbox *m, struct Email *e)
Display a message in the pager.
Definition: commands.c:197
WHERE SIG_ATOMIC_VOLATILE_T SigWinch
true after SIGWINCH is received
Definition: globals.h:80
WHERE char * CurrentFolder
Currently selected mailbox.
Definition: globals.h:54
struct Menu * menu
Needed for pattern compilation.
Definition: context.h:46
void mutt_break_thread(struct Email *e)
Break the email Thread.
Definition: thread.c:225
WHERE int C_NmQueryWindowDuration
Config: (notmuch) Time duration of the current search window.
Definition: globals.h:168
void(* menu_custom_redraw)(struct Menu *menu)
Redraw the menu.
Definition: mutt_menu.h:149
WHERE unsigned char C_PostModerated
Config: (nntp) Allow posting to moderated newsgroups.
Definition: globals.h:189
#define SEND_LIST_REPLY
Reply to mailing list.
Definition: send.h:90
bool limited
Is this message in a limited view?
Definition: email.h:74
WHERE short C_Sort
Config: Sort method for the index.
Definition: sort.h:58
int nntp_check_children(struct Mailbox *m, const char *msgid)
Fetch children of article with the Message-ID.
Definition: nntp.c:2298
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:113
static int mx_toggle_write(struct Mailbox *m)
Toggle the mailbox&#39;s readonly flag.
Definition: index.c:419
Progress bar.
WHERE bool C_ReadOnly
Config: Open folders in read-only mode.
Definition: globals.h:245
bool message_is_visible(struct Context *ctx, struct Email *e)
Is a message in the index within limit.
Definition: context.c:336
void * mdata
Driver specific data.
Definition: mailbox.h:135
uint16_t AclFlags
ACL Rights - These show permission to...
Definition: mailbox.h:61
#define MUTT_ACL_WRITE
Write to a message (for flagging or linking threads)
Definition: mailbox.h:73
struct TagList tags
For drivers that support server tagging.
Definition: email.h:102
#define REDRAW_MOTION
Redraw after moving the menu list.
Definition: mutt_menu.h:43
&#39;Maildir&#39; Mailbox type
Definition: mailbox.h:50
void * global_data
Data from notify_observer_add()
Definition: observer.h:45
Usenet network mailbox type; talk to an NNTP server.
int flags
e.g. MB_NORMAL
Definition: mailbox.h:133
bool quasi_deleted
Deleted from neomutt, but not modified on disk.
Definition: email.h:47
#define SEND_KEY
Mail a PGP public key.
Definition: send.h:95
Window has a fixed size.
Definition: mutt_window.h:42
Plain text.
Definition: color.h:78
void mutt_mem_realloc(void *ptr, size_t size)
Resize a block of memory on the heap.
Definition: memory.c:114
struct Regex * C_ReplyRegex
Config: Regex to match message reply subjects like "re: ".
Definition: email_globals.c:37
#define TAILQ_REMOVE(head, elm, field)
Definition: queue.h:834
#define REDRAW_MOTION_RESYNC
Redraw any changing the menu selection.
Definition: mutt_menu.h:44
static int mailbox_index_observer(struct NotifyCallback *nc)
Listen for Mailbox changes - Implements observer_t()
Definition: index.c:657
short cols
Number of columns, can be MUTT_WIN_SIZE_UNLIMITED.
Definition: mutt_window.h:56
off_t vsize
Definition: context.h:38
#define mutt_b2s(buf)
Definition: buffer.h:41
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: pattern.c:2124
WHERE char * C_NewsServer
Config: (nntp) Url of the news server.
Definition: globals.h:129
View the message.
Definition: protos.h:58
int mutt_reply_observer(struct NotifyCallback *nc)
Listen for config changes to "reply_regex" - Implements observer_t()
Definition: index.c:3962
void mutt_alias_create(struct Envelope *cur, struct AddressList *al)
Create a new Alias from an Envelope or an Address.
Definition: alias.c:375
void mutt_refresh(void)
Force a refresh of the screen.
Definition: curs_lib.c:106
Side panel containing Accounts or groups of data.
Definition: mutt_window.h:76
struct MuttThread * child
Child of this Thread.
Definition: thread.h:46
Window size depends on its children.
Definition: mutt_window.h:44
Prototypes for many functions.
Edit the message.
Definition: protos.h:59
const char * line
Definition: common.c:36
WHERE short C_SortAux
Config: Secondary sort method for the index.
Definition: sort.h:59
char * nm_uri_from_query(struct Mailbox *m, char *buf, size_t buflen)
Turn a query into a URI.
Notmuch virtual mailbox type.
#define mutt_mktemp(buf, buflen)
Definition: muttlib.h:78
void mutt_sort_headers(struct Context *ctx, bool init)
Sort emails by their headers.
Definition: sort.c:364
Sort by email threads.
Definition: sort2.h:56
struct WindowState state
Current state of the Window.
Definition: mutt_window.h:91
#define CAN_COLLAPSE(email)
Definition: index.c:139
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: lib.h:135
WHERE bool OptAttachMsg
(pseudo) used by attach-message
Definition: options.h:31
#define REDRAW_STATUS
Redraw the status bar.
Definition: mutt_menu.h:46
#define SLIST_FIRST(head)
Definition: queue.h:228
int email_max
Number of pointers in emails.
Definition: mailbox.h:99
bool visible
Window is visible.
Definition: mutt_window.h:54
struct MuttWindow * mutt_window_new(enum MuttWindowOrientation orient, enum MuttWindowSize size, int rows, int cols)
Create a new Window.
Definition: mutt_window.c:57
WHERE char * C_Folder
Config: Base folder for a set of mailboxes.
Definition: globals.h:119
struct Mailbox * mailbox_find_name(const char *name)
Find the mailbox with a given name.
Definition: mailbox.c:126
Create/manipulate threading in emails.
void km_error_key(enum MenuType menu)
Handle an unbound key sequence.
Definition: keymap.c:1052
bool notify_observer_remove(struct Notify *notify, observer_t callback, void *global_data)
Remove an observer from an object.
Definition: notify.c:186
LOFF_T length
length (in bytes) of attachment
Definition: body.h:45
WHERE char * C_IndexFormat
Config: printf-like format string for the index menu (emails)
Definition: globals.h:112
Status bar (takes a pattern)
Definition: color.h:95
Messages to be deleted.
Definition: mutt.h:102
A mailbox.
Definition: mailbox.h:80
int mutt_strwidth(const char *s)
Measure a string&#39;s width in screen cells.
Definition: curs_lib.c:1332
#define PATH_MAX
Definition: mutt.h:50
int mutt_mailbox_check(struct Mailbox *m_cur, int force)
Check all all Mailboxes for new mail.
Definition: mutt_mailbox.c:152
#define MUTT_WIN_SIZE_UNLIMITED
Use as much space as possible.
Definition: mutt_window.h:47
static struct Email * get_cur_email(struct Context *ctx, struct Menu *menu)
Get the currently-selected Email.
Definition: index.c:162
short rows
Number of rows, can be MUTT_WIN_SIZE_UNLIMITED.
Definition: mutt_window.h:55
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: mutt_menu.h:108
Nondestructive flags change (IMAP)
Definition: mx.h:77
int log_queue_save(FILE *fp)
Save the contents of the queue to a temporary file.
Definition: logging.c:378
void pop_fetch_mail(void)
Fetch messages and save them in $spoolfile.
Definition: pop.c:570
#define UNREAD(email)
Definition: index.c:136
Manage where the email is piped to external commands.
WHERE bool C_Resolve
Config: Move to the next email whenever a command modifies an email.
Definition: globals.h:246
struct PatternList * limit_pattern
Compiled limit pattern.
Definition: context.h:40
int nm_read_entire_thread(struct Mailbox *m, struct Email *e)
Get the entire thread of an email.
bool dontwrite
Don&#39;t write the mailbox on close.
Definition: mailbox.h:114
Tagged messages.
Definition: mutt.h:107
char * data
Pointer to data.
Definition: buffer.h:35
int bool_str_toggle(struct ConfigSubset *sub, const char *name, struct Buffer *err)
Toggle the value of a bool.
Definition: bool.c:239
WHERE char * C_NewMailCommand
Config: External command to run when new mail arrives.
Definition: globals.h:137
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:1282
size_t mutt_str_strfcpy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:773
#define mutt_next_thread(e)
Definition: mutt_thread.h:65
POP network mailbox.
New messages.
Definition: mutt.h:97
Messages that have been read.
Definition: mutt.h:100
Not object-related.
Definition: notify_type.h:37
GUI present the user with a selectable list.
API for encryption/signing of emails.
#define TAILQ_INSERT_TAIL(head, elm, field)
Definition: queue.h:802
&#39;MH&#39; Mailbox type
Definition: mailbox.h:49
bool collapsed
Is this message part of a collapsed thread?
Definition: email.h:73
bool quiet
Inhibit status messages?
Definition: mailbox.h:117
void mutt_autocrypt_account_menu(void)
Display the Autocrypt account Menu.
int mx_tags_edit(struct Mailbox *m, const char *tags, char *buf, size_t buflen)
start the tag editor of the mailbox
Definition: mx.c:1263
int msg_tagged
How many messages are tagged?
Definition: mailbox.h:96
#define CHECK_READONLY
Is the mailbox readonly?
Definition: index.c:151
int vnum
Virtual message number.
Definition: email.h:87
#define SEND_NEWS
Reply to a news article.
Definition: send.h:102
int ci_send_message(SendFlags flags, struct Email *e_templ, const char *tempfile, struct Context *ctx, struct EmailList *el)
Send an email.
Definition: send.c:1892
WHERE bool OptSearchInvalid
(pseudo) used to invalidate the search pattern
Definition: options.h:51
void nm_db_debug_check(struct Mailbox *m)
Check if the database is open.
Definition: nm_db.c:322
enum MuttWindowSize size
Type of Window, e.g. MUTT_WIN_SIZE_FIXED.
Definition: mutt_window.h:95
AclFlags rights
ACL bits, see AclFlags.
Definition: mailbox.h:120
int mutt_messages_in_thread(struct Mailbox *m, struct Email *e, int flag)
Count the messages in a thread.
Definition: mutt_thread.c:1414
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:349
void update_index(struct Menu *menu, struct Context *ctx, int check, int oldcount, int index_hint)
Update the index.
Definition: index.c:612
void mutt_progress_init(struct Progress *progress, const char *msg, enum ProgressType type, size_t size)
Set up a progress bar.
Definition: progress.c:153
int pagelen
Number of entries per screen.
Definition: mutt_menu.h:92
char * tree
Character string to print thread tree.
Definition: email.h:93
struct Notify * notify
Notifications handler.
Definition: neomutt.h:37
WHERE bool OptRedrawTree
(pseudo) redraw the thread tree
Definition: options.h:49
bool TsSupported
Terminal Setting is supported.
Definition: terminal.c:43
#define STAILQ_NEXT(elm, field)
Definition: queue.h:397
SecurityFlags security
bit 0-10: flags, bit 11,12: application, bit 13: traditional pgp See: ncrypt/lib.h pgplib...
Definition: email.h:39
Definition: color.h:130
WHERE bool OptResortInit
(pseudo) used to force the next resort to be from scratch
Definition: options.h:50
struct Email * message
Email this Thread refers to.
Definition: thread.h:49
#define SEND_REPLY
Reply to sender.
Definition: send.h:88
#define MUTT_MATCH_FULL_ADDRESS
Match the full address.
Definition: pattern.h:77
int mutt_index_menu(struct MuttWindow *dlg)
Display a list of emails.
Definition: index.c:1114
#define MUTT_PAGER_LOGS
Logview mode.
Definition: pager.h:57
struct Hash * mutt_make_id_hash(struct Mailbox *m)
Create a Hash Table for message-ids.
Definition: mutt_thread.c:1456
NNTP-specific Mailbox data -.
Definition: lib.h:140
void mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:453
int mutt_window_mvaddstr(struct MuttWindow *win, int row, int col, const char *str)
Move the cursor and write a fixed string to a Window.
Definition: mutt_window.c:293
int mutt_window_move(struct MuttWindow *win, int row, int col)
Move the cursor in a Window.
Definition: mutt_window.c:279
Routines for adding user scores to emails.
void mutt_clear_pager_position(void)
Reset the pager&#39;s viewing position.
Definition: pager.c:1922
WHERE char * C_TsStatusFormat
Config: printf-like format string for the terminal&#39;s status (window title)
Definition: globals.h:146
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:312
int(* menu_color)(int line)
Calculate the colour for a line of the menu.
Definition: mutt_menu.h:144
#define MUTT_MAILBOX_CHECK_FORCE
Definition: mutt_mailbox.h:17
void * event_data
Data from notify_send()
Definition: observer.h:44
int max
Number of entries in the menu.
Definition: mutt_menu.h:88
void mutt_window_add_child(struct MuttWindow *parent, struct MuttWindow *child)
Add a child to Window.
Definition: mutt_window.c:471
&#39;Notmuch&#39; (virtual) Mailbox type
Definition: mailbox.h:53
LOFF_T offset
Where in the stream does this message begin?
Definition: email.h:83
WHERE bool C_DeleteUntag
Config: Untag messages when they are marked for deletion.
Definition: globals.h:209
GUI display a user-configurable status line.
MuttRedrawFlags redraw
When to redraw the screen.
Definition: mutt_menu.h:89
An Email conversation.
Definition: thread.h:34
bool mutt_regex_capture(const struct Regex *regex, const char *str, size_t nmatch, regmatch_t matches[])
match a regex against a string, with provided options
Definition: regex.c:594
Config has changed.
Definition: notify_type.h:34
bool notify_send(struct Notify *notify, enum NotifyType event_type, int event_subtype, void *event_data)
Send out a notification message.
Definition: notify.c:138
void mutt_set_header_color(struct Mailbox *m, struct Email *e)
Select a colour for a message.
Definition: index.c:3939
int * v2r
Mapping from virtual to real msgno.
Definition: mailbox.h:100
struct Connection * conn
Definition: lib.h:104
Window containing paged free-form text.
Definition: mutt_window.h:74
regex_t regex
Compiled regex.
Definition: color.h:38
#define MUTT_FORMAT_INDEX
This is a main index entry.
Definition: format_flags.h:36
char * mutt_str_strcat(char *buf, size_t buflen, const char *s)
Concatenate two strings.
Definition: string.c:395
GUI display a file/email/help in a viewport with paging.
void ci_bounce_message(struct Mailbox *m, struct EmailList *el)
Bounce an email.
Definition: commands.c:406
int imap_check_mailbox(struct Mailbox *m, bool force)
use the NOOP or IDLE command to poll for new mail
Definition: imap.c:1203
enum MailboxType mx_path_probe(const char *path)
Find a mailbox that understands a path.
Definition: mx.c:1310
char * driver_tags_get_with_hidden(struct TagList *list)
Get tags with hiddens.
Definition: tags.c:155
int offset
Row offset within the window to start the index.
Definition: mutt_menu.h:91
#define SEND_GROUP_REPLY
Reply to all.
Definition: send.h:89
char * data
String.
Definition: list.h:35
char * subject
Email&#39;s subject.
Definition: envelope.h:66
void mutt_buffer_expand_path(struct Buffer *buf)
Create the canonical path.
Definition: muttlib.c:341
MailboxType
Supported mailbox formats.
Definition: mailbox.h:42
int mutt_label_message(struct Mailbox *m, struct EmailList *el)
Let the user label a message.
Definition: mutt_header.c:125
Routines for managing attachments.
Log at debug level 1.
Definition: logging.h:40
bool flagged
Marked important?
Definition: email.h:43
void mutt_browser_select_dir(const char *f)
Remember the last directory selected.
Definition: browser.c:1136
void emaillist_clear(struct EmailList *el)
Drop a private list of Emails.
Definition: email.c:123
int mutt_do_pager(const char *banner, const char *tempfile, PagerFlags do_color, struct Pager *info)
Display some page-able text to the user.
Definition: curs_lib.c:664
int mx_mbox_sync(struct Mailbox *m, int *index_hint)
Save changes to mailbox.
Definition: mx.c:898
#define REDRAW_INDEX
Redraw the index.
Definition: mutt_menu.h:42
Window uses all available horizontal space.
Definition: mutt_window.h:34
static int main_change_folder(struct Menu *menu, int op, struct Mailbox *m, char *buf, size_t buflen, int *oldcount, int *index_hint, bool *pager_return)
Change to a different mailbox.
Definition: index.c:685
char * mutt_str_strdup(const char *str)
Copy a string, safely.
Definition: string.c:380
void mutt_help(enum MenuType menu, int wraplen)
Display the help menu.
Definition: help.c:444
bool collapsed
Are all threads collapsed?
Definition: context.h:48
bool deleted
Email is deleted.
Definition: email.h:45
void mutt_window_reflow(struct MuttWindow *win)
Resize a Window and its children.
Definition: mutt_window.c:346
struct MuttWindow * parent
Parent Window.
Definition: mutt_window.h:98
#define mutt_error(...)
Definition: logging.h:84
void mutt_query_menu(char *buf, size_t buflen)
Show the user the results of a Query.
Definition: query.c:694
char * followup_to
List of &#39;followup-to&#39; fields.
Definition: envelope.h:77
int mutt_str_strcasecmp(const char *a, const char *b)
Compare two strings ignoring case, safely.
Definition: string.c:651
void * compress_info
Compressed mbox module private data.
Definition: mailbox.h:123
Connection Library.
NeoMutt is about to close.
Definition: neomutt.h:50
void mutt_timeout_hook(void)
Execute any timeout hooks.
Definition: hook.c:812
void nm_db_longrun_done(struct Mailbox *m)
Finish a long transaction.
Definition: nm_db.c:304
static void collapse_all(struct Context *ctx, struct Menu *menu, int toggle)
Collapse/uncollapse all threads.
Definition: index.c:254
int mutt_select_sort(bool reverse)
Ask the user for a sort method.
Definition: commands.c:758
struct ColorLineList index_list
List of default colours applied to the index.
Definition: color.h:139
bool C_CollapseUnread
Config: Prevent the collapse of threads with unread emails.
Definition: index.c:104
int index
The absolute (unsorted) message number.
Definition: email.h:85
#define FREE(x)
Definition: memory.h:40
struct Mailbox * mx_path_resolve(const char *path)
Get a Mailbox for a path.
Definition: mx.c:1644
Mailbox has changed.
Definition: notify_type.h:38
Mapping between user-readable string and a constant.
Definition: mapping.h:29
Monitor files for changes.
void crypt_extract_keys_from_messages(struct Mailbox *m, struct EmailList *el)
Extract keys from a message.
Definition: crypt.c:857
#define MUTT_ACL_SEEN
Change the &#39;seen&#39; status of a message.
Definition: mailbox.h:72
#define STAILQ_EMPTY(head)
Definition: queue.h:345
Hide the cursor.
Definition: mutt_curses.h:81
struct MuttWindowList children
Children Windows.
Definition: mutt_window.h:99
#define STAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:321
void index_pager_shutdown(struct MuttWindow *dlg)
Clear up any non-Window parts.
Definition: index.c:4090
struct NntpAccountData * CurrentNewsSrv
Current NNTP news server.
Definition: nntp.c:79
short req_rows
Number of rows required.
Definition: mutt_window.h:88
void mutt_ts_icon(char *str)
Set the icon in the terminal title bar.
Definition: terminal.c:118
enum CommandResult km_bind(char *s, enum MenuType menu, int op, char *macro, char *desc)
Bind a key to a macro.
Definition: keymap.c:438
WHERE bool C_AutoTag
Config: Automatically apply actions to all tagged messages.
Definition: globals.h:202
void mutt_show_error(void)
Show the user an error message.
Definition: curs_lib.c:531
bool C_PgpAutoDecode
Config: Automatically decrypt PGP messages.
Definition: index.c:106
struct MuttWindow * MuttMessageWindow
Message Window.
Definition: mutt_window.c:47
struct MuttWindow * index_pager_init(void)
Allocate the Windows for the Index/Pager.
Definition: index.c:4006
#define PGP_TRADITIONAL_CHECKED
Email has a traditional (inline) signature.
Definition: lib.h:137
bool C_ChangeFolderNext
Config: Suggest the next folder, rather than the first when using &#39;<change-folder>&#39;.
Definition: index.c:101
Messages to be un-tagged.
Definition: mutt.h:108
bool changed
Mailbox has been modified.
Definition: mailbox.h:113
int mutt_change_flag(struct Mailbox *m, struct EmailList *el, bool bf)
Change the flag on a Message.
Definition: flags.c:432
void ctx_free(struct Context **ptr)
Free a Context.
Definition: context.c:49
Handling of global boolean variables.
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:38
int mx_msg_padding_size(struct Mailbox *m)
Bytes of padding between messages - Wrapper for MxOps::msg_padding_size()
Definition: mx.c:1520
New mail received in Mailbox.
Definition: mx.h:74
bool mx_tags_is_supported(struct Mailbox *m)
return true if mailbox support tagging
Definition: mx.c:1300
struct Notify * notify
Notifications handler.
Definition: mailbox.h:138
long hdr_offset
Offset in stream where the headers begin.
Definition: body.h:42
void mutt_ts_status(char *str)
Set the text of the terminal title bar.
Definition: terminal.c:104
#define CHECK_MSGCOUNT
Are there any messages?
Definition: index.c:149
static void update_index_threaded(struct Context *ctx, int check, int oldcount)
Update the index (if threaded)
Definition: index.c:487
#define SEND_GROUP_CHAT_REPLY
Reply to all recipients preserving To/Cc.
Definition: send.h:101
bool mutt_edit_content_type(struct Email *e, struct Body *b, FILE *fp)
Edit the content type of an attachment.
Definition: commands.c:1236
int current
Current entry.
Definition: mutt_menu.h:87
Cache commonly-used patterns.
Definition: pattern.h:87
int el_add_tagged(struct EmailList *el, struct Context *ctx, struct Email *e, bool use_tagged)
Get a list of the tagged Emails.
Definition: context.c:366
struct NntpMboxData * mutt_newsgroup_catchup(struct Mailbox *m, struct NntpAccountData *adata, char *group)
Catchup newsgroup.
Definition: newsrc.c:1297
struct Buffer pathbuf
Definition: mailbox.h:82
struct MuttWindow * win_index
Definition: mutt_menu.h:95
Convenience wrapper for the library headers.
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:585
#define SORT_REVERSE
Reverse the order of the sort.
Definition: sort2.h:86
char * mutt_compile_help(char *buf, size_t buflen, enum MenuType menu, const struct Mapping *items)
Create the text for the help menu.
Definition: help.c:116
struct ListHead references
message references (in reverse order)
Definition: envelope.h:81
A List node for strings.
Definition: list.h:33
void nntp_expand_path(char *buf, size_t buflen, struct ConnAccount *acct)
Make fully qualified url from newsgroup name.
Definition: newsrc.c:563
Match patterns to emails.
Window wants as much space as possible.
Definition: mutt_window.h:43
bool mutt_buffer_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:252
#define REDRAW_NO_FLAGS
No flags are set.
Definition: mutt_menu.h:41
Mailbox was reopened.
Definition: mx.h:76
int mutt_resend_message(FILE *fp, struct Context *ctx, struct Email *e_cur)
Resend an email.
Definition: send.c:1505
&#39;IMAP&#39; Mailbox type
Definition: mailbox.h:52
char * pattern
Limit pattern string.
Definition: context.h:39
#define N_(a)
Definition: message.h:32
bool C_UncollapseNew
Config: Open collapsed threads when new mail arrives.
Definition: index.c:108
Index Bar containing status info about the Index.
Definition: mutt_window.h:73
enum WindowType type
Window type, e.g. WT_SIDEBAR.
Definition: mutt_window.h:101
static void resort_index(struct Context *ctx, struct Menu *menu)
Resort the index.
Definition: index.c:449
int mutt_search_command(int cur, int op)
Perform a search.
Definition: pattern.c:2693
#define STAILQ_FIRST(head)
Definition: queue.h:347
const char * name
Name of config item that changed.
Definition: subset.h:71
static int ci_first_message(struct Context *ctx)
Get index of first new message.
Definition: index.c:373
WHERE bool OptNews
(pseudo) used to change reader mode
Definition: options.h:44
char * help
Quickref for the current menu.
Definition: mutt_menu.h:85
int mutt_ev_message(struct Mailbox *m, struct EmailList *el, enum EvMessage action)
Edit or view a message.
Definition: editmsg.c:264
void nm_db_longrun_init(struct Mailbox *m, bool writable)
Start a long transaction.
Definition: nm_db.c:289
int mutt_str_strcmp(const char *a, const char *b)
Compare two strings, safely.
Definition: string.c:638
int pair
Color-pair to use when displaying in the index.
Definition: email.h:79
int mutt_system(const char *cmd)
Run an external command.
Definition: system.c:52
#define mutt_buffer_enter_fname(prompt, fname, mailbox)
Definition: curs_lib.h:87
Log at debug level 3.
Definition: logging.h:42
#define mutt_uncollapse_thread(ctx, e)
Definition: mutt_thread.h:58
struct Hash * id_hash
Hash table by msg id.
Definition: mailbox.h:126
void mutt_draw_statusline(int cols, const char *buf, size_t buflen)
Draw a highlighted status bar.
Definition: index.c:927
#define REDRAW_CURRENT
Redraw the current line of the menu.
Definition: mutt_menu.h:45
#define SORT_MASK
Mask for the sort id.
Definition: sort2.h:85
short C_PagerIndexLines
Config: Number of index lines to display above the pager.
Definition: pager.c:87
A regular expression and a color to highlight a line.
Definition: color.h:36
bool C_CollapseFlagged
Config: Prevent the collapse of threads with flagged emails.
Definition: index.c:103
struct Email * last_tag
Last tagged msg (used to link threads)
Definition: context.h:41
The header of an Email.
Definition: envelope.h:54
void mutt_draw_tree(struct Context *ctx)
Draw a tree of threaded emails.
Definition: mutt_thread.c:285
int msgno
Number displayed to the user.
Definition: email.h:86
#define mutt_previous_subthread(e)
Definition: mutt_thread.h:68
const char * mutt_make_version(void)
Generate the NeoMutt version string.
Definition: muttlib.c:1558
void mutt_buffer_alloc(struct Buffer *buf, size_t new_size)
Make sure a buffer can store at least new_size bytes.
Definition: buffer.c:265
WHERE bool C_ArrowCursor
Config: Use an arrow &#39;->&#39; instead of highlighting in the index.
Definition: globals.h:193
void nntp_mailbox(struct Mailbox *m, char *buf, size_t buflen)
Get first newsgroup with new messages.
Definition: newsrc.c:1379