mutt stable branch with some hacks
1/*
2 * Copyright (C) 1996-2000,2007,2011,2013 Michael R. Elkins <me@mutt.org>
3 * Copyright (C) 2000-2001 Edmund Grimley Evans <edmundo@rano.org>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 */
19
20#if HAVE_CONFIG_H
21# include "config.h"
22#endif
23
24#include "mutt.h"
25#include "mutt_menu.h"
26#include "mutt_curses.h"
27#include "keymap.h"
28#include "history.h"
29#include "buffy.h"
30
31#include <string.h>
32
33/* redraw flags for mutt_enter_string() */
34enum
35{
36 MUTT_REDRAW_INIT = 1, /* go to end of line and redraw */
37 MUTT_REDRAW_LINE /* redraw entire line */
38};
39
40static int my_wcwidth (wchar_t wc)
41{
42 int n = wcwidth (wc);
43 if (IsWPrint (wc) && n > 0)
44 return n;
45 if (!(wc & ~0x7f))
46 return 2;
47 if (!(wc & ~0xffff))
48 return 6;
49 return 10;
50}
51
52/* combining mark / non-spacing character */
53#define COMB_CHAR(wc) (IsWPrint (wc) && !wcwidth (wc))
54
55static int my_wcswidth (const wchar_t *s, size_t n)
56{
57 int w = 0;
58 while (n--)
59 w += my_wcwidth (*s++);
60 return w;
61}
62
63static int my_addwch (wchar_t wc)
64{
65 int n = wcwidth (wc);
66 if (IsWPrint (wc) && n > 0)
67 return mutt_addwch (wc);
68 if (!(wc & ~0x7f))
69 return printw ("^%c", ((int)wc + 0x40) & 0x7f);
70 if (!(wc & ~0xffff))
71 return printw ("\\u%04x", (int)wc);
72 return printw ("\\u%08x", (int)wc);
73}
74
75static size_t width_ceiling (const wchar_t *s, size_t n, int w1)
76{
77 const wchar_t *s0 = s;
78 int w = 0;
79 for (; n; s++, n--)
80 if ((w += my_wcwidth (*s)) > w1)
81 break;
82 return s - s0;
83}
84
85static void my_wcstombs (char *dest, size_t dlen, const wchar_t *src, size_t slen)
86{
87 mbstate_t st;
88 size_t k;
89
90 /* First convert directly into the destination buffer */
91 memset (&st, 0, sizeof (st));
92 for (; slen && dlen >= MB_LEN_MAX; dest += k, dlen -= k, src++, slen--)
93 if ((k = wcrtomb (dest, *src, &st)) == (size_t)(-1))
94 break;
95
96 /* If this works, we can stop now */
97 if (dlen >= MB_LEN_MAX)
98 {
99 /* We don't need to update dest - this just appeases -Wunused-result */
100 dest += wcrtomb (dest, 0, &st);
101 return;
102 }
103
104 /* Otherwise convert any remaining data into a local buffer */
105 {
106 char buf[3 * MB_LEN_MAX];
107 char *p = buf;
108
109 for (; slen && p - buf < dlen; p += k, src++, slen--)
110 if ((k = wcrtomb (p, *src, &st)) == (size_t)(-1))
111 break;
112 p += wcrtomb (p, 0, &st);
113
114 /* If it fits into the destination buffer, we can stop now */
115 if (p - buf <= dlen)
116 {
117 memcpy (dest, buf, p - buf);
118 return;
119 }
120
121 /* Otherwise we truncate the string in an ugly fashion */
122 memcpy (dest, buf, dlen);
123 dest[dlen - 1] = '\0'; /* assume original dlen > 0 */
124 }
125}
126
127static size_t my_mbstowcs (wchar_t **pwbuf, size_t *pwbuflen, size_t i, char *buf)
128{
129 wchar_t wc;
130 mbstate_t st;
131 size_t k;
132 wchar_t *wbuf;
133 size_t wbuflen;
134
135 wbuf = *pwbuf, wbuflen = *pwbuflen;
136
137 while (*buf)
138 {
139 memset (&st, 0, sizeof (st));
140 for (; (k = mbrtowc (&wc, buf, MB_LEN_MAX, &st)) &&
141 k != (size_t)(-1) && k != (size_t)(-2); buf += k)
142 {
143 if (i >= wbuflen)
144 {
145 wbuflen = i + 20;
146 safe_realloc (&wbuf, wbuflen * sizeof (*wbuf));
147 }
148 wbuf[i++] = wc;
149 }
150 if (*buf && (k == (size_t) -1 || k == (size_t) -2))
151 {
152 if (i >= wbuflen)
153 {
154 wbuflen = i + 20;
155 safe_realloc (&wbuf, wbuflen * sizeof (*wbuf));
156 }
157 wbuf[i++] = replacement_char();
158 buf++;
159 }
160 }
161 *pwbuf = wbuf, *pwbuflen = wbuflen;
162 return i;
163}
164
165/*
166 * Replace part of the wchar_t buffer, from FROM to CURPOS, by BUF.
167 */
168
169static void replace_part (ENTER_STATE *state, size_t from, char *buf)
170{
171 /* Save the suffix */
172 size_t savelen = state->lastchar - state->curpos;
173 wchar_t *savebuf = NULL;
174
175 if (savelen)
176 {
177 savebuf = safe_calloc (savelen, sizeof (wchar_t));
178 memcpy (savebuf, state->wbuf + state->curpos, savelen * sizeof (wchar_t));
179 }
180
181 /* Convert to wide characters */
182 state->curpos = my_mbstowcs (&state->wbuf, &state->wbuflen, from, buf);
183
184 if (savelen)
185 {
186 /* Make space for suffix */
187 if (state->curpos + savelen > state->wbuflen)
188 {
189 state->wbuflen = state->curpos + savelen;
190 safe_realloc (&state->wbuf, state->wbuflen * sizeof (wchar_t));
191 }
192
193 /* Restore suffix */
194 memcpy (state->wbuf + state->curpos, savebuf, savelen * sizeof (wchar_t));
195 FREE (&savebuf);
196 }
197
198 state->lastchar = state->curpos + savelen;
199}
200
201/*
202 * Return 1 if the character is not typically part of a pathname
203 */
204static inline int is_shell_char(wchar_t ch)
205{
206 static const wchar_t shell_chars[] = L"<>&()$?*;{}| "; /* ! not included because it can be part of a pathname in Mutt */
207 return wcschr(shell_chars, ch) != NULL;
208}
209
210/* This function is for very basic input, currently used only by the
211 * built-in editor. It does not handle screen redrawing on resizes
212 * well, because there is no active menu for the built-in editor.
213 * Most callers should prefer mutt_get_field() instead.
214 *
215 * Returns:
216 * 0 if input was given
217 * -1 if abort.
218 */
219int mutt_enter_string(char *buf, size_t buflen, int col, int flags)
220{
221 int rv;
222 ENTER_STATE *es = mutt_new_enter_state ();
223 do
224 {
225#if defined (USE_SLANG_CURSES) || defined (HAVE_RESIZETERM)
226 if (SigWinch)
227 {
228 SigWinch = 0;
229 mutt_resize_screen ();
230 clearok(stdscr, TRUE);
231 }
232#endif
233 rv = _mutt_enter_string (buf, buflen, col, flags, 0, NULL, NULL, es);
234 }
235 while (rv == 1);
236 mutt_free_enter_state (&es);
237 return rv;
238}
239
240/*
241 * Returns:
242 * 1 need to redraw the screen and call me again
243 * 0 if input was given
244 * -1 if abort.
245 */
246int _mutt_enter_string (char *buf, size_t buflen, int col,
247 int flags, int multiple, char ***files, int *numfiles,
248 ENTER_STATE *state)
249{
250 int width = MuttMessageWindow->cols - col - 1;
251 int redraw;
252 int pass = (flags & MUTT_PASS);
253 int first = 1;
254 int ch, w, r;
255 size_t i;
256 wchar_t *tempbuf = 0;
257 size_t templen = 0;
258 history_class_t hclass;
259 wchar_t wc;
260 mbstate_t mbstate;
261
262 int rv = 0;
263 memset (&mbstate, 0, sizeof (mbstate));
264
265 if (state->wbuf)
266 {
267 /* Coming back after return 1 */
268 redraw = MUTT_REDRAW_LINE;
269 first = 0;
270 }
271 else
272 {
273 /* Initialise wbuf from buf */
274 state->wbuflen = 0;
275 state->lastchar = my_mbstowcs (&state->wbuf, &state->wbuflen, 0, buf);
276 redraw = MUTT_REDRAW_INIT;
277 }
278
279 if (flags & MUTT_FILE)
280 hclass = HC_FILE;
281 else if (flags & MUTT_EFILE)
282 hclass = HC_MBOX;
283 else if (flags & MUTT_CMD)
284 hclass = HC_CMD;
285 else if (flags & MUTT_ALIAS)
286 hclass = HC_ALIAS;
287 else if (flags & MUTT_COMMAND)
288 hclass = HC_COMMAND;
289 else if (flags & MUTT_PATTERN)
290 hclass = HC_PATTERN;
291 else
292 hclass = HC_OTHER;
293
294 for (;;)
295 {
296 if (redraw && !pass)
297 {
298 if (redraw == MUTT_REDRAW_INIT)
299 {
300 /* Go to end of line */
301 state->curpos = state->lastchar;
302 state->begin = width_ceiling (state->wbuf, state->lastchar, my_wcswidth (state->wbuf, state->lastchar) - width + 1);
303 }
304 if (state->curpos < state->begin ||
305 my_wcswidth (state->wbuf + state->begin, state->curpos - state->begin) >= width)
306 state->begin = width_ceiling (state->wbuf, state->lastchar, my_wcswidth (state->wbuf, state->curpos) - width / 2);
307 mutt_window_move (MuttMessageWindow, 0, col);
308 w = 0;
309 for (i = state->begin; i < state->lastchar; i++)
310 {
311 w += my_wcwidth (state->wbuf[i]);
312 if (w > width)
313 break;
314 my_addwch (state->wbuf[i]);
315 }
316 mutt_window_clrtoeol (MuttMessageWindow);
317 mutt_window_move (MuttMessageWindow, 0,
318 col + my_wcswidth (state->wbuf + state->begin, state->curpos - state->begin));
319 }
320 mutt_refresh ();
321
322 if ((ch = km_dokey (MENU_EDITOR)) < 0)
323 {
324 rv = (SigWinch && ch == -2) ? 1 : -1;
325 goto bye;
326 }
327
328 if (ch != OP_NULL)
329 {
330 first = 0;
331 if (ch != OP_EDITOR_COMPLETE && ch != OP_EDITOR_COMPLETE_QUERY)
332 state->tabs = 0;
333 redraw = MUTT_REDRAW_LINE;
334 switch (ch)
335 {
336 case OP_EDITOR_HISTORY_UP:
337 state->curpos = state->lastchar;
338 if (mutt_history_at_scratch (hclass))
339 {
340 my_wcstombs (buf, buflen, state->wbuf, state->curpos);
341 mutt_history_save_scratch (hclass, buf);
342 }
343 replace_part (state, 0, mutt_history_prev (hclass));
344 redraw = MUTT_REDRAW_INIT;
345 break;
346
347 case OP_EDITOR_HISTORY_DOWN:
348 state->curpos = state->lastchar;
349 if (mutt_history_at_scratch (hclass))
350 {
351 my_wcstombs (buf, buflen, state->wbuf, state->curpos);
352 mutt_history_save_scratch (hclass, buf);
353 }
354 replace_part (state, 0, mutt_history_next (hclass));
355 redraw = MUTT_REDRAW_INIT;
356 break;
357
358 case OP_EDITOR_HISTORY_SEARCH:
359 state->curpos = state->lastchar;
360 my_wcstombs (buf, buflen, state->wbuf, state->curpos);
361 mutt_history_complete (buf, buflen, hclass);
362 replace_part (state, 0, buf);
363 rv = 1;
364 goto bye;
365 break;
366
367 case OP_EDITOR_BACKSPACE:
368 if (state->curpos == 0)
369 BEEP ();
370 else
371 {
372 i = state->curpos;
373 while (i && COMB_CHAR (state->wbuf[i - 1]))
374 --i;
375 if (i)
376 --i;
377 memmove (state->wbuf + i, state->wbuf + state->curpos, (state->lastchar - state->curpos) * sizeof (wchar_t));
378 state->lastchar -= state->curpos - i;
379 state->curpos = i;
380 }
381 break;
382
383 case OP_EDITOR_BOL:
384 state->curpos = 0;
385 break;
386
387 case OP_EDITOR_EOL:
388 redraw= MUTT_REDRAW_INIT;
389 break;
390
391 case OP_EDITOR_KILL_LINE:
392 state->curpos = state->lastchar = 0;
393 break;
394
395 case OP_EDITOR_KILL_EOL:
396 state->lastchar = state->curpos;
397 break;
398
399 case OP_EDITOR_BACKWARD_CHAR:
400 if (state->curpos == 0)
401 BEEP ();
402 else
403 {
404 while (state->curpos && COMB_CHAR (state->wbuf[state->curpos - 1]))
405 state->curpos--;
406 if (state->curpos)
407 state->curpos--;
408 }
409 break;
410
411 case OP_EDITOR_FORWARD_CHAR:
412 if (state->curpos == state->lastchar)
413 BEEP ();
414 else
415 {
416 ++state->curpos;
417 while (state->curpos < state->lastchar && COMB_CHAR (state->wbuf[state->curpos]))
418 ++state->curpos;
419 }
420 break;
421
422 case OP_EDITOR_BACKWARD_WORD:
423 if (state->curpos == 0)
424 BEEP ();
425 else
426 {
427 while (state->curpos && iswspace (state->wbuf[state->curpos - 1]))
428 --state->curpos;
429 while (state->curpos && !iswspace (state->wbuf[state->curpos - 1]))
430 --state->curpos;
431 }
432 break;
433
434 case OP_EDITOR_FORWARD_WORD:
435 if (state->curpos == state->lastchar)
436 BEEP ();
437 else
438 {
439 while (state->curpos < state->lastchar && iswspace (state->wbuf[state->curpos]))
440 ++state->curpos;
441 while (state->curpos < state->lastchar && !iswspace (state->wbuf[state->curpos]))
442 ++state->curpos;
443 }
444 break;
445
446 case OP_EDITOR_CAPITALIZE_WORD:
447 case OP_EDITOR_UPCASE_WORD:
448 case OP_EDITOR_DOWNCASE_WORD:
449 if (state->curpos == state->lastchar)
450 {
451 BEEP ();
452 break;
453 }
454 while (state->curpos && !iswspace (state->wbuf[state->curpos]))
455 --state->curpos;
456 while (state->curpos < state->lastchar && iswspace (state->wbuf[state->curpos]))
457 ++state->curpos;
458 while (state->curpos < state->lastchar && !iswspace (state->wbuf[state->curpos]))
459 {
460 if (ch == OP_EDITOR_DOWNCASE_WORD)
461 state->wbuf[state->curpos] = towlower (state->wbuf[state->curpos]);
462 else
463 {
464 state->wbuf[state->curpos] = towupper (state->wbuf[state->curpos]);
465 if (ch == OP_EDITOR_CAPITALIZE_WORD)
466 ch = OP_EDITOR_DOWNCASE_WORD;
467 }
468 state->curpos++;
469 }
470 break;
471
472 case OP_EDITOR_DELETE_CHAR:
473 if (state->curpos == state->lastchar)
474 BEEP ();
475 else
476 {
477 i = state->curpos;
478 while (i < state->lastchar && COMB_CHAR (state->wbuf[i]))
479 ++i;
480 if (i < state->lastchar)
481 ++i;
482 while (i < state->lastchar && COMB_CHAR (state->wbuf[i]))
483 ++i;
484 memmove (state->wbuf + state->curpos, state->wbuf + i, (state->lastchar - i) * sizeof (wchar_t));
485 state->lastchar -= i - state->curpos;
486 }
487 break;
488
489 case OP_EDITOR_KILL_WORD:
490 /* delete to beginning of word */
491 if (state->curpos != 0)
492 {
493 i = state->curpos;
494 while (i && iswspace (state->wbuf[i - 1]))
495 --i;
496 if (i)
497 {
498 if (iswalnum (state->wbuf[i - 1]))
499 {
500 for (--i; i && iswalnum (state->wbuf[i - 1]); i--)
501 ;
502 }
503 else
504 --i;
505 }
506 memmove (state->wbuf + i, state->wbuf + state->curpos,
507 (state->lastchar - state->curpos) * sizeof (wchar_t));
508 state->lastchar += i - state->curpos;
509 state->curpos = i;
510 }
511 break;
512
513 case OP_EDITOR_KILL_EOW:
514 /* delete to end of word */
515
516 /* first skip over whitespace */
517 for (i = state->curpos;
518 i < state->lastchar && iswspace (state->wbuf[i]); i++)
519 ;
520
521 /* if there are any characters left.. */
522 if (i < state->lastchar)
523 {
524 /* if the current character is alphanumeric.. */
525 if (iswalnum (state->wbuf[i]))
526 {
527 /* skip over the rest of the word consistent of only alphanumerics */
528 for (; i < state->lastchar && iswalnum (state->wbuf[i]); i++)
529 ;
530 }
531 else
532 {
533 /* skip over one non-alphanumeric character */
534 ++i;
535 }
536 }
537
538 memmove (state->wbuf + state->curpos, state->wbuf + i,
539 (state->lastchar - i) * sizeof (wchar_t));
540 state->lastchar += state->curpos - i;
541 break;
542
543 case OP_EDITOR_BUFFY_CYCLE:
544 if (flags & MUTT_EFILE)
545 {
546 first = 1; /* clear input if user types a real key later */
547 my_wcstombs (buf, buflen, state->wbuf, state->curpos);
548 mutt_buffy (buf, buflen);
549 state->curpos = state->lastchar = my_mbstowcs (&state->wbuf, &state->wbuflen, 0, buf);
550 break;
551 }
552 else if (!(flags & MUTT_FILE))
553 goto self_insert;
554 /* else fall through */
555
556 case OP_EDITOR_COMPLETE:
557 case OP_EDITOR_COMPLETE_QUERY:
558 state->tabs++;
559 if (flags & MUTT_CMD)
560 {
561 for (i = state->curpos; i && !is_shell_char(state->wbuf[i-1]); i--)
562 ;
563 my_wcstombs (buf, buflen, state->wbuf + i, state->curpos - i);
564 if (tempbuf && templen == state->lastchar - i &&
565 !memcmp (tempbuf, state->wbuf + i, (state->lastchar - i) * sizeof (wchar_t)))
566 {
567 mutt_select_file (buf, buflen, (flags & MUTT_EFILE) ? MUTT_SEL_FOLDER : 0);
568 if (*buf)
569 replace_part (state, i, buf);
570 rv = 1;
571 goto bye;
572 }
573 if (!mutt_complete (buf, buflen))
574 {
575 templen = state->lastchar - i;
576 safe_realloc (&tempbuf, templen * sizeof (wchar_t));
577 }
578 else
579 BEEP ();
580
581 replace_part (state, i, buf);
582 }
583 else if (flags & MUTT_ALIAS && ch == OP_EDITOR_COMPLETE)
584 {
585 /* invoke the alias-menu to get more addresses */
586 for (i = state->curpos;
587 i && state->wbuf[i-1] != ',' && state->wbuf[i-1] != ':';
588 i--)
589 ;
590 for (; i < state->lastchar && state->wbuf[i] == ' '; i++)
591 ;
592 my_wcstombs (buf, buflen, state->wbuf + i, state->curpos - i);
593 r = mutt_alias_complete (buf, buflen);
594 replace_part (state, i, buf);
595 if (!r)
596 {
597 rv = 1;
598 goto bye;
599 }
600 break;
601 }
602 else if (flags & MUTT_LABEL && ch == OP_EDITOR_COMPLETE)
603 {
604 for (i = state->curpos;
605 i && state->wbuf[i-1] != ',' && state->wbuf[i-1] != ':';
606 i--)
607 ;
608 for (; i < state->lastchar && state->wbuf[i] == ' '; i++)
609 ;
610 my_wcstombs (buf, buflen, state->wbuf + i, state->curpos - i);
611 r = mutt_label_complete (buf, buflen, state->tabs);
612 replace_part (state, i, buf);
613 if (!r)
614 {
615 rv = 1;
616 goto bye;
617 }
618 break;
619 }
620 else if (flags & MUTT_PATTERN && ch == OP_EDITOR_COMPLETE)
621 {
622 for (i = state->curpos; i && state->wbuf[i-1] != '~'; i--)
623 ;
624 if (i && i < state->curpos && state->wbuf[i-1] == '~' && state->wbuf[i] == 'y')
625 {
626 i++;
627 my_wcstombs (buf, buflen, state->wbuf + i, state->curpos - i);
628 r = mutt_label_complete (buf, buflen, state->tabs);
629 replace_part (state, i, buf);
630 if (!r)
631 {
632 rv = 1;
633 goto bye;
634 }
635 }
636 else
637 goto self_insert;
638 break;
639 }
640 else if (flags & MUTT_ALIAS && ch == OP_EDITOR_COMPLETE_QUERY)
641 {
642 /* invoke the query-menu to get more addresses */
643 if ((i = state->curpos))
644 {
645 for (; i && state->wbuf[i - 1] != ','; i--)
646 ;
647 for (; i < state->curpos && state->wbuf[i] == ' '; i++)
648 ;
649 }
650
651 my_wcstombs (buf, buflen, state->wbuf + i, state->curpos - i);
652 mutt_query_complete (buf, buflen);
653 replace_part (state, i, buf);
654
655 rv = 1;
656 goto bye;
657 }
658 else if (flags & MUTT_COMMAND)
659 {
660 my_wcstombs (buf, buflen, state->wbuf, state->curpos);
661 i = strlen (buf);
662 if (i && buf[i - 1] == '=' &&
663 mutt_var_value_complete (buf, buflen, i))
664 state->tabs = 0;
665 else if (!mutt_command_complete (buf, buflen, i, state->tabs))
666 BEEP ();
667 replace_part (state, 0, buf);
668 }
669 else if (flags & (MUTT_FILE | MUTT_EFILE))
670 {
671 my_wcstombs (buf, buflen, state->wbuf, state->curpos);
672
673 /* see if the path has changed from the last time */
674 if ((!tempbuf && !state->lastchar) ||
675 (tempbuf && templen == state->lastchar &&
676 !memcmp (tempbuf, state->wbuf, state->lastchar * sizeof (wchar_t))))
677 {
678 _mutt_select_file (buf, buflen,
679 ((flags & MUTT_EFILE) ? MUTT_SEL_FOLDER : 0) | (multiple ? MUTT_SEL_MULTI : 0),
680 files, numfiles);
681 if (*buf)
682 {
683 mutt_pretty_mailbox (buf, buflen);
684 if (!pass)
685 mutt_history_add (hclass, buf, 1);
686 rv = 0;
687 goto bye;
688 }
689
690 /* file selection cancelled */
691 rv = 1;
692 goto bye;
693 }
694
695 if (!mutt_complete (buf, buflen))
696 {
697 templen = state->lastchar;
698 safe_realloc (&tempbuf, templen * sizeof (wchar_t));
699 memcpy (tempbuf, state->wbuf, templen * sizeof (wchar_t));
700 }
701 else
702 BEEP (); /* let the user know that nothing matched */
703 replace_part (state, 0, buf);
704 }
705 else
706 goto self_insert;
707 break;
708
709 case OP_EDITOR_QUOTE_CHAR:
710 {
711 event_t event;
712 /*ADDCH (LastKey);*/
713 do
714 {
715 event = mutt_getch ();
716 } while (event.ch == -2);
717 if (event.ch >= 0)
718 {
719 LastKey = event.ch;
720 goto self_insert;
721 }
722 break;
723 }
724
725 case OP_EDITOR_TRANSPOSE_CHARS:
726 if (state->lastchar < 2)
727 BEEP ();
728 else
729 {
730 wchar_t t;
731
732 if (state->curpos == 0)
733 state->curpos = 2;
734 else if (state->curpos < state->lastchar)
735 ++state->curpos;
736
737 t = state->wbuf[state->curpos - 2];
738 state->wbuf[state->curpos - 2] = state->wbuf[state->curpos - 1];
739 state->wbuf[state->curpos - 1] = t;
740 }
741 break;
742
743 default:
744 BEEP ();
745 }
746 }
747 else
748 {
749
750self_insert:
751
752 state->tabs = 0;
753 /* use the raw keypress */
754 ch = LastKey;
755
756#ifdef KEY_ENTER
757 /* treat ENTER the same as RETURN */
758 if (ch == KEY_ENTER)
759 ch = '\r';
760#endif
761
762 /* quietly ignore all other function keys */
763 if (ch & ~0xff)
764 continue;
765
766 /* gather the octets into a wide character */
767 {
768 char c;
769 size_t k;
770
771 c = ch;
772 k = mbrtowc (&wc, &c, 1, &mbstate);
773 if (k == (size_t)(-2))
774 continue;
775 else if (k && k != 1)
776 {
777 memset (&mbstate, 0, sizeof (mbstate));
778 continue;
779 }
780 }
781
782 if (first && (flags & MUTT_CLEAR))
783 {
784 first = 0;
785 if (IsWPrint (wc)) /* why? */
786 state->curpos = state->lastchar = 0;
787 }
788
789 if (wc == '\r' || wc == '\n')
790 {
791 /* Convert from wide characters */
792 my_wcstombs (buf, buflen, state->wbuf, state->lastchar);
793 if (!pass)
794 mutt_history_add (hclass, buf, 1);
795
796 if (multiple)
797 {
798 char **tfiles;
799 *numfiles = 1;
800 tfiles = safe_calloc (*numfiles, sizeof (char *));
801 mutt_expand_path (buf, buflen);
802 tfiles[0] = safe_strdup (buf);
803 *files = tfiles;
804 }
805 rv = 0;
806 goto bye;
807 }
808 else if (wc && (wc < ' ' || IsWPrint (wc))) /* why? */
809 {
810 if (state->lastchar >= state->wbuflen)
811 {
812 state->wbuflen = state->lastchar + 20;
813 safe_realloc (&state->wbuf, state->wbuflen * sizeof (wchar_t));
814 }
815 memmove (state->wbuf + state->curpos + 1, state->wbuf + state->curpos, (state->lastchar - state->curpos) * sizeof (wchar_t));
816 state->wbuf[state->curpos++] = wc;
817 state->lastchar++;
818 }
819 else
820 {
821 mutt_flushinp ();
822 BEEP ();
823 }
824 }
825 }
826
827bye:
828
829 mutt_reset_history_state (hclass);
830 FREE (&tempbuf);
831 return rv;
832}
833
834void mutt_free_enter_state (ENTER_STATE **esp)
835{
836 if (!esp) return;
837
838 FREE (&(*esp)->wbuf);
839 FREE (esp); /* __FREE_CHECKED__ */
840}
841
842/*
843 * TODO:
844 * very narrow screen might crash it
845 * sort out the input side
846 * unprintable chars
847 */