Example #1
0
/**
 * 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;
}
Example #2
0
/**
 * 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);
}
Example #3
0
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 */
}
Example #4
0
/**
 * 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;
}
Example #5
0
/**
 * 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;
}