int mutt_yesorno (const char *msg, int def)
{
  event_t ch;
  unsigned char *yes = (unsigned char *) _("yes");
  unsigned char *no = (unsigned char *) _("no");
  
  CLEARLINE(LINES-1);
  printw("%s ([%c]/%c): ", msg, def ? *yes : *no,
	 def ? *no : *yes);
  FOREVER
  {
    mutt_refresh ();
    ch = mutt_getch ();
    if (ch.ch == -1) return(-1);
    if (CI_is_return (ch.ch))
      break;
    else if (tolower(ch.ch) == tolower(*yes))
    {
      def = 1;
      break;
    }
    else if (tolower(ch.ch) == tolower(*no))
    {
      def = 0;
      break;
    }
    else
    {
      BEEP();
    }
  }
  addstr ((char *) (def ? yes : no));
  mutt_refresh ();
  return (def);
}
Beispiel #2
0
/**
 * mutt_enter_fname_full - Ask the user to select a file
 * @param[in]  prompt   Prompt
 * @param[in]  buf      Buffer for the result
 * @param[in]  buflen   Length of the buffer
 * @param[in]  mailbox  If true, select mailboxes
 * @param[in]  multiple Allow multiple selections
 * @param[out] files    List of files selected
 * @param[out] numfiles Number of files selected
 * @param[in]  flags    Flags, see #SelectFileFlags
 * @retval  0 Success
 * @retval -1 Error
 */
int mutt_enter_fname_full(const char *prompt, char *buf, size_t buflen, bool mailbox,
                          bool multiple, char ***files, int *numfiles, SelectFileFlags flags)
{
  struct Event ch;

  SETCOLOR(MT_COLOR_PROMPT);
  mutt_window_mvaddstr(MuttMessageWindow, 0, 0, (char *) prompt);
  addstr(_(" ('?' for list): "));
  NORMAL_COLOR;
  if (buf[0] != '\0')
    addstr(buf);
  mutt_window_clrtoeol(MuttMessageWindow);
  mutt_refresh();

  do
  {
    ch = mutt_getch();
  } while (ch.ch == -2);
  if (ch.ch < 0)
  {
    mutt_window_clearline(MuttMessageWindow, 0);
    return -1;
  }
  else if (ch.ch == '?')
  {
    mutt_refresh();
    buf[0] = '\0';

    if (!flags)
      flags = MUTT_SEL_FOLDER;
    if (multiple)
      flags |= MUTT_SEL_MULTI;
    if (mailbox)
      flags |= MUTT_SEL_MAILBOX;
    mutt_select_file(buf, buflen, flags, files, numfiles);
  }
  else
  {
    char *pc = mutt_mem_malloc(mutt_str_strlen(prompt) + 3);

    sprintf(pc, "%s: ", prompt);
    mutt_unget_event(ch.op ? 0 : ch.ch, ch.op ? ch.op : 0);
    if (mutt_get_field_full(pc, buf, buflen, (mailbox ? MUTT_EFILE : MUTT_FILE) | MUTT_CLEAR,
                            multiple, files, numfiles) != 0)
    {
      buf[0] = '\0';
    }
    FREE(&pc);
  }

  return 0;
}
Beispiel #3
0
static int edit_address (ADDRESS **a, /* const */ char *field)
{
  char buf[HUGE_STRING];
  char *err = NULL;
  int idna_ok = 0;
  
  do
  {
    buf[0] = 0;
    mutt_addrlist_to_local (*a);
    rfc822_write_address (buf, sizeof (buf), *a, 0);
    if (mutt_get_field (field, buf, sizeof (buf), M_ALIAS) != 0)
      return (-1);
    rfc822_free_address (a);
    *a = mutt_expand_aliases (mutt_parse_adrlist (NULL, buf));
    if ((idna_ok = mutt_addrlist_to_idna (*a, &err)) != 0)
    {
      mutt_error (_("Error: '%s' is a bad IDN."), err);
      mutt_refresh ();
      mutt_sleep (2);
      FREE (&err);
    }
  } 
  while (idna_ok != 0);
  return 0;
}
Beispiel #4
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;
}
Beispiel #5
0
static int edit_address_list (int line, ADDRESS **addr)
{
  char buf[HUGE_STRING] = ""; /* needs to be large for alias expansion */
  char *err = NULL;
  
  mutt_addrlist_to_local (*addr);
  rfc822_write_address (buf, sizeof (buf), *addr, 0);
  if (mutt_get_field (Prompts[line - 1], buf, sizeof (buf), M_ALIAS) == 0)
  {
    rfc822_free_address (addr);
    *addr = mutt_parse_adrlist (*addr, buf);
    *addr = mutt_expand_aliases (*addr);
  }

  if (option (OPTNEEDREDRAW))
  {
    unset_option (OPTNEEDREDRAW);
    return (REDRAW_FULL);
  }

  if (mutt_addrlist_to_intl (*addr, &err) != 0)
  {
    mutt_error (_("Warning: '%s' is a bad IDN."), err);
    mutt_refresh();
    FREE (&err);
  }

  /* redraw the expanded list so the user can see the result */
  buf[0] = 0;
  rfc822_write_address (buf, sizeof (buf), *addr, 1);
  move (line, HDR_XOFFSET);
  mutt_paddstr (W, buf);
  
  return 0;
}
Beispiel #6
0
/**
 * message_bar - Draw a colourful progress bar
 * @param percent %age complete
 * @param fmt     printf(1)-like formatting string
 * @param ...     Arguments to formatting string
 */
