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