2 * Copyright (C) 1996-2000 Michael R. Elkins <me@mutt.org>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
24 #include "mutt_curses.h"
26 #include "mutt_menu.h"
39 #include "imap_private.h"
42 #include "mutt_crypt.h"
57 static const char *No_mailbox_is_open = N_("No mailbox is open.");
58 static const char *There_are_no_messages = N_("There are no messages.");
59 static const char *Mailbox_is_read_only = N_("Mailbox is read-only.");
60 static const char *Function_not_permitted_in_attach_message_mode = N_("Function not permitted in attach-message mode.");
61 static const char *No_visible = N_("No visible messages.");
63 #define CHECK_MSGCOUNT if (!Context) \
66 mutt_error _(No_mailbox_is_open); \
69 else if (!Context->msgcount) \
72 mutt_error _(There_are_no_messages); \
76 #define CHECK_VISIBLE if (Context && menu->current >= Context->vcount) \
79 mutt_error _(No_visible); \
84 #define CHECK_READONLY if (Context->readonly) \
87 mutt_error _(Mailbox_is_read_only); \
92 /* the error message returned here could be better. */
93 #define CHECK_IMAP_ACL(aclbit) if (Context->magic == M_IMAP) \
94 if (mutt_bit_isset (((IMAP_DATA *)Context->data)->capabilities, ACL) \
95 && !mutt_bit_isset(((IMAP_DATA *)Context->data)->rights,aclbit)){ \
97 mutt_error ("Operation not permitted by the IMAP ACL for this mailbox"); \
102 #define CHECK_ATTACH if(option(OPTATTACHMSG)) \
105 mutt_error _(Function_not_permitted_in_attach_message_mode); \
109 #define CURHDR Context->hdrs[Context->v2r[menu->current]]
110 #define OLDHDR Context->hdrs[Context->v2r[menu->oldcurrent]]
111 #define UNREAD(h) mutt_thread_contains_unread (Context, h)
113 extern const char *ReleaseDate;
114 extern size_t UngetCount;
116 static void set_xterm_title_bar(char *title)
118 fputs("\033]2;", stdout);
119 fputs(title, stdout);
120 fputs("\007", stdout);
124 static void set_xterm_icon_name(char *name)
126 fputs("\033]1;", stdout);
128 fputs("\007", stdout);
132 void index_make_entry (char *s, size_t l, MUTTMENU *menu, int num)
134 format_flag flag = M_FORMAT_MAKEPRINT | M_FORMAT_ARROWCURSOR | M_FORMAT_INDEX;
135 int edgemsgno, reverse = Sort & SORT_REVERSE;
136 HEADER *h = Context->hdrs[Context->v2r[num]];
139 if ((Sort & SORT_MASK) == SORT_THREADS && h->tree)
141 flag |= M_FORMAT_TREE; /* display the thread tree */
142 if (h->display_subject)
143 flag |= M_FORMAT_FORCESUBJ;
148 if (menu->top + menu->pagelen > menu->max)
149 edgemsgno = Context->v2r[menu->max - 1];
151 edgemsgno = Context->v2r[menu->top + menu->pagelen - 1];
154 edgemsgno = Context->v2r[menu->top];
156 for (tmp = h->thread->parent; tmp; tmp = tmp->parent)
161 /* if no ancestor is visible on current screen, provisionally force
163 if (reverse ? tmp->message->msgno > edgemsgno : tmp->message->msgno < edgemsgno)
165 flag |= M_FORMAT_FORCESUBJ;
168 else if (tmp->message->virtual >= 0)
171 if (flag & M_FORMAT_FORCESUBJ)
173 for (tmp = h->thread->prev; tmp; tmp = tmp->prev)
178 /* ...but if a previous sibling is available, don't force it */
179 if (reverse ? tmp->message->msgno > edgemsgno : tmp->message->msgno < edgemsgno)
181 else if (tmp->message->virtual >= 0)
183 flag &= ~M_FORMAT_FORCESUBJ;
191 _mutt_make_string (s, l, NONULL (HdrFmt), Context, h, flag);
194 int index_color (int index_no)
196 HEADER *h = Context->hdrs[Context->v2r[index_no]];
201 mutt_set_header_color (Context, h);
205 static int ci_next_undeleted (int msgno)
209 for (i=msgno+1; i < Context->vcount; i++)
210 if (! Context->hdrs[Context->v2r[i]]->deleted)
215 static int ci_previous_undeleted (int msgno)
219 for (i=msgno-1; i>=0; i--)
220 if (! Context->hdrs[Context->v2r[i]]->deleted)
225 /* Return the index of the first new message, or failing that, the first
228 static int ci_first_message (void)
232 if (Context && Context->msgcount)
234 for (i=0; i < Context->vcount; i++)
236 if (! Context->hdrs[Context->v2r[i]]->read &&
237 ! Context->hdrs[Context->v2r[i]]->deleted)
239 if (! Context->hdrs[Context->v2r[i]]->old)
248 /* If Sort is reverse and not threaded, the latest message is first.
249 * If Sort is threaded, the latest message is first iff exactly one
250 * of Sort and SortAux are reverse.
252 if (((Sort & SORT_REVERSE) && (Sort & SORT_MASK) != SORT_THREADS) ||
253 ((Sort & SORT_MASK) == SORT_THREADS &&
254 ((Sort ^ SortAux) & SORT_REVERSE)))
257 return (Context->vcount ? Context->vcount - 1 : 0);
262 /* This should be in mx.c, but it only gets used here. */
263 static int mx_toggle_write (CONTEXT *ctx)
270 mutt_error _("Cannot toggle write on a readonly mailbox!");
277 mutt_message _("Changes to folder will be written on folder exit.");
282 mutt_message _("Changes to folder will not be written.");
288 static void update_index (MUTTMENU *menu, CONTEXT *ctx, int check,
289 int oldcount, int index_hint)
291 /* store pointers to the newly added messages */
292 HEADER **save_new = NULL;
295 /* take note of the current message */
298 if (menu->current < Context->vcount)
299 menu->oldcurrent = index_hint;
301 oldcount = 0; /* invalid message number! */
304 /* We are in a limited view. Check if the new message(s) satisfy
305 * the limit criteria. If they do, set their virtual msgno so that
306 * they will be visible in the limited view */
307 if (Context->pattern)
309 #define THIS_BODY Context->hdrs[j]->content
310 if (oldcount || check == M_REOPENED)
312 for (j = (check == M_REOPENED) ? 0 : oldcount; j < Context->msgcount; j++)
314 if (mutt_pattern_exec (Context->limit_pattern,
315 M_MATCH_FULL_ADDRESS,
316 Context, Context->hdrs[j]))
318 Context->hdrs[j]->virtual = Context->vcount;
319 Context->v2r[Context->vcount] = j;
320 Context->hdrs[j]->limited = 1;
322 Context->vsize += THIS_BODY->length + THIS_BODY->offset - THIS_BODY->hdr_offset;
329 /* save the list of new messages */
330 if (oldcount && check != M_REOPENED
331 && ((Sort & SORT_MASK) == SORT_THREADS))
333 save_new = (HEADER **) safe_malloc (sizeof (HEADER *) * (Context->msgcount - oldcount));
334 for (j = oldcount; j < Context->msgcount; j++)
335 save_new[j-oldcount] = Context->hdrs[j];
338 /* if the mailbox was reopened, need to rethread from scratch */
339 mutt_sort_headers (Context, (check == M_REOPENED));
341 /* uncollapse threads with new mail */
342 if ((Sort & SORT_MASK) == SORT_THREADS)
344 if (check == M_REOPENED)
348 Context->collapsed = 0;
350 for (h = Context->tree; h; h = h->next)
352 for (j = h; !j->message; j = j->child)
354 mutt_uncollapse_thread (Context, j->message);
356 mutt_set_virtual (Context);
360 for (j = 0; j < Context->msgcount - oldcount; j++)
364 for (k = 0; k < Context->msgcount; k++)
366 HEADER *h = Context->hdrs[k];
367 if (h == save_new[j] && (!Context->pattern || h->limited))
368 mutt_uncollapse_thread (Context, h);
372 mutt_set_virtual (Context);
379 /* restore the current message to the message it was pointing to */
380 for (j = 0; j < Context->vcount; j++)
382 if (Context->hdrs[Context->v2r[j]]->index == menu->oldcurrent)
390 if (menu->current < 0)
391 menu->current = ci_first_message ();
395 static void resort_index (MUTTMENU *menu)
398 HEADER *current = CURHDR;
401 mutt_sort_headers (Context, 0);
402 /* Restore the current message */
404 for (i = 0; i < Context->vcount; i++)
406 if (Context->hdrs[Context->v2r[i]] == current)
413 if ((Sort & SORT_MASK) == SORT_THREADS && menu->current < 0)
414 menu->current = mutt_parent_message (Context, current);
416 if (menu->current < 0)
417 menu->current = ci_first_message ();
419 menu->redraw = REDRAW_INDEX | REDRAW_STATUS;
422 struct mapping_t IndexHelp[] = {
423 { N_("Quit"), OP_QUIT },
424 { N_("Del"), OP_DELETE },
425 { N_("Undel"), OP_UNDELETE },
426 { N_("Save"), OP_SAVE },
427 { N_("Mail"), OP_MAIL },
428 { N_("Reply"), OP_REPLY },
429 { N_("Group"), OP_GROUP_REPLY },
430 { N_("Help"), OP_HELP },
435 struct mapping_t IndexNewsHelp[] = {
436 { N_("Quit"), OP_QUIT },
437 { N_("Del"), OP_DELETE },
438 { N_("Undel"), OP_UNDELETE },
439 { N_("Save"), OP_SAVE },
440 { N_("Post"), OP_POST },
441 { N_("Followup"), OP_FOLLOWUP },
442 { N_("Catchup"), OP_CATCHUP },
443 { N_("Help"), OP_HELP },
448 /* This function handles the message index window as well as commands returned
449 * from the pager (MENU_PAGER).
451 int mutt_index_menu (void)
453 char buf[LONG_STRING], helpstr[SHORT_STRING];
456 int done = 0; /* controls when to exit the "event" loop */
458 int tag = 0; /* has the tag-prefix command been pressed? */
463 char *cp; /* temporary variable. */
464 int index_hint; /* used to restore cursor position */
465 int do_buffy_notify = 1;
466 int close = 0; /* did we OP_QUIT or OP_EXIT out of this menu? */
467 int attach_msg = option(OPTATTACHMSG);
469 menu = mutt_new_menu ();
470 menu->menu = MENU_MAIN;
472 menu->pagelen = LINES - 3;
473 menu->make_entry = index_make_entry;
474 menu->color = index_color;
475 menu->current = ci_first_message ();
476 menu->help = mutt_compile_help (helpstr, sizeof (helpstr), MENU_MAIN,
478 (Context && (Context->magic == M_NNTP)) ? IndexNewsHelp :
483 mutt_buffy_check(1); /* force the buffy check after we enter the folder */
487 tag = 0; /* clear the tag-prefix */
489 menu->max = Context ? Context->vcount : 0;
490 oldcount = Context ? Context->msgcount : 0;
492 /* check if we need to resort the index because just about
493 * any 'op' below could do mutt_enter_command(), either here or
494 * from any new menu launched, and change $sort/$sort_aux
496 if (option (OPTNEEDRESORT) && Context && Context->msgcount)
499 if (option (OPTREDRAWTREE) && Context && Context->msgcount && (Sort & SORT_MASK) == SORT_THREADS)
501 mutt_draw_tree (Context);
502 menu->redraw |= REDRAW_STATUS;
503 unset_option (OPTREDRAWTREE);
506 if (Context && !attach_msg)
509 /* check for new mail in the mailbox. If nonzero, then something has
510 * changed about the file (either we got new mail or the file was
511 * modified underneath us.)
515 imap_allow_reopen (Context);
518 index_hint = (Context->vcount && menu->current >= 0 && menu->current < Context->vcount) ? CURHDR->index : 0;
520 if ((check = mx_check_mailbox (Context, &index_hint, 0)) < 0)
524 /* fatal error occurred */
526 menu->redraw = REDRAW_FULL;
529 set_option (OPTSEARCHINVALID);
531 else if (check == M_NEW_MAIL || check == M_REOPENED || check == M_FLAGS)
533 update_index (menu, Context, check, oldcount, index_hint);
535 /* notify the user of new mail */
536 if (check == M_REOPENED)
537 mutt_error _("Mailbox was externally modified. Flags may be wrong.");
538 else if (check == M_NEW_MAIL)
540 /* on new mail: redraw sidebar */
541 draw_sidebar (CurrentMenu);
542 mutt_message _("New mail in this mailbox.");
543 if (option (OPTBEEPNEW))
545 } else if (check == M_FLAGS)
546 mutt_message _("Mailbox was externally modified.");
548 /* avoid the message being overwritten by buffy */
551 menu->redraw = REDRAW_FULL;
552 menu->max = Context->vcount;
554 set_option (OPTSEARCHINVALID);
560 imap_disallow_reopen (Context);
565 /* check for new mail in the incoming folders */
567 if ((newcount = mutt_buffy_check (0)) != oldcount)
568 menu->redraw |= REDRAW_STATUS;
571 if (mutt_buffy_notify () && option (OPTBEEPNEW))
581 if (menu->redraw & REDRAW_FULL)
583 menu_redraw_full (menu);
584 draw_sidebar(menu->menu);
588 if (menu->menu == MENU_MAIN)
590 if (Context && Context->hdrs && !(menu->current >= Context->vcount))
592 menu_check_recenter (menu);
594 if (menu->redraw & REDRAW_INDEX)
596 menu_redraw_index (menu);
597 menu->redraw |= REDRAW_STATUS;
599 else if (menu->redraw & (REDRAW_MOTION_RESYNCH | REDRAW_MOTION))
600 menu_redraw_motion (menu);
601 else if (menu->redraw & REDRAW_CURRENT)
602 menu_redraw_current (menu);
605 if (menu->redraw & REDRAW_STATUS)
608 menu_status_line (buf, sizeof (buf), menu, NONULL (Status));
610 CLEARLINE (option (OPTSTATUSONTOP) ? 0 : LINES-2);
611 SETCOLOR (MT_COLOR_STATUS);
612 mutt_paddstr (COLS, buf);
613 SETCOLOR (MT_COLOR_NORMAL);
614 set_buffystats (Context);
615 menu->redraw &= ~REDRAW_STATUS;
616 if (option(OPTXTERMSETTITLES))
618 menu_status_line (buf, sizeof (buf), menu, NONULL (XtermTitle));
619 set_xterm_title_bar(buf);
620 menu_status_line (buf, sizeof (buf), menu, NONULL (XtermIcon));
621 set_xterm_icon_name(buf);
626 if (menu->current < menu->max)
627 menu->oldcurrent = menu->current;
629 menu->oldcurrent = -1;
631 if (option (OPTARROWCURSOR))
632 move (menu->current - menu->top + menu->offset, 2);
634 move (menu->current - menu->top + menu->offset, COLS - 1);
637 op = km_dokey (MENU_MAIN);
639 dprint(4, (debugfile, "mutt_index_menu[%d]: Got op %d\n", __LINE__, op));
641 #if defined (USE_SLANG_CURSES) || defined (HAVE_RESIZETERM)
645 mutt_resize_screen ();
646 menu->redraw = REDRAW_FULL;
647 menu->menu = MENU_MAIN;
649 menu->top = 0; /* so we scroll the right amount */
651 * force a real complete redraw. clrtobot() doesn't seem to be able
652 * to handle every case without this.
654 clearok(stdscr,TRUE);
660 continue; /* either user abort or timeout */
664 /* special handling for the tag-prefix function */
665 if (op == OP_TAG_PREFIX)
669 mutt_error _("No mailbox is open.");
673 if (!Context->tagged)
675 mutt_error _("No tagged messages.");
680 /* give visual indication that the next command is a tag- command */
681 mvaddstr (LINES - 1, 0, "tag-");
684 /* get the real command */
685 if ((op = km_dokey (MENU_MAIN)) == OP_TAG_PREFIX)
687 /* abort tag sequence */
692 else if (option (OPTAUTOTAG) && Context && Context->tagged)
695 if (op == OP_TAG_PREFIX_COND)
699 mutt_error _("No mailbox is open.");
703 if (!Context->tagged)
709 if(tmp.op==OP_END_COND)break;
711 mutt_message _("Nothing to do.");
716 /* give visual indication that the next command is a tag- command */
717 mvaddstr (LINES - 1, 0, "tag-");
720 /* get the real command */
721 if ((op = km_dokey (MENU_MAIN)) == OP_TAG_PREFIX)
723 /* abort tag sequence */
733 if (menu->current < menu->max)
734 menu->oldcurrent = menu->current;
736 menu->oldcurrent = -1;
738 mutt_curs_set (1); /* fallback from the pager */
742 unset_option (OPTNEWS); /* for any case */
748 /* ----------------------------------------------------------------------
753 menu_bottom_page (menu);
756 menu_first_entry (menu);
759 menu_middle_page (menu);
765 menu_half_down (menu);
768 menu_next_line (menu);
771 menu_prev_line (menu);
774 menu_next_page (menu);
777 menu_prev_page (menu);
780 menu_last_entry (menu);
783 menu_top_page (menu);
786 menu_current_top (menu);
788 case OP_CURRENT_MIDDLE:
789 menu_current_middle (menu);
791 case OP_CURRENT_BOTTOM:
792 menu_current_bottom (menu);
799 if (Context->magic == M_NNTP)
803 if (op == OP_GET_MESSAGE)
806 if (mutt_get_field (_("Enter Message-Id: "), buf, sizeof (buf), 0) != 0
812 LIST *ref = CURHDR->env->references;
815 mutt_error _("Article has no parent reference!");
818 strfcpy (buf, ref->data, sizeof (buf));
820 if (!Context->id_hash)
821 Context->id_hash = mutt_make_id_hash (Context);
822 if ((h = hash_find (Context->id_hash, buf)))
824 if (h->virtual != -1)
826 menu->current = h->virtual;
827 menu->redraw = REDRAW_MOTION_RESYNCH;
829 else if (h->collapsed)
831 mutt_uncollapse_thread (Context, h);
832 mutt_set_virtual (Context);
833 menu->current = h->virtual;
834 menu->redraw = REDRAW_MOTION_RESYNCH;
837 mutt_error _("Message not visible in limited view.");
841 if (nntp_check_msgid (Context, buf) == 0)
843 h = Context->hdrs[Context->msgcount-1];
844 mutt_sort_headers (Context, 0);
845 menu->current = h->virtual;
846 menu->redraw = REDRAW_FULL;
849 mutt_error (_("Article %s not found on server"), buf);
854 case OP_GET_CHILDREN:
855 case OP_RECONSTRUCT_THREAD:
857 if (Context->magic == M_NNTP)
860 int old = CURHDR->index, i;
862 if (!CURHDR->env->message_id)
864 mutt_error _("No Message-Id. Unable to perform operation");
868 if (!Context->id_hash)
869 Context->id_hash = mutt_make_id_hash (Context);
870 strfcpy (buf, CURHDR->env->message_id, sizeof (buf));
872 if (op == OP_RECONSTRUCT_THREAD)
874 LIST *ref = CURHDR->env->references;
877 nntp_check_msgid (Context, ref->data);
878 /* the last msgid in References is the root message */
880 strfcpy (buf, ref->data, sizeof (buf));
884 mutt_message _("Check for children of message...");
885 if (nntp_check_children (Context, buf) == 0)
887 mutt_sort_headers (Context, (op == OP_RECONSTRUCT_THREAD));
888 h = hash_find (Context->id_hash, buf);
889 /* if the root message was retrieved, move to it */
891 menu->current = h->virtual;
892 else /* try to restore old position */
893 for (i = 0; i < Context->msgcount; i++)
894 if (Context->hdrs[i]->index == old)
896 menu->current = Context->hdrs[i]->virtual;
897 /* As an added courtesy, recenter the menu
898 * with the current entry at the middle of the screen */
899 menu_check_recenter (menu);
900 menu_current_middle (menu);
903 menu->redraw = REDRAW_FULL;
913 if (isdigit (LastKey)) mutt_ungetch (LastKey, 0);
915 if (mutt_get_field (_("Jump to message: "), buf, sizeof (buf), 0) != 0
919 if (! isdigit ((unsigned char) buf[0]))
921 mutt_error _("Argument must be a message number.");
926 if (i > 0 && i <= Context->msgcount)
928 for (j = i-1; j < Context->msgcount; j++)
930 if (Context->hdrs[j]->virtual != -1)
933 if (j >= Context->msgcount)
935 for (j = i-2; j >= 0; j--)
937 if (Context->hdrs[j]->virtual != -1)
944 menu->current = Context->hdrs[j]->virtual;
945 if (menu->menu == MENU_PAGER)
947 op = OP_DISPLAY_MESSAGE;
951 menu->redraw = REDRAW_MOTION;
954 mutt_error _("That message is not visible.");
957 mutt_error _("Invalid message number.");
961 /* --------------------------------------------------------------------
962 * `index' specific commands
965 case OP_MAIN_DELETE_PATTERN:
972 CHECK_IMAP_ACL(IMAP_ACL_DELETE);
976 mutt_pattern_func (M_DELETE, _("Delete messages matching: "));
977 menu->redraw = REDRAW_INDEX | REDRAW_STATUS;
981 case OP_MAIN_FETCH_MAIL:
985 menu->redraw = REDRAW_FULL;
991 mutt_help (MENU_MAIN);
992 menu->redraw = REDRAW_FULL;
995 case OP_MAIN_SHOW_LIMIT:
997 if (!Context->pattern)
998 mutt_message _("No limit pattern is in effect.");
1002 /* i18n: ask for a limit to apply */
1003 snprintf (buf, sizeof(buf), _("Limit: %s"),Context->pattern);
1004 mutt_message ("%s", buf);
1009 case OP_TOGGLE_READ:
1012 menu->oldcurrent = (Context->vcount && menu->current >= 0 && menu->current < Context->vcount) ?
1014 if (op == OP_TOGGLE_READ)
1016 char buf[LONG_STRING];
1018 if (!Context->pattern || strncmp (Context->pattern, "!~R!~D~s", 8) != 0)
1020 snprintf (buf, sizeof (buf), "!~R!~D~s%s",
1021 Context->pattern ? Context->pattern : ".*");
1022 set_option (OPTHIDEREAD);
1026 strfcpy (buf, Context->pattern + 8, sizeof(buf));
1027 if (!*buf || strncmp (buf, ".*", 2) == 0)
1028 snprintf (buf, sizeof(buf), "~A");
1029 unset_option (OPTHIDEREAD);
1031 FREE (&Context->pattern);
1032 Context->pattern = safe_strdup (buf);
1034 if ((op == OP_TOGGLE_READ && mutt_pattern_func (M_LIMIT, NULL) == 0) ||
1035 mutt_pattern_func (M_LIMIT, _("Limit to messages matching: ")) == 0)
1037 if (menu->oldcurrent >= 0)
1039 /* try to find what used to be the current message */
1041 for (i = 0; i < Context->vcount; i++)
1042 if (Context->hdrs[Context->v2r[i]]->index == menu->oldcurrent)
1047 if (menu->current < 0) menu->current = 0;
1051 menu->redraw = REDRAW_INDEX | REDRAW_STATUS;
1052 if ((Sort & SORT_MASK) == SORT_THREADS)
1053 mutt_draw_tree (Context);
1054 menu->redraw = REDRAW_FULL;
1067 if (query_quadoption (OPT_QUIT, _("Quit Mutt?")) == M_YES)
1071 oldcount = Context ? Context->msgcount : 0;
1073 if (!Context || (check = mx_close_mailbox (Context, &index_hint)) == 0)
1077 if (check == M_NEW_MAIL || check == M_REOPENED)
1078 update_index (menu, Context, check, oldcount, index_hint);
1080 menu->redraw = REDRAW_FULL; /* new mail arrived? */
1081 set_option (OPTSEARCHINVALID);
1088 clearok (stdscr, TRUE);
1089 menu->redraw = REDRAW_FULL;
1093 case OP_SEARCH_REVERSE:
1094 case OP_SEARCH_NEXT:
1095 case OP_SEARCH_OPPOSITE:
1099 if ((menu->current = mutt_search_command (menu->current, op)) == -1)
1100 menu->current = menu->oldcurrent;
1102 menu->redraw = REDRAW_MOTION;
1106 case OP_SORT_REVERSE:
1108 if (mutt_select_sort ((op == OP_SORT_REVERSE)) == 0)
1110 if (Context && Context->msgcount)
1112 resort_index (menu);
1113 set_option (OPTSEARCHINVALID);
1122 if (tag && !option (OPTAUTOTAG))
1124 for (j = 0; j < Context->vcount; j++)
1125 mutt_set_flag (Context, Context->hdrs[Context->v2r[j]], M_TAG, 0);
1126 menu->redraw = REDRAW_STATUS | REDRAW_INDEX;
1130 mutt_set_flag (Context, CURHDR, M_TAG, !CURHDR->tagged);
1131 Context->last_tag = CURHDR->tagged ? CURHDR :
1132 ((Context->last_tag == CURHDR && !CURHDR->tagged)
1133 ? NULL : Context->last_tag);
1134 menu->redraw = REDRAW_STATUS;
1135 if (option (OPTRESOLVE) && menu->current < Context->vcount - 1)
1138 menu->redraw |= REDRAW_MOTION_RESYNCH;
1141 menu->redraw |= REDRAW_CURRENT;
1145 case OP_MAIN_TAG_PATTERN:
1149 mutt_pattern_func (M_TAG, _("Tag messages matching: "));
1150 menu->redraw = REDRAW_INDEX | REDRAW_STATUS;
1153 case OP_MAIN_UNDELETE_PATTERN:
1160 CHECK_IMAP_ACL(IMAP_ACL_DELETE);
1163 if (mutt_pattern_func (M_UNDELETE, _("Undelete messages matching: ")) == 0)
1164 menu->redraw = REDRAW_INDEX | REDRAW_STATUS;
1167 case OP_MAIN_UNTAG_PATTERN:
1171 if (mutt_pattern_func (M_UNTAG, _("Untag messages matching: ")) == 0)
1172 menu->redraw = REDRAW_INDEX | REDRAW_STATUS;
1175 /* --------------------------------------------------------------------
1176 * The following operations can be performed inside of the pager.
1180 case OP_MAIN_IMAP_FETCH:
1181 if (Context->magic == M_IMAP)
1182 imap_check_mailbox (Context, &index_hint, 1);
1186 case OP_MAIN_SYNC_FOLDER:
1188 if (Context && !Context->msgcount)
1195 int oldvcount = Context->vcount;
1196 int oldcount = Context->msgcount;
1200 /* calculate the number of messages _above_ the cursor,
1201 * so we can keep the cursor on the current message
1203 for (j = 0; j <= menu->current; j++)
1205 if (Context->hdrs[Context->v2r[j]]->deleted)
1209 if ((check = mx_sync_mailbox (Context, &index_hint)) == 0)
1211 if (Context->vcount != oldvcount)
1212 menu->current -= dcount;
1213 set_option (OPTSEARCHINVALID);
1215 else if (check == M_NEW_MAIL || check == M_REOPENED)
1216 update_index (menu, Context, check, oldcount, index_hint);
1219 * do a sanity check even if mx_sync_mailbox failed.
1222 if (menu->current < 0 || menu->current >= Context->vcount)
1223 menu->current = ci_first_message ();
1226 /* check for a fatal error, or all messages deleted */
1230 /* if we were in the pager, redisplay the message */
1231 if (menu->menu == MENU_PAGER)
1233 op = OP_DISPLAY_MESSAGE;
1237 menu->redraw = REDRAW_FULL;
1240 case OP_SIDEBAR_OPEN:
1241 case OP_MAIN_CHANGE_FOLDER:
1242 case OP_MAIN_CHANGE_FOLDER_READONLY:
1244 case OP_MAIN_CHANGE_GROUP:
1245 case OP_MAIN_CHANGE_GROUP_READONLY:
1247 if (attach_msg || option (OPTREADONLY) ||
1249 op == OP_MAIN_CHANGE_GROUP_READONLY ||
1251 op == OP_MAIN_CHANGE_FOLDER_READONLY)
1257 cp = _("Open mailbox in read-only mode");
1259 cp = _("Open mailbox");
1263 unset_option (OPTNEWS);
1264 if (op == OP_MAIN_CHANGE_GROUP ||
1265 op == OP_MAIN_CHANGE_GROUP_READONLY)
1267 set_option (OPTNEWS);
1268 if (!(CurrentNewsSrv = mutt_select_newsserver (NewsServer)))
1271 cp = _("Open newsgroup in read-only mode");
1273 cp = _("Open newsgroup");
1278 mutt_buffy (buf, sizeof (buf));
1280 if ( op == OP_SIDEBAR_OPEN ) {
1283 strncpy( buf, CurBuffy->path, sizeof(buf) );
1284 } else if (mutt_enter_fname (cp, buf, sizeof (buf), &menu->redraw, 1) == -1)
1288 CLEARLINE (LINES-1);
1293 if (option (OPTNEWS))
1295 unset_option (OPTNEWS);
1296 nntp_expand_path (buf, sizeof (buf), &CurrentNewsSrv->conn->account);
1300 mutt_expand_path (buf, sizeof (buf));
1302 if (mx_get_magic (buf) <= 0)
1304 mutt_error (_("%s is not a mailbox."), buf);
1312 #ifdef USE_COMPRESSED
1313 if (Context->compressinfo && Context->realpath)
1314 mutt_str_replace (&LastFolder, Context->realpath);
1318 mutt_str_replace (&LastFolder, Context->path);
1319 oldcount = Context ? Context->msgcount : 0;
1321 if ((check = mx_close_mailbox (Context, &index_hint)) != 0)
1323 if (check == M_NEW_MAIL || check == M_REOPENED)
1324 update_index (menu, Context, check, oldcount, index_hint);
1326 set_option (OPTSEARCHINVALID);
1327 menu->redraw = REDRAW_INDEX | REDRAW_STATUS;
1335 /* Set CurrentMenu to MENU_MAIN before executing any folder
1336 * hooks so that all the index menu functions are available to
1340 CurrentMenu = MENU_MAIN;
1341 mutt_folder_hook (buf);
1343 if ((Context = mx_open_mailbox (buf, flags, NULL)) != NULL)
1345 menu->current = ci_first_message ();
1351 /* mutt_buffy_check() must be done with mail-reader mode! */
1352 menu->help = mutt_compile_help (helpstr, sizeof (helpstr), MENU_MAIN,
1353 (Context && (Context->magic == M_NNTP)) ? IndexNewsHelp : IndexHelp);
1355 mutt_clear_error ();
1356 mutt_buffy_check(1); /* force the buffy check after we have changed
1358 menu->redraw = REDRAW_FULL;
1359 set_option (OPTSEARCHINVALID);
1362 case OP_DISPLAY_MESSAGE:
1363 case OP_DISPLAY_HEADERS: /* don't weed the headers */
1368 * toggle the weeding of headers so that a user can press the key
1369 * again while reading the message.
1371 if (op == OP_DISPLAY_HEADERS)
1372 toggle_option (OPTWEED);
1374 unset_option (OPTNEEDRESORT);
1376 if ((Sort & SORT_MASK) == SORT_THREADS && CURHDR->collapsed)
1378 mutt_uncollapse_thread (Context, CURHDR);
1379 mutt_set_virtual (Context);
1380 if (option (OPTUNCOLLAPSEJUMP))
1381 menu->current = mutt_thread_next_unread (Context, CURHDR);
1384 if ((op = mutt_display_message (CURHDR)) == -1)
1386 unset_option (OPTNEEDRESORT);
1390 menu->menu = MENU_PAGER;
1391 menu->oldcurrent = menu->current;
1397 if (menu->menu == MENU_MAIN && attach_msg)
1403 if ((menu->menu == MENU_MAIN)
1404 && (query_quadoption (OPT_QUIT,
1405 _("Exit Mutt-ng without saving?")) == M_YES))
1409 mx_fastclose_mailbox (Context);
1421 mutt_edit_content_type (CURHDR, CURHDR->content, NULL);
1422 /* if we were in the pager, redisplay the message */
1423 if (menu->menu == MENU_PAGER)
1425 op = OP_DISPLAY_MESSAGE;
1429 menu->redraw = REDRAW_CURRENT;
1432 case OP_MAIN_NEXT_UNDELETED:
1436 if (menu->current >= Context->vcount - 1)
1438 if (menu->menu == MENU_MAIN)
1439 mutt_error _("You are on the last message.");
1442 if ((menu->current = ci_next_undeleted (menu->current)) == -1)
1444 menu->current = menu->oldcurrent;
1445 if (menu->menu == MENU_MAIN)
1446 mutt_error _("No undeleted messages.");
1448 else if (menu->menu == MENU_PAGER)
1450 op = OP_DISPLAY_MESSAGE;
1454 menu->redraw = REDRAW_MOTION;
1461 if (menu->current >= Context->vcount - 1)
1463 if (menu->menu == MENU_MAIN)
1464 mutt_error _("You are on the last message.");
1468 if (menu->menu == MENU_PAGER)
1470 op = OP_DISPLAY_MESSAGE;
1474 menu->redraw = REDRAW_MOTION;
1477 case OP_MAIN_PREV_UNDELETED:
1481 if (menu->current < 1)
1483 mutt_error _("You are on the first message.");
1486 if ((menu->current = ci_previous_undeleted (menu->current)) == -1)
1488 menu->current = menu->oldcurrent;
1489 if (menu->menu == MENU_MAIN)
1490 mutt_error _("No undeleted messages.");
1492 else if (menu->menu == MENU_PAGER)
1494 op = OP_DISPLAY_MESSAGE;
1498 menu->redraw = REDRAW_MOTION;
1505 if (menu->current < 1)
1507 if (menu->menu == MENU_MAIN) mutt_error _("You are on the first message.");
1511 if (menu->menu == MENU_PAGER)
1513 op = OP_DISPLAY_MESSAGE;
1517 menu->redraw = REDRAW_MOTION;
1520 case OP_DECRYPT_COPY:
1521 case OP_DECRYPT_SAVE:
1525 case OP_COPY_MESSAGE:
1527 case OP_DECODE_COPY:
1528 case OP_DECODE_SAVE:
1531 if (mutt_save_message (tag ? NULL : CURHDR,
1532 (op == OP_DECRYPT_SAVE) ||
1533 (op == OP_SAVE) || (op == OP_DECODE_SAVE),
1534 (op == OP_DECODE_SAVE) || (op == OP_DECODE_COPY),
1535 (op == OP_DECRYPT_SAVE) || (op == OP_DECRYPT_COPY) ||
1537 &menu->redraw) == 0 &&
1538 (op == OP_SAVE || op == OP_DECODE_SAVE || op == OP_DECRYPT_SAVE)
1542 menu->redraw |= REDRAW_INDEX;
1543 else if (option (OPTRESOLVE))
1545 if ((menu->current = ci_next_undeleted (menu->current)) == -1)
1547 menu->current = menu->oldcurrent;
1548 menu->redraw |= REDRAW_CURRENT;
1551 menu->redraw |= REDRAW_MOTION_RESYNCH;
1554 menu->redraw |= REDRAW_CURRENT;
1558 case OP_MAIN_NEXT_NEW:
1559 case OP_MAIN_NEXT_UNREAD:
1560 case OP_MAIN_PREV_NEW:
1561 case OP_MAIN_PREV_UNREAD:
1562 case OP_MAIN_NEXT_NEW_THEN_UNREAD:
1563 case OP_MAIN_PREV_NEW_THEN_UNREAD:
1566 int first_unread = -1;
1574 for (j = 0; j != Context->vcount; j++)
1576 #define CURHDRi Context->hdrs[Context->v2r[i]]
1577 if (op == OP_MAIN_NEXT_NEW || op == OP_MAIN_NEXT_UNREAD || op == OP_MAIN_NEXT_NEW_THEN_UNREAD)
1580 if (i > Context->vcount - 1)
1582 mutt_message _("Search wrapped to top.");
1591 mutt_message _("Search wrapped to bottom.");
1592 i = Context->vcount - 1;
1596 if (CURHDRi->collapsed && (Sort & SORT_MASK) == SORT_THREADS)
1598 if (UNREAD (CURHDRi) && first_unread == -1)
1600 if (UNREAD (CURHDRi) == 1 && first_new == -1)
1603 else if ((!CURHDRi->deleted && !CURHDRi->read))
1605 if (first_unread == -1)
1607 if ((!CURHDRi->old) && first_new == -1)
1611 if ((op == OP_MAIN_NEXT_UNREAD || op == OP_MAIN_PREV_UNREAD) &&
1614 if ((op == OP_MAIN_NEXT_NEW || op == OP_MAIN_PREV_NEW ||
1615 op == OP_MAIN_NEXT_NEW_THEN_UNREAD || op == OP_MAIN_PREV_NEW_THEN_UNREAD)
1620 if ((op == OP_MAIN_NEXT_NEW || op == OP_MAIN_PREV_NEW ||
1621 op == OP_MAIN_NEXT_NEW_THEN_UNREAD || op == OP_MAIN_PREV_NEW_THEN_UNREAD)
1623 menu->current = first_new;
1624 else if ((op == OP_MAIN_NEXT_UNREAD || op == OP_MAIN_PREV_UNREAD ||
1625 op == OP_MAIN_NEXT_NEW_THEN_UNREAD || op == OP_MAIN_PREV_NEW_THEN_UNREAD)
1626 && first_unread != -1)
1627 menu->current = first_unread;
1629 if (menu->current == -1)
1631 menu->current = menu->oldcurrent;
1632 mutt_error ("%s%s.", (op == OP_MAIN_NEXT_NEW || op == OP_MAIN_PREV_NEW) ? _("No new messages") : _("No unread messages"),
1633 Context->pattern ? _(" in this limited view") : "");
1635 else if (menu->menu == MENU_PAGER)
1637 op = OP_DISPLAY_MESSAGE;
1641 menu->redraw = REDRAW_MOTION;
1644 case OP_FLAG_MESSAGE:
1651 if (Context->magic == M_POP)
1654 mutt_error _("Can't change 'important' flag on POP server.");
1660 CHECK_IMAP_ACL(IMAP_ACL_WRITE);
1664 if (Context->magic == M_NNTP)
1667 mutt_error _("Can't change 'important' flag on NNTP server.");
1674 for (j = 0; j < Context->vcount; j++)
1676 if (Context->hdrs[Context->v2r[j]]->tagged)
1677 mutt_set_flag (Context, Context->hdrs[Context->v2r[j]],
1678 M_FLAG, !Context->hdrs[Context->v2r[j]]->flagged);
1681 menu->redraw |= REDRAW_INDEX;
1685 mutt_set_flag (Context, CURHDR, M_FLAG, !CURHDR->flagged);
1686 if (option (OPTRESOLVE))
1688 if ((menu->current = ci_next_undeleted (menu->current)) == -1)
1690 menu->current = menu->oldcurrent;
1691 menu->redraw = REDRAW_CURRENT;
1694 menu->redraw = REDRAW_MOTION_RESYNCH;
1697 menu->redraw = REDRAW_CURRENT;
1699 menu->redraw |= REDRAW_STATUS;
1709 CHECK_IMAP_ACL(IMAP_ACL_SEEN);
1714 for (j = 0; j < Context->vcount; j++)
1716 if (Context->hdrs[Context->v2r[j]]->tagged)
1718 if (Context->hdrs[Context->v2r[j]]->read ||
1719 Context->hdrs[Context->v2r[j]]->old)
1720 mutt_set_flag (Context, Context->hdrs[Context->v2r[j]], M_NEW, 1);
1722 mutt_set_flag (Context, Context->hdrs[Context->v2r[j]], M_READ, 1);
1725 menu->redraw = REDRAW_STATUS | REDRAW_INDEX;
1729 if (CURHDR->read || CURHDR->old)
1730 mutt_set_flag (Context, CURHDR, M_NEW, 1);
1732 mutt_set_flag (Context, CURHDR, M_READ, 1);
1734 if (option (OPTRESOLVE))
1736 if ((menu->current = ci_next_undeleted (menu->current)) == -1)
1738 menu->current = menu->oldcurrent;
1739 menu->redraw = REDRAW_CURRENT;
1742 menu->redraw = REDRAW_MOTION_RESYNCH;
1745 menu->redraw = REDRAW_CURRENT;
1746 menu->redraw |= REDRAW_STATUS;
1750 case OP_TOGGLE_WRITE:
1753 if (mx_toggle_write (Context) == 0)
1754 menu->redraw |= REDRAW_STATUS;
1757 case OP_MAIN_NEXT_THREAD:
1758 case OP_MAIN_NEXT_SUBTHREAD:
1759 case OP_MAIN_PREV_THREAD:
1760 case OP_MAIN_PREV_SUBTHREAD:
1766 case OP_MAIN_NEXT_THREAD:
1767 menu->current = mutt_next_thread (CURHDR);
1770 case OP_MAIN_NEXT_SUBTHREAD:
1771 menu->current = mutt_next_subthread (CURHDR);
1774 case OP_MAIN_PREV_THREAD:
1775 menu->current = mutt_previous_thread (CURHDR);
1778 case OP_MAIN_PREV_SUBTHREAD:
1779 menu->current = mutt_previous_subthread (CURHDR);
1783 if (menu->current < 0)
1785 menu->current = menu->oldcurrent;
1786 if (op == OP_MAIN_NEXT_THREAD || op == OP_MAIN_NEXT_SUBTHREAD)
1787 mutt_error _("No more threads.");
1789 mutt_error _("You are on the first thread.");
1791 else if (menu->menu == MENU_PAGER)
1793 op = OP_DISPLAY_MESSAGE;
1797 menu->redraw = REDRAW_MOTION;
1800 case OP_MAIN_PARENT_MESSAGE:
1805 if ((menu->current = mutt_parent_message (Context, CURHDR)) < 0)
1807 menu->current = menu->oldcurrent;
1809 else if (menu->menu == MENU_PAGER)
1811 op = OP_DISPLAY_MESSAGE;
1815 menu->redraw = REDRAW_MOTION;
1818 case OP_MAIN_SET_FLAG:
1819 case OP_MAIN_CLEAR_FLAG:
1826 CHECK_IMAP_ACL(IMAP_ACL_WRITE);
1829 if (mutt_change_flag (tag ? NULL : CURHDR, (op == OP_MAIN_SET_FLAG)) == 0)
1831 menu->redraw = REDRAW_STATUS;
1833 menu->redraw |= REDRAW_INDEX;
1834 else if (option (OPTRESOLVE))
1836 if ((menu->current = ci_next_undeleted (menu->current)) == -1)
1838 menu->current = menu->oldcurrent;
1839 menu->redraw |= REDRAW_CURRENT;
1842 menu->redraw |= REDRAW_MOTION_RESYNCH;
1845 menu->redraw |= REDRAW_CURRENT;
1849 case OP_MAIN_COLLAPSE_THREAD:
1853 if ((Sort & SORT_MASK) != SORT_THREADS)
1855 mutt_error _("Threading is not enabled.");
1859 if (CURHDR->collapsed)
1861 menu->current = mutt_uncollapse_thread (Context, CURHDR);
1862 mutt_set_virtual (Context);
1863 if (option (OPTUNCOLLAPSEJUMP))
1864 menu->current = mutt_thread_next_unread (Context, CURHDR);
1866 else if (option (OPTCOLLAPSEUNREAD) || !UNREAD (CURHDR))
1868 menu->current = mutt_collapse_thread (Context, CURHDR);
1869 mutt_set_virtual (Context);
1873 mutt_error _("Thread contains unread messages.");
1877 menu->redraw = REDRAW_INDEX | REDRAW_STATUS;
1881 case OP_MAIN_COLLAPSE_ALL:
1885 if ((Sort & SORT_MASK) != SORT_THREADS)
1887 mutt_error _("Threading is not enabled.");
1893 THREAD *thread, *top;
1896 if (CURHDR->collapsed)
1897 final = mutt_uncollapse_thread (Context, CURHDR);
1898 else if (option (OPTCOLLAPSEUNREAD) || !UNREAD (CURHDR))
1899 final = mutt_collapse_thread (Context, CURHDR);
1901 final = CURHDR->virtual;
1903 base = Context->hdrs[Context->v2r[final]];
1905 top = Context->tree;
1906 Context->collapsed = !Context->collapsed;
1907 while ((thread = top) != NULL)
1909 while (!thread->message)
1910 thread = thread->child;
1911 h = thread->message;
1913 if (h->collapsed != Context->collapsed)
1916 mutt_uncollapse_thread (Context, h);
1917 else if (option (OPTCOLLAPSEUNREAD) || !UNREAD (h))
1918 mutt_collapse_thread (Context, h);
1923 mutt_set_virtual (Context);
1924 for (j = 0; j < Context->vcount; j++)
1926 if (Context->hdrs[Context->v2r[j]]->index == base->index)
1933 menu->redraw = REDRAW_INDEX | REDRAW_STATUS;
1937 /* --------------------------------------------------------------------
1938 * These functions are invoked directly from the internal-pager
1941 case OP_BOUNCE_MESSAGE:
1946 ci_bounce_message (tag ? NULL : CURHDR, &menu->redraw);
1949 case OP_CREATE_ALIAS:
1951 mutt_create_alias (Context && Context->vcount ? CURHDR->env : NULL, NULL);
1952 MAYBE_REDRAW (menu->redraw);
1953 menu->redraw |= REDRAW_CURRENT;
1958 mutt_query_menu (NULL, 0);
1959 MAYBE_REDRAW (menu->redraw);
1962 case OP_PURGE_MESSAGE:
1970 CHECK_IMAP_ACL(IMAP_ACL_DELETE);
1975 mutt_tag_set_flag (M_DELETE, 1);
1976 mutt_tag_set_flag (M_PURGED, (op != OP_PURGE_MESSAGE) ? 0 : 1);
1977 if (option (OPTDELETEUNTAG))
1978 mutt_tag_set_flag (M_TAG, 0);
1979 menu->redraw = REDRAW_INDEX;
1983 mutt_set_flag (Context, CURHDR, M_DELETE, 1);
1984 mutt_set_flag (Context, CURHDR, M_PURGED,
1985 (op != OP_PURGE_MESSAGE) ? 0 : 1);
1986 if (option (OPTDELETEUNTAG))
1987 mutt_set_flag (Context, CURHDR, M_TAG, 0);
1988 if (option (OPTRESOLVE))
1990 if ((menu->current = ci_next_undeleted (menu->current)) == -1)
1992 menu->current = menu->oldcurrent;
1993 menu->redraw = REDRAW_CURRENT;
1995 else if (menu->menu == MENU_PAGER)
1997 op = OP_DISPLAY_MESSAGE;
2001 menu->redraw |= REDRAW_MOTION_RESYNCH;
2004 menu->redraw = REDRAW_CURRENT;
2006 menu->redraw |= REDRAW_STATUS;
2009 case OP_DELETE_THREAD:
2010 case OP_DELETE_SUBTHREAD:
2017 CHECK_IMAP_ACL(IMAP_ACL_DELETE);
2020 rc = mutt_thread_set_flag (CURHDR, M_DELETE, 1,
2021 op == OP_DELETE_THREAD ? 0 : 1);
2025 if (option (OPTDELETEUNTAG))
2026 mutt_thread_set_flag (CURHDR, M_TAG, 0,
2027 op == OP_DELETE_THREAD ? 0 : 1);
2028 if (option (OPTRESOLVE))
2029 if ((menu->current = ci_next_undeleted (menu->current)) == -1)
2030 menu->current = menu->oldcurrent;
2031 menu->redraw = REDRAW_INDEX | REDRAW_STATUS;
2037 if (Context && Context->magic == M_NNTP)
2039 if (mutt_newsgroup_catchup (CurrentNewsSrv,
2040 ((NNTP_DATA *)Context->data)->group))
2041 menu->redraw = REDRAW_INDEX | REDRAW_STATUS;
2046 case OP_DISPLAY_ADDRESS:
2050 mutt_display_address (CURHDR->env);
2053 case OP_ENTER_COMMAND:
2055 CurrentMenu = MENU_MAIN;
2056 mutt_enter_command ();
2057 mutt_check_rescore (Context);
2058 if (option (OPTFORCEREDRAWINDEX))
2059 menu->redraw = REDRAW_FULL;
2060 unset_option (OPTFORCEREDRAWINDEX);
2061 unset_option (OPTFORCEREDRAWPAGER);
2064 case OP_EDIT_MESSAGE:
2072 if (Context->magic == M_POP)
2075 mutt_error _("Can't edit message on POP server.");
2081 CHECK_IMAP_ACL(IMAP_ACL_INSERT);
2085 if (Context->magic == M_NNTP)
2088 mutt_error _("Can't edit message on newsserver.");
2093 if (option (OPTPGPAUTODEC) && (tag || !(CURHDR->security & PGP_TRADITIONAL_CHECKED)))
2094 mutt_check_traditional_pgp (tag ? NULL : CURHDR, &menu->redraw);
2095 mutt_edit_message (Context, tag ? NULL : CURHDR);
2096 menu->redraw = REDRAW_FULL;
2100 case OP_FORWARD_MESSAGE:
2105 ci_send_message (SENDFORWARD, NULL, NULL, Context, tag ? NULL : CURHDR);
2106 menu->redraw = REDRAW_FULL;
2110 case OP_FORGET_PASSPHRASE:
2111 crypt_forget_passphrase ();
2114 case OP_GROUP_REPLY:
2119 ci_send_message (SENDREPLY|SENDGROUPREPLY, NULL, NULL, Context, tag ? NULL : CURHDR);
2120 menu->redraw = REDRAW_FULL;
2128 ci_send_message (SENDREPLY|SENDLISTREPLY, NULL, NULL, Context, tag ? NULL : CURHDR);
2129 menu->redraw = REDRAW_FULL;
2135 ci_send_message (0, NULL, NULL, Context, NULL);
2136 menu->redraw = REDRAW_FULL;
2140 if (!(WithCrypto & APPLICATION_PGP))
2143 ci_send_message (SENDKEY, NULL, NULL, NULL, NULL);
2144 menu->redraw = REDRAW_FULL;
2148 case OP_EXTRACT_KEYS:
2153 crypt_extract_keys_from_messages(tag ? NULL : CURHDR);
2154 menu->redraw = REDRAW_FULL;
2158 case OP_CHECK_TRADITIONAL:
2159 if (!(WithCrypto & APPLICATION_PGP))
2163 if (tag || !(CURHDR->security & PGP_TRADITIONAL_CHECKED))
2164 mutt_check_traditional_pgp (tag ? NULL : CURHDR, &menu->redraw);
2166 if (menu->menu == MENU_PAGER)
2168 op = OP_DISPLAY_MESSAGE;
2177 mutt_pipe_message (tag ? NULL : CURHDR);
2178 MAYBE_REDRAW (menu->redraw);
2185 mutt_print_message (tag ? NULL : CURHDR);
2188 case OP_MAIN_READ_THREAD:
2189 case OP_MAIN_READ_SUBTHREAD:
2196 CHECK_IMAP_ACL(IMAP_ACL_SEEN);
2199 rc = mutt_thread_set_flag (CURHDR, M_READ, 1,
2200 op == OP_MAIN_READ_THREAD ? 0 : 1);
2204 if (option (OPTRESOLVE))
2206 if ((menu->current = (op == OP_MAIN_READ_THREAD ?
2207 mutt_next_thread (CURHDR) : mutt_next_subthread (CURHDR))) == -1)
2208 menu->current = menu->oldcurrent;
2210 menu->redraw = REDRAW_INDEX | REDRAW_STATUS;
2214 case OP_RECALL_MESSAGE:
2217 ci_send_message (SENDPOSTPONED, NULL, NULL, Context, NULL);
2218 menu->redraw = REDRAW_FULL;
2229 for (j = 0; j < Context->vcount; j++)
2231 if (Context->hdrs[Context->v2r[j]]->tagged)
2232 mutt_resend_message (NULL, Context, Context->hdrs[Context->v2r[j]]);
2236 mutt_resend_message (NULL, Context, CURHDR);
2238 menu->redraw = REDRAW_FULL;
2244 case OP_FORWARD_TO_GROUP:
2247 if (op != OP_FOLLOWUP || !CURHDR->env->followup_to ||
2248 mutt_strcasecmp (CURHDR->env->followup_to, "poster") ||
2249 query_quadoption (OPT_FOLLOWUPTOPOSTER,_("Reply by mail as poster prefers?")) != M_YES)
2251 if (Context && Context->magic == M_NNTP &&
2252 !((NNTP_DATA *)Context->data)->allowed &&
2253 query_quadoption (OPT_TOMODERATED, _("Posting to this group not allowed, may be moderated. Continue?")) != M_YES)
2256 ci_send_message (SENDNEWS, NULL, NULL, Context, NULL);
2260 if (op == OP_FOLLOWUP)
2261 ci_send_message (SENDNEWS|SENDREPLY, NULL, NULL, Context,
2262 tag ? NULL : CURHDR);
2264 ci_send_message (SENDNEWS|SENDFORWARD, NULL, NULL, Context,
2265 tag ? NULL : CURHDR);
2267 menu->redraw = REDRAW_FULL;
2277 ci_send_message (SENDREPLY, NULL, NULL, Context, tag ? NULL : CURHDR);
2278 menu->redraw = REDRAW_FULL;
2281 case OP_SHELL_ESCAPE:
2283 mutt_shell_escape ();
2284 MAYBE_REDRAW (menu->redraw);
2288 case OP_TAG_SUBTHREAD:
2292 rc = mutt_thread_set_flag (CURHDR, M_TAG, !CURHDR->tagged,
2293 op == OP_TAG_THREAD ? 0 : 1);
2297 if (option (OPTRESOLVE))
2299 menu->current = mutt_next_thread (CURHDR);
2301 if (menu->current == -1)
2302 menu->current = menu->oldcurrent;
2304 menu->redraw = REDRAW_INDEX | REDRAW_STATUS;
2315 CHECK_IMAP_ACL(IMAP_ACL_DELETE);
2320 mutt_tag_set_flag (M_DELETE, 0);
2321 mutt_tag_set_flag (M_PURGED, 0);
2322 menu->redraw = REDRAW_INDEX;
2326 mutt_set_flag (Context, CURHDR, M_DELETE, 0);
2327 mutt_set_flag (Context, CURHDR, M_PURGED, 0);
2328 if (option (OPTRESOLVE) && menu->current < Context->vcount - 1)
2331 menu->redraw = REDRAW_MOTION_RESYNCH;
2334 menu->redraw = REDRAW_CURRENT;
2336 menu->redraw |= REDRAW_STATUS;
2339 case OP_UNDELETE_THREAD:
2340 case OP_UNDELETE_SUBTHREAD:
2347 CHECK_IMAP_ACL(IMAP_ACL_DELETE);
2350 rc = mutt_thread_set_flag (CURHDR, M_DELETE, 0,
2351 op == OP_UNDELETE_THREAD ? 0 : 1)
2352 + mutt_thread_set_flag (CURHDR, M_PURGED, 0,
2353 op == OP_UNDELETE_THREAD ? 0 : 1);
2357 if (option (OPTRESOLVE))
2359 if (op == OP_UNDELETE_THREAD)
2360 menu->current = mutt_next_thread (CURHDR);
2362 menu->current = mutt_next_subthread (CURHDR);
2364 if (menu->current == -1)
2365 menu->current = menu->oldcurrent;
2367 menu->redraw = REDRAW_INDEX | REDRAW_STATUS;
2379 case OP_VIEW_ATTACHMENTS:
2382 mutt_view_attachments (CURHDR);
2383 if (CURHDR->attach_del)
2384 Context->changed = 1;
2385 menu->redraw = REDRAW_FULL;
2395 case OP_SIDEBAR_SCROLL_UP:
2396 case OP_SIDEBAR_SCROLL_DOWN:
2397 case OP_SIDEBAR_NEXT:
2398 case OP_SIDEBAR_PREV:
2399 case OP_SIDEBAR_NEXT_NEW:
2400 case OP_SIDEBAR_PREV_NEW:
2401 scroll_sidebar(op, menu->menu);
2404 if (menu->menu == MENU_MAIN)
2405 km_error_key (MENU_MAIN);
2408 if (menu->menu == MENU_PAGER)
2410 menu->menu = MENU_MAIN;
2411 menu->redraw = REDRAW_FULL;
2413 set_option (OPTWEED); /* turn header weeding back on. */
2421 /* Close all open IMAP connections */
2426 /* Close all open NNTP connections */
2431 mutt_menuDestroy (&menu);
2435 void mutt_set_header_color (CONTEXT *ctx, HEADER *curhdr)
2442 for (color = ColorIndexList; color; color = color->next)
2443 if (mutt_pattern_exec (color->color_pattern, M_MATCH_FULL_ADDRESS, ctx, curhdr))
2445 curhdr->pair = color->pair;
2448 curhdr->pair = ColorDefs[MT_COLOR_NORMAL];