mutt stable branch with some hacks
at master 2459 lines 59 kB view raw
1/* 2 * Copyright (C) 1996-2000,2002,2010,2012-2013 Michael R. Elkins <me@mutt.org> 3 * 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. 8 * 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. 13 * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 17 */ 18 19#if HAVE_CONFIG_H 20# include "config.h" 21#endif 22 23#include "mutt.h" 24#include "mutt_curses.h" 25#include "mutt_menu.h" 26#include "mailbox.h" 27#include "mapping.h" 28#include "sort.h" 29#include "buffy.h" 30#include "mx.h" 31 32#ifdef USE_SIDEBAR 33#include "sidebar.h" 34#endif 35 36#ifdef USE_POP 37#include "pop.h" 38#endif 39 40#ifdef USE_IMAP 41#include "imap_private.h" 42#endif 43 44#include "mutt_crypt.h" 45 46 47#include <ctype.h> 48#include <stdlib.h> 49#include <unistd.h> 50#include <sys/wait.h> 51#include <string.h> 52#include <sys/stat.h> 53#include <errno.h> 54 55#include <assert.h> 56 57static const char *No_mailbox_is_open = N_("No mailbox is open."); 58static const char *There_are_no_messages = N_("There are no messages."); 59static const char *Mailbox_is_read_only = N_("Mailbox is read-only."); 60static const char *Function_not_permitted_in_attach_message_mode = N_("Function not permitted in attach-message mode."); 61static const char *No_visible = N_("No visible messages."); 62 63#define CHECK_IN_MAILBOX if (!Context) \ 64 { \ 65 mutt_flushinp (); \ 66 mutt_error _(No_mailbox_is_open); \ 67 break; \ 68 } 69 70#define CHECK_MSGCOUNT if (!Context) \ 71 { \ 72 mutt_flushinp (); \ 73 mutt_error _(No_mailbox_is_open); \ 74 break; \ 75 } \ 76 else if (!Context->msgcount) \ 77 { \ 78 mutt_flushinp (); \ 79 mutt_error _(There_are_no_messages); \ 80 break; \ 81 } 82 83#define CHECK_VISIBLE if (Context && menu->current >= Context->vcount) \ 84 {\ 85 mutt_flushinp (); \ 86 mutt_error _(No_visible); \ 87 break; \ 88 } 89 90 91#define CHECK_READONLY if (Context->readonly) \ 92 { \ 93 mutt_flushinp (); \ 94 mutt_error _(Mailbox_is_read_only); \ 95 break; \ 96 } 97 98#define CHECK_ACL(aclbit,action) \ 99 if (!mutt_bit_isset(Context->rights,aclbit)) { \ 100 mutt_flushinp(); \ 101 /* L10N: %s is one of the CHECK_ACL entries below. */ \ 102 mutt_error (_("%s: Operation not permitted by ACL"), action); \ 103 break; \ 104 } 105 106#define CHECK_ATTACH if(option(OPTATTACHMSG)) \ 107 {\ 108 mutt_flushinp (); \ 109 mutt_error _(Function_not_permitted_in_attach_message_mode); \ 110 break; \ 111 } 112 113#define CURHDR Context->hdrs[Context->v2r[menu->current]] 114#define OLDHDR Context->hdrs[Context->v2r[menu->oldcurrent]] 115#define UNREAD(h) mutt_thread_contains_unread (Context, h) 116 117/* de facto standard escapes for tsl/fsl */ 118static char *tsl = "\033]0;"; 119static char *fsl = "\007"; 120 121/* terminal status capability check. terminfo must have been initialized. */ 122short mutt_ts_capability(void) 123{ 124 char *term = getenv("TERM"); 125 char *tcaps; 126 int tcapi; 127 char **termp; 128 char *known[] = { 129 "color-xterm", 130 "cygwin", 131 "eterm", 132 "kterm", 133 "nxterm", 134 "putty", 135 "rxvt", 136 "screen", 137 "xterm", 138 NULL 139 }; 140 141 /* If tsl is set, then terminfo says that status lines work. */ 142 tcaps = tigetstr("tsl"); 143 if (tcaps && tcaps != (char *)-1 && *tcaps) 144 { 145 /* update the static defns of tsl/fsl from terminfo */ 146 tsl = safe_strdup(tcaps); 147 148 tcaps = tigetstr("fsl"); 149 if (tcaps && tcaps != (char *)-1 && *tcaps) 150 fsl = safe_strdup(tcaps); 151 152 return 1; 153 } 154 155 /* If XT (boolean) is set, then this terminal supports the standard escape. */ 156 /* Beware: tigetflag returns -1 if XT is invalid or not a boolean. */ 157#ifdef HAVE_USE_EXTENDED_NAMES 158 use_extended_names (TRUE); 159 tcapi = tigetflag("XT"); 160 if (tcapi == 1) 161 return 1; 162#endif /* HAVE_USE_EXTENDED_NAMES */ 163 164 /* Check term types that are known to support the standard escape without 165 * necessarily asserting it in terminfo. */ 166 for (termp = known; termp; termp++) 167 { 168 if (term && *termp && mutt_strncasecmp (term, *termp, strlen(*termp))) 169 return 1; 170 } 171 172 /* not supported */ 173 return 0; 174} 175 176void mutt_ts_status(char *str) 177{ 178 /* If empty, do not set. To clear, use a single space. */ 179 if (str == NULL || *str == '\0') 180 return; 181 fprintf(stderr, "%s%s%s", tsl, str, fsl); 182} 183 184void mutt_ts_icon(char *str) 185{ 186 /* If empty, do not set. To clear, use a single space. */ 187 if (str == NULL || *str == '\0') 188 return; 189 190 /* icon setting is not supported in terminfo, so hardcode the escape - yuck */ 191 fprintf(stderr, "\033]1;%s\007", str); 192} 193 194void index_make_entry (char *s, size_t l, MUTTMENU *menu, int num) 195{ 196 format_flag flag = MUTT_FORMAT_MAKEPRINT | MUTT_FORMAT_ARROWCURSOR | MUTT_FORMAT_INDEX; 197 int edgemsgno, reverse = Sort & SORT_REVERSE; 198 HEADER *h = Context->hdrs[Context->v2r[num]]; 199 THREAD *tmp; 200 201 if ((Sort & SORT_MASK) == SORT_THREADS && h->tree) 202 { 203 flag |= MUTT_FORMAT_TREE; /* display the thread tree */ 204 if (h->display_subject) 205 flag |= MUTT_FORMAT_FORCESUBJ; 206 else 207 { 208 if (reverse) 209 { 210 if (menu->top + menu->pagelen > menu->max) 211 edgemsgno = Context->v2r[menu->max - 1]; 212 else 213 edgemsgno = Context->v2r[menu->top + menu->pagelen - 1]; 214 } 215 else 216 edgemsgno = Context->v2r[menu->top]; 217 218 for (tmp = h->thread->parent; tmp; tmp = tmp->parent) 219 { 220 if (!tmp->message) 221 continue; 222 223 /* if no ancestor is visible on current screen, provisionally force 224 * subject... */ 225 if (reverse ? tmp->message->msgno > edgemsgno : tmp->message->msgno < edgemsgno) 226 { 227 flag |= MUTT_FORMAT_FORCESUBJ; 228 break; 229 } 230 else if (tmp->message->virtual >= 0) 231 break; 232 } 233 if (flag & MUTT_FORMAT_FORCESUBJ) 234 { 235 for (tmp = h->thread->prev; tmp; tmp = tmp->prev) 236 { 237 if (!tmp->message) 238 continue; 239 240 /* ...but if a previous sibling is available, don't force it */ 241 if (reverse ? tmp->message->msgno > edgemsgno : tmp->message->msgno < edgemsgno) 242 break; 243 else if (tmp->message->virtual >= 0) 244 { 245 flag &= ~MUTT_FORMAT_FORCESUBJ; 246 break; 247 } 248 } 249 } 250 } 251 } 252 253 _mutt_make_string (s, l, NONULL (HdrFmt), Context, h, flag); 254} 255 256int index_color (int index_no) 257{ 258 HEADER *h = Context->hdrs[Context->v2r[index_no]]; 259 260 if (h && h->pair) 261 return h->pair; 262 263 mutt_set_header_color (Context, h); 264 return h->pair; 265} 266 267static int ci_next_undeleted (int msgno) 268{ 269 int i; 270 271 for (i=msgno+1; i < Context->vcount; i++) 272 if (! Context->hdrs[Context->v2r[i]]->deleted) 273 return (i); 274 return (-1); 275} 276 277static int ci_previous_undeleted (int msgno) 278{ 279 int i; 280 281 for (i=msgno-1; i>=0; i--) 282 if (! Context->hdrs[Context->v2r[i]]->deleted) 283 return (i); 284 return (-1); 285} 286 287/* Return the index of the first new message, or failing that, the first 288 * unread message. 289 */ 290static int ci_first_message (void) 291{ 292 int old = -1, i; 293 294 if (Context && Context->msgcount) 295 { 296 for (i=0; i < Context->vcount; i++) 297 { 298 if (! Context->hdrs[Context->v2r[i]]->read && 299 ! Context->hdrs[Context->v2r[i]]->deleted) 300 { 301 if (! Context->hdrs[Context->v2r[i]]->old) 302 return (i); 303 else if (old == -1) 304 old = i; 305 } 306 } 307 if (old != -1) 308 return (old); 309 310 /* If Sort is reverse and not threaded, the latest message is first. 311 * If Sort is threaded, the latest message is first iff exactly one 312 * of Sort and SortAux are reverse. 313 */ 314 if (((Sort & SORT_REVERSE) && (Sort & SORT_MASK) != SORT_THREADS) || 315 ((Sort & SORT_MASK) == SORT_THREADS && 316 ((Sort ^ SortAux) & SORT_REVERSE))) 317 return 0; 318 else 319 return (Context->vcount ? Context->vcount - 1 : 0); 320 } 321 return 0; 322} 323 324/* This should be in mx.c, but it only gets used here. */ 325static int mx_toggle_write (CONTEXT *ctx) 326{ 327 if (!ctx) 328 return -1; 329 330 if (ctx->readonly) 331 { 332 mutt_error _("Cannot toggle write on a readonly mailbox!"); 333 return -1; 334 } 335 336 if (ctx->dontwrite) 337 { 338 ctx->dontwrite = 0; 339 mutt_message _("Changes to folder will be written on folder exit."); 340 } 341 else 342 { 343 ctx->dontwrite = 1; 344 mutt_message _("Changes to folder will not be written."); 345 } 346 347 return 0; 348} 349 350static void update_index (MUTTMENU *menu, CONTEXT *ctx, int check, 351 int oldcount, int index_hint) 352{ 353 /* store pointers to the newly added messages */ 354 HEADER **save_new = NULL; 355 int j; 356 357 /* take note of the current message */ 358 if (oldcount) 359 { 360 if (menu->current < ctx->vcount) 361 menu->oldcurrent = index_hint; 362 else 363 oldcount = 0; /* invalid message number! */ 364 } 365 366 /* We are in a limited view. Check if the new message(s) satisfy 367 * the limit criteria. If they do, set their virtual msgno so that 368 * they will be visible in the limited view */ 369 if (ctx->pattern) 370 { 371#define THIS_BODY ctx->hdrs[j]->content 372 for (j = (check == MUTT_REOPENED) ? 0 : oldcount; j < ctx->msgcount; j++) 373 { 374 if (!j) 375 ctx->vcount = 0; 376 377 if (mutt_pattern_exec (ctx->limit_pattern, 378 MUTT_MATCH_FULL_ADDRESS, 379 ctx, ctx->hdrs[j], NULL)) 380 { 381 assert (ctx->vcount < ctx->msgcount); 382 ctx->hdrs[j]->virtual = ctx->vcount; 383 ctx->v2r[ctx->vcount] = j; 384 ctx->hdrs[j]->limited = 1; 385 ctx->vcount++; 386 ctx->vsize += THIS_BODY->length + THIS_BODY->offset - THIS_BODY->hdr_offset; 387 } 388 } 389#undef THIS_BODY 390 } 391 392 /* save the list of new messages */ 393 if (option(OPTUNCOLLAPSENEW) && oldcount && check != MUTT_REOPENED 394 && ((Sort & SORT_MASK) == SORT_THREADS)) 395 { 396 save_new = (HEADER **) safe_malloc (sizeof (HEADER *) * (ctx->msgcount - oldcount)); 397 for (j = oldcount; j < ctx->msgcount; j++) 398 save_new[j-oldcount] = ctx->hdrs[j]; 399 } 400 401 /* if the mailbox was reopened, need to rethread from scratch */ 402 mutt_sort_headers (ctx, (check == MUTT_REOPENED)); 403 404 /* uncollapse threads with new mail */ 405 if (option(OPTUNCOLLAPSENEW) && ((Sort & SORT_MASK) == SORT_THREADS)) 406 { 407 if (check == MUTT_REOPENED) 408 { 409 THREAD *h, *j; 410 411 ctx->collapsed = 0; 412 413 for (h = ctx->tree; h; h = h->next) 414 { 415 for (j = h; !j->message; j = j->child) 416 ; 417 mutt_uncollapse_thread (ctx, j->message); 418 } 419 mutt_set_virtual (ctx); 420 } 421 else if (oldcount) 422 { 423 for (j = 0; j < ctx->msgcount - oldcount; j++) 424 { 425 int k; 426 427 for (k = 0; k < ctx->msgcount; k++) 428 { 429 HEADER *h = ctx->hdrs[k]; 430 if (h == save_new[j] && (!ctx->pattern || h->limited)) 431 mutt_uncollapse_thread (ctx, h); 432 } 433 } 434 FREE (&save_new); 435 mutt_set_virtual (ctx); 436 } 437 } 438 439 menu->current = -1; 440 if (oldcount) 441 { 442 /* restore the current message to the message it was pointing to */ 443 for (j = 0; j < ctx->vcount; j++) 444 { 445 if (ctx->hdrs[ctx->v2r[j]]->index == menu->oldcurrent) 446 { 447 menu->current = j; 448 break; 449 } 450 } 451 } 452 453 if (menu->current < 0) 454 menu->current = ci_first_message (); 455 456} 457 458static void resort_index (MUTTMENU *menu) 459{ 460 int i; 461 HEADER *current = CURHDR; 462 463 menu->current = -1; 464 mutt_sort_headers (Context, 0); 465 /* Restore the current message */ 466 467 for (i = 0; i < Context->vcount; i++) 468 { 469 if (Context->hdrs[Context->v2r[i]] == current) 470 { 471 menu->current = i; 472 break; 473 } 474 } 475 476 if ((Sort & SORT_MASK) == SORT_THREADS && menu->current < 0) 477 menu->current = mutt_parent_message (Context, current, 0); 478 479 if (menu->current < 0) 480 menu->current = ci_first_message (); 481 482 menu->redraw = REDRAW_INDEX | REDRAW_STATUS; 483} 484 485static const struct mapping_t IndexHelp[] = { 486 { N_("Quit"), OP_QUIT }, 487 { N_("Del"), OP_DELETE }, 488 { N_("Undel"), OP_UNDELETE }, 489 { N_("Save"), OP_SAVE }, 490 { N_("Mail"), OP_MAIL }, 491 { N_("Reply"), OP_REPLY }, 492 { N_("Group"), OP_GROUP_REPLY }, 493 { N_("Help"), OP_HELP }, 494 { NULL, 0 } 495}; 496 497/* This function handles the message index window as well as commands returned 498 * from the pager (MENU_PAGER). 499 */ 500int mutt_index_menu (void) 501{ 502 char buf[LONG_STRING], helpstr[LONG_STRING]; 503 int op = OP_NULL; 504 int done = 0; /* controls when to exit the "event" loop */ 505 int i = 0, j; 506 int tag = 0; /* has the tag-prefix command been pressed? */ 507 int newcount = -1; 508 int oldcount = -1; 509 int rc = -1; 510 MUTTMENU *menu; 511 char *cp; /* temporary variable. */ 512 int index_hint; /* used to restore cursor position */ 513 int do_buffy_notify = 1; 514 int close = 0; /* did we OP_QUIT or OP_EXIT out of this menu? */ 515 int attach_msg = option(OPTATTACHMSG); 516 517 menu = mutt_new_menu (MENU_MAIN); 518 menu->make_entry = index_make_entry; 519 menu->color = index_color; 520 menu->current = ci_first_message (); 521 menu->help = mutt_compile_help (helpstr, sizeof (helpstr), MENU_MAIN, IndexHelp); 522 523 if (!attach_msg) 524 mutt_buffy_check(1); /* force the buffy check after we enter the folder */ 525 526 FOREVER 527 { 528 tag = 0; /* clear the tag-prefix */ 529 530 /* check if we need to resort the index because just about 531 * any 'op' below could do mutt_enter_command(), either here or 532 * from any new menu launched, and change $sort/$sort_aux 533 */ 534 if (option (OPTNEEDRESORT) && Context && Context->msgcount && menu->current >= 0) 535 resort_index (menu); 536 537 menu->max = Context ? Context->vcount : 0; 538 oldcount = Context ? Context->msgcount : 0; 539 540 if (option (OPTREDRAWTREE) && Context && Context->msgcount && (Sort & SORT_MASK) == SORT_THREADS) 541 { 542 mutt_draw_tree (Context); 543 menu->redraw |= REDRAW_STATUS; 544 unset_option (OPTREDRAWTREE); 545 } 546 547 if (Context && !attach_msg) 548 { 549 int check; 550 /* check for new mail in the mailbox. If nonzero, then something has 551 * changed about the file (either we got new mail or the file was 552 * modified underneath us.) 553 */ 554 555 index_hint = (Context->vcount && menu->current >= 0 && menu->current < Context->vcount) ? CURHDR->index : 0; 556 557 if ((check = mx_check_mailbox (Context, &index_hint)) < 0) 558 { 559 if (!Context->path) 560 { 561 /* fatal error occurred */ 562 FREE (&Context); 563 menu->redraw = REDRAW_FULL; 564 } 565 566 set_option (OPTSEARCHINVALID); 567 } 568 else if (check == MUTT_NEW_MAIL || check == MUTT_REOPENED || check == MUTT_FLAGS) 569 { 570 update_index (menu, Context, check, oldcount, index_hint); 571 572 /* notify the user of new mail */ 573 if (check == MUTT_REOPENED) 574 mutt_error _("Mailbox was externally modified. Flags may be wrong."); 575 else if (check == MUTT_NEW_MAIL) 576 { 577 mutt_message _("New mail in this mailbox."); 578 if (option (OPTBEEPNEW)) 579 beep (); 580 } else if (check == MUTT_FLAGS) 581 mutt_message _("Mailbox was externally modified."); 582 583 /* avoid the message being overwritten by buffy */ 584 do_buffy_notify = 0; 585 586 menu->redraw = REDRAW_FULL; 587 menu->max = Context->vcount; 588 589 set_option (OPTSEARCHINVALID); 590 } 591 } 592 593 if (!attach_msg) 594 { 595 /* check for new mail in the incoming folders */ 596 oldcount = newcount; 597 if ((newcount = mutt_buffy_check (0)) != oldcount) 598 menu->redraw |= REDRAW_STATUS; 599 if (do_buffy_notify) 600 { 601 if (mutt_buffy_notify()) 602 { 603 menu->redraw |= REDRAW_STATUS; 604 if (option (OPTBEEPNEW)) 605 beep(); 606 } 607 } 608 else 609 do_buffy_notify = 1; 610 } 611 612 if (op != -1) 613 mutt_curs_set (0); 614 615 if (menu->redraw & REDRAW_FULL) 616 { 617 menu_redraw_full (menu); 618 mutt_show_error (); 619 } 620 621 if (menu->menu == MENU_MAIN) 622 { 623#ifdef USE_SIDEBAR 624 if (menu->redraw & REDRAW_SIDEBAR || SidebarNeedsRedraw) 625 { 626 mutt_sb_set_buffystats (Context); 627 menu_redraw_sidebar (menu); 628 } 629#endif 630 if (Context && Context->hdrs && !(menu->current >= Context->vcount)) 631 { 632 menu_check_recenter (menu); 633 634 if (menu->redraw & REDRAW_INDEX) 635 { 636 menu_redraw_index (menu); 637 menu->redraw |= REDRAW_STATUS; 638 } 639 else if (menu->redraw & (REDRAW_MOTION_RESYNCH | REDRAW_MOTION)) 640 menu_redraw_motion (menu); 641 else if (menu->redraw & REDRAW_CURRENT) 642 menu_redraw_current (menu); 643 } 644 645 if (menu->redraw & REDRAW_STATUS) 646 { 647 menu_status_line (buf, sizeof (buf), menu, NONULL (Status)); 648 mutt_window_move (MuttStatusWindow, 0, 0); 649 SETCOLOR (MT_COLOR_STATUS); 650 mutt_paddstr (MuttStatusWindow->cols, buf); 651 NORMAL_COLOR; 652 menu->redraw &= ~REDRAW_STATUS; 653 if (option(OPTTSENABLED) && TSSupported) 654 { 655 menu_status_line (buf, sizeof (buf), menu, NONULL (TSStatusFormat)); 656 mutt_ts_status(buf); 657 menu_status_line (buf, sizeof (buf), menu, NONULL (TSIconFormat)); 658 mutt_ts_icon(buf); 659 } 660 } 661 662 menu->redraw = 0; 663 if (menu->current < menu->max) 664 menu->oldcurrent = menu->current; 665 else 666 menu->oldcurrent = -1; 667 668 if (option (OPTARROWCURSOR)) 669 mutt_window_move (MuttIndexWindow, menu->current - menu->top + menu->offset, 2); 670 else if (option (OPTBRAILLEFRIENDLY)) 671 mutt_window_move (MuttIndexWindow, menu->current - menu->top + menu->offset, 0); 672 else 673 mutt_window_move (MuttIndexWindow, menu->current - menu->top + menu->offset, 674 MuttIndexWindow->cols - 1); 675 mutt_refresh (); 676 677#if defined (USE_SLANG_CURSES) || defined (HAVE_RESIZETERM) 678 if (SigWinch) 679 { 680 mutt_flushinp (); 681 mutt_resize_screen (); 682 menu->redraw = REDRAW_FULL; 683 menu->menu = MENU_MAIN; 684 SigWinch = 0; 685 menu->top = 0; /* so we scroll the right amount */ 686 /* 687 * force a real complete redraw. clrtobot() doesn't seem to be able 688 * to handle every case without this. 689 */ 690 clearok(stdscr,TRUE); 691 continue; 692 } 693#endif 694 695 op = km_dokey (MENU_MAIN); 696 697 dprint(4, (debugfile, "mutt_index_menu[%d]: Got op %d\n", __LINE__, op)); 698 699 if (op == -1) 700 continue; /* either user abort or timeout */ 701 702 mutt_curs_set (1); 703 704 /* special handling for the tag-prefix function */ 705 if (op == OP_TAG_PREFIX) 706 { 707 if (!Context) 708 { 709 mutt_error _("No mailbox is open."); 710 continue; 711 } 712 713 if (!Context->tagged) 714 { 715 mutt_error _("No tagged messages."); 716 continue; 717 } 718 tag = 1; 719 720 /* give visual indication that the next command is a tag- command */ 721 mutt_window_mvaddstr (MuttMessageWindow, 0, 0, "tag-"); 722 mutt_window_clrtoeol (MuttMessageWindow); 723 724 /* get the real command */ 725 if ((op = km_dokey (MENU_MAIN)) == OP_TAG_PREFIX) 726 { 727 /* abort tag sequence */ 728 mutt_window_clearline (MuttMessageWindow, 0); 729 continue; 730 } 731 } 732 else if (option (OPTAUTOTAG) && Context && Context->tagged) 733 tag = 1; 734 735 if (op == OP_TAG_PREFIX_COND) 736 { 737 if (!Context) 738 { 739 mutt_error _("No mailbox is open."); 740 continue; 741 } 742 743 if (!Context->tagged) 744 { 745 mutt_flush_macro_to_endcond (); 746 mutt_message _("Nothing to do."); 747 continue; 748 } 749 tag = 1; 750 751 /* give visual indication that the next command is a tag- command */ 752 mutt_window_mvaddstr (MuttMessageWindow, 0, 0, "tag-"); 753 mutt_window_clrtoeol (MuttMessageWindow); 754 755 /* get the real command */ 756 if ((op = km_dokey (MENU_MAIN)) == OP_TAG_PREFIX) 757 { 758 /* abort tag sequence */ 759 mutt_window_clearline (MuttMessageWindow, 0); 760 continue; 761 } 762 } 763 764 mutt_clear_error (); 765 } 766 else 767 { 768 if (menu->current < menu->max) 769 menu->oldcurrent = menu->current; 770 else 771 menu->oldcurrent = -1; 772 773 mutt_curs_set (1); /* fallback from the pager */ 774 } 775 776 switch (op) 777 { 778 779 /* ---------------------------------------------------------------------- 780 * movement commands 781 */ 782 783 case OP_BOTTOM_PAGE: 784 menu_bottom_page (menu); 785 break; 786 case OP_FIRST_ENTRY: 787 menu_first_entry (menu); 788 break; 789 case OP_MIDDLE_PAGE: 790 menu_middle_page (menu); 791 break; 792 case OP_HALF_UP: 793 menu_half_up (menu); 794 break; 795 case OP_HALF_DOWN: 796 menu_half_down (menu); 797 break; 798 case OP_NEXT_LINE: 799 menu_next_line (menu); 800 break; 801 case OP_PREV_LINE: 802 menu_prev_line (menu); 803 break; 804 case OP_NEXT_PAGE: 805 menu_next_page (menu); 806 break; 807 case OP_PREV_PAGE: 808 menu_prev_page (menu); 809 break; 810 case OP_LAST_ENTRY: 811 menu_last_entry (menu); 812 break; 813 case OP_TOP_PAGE: 814 menu_top_page (menu); 815 break; 816 case OP_CURRENT_TOP: 817 menu_current_top (menu); 818 break; 819 case OP_CURRENT_MIDDLE: 820 menu_current_middle (menu); 821 break; 822 case OP_CURRENT_BOTTOM: 823 menu_current_bottom (menu); 824 break; 825 826 case OP_JUMP: 827 828 CHECK_MSGCOUNT; 829 CHECK_VISIBLE; 830 if (isdigit (LastKey)) mutt_unget_event (LastKey, 0); 831 buf[0] = 0; 832 if (mutt_get_field (_("Jump to message: "), buf, sizeof (buf), 0) != 0 833 || !buf[0]) 834 { 835 if (menu->menu == MENU_PAGER) 836 { 837 op = OP_DISPLAY_MESSAGE; 838 continue; 839 } 840 break; 841 } 842 843 if (mutt_atoi (buf, &i) < 0) 844 { 845 mutt_error _("Argument must be a message number."); 846 break; 847 } 848 849 if (i > 0 && i <= Context->msgcount) 850 { 851 for (j = i-1; j < Context->msgcount; j++) 852 { 853 if (Context->hdrs[j]->virtual != -1) 854 break; 855 } 856 if (j >= Context->msgcount) 857 { 858 for (j = i-2; j >= 0; j--) 859 { 860 if (Context->hdrs[j]->virtual != -1) 861 break; 862 } 863 } 864 865 if (j >= 0) 866 { 867 menu->current = Context->hdrs[j]->virtual; 868 if (menu->menu == MENU_PAGER) 869 { 870 op = OP_DISPLAY_MESSAGE; 871 continue; 872 } 873 else 874 menu->redraw = REDRAW_MOTION; 875 } 876 else 877 mutt_error _("That message is not visible."); 878 } 879 else 880 mutt_error _("Invalid message number."); 881 882 break; 883 884 /* -------------------------------------------------------------------- 885 * `index' specific commands 886 */ 887 888 case OP_MAIN_DELETE_PATTERN: 889 890 CHECK_MSGCOUNT; 891 CHECK_VISIBLE; 892 CHECK_READONLY; 893 /* L10N: CHECK_ACL */ 894 CHECK_ACL(MUTT_ACL_DELETE, _("Cannot delete message(s)")); 895 896 CHECK_ATTACH; 897 mutt_pattern_func (MUTT_DELETE, _("Delete messages matching: ")); 898 menu->redraw = REDRAW_INDEX | REDRAW_STATUS; 899 break; 900 901#ifdef USE_POP 902 case OP_MAIN_FETCH_MAIL: 903 904 CHECK_ATTACH; 905 pop_fetch_mail (); 906 menu->redraw = REDRAW_FULL; 907 break; 908#endif /* USE_POP */ 909 910 case OP_HELP: 911 912 mutt_help (MENU_MAIN); 913 menu->redraw = REDRAW_FULL; 914 break; 915 916 case OP_MAIN_SHOW_LIMIT: 917 CHECK_IN_MAILBOX; 918 if (!Context->pattern) 919 mutt_message _("No limit pattern is in effect."); 920 else 921 { 922 char buf[STRING]; 923 /* L10N: ask for a limit to apply */ 924 snprintf (buf, sizeof(buf), _("Limit: %s"),Context->pattern); 925 mutt_message ("%s", buf); 926 } 927 break; 928 929 case OP_MAIN_LIMIT: 930 931 CHECK_IN_MAILBOX; 932 menu->oldcurrent = (Context->vcount && menu->current >= 0 && menu->current < Context->vcount) ? 933 CURHDR->index : -1; 934 if (mutt_pattern_func (MUTT_LIMIT, _("Limit to messages matching: ")) == 0) 935 { 936 if (menu->oldcurrent >= 0) 937 { 938 /* try to find what used to be the current message */ 939 menu->current = -1; 940 for (i = 0; i < Context->vcount; i++) 941 if (Context->hdrs[Context->v2r[i]]->index == menu->oldcurrent) 942 { 943 menu->current = i; 944 break; 945 } 946 if (menu->current < 0) menu->current = 0; 947 } 948 else 949 menu->current = 0; 950 menu->redraw = REDRAW_INDEX | REDRAW_STATUS; 951 if (Context->msgcount && (Sort & SORT_MASK) == SORT_THREADS) 952 mutt_draw_tree (Context); 953 menu->redraw = REDRAW_FULL; 954 } 955 if (Context->pattern) 956 mutt_message _("To view all messages, limit to \"all\"."); 957 break; 958 959 case OP_QUIT: 960 961 close = op; 962 if (attach_msg) 963 { 964 done = 1; 965 break; 966 } 967 968 if (query_quadoption (OPT_QUIT, _("Quit Mutt?")) == MUTT_YES) 969 { 970 int check; 971 972 oldcount = Context ? Context->msgcount : 0; 973 974 if (!Context || (check = mx_close_mailbox (Context, &index_hint)) == 0) 975 done = 1; 976 else 977 { 978 if (check == MUTT_NEW_MAIL || check == MUTT_REOPENED) 979 update_index (menu, Context, check, oldcount, index_hint); 980 981 menu->redraw = REDRAW_FULL; /* new mail arrived? */ 982 set_option (OPTSEARCHINVALID); 983 } 984 } 985 break; 986 987 case OP_REDRAW: 988 989 clearok (stdscr, TRUE); 990 menu->redraw = REDRAW_FULL; 991 break; 992 993 case OP_SEARCH: 994 case OP_SEARCH_REVERSE: 995 case OP_SEARCH_NEXT: 996 case OP_SEARCH_OPPOSITE: 997 998 CHECK_MSGCOUNT; 999 CHECK_VISIBLE; 1000 if ((menu->current = mutt_search_command (menu->current, op)) == -1) 1001 menu->current = menu->oldcurrent; 1002 else 1003 menu->redraw = REDRAW_MOTION; 1004 break; 1005 1006 case OP_SORT: 1007 case OP_SORT_REVERSE: 1008 1009 if (mutt_select_sort ((op == OP_SORT_REVERSE)) == 0) 1010 { 1011 if (Context && Context->msgcount) 1012 { 1013 resort_index (menu); 1014 set_option (OPTSEARCHINVALID); 1015 } 1016 if (menu->menu == MENU_PAGER) 1017 { 1018 op = OP_DISPLAY_MESSAGE; 1019 continue; 1020 } 1021 menu->redraw |= REDRAW_STATUS; 1022 } 1023 break; 1024 1025 case OP_TAG: 1026 1027 CHECK_MSGCOUNT; 1028 CHECK_VISIBLE; 1029 if (tag && !option (OPTAUTOTAG)) 1030 { 1031 for (j = 0; j < Context->vcount; j++) 1032 mutt_set_flag (Context, Context->hdrs[Context->v2r[j]], MUTT_TAG, 0); 1033 menu->redraw = REDRAW_STATUS | REDRAW_INDEX; 1034 } 1035 else 1036 { 1037 mutt_set_flag (Context, CURHDR, MUTT_TAG, !CURHDR->tagged); 1038 1039 Context->last_tag = CURHDR->tagged ? CURHDR : 1040 ((Context->last_tag == CURHDR && !CURHDR->tagged) 1041 ? NULL : Context->last_tag); 1042 1043 menu->redraw = REDRAW_STATUS; 1044 if (option (OPTRESOLVE) && menu->current < Context->vcount - 1) 1045 { 1046 menu->current++; 1047 menu->redraw |= REDRAW_MOTION_RESYNCH; 1048 } 1049 else 1050 menu->redraw |= REDRAW_CURRENT; 1051 } 1052 break; 1053 1054 case OP_MAIN_TAG_PATTERN: 1055 1056 CHECK_MSGCOUNT; 1057 CHECK_VISIBLE; 1058 mutt_pattern_func (MUTT_TAG, _("Tag messages matching: ")); 1059 menu->redraw = REDRAW_INDEX | REDRAW_STATUS; 1060 break; 1061 1062 case OP_MAIN_UNDELETE_PATTERN: 1063 1064 CHECK_MSGCOUNT; 1065 CHECK_VISIBLE; 1066 CHECK_READONLY; 1067 /* L10N: CHECK_ACL */ 1068 CHECK_ACL(MUTT_ACL_DELETE, _("Cannot undelete message(s)")); 1069 1070 if (mutt_pattern_func (MUTT_UNDELETE, _("Undelete messages matching: ")) == 0) 1071 menu->redraw = REDRAW_INDEX | REDRAW_STATUS; 1072 break; 1073 1074 case OP_MAIN_UNTAG_PATTERN: 1075 1076 CHECK_MSGCOUNT; 1077 CHECK_VISIBLE; 1078 if (mutt_pattern_func (MUTT_UNTAG, _("Untag messages matching: ")) == 0) 1079 menu->redraw = REDRAW_INDEX | REDRAW_STATUS; 1080 break; 1081 1082 /* -------------------------------------------------------------------- 1083 * The following operations can be performed inside of the pager. 1084 */ 1085 1086#ifdef USE_IMAP 1087 case OP_MAIN_IMAP_FETCH: 1088 if (Context && Context->magic == MUTT_IMAP) 1089 imap_check_mailbox (Context, &index_hint, 1); 1090 break; 1091 1092 case OP_MAIN_IMAP_LOGOUT_ALL: 1093 if (Context && Context->magic == MUTT_IMAP) 1094 { 1095 if (mx_close_mailbox (Context, &index_hint) != 0) 1096 { 1097 set_option (OPTSEARCHINVALID); 1098 menu->redraw = REDRAW_FULL; 1099 break; 1100 } 1101 FREE (&Context); 1102 } 1103 imap_logout_all(); 1104 mutt_message _("Logged out of IMAP servers."); 1105 set_option (OPTSEARCHINVALID); 1106 menu->redraw = REDRAW_FULL; 1107 break; 1108#endif 1109 1110 case OP_MAIN_SYNC_FOLDER: 1111 1112 if (Context && !Context->msgcount) 1113 break; 1114 1115 CHECK_MSGCOUNT; 1116 CHECK_READONLY; 1117 { 1118 int oldvcount = Context->vcount; 1119 int oldcount = Context->msgcount; 1120 int check, newidx; 1121 HEADER *newhdr = NULL; 1122 1123 /* don't attempt to move the cursor if there are no visible messages in the current limit */ 1124 if (menu->current < Context->vcount) 1125 { 1126 /* threads may be reordered, so figure out what header the cursor 1127 * should be on. #3092 */ 1128 newidx = menu->current; 1129 if (CURHDR->deleted) 1130 newidx = ci_next_undeleted (menu->current); 1131 if (newidx < 0) 1132 newidx = ci_previous_undeleted (menu->current); 1133 if (newidx >= 0) 1134 newhdr = Context->hdrs[Context->v2r[newidx]]; 1135 } 1136 1137 if ((check = mx_sync_mailbox (Context, &index_hint)) == 0) 1138 { 1139 if (newhdr && Context->vcount != oldvcount) 1140 for (j = 0; j < Context->vcount; j++) 1141 { 1142 if (Context->hdrs[Context->v2r[j]] == newhdr) 1143 { 1144 menu->current = j; 1145 break; 1146 } 1147 } 1148 set_option (OPTSEARCHINVALID); 1149 } 1150 else if (check == MUTT_NEW_MAIL || check == MUTT_REOPENED) 1151 update_index (menu, Context, check, oldcount, index_hint); 1152 1153 /* 1154 * do a sanity check even if mx_sync_mailbox failed. 1155 */ 1156 1157 if (menu->current < 0 || menu->current >= Context->vcount) 1158 menu->current = ci_first_message (); 1159 } 1160 1161 /* check for a fatal error, or all messages deleted */ 1162 if (!Context->path) 1163 FREE (&Context); 1164 1165 /* if we were in the pager, redisplay the message */ 1166 if (menu->menu == MENU_PAGER) 1167 { 1168 op = OP_DISPLAY_MESSAGE; 1169 continue; 1170 } 1171 else 1172 menu->redraw = REDRAW_FULL; 1173 break; 1174 1175#ifdef USE_SIDEBAR 1176 case OP_SIDEBAR_OPEN: 1177#endif 1178 case OP_MAIN_CHANGE_FOLDER: 1179 case OP_MAIN_NEXT_UNREAD_MAILBOX: 1180 1181 if (attach_msg) 1182 op = OP_MAIN_CHANGE_FOLDER_READONLY; 1183 1184 /* fallback to the readonly case */ 1185 1186 case OP_MAIN_CHANGE_FOLDER_READONLY: 1187 1188 if ((op == OP_MAIN_CHANGE_FOLDER_READONLY) || option (OPTREADONLY)) 1189 cp = _("Open mailbox in read-only mode"); 1190 else 1191 cp = _("Open mailbox"); 1192 1193 buf[0] = '\0'; 1194 if ((op == OP_MAIN_NEXT_UNREAD_MAILBOX) && Context && Context->path) 1195 { 1196 strfcpy (buf, Context->path, sizeof (buf)); 1197 mutt_pretty_mailbox (buf, sizeof (buf)); 1198 mutt_buffy (buf, sizeof (buf)); 1199 if (!buf[0]) 1200 { 1201 mutt_error _("No mailboxes have new mail"); 1202 break; 1203 } 1204 } 1205#ifdef USE_SIDEBAR 1206 else if (op == OP_SIDEBAR_OPEN) 1207 { 1208 const char *path = mutt_sb_get_highlight(); 1209 if (!path || !*path) 1210 break; 1211 strncpy (buf, path, sizeof (buf)); 1212 } 1213#endif 1214 else 1215 { 1216 mutt_buffy (buf, sizeof (buf)); 1217 1218 if (mutt_enter_fname (cp, buf, sizeof (buf), &menu->redraw, 1) == -1) 1219 { 1220 if (menu->menu == MENU_PAGER) 1221 { 1222 op = OP_DISPLAY_MESSAGE; 1223 continue; 1224 } 1225 else 1226 break; 1227 } 1228 if (!buf[0]) 1229 { 1230 mutt_window_clearline (MuttMessageWindow, 0); 1231 break; 1232 } 1233 } 1234 1235 mutt_expand_path (buf, sizeof (buf)); 1236 if (mx_get_magic (buf) <= 0) 1237 { 1238 mutt_error (_("%s is not a mailbox."), buf); 1239 break; 1240 } 1241 mutt_str_replace (&CurrentFolder, buf); 1242 1243 /* keepalive failure in mutt_enter_fname may kill connection. #3028 */ 1244 if (Context && !Context->path) 1245 FREE (&Context); 1246 1247 if (Context) 1248 { 1249 int check; 1250 1251#ifdef USE_COMPRESSED 1252 if (Context->compress_info && Context->realpath) 1253 mutt_str_replace (&LastFolder, Context->realpath); 1254 else 1255#endif 1256 mutt_str_replace (&LastFolder, Context->path); 1257 oldcount = Context ? Context->msgcount : 0; 1258 1259 if ((check = mx_close_mailbox (Context, &index_hint)) != 0) 1260 { 1261 if (check == MUTT_NEW_MAIL || check == MUTT_REOPENED) 1262 update_index (menu, Context, check, oldcount, index_hint); 1263 1264 set_option (OPTSEARCHINVALID); 1265 menu->redraw = REDRAW_INDEX | REDRAW_STATUS; 1266 break; 1267 } 1268 FREE (&Context); 1269 } 1270 1271 mutt_sleep (0); 1272 1273 /* Set CurrentMenu to MENU_MAIN before executing any folder 1274 * hooks so that all the index menu functions are available to 1275 * the exec command. 1276 */ 1277 1278 CurrentMenu = MENU_MAIN; 1279 mutt_folder_hook (buf); 1280 1281 if ((Context = mx_open_mailbox (buf, 1282 (option (OPTREADONLY) || op == OP_MAIN_CHANGE_FOLDER_READONLY) ? 1283 MUTT_READONLY : 0, NULL)) != NULL) 1284 { 1285 menu->current = ci_first_message (); 1286 } 1287 else 1288 menu->current = 0; 1289 1290#ifdef USE_SIDEBAR 1291 mutt_sb_set_open_buffy (); 1292#endif 1293 1294 mutt_clear_error (); 1295 mutt_buffy_check(1); /* force the buffy check after we have changed 1296 the folder */ 1297 menu->redraw = REDRAW_FULL; 1298 set_option (OPTSEARCHINVALID); 1299 break; 1300 1301 case OP_DISPLAY_MESSAGE: 1302 case OP_DISPLAY_HEADERS: /* don't weed the headers */ 1303 1304 CHECK_MSGCOUNT; 1305 CHECK_VISIBLE; 1306 /* 1307 * toggle the weeding of headers so that a user can press the key 1308 * again while reading the message. 1309 */ 1310 if (op == OP_DISPLAY_HEADERS) 1311 toggle_option (OPTWEED); 1312 1313 unset_option (OPTNEEDRESORT); 1314 1315 if ((Sort & SORT_MASK) == SORT_THREADS && CURHDR->collapsed) 1316 { 1317 mutt_uncollapse_thread (Context, CURHDR); 1318 mutt_set_virtual (Context); 1319 if (option (OPTUNCOLLAPSEJUMP)) 1320 menu->current = mutt_thread_next_unread (Context, CURHDR); 1321 } 1322 1323 if (option (OPTPGPAUTODEC) && (tag || !(CURHDR->security & PGP_TRADITIONAL_CHECKED))) 1324 mutt_check_traditional_pgp (tag ? NULL : CURHDR, &menu->redraw); 1325 if ((op = mutt_display_message (CURHDR)) == -1) 1326 { 1327 unset_option (OPTNEEDRESORT); 1328 break; 1329 } 1330 1331 menu->menu = MENU_PAGER; 1332 menu->oldcurrent = menu->current; 1333 continue; 1334 1335 case OP_EXIT: 1336 1337 close = op; 1338 if (menu->menu == MENU_MAIN && attach_msg) 1339 { 1340 done = 1; 1341 break; 1342 } 1343 1344 if ((menu->menu == MENU_MAIN) 1345 && (query_quadoption (OPT_QUIT, 1346 _("Exit Mutt without saving?")) == MUTT_YES)) 1347 { 1348 if (Context) 1349 { 1350 mx_fastclose_mailbox (Context); 1351 FREE (&Context); 1352 } 1353 done = 1; 1354 } 1355 break; 1356 1357 case OP_MAIN_BREAK_THREAD: 1358 1359 CHECK_MSGCOUNT; 1360 CHECK_VISIBLE; 1361 CHECK_READONLY; 1362 1363 if ((Sort & SORT_MASK) != SORT_THREADS) 1364 mutt_error _("Threading is not enabled."); 1365 else if (CURHDR->env->in_reply_to || CURHDR->env->references) 1366 { 1367 { 1368 HEADER *oldcur = CURHDR; 1369 1370 mutt_break_thread (CURHDR); 1371 mutt_sort_headers (Context, 1); 1372 menu->current = oldcur->virtual; 1373 } 1374 1375 Context->changed = 1; 1376 mutt_message _("Thread broken"); 1377 1378 if (menu->menu == MENU_PAGER) 1379 { 1380 op = OP_DISPLAY_MESSAGE; 1381 continue; 1382 } 1383 else 1384 menu->redraw |= REDRAW_INDEX; 1385 } 1386 else 1387 mutt_error _("Thread cannot be broken, message is not part of a thread"); 1388 1389 break; 1390 1391 case OP_MAIN_LINK_THREADS: 1392 1393 CHECK_MSGCOUNT; 1394 CHECK_VISIBLE; 1395 CHECK_READONLY; 1396 /* L10N: CHECK_ACL */ 1397 CHECK_ACL(MUTT_ACL_DELETE, _("Cannot link threads")); 1398 1399 if ((Sort & SORT_MASK) != SORT_THREADS) 1400 mutt_error _("Threading is not enabled."); 1401 else if (!CURHDR->env->message_id) 1402 mutt_error _("No Message-ID: header available to link thread"); 1403 else if (!tag && (!Context->last_tag || !Context->last_tag->tagged)) 1404 mutt_error _("First, please tag a message to be linked here"); 1405 else 1406 { 1407 HEADER *oldcur = CURHDR; 1408 1409 if (mutt_link_threads (CURHDR, tag ? NULL : Context->last_tag, 1410 Context)) 1411 { 1412 mutt_sort_headers (Context, 1); 1413 menu->current = oldcur->virtual; 1414 1415 Context->changed = 1; 1416 mutt_message _("Threads linked"); 1417 } 1418 else 1419 mutt_error _("No thread linked"); 1420 } 1421 1422 if (menu->menu == MENU_PAGER) 1423 { 1424 op = OP_DISPLAY_MESSAGE; 1425 continue; 1426 } 1427 else 1428 menu->redraw |= REDRAW_STATUS | REDRAW_INDEX; 1429 1430 break; 1431 1432 case OP_EDIT_TYPE: 1433 1434 CHECK_MSGCOUNT; 1435 CHECK_VISIBLE; 1436 CHECK_ATTACH; 1437 mutt_edit_content_type (CURHDR, CURHDR->content, NULL); 1438 /* if we were in the pager, redisplay the message */ 1439 if (menu->menu == MENU_PAGER) 1440 { 1441 op = OP_DISPLAY_MESSAGE; 1442 continue; 1443 } 1444 else 1445 menu->redraw = REDRAW_CURRENT; 1446 break; 1447 1448 case OP_MAIN_NEXT_UNDELETED: 1449 1450 CHECK_MSGCOUNT; 1451 CHECK_VISIBLE; 1452 if (menu->current >= Context->vcount - 1) 1453 { 1454 if (menu->menu == MENU_MAIN) 1455 mutt_error _("You are on the last message."); 1456 break; 1457 } 1458 if ((menu->current = ci_next_undeleted (menu->current)) == -1) 1459 { 1460 menu->current = menu->oldcurrent; 1461 if (menu->menu == MENU_MAIN) 1462 mutt_error _("No undeleted messages."); 1463 } 1464 else if (menu->menu == MENU_PAGER) 1465 { 1466 op = OP_DISPLAY_MESSAGE; 1467 continue; 1468 } 1469 else 1470 menu->redraw = REDRAW_MOTION; 1471 break; 1472 1473 case OP_NEXT_ENTRY: 1474 1475 CHECK_MSGCOUNT; 1476 CHECK_VISIBLE; 1477 if (menu->current >= Context->vcount - 1) 1478 { 1479 if (menu->menu == MENU_MAIN) 1480 mutt_error _("You are on the last message."); 1481 break; 1482 } 1483 menu->current++; 1484 if (menu->menu == MENU_PAGER) 1485 { 1486 op = OP_DISPLAY_MESSAGE; 1487 continue; 1488 } 1489 else 1490 menu->redraw = REDRAW_MOTION; 1491 break; 1492 1493 case OP_MAIN_PREV_UNDELETED: 1494 1495 CHECK_MSGCOUNT; 1496 CHECK_VISIBLE; 1497 if (menu->current < 1) 1498 { 1499 mutt_error _("You are on the first message."); 1500 break; 1501 } 1502 if ((menu->current = ci_previous_undeleted (menu->current)) == -1) 1503 { 1504 menu->current = menu->oldcurrent; 1505 if (menu->menu == MENU_MAIN) 1506 mutt_error _("No undeleted messages."); 1507 } 1508 else if (menu->menu == MENU_PAGER) 1509 { 1510 op = OP_DISPLAY_MESSAGE; 1511 continue; 1512 } 1513 else 1514 menu->redraw = REDRAW_MOTION; 1515 break; 1516 1517 case OP_PREV_ENTRY: 1518 1519 CHECK_MSGCOUNT; 1520 CHECK_VISIBLE; 1521 if (menu->current < 1) 1522 { 1523 if (menu->menu == MENU_MAIN) mutt_error _("You are on the first message."); 1524 break; 1525 } 1526 menu->current--; 1527 if (menu->menu == MENU_PAGER) 1528 { 1529 op = OP_DISPLAY_MESSAGE; 1530 continue; 1531 } 1532 else 1533 menu->redraw = REDRAW_MOTION; 1534 break; 1535 1536 case OP_DECRYPT_COPY: 1537 case OP_DECRYPT_SAVE: 1538 if (!WithCrypto) 1539 break; 1540 /* fall thru */ 1541 case OP_COPY_MESSAGE: 1542 case OP_SAVE: 1543 case OP_DECODE_COPY: 1544 case OP_DECODE_SAVE: 1545 CHECK_MSGCOUNT; 1546 CHECK_VISIBLE; 1547 if (mutt_save_message (tag ? NULL : CURHDR, 1548 (op == OP_DECRYPT_SAVE) || 1549 (op == OP_SAVE) || (op == OP_DECODE_SAVE), 1550 (op == OP_DECODE_SAVE) || (op == OP_DECODE_COPY), 1551 (op == OP_DECRYPT_SAVE) || (op == OP_DECRYPT_COPY) || 1552 0, 1553 &menu->redraw) == 0 && 1554 (op == OP_SAVE || op == OP_DECODE_SAVE || op == OP_DECRYPT_SAVE) 1555 ) 1556 { 1557 if (tag) 1558 menu->redraw |= REDRAW_INDEX; 1559 else if (option (OPTRESOLVE)) 1560 { 1561 if ((menu->current = ci_next_undeleted (menu->current)) == -1) 1562 { 1563 menu->current = menu->oldcurrent; 1564 menu->redraw |= REDRAW_CURRENT; 1565 } 1566 else 1567 menu->redraw |= REDRAW_MOTION_RESYNCH; 1568 } 1569 else 1570 menu->redraw |= REDRAW_CURRENT; 1571 } 1572 break; 1573 1574 case OP_MAIN_NEXT_NEW: 1575 case OP_MAIN_NEXT_UNREAD: 1576 case OP_MAIN_PREV_NEW: 1577 case OP_MAIN_PREV_UNREAD: 1578 case OP_MAIN_NEXT_NEW_THEN_UNREAD: 1579 case OP_MAIN_PREV_NEW_THEN_UNREAD: 1580 1581 { 1582 int first_unread = -1; 1583 int first_new = -1; 1584 1585 CHECK_MSGCOUNT; 1586 CHECK_VISIBLE; 1587 1588 i = menu->current; 1589 menu->current = -1; 1590 for (j = 0; j != Context->vcount; j++) 1591 { 1592#define CURHDRi Context->hdrs[Context->v2r[i]] 1593 if (op == OP_MAIN_NEXT_NEW || op == OP_MAIN_NEXT_UNREAD || op == OP_MAIN_NEXT_NEW_THEN_UNREAD) 1594 { 1595 i++; 1596 if (i > Context->vcount - 1) 1597 { 1598 mutt_message _("Search wrapped to top."); 1599 i = 0; 1600 } 1601 } 1602 else 1603 { 1604 i--; 1605 if (i < 0) 1606 { 1607 mutt_message _("Search wrapped to bottom."); 1608 i = Context->vcount - 1; 1609 } 1610 } 1611 1612 if (CURHDRi->collapsed && (Sort & SORT_MASK) == SORT_THREADS) 1613 { 1614 if (UNREAD (CURHDRi) && first_unread == -1) 1615 first_unread = i; 1616 if (UNREAD (CURHDRi) == 1 && first_new == -1) 1617 first_new = i; 1618 } 1619 else if ((!CURHDRi->deleted && !CURHDRi->read)) 1620 { 1621 if (first_unread == -1) 1622 first_unread = i; 1623 if ((!CURHDRi->old) && first_new == -1) 1624 first_new = i; 1625 } 1626 1627 if ((op == OP_MAIN_NEXT_UNREAD || op == OP_MAIN_PREV_UNREAD) && 1628 first_unread != -1) 1629 break; 1630 if ((op == OP_MAIN_NEXT_NEW || op == OP_MAIN_PREV_NEW || 1631 op == OP_MAIN_NEXT_NEW_THEN_UNREAD || op == OP_MAIN_PREV_NEW_THEN_UNREAD) 1632 && first_new != -1) 1633 break; 1634 } 1635#undef CURHDRi 1636 if ((op == OP_MAIN_NEXT_NEW || op == OP_MAIN_PREV_NEW || 1637 op == OP_MAIN_NEXT_NEW_THEN_UNREAD || op == OP_MAIN_PREV_NEW_THEN_UNREAD) 1638 && first_new != -1) 1639 menu->current = first_new; 1640 else if ((op == OP_MAIN_NEXT_UNREAD || op == OP_MAIN_PREV_UNREAD || 1641 op == OP_MAIN_NEXT_NEW_THEN_UNREAD || op == OP_MAIN_PREV_NEW_THEN_UNREAD) 1642 && first_unread != -1) 1643 menu->current = first_unread; 1644 1645 if (menu->current == -1) 1646 { 1647 menu->current = menu->oldcurrent; 1648 if (op == OP_MAIN_NEXT_NEW || op == OP_MAIN_PREV_NEW) 1649 { 1650 if (Context->pattern) 1651 mutt_error (_("No new messages in this limited view.")); 1652 else 1653 mutt_error (_("No new messages.")); 1654 } 1655 else 1656 { 1657 if (Context->pattern) 1658 mutt_error (_("No unread messages in this limited view.")); 1659 else 1660 mutt_error (_("No unread messages.")); 1661 } 1662 } 1663 else if (menu->menu == MENU_PAGER) 1664 { 1665 op = OP_DISPLAY_MESSAGE; 1666 continue; 1667 } 1668 else 1669 menu->redraw = REDRAW_MOTION; 1670 break; 1671 } 1672 case OP_FLAG_MESSAGE: 1673 1674 CHECK_MSGCOUNT; 1675 CHECK_VISIBLE; 1676 CHECK_READONLY; 1677 /* L10N: CHECK_ACL */ 1678 CHECK_ACL(MUTT_ACL_WRITE, _("Cannot flag message")); 1679 1680 if (tag) 1681 { 1682 for (j = 0; j < Context->vcount; j++) 1683 { 1684 if (Context->hdrs[Context->v2r[j]]->tagged) 1685 mutt_set_flag (Context, Context->hdrs[Context->v2r[j]], 1686 MUTT_FLAG, !Context->hdrs[Context->v2r[j]]->flagged); 1687 } 1688 1689 menu->redraw |= REDRAW_INDEX; 1690 } 1691 else 1692 { 1693 mutt_set_flag (Context, CURHDR, MUTT_FLAG, !CURHDR->flagged); 1694 if (option (OPTRESOLVE)) 1695 { 1696 if ((menu->current = ci_next_undeleted (menu->current)) == -1) 1697 { 1698 menu->current = menu->oldcurrent; 1699 menu->redraw = REDRAW_CURRENT; 1700 } 1701 else 1702 menu->redraw = REDRAW_MOTION_RESYNCH; 1703 } 1704 else 1705 menu->redraw = REDRAW_CURRENT; 1706 } 1707 menu->redraw |= REDRAW_STATUS; 1708 break; 1709 1710 case OP_TOGGLE_NEW: 1711 1712 CHECK_MSGCOUNT; 1713 CHECK_VISIBLE; 1714 CHECK_READONLY; 1715 /* L10N: CHECK_ACL */ 1716 CHECK_ACL(MUTT_ACL_SEEN, _("Cannot toggle new")); 1717 1718 if (tag) 1719 { 1720 for (j = 0; j < Context->vcount; j++) 1721 { 1722 if (Context->hdrs[Context->v2r[j]]->tagged) 1723 { 1724 if (Context->hdrs[Context->v2r[j]]->read || 1725 Context->hdrs[Context->v2r[j]]->old) 1726 mutt_set_flag (Context, Context->hdrs[Context->v2r[j]], MUTT_NEW, 1); 1727 else 1728 mutt_set_flag (Context, Context->hdrs[Context->v2r[j]], MUTT_READ, 1); 1729 } 1730 } 1731 menu->redraw = REDRAW_STATUS | REDRAW_INDEX; 1732 } 1733 else 1734 { 1735 if (CURHDR->read || CURHDR->old) 1736 mutt_set_flag (Context, CURHDR, MUTT_NEW, 1); 1737 else 1738 mutt_set_flag (Context, CURHDR, MUTT_READ, 1); 1739 1740 if (option (OPTRESOLVE)) 1741 { 1742 if ((menu->current = ci_next_undeleted (menu->current)) == -1) 1743 { 1744 menu->current = menu->oldcurrent; 1745 menu->redraw = REDRAW_CURRENT; 1746 } 1747 else 1748 menu->redraw = REDRAW_MOTION_RESYNCH; 1749 } 1750 else 1751 menu->redraw = REDRAW_CURRENT; 1752 menu->redraw |= REDRAW_STATUS; 1753 } 1754 break; 1755 1756 case OP_TOGGLE_WRITE: 1757 1758 CHECK_IN_MAILBOX; 1759 if (mx_toggle_write (Context) == 0) 1760 menu->redraw |= REDRAW_STATUS; 1761 break; 1762 1763 case OP_MAIN_NEXT_THREAD: 1764 case OP_MAIN_NEXT_SUBTHREAD: 1765 case OP_MAIN_PREV_THREAD: 1766 case OP_MAIN_PREV_SUBTHREAD: 1767 1768 CHECK_MSGCOUNT; 1769 CHECK_VISIBLE; 1770 switch (op) 1771 { 1772 case OP_MAIN_NEXT_THREAD: 1773 menu->current = mutt_next_thread (CURHDR); 1774 break; 1775 1776 case OP_MAIN_NEXT_SUBTHREAD: 1777 menu->current = mutt_next_subthread (CURHDR); 1778 break; 1779 1780 case OP_MAIN_PREV_THREAD: 1781 menu->current = mutt_previous_thread (CURHDR); 1782 break; 1783 1784 case OP_MAIN_PREV_SUBTHREAD: 1785 menu->current = mutt_previous_subthread (CURHDR); 1786 break; 1787 } 1788 1789 if (menu->current < 0) 1790 { 1791 menu->current = menu->oldcurrent; 1792 if (op == OP_MAIN_NEXT_THREAD || op == OP_MAIN_NEXT_SUBTHREAD) 1793 mutt_error _("No more threads."); 1794 else 1795 mutt_error _("You are on the first thread."); 1796 } 1797 else if (menu->menu == MENU_PAGER) 1798 { 1799 op = OP_DISPLAY_MESSAGE; 1800 continue; 1801 } 1802 else 1803 menu->redraw = REDRAW_MOTION; 1804 break; 1805 1806 case OP_MAIN_ROOT_MESSAGE: 1807 case OP_MAIN_PARENT_MESSAGE: 1808 1809 CHECK_MSGCOUNT; 1810 CHECK_VISIBLE; 1811 1812 if ((menu->current = mutt_parent_message (Context, CURHDR, 1813 op == OP_MAIN_ROOT_MESSAGE)) < 0) 1814 { 1815 menu->current = menu->oldcurrent; 1816 } 1817 else if (menu->menu == MENU_PAGER) 1818 { 1819 op = OP_DISPLAY_MESSAGE; 1820 continue; 1821 } 1822 else 1823 menu->redraw = REDRAW_MOTION; 1824 break; 1825 1826 case OP_MAIN_SET_FLAG: 1827 case OP_MAIN_CLEAR_FLAG: 1828 1829 CHECK_MSGCOUNT; 1830 CHECK_VISIBLE; 1831 CHECK_READONLY; 1832 /* CHECK_ACL(MUTT_ACL_WRITE); */ 1833 1834 if (mutt_change_flag (tag ? NULL : CURHDR, (op == OP_MAIN_SET_FLAG)) == 0) 1835 { 1836 menu->redraw = REDRAW_STATUS; 1837 if (tag) 1838 menu->redraw |= REDRAW_INDEX; 1839 else if (option (OPTRESOLVE)) 1840 { 1841 if ((menu->current = ci_next_undeleted (menu->current)) == -1) 1842 { 1843 menu->current = menu->oldcurrent; 1844 menu->redraw |= REDRAW_CURRENT; 1845 } 1846 else 1847 menu->redraw |= REDRAW_MOTION_RESYNCH; 1848 } 1849 else 1850 menu->redraw |= REDRAW_CURRENT; 1851 } 1852 break; 1853 1854 case OP_MAIN_COLLAPSE_THREAD: 1855 CHECK_MSGCOUNT; 1856 CHECK_VISIBLE; 1857 1858 if ((Sort & SORT_MASK) != SORT_THREADS) 1859 { 1860 mutt_error _("Threading is not enabled."); 1861 break; 1862 } 1863 1864 if (CURHDR->collapsed) 1865 { 1866 menu->current = mutt_uncollapse_thread (Context, CURHDR); 1867 mutt_set_virtual (Context); 1868 if (option (OPTUNCOLLAPSEJUMP)) 1869 menu->current = mutt_thread_next_unread (Context, CURHDR); 1870 } 1871 else if (option (OPTCOLLAPSEUNREAD) || !UNREAD (CURHDR)) 1872 { 1873 menu->current = mutt_collapse_thread (Context, CURHDR); 1874 mutt_set_virtual (Context); 1875 } 1876 else 1877 { 1878 mutt_error _("Thread contains unread messages."); 1879 break; 1880 } 1881 1882 menu->redraw = REDRAW_INDEX | REDRAW_STATUS; 1883 1884 break; 1885 1886 case OP_MAIN_COLLAPSE_ALL: 1887 CHECK_MSGCOUNT; 1888 CHECK_VISIBLE; 1889 1890 if ((Sort & SORT_MASK) != SORT_THREADS) 1891 { 1892 mutt_error _("Threading is not enabled."); 1893 break; 1894 } 1895 1896 { 1897 HEADER *h, *base; 1898 THREAD *thread, *top; 1899 int final; 1900 1901 if (CURHDR->collapsed) 1902 final = mutt_uncollapse_thread (Context, CURHDR); 1903 else if (option (OPTCOLLAPSEUNREAD) || !UNREAD (CURHDR)) 1904 final = mutt_collapse_thread (Context, CURHDR); 1905 else 1906 final = CURHDR->virtual; 1907 1908 base = Context->hdrs[Context->v2r[final]]; 1909 1910 top = Context->tree; 1911 Context->collapsed = !Context->collapsed; 1912 while ((thread = top) != NULL) 1913 { 1914 while (!thread->message) 1915 thread = thread->child; 1916 h = thread->message; 1917 1918 if (h->collapsed != Context->collapsed) 1919 { 1920 if (h->collapsed) 1921 mutt_uncollapse_thread (Context, h); 1922 else if (option (OPTCOLLAPSEUNREAD) || !UNREAD (h)) 1923 mutt_collapse_thread (Context, h); 1924 } 1925 top = top->next; 1926 } 1927 1928 mutt_set_virtual (Context); 1929 for (j = 0; j < Context->vcount; j++) 1930 { 1931 if (Context->hdrs[Context->v2r[j]]->index == base->index) 1932 { 1933 menu->current = j; 1934 break; 1935 } 1936 } 1937 1938 menu->redraw = REDRAW_INDEX | REDRAW_STATUS; 1939 } 1940 break; 1941 1942 /* -------------------------------------------------------------------- 1943 * These functions are invoked directly from the internal-pager 1944 */ 1945 1946 case OP_BOUNCE_MESSAGE: 1947 1948 CHECK_ATTACH; 1949 CHECK_MSGCOUNT; 1950 CHECK_VISIBLE; 1951 ci_bounce_message (tag ? NULL : CURHDR, &menu->redraw); 1952 break; 1953 1954 case OP_CREATE_ALIAS: 1955 1956 mutt_create_alias (Context && Context->vcount ? CURHDR->env : NULL, NULL); 1957 MAYBE_REDRAW (menu->redraw); 1958 menu->redraw |= REDRAW_CURRENT; 1959 break; 1960 1961 case OP_QUERY: 1962 CHECK_ATTACH; 1963 mutt_query_menu (NULL, 0); 1964 MAYBE_REDRAW (menu->redraw); 1965 break; 1966 1967 case OP_PURGE_MESSAGE: 1968 case OP_DELETE: 1969 1970 CHECK_MSGCOUNT; 1971 CHECK_VISIBLE; 1972 CHECK_READONLY; 1973 /* L10N: CHECK_ACL */ 1974 CHECK_ACL(MUTT_ACL_DELETE, _("Cannot delete message")); 1975 1976 if (tag) 1977 { 1978 mutt_tag_set_flag (MUTT_DELETE, 1); 1979 mutt_tag_set_flag (MUTT_PURGE, (op == OP_PURGE_MESSAGE)); 1980 if (option (OPTDELETEUNTAG)) 1981 mutt_tag_set_flag (MUTT_TAG, 0); 1982 menu->redraw = REDRAW_INDEX; 1983 } 1984 else 1985 { 1986 mutt_set_flag (Context, CURHDR, MUTT_DELETE, 1); 1987 mutt_set_flag (Context, CURHDR, MUTT_PURGE, (op == OP_PURGE_MESSAGE)); 1988 if (option (OPTDELETEUNTAG)) 1989 mutt_set_flag (Context, CURHDR, MUTT_TAG, 0); 1990 if (option (OPTRESOLVE)) 1991 { 1992 if ((menu->current = ci_next_undeleted (menu->current)) == -1) 1993 { 1994 menu->current = menu->oldcurrent; 1995 menu->redraw = REDRAW_CURRENT; 1996 } 1997 else if (menu->menu == MENU_PAGER) 1998 { 1999 op = OP_DISPLAY_MESSAGE; 2000 continue; 2001 } 2002 else 2003 menu->redraw |= REDRAW_MOTION_RESYNCH; 2004 } 2005 else 2006 menu->redraw = REDRAW_CURRENT; 2007 } 2008 menu->redraw |= REDRAW_STATUS; 2009 break; 2010 2011 case OP_DELETE_THREAD: 2012 case OP_DELETE_SUBTHREAD: 2013 2014 CHECK_MSGCOUNT; 2015 CHECK_VISIBLE; 2016 CHECK_READONLY; 2017 /* L10N: CHECK_ACL */ 2018 CHECK_ACL(MUTT_ACL_DELETE, _("Cannot delete message(s)")); 2019 2020 rc = mutt_thread_set_flag (CURHDR, MUTT_DELETE, 1, 2021 op == OP_DELETE_THREAD ? 0 : 1); 2022 2023 if (rc != -1) 2024 { 2025 if (option (OPTDELETEUNTAG)) 2026 mutt_thread_set_flag (CURHDR, MUTT_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; 2032 } 2033 break; 2034 2035 case OP_DISPLAY_ADDRESS: 2036 2037 CHECK_MSGCOUNT; 2038 CHECK_VISIBLE; 2039 mutt_display_address (CURHDR->env); 2040 break; 2041 2042 case OP_ENTER_COMMAND: 2043 2044 CurrentMenu = MENU_MAIN; 2045 mutt_enter_command (); 2046 mutt_check_rescore (Context); 2047 if (option (OPTFORCEREDRAWINDEX)) 2048 menu->redraw = REDRAW_FULL; 2049 unset_option (OPTFORCEREDRAWINDEX); 2050 unset_option (OPTFORCEREDRAWPAGER); 2051 break; 2052 2053 case OP_EDIT_MESSAGE: 2054 2055 CHECK_MSGCOUNT; 2056 CHECK_VISIBLE; 2057 CHECK_READONLY; 2058 CHECK_ATTACH; 2059 /* L10N: CHECK_ACL */ 2060 CHECK_ACL(MUTT_ACL_INSERT, _("Cannot edit message")); 2061 2062 if (option (OPTPGPAUTODEC) && (tag || !(CURHDR->security & PGP_TRADITIONAL_CHECKED))) 2063 mutt_check_traditional_pgp (tag ? NULL : CURHDR, &menu->redraw); 2064 mutt_edit_message (Context, tag ? NULL : CURHDR); 2065 menu->redraw = REDRAW_FULL; 2066 2067 break; 2068 2069 case OP_FORWARD_MESSAGE: 2070 2071 CHECK_MSGCOUNT; 2072 CHECK_VISIBLE; 2073 CHECK_ATTACH; 2074 if (option (OPTPGPAUTODEC) && (tag || !(CURHDR->security & PGP_TRADITIONAL_CHECKED))) 2075 mutt_check_traditional_pgp (tag ? NULL : CURHDR, &menu->redraw); 2076 ci_send_message (SENDFORWARD, NULL, NULL, Context, tag ? NULL : CURHDR); 2077 menu->redraw = REDRAW_FULL; 2078 break; 2079 2080 2081 case OP_FORGET_PASSPHRASE: 2082 crypt_forget_passphrase (); 2083 break; 2084 2085 case OP_GROUP_REPLY: 2086 2087 CHECK_MSGCOUNT; 2088 CHECK_VISIBLE; 2089 CHECK_ATTACH; 2090 if (option (OPTPGPAUTODEC) && (tag || !(CURHDR->security & PGP_TRADITIONAL_CHECKED))) 2091 mutt_check_traditional_pgp (tag ? NULL : CURHDR, &menu->redraw); 2092 ci_send_message (SENDREPLY|SENDGROUPREPLY, NULL, NULL, Context, tag ? NULL : CURHDR); 2093 menu->redraw = REDRAW_FULL; 2094 break; 2095 2096 case OP_LIST_REPLY: 2097 2098 CHECK_ATTACH; 2099 CHECK_MSGCOUNT; 2100 CHECK_VISIBLE; 2101 if (option (OPTPGPAUTODEC) && (tag || !(CURHDR->security & PGP_TRADITIONAL_CHECKED))) 2102 mutt_check_traditional_pgp (tag ? NULL : CURHDR, &menu->redraw); 2103 ci_send_message (SENDREPLY|SENDLISTREPLY, NULL, NULL, Context, tag ? NULL : CURHDR); 2104 menu->redraw = REDRAW_FULL; 2105 break; 2106 2107 case OP_MAIL: 2108 2109 CHECK_ATTACH; 2110 ci_send_message (0, NULL, NULL, Context, NULL); 2111 menu->redraw = REDRAW_FULL; 2112 break; 2113 2114 case OP_MAIL_KEY: 2115 if (!(WithCrypto & APPLICATION_PGP)) 2116 break; 2117 CHECK_ATTACH; 2118 ci_send_message (SENDKEY, NULL, NULL, NULL, NULL); 2119 menu->redraw = REDRAW_FULL; 2120 break; 2121 2122 2123 case OP_EXTRACT_KEYS: 2124 if (!WithCrypto) 2125 break; 2126 CHECK_MSGCOUNT; 2127 CHECK_VISIBLE; 2128 crypt_extract_keys_from_messages(tag ? NULL : CURHDR); 2129 menu->redraw = REDRAW_FULL; 2130 break; 2131 2132 2133 case OP_CHECK_TRADITIONAL: 2134 if (!(WithCrypto & APPLICATION_PGP)) 2135 break; 2136 CHECK_MSGCOUNT; 2137 CHECK_VISIBLE; 2138 if (tag || !(CURHDR->security & PGP_TRADITIONAL_CHECKED)) 2139 mutt_check_traditional_pgp (tag ? NULL : CURHDR, &menu->redraw); 2140 2141 if (menu->menu == MENU_PAGER) 2142 { 2143 op = OP_DISPLAY_MESSAGE; 2144 continue; 2145 } 2146 break; 2147 2148 case OP_PIPE: 2149 2150 CHECK_MSGCOUNT; 2151 CHECK_VISIBLE; 2152 mutt_pipe_message (tag ? NULL : CURHDR); 2153 2154#ifdef USE_IMAP 2155 /* in an IMAP folder index with imap_peek=no, piping could change 2156 * new or old messages status to read. Redraw what's needed. 2157 */ 2158 if (Context->magic == MUTT_IMAP && !option (OPTIMAPPEEK)) 2159 { 2160 menu->redraw = (tag ? REDRAW_INDEX : REDRAW_CURRENT) | REDRAW_STATUS; 2161 } 2162#endif 2163 2164 MAYBE_REDRAW (menu->redraw); 2165 break; 2166 2167 case OP_PRINT: 2168 2169 CHECK_MSGCOUNT; 2170 CHECK_VISIBLE; 2171 mutt_print_message (tag ? NULL : CURHDR); 2172 2173#ifdef USE_IMAP 2174 /* in an IMAP folder index with imap_peek=no, printing could change 2175 * new or old messages status to read. Redraw what's needed. 2176 */ 2177 if (Context->magic == MUTT_IMAP && !option (OPTIMAPPEEK)) 2178 { 2179 menu->redraw = (tag ? REDRAW_INDEX : REDRAW_CURRENT) | REDRAW_STATUS; 2180 } 2181#endif 2182 2183 break; 2184 2185 case OP_MAIN_READ_THREAD: 2186 case OP_MAIN_READ_SUBTHREAD: 2187 2188 CHECK_MSGCOUNT; 2189 CHECK_VISIBLE; 2190 CHECK_READONLY; 2191 /* L10N: CHECK_ACL */ 2192 CHECK_ACL(MUTT_ACL_SEEN, _("Cannot mark message(s) as read")); 2193 2194 rc = mutt_thread_set_flag (CURHDR, MUTT_READ, 1, 2195 op == OP_MAIN_READ_THREAD ? 0 : 1); 2196 2197 if (rc != -1) 2198 { 2199 if (option (OPTRESOLVE)) 2200 { 2201 if ((menu->current = (op == OP_MAIN_READ_THREAD ? 2202 mutt_next_thread (CURHDR) : mutt_next_subthread (CURHDR))) == -1) 2203 menu->current = menu->oldcurrent; 2204 else if (menu->menu == MENU_PAGER) 2205 { 2206 op = OP_DISPLAY_MESSAGE; 2207 continue; 2208 } 2209 } 2210 menu->redraw = REDRAW_INDEX | REDRAW_STATUS; 2211 } 2212 break; 2213 2214 2215 case OP_MARK_MSG: 2216 2217 CHECK_MSGCOUNT; 2218 CHECK_VISIBLE; 2219 if (CURHDR->env->message_id) 2220 { 2221 char str[STRING], macro[STRING]; 2222 char buf[128]; 2223 2224 buf[0] = '\0'; 2225 /* L10N: This is the prompt for <mark-message>. Whatever they 2226 enter will be prefixed by $mark_macro_prefix and will become 2227 a macro hotkey to jump to the currently selected message. */ 2228 if (!mutt_get_field (_("Enter macro stroke: "), buf, sizeof(buf), 2229 MUTT_CLEAR) && buf[0]) 2230 { 2231 snprintf(str, sizeof(str), "%s%s", MarkMacroPrefix, buf); 2232 snprintf(macro, sizeof(macro), 2233 "<search>~i \"%s\"\n", CURHDR->env->message_id); 2234 /* L10N: "message hotkey" is the key bindings menu description of a 2235 macro created by <mark-message>. */ 2236 km_bind(str, MENU_MAIN, OP_MACRO, macro, _("message hotkey")); 2237 2238 /* L10N: This is echoed after <mark-message> creates a new hotkey 2239 macro. %s is the hotkey string ($mark_macro_prefix followed 2240 by whatever they typed at the prompt.) */ 2241 snprintf(buf, sizeof(buf), _("Message bound to %s."), str); 2242 mutt_message(buf); 2243 dprint (1, (debugfile, "Mark: %s => %s\n", str, macro)); 2244 } 2245 } 2246 else 2247 /* L10N: This error is printed if <mark-message> cannot find a 2248 Message-ID for the currently selected message in the index. */ 2249 mutt_error _("No message ID to macro."); 2250 break; 2251 2252 case OP_RECALL_MESSAGE: 2253 2254 CHECK_ATTACH; 2255 ci_send_message (SENDPOSTPONED, NULL, NULL, Context, NULL); 2256 menu->redraw = REDRAW_FULL; 2257 break; 2258 2259 case OP_RESEND: 2260 2261 CHECK_ATTACH; 2262 CHECK_MSGCOUNT; 2263 CHECK_VISIBLE; 2264 2265 if (tag) 2266 { 2267 for (j = 0; j < Context->vcount; j++) 2268 { 2269 if (Context->hdrs[Context->v2r[j]]->tagged) 2270 mutt_resend_message (NULL, Context, Context->hdrs[Context->v2r[j]]); 2271 } 2272 } 2273 else 2274 mutt_resend_message (NULL, Context, CURHDR); 2275 2276 menu->redraw = REDRAW_FULL; 2277 break; 2278 2279 case OP_REPLY: 2280 2281 CHECK_ATTACH; 2282 CHECK_MSGCOUNT; 2283 CHECK_VISIBLE; 2284 if (option (OPTPGPAUTODEC) && (tag || !(CURHDR->security & PGP_TRADITIONAL_CHECKED))) 2285 mutt_check_traditional_pgp (tag ? NULL : CURHDR, &menu->redraw); 2286 ci_send_message (SENDREPLY, NULL, NULL, Context, tag ? NULL : CURHDR); 2287 menu->redraw = REDRAW_FULL; 2288 break; 2289 2290 case OP_SHELL_ESCAPE: 2291 2292 mutt_shell_escape (); 2293 MAYBE_REDRAW (menu->redraw); 2294 break; 2295 2296 case OP_TAG_THREAD: 2297 case OP_TAG_SUBTHREAD: 2298 2299 CHECK_MSGCOUNT; 2300 CHECK_VISIBLE; 2301 rc = mutt_thread_set_flag (CURHDR, MUTT_TAG, !CURHDR->tagged, 2302 op == OP_TAG_THREAD ? 0 : 1); 2303 2304 if (rc != -1) 2305 { 2306 if (option (OPTRESOLVE)) 2307 { 2308 if (op == OP_TAG_THREAD) 2309 menu->current = mutt_next_thread (CURHDR); 2310 else 2311 menu->current = mutt_next_subthread (CURHDR); 2312 2313 if (menu->current == -1) 2314 menu->current = menu->oldcurrent; 2315 } 2316 menu->redraw = REDRAW_INDEX | REDRAW_STATUS; 2317 } 2318 break; 2319 2320 case OP_UNDELETE: 2321 2322 CHECK_MSGCOUNT; 2323 CHECK_VISIBLE; 2324 CHECK_READONLY; 2325 /* L10N: CHECK_ACL */ 2326 CHECK_ACL(MUTT_ACL_DELETE, _("Cannot undelete message")); 2327 2328 if (tag) 2329 { 2330 mutt_tag_set_flag (MUTT_DELETE, 0); 2331 mutt_tag_set_flag (MUTT_PURGE, 0); 2332 menu->redraw = REDRAW_INDEX; 2333 } 2334 else 2335 { 2336 mutt_set_flag (Context, CURHDR, MUTT_DELETE, 0); 2337 mutt_set_flag (Context, CURHDR, MUTT_PURGE, 0); 2338 if (option (OPTRESOLVE) && menu->current < Context->vcount - 1) 2339 { 2340 menu->current++; 2341 menu->redraw = REDRAW_MOTION_RESYNCH; 2342 } 2343 else 2344 menu->redraw = REDRAW_CURRENT; 2345 } 2346 menu->redraw |= REDRAW_STATUS; 2347 break; 2348 2349 case OP_UNDELETE_THREAD: 2350 case OP_UNDELETE_SUBTHREAD: 2351 2352 CHECK_MSGCOUNT; 2353 CHECK_VISIBLE; 2354 CHECK_READONLY; 2355 /* L10N: CHECK_ACL */ 2356 CHECK_ACL(MUTT_ACL_DELETE, _("Cannot undelete message(s)")); 2357 2358 rc = mutt_thread_set_flag (CURHDR, MUTT_DELETE, 0, 2359 op == OP_UNDELETE_THREAD ? 0 : 1); 2360 if (rc != -1) 2361 rc = mutt_thread_set_flag (CURHDR, MUTT_PURGE, 0, 2362 op == OP_UNDELETE_THREAD ? 0 : 1); 2363 if (rc != -1) 2364 { 2365 if (option (OPTRESOLVE)) 2366 { 2367 if (op == OP_UNDELETE_THREAD) 2368 menu->current = mutt_next_thread (CURHDR); 2369 else 2370 menu->current = mutt_next_subthread (CURHDR); 2371 2372 if (menu->current == -1) 2373 menu->current = menu->oldcurrent; 2374 } 2375 menu->redraw = REDRAW_INDEX | REDRAW_STATUS; 2376 } 2377 break; 2378 2379 case OP_VERSION: 2380 mutt_version (); 2381 break; 2382 2383 case OP_BUFFY_LIST: 2384 mutt_buffy_list (); 2385 break; 2386 2387 case OP_VIEW_ATTACHMENTS: 2388 CHECK_MSGCOUNT; 2389 CHECK_VISIBLE; 2390 mutt_view_attachments (CURHDR); 2391 if (CURHDR->attach_del) 2392 Context->changed = 1; 2393 menu->redraw = REDRAW_FULL; 2394 break; 2395 2396 case OP_END_COND: 2397 break; 2398 2399 case OP_WHAT_KEY: 2400 mutt_what_key(); 2401 break; 2402 2403#ifdef USE_SIDEBAR 2404 case OP_SIDEBAR_NEXT: 2405 case OP_SIDEBAR_NEXT_NEW: 2406 case OP_SIDEBAR_PAGE_DOWN: 2407 case OP_SIDEBAR_PAGE_UP: 2408 case OP_SIDEBAR_PREV: 2409 case OP_SIDEBAR_PREV_NEW: 2410 mutt_sb_change_mailbox (op); 2411 break; 2412 2413 case OP_SIDEBAR_TOGGLE_VISIBLE: 2414 toggle_option (OPTSIDEBAR); 2415 mutt_reflow_windows(); 2416 menu->redraw = REDRAW_FULL; 2417 break; 2418#endif 2419 default: 2420 if (menu->menu == MENU_MAIN) 2421 km_error_key (MENU_MAIN); 2422 } 2423 2424 if (menu->menu == MENU_PAGER) 2425 { 2426 mutt_clear_pager_position (); 2427 menu->menu = MENU_MAIN; 2428 menu->redraw = REDRAW_FULL; 2429#if 0 2430 set_option (OPTWEED); /* turn header weeding back on. */ 2431#endif 2432 } 2433 2434 if (done) break; 2435 } 2436 2437 mutt_menuDestroy (&menu); 2438 return (close); 2439} 2440 2441void mutt_set_header_color (CONTEXT *ctx, HEADER *curhdr) 2442{ 2443 COLOR_LINE *color; 2444 pattern_cache_t cache; 2445 2446 if (!curhdr) 2447 return; 2448 2449 memset (&cache, 0, sizeof (cache)); 2450 2451 for (color = ColorIndexList; color; color = color->next) 2452 if (mutt_pattern_exec (color->color_pattern, MUTT_MATCH_FULL_ADDRESS, ctx, curhdr, 2453 &cache)) 2454 { 2455 curhdr->pair = color->pair; 2456 return; 2457 } 2458 curhdr->pair = ColorDefs[MT_COLOR_NORMAL]; 2459}