/** * mutt_get_field_full - Ask the user for a string * @param[in] field Prompt * @param[in] buf Buffer for the result * @param[in] buflen Length of buffer * @param[in] complete Flags, see #CompletionFlags * @param[in] multiple Allow multiple selections * @param[out] files List of files selected * @param[out] numfiles Number of files selected * @retval 1 Redraw the screen and call the function again * @retval 0 Selection made * @retval -1 Aborted */ int mutt_get_field_full(const char *field, char *buf, size_t buflen, CompletionFlags complete, bool multiple, char ***files, int *numfiles) { int ret; int x; struct EnterState *es = mutt_enter_state_new(); do { if (SigWinch) { SigWinch = 0; mutt_resize_screen(); clearok(stdscr, TRUE); mutt_menu_current_redraw(); } mutt_window_clearline(MuttMessageWindow, 0); SETCOLOR(MT_COLOR_PROMPT); addstr(field); NORMAL_COLOR; mutt_refresh(); mutt_window_getxy(MuttMessageWindow, &x, NULL); ret = mutt_enter_string_full(buf, buflen, x, complete, multiple, files, numfiles, es); } while (ret == 1); mutt_window_clearline(MuttMessageWindow, 0); mutt_enter_state_free(&es); return ret; }
/** * mutt_edit_file - Let the user edit a file * @param editor User's editor config * @param file File to edit */ void mutt_edit_file(const char *editor, const char *file) { char cmd[STR_COMMAND]; mutt_endwin(); mutt_file_expand_fmt_quote(cmd, sizeof(cmd), editor, file); if (mutt_system(cmd) != 0) { mutt_error(_("Error running \"%s\""), cmd); } /* the terminal may have been resized while the editor owned it */ mutt_resize_screen(); keypad(stdscr, true); clearok(stdscr, true); }
int mutt_menuLoop (MUTTMENU * menu) { int i = OP_NULL; FOREVER { if (option (OPTMENUCALLER)) { unset_option (OPTMENUCALLER); return OP_NULL; } mutt_curs_set (0); #ifdef USE_IMAP imap_keepalive (); #endif if (menu_redraw (menu) == OP_REDRAW) return OP_REDRAW; menu->oldcurrent = menu->current; if (option (OPTARROWCURSOR)) move (menu->current - menu->top + menu->offset, SW + 2); else if (option (OPTBRAILLEFRIENDLY)) move (menu->current - menu->top + menu->offset, SW); else move (menu->current - menu->top + menu->offset, COLS - 1); mutt_refresh (); /* try to catch dialog keys before ops */ if (menu->dialog && menu_dialog_dokey (menu, &i) == 0) return i; i = km_dokey (menu->menu); if (i == OP_TAG_PREFIX || i == OP_TAG_PREFIX_COND) { if (menu->tagged) { mvaddstr (LINES - 1, 0, "Tag-"); clrtoeol (); i = km_dokey (menu->menu); menu->tagprefix = 1; CLEARLINE (LINES - 1); } else if (i == OP_TAG_PREFIX) { mutt_error _("No tagged entries."); i = -1; } else { /* None tagged, OP_TAG_PREFIX_COND */ event_t tmp; while (UngetCount > 0) { tmp = mutt_getch (); if (tmp.op == OP_END_COND) break; } mutt_message _("Nothing to do."); i = -1; } } else if (menu->tagged && option (OPTAUTOTAG)) menu->tagprefix = 1; else menu->tagprefix = 0; mutt_curs_set (1); #if defined (USE_SLANG_CURSES) || defined (HAVE_RESIZETERM) if (SigWinch) { mutt_resize_screen (); menu->redraw = REDRAW_FULL; SigWinch = 0; clearok (stdscr, TRUE); /*force complete redraw */ } #endif if (i == -1) continue; if (!menu->dialog) mutt_clear_error (); /* Convert menubar movement to scrolling */ if (menu->dialog) i = menu_dialog_translate_op (i); switch (i) { case OP_NEXT_ENTRY: menu_next_entry (menu); break; case OP_PREV_ENTRY: menu_prev_entry (menu); break; case OP_HALF_DOWN: menu_half_down (menu); break; case OP_HALF_UP: menu_half_up (menu); break; case OP_NEXT_PAGE: menu_next_page (menu); break; case OP_PREV_PAGE: menu_prev_page (menu); break; case OP_NEXT_LINE: menu_next_line (menu); break; case OP_PREV_LINE: menu_prev_line (menu); break; case OP_FIRST_ENTRY: menu_first_entry (menu); break; case OP_LAST_ENTRY: menu_last_entry (menu); break; case OP_TOP_PAGE: menu_top_page (menu); break; case OP_MIDDLE_PAGE: menu_middle_page (menu); break; case OP_BOTTOM_PAGE: menu_bottom_page (menu); break; case OP_CURRENT_TOP: menu_current_top (menu); break; case OP_CURRENT_MIDDLE: menu_current_middle (menu); break; case OP_CURRENT_BOTTOM: menu_current_bottom (menu); break; case OP_SEARCH: case OP_SEARCH_REVERSE: case OP_SEARCH_NEXT: case OP_SEARCH_OPPOSITE: if (menu->search && !menu->dialog) { /* Searching dialogs won't work */ menu->oldcurrent = menu->current; if ((menu->current = menu_search (menu, i)) != -1) menu->redraw = REDRAW_MOTION; else menu->current = menu->oldcurrent; } else mutt_error _("Search is not implemented for this menu."); break; case OP_JUMP: if (menu->dialog) mutt_error (_("Jumping is not implemented for dialogs.")); else menu_jump (menu); break; case OP_ENTER_COMMAND: CurrentMenu = menu->menu; mutt_enter_command (); if (option (OPTFORCEREDRAWINDEX)) { menu->redraw = REDRAW_FULL; unset_option (OPTFORCEREDRAWINDEX); unset_option (OPTFORCEREDRAWPAGER); } break; case OP_TAG: if (menu->tag && !menu->dialog) { if (menu->tagprefix && !option (OPTAUTOTAG)) { for (i = 0; i < menu->max; i++) menu->tagged += menu->tag (menu, i, 0); menu->redraw = REDRAW_INDEX; } else if (menu->max) { int i = menu->tag (menu, menu->current, -1); menu->tagged += i; if (i && option (OPTRESOLVE) && menu->current < menu->max - 1) { menu->current++; menu->redraw = REDRAW_MOTION_RESYNCH; } else menu->redraw = REDRAW_CURRENT; } else mutt_error _("No entries."); } else mutt_error _("Tagging is not supported."); break; case OP_SHELL_ESCAPE: mutt_shell_escape (); MAYBE_REDRAW (menu->redraw); break; case OP_WHAT_KEY: mutt_what_key (); break; case OP_REBUILD_CACHE: mx_rebuild_cache (); break; case OP_REDRAW: clearok (stdscr, TRUE); menu->redraw = REDRAW_FULL; break; case OP_HELP: mutt_help (menu->menu); menu->redraw = REDRAW_FULL; break; case OP_NULL: km_error_key (menu->menu); break; case OP_END_COND: break; default: return (i); } } /* not reached */ }
/** * mutt_multi_choice - Offer the user a multiple choice question * @param prompt Message prompt * @param letters Allowable selection keys * @retval >=0 0-based user selection * @retval -1 Selection aborted */ int mutt_multi_choice(const char *prompt, const char *letters) { struct Event ch; int choice; bool redraw = true; int prompt_lines = 1; char *p = NULL; while (true) { if (redraw || SigWinch) { redraw = false; if (SigWinch) { SigWinch = 0; mutt_resize_screen(); clearok(stdscr, TRUE); mutt_menu_current_redraw(); } if (MuttMessageWindow->cols) { prompt_lines = (mutt_strwidth(prompt) + MuttMessageWindow->cols - 1) / MuttMessageWindow->cols; prompt_lines = MAX(1, MIN(3, prompt_lines)); } if (prompt_lines != MuttMessageWindow->rows) { mutt_window_reflow_message_rows(prompt_lines); mutt_menu_current_redraw(); } SETCOLOR(MT_COLOR_PROMPT); mutt_window_mvaddstr(MuttMessageWindow, 0, 0, prompt); NORMAL_COLOR; mutt_window_clrtoeol(MuttMessageWindow); } mutt_refresh(); /* SigWinch is not processed unless timeout is set */ mutt_getch_timeout(30 * 1000); ch = mutt_getch(); mutt_getch_timeout(-1); if (ch.ch == -2) continue; /* (ch.ch == 0) is technically possible. Treat the same as < 0 (abort) */ if ((ch.ch <= 0) || CI_is_return(ch.ch)) { choice = -1; break; } else { p = strchr(letters, ch.ch); if (p) { choice = p - letters + 1; break; } else if ((ch.ch <= '9') && (ch.ch > '0')) { choice = ch.ch - '0'; if (choice <= mutt_str_strlen(letters)) break; } } BEEP(); } if (MuttMessageWindow->rows != 1) { mutt_window_reflow_message_rows(1); mutt_menu_current_redraw(); } else mutt_window_clearline(MuttMessageWindow, 0); mutt_refresh(); return choice; }
/** * mutt_yesorno - Ask the user a Yes/No question * @param msg Prompt * @param def Default answer, see #QuadOption * @retval num Selection made, see #QuadOption */ enum QuadOption mutt_yesorno(const char *msg, enum QuadOption def) { struct Event ch; char *yes = _("yes"); char *no = _("no"); char *answer_string = NULL; int answer_string_wid, msg_wid; size_t trunc_msg_len; bool redraw = true; int prompt_lines = 1; char *expr = NULL; regex_t reyes; regex_t reno; char answer[2]; answer[1] = '\0'; bool reyes_ok = (expr = nl_langinfo(YESEXPR)) && (expr[0] == '^') && (REGCOMP(&reyes, expr, REG_NOSUB) == 0); bool reno_ok = (expr = nl_langinfo(NOEXPR)) && (expr[0] == '^') && (REGCOMP(&reno, expr, REG_NOSUB) == 0); /* In order to prevent the default answer to the question to wrapped * around the screen in the even the question is wider than the screen, * ensure there is enough room for the answer and truncate the question * to fit. */ safe_asprintf(&answer_string, " ([%s]/%s): ", (def == MUTT_YES) ? yes : no, (def == MUTT_YES) ? no : yes); answer_string_wid = mutt_strwidth(answer_string); msg_wid = mutt_strwidth(msg); while (true) { if (redraw || SigWinch) { redraw = false; if (SigWinch) { SigWinch = 0; mutt_resize_screen(); clearok(stdscr, TRUE); mutt_menu_current_redraw(); } if (MuttMessageWindow->cols) { prompt_lines = (msg_wid + answer_string_wid + MuttMessageWindow->cols - 1) / MuttMessageWindow->cols; prompt_lines = MAX(1, MIN(3, prompt_lines)); } if (prompt_lines != MuttMessageWindow->rows) { mutt_window_reflow_message_rows(prompt_lines); mutt_menu_current_redraw(); } /* maxlen here is sort of arbitrary, so pick a reasonable upper bound */ trunc_msg_len = mutt_wstr_trunc( msg, 4 * prompt_lines * MuttMessageWindow->cols, prompt_lines * MuttMessageWindow->cols - answer_string_wid, NULL); mutt_window_move(MuttMessageWindow, 0, 0); SETCOLOR(MT_COLOR_PROMPT); addnstr(msg, trunc_msg_len); addstr(answer_string); NORMAL_COLOR; mutt_window_clrtoeol(MuttMessageWindow); } mutt_refresh(); /* SigWinch is not processed unless timeout is set */ mutt_getch_timeout(30 * 1000); ch = mutt_getch(); mutt_getch_timeout(-1); if (ch.ch == -2) continue; if (CI_is_return(ch.ch)) break; if (ch.ch < 0) { def = MUTT_ABORT; break; } answer[0] = ch.ch; if (reyes_ok ? (regexec(&reyes, answer, 0, 0, 0) == 0) : (tolower(ch.ch) == 'y')) { def = MUTT_YES; break; } else if (reno_ok ? (regexec(&reno, answer, 0, 0, 0) == 0) : (tolower(ch.ch) == 'n')) { def = MUTT_NO; break; } else { BEEP(); } } FREE(&answer_string); if (reyes_ok) regfree(&reyes); if (reno_ok) regfree(&reno); if (MuttMessageWindow->rows != 1) { mutt_window_reflow_message_rows(1); mutt_menu_current_redraw(); } else mutt_window_clearline(MuttMessageWindow, 0); if (def != MUTT_ABORT) { addstr((char *) ((def == MUTT_YES) ? yes : no)); mutt_refresh(); } else { /* when the users cancels with ^G, clear the message stored with * mutt_message() so it isn't displayed when the screen is refreshed. */ mutt_clear_error(); } return def; }