static void message_bar(int percent, const char *fmt, ...)
{
  va_list ap;
  char buf[256], buf2[256];
  int w = percent * COLS / 100;
  size_t l;

  va_start(ap, fmt);
  vsnprintf(buf, sizeof(buf), fmt, ap);
  l = mutt_strwidth(buf);
  va_end(ap);

  mutt_simple_format(buf2, sizeof(buf2), 0, COLS - 2, FMT_LEFT, 0, buf, sizeof(buf), 0);

  move(LINES - 1, 0);

  if (ColorDefs[MT_COLOR_PROGRESS] == 0)
  {
    addstr(buf2);
  }
  else
  {
    if (l < w)
    {
      /* The string fits within the colour bar */
      SETCOLOR(MT_COLOR_PROGRESS);
      addstr(buf2);
      w -= l;
      while (w-- > 0)
      {
        addch(' ');
      }
      NORMAL_COLOR;
    }
    else
    {
      /* The string is too long for the colour bar */
      char ch;
      int off = mutt_wstr_trunc(buf2, sizeof(buf2), w, NULL);

      ch = buf2[off];
      buf2[off] = '\0';
      SETCOLOR(MT_COLOR_PROGRESS);
      addstr(buf2);
      buf2[off] = ch;
      NORMAL_COLOR;
      addstr(&buf2[off]);
    }
  }

  clrtoeol();
  mutt_refresh();
}
int _mutt_enter_fname (const char *prompt, char *buf, size_t blen, int *redraw, int buffy, int multiple, char ***files, int *numfiles)
{
  event_t ch;

  mvaddstr (LINES-1, 0, (char *) prompt);
  addstr (_(" ('?' for list): "));
  if (buf[0])
    addstr (buf);
  clrtoeol ();
  mutt_refresh ();

  ch = mutt_getch();
  if (ch.ch == -1)
  {
    CLEARLINE (LINES-1);
    return (-1);
  }
  else if (ch.ch == '?')
  {
    mutt_refresh ();
    buf[0] = 0;
    _mutt_select_file (buf, blen, 0, multiple, files, numfiles);
    *redraw = REDRAW_FULL;
  }
  else
  {
    char *pc = safe_malloc (mutt_strlen (prompt) + 3);

    sprintf (pc, "%s: ", prompt);
    mutt_ungetch (ch.op ? 0 : ch.ch, ch.op ? ch.op : 0);
    if (_mutt_get_field (pc, buf, blen, (buffy ? M_EFILE : M_FILE) | M_CLEAR, multiple, files, numfiles)
	!= 0)
      buf[0] = 0;
    MAYBE_REDRAW (*redraw);
    FREE (&pc);
  }

  return 0;
}
int mutt_multi_choice (char *prompt, char *letters)
{
  event_t ch;
  int choice;
  char *p;

  mvaddstr (LINES - 1, 0, prompt);
  clrtoeol ();
  FOREVER
  {
    mutt_refresh ();
    ch  = mutt_getch ();
    if (ch.ch == -1 || 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_strlen (letters))
	  break;
      }
    }
    BEEP ();
  }
  CLEARLINE (LINES - 1);
  mutt_refresh ();
  return choice;
}
Beispiel #9
0
/**
 * mutt_endwin - Shutdown curses/slang
 */
void mutt_endwin(void)
{
  if (OptNoCurses)
    return;

  int e = errno;

  /* at least in some situations (screen + xterm under SuSE11/12) endwin()
   * doesn't properly flush the screen without an explicit call.  */
  mutt_refresh();
  endwin();

  errno = e;
}
void mutt_endwin (const char *msg)
{
  if (!option (OPTNOCURSES))
  {
    CLEARLINE (LINES - 1);
    
    attrset (A_NORMAL);
    mutt_refresh ();
    endwin ();
  }
  
  if (msg && *msg)
    puts (msg);
}
int _mutt_get_field (/* const */ char *field, char *buf, size_t buflen, int complete, int multiple, char ***files, int *numfiles)
{
  int ret;
  int len = mutt_strlen (field); /* in case field==buffer */

  do
  {
    CLEARLINE (LINES-1);
    addstr (field);
    mutt_refresh ();
    ret = _mutt_enter_string ((unsigned char *) buf, buflen, LINES-1, len, complete, multiple, files, numfiles);
  }
  while (ret == 1);
  CLEARLINE (LINES-1);
  return (ret);
}
void mutt_message (const char *fmt, ...)
{
  va_list ap;

  va_start (ap, fmt);
  vsnprintf (Errorbuf, sizeof (Errorbuf), fmt, ap);
  va_end (ap);

  Errorbuf[ (COLS < sizeof (Errorbuf) ? COLS : sizeof (Errorbuf)) - 2 ] = 0;
  clean_error_buf();

  if (!option (OPTKEEPQUIET))
  {
    SETCOLOR (MT_COLOR_MESSAGE);
    mvaddstr (LINES - 1, 0, Errorbuf);
    clrtoeol ();
    SETCOLOR (MT_COLOR_NORMAL);
    mutt_refresh ();
  }

  unset_option (OPTMSGERR);
}
void mutt_curses_error (const char *fmt, ...)
{
  va_list ap;

  va_start (ap, fmt);
  vsnprintf (Errorbuf, sizeof (Errorbuf), fmt, ap);
  va_end (ap);
  
  dprint (1, (debugfile, "%s\n", Errorbuf));
  Errorbuf[ (COLS < sizeof (Errorbuf) ? COLS : sizeof (Errorbuf)) - 2 ] = 0;
  clean_error_buf();

  if (!option (OPTKEEPQUIET))
  {
    BEEP ();
    SETCOLOR (MT_COLOR_ERROR);
    mvaddstr (LINES-1, 0, Errorbuf);
    clrtoeol ();
    SETCOLOR (MT_COLOR_NORMAL);
    mutt_refresh ();
  }

  set_option (OPTMSGERR);
}
Beispiel #14
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;
}
Beispiel #15
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;
}
Beispiel #16
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 */
}
Beispiel #17
0
int _mutt_enter_string(char *buf, size_t buflen, int y, int x,
			int flags, int multiple, char ***files, int *numfiles,
			struct enter_state *state)
{
	int width = COLS - x - 1;
	int redraw;
	int pass =(flags & M_PASS);
	int first = 1;
	int ch, w, r;
	size_t i;
	wchar_t *tempbuf = 0;
	size_t templen = 0;
	history_class_t hclass;
	wchar_t wc;
	mbstate_t mbstate;

	int rv = 0;
	memset(&mbstate, 0, sizeof(mbstate));

	if (state->wbuf)
	{
		/* Coming back after return 1 */
		redraw = M_REDRAW_LINE;
		first = 0;
	}
	else
	{
		/* Initialise wbuf from buf */
		state->wbuflen = 0;
		state->lastchar = my_mbstowcs(&state->wbuf, &state->wbuflen, 0, buf);
		redraw = M_REDRAW_INIT;
	}

	if (flags & M_FILE)
		hclass = HC_FILE;
	else if (flags & M_EFILE)
		hclass = HC_MBOX;
	else if (flags & M_CMD)
		hclass = HC_CMD;
	else if (flags & M_ALIAS)
		hclass = HC_ALIAS;
	else if (flags & M_COMMAND)
		hclass = HC_COMMAND;
	else if (flags & M_PATTERN)
		hclass = HC_PATTERN;
	else
		hclass = HC_OTHER;

	for(;;)
	{
		if (redraw && !pass)
		{
			if (redraw == M_REDRAW_INIT)
			{
				/* Go to end of line */
				state->curpos = state->lastchar;
				state->begin = width_ceiling(state->wbuf, state->lastchar, my_wcswidth(state->wbuf, state->lastchar) - width + 1);
			}
			if (state->curpos < state->begin ||
			    my_wcswidth(state->wbuf + state->begin, state->curpos - state->begin) >= width)
				state->begin = width_ceiling(state->wbuf, state->lastchar, my_wcswidth(state->wbuf, state->curpos) - width / 2);
			move(y, x);
			w = 0;
			for(i = state->begin; i < state->lastchar; i++)
			{
				w += my_wcwidth(state->wbuf[i]);
				if (w > width)
					break;
				my_addwch(state->wbuf[i]);
			}
			clrtoeol();
			move(y, x + my_wcswidth(state->wbuf + state->begin, state->curpos - state->begin));
		}
		mutt_refresh();

		if ((ch = km_dokey(MENU_EDITOR)) == -1)
		{
			rv = -1;
			goto bye;
		}

		if (ch != OP_NULL)
		{
			first = 0;
			if (ch != OP_EDITOR_COMPLETE && ch != OP_EDITOR_COMPLETE_QUERY)
				state->tabs = 0;
			redraw = M_REDRAW_LINE;
			switch(ch)
			{
			case OP_EDITOR_HISTORY_UP:
				state->curpos = state->lastchar;
				if (mutt_history_at_scratch(hclass))
				{
					my_wcstombs(buf, buflen, state->wbuf, state->curpos);
					mutt_history_save_scratch(hclass, buf);
				}
				replace_part(state, 0, mutt_history_prev(hclass));
				redraw = M_REDRAW_INIT;
				break;

			case OP_EDITOR_HISTORY_DOWN:
				state->curpos = state->lastchar;
				if (mutt_history_at_scratch(hclass))
				{
					my_wcstombs(buf, buflen, state->wbuf, state->curpos);
					mutt_history_save_scratch(hclass, buf);
				}
				replace_part(state, 0, mutt_history_next(hclass));
				redraw = M_REDRAW_INIT;
				break;

			case OP_EDITOR_BACKSPACE:
				if (state->curpos == 0)
					BEEP();
				else
				{
					i = state->curpos;
					while(i && COMB_CHAR(state->wbuf[i - 1]))
						--i;
					if (i)
						--i;
					memmove(state->wbuf + i, state->wbuf + state->curpos,(state->lastchar - state->curpos) * sizeof(wchar_t));
					state->lastchar -= state->curpos - i;
					state->curpos = i;
				}
				break;

			case OP_EDITOR_BOL:
				state->curpos = 0;
				break;

			case OP_EDITOR_EOL:
				redraw= M_REDRAW_INIT;
				break;

			case OP_EDITOR_KILL_LINE:
				state->curpos = state->lastchar = 0;
				break;

			case OP_EDITOR_KILL_EOL:
				state->lastchar = state->curpos;
				break;

			case OP_EDITOR_BACKWARD_CHAR:
				if (state->curpos == 0)
					BEEP();
				else
				{
					while(state->curpos && COMB_CHAR(state->wbuf[state->curpos - 1]))
						state->curpos--;
					if (state->curpos)
						state->curpos--;
				}
				break;

			case OP_EDITOR_FORWARD_CHAR:
				if (state->curpos == state->lastchar)
					BEEP();
				else
				{
					++state->curpos;
					while(state->curpos < state->lastchar && COMB_CHAR(state->wbuf[state->curpos]))
						++state->curpos;
				}
				break;

			case OP_EDITOR_BACKWARD_WORD:
				if (state->curpos == 0)
					BEEP();
				else
				{
					while(state->curpos && iswspace(state->wbuf[state->curpos - 1]))
						--state->curpos;
					while(state->curpos && !iswspace(state->wbuf[state->curpos - 1]))
						--state->curpos;
				}
				break;

			case OP_EDITOR_FORWARD_WORD:
				if (state->curpos == state->lastchar)
					BEEP();
				else
				{
					while(state->curpos < state->lastchar && iswspace(state->wbuf[state->curpos]))
						++state->curpos;
					while(state->curpos < state->lastchar && !iswspace(state->wbuf[state->curpos]))
						++state->curpos;
				}
				break;

			case OP_EDITOR_CAPITALIZE_WORD:
			case OP_EDITOR_UPCASE_WORD:
			case OP_EDITOR_DOWNCASE_WORD:
				if (state->curpos == state->lastchar)
				{
					BEEP();
					break;
				}
				while(state->curpos && !iswspace(state->wbuf[state->curpos]))
					--state->curpos;
				while(state->curpos < state->lastchar && iswspace(state->wbuf[state->curpos]))
					++state->curpos;
				while(state->curpos < state->lastchar && !iswspace(state->wbuf[state->curpos]))
				{
					if (ch == OP_EDITOR_DOWNCASE_WORD)
						state->wbuf[state->curpos] = towlower(state->wbuf[state->curpos]);
					else
					{
						state->wbuf[state->curpos] = towupper(state->wbuf[state->curpos]);
						if (ch == OP_EDITOR_CAPITALIZE_WORD)
							ch = OP_EDITOR_DOWNCASE_WORD;
					}
					state->curpos++;
				}
				break;

			case OP_EDITOR_DELETE_CHAR:
				if (state->curpos == state->lastchar)
					BEEP();
				else
				{
					i = state->curpos;
					while(i < state->lastchar && COMB_CHAR(state->wbuf[i]))
						++i;
					if (i < state->lastchar)
						++i;
					while(i < state->lastchar && COMB_CHAR(state->wbuf[i]))
						++i;
					memmove(state->wbuf + state->curpos, state->wbuf + i,(state->lastchar - i) * sizeof(wchar_t));
					state->lastchar -= i - state->curpos;
				}
				break;

			case OP_EDITOR_KILL_WORD:
				/* delete to beginning of word */
				if (state->curpos != 0)
				{
					i = state->curpos;
					while(i && iswspace(state->wbuf[i - 1]))
						--i;
					if (i)
					{
						if (iswalnum(state->wbuf[i - 1]))
						{
							for(--i; i && iswalnum(state->wbuf[i - 1]); i--)
								;
						}
						else
							--i;
					}
					memmove(state->wbuf + i, state->wbuf + state->curpos,
						(state->lastchar - state->curpos) * sizeof(wchar_t));
					state->lastchar += i - state->curpos;
					state->curpos = i;
				}
				break;

			case OP_EDITOR_KILL_EOW:
				/* delete to end of word */

				/* first skip over whitespace */
				for(i = state->curpos;
				     i < state->lastchar && iswspace(state->wbuf[i]); i++)
					;

				/* if there are any characters left.. */
				if (i < state->lastchar)
				{
					/* if the current character is alphanumeric.. */
					if (iswalnum(state->wbuf[i]))
					{
						/* skip over the rest of the word consistent of only alphanumerics */
						for(; i < state->lastchar && iswalnum(state->wbuf[i]); i++)
							;
					}
					else
					{
						/* skip over one non-alphanumeric character */
						++i;
					}
				}

				memmove(state->wbuf + state->curpos, state->wbuf + i,
					(state->lastchar - i) * sizeof(wchar_t));
				state->lastchar += state->curpos - i;
				break;

			case OP_EDITOR_BUFFY_CYCLE:
				if (flags & M_EFILE)
				{
					first = 1; /* clear input if user types a real key later */
					my_wcstombs(buf, buflen, state->wbuf, state->curpos);
					mutt_buffy(buf, buflen);
					state->curpos = state->lastchar = my_mbstowcs(&state->wbuf, &state->wbuflen, 0, buf);
					break;
				}
				else if (!(flags & M_FILE))
					goto self_insert;
				/* fall through to completion routine(M_FILE) */

			case OP_EDITOR_COMPLETE:
			case OP_EDITOR_COMPLETE_QUERY:
				state->tabs++;
				if (flags & M_CMD)
				{
					for(i = state->curpos; i && !is_shell_char(state->wbuf[i-1]); i--)
						;
					my_wcstombs(buf, buflen, state->wbuf + i, state->curpos - i);
					if (tempbuf && templen == state->lastchar - i &&
					    !memcmp(tempbuf, state->wbuf + i,(state->lastchar - i) * sizeof(wchar_t)))
					{
						mutt_select_file(buf, buflen,(flags & M_EFILE) ? M_SEL_FOLDER : 0);
						set_bit(options, OPTNEEDREDRAW);
						if (*buf)
							replace_part(state, i, buf);
						rv = 1;
						goto bye;
					}
					if (!mutt_complete(buf, buflen))
					{
						templen = state->lastchar - i;
						safe_realloc(&tempbuf, templen * sizeof(wchar_t));
					}
					else
						BEEP();

					replace_part(state, i, buf);
				}
				else if (flags & M_ALIAS && ch == OP_EDITOR_COMPLETE)
				{
					/* invoke the alias-menu to get more addresses */
					for(i = state->curpos; i && state->wbuf[i-1] != ',' &&
						     state->wbuf[i-1] != ':'; i--)
						;
					for(; i < state->lastchar && state->wbuf[i] == ' '; i++)
						;
					my_wcstombs(buf, buflen, state->wbuf + i, state->curpos - i);
					r = mutt_alias_complete(buf, buflen);
					replace_part(state, i, buf);
					if (!r)
					{
						rv = 1;
						goto bye;
					}
					break;
				}
				else if (flags & M_ALIAS && ch == OP_EDITOR_COMPLETE_QUERY)
				{
					/* invoke the query-menu to get more addresses */
					if ((i = state->curpos))
					{
						for(; i && state->wbuf[i - 1] != ','; i--)
							;
						for(; i < state->curpos && state->wbuf[i] == ' '; i++)
							;
					}

					my_wcstombs(buf, buflen, state->wbuf + i, state->curpos - i);
					mutt_query_complete(buf, buflen);
					replace_part(state, i, buf);

					rv = 1;
					goto bye;
				}
				else if (flags & M_COMMAND)
				{
					my_wcstombs(buf, buflen, state->wbuf, state->curpos);
					i = strlen(buf);
					if (i && buf[i - 1] == '=' &&
					    mutt_var_value_complete(buf, buflen, i))
						state->tabs = 0;
					else if (!mutt_command_complete(buf, buflen, i, state->tabs))
						BEEP();
					replace_part(state, 0, buf);
				}
				else if (flags &(M_FILE | M_EFILE))
				{
					my_wcstombs(buf, buflen, state->wbuf, state->curpos);

					/* see if the path has changed from the last time */
					if ((!tempbuf && !state->lastchar) ||(tempbuf && templen == state->lastchar &&
									       !memcmp(tempbuf, state->wbuf, state->lastchar * sizeof(wchar_t))))
					{
						_mutt_select_file(buf, buflen,
								  ((flags & M_EFILE) ? M_SEL_FOLDER : 0) |(multiple ? M_SEL_MULTI : 0),
								   files, numfiles);
						set_bit(options, OPTNEEDREDRAW);
						if (*buf)
						{
							mutt_pretty_mailbox(buf, buflen);
							if (!pass)
								mutt_history_add(hclass, buf, 1);
							rv = 0;
							goto bye;
						}

						/* file selection cancelled */
						rv = 1;
						goto bye;
					}

					if (!mutt_complete(buf, buflen))
					{
						templen = state->lastchar;
						safe_realloc(&tempbuf, templen * sizeof(wchar_t));
						memcpy(tempbuf, state->wbuf, templen * sizeof(wchar_t));
					}
					else
						BEEP(); /* let the user know that nothing matched */
					replace_part(state, 0, buf);
				}
				else
					goto self_insert;
				break;

			case OP_EDITOR_QUOTE_CHAR:
			{
				struct event event;
				/*ADDCH(LastKey);*/
				event = mutt_getch();
				if (event.ch >= 0)
				{
					LastKey = event.ch;
					goto self_insert;
				}
			}

			case OP_EDITOR_TRANSPOSE_CHARS:
				if (state->lastchar < 2)
					BEEP();
				else
				{
					wchar_t t;

					if (state->curpos == 0)
						state->curpos = 2;
					else if (state->curpos < state->lastchar)
						++state->curpos;

					t = state->wbuf[state->curpos - 2];
					state->wbuf[state->curpos - 2] = state->wbuf[state->curpos - 1];
					state->wbuf[state->curpos - 1] = t;
				}
				break;

			default:
				BEEP();
			}
		}
		else
		{

		self_insert:

			state->tabs = 0;
			/* use the raw keypress */
			ch = LastKey;

#if KEY_ENTER
			/* treat ENTER the same as RETURN */
			if (ch == KEY_ENTER)
				ch = '\r';
#endif

			/* quietly ignore all other function keys */
			if (ch & ~0xff)
				continue;

			/* gather the octets into a wide character */
			{
				char c;
				size_t k;

				c = ch;
				k = mbrtowc(&wc, &c, 1, &mbstate);
				if (k ==(size_t)(-2))
					continue;
				else if (k && k != 1)
				{
					memset(&mbstate, 0, sizeof(mbstate));
					continue;
				}
			}

			if (first &&(flags & M_CLEAR))
			{
				first = 0;
				if (IsWPrint(wc)) /* why? */
					state->curpos = state->lastchar = 0;
			}

			if (wc == '\r' || wc == '\n')
			{
				/* Convert from wide characters */
				my_wcstombs(buf, buflen, state->wbuf, state->lastchar);
				if (!pass)
					mutt_history_add(hclass, buf, 1);

				if (multiple)
				{
					char **tfiles;
					*numfiles = 1;
					tfiles = safe_calloc(*numfiles, sizeof(char *));
					mutt_expand_path(buf, buflen);
					tfiles[0] = safe_strdup(buf);
					*files = tfiles;
				}
				rv = 0;
				goto bye;
			}
			else if (wc &&(wc < ' ' || IsWPrint(wc))) /* why? */
			{
				if (state->lastchar >= state->wbuflen)
				{
					state->wbuflen = state->lastchar + 20;
					safe_realloc(&state->wbuf, state->wbuflen * sizeof(wchar_t));
				}
				memmove(state->wbuf + state->curpos + 1, state->wbuf + state->curpos,(state->lastchar - state->curpos) * sizeof(wchar_t));
				state->wbuf[state->curpos++] = wc;
				state->lastchar++;
			}
			else
			{
				mutt_flushinp();
				BEEP();
			}
		}
	}

bye:

	mutt_reset_history_state(hclass);
	safe_free(&tempbuf);
	return rv;
}