2 * Copyright notice from original mutt:
3 * Copyright (C) 1996-2000 Michael R. Elkins <me@mutt.org>
5 * Parts were written/modified by:
6 * Nico Golde <nico@ngolde.de>
8 * This file is part of mutt-ng, see http://www.muttng.org/.
9 * It's licensed under the GNU General Public License,
10 * please see the file GPL in the top level source directory.
13 #include <lib-lib/lib-lib.h>
15 #include <lib-ui/sidebar.h>
16 #include <lib-mx/mx.h>
27 #include "recvattach.h"
32 #include <imap/imap_private.h>
38 static const char *No_mailbox_is_open = N_("No mailbox is open.");
39 static const char *There_are_no_messages = N_("There are no messages.");
40 static const char *Mailbox_is_read_only = N_("Mailbox is read-only.");
41 static const char *Function_not_permitted_in_attach_message_mode =
42 N_("Function not permitted in attach-message mode.");
43 static const char *No_visible = N_("No visible messages.");
45 #define CHECK_IN_MAILBOX if (!Context) \
48 mutt_error (_(No_mailbox_is_open)); \
52 #define CHECK_MSGCOUNT if (!Context) \
55 mutt_error(_(No_mailbox_is_open)); \
58 else if (!Context->msgcount) \
61 mutt_error(_(There_are_no_messages)); \
65 #define CHECK_VISIBLE if (Context && menu->current >= Context->vcount) \
68 mutt_error(_(No_visible)); \
73 #define CHECK_READONLY if (Context->readonly) \
76 mutt_error(_(Mailbox_is_read_only)); \
80 #define CHECK_ATTACH if(option(OPTATTACHMSG)) \
83 mutt_error(_(Function_not_permitted_in_attach_message_mode)); \
87 #define CURHDR Context->hdrs[Context->v2r[menu->current]]
88 #define OLDHDR Context->hdrs[Context->v2r[menu->oldcurrent]]
89 #define UNREAD(h) mutt_thread_contains_unread (Context, h)
90 #define SW (option(OPTMBOXPANE)?SidebarWidth:0)
92 extern size_t UngetCount;
94 void index_make_entry (char *s, ssize_t l, struct menu_t * menu, int num)
96 format_flag flag = M_FORMAT_MAKEPRINT | M_FORMAT_INDEX;
97 int edgemsgno, reverse = Sort & SORT_REVERSE;
98 HEADER *h = Context->hdrs[Context->v2r[num]];
101 if ((Sort & SORT_MASK) == SORT_THREADS && h->tree) {
102 flag |= M_FORMAT_TREE; /* display the thread tree */
103 if (h->display_subject)
104 flag |= M_FORMAT_FORCESUBJ;
107 if (menu->top + menu->pagelen > menu->max)
108 edgemsgno = Context->v2r[menu->max - 1];
110 edgemsgno = Context->v2r[menu->top + menu->pagelen - 1];
113 edgemsgno = Context->v2r[menu->top];
115 for (tmp = h->thread->parent; tmp; tmp = tmp->parent) {
119 /* if no ancestor is visible on current screen, provisionally force
121 if (reverse ? tmp->message->msgno > edgemsgno : tmp->message->msgno <
123 flag |= M_FORMAT_FORCESUBJ;
126 else if (tmp->message->virtual >= 0)
129 if (flag & M_FORMAT_FORCESUBJ) {
130 for (tmp = h->thread->prev; tmp; tmp = tmp->prev) {
134 /* ...but if a previous sibling is available, don't force it */
135 if (reverse ? tmp->message->msgno >
136 edgemsgno : tmp->message->msgno < edgemsgno)
138 else if (tmp->message->virtual >= 0) {
139 flag &= ~M_FORMAT_FORCESUBJ;
147 _mutt_make_string (s, l, NONULL (HdrFmt), Context, h, flag);
150 int index_color (int index_no)
152 HEADER *h = Context->hdrs[Context->v2r[index_no]];
157 mutt_set_header_color (Context, h);
161 static int ci_next_undeleted (int msgno)
165 for (i = msgno + 1; i < Context->vcount; i++)
166 if (!Context->hdrs[Context->v2r[i]]->deleted)
171 static int ci_previous_undeleted (int msgno)
175 for (i = msgno - 1; i >= 0; i--)
176 if (!Context->hdrs[Context->v2r[i]]->deleted)
181 /* Return the index of the first new message, or failing that, the first
184 static int ci_first_message (void)
188 if (Context && Context->msgcount) {
189 for (i = 0; i < Context->vcount; i++) {
190 if (!Context->hdrs[Context->v2r[i]]->read &&
191 !Context->hdrs[Context->v2r[i]]->deleted) {
192 if (!Context->hdrs[Context->v2r[i]]->old)
201 /* If Sort is reverse and not threaded, the latest message is first.
202 * If Sort is threaded, the latest message is first iff exactly one
203 * of Sort and SortAux are reverse.
205 if (((Sort & SORT_REVERSE) && (Sort & SORT_MASK) != SORT_THREADS) ||
206 ((Sort & SORT_MASK) == SORT_THREADS &&
207 ((Sort ^ SortAux) & SORT_REVERSE)))
210 return (Context->vcount ? Context->vcount - 1 : 0);
215 /* This should be in mx.c, but it only gets used here. */
216 static int mx_toggle_write (CONTEXT * ctx)
222 mutt_error (_("Cannot toggle write on a readonly mailbox!"));
227 if (ctx->dontwrite) {
229 mutt_message (_("Changes to folder will be written on folder exit."));
233 mutt_message (_("Changes to folder will not be written."));
239 static void update_index (MUTTMENU * menu, CONTEXT * ctx __attribute__ ((unused)), int check,
240 int oldcount, int index_hint)
242 /* store pointers to the newly added messages */
243 HEADER **save_new = NULL;
246 /* take note of the current message */
248 if (menu->current < Context->vcount)
249 menu->oldcurrent = index_hint;
251 oldcount = 0; /* invalid message number! */
254 /* We are in a limited view. Check if the new message(s) satisfy
255 * the limit criteria. If they do, set their virtual msgno so that
256 * they will be visible in the limited view */
257 if (Context->pattern) {
258 #define THIS_BODY Context->hdrs[j]->content
259 for (j = (check == M_REOPENED) ? 0 : oldcount; j < Context->msgcount; j++) {
260 if (mutt_pattern_exec
261 (Context->limit_pattern, M_MATCH_FULL_ADDRESS, Context,
263 Context->hdrs[j]->virtual = Context->vcount;
264 Context->v2r[Context->vcount] = j;
265 Context->hdrs[j]->limited = 1;
268 THIS_BODY->length + THIS_BODY->offset - THIS_BODY->hdr_offset;
274 /* save the list of new messages */
275 if (oldcount && check != M_REOPENED && ((Sort & SORT_MASK) == SORT_THREADS)) {
276 save_new = p_new(HEADER*, Context->msgcount - oldcount);
277 for (j = oldcount; j < Context->msgcount; j++)
278 save_new[j - oldcount] = Context->hdrs[j];
281 /* if the mailbox was reopened, need to rethread from scratch */
282 mutt_sort_headers (Context, (check == M_REOPENED));
284 /* uncollapse threads with new mail */
285 if ((Sort & SORT_MASK) == SORT_THREADS) {
286 if (check == M_REOPENED) {
289 Context->collapsed = 0;
291 for (h = Context->tree; h; h = h->next) {
292 for (c = h; !c->message; c = c->child);
293 mutt_uncollapse_thread (Context, c->message);
295 mutt_set_virtual (Context);
298 for (j = 0; j < Context->msgcount - oldcount; j++) {
301 for (k = 0; k < Context->msgcount; k++) {
302 HEADER *h = Context->hdrs[k];
304 if (h == save_new[j] && (!Context->pattern || h->limited))
305 mutt_uncollapse_thread (Context, h);
309 mutt_set_virtual (Context);
315 /* restore the current message to the message it was pointing to */
316 for (j = 0; j < Context->vcount; j++) {
317 if (Context->hdrs[Context->v2r[j]]->index == menu->oldcurrent) {
324 if (menu->current < 0)
325 menu->current = ci_first_message ();
328 static void resort_index (MUTTMENU * menu)
331 HEADER *current = CURHDR;
334 mutt_sort_headers (Context, 0);
335 /* Restore the current message */
337 for (i = 0; i < Context->vcount; i++) {
338 if (Context->hdrs[Context->v2r[i]] == current) {
344 if ((Sort & SORT_MASK) == SORT_THREADS && menu->current < 0)
345 menu->current = mutt_parent_message (Context, current);
347 if (menu->current < 0)
348 menu->current = ci_first_message ();
350 menu->redraw = REDRAW_INDEX | REDRAW_STATUS;
353 struct mapping_t IndexHelp[] = {
354 {N_("Quit"), OP_QUIT},
355 {N_("Del"), OP_DELETE},
356 {N_("Undel"), OP_UNDELETE},
357 {N_("Save"), OP_SAVE},
358 {N_("Mail"), OP_MAIL},
359 {N_("Reply"), OP_REPLY},
360 {N_("Group"), OP_GROUP_REPLY},
361 {N_("Help"), OP_HELP},
366 struct mapping_t IndexNewsHelp[] = {
367 {N_("Quit"), OP_QUIT},
368 {N_("Del"), OP_DELETE},
369 {N_("Undel"), OP_UNDELETE},
370 {N_("Save"), OP_SAVE},
371 {N_("Post"), OP_POST},
372 {N_("Followup"), OP_FOLLOWUP},
373 {N_("Catchup"), OP_CATCHUP},
374 {N_("Help"), OP_HELP},
379 /* This function handles the message index window as well as commands returned
380 * from the pager (MENU_PAGER).
382 int mutt_index_menu (void)
384 char buf[LONG_STRING], helpstr[STRING];
387 int done = 0; /* controls when to exit the "event" loop */
389 int tag = 0; /* has the tag-prefix command been pressed? */
394 const char *cp; /* temporary variable. */
395 int index_hint; /* used to restore cursor position */
396 int do_buffy_notify = 1;
397 int closed = 0; /* did we OP_QUIT or OP_EXIT out of this menu? */
398 int attach_msg = option (OPTATTACHMSG);
400 menu = mutt_new_menu ();
401 menu->menu = MENU_MAIN;
403 menu->pagelen = LINES - 3;
404 menu->make_entry = (void *) index_make_entry;
405 menu->color = index_color;
406 menu->current = ci_first_message ();
407 menu->help = mutt_compile_help (helpstr, sizeof (helpstr), MENU_MAIN,
410 && (Context->magic ==
411 M_NNTP)) ? IndexNewsHelp :
416 buffy_check (0); /* force the buffy check after we enter the folder */
417 /* record folder we open to place sidebar indicator properly */
418 if (Context && Context->path)
419 sidebar_set_current (Context->path);
423 tag = 0; /* clear the tag-prefix */
425 menu->max = Context ? Context->vcount : 0;
426 oldcount = Context ? Context->msgcount : 0;
428 /* check if we need to resort the index because just about
429 * any 'op' below could do mutt_enter_command(), either here or
430 * from any new menu launched, and change $sort/$sort_aux
432 if (option (OPTNEEDRESORT) && Context && Context->msgcount)
435 if (option (OPTREDRAWTREE) && Context && Context->msgcount
436 && (Sort & SORT_MASK) == SORT_THREADS) {
437 mutt_draw_tree (Context);
438 menu->redraw |= REDRAW_STATUS;
439 unset_option (OPTREDRAWTREE);
442 if (Context && !attach_msg) {
445 /* check for new mail in the mailbox. If nonzero, then something has
446 * changed about the file (either we got new mail or the file was
447 * modified underneath us.)
450 imap_allow_reopen (Context);
452 index_hint = (Context->vcount && menu->current >= 0
453 && menu->current < Context->vcount) ? CURHDR->index : 0;
455 if ((check = mx_check_mailbox (Context, &index_hint, 0)) < 0) {
456 if (!Context->path) {
457 /* fatal error occurred */
459 menu->redraw = REDRAW_FULL;
461 set_option (OPTSEARCHINVALID);
463 else if (check == M_NEW_MAIL || check == M_REOPENED || check == M_FLAGS) {
464 update_index (menu, Context, check, oldcount, index_hint);
466 /* notify the user of new mail */
467 if (check == M_REOPENED)
469 ("Mailbox was externally modified. Flags may be wrong."));
470 else if (check == M_NEW_MAIL) {
471 /* on new mail: redraw sidebar */
473 mutt_message (_("New mail in this mailbox."));
475 if (mod_core.beep_new)
478 else if (check == M_FLAGS)
479 mutt_message (_("Mailbox was externally modified."));
481 /* avoid the message being overwritten by buffy */
484 menu->redraw = REDRAW_FULL;
485 menu->max = Context->vcount;
487 set_option (OPTSEARCHINVALID);
492 imap_disallow_reopen (Context);
495 /* check for new mail in the incoming folders */
497 if ((newcount = buffy_check (0)) != oldcount) {
498 menu->redraw |= REDRAW_STATUS;
499 menu->redraw |= REDRAW_SIDEBAR;
501 if (do_buffy_notify) {
502 if (buffy_notify () && mod_core.beep_new)
511 if (menu->redraw & REDRAW_SIDEBAR)
513 if (menu->redraw & REDRAW_FULL) {
514 menu_redraw_full (menu);
519 if (menu->menu == MENU_MAIN) {
520 if (Context && Context->hdrs && !(menu->current >= Context->vcount)) {
521 menu_check_recenter (menu);
523 if (menu->redraw & REDRAW_INDEX) {
524 menu_redraw_index (menu);
525 menu->redraw |= REDRAW_STATUS;
527 else if (menu->redraw & (REDRAW_MOTION_RESYNCH | REDRAW_MOTION))
528 menu_redraw_motion (menu);
529 else if (menu->redraw & REDRAW_CURRENT)
530 menu_redraw_current (menu);
533 if (menu->redraw & REDRAW_STATUS) {
534 menu_status_line (buf, sizeof (buf), menu, NONULL (Status));
535 CLEARLINE (option (OPTSTATUSONTOP) ? 0 : LINES - 2);
536 sidebar_draw_frames();
537 SETCOLOR (MT_COLOR_STATUS);
538 BKGDSET (MT_COLOR_STATUS);
539 move(option (OPTSTATUSONTOP) ? 0 : LINES - 2,SW);
540 mutt_paddstr (COLS-SW, buf);
541 SETCOLOR (MT_COLOR_NORMAL);
542 BKGDSET (MT_COLOR_NORMAL);
543 sidebar_set_buffystats (Context);
544 menu->redraw &= ~REDRAW_STATUS;
545 if (option (OPTXTERMSETTITLES)) {
546 menu_status_line(buf, sizeof(buf), menu, NONULL(XtermTitle));
547 printf("\033]2;%s\007", buf);
548 menu_status_line(buf, sizeof(buf), menu, NONULL(XtermIcon));
549 printf("\033]1;%s\007", buf);
555 if (menu->current < menu->max)
556 menu->oldcurrent = menu->current;
558 menu->oldcurrent = -1;
560 if (option (OPTBRAILLEFRIENDLY))
561 move (menu->current - menu->top + menu->offset, 0);
563 move (menu->current - menu->top + menu->offset, COLS - 1);
568 mutt_resize_screen ();
569 menu->redraw = REDRAW_FULL;
570 menu->menu = MENU_MAIN;
572 menu->top = 0; /* so we scroll the right amount */
574 * force a real complete redraw. clrtobot() doesn't seem to be able
575 * to handle every case without this.
577 clearok (stdscr, TRUE);
581 op = km_dokey (MENU_MAIN);
583 continue; /* either user abort or timeout */
587 /* special handling for the tag-prefix function */
588 if (op == OP_TAG_PREFIX) {
590 mutt_error (_("No mailbox is open."));
595 if (!Context->tagged) {
596 mutt_error (_("No tagged messages."));
602 /* give visual indication that the next command is a tag- command */
603 mvaddstr (LINES - 1, 0, "tag-");
606 /* get the real command */
607 if ((op = km_dokey (MENU_MAIN)) == OP_TAG_PREFIX) {
608 /* abort tag sequence */
609 CLEARLINE (LINES - 1);
613 else if (option (OPTAUTOTAG) && Context && Context->tagged)
616 if (op == OP_TAG_PREFIX_COND) {
618 mutt_error (_("No mailbox is open."));
623 if (!Context->tagged) {
626 while (UngetCount > 0) {
628 if (tmp.op == OP_END_COND)
631 mutt_message (_("Nothing to do."));
637 /* give visual indication that the next command is a tag- command */
638 mvaddstr (LINES - 1, 0, "tag-");
641 /* get the real command */
642 if ((op = km_dokey (MENU_MAIN)) == OP_TAG_PREFIX) {
643 /* abort tag sequence */
644 CLEARLINE (LINES - 1);
652 if (menu->current < menu->max)
653 menu->oldcurrent = menu->current;
655 menu->oldcurrent = -1;
657 mutt_curs_set (1); /* fallback from the pager */
661 unset_option (OPTNEWS); /* for any case */
666 /* ----------------------------------------------------------------------
671 menu_bottom_page (menu);
674 menu_first_entry (menu);
677 menu_middle_page (menu);
683 menu_half_down (menu);
686 menu_next_line (menu);
689 menu_prev_line (menu);
692 menu_next_page (menu);
695 menu_prev_page (menu);
698 menu_last_entry (menu);
701 menu_top_page (menu);
704 menu_current_top (menu);
706 case OP_CURRENT_MIDDLE:
707 menu_current_middle (menu);
709 case OP_CURRENT_BOTTOM:
710 menu_current_bottom (menu);
717 if (Context->magic == M_NNTP) {
720 if (op == OP_GET_MESSAGE) {
722 if (mutt_get_field (_("Enter Message-ID: "), buf, sizeof (buf), 0)
727 string_list_t *ref = CURHDR->env->references;
730 mutt_error (_("Article has no parent reference!"));
734 m_strcpy(buf, sizeof(buf), ref->data);
736 if (!Context->id_hash)
737 Context->id_hash = mutt_make_id_hash (Context);
738 if ((h = hash_find (Context->id_hash, buf))) {
739 if (h->virtual != -1) {
740 menu->current = h->virtual;
741 menu->redraw = REDRAW_MOTION_RESYNCH;
743 else if (h->collapsed) {
744 mutt_uncollapse_thread (Context, h);
745 mutt_set_virtual (Context);
746 menu->current = h->virtual;
747 menu->redraw = REDRAW_MOTION_RESYNCH;
750 mutt_error (_("Message not visible in limited view."));
753 if (nntp_check_msgid (Context, buf) == 0) {
754 h = Context->hdrs[Context->msgcount - 1];
755 mutt_sort_headers (Context, 0);
756 menu->current = h->virtual;
757 menu->redraw = REDRAW_FULL;
760 mutt_error (_("Article %s not found on server"), buf);
765 case OP_GET_CHILDREN:
766 case OP_RECONSTRUCT_THREAD:
768 if (Context->magic == M_NNTP) {
770 int old = CURHDR->index;
772 if (!CURHDR->env->message_id) {
773 mutt_error (_("No Message-ID. Unable to perform operation"));
778 if (!Context->id_hash)
779 Context->id_hash = mutt_make_id_hash (Context);
780 m_strcpy(buf, sizeof(buf), CURHDR->env->message_id);
782 if (op == OP_RECONSTRUCT_THREAD) {
783 string_list_t *ref = CURHDR->env->references;
786 nntp_check_msgid (Context, ref->data);
787 /* the last msgid in References is the root message */
789 m_strcpy(buf, sizeof(buf), ref->data);
793 mutt_message (_("Check for children of message..."));
795 if (nntp_check_children (Context, buf) == 0) {
796 mutt_sort_headers (Context, (op == OP_RECONSTRUCT_THREAD));
797 h = hash_find (Context->id_hash, buf);
798 /* if the root message was retrieved, move to it */
800 menu->current = h->virtual;
801 else /* try to restore old position */
802 for (i = 0; i < Context->msgcount; i++)
803 if (Context->hdrs[i]->index == old) {
804 menu->current = Context->hdrs[i]->virtual;
805 /* As an added courtesy, recenter the menu
806 * with the current entry at the middle of the screen */
807 menu_check_recenter (menu);
808 menu_current_middle (menu);
811 menu->redraw = REDRAW_FULL;
821 if (isdigit (LastKey))
822 mutt_ungetch (LastKey, 0);
824 if (mutt_get_field (_("Jump to message: "), buf, sizeof (buf), 0) != 0
828 if (!isdigit ((unsigned char) buf[0])) {
829 mutt_error (_("Argument must be a message number."));
835 if (i > 0 && i <= Context->msgcount) {
836 for (j = i - 1; j < Context->msgcount; j++) {
837 if (Context->hdrs[j]->virtual != -1)
840 if (j >= Context->msgcount) {
841 for (j = i - 2; j >= 0; j--) {
842 if (Context->hdrs[j]->virtual != -1)
848 menu->current = Context->hdrs[j]->virtual;
849 if (menu->menu == MENU_PAGER) {
850 op = OP_DISPLAY_MESSAGE;
854 menu->redraw = REDRAW_MOTION;
857 mutt_error (_("That message is not visible."));
860 mutt_error (_("Invalid message number."));
864 /* --------------------------------------------------------------------
865 * `index' specific commands
868 case OP_MAIN_DELETE_PATTERN:
874 CHECK_MX_ACL (Context, ACL_DELETE, _("Deletion"));
877 mutt_pattern_func (M_DELETE, _("Delete messages matching: "));
878 menu->redraw = REDRAW_INDEX | REDRAW_STATUS;
881 case OP_MAIN_FETCH_MAIL:
885 menu->redraw = REDRAW_FULL;
890 mutt_help (MENU_MAIN);
891 menu->redraw = REDRAW_FULL;
894 case OP_MAIN_SHOW_LIMIT:
896 if (!Context->pattern)
897 mutt_message (_("No limit pattern is in effect."));
902 /* i18n: ask for a limit to apply */
903 snprintf (buffer, sizeof (buffer), _("Limit: %s"), Context->pattern);
904 mutt_message ("%s", buffer);
912 menu->oldcurrent = (Context->vcount && menu->current >= 0
914 Context->vcount) ? CURHDR->index : -1;
915 if (op == OP_TOGGLE_READ) {
916 char buffer[LONG_STRING];
918 if (m_strncmp (Context->pattern, "!~R!~D~s", 8) != 0) {
919 snprintf (buffer, sizeof (buffer), "!~R!~D~s%s",
920 Context->pattern ? Context->pattern : ".*");
921 set_option (OPTHIDEREAD);
924 m_strcpy(buf, sizeof(buf), Context->pattern + 8);
925 if (m_strncmp (buf, ".*", 2) == 0)
926 snprintf (buf, sizeof (buf), "~A");
927 unset_option (OPTHIDEREAD);
929 p_delete(&Context->pattern);
930 Context->pattern = m_strdup(buf);
932 if ((op == OP_TOGGLE_READ && mutt_pattern_func (M_LIMIT, NULL) == 0) ||
933 mutt_pattern_func (M_LIMIT, _("Limit to messages matching: ")) == 0)
935 if (menu->oldcurrent >= 0) {
936 /* try to find what used to be the current message */
938 for (i = 0; i < Context->vcount; i++)
939 if (Context->hdrs[Context->v2r[i]]->index == menu->oldcurrent) {
943 if (menu->current < 0)
948 menu->redraw = REDRAW_INDEX | REDRAW_STATUS;
949 if (Context->msgcount && (Sort & SORT_MASK) == SORT_THREADS)
950 mutt_draw_tree (Context);
951 menu->redraw = REDRAW_FULL;
953 if (Context->pattern)
954 mutt_message _("To view all messages, limit to \"all\".");
965 if (query_quadoption2(mod_core.quit, _("Quit Madmutt?")) == M_YES) {
968 oldcount = Context ? Context->msgcount : 0;
971 || (check = mx_close_mailbox (Context, &index_hint)) == 0)
974 if (check == M_NEW_MAIL || check == M_REOPENED)
975 update_index (menu, Context, check, oldcount, index_hint);
977 menu->redraw = REDRAW_FULL; /* new mail arrived? */
978 set_option (OPTSEARCHINVALID);
985 clearok (stdscr, TRUE);
986 menu->redraw = REDRAW_FULL;
990 case OP_SEARCH_REVERSE:
992 case OP_SEARCH_OPPOSITE:
996 if ((menu->current = mutt_search_command (menu->current, op)) == -1)
997 menu->current = menu->oldcurrent;
999 menu->redraw = REDRAW_MOTION;
1003 case OP_SORT_REVERSE:
1005 if (mutt_select_sort ((op == OP_SORT_REVERSE)) == 0) {
1006 if (Context && Context->msgcount) {
1007 resort_index (menu);
1008 set_option (OPTSEARCHINVALID);
1017 if (tag && !option (OPTAUTOTAG)) {
1018 for (j = 0; j < Context->vcount; j++)
1019 mutt_set_flag (Context, Context->hdrs[Context->v2r[j]], M_TAG, 0);
1020 menu->redraw = REDRAW_STATUS | REDRAW_INDEX;
1023 mutt_set_flag (Context, CURHDR, M_TAG, !CURHDR->tagged);
1024 Context->last_tag = CURHDR->tagged ? CURHDR :
1025 ((Context->last_tag == CURHDR && !CURHDR->tagged)
1026 ? NULL : Context->last_tag);
1027 menu->redraw = REDRAW_STATUS;
1028 if (option (OPTRESOLVE) && menu->current < Context->vcount - 1) {
1030 menu->redraw |= REDRAW_MOTION_RESYNCH;
1033 menu->redraw |= REDRAW_CURRENT;
1037 case OP_MAIN_TAG_PATTERN:
1041 mutt_pattern_func (M_TAG, _("Tag messages matching: "));
1042 menu->redraw = REDRAW_INDEX | REDRAW_STATUS;
1045 case OP_MAIN_UNDELETE_PATTERN:
1051 CHECK_MX_ACL (Context, ACL_DELETE, _("Undeletion"));
1053 if (mutt_pattern_func (M_UNDELETE, _("Undelete messages matching: ")) ==
1055 menu->redraw = REDRAW_INDEX | REDRAW_STATUS;
1058 case OP_MAIN_UNTAG_PATTERN:
1062 if (mutt_pattern_func (M_UNTAG, _("Untag messages matching: ")) == 0)
1063 menu->redraw = REDRAW_INDEX | REDRAW_STATUS;
1066 /* --------------------------------------------------------------------
1067 * The following operations can be performed inside of the pager.
1070 case OP_MAIN_IMAP_FETCH:
1071 if (Context->magic == M_IMAP)
1072 imap_check_mailbox (Context, &index_hint, 1);
1075 case OP_MAIN_SYNC_FOLDER:
1077 if (Context && !Context->msgcount)
1084 int oldvcount = Context->vcount;
1085 oldcount = Context->msgcount;
1089 /* calculate the number of messages _above_ the cursor,
1090 * so we can keep the cursor on the current message
1092 for (j = 0; j <= menu->current; j++) {
1093 if (Context->hdrs[Context->v2r[j]]->deleted)
1097 if ((check = mx_sync_mailbox (Context, &index_hint)) == 0) {
1098 if (Context->vcount != oldvcount)
1099 menu->current -= dcount;
1100 set_option (OPTSEARCHINVALID);
1102 else if (check == M_NEW_MAIL || check == M_REOPENED)
1103 update_index (menu, Context, check, oldcount, index_hint);
1106 * do a sanity check even if mx_sync_mailbox failed.
1109 if (menu->current < 0 || menu->current >= Context->vcount)
1110 menu->current = ci_first_message ();
1113 /* check for a fatal error, or all messages deleted */
1117 /* if we were in the pager, redisplay the message */
1118 if (menu->menu == MENU_PAGER) {
1119 op = OP_DISPLAY_MESSAGE;
1123 menu->redraw = REDRAW_FULL;
1126 case OP_SIDEBAR_OPEN:
1127 case OP_MAIN_CHANGE_FOLDER:
1128 case OP_MAIN_CHANGE_FOLDER_READONLY:
1130 case OP_MAIN_CHANGE_GROUP:
1131 case OP_MAIN_CHANGE_GROUP_READONLY:
1133 if (attach_msg || option (OPTREADONLY) ||
1135 op == OP_MAIN_CHANGE_GROUP_READONLY ||
1137 op == OP_MAIN_CHANGE_FOLDER_READONLY)
1143 cp = _("Open mailbox in read-only mode");
1145 cp = _("Open mailbox");
1149 unset_option (OPTNEWS);
1150 if (op == OP_MAIN_CHANGE_GROUP || op == OP_MAIN_CHANGE_GROUP_READONLY) {
1151 set_option (OPTNEWS);
1152 if (!(CurrentNewsSrv = mutt_select_newsserver (NewsServer)))
1155 cp = _("Open newsgroup in read-only mode");
1157 cp = _("Open newsgroup");
1158 nntp_buffy (buf, sizeof (buf));
1163 if (Context && Context->path)
1164 m_strcpy(buf, sizeof(buf), Context->path);
1165 if (op != OP_SIDEBAR_OPEN)
1166 buffy_next (buf, sizeof (buf));
1169 if (op == OP_SIDEBAR_OPEN) {
1170 m_strcpy(buf, sizeof(buf), sidebar_get_current());
1172 else if (mutt_enter_fname (cp, buf, sizeof (buf), &menu->redraw, 1) == -1) {
1173 if (menu->menu == MENU_PAGER) {
1174 op = OP_DISPLAY_MESSAGE;
1180 CLEARLINE (LINES - 1);
1185 if (option (OPTNEWS)) {
1186 unset_option (OPTNEWS);
1187 nntp_expand_path (buf, sizeof (buf), &CurrentNewsSrv->conn->account);
1191 mutt_expand_path (buf, sizeof (buf));
1192 if (mx_get_magic (buf) <= 0) {
1193 mutt_error (_("%s is not a mailbox."), buf);
1196 m_strreplace(&CurrentFolder, buf);
1201 if (Context->cinfo && Context->realpath)
1202 m_strreplace(&LastFolder, Context->realpath);
1204 m_strreplace(&LastFolder, Context->path);
1205 oldcount = Context ? Context->msgcount : 0;
1207 if ((check = mx_close_mailbox (Context, &index_hint)) != 0) {
1208 if (check == M_NEW_MAIL || check == M_REOPENED)
1209 update_index (menu, Context, check, oldcount, index_hint);
1211 set_option (OPTSEARCHINVALID);
1212 menu->redraw = REDRAW_INDEX | REDRAW_STATUS;
1220 /* Set CurrentMenu to MENU_MAIN before executing any folder
1221 * hooks so that all the index menu functions are available to
1225 CurrentMenu = MENU_MAIN;
1226 mutt_folder_hook (buf);
1228 if ((Context = mx_open_mailbox (buf, flags, NULL)) != NULL) {
1229 menu->current = ci_first_message ();
1233 sidebar_set_current (buf);
1236 /* buffy_check() must be done with mail-reader mode! */
1237 menu->help = mutt_compile_help (helpstr, sizeof (helpstr), MENU_MAIN,
1239 && (Context->magic ==
1240 M_NNTP)) ? IndexNewsHelp :
1243 mutt_clear_error ();
1244 buffy_check (0); /* force the buffy check after we have changed
1246 menu->redraw = REDRAW_FULL;
1247 set_option (OPTSEARCHINVALID);
1250 case OP_DISPLAY_MESSAGE:
1251 case OP_DISPLAY_HEADERS: /* don't weed the headers */
1256 * toggle the weeding of headers so that a user can press the key
1257 * again while reading the message.
1259 if (op == OP_DISPLAY_HEADERS)
1260 toggle_option (OPTWEED);
1262 unset_option (OPTNEEDRESORT);
1264 if ((Sort & SORT_MASK) == SORT_THREADS && CURHDR->collapsed) {
1265 mutt_uncollapse_thread (Context, CURHDR);
1266 mutt_set_virtual (Context);
1267 if (option (OPTUNCOLLAPSEJUMP))
1268 menu->current = mutt_thread_next_unread (Context, CURHDR);
1271 if (tag || !(CURHDR->security & PGP_TRADITIONAL_CHECKED))
1272 mutt_check_traditional_pgp (tag ? NULL : CURHDR, &menu->redraw);
1274 if ((op = mutt_display_message (CURHDR)) == -1) {
1275 unset_option (OPTNEEDRESORT);
1279 menu->menu = MENU_PAGER;
1280 menu->oldcurrent = menu->current;
1286 if (menu->menu == MENU_MAIN && attach_msg) {
1291 if ((menu->menu == MENU_MAIN)
1292 && (query_quadoption2(mod_core.quit,
1293 _("Exit Madmutt without saving?")) == M_YES))
1296 mx_fastclose_mailbox (Context);
1308 mutt_edit_content_type (CURHDR, CURHDR->content, NULL);
1309 /* if we were in the pager, redisplay the message */
1310 if (menu->menu == MENU_PAGER) {
1311 op = OP_DISPLAY_MESSAGE;
1315 menu->redraw = REDRAW_CURRENT;
1318 case OP_MAIN_BREAK_THREAD:
1324 if ((Sort & SORT_MASK) != SORT_THREADS)
1325 mutt_error (_("Threading is not enabled."));
1329 HEADER *oldcur = CURHDR;
1331 mutt_break_thread (CURHDR);
1332 mutt_sort_headers (Context, 1);
1333 menu->current = oldcur->virtual;
1336 Context->changed = 1;
1337 mutt_message _("Thread broken");
1339 if (menu->menu == MENU_PAGER) {
1340 op = OP_DISPLAY_MESSAGE;
1344 menu->redraw |= REDRAW_INDEX;
1348 case OP_MAIN_LINK_THREADS:
1354 if ((Sort & SORT_MASK) != SORT_THREADS)
1355 mutt_error (_("Threading is not enabled."));
1357 else if (!CURHDR->env->message_id)
1358 mutt_error (_("No Message-ID: header available to link thread"));
1360 else if (!tag && (!Context->last_tag || !Context->last_tag->tagged))
1361 mutt_error (_("First, please tag a message to be linked here"));
1364 HEADER *oldcur = CURHDR;
1366 if (mutt_link_threads (CURHDR, tag ? NULL : Context->last_tag,
1368 mutt_sort_headers (Context, 1);
1369 menu->current = oldcur->virtual;
1371 Context->changed = 1;
1372 mutt_message _("Threads linked");
1375 mutt_error (_("No thread linked"));
1378 if (menu->menu == MENU_PAGER) {
1379 op = OP_DISPLAY_MESSAGE;
1383 menu->redraw |= REDRAW_STATUS | REDRAW_INDEX;
1386 case OP_MAIN_NEXT_UNDELETED:
1390 if (menu->current >= Context->vcount - 1) {
1391 if (menu->menu == MENU_MAIN)
1392 mutt_error (_("You are on the last message."));
1396 if ((menu->current = ci_next_undeleted (menu->current)) == -1) {
1397 menu->current = menu->oldcurrent;
1398 if (menu->menu == MENU_MAIN)
1399 mutt_error (_("No undeleted messages."));
1401 else if (menu->menu == MENU_PAGER) {
1402 op = OP_DISPLAY_MESSAGE;
1406 menu->redraw = REDRAW_MOTION;
1413 if (menu->current >= Context->vcount - 1) {
1414 if (menu->menu == MENU_MAIN)
1415 mutt_error (_("You are on the last message."));
1420 if (menu->menu == MENU_PAGER) {
1421 op = OP_DISPLAY_MESSAGE;
1425 menu->redraw = REDRAW_MOTION;
1428 case OP_MAIN_PREV_UNDELETED:
1432 if (menu->current < 1) {
1433 mutt_error (_("You are on the first message."));
1437 if ((menu->current = ci_previous_undeleted (menu->current)) == -1) {
1438 menu->current = menu->oldcurrent;
1439 if (menu->menu == MENU_MAIN)
1440 mutt_error (_("No undeleted messages."));
1442 else if (menu->menu == MENU_PAGER) {
1443 op = OP_DISPLAY_MESSAGE;
1447 menu->redraw = REDRAW_MOTION;
1454 if (menu->current < 1) {
1455 if (menu->menu == MENU_MAIN)
1456 mutt_error (_("You are on the first message."));
1461 if (menu->menu == MENU_PAGER) {
1462 op = OP_DISPLAY_MESSAGE;
1466 menu->redraw = REDRAW_MOTION;
1469 case OP_DECRYPT_COPY:
1470 case OP_DECRYPT_SAVE:
1471 case OP_COPY_MESSAGE:
1473 case OP_DECODE_COPY:
1474 case OP_DECODE_SAVE:
1477 if (mutt_save_message (tag ? NULL : CURHDR,
1478 (op == OP_DECRYPT_SAVE) ||
1479 (op == OP_SAVE) || (op == OP_DECODE_SAVE),
1480 (op == OP_DECODE_SAVE) || (op == OP_DECODE_COPY),
1481 (op == OP_DECRYPT_SAVE)
1482 || (op == OP_DECRYPT_COPY)
1483 || 0, &menu->redraw) == 0 && (op == OP_SAVE
1490 menu->redraw |= REDRAW_INDEX;
1491 else if (option (OPTRESOLVE)) {
1492 if ((menu->current = ci_next_undeleted (menu->current)) == -1) {
1493 menu->current = menu->oldcurrent;
1494 menu->redraw |= REDRAW_CURRENT;
1497 menu->redraw |= REDRAW_MOTION_RESYNCH;
1500 menu->redraw |= REDRAW_CURRENT;
1504 case OP_MAIN_NEXT_NEW:
1505 case OP_MAIN_NEXT_UNREAD:
1506 case OP_MAIN_PREV_NEW:
1507 case OP_MAIN_PREV_UNREAD:
1508 case OP_MAIN_NEXT_NEW_THEN_UNREAD:
1509 case OP_MAIN_PREV_NEW_THEN_UNREAD:
1512 int first_unread = -1;
1520 for (j = 0; j != Context->vcount; j++) {
1521 #define CURHDRi Context->hdrs[Context->v2r[i]]
1522 if (op == OP_MAIN_NEXT_NEW || op == OP_MAIN_NEXT_UNREAD
1523 || op == OP_MAIN_NEXT_NEW_THEN_UNREAD) {
1525 if (i > Context->vcount - 1) {
1526 mutt_message _("Search wrapped to top.");
1534 mutt_message _("Search wrapped to bottom.");
1536 i = Context->vcount - 1;
1540 if (CURHDRi->collapsed && (Sort & SORT_MASK) == SORT_THREADS) {
1541 if (UNREAD (CURHDRi) && first_unread == -1)
1543 if (UNREAD (CURHDRi) == 1 && first_new == -1)
1546 else if ((!CURHDRi->deleted && !CURHDRi->read)) {
1547 if (first_unread == -1)
1549 if ((!CURHDRi->old) && first_new == -1)
1553 if ((op == OP_MAIN_NEXT_UNREAD || op == OP_MAIN_PREV_UNREAD) &&
1556 if ((op == OP_MAIN_NEXT_NEW || op == OP_MAIN_PREV_NEW ||
1557 op == OP_MAIN_NEXT_NEW_THEN_UNREAD
1558 || op == OP_MAIN_PREV_NEW_THEN_UNREAD)
1563 if ((op == OP_MAIN_NEXT_NEW || op == OP_MAIN_PREV_NEW ||
1564 op == OP_MAIN_NEXT_NEW_THEN_UNREAD
1565 || op == OP_MAIN_PREV_NEW_THEN_UNREAD)
1567 menu->current = first_new;
1568 else if ((op == OP_MAIN_NEXT_UNREAD || op == OP_MAIN_PREV_UNREAD ||
1569 op == OP_MAIN_NEXT_NEW_THEN_UNREAD
1570 || op == OP_MAIN_PREV_NEW_THEN_UNREAD)
1571 && first_unread != -1)
1572 menu->current = first_unread;
1574 if (menu->current == -1) {
1575 menu->current = menu->oldcurrent;
1576 mutt_error ("%s%s.",
1577 (op == OP_MAIN_NEXT_NEW
1579 OP_MAIN_PREV_NEW) ? _("No new messages") :
1580 _("No unread messages"),
1581 Context->pattern ? _(" in this limited view") : "");
1583 else if (menu->menu == MENU_PAGER) {
1584 op = OP_DISPLAY_MESSAGE;
1588 menu->redraw = REDRAW_MOTION;
1591 case OP_FLAG_MESSAGE:
1597 CHECK_MX_ACL (Context, ACL_WRITE, _("Flagging"));
1600 for (j = 0; j < Context->vcount; j++) {
1601 if (Context->hdrs[Context->v2r[j]]->tagged)
1602 mutt_set_flag (Context, Context->hdrs[Context->v2r[j]],
1603 M_FLAG, !Context->hdrs[Context->v2r[j]]->flagged);
1606 menu->redraw |= REDRAW_INDEX;
1609 mutt_set_flag (Context, CURHDR, M_FLAG, !CURHDR->flagged);
1610 if (option (OPTRESOLVE)) {
1611 if ((menu->current = ci_next_undeleted (menu->current)) == -1) {
1612 menu->current = menu->oldcurrent;
1613 menu->redraw = REDRAW_CURRENT;
1616 menu->redraw = REDRAW_MOTION_RESYNCH;
1619 menu->redraw = REDRAW_CURRENT;
1621 menu->redraw |= REDRAW_STATUS;
1630 CHECK_MX_ACL (Context, ACL_SEEN, _("Toggling"));
1633 for (j = 0; j < Context->vcount; j++) {
1634 if (Context->hdrs[Context->v2r[j]]->tagged) {
1635 if (Context->hdrs[Context->v2r[j]]->read ||
1636 Context->hdrs[Context->v2r[j]]->old)
1637 mutt_set_flag (Context, Context->hdrs[Context->v2r[j]], M_NEW,
1640 mutt_set_flag (Context, Context->hdrs[Context->v2r[j]], M_READ,
1644 menu->redraw = REDRAW_STATUS | REDRAW_INDEX;
1647 if (CURHDR->read || CURHDR->old)
1648 mutt_set_flag (Context, CURHDR, M_NEW, 1);
1650 mutt_set_flag (Context, CURHDR, M_READ, 1);
1652 if (option (OPTRESOLVE)) {
1653 if ((menu->current = ci_next_undeleted (menu->current)) == -1) {
1654 menu->current = menu->oldcurrent;
1655 menu->redraw = REDRAW_CURRENT;
1658 menu->redraw = REDRAW_MOTION_RESYNCH;
1661 menu->redraw = REDRAW_CURRENT;
1662 menu->redraw |= REDRAW_STATUS;
1666 case OP_TOGGLE_WRITE:
1669 if (mx_toggle_write (Context) == 0)
1670 menu->redraw |= REDRAW_STATUS;
1673 case OP_MAIN_NEXT_THREAD:
1674 case OP_MAIN_NEXT_SUBTHREAD:
1675 case OP_MAIN_PREV_THREAD:
1676 case OP_MAIN_PREV_SUBTHREAD:
1681 case OP_MAIN_NEXT_THREAD:
1682 menu->current = mutt_next_thread (CURHDR);
1685 case OP_MAIN_NEXT_SUBTHREAD:
1686 menu->current = mutt_next_subthread (CURHDR);
1689 case OP_MAIN_PREV_THREAD:
1690 menu->current = mutt_previous_thread (CURHDR);
1693 case OP_MAIN_PREV_SUBTHREAD:
1694 menu->current = mutt_previous_subthread (CURHDR);
1698 if (menu->current < 0) {
1699 menu->current = menu->oldcurrent;
1700 if (op == OP_MAIN_NEXT_THREAD || op == OP_MAIN_NEXT_SUBTHREAD)
1701 mutt_error (_("No more threads."));
1704 mutt_error (_("You are on the first thread."));
1706 else if (menu->menu == MENU_PAGER) {
1707 op = OP_DISPLAY_MESSAGE;
1711 menu->redraw = REDRAW_MOTION;
1714 case OP_MAIN_PARENT_MESSAGE:
1719 if ((menu->current = mutt_parent_message (Context, CURHDR)) < 0) {
1720 menu->current = menu->oldcurrent;
1722 else if (menu->menu == MENU_PAGER) {
1723 op = OP_DISPLAY_MESSAGE;
1727 menu->redraw = REDRAW_MOTION;
1730 case OP_MAIN_SET_FLAG:
1731 case OP_MAIN_CLEAR_FLAG:
1737 if (mutt_change_flag (tag ? NULL : CURHDR, (op == OP_MAIN_SET_FLAG)) == 0) {
1738 menu->redraw = REDRAW_STATUS;
1740 menu->redraw |= REDRAW_INDEX;
1741 else if (option (OPTRESOLVE)) {
1742 if ((menu->current = ci_next_undeleted (menu->current)) == -1) {
1743 menu->current = menu->oldcurrent;
1744 menu->redraw |= REDRAW_CURRENT;
1747 menu->redraw |= REDRAW_MOTION_RESYNCH;
1750 menu->redraw |= REDRAW_CURRENT;
1754 case OP_MAIN_COLLAPSE_THREAD:
1758 if ((Sort & SORT_MASK) != SORT_THREADS) {
1759 mutt_error (_("Threading is not enabled."));
1764 if (CURHDR->collapsed) {
1765 menu->current = mutt_uncollapse_thread (Context, CURHDR);
1766 mutt_set_virtual (Context);
1767 if (option (OPTUNCOLLAPSEJUMP))
1768 menu->current = mutt_thread_next_unread (Context, CURHDR);
1770 else if (option (OPTCOLLAPSEUNREAD) || !UNREAD (CURHDR)) {
1771 menu->current = mutt_collapse_thread (Context, CURHDR);
1772 mutt_set_virtual (Context);
1775 mutt_error (_("Thread contains unread messages."));
1780 menu->redraw = REDRAW_INDEX | REDRAW_STATUS;
1784 case OP_MAIN_COLLAPSE_ALL:
1788 if ((Sort & SORT_MASK) != SORT_THREADS) {
1789 mutt_error (_("Threading is not enabled."));
1796 THREAD *thread, *top;
1799 if (CURHDR->collapsed)
1800 final = mutt_uncollapse_thread (Context, CURHDR);
1801 else if (option (OPTCOLLAPSEUNREAD) || !UNREAD (CURHDR))
1802 final = mutt_collapse_thread (Context, CURHDR);
1804 final = CURHDR->virtual;
1806 base = Context->hdrs[Context->v2r[final]];
1808 top = Context->tree;
1809 Context->collapsed = !Context->collapsed;
1810 while ((thread = top) != NULL) {
1811 while (!thread->message)
1812 thread = thread->child;
1813 h = thread->message;
1815 if (h->collapsed != Context->collapsed) {
1817 mutt_uncollapse_thread (Context, h);
1818 else if (option (OPTCOLLAPSEUNREAD) || !UNREAD (h))
1819 mutt_collapse_thread (Context, h);
1824 mutt_set_virtual (Context);
1825 for (j = 0; j < Context->vcount; j++) {
1826 if (Context->hdrs[Context->v2r[j]]->index == base->index) {
1832 menu->redraw = REDRAW_INDEX | REDRAW_STATUS;
1836 /* --------------------------------------------------------------------
1837 * These functions are invoked directly from the internal-pager
1840 case OP_BOUNCE_MESSAGE:
1845 ci_bounce_message (tag ? NULL : CURHDR, &menu->redraw);
1848 case OP_CREATE_ALIAS:
1850 mutt_create_alias (Context
1851 && Context->vcount ? CURHDR->env : NULL, NULL);
1852 MAYBE_REDRAW (menu->redraw);
1853 menu->redraw |= REDRAW_CURRENT;
1858 mutt_query_menu (NULL, 0);
1859 MAYBE_REDRAW (menu->redraw);
1862 case OP_PURGE_MESSAGE:
1869 CHECK_MX_ACL (Context, ACL_DELETE, _("Deletion"));
1872 mutt_tag_set_flag (M_DELETE, 1);
1873 mutt_tag_set_flag (M_PURGED, (op != OP_PURGE_MESSAGE) ? 0 : 1);
1874 if (option (OPTDELETEUNTAG))
1875 mutt_tag_set_flag (M_TAG, 0);
1876 menu->redraw = REDRAW_INDEX;
1879 mutt_set_flag (Context, CURHDR, M_DELETE, 1);
1880 mutt_set_flag (Context, CURHDR, M_PURGED,
1881 (op != OP_PURGE_MESSAGE) ? 0 : 1);
1882 if (option (OPTDELETEUNTAG))
1883 mutt_set_flag (Context, CURHDR, M_TAG, 0);
1884 if (option (OPTRESOLVE)) {
1885 if ((menu->current = ci_next_undeleted (menu->current)) == -1) {
1886 menu->current = menu->oldcurrent;
1887 menu->redraw = REDRAW_CURRENT;
1889 else if (menu->menu == MENU_PAGER) {
1890 op = OP_DISPLAY_MESSAGE;
1894 menu->redraw |= REDRAW_MOTION_RESYNCH;
1897 menu->redraw = REDRAW_CURRENT;
1899 menu->redraw |= REDRAW_STATUS;
1902 case OP_DELETE_THREAD:
1903 case OP_DELETE_SUBTHREAD:
1909 CHECK_MX_ACL (Context, ACL_DELETE, _("Deletion"));
1911 rc = mutt_thread_set_flag (CURHDR, M_DELETE, 1,
1912 op == OP_DELETE_THREAD ? 0 : 1);
1915 if (option (OPTDELETEUNTAG))
1916 mutt_thread_set_flag (CURHDR, M_TAG, 0,
1917 op == OP_DELETE_THREAD ? 0 : 1);
1918 if (option (OPTRESOLVE))
1919 if ((menu->current = ci_next_undeleted (menu->current)) == -1)
1920 menu->current = menu->oldcurrent;
1921 menu->redraw = REDRAW_INDEX | REDRAW_STATUS;
1927 if (Context && Context->magic == M_NNTP) {
1928 if (mutt_newsgroup_catchup (CurrentNewsSrv,
1929 ((nntp_data_t *) Context->data)->group))
1930 menu->redraw = REDRAW_INDEX | REDRAW_STATUS;
1935 case OP_DISPLAY_ADDRESS:
1939 mutt_display_address (CURHDR->env);
1942 case OP_ENTER_COMMAND:
1944 CurrentMenu = MENU_MAIN;
1945 mutt_enter_command ();
1946 mutt_check_rescore (Context);
1947 if (option (OPTFORCEREDRAWINDEX))
1948 menu->redraw = REDRAW_FULL;
1949 unset_option (OPTFORCEREDRAWINDEX);
1950 unset_option (OPTFORCEREDRAWPAGER);
1953 case OP_EDIT_MESSAGE:
1960 CHECK_MX_ACL (Context, ACL_INSERT, _("Editing"));
1962 if (tag || !(CURHDR->security & PGP_TRADITIONAL_CHECKED))
1963 mutt_check_traditional_pgp (tag ? NULL : CURHDR, &menu->redraw);
1964 mutt_edit_message (Context, tag ? NULL : CURHDR);
1965 menu->redraw = REDRAW_FULL;
1969 case OP_FORWARD_MESSAGE:
1975 if (tag || !(CURHDR->security & PGP_TRADITIONAL_CHECKED))
1976 mutt_check_traditional_pgp (tag ? NULL : CURHDR, &menu->redraw);
1977 ci_send_message (SENDFORWARD, NULL, NULL, Context, tag ? NULL : CURHDR);
1978 menu->redraw = REDRAW_FULL;
1981 case OP_GROUP_REPLY:
1987 if (tag || !(CURHDR->security & PGP_TRADITIONAL_CHECKED))
1988 mutt_check_traditional_pgp (tag ? NULL : CURHDR, &menu->redraw);
1990 ci_send_message (SENDREPLY | SENDGROUPREPLY, NULL, NULL, Context,
1991 tag ? NULL : CURHDR);
1992 menu->redraw = REDRAW_FULL;
2001 if (tag || !(CURHDR->security & PGP_TRADITIONAL_CHECKED))
2002 mutt_check_traditional_pgp (tag ? NULL : CURHDR, &menu->redraw);
2004 ci_send_message (SENDREPLY | SENDLISTREPLY, NULL, NULL, Context,
2005 tag ? NULL : CURHDR);
2006 menu->redraw = REDRAW_FULL;
2012 ci_send_message (0, NULL, NULL, Context, NULL);
2013 menu->redraw = REDRAW_FULL;
2016 case OP_EXTRACT_KEYS:
2019 crypt_extract_keys_from_messages (tag ? NULL : CURHDR);
2020 menu->redraw = REDRAW_FULL;
2024 case OP_CHECK_TRADITIONAL:
2027 if (tag || !(CURHDR->security & PGP_TRADITIONAL_CHECKED))
2028 mutt_check_traditional_pgp (tag ? NULL : CURHDR, &menu->redraw);
2030 if (menu->menu == MENU_PAGER) {
2031 op = OP_DISPLAY_MESSAGE;
2039 mutt_pipe_message (tag ? NULL : CURHDR);
2040 MAYBE_REDRAW (menu->redraw);
2046 mutt_print_message (tag ? NULL : CURHDR);
2049 case OP_MAIN_READ_THREAD:
2050 case OP_MAIN_READ_SUBTHREAD:
2055 CHECK_MX_ACL (Context, ACL_SEEN, _("Marking as read"));
2057 rc = mutt_thread_set_flag (CURHDR, M_READ, 1,
2058 op == OP_MAIN_READ_THREAD ? 0 : 1);
2061 if (option (OPTRESOLVE)) {
2062 if ((menu->current = (op == OP_MAIN_READ_THREAD ?
2063 mutt_next_thread (CURHDR) :
2064 mutt_next_subthread (CURHDR))) == -1)
2065 menu->current = menu->oldcurrent;
2067 menu->redraw = REDRAW_INDEX | REDRAW_STATUS;
2071 case OP_RECALL_MESSAGE:
2074 ci_send_message (SENDPOSTPONED, NULL, NULL, Context, NULL);
2075 menu->redraw = REDRAW_FULL;
2085 for (j = 0; j < Context->vcount; j++) {
2086 if (Context->hdrs[Context->v2r[j]]->tagged)
2087 mutt_resend_message (NULL, Context,
2088 Context->hdrs[Context->v2r[j]]);
2092 mutt_resend_message (NULL, Context, CURHDR);
2094 menu->redraw = REDRAW_FULL;
2100 case OP_FORWARD_TO_GROUP:
2103 if ((op == OP_FOLLOWUP || op == OP_FORWARD_TO_GROUP) &&
2104 Context && Context->msgcount == 0) {
2105 mutt_error (_("There are no messages."));
2108 else if (op != OP_FOLLOWUP || !CURHDR->env->followup_to ||
2109 m_strcasecmp(CURHDR->env->followup_to, "poster") ||
2110 query_quadoption (OPT_FOLLOWUPTOPOSTER,
2111 _("Reply by mail as poster prefers?")) !=
2113 if (Context && Context->magic == M_NNTP
2114 && !((nntp_data_t *) Context->data)->allowed
2115 && query_quadoption (OPT_TOMODERATED,
2117 ("Posting to this group not allowed, may be moderated. Continue?"))
2121 ci_send_message (SENDNEWS, NULL, NULL, Context, NULL);
2124 if (op == OP_FOLLOWUP)
2125 ci_send_message (SENDNEWS | SENDREPLY, NULL, NULL, Context,
2126 tag ? NULL : CURHDR);
2128 ci_send_message (SENDNEWS | SENDFORWARD, NULL, NULL, Context,
2129 tag ? NULL : CURHDR);
2131 menu->redraw = REDRAW_FULL;
2142 if (tag || !(CURHDR->security & PGP_TRADITIONAL_CHECKED))
2143 mutt_check_traditional_pgp (tag ? NULL : CURHDR, &menu->redraw);
2145 ci_send_message (SENDREPLY, NULL, NULL, Context, tag ? NULL : CURHDR);
2146 menu->redraw = REDRAW_FULL;
2149 case OP_SHELL_ESCAPE:
2151 mutt_shell_escape ();
2152 MAYBE_REDRAW (menu->redraw);
2156 case OP_TAG_SUBTHREAD:
2160 rc = mutt_thread_set_flag (CURHDR, M_TAG, !CURHDR->tagged,
2161 op == OP_TAG_THREAD ? 0 : 1);
2164 if (option (OPTRESOLVE)) {
2165 menu->current = mutt_next_thread (CURHDR);
2167 if (menu->current == -1)
2168 menu->current = menu->oldcurrent;
2170 menu->redraw = REDRAW_INDEX | REDRAW_STATUS;
2180 CHECK_MX_ACL (Context, ACL_DELETE, _("Undeletion"));
2183 mutt_tag_set_flag (M_DELETE, 0);
2184 mutt_tag_set_flag (M_PURGED, 0);
2185 menu->redraw = REDRAW_INDEX;
2188 mutt_set_flag (Context, CURHDR, M_DELETE, 0);
2189 mutt_set_flag (Context, CURHDR, M_PURGED, 0);
2190 if (option (OPTRESOLVE) && menu->current < Context->vcount - 1) {
2192 menu->redraw = REDRAW_MOTION_RESYNCH;
2195 menu->redraw = REDRAW_CURRENT;
2197 menu->redraw |= REDRAW_STATUS;
2200 case OP_UNDELETE_THREAD:
2201 case OP_UNDELETE_SUBTHREAD:
2207 CHECK_MX_ACL (Context, ACL_DELETE, _("Undeletion"));
2209 rc = mutt_thread_set_flag (CURHDR, M_DELETE, 0,
2210 op == OP_UNDELETE_THREAD ? 0 : 1)
2211 + mutt_thread_set_flag (CURHDR, M_PURGED, 0,
2212 op == OP_UNDELETE_THREAD ? 0 : 1);
2215 if (option (OPTRESOLVE)) {
2216 if (op == OP_UNDELETE_THREAD)
2217 menu->current = mutt_next_thread (CURHDR);
2219 menu->current = mutt_next_subthread (CURHDR);
2221 if (menu->current == -1)
2222 menu->current = menu->oldcurrent;
2224 menu->redraw = REDRAW_INDEX | REDRAW_STATUS;
2233 if (option (OPTFORCEBUFFYCHECK))
2236 menu->redraw = REDRAW_FULL;
2239 case OP_VIEW_ATTACHMENTS:
2242 mutt_view_attachments (CURHDR);
2243 if (CURHDR->attach_del)
2244 Context->changed = 1;
2245 menu->redraw = REDRAW_FULL;
2255 case OP_SIDEBAR_SCROLL_UP:
2256 case OP_SIDEBAR_SCROLL_DOWN:
2257 case OP_SIDEBAR_NEXT:
2258 case OP_SIDEBAR_PREV:
2259 case OP_SIDEBAR_NEXT_NEW:
2260 case OP_SIDEBAR_PREV_NEW:
2261 sidebar_scroll (op);
2264 if (menu->menu == MENU_MAIN)
2265 km_error_key (MENU_MAIN);
2268 if (menu->menu == MENU_PAGER) {
2269 menu->menu = MENU_MAIN;
2270 menu->redraw = REDRAW_FULL;
2278 /* Close all open IMAP connections */
2281 /* Close all open NNTP connections */
2286 mutt_menuDestroy (&menu);
2290 void mutt_set_header_color (CONTEXT * ctx, HEADER * curhdr)
2297 for (color = ColorIndexList; color; color = color->next)
2298 if (mutt_pattern_exec
2299 (color->color_pattern, M_MATCH_FULL_ADDRESS, ctx, curhdr)) {
2300 curhdr->pair = color->pair;
2303 curhdr->pair = ColorDefs[MT_COLOR_NORMAL];