NeoMutt  2020-03-20-65-g141838
Teaching an old dog new tricks
DOXYGEN
curs_lib.c
Go to the documentation of this file.
1 
30 #include "config.h"
31 #include <stddef.h>
32 #include <ctype.h>
33 #include <errno.h>
34 #include <fcntl.h>
35 #include <langinfo.h>
36 #include <limits.h>
37 #include <regex.h>
38 #include <stdbool.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <termios.h>
43 #include <unistd.h>
44 #include <wchar.h>
45 #include "mutt/lib.h"
46 #include "config/lib.h"
47 #include "core/lib.h"
48 #include "mutt.h"
49 #include "curs_lib.h"
50 #include "browser.h"
51 #include "color.h"
52 #include "enter_state.h"
53 #include "globals.h"
54 #include "keymap.h"
55 #include "mutt_curses.h"
56 #include "mutt_logging.h"
57 #include "mutt_menu.h"
58 #include "mutt_window.h"
59 #include "opcodes.h"
60 #include "options.h"
61 #include "pager.h"
62 #include "protos.h"
63 #ifdef HAVE_ISWBLANK
64 #include <wctype.h>
65 #endif
66 #ifdef USE_INOTIFY
67 #include "monitor.h"
68 #endif
69 
70 /* These Config Variables are only used in curs_lib.c */
71 bool C_MetaKey;
72 
73 /* not possible to unget more than one char under some curses libs, and it
74  * is impossible to unget function keys in SLang, so roll our own input
75  * buffering routines.
76  */
77 
78 /* These are used for macros and exec/push commands.
79  * They can be temporarily ignored by setting OptIgnoreMacroEvents
80  */
81 static size_t MacroBufferCount = 0;
82 static size_t MacroBufferLen = 0;
83 static struct KeyEvent *MacroEvents;
84 
85 /* These are used in all other "normal" situations, and are not
86  * ignored when setting OptIgnoreMacroEvents
87  */
88 static size_t UngetCount = 0;
89 static size_t UngetLen = 0;
90 static struct KeyEvent *UngetKeyEvents;
91 
93 
98 void mutt_beep(bool force)
99 {
100  if (force || C_Beep)
101  beep();
102 }
103 
107 void mutt_refresh(void)
108 {
109  /* don't refresh when we are waiting for a child. */
110  if (OptKeepQuiet)
111  return;
112 
113  /* don't refresh in the middle of macros unless necessary */
115  return;
116 
117  /* else */
118  refresh();
119 }
120 
130 {
131  keypad(stdscr, true);
132  clearok(stdscr, true);
134 }
135 
145 void mutt_getch_timeout(int delay)
146 {
147  MuttGetchTimeout = delay;
148  timeout(delay);
149 }
150 
151 #ifdef USE_INOTIFY
152 
157 static int mutt_monitor_getch(void)
158 {
159  /* ncurses has its own internal buffer, so before we perform a poll,
160  * we need to make sure there isn't a character waiting */
161  timeout(0);
162  int ch = getch();
163  timeout(MuttGetchTimeout);
164  if (ch == ERR)
165  {
166  if (mutt_monitor_poll() != 0)
167  ch = ERR;
168  else
169  ch = getch();
170  }
171  return ch;
172 }
173 #endif /* USE_INOTIFY */
174 
188 struct KeyEvent mutt_getch(void)
189 {
190  int ch;
191  struct KeyEvent err = { -1, OP_NULL }, ret;
192  struct KeyEvent timeout = { -2, OP_NULL };
193 
194  if (UngetCount)
195  return UngetKeyEvents[--UngetCount];
196 
198  return MacroEvents[--MacroBufferCount];
199 
200  SigInt = 0;
201 
203 #ifdef KEY_RESIZE
204  /* ncurses 4.2 sends this when the screen is resized */
205  ch = KEY_RESIZE;
206  while (ch == KEY_RESIZE)
207 #endif /* KEY_RESIZE */
208 #ifdef USE_INOTIFY
209  ch = mutt_monitor_getch();
210 #else
211  ch = getch();
212 #endif /* USE_INOTIFY */
214 
215  if (SigInt)
216  {
217  mutt_query_exit();
218  return err;
219  }
220 
221  /* either timeout, a sigwinch (if timeout is set), or the terminal
222  * has been lost */
223  if (ch == ERR)
224  {
225  if (!isatty(0))
226  mutt_exit(1);
227 
228  return timeout;
229  }
230 
231  if ((ch & 0x80) && C_MetaKey)
232  {
233  /* send ALT-x as ESC-x */
234  ch &= ~0x80;
235  mutt_unget_event(ch, 0);
236  ret.ch = '\033'; // Escape
237  ret.op = 0;
238  return ret;
239  }
240 
241  ret.ch = ch;
242  ret.op = 0;
243  return (ch == AbortKey) ? err : ret;
244 }
245 
258 int mutt_buffer_get_field_full(const char *field, struct Buffer *buf, CompletionFlags complete,
259  bool multiple, char ***files, int *numfiles)
260 {
261  int ret;
262  int col;
263 
264  struct EnterState *es = mutt_enter_state_new();
265 
266  do
267  {
268  if (SigWinch)
269  {
270  SigWinch = 0;
272  clearok(stdscr, true);
274  }
277  mutt_window_addstr(field);
279  mutt_refresh();
281  ret = mutt_enter_string_full(buf->data, buf->dsize, col, complete, multiple,
282  files, numfiles, es);
283  } while (ret == 1);
284 
285  if (ret == 0)
287  else
288  mutt_buffer_reset(buf);
289 
292 
293  return ret;
294 }
295 
309 int mutt_get_field_full(const char *field, char *buf, size_t buflen, CompletionFlags complete,
310  bool multiple, char ***files, int *numfiles)
311 {
312  if (!buf)
313  return -1;
314 
315  struct Buffer tmp = {
316  .data = buf,
317  .dptr = buf + mutt_str_strlen(buf),
318  .dsize = buflen,
319  };
320  return mutt_buffer_get_field_full(field, &tmp, complete, multiple, files, numfiles);
321 }
322 
333 int mutt_get_field_unbuffered(const char *msg, char *buf, size_t buflen, CompletionFlags flags)
334 {
335  bool reset_ignoremacro = false;
336 
338  {
339  OptIgnoreMacroEvents = true;
340  reset_ignoremacro = true;
341  }
342  int rc = mutt_get_field(msg, buf, buflen, flags);
343  if (reset_ignoremacro)
344  OptIgnoreMacroEvents = false;
345 
346  return rc;
347 }
348 
354 void mutt_edit_file(const char *editor, const char *file)
355 {
356  struct Buffer *cmd = mutt_buffer_pool_get();
357 
358  mutt_endwin();
359  mutt_buffer_file_expand_fmt_quote(cmd, editor, file);
360  if (mutt_system(mutt_b2s(cmd)) != 0)
361  {
362  mutt_error(_("Error running \"%s\""), mutt_b2s(cmd));
363  }
364  /* the terminal may have been resized while the editor owned it */
366  keypad(stdscr, true);
367  clearok(stdscr, true);
368 
370 }
371 
378 enum QuadOption mutt_yesorno(const char *msg, enum QuadOption def)
379 {
380  struct KeyEvent ch;
381  char *yes = _("yes");
382  char *no = _("no");
383  char *answer_string = NULL;
384  int answer_string_wid, msg_wid;
385  size_t trunc_msg_len;
386  bool redraw = true;
387  int prompt_lines = 1;
388 
389  char *expr = NULL;
390  regex_t reyes;
391  regex_t reno;
392  char answer[2];
393 
394  answer[1] = '\0';
395 
396  bool reyes_ok = (expr = nl_langinfo(YESEXPR)) && (expr[0] == '^') &&
397  (REG_COMP(&reyes, expr, REG_NOSUB) == 0);
398  bool reno_ok = (expr = nl_langinfo(NOEXPR)) && (expr[0] == '^') &&
399  (REG_COMP(&reno, expr, REG_NOSUB) == 0);
400 
401  /* In order to prevent the default answer to the question to wrapped
402  * around the screen in the even the question is wider than the screen,
403  * ensure there is enough room for the answer and truncate the question
404  * to fit. */
405  mutt_str_asprintf(&answer_string, " ([%s]/%s): ", (def == MUTT_YES) ? yes : no,
406  (def == MUTT_YES) ? no : yes);
407  answer_string_wid = mutt_strwidth(answer_string);
408  msg_wid = mutt_strwidth(msg);
409 
410  while (true)
411  {
412  if (redraw || SigWinch)
413  {
414  redraw = false;
415  if (SigWinch)
416  {
417  SigWinch = 0;
419  clearok(stdscr, true);
421  }
423  {
424  prompt_lines = (msg_wid + answer_string_wid + MuttMessageWindow->state.cols - 1) /
426  prompt_lines = MAX(1, MIN(3, prompt_lines));
427  }
428  if (prompt_lines != MuttMessageWindow->state.rows)
429  {
430  mutt_window_reflow_message_rows(prompt_lines);
432  }
433 
434  /* maxlen here is sort of arbitrary, so pick a reasonable upper bound */
435  trunc_msg_len = mutt_wstr_trunc(
436  msg, (size_t) 4 * prompt_lines * MuttMessageWindow->state.cols,
437  ((size_t) prompt_lines * MuttMessageWindow->state.cols) - answer_string_wid, NULL);
438 
441  mutt_window_addnstr(msg, trunc_msg_len);
442  mutt_window_addstr(answer_string);
445  }
446 
447  mutt_refresh();
448  /* SigWinch is not processed unless timeout is set */
449  mutt_getch_timeout(30 * 1000);
450  ch = mutt_getch();
451  mutt_getch_timeout(-1);
452  if (ch.ch == -2)
453  continue;
454  if (CI_is_return(ch.ch))
455  break;
456  if (ch.ch < 0)
457  {
458  def = MUTT_ABORT;
459  break;
460  }
461 
462  answer[0] = ch.ch;
463  if (reyes_ok ? (regexec(&reyes, answer, 0, 0, 0) == 0) : (tolower(ch.ch) == 'y'))
464  {
465  def = MUTT_YES;
466  break;
467  }
468  else if (reno_ok ? (regexec(&reno, answer, 0, 0, 0) == 0) : (tolower(ch.ch) == 'n'))
469  {
470  def = MUTT_NO;
471  break;
472  }
473  else
474  {
475  mutt_beep(false);
476  }
477  }
478 
479  FREE(&answer_string);
480 
481  if (reyes_ok)
482  regfree(&reyes);
483  if (reno_ok)
484  regfree(&reno);
485 
486  if (MuttMessageWindow->state.rows == 1)
487  {
489  }
490  else
491  {
494  }
495 
496  if (def == MUTT_ABORT)
497  {
498  /* when the users cancels with ^G, clear the message stored with
499  * mutt_message() so it isn't displayed when the screen is refreshed. */
501  }
502  else
503  {
504  mutt_window_addstr((char *) ((def == MUTT_YES) ? yes : no));
505  mutt_refresh();
506  }
507  return def;
508 }
509 
515 void mutt_query_exit(void)
516 {
517  mutt_flushinp();
519  if (C_Timeout)
520  mutt_getch_timeout(-1); /* restore blocking operation */
521  if (mutt_yesorno(_("Exit NeoMutt?"), MUTT_YES) == MUTT_YES)
522  {
523  mutt_exit(1);
524  }
527  SigInt = 0;
528 }
529 
533 void mutt_show_error(void)
534 {
536  return;
537 
542 }
543 
547 void mutt_endwin(void)
548 {
549  if (OptNoCurses)
550  return;
551 
552  int e = errno;
553 
554  /* at least in some situations (screen + xterm under SuSE11/12) endwin()
555  * doesn't properly flush the screen without an explicit call. */
556  mutt_refresh();
557  endwin();
558 
559  errno = e;
560 }
561 
566 void mutt_perror_debug(const char *s)
567 {
568  char *p = strerror(errno);
569 
570  mutt_debug(LL_DEBUG1, "%s: %s (errno = %d)\n", s, p ? p : "unknown error", errno);
571  mutt_error("%s: %s (errno = %d)", s, p ? p : _("unknown error"), errno);
572 }
573 
580 int mutt_any_key_to_continue(const char *s)
581 {
582  struct termios term;
583  struct termios old;
584 
585  int fd = open("/dev/tty", O_RDONLY);
586  if (fd < 0)
587  return EOF;
588 
589  tcgetattr(fd, &old); // Save the current tty settings
590 
591  term = old;
592  term.c_lflag &= ~(ICANON | ECHO); // Canonical (not line-buffered), don't echo the characters
593  term.c_cc[VMIN] = 1; // Wait for at least one character
594  term.c_cc[VTIME] = 255; // Wait for 25.5s
595  tcsetattr(fd, TCSANOW, &term);
596 
597  if (s)
598  fputs(s, stdout);
599  else
600  fputs(_("Press any key to continue..."), stdout);
601  fflush(stdout);
602 
603  char ch = '\0';
604  // Wait for a character. This might timeout, so loop.
605  while (read(fd, &ch, 1) == 0)
606  ;
607 
608  // Change the tty settings to be non-blocking
609  term.c_cc[VMIN] = 0; // Returning with zero characters is acceptable
610  term.c_cc[VTIME] = 0; // Don't wait
611  tcsetattr(fd, TCSANOW, &term);
612 
613  char buf[64];
614  while (read(fd, buf, sizeof(buf)) > 0) // Mop up any remaining chars
615  ;
616 
617  tcsetattr(fd, TCSANOW, &old); // Restore the previous tty settings
618  close(fd);
619 
620  fputs("\r\n", stdout);
622  return (ch >= 0) ? ch : EOF;
623 }
624 
629 {
630  if (!nc->event_data || !nc->global_data)
631  return -1;
632  if (nc->event_type != NT_CONFIG)
633  return 0;
634 
635  struct EventConfig *ec = nc->event_data;
636  struct MuttWindow *dlg = nc->global_data;
637 
638  if (mutt_str_strcmp(ec->name, "status_on_top") != 0)
639  return 0;
640 
641  struct MuttWindow *win_first = TAILQ_FIRST(&dlg->children);
642  if (!win_first)
643  return -1;
644 
645  if ((C_StatusOnTop && (win_first->type == WT_PAGER)) ||
646  (!C_StatusOnTop && (win_first->type != WT_PAGER)))
647  {
648  // Swap the Index and the IndexBar Windows
649  TAILQ_REMOVE(&dlg->children, win_first, entries);
650  TAILQ_INSERT_TAIL(&dlg->children, win_first, entries);
651  }
652 
653  mutt_window_reflow(dlg);
654  return 0;
655 }
656 
666 int mutt_do_pager(const char *banner, const char *tempfile, PagerFlags do_color,
667  struct Pager *info)
668 {
669  struct Pager info2 = { 0 };
670  if (!info)
671  info = &info2;
672 
673  struct MuttWindow *dlg =
676 #ifdef USE_DEBUG_WINDOW
677  dlg->name = "do-pager";
678 #endif
679  dlg->type = WT_DIALOG;
680  struct MuttWindow *pager =
683  pager->type = WT_PAGER;
684  struct MuttWindow *pbar = mutt_window_new(
686  pbar->type = WT_PAGER_BAR;
687 
688  if (C_StatusOnTop)
689  {
690  mutt_window_add_child(dlg, pbar);
691  mutt_window_add_child(dlg, pager);
692  }
693  else
694  {
695  mutt_window_add_child(dlg, pager);
696  mutt_window_add_child(dlg, pbar);
697  }
698 
700  dialog_push(dlg);
701 
702  info->win_ibar = NULL;
703  info->win_index = NULL;
704  info->win_pbar = pbar;
705  info->win_pager = pager;
706 
707  int rc;
708 
709  if (!C_Pager || (mutt_str_strcmp(C_Pager, "builtin") == 0))
710  rc = mutt_pager(banner, tempfile, do_color, info);
711  else
712  {
713  struct Buffer *cmd = mutt_buffer_pool_get();
714 
715  mutt_endwin();
717  if (mutt_system(mutt_b2s(cmd)) == -1)
718  {
719  mutt_error(_("Error running \"%s\""), mutt_b2s(cmd));
720  rc = -1;
721  }
722  else
723  rc = 0;
724  mutt_file_unlink(tempfile);
726  }
727 
728  dialog_pop();
730  mutt_window_free(&dlg);
731  return rc;
732 }
733 
746 int mutt_buffer_enter_fname_full(const char *prompt, struct Buffer *fname,
747  bool mailbox, bool multiple, char ***files,
748  int *numfiles, SelectFileFlags flags)
749 {
750  struct KeyEvent ch;
751 
754  mutt_window_addstr(_(" ('?' for list): "));
756  if (!mutt_buffer_is_empty(fname))
759  mutt_refresh();
760 
761  do
762  {
763  ch = mutt_getch();
764  } while (ch.ch == -2);
765  if (ch.ch < 0)
766  {
768  return -1;
769  }
770  else if (ch.ch == '?')
771  {
772  mutt_refresh();
773  mutt_buffer_reset(fname);
774 
775  if (flags == MUTT_SEL_NO_FLAGS)
776  flags = MUTT_SEL_FOLDER;
777  if (multiple)
778  flags |= MUTT_SEL_MULTI;
779  if (mailbox)
780  flags |= MUTT_SEL_MAILBOX;
781  mutt_buffer_select_file(fname, flags, files, numfiles);
782  }
783  else
784  {
785  char *pc = mutt_mem_malloc(mutt_str_strlen(prompt) + 3);
786 
787  sprintf(pc, "%s: ", prompt);
788  if (ch.op == OP_NULL)
789  mutt_unget_event(ch.ch, 0);
790  else
791  mutt_unget_event(0, ch.op);
792 
793  mutt_buffer_alloc(fname, 1024);
794  if (mutt_buffer_get_field_full(pc, fname, (mailbox ? MUTT_EFILE : MUTT_FILE) | MUTT_CLEAR,
795  multiple, files, numfiles) != 0)
796  {
797  mutt_buffer_reset(fname);
798  }
799  FREE(&pc);
800  }
801 
802  return 0;
803 }
804 
812 void mutt_unget_event(int ch, int op)
813 {
814  struct KeyEvent tmp;
815 
816  tmp.ch = ch;
817  tmp.op = op;
818 
819  if (UngetCount >= UngetLen)
820  mutt_mem_realloc(&UngetKeyEvents, (UngetLen += 16) * sizeof(struct KeyEvent));
821 
822  UngetKeyEvents[UngetCount++] = tmp;
823 }
824 
831 void mutt_unget_string(const char *s)
832 {
833  const char *p = s + mutt_str_strlen(s) - 1;
834 
835  while (p >= s)
836  {
837  mutt_unget_event((unsigned char) *p--, 0);
838  }
839 }
840 
850 {
851  struct KeyEvent tmp;
852 
853  tmp.ch = ch;
854  tmp.op = op;
855 
857  mutt_mem_realloc(&MacroEvents, (MacroBufferLen += 128) * sizeof(struct KeyEvent));
858 
859  MacroEvents[MacroBufferCount++] = tmp;
860 }
861 
869 {
870  UngetCount = 0;
871  while (MacroBufferCount > 0)
872  {
873  if (MacroEvents[--MacroBufferCount].op == OP_END_COND)
874  return;
875  }
876 }
877 
886 {
887  while (UngetCount > 0)
888  {
889  if (UngetKeyEvents[--UngetCount].op == OP_END_COND)
890  return;
891  }
892 }
893 
897 void mutt_flushinp(void)
898 {
899  UngetCount = 0;
900  MacroBufferCount = 0;
901  flushinp();
902 }
903 
911 int mutt_multi_choice(const char *prompt, const char *letters)
912 {
913  struct KeyEvent ch;
914  int choice;
915  bool redraw = true;
916  int prompt_lines = 1;
917 
918  bool opt_cols = ((Colors->defs[MT_COLOR_OPTIONS] != 0) &&
920 
921  while (true)
922  {
923  if (redraw || SigWinch)
924  {
925  redraw = false;
926  if (SigWinch)
927  {
928  SigWinch = 0;
930  clearok(stdscr, true);
932  }
934  {
935  int width = mutt_strwidth(prompt) + 2; // + '?' + space
936  /* If we're going to colour the options,
937  * make an assumption about the modified prompt size. */
938  if (opt_cols)
939  width -= 2 * mutt_str_strlen(letters);
940 
941  prompt_lines = (width + MuttMessageWindow->state.cols - 1) /
943  prompt_lines = MAX(1, MIN(3, prompt_lines));
944  }
945  if (prompt_lines != MuttMessageWindow->state.rows)
946  {
947  mutt_window_reflow_message_rows(prompt_lines);
949  }
950 
952 
953  if ((Colors->defs[MT_COLOR_OPTIONS] != 0) &&
955  {
956  char *cur = NULL;
957 
958  while ((cur = strchr(prompt, '(')))
959  {
960  // write the part between prompt and cur using MT_COLOR_PROMPT
962  mutt_window_addnstr(prompt, cur - prompt);
963 
964  if (isalnum(cur[1]) && (cur[2] == ')'))
965  {
966  // we have a single letter within parentheses
968  mutt_window_addch(cur[1]);
969  prompt = cur + 3;
970  }
971  else
972  {
973  // we have a parenthesis followed by something else
974  mutt_window_addch(cur[0]);
975  prompt = cur + 1;
976  }
977  }
978  }
979 
981  mutt_window_addstr(prompt);
983 
984  mutt_window_addch(' ');
986  }
987 
988  mutt_refresh();
989  /* SigWinch is not processed unless timeout is set */
990  mutt_getch_timeout(30 * 1000);
991  ch = mutt_getch();
992  mutt_getch_timeout(-1);
993  if (ch.ch == -2)
994  continue;
995  /* (ch.ch == 0) is technically possible. Treat the same as < 0 (abort) */
996  if ((ch.ch <= 0) || CI_is_return(ch.ch))
997  {
998  choice = -1;
999  break;
1000  }
1001  else
1002  {
1003  char *p = strchr(letters, ch.ch);
1004  if (p)
1005  {
1006  choice = p - letters + 1;
1007  break;
1008  }
1009  else if ((ch.ch <= '9') && (ch.ch > '0'))
1010  {
1011  choice = ch.ch - '0';
1012  if (choice <= mutt_str_strlen(letters))
1013  break;
1014  }
1015  }
1016  mutt_beep(false);
1017  }
1018  if (MuttMessageWindow->state.rows == 1)
1019  {
1021  }
1022  else
1023  {
1026  }
1027  mutt_refresh();
1028  return choice;
1029 }
1030 
1037 int mutt_addwch(wchar_t wc)
1038 {
1039  char buf[MB_LEN_MAX * 2];
1040  mbstate_t mbstate;
1041  size_t n1, n2;
1042 
1043  memset(&mbstate, 0, sizeof(mbstate));
1044  if (((n1 = wcrtomb(buf, wc, &mbstate)) == (size_t)(-1)) ||
1045  ((n2 = wcrtomb(buf + n1, 0, &mbstate)) == (size_t)(-1)))
1046  {
1047  return -1; /* ERR */
1048  }
1049  else
1050  {
1051  return mutt_window_addstr(buf);
1052  }
1053 }
1054 
1071 void mutt_simple_format(char *buf, size_t buflen, int min_width, int max_width,
1072  enum FormatJustify justify, char pad_char,
1073  const char *s, size_t n, bool arboreal)
1074 {
1075  wchar_t wc;
1076  int w;
1077  size_t k, k2;
1078  char scratch[MB_LEN_MAX];
1079  mbstate_t mbstate1, mbstate2;
1080  bool escaped = false;
1081 
1082  memset(&mbstate1, 0, sizeof(mbstate1));
1083  memset(&mbstate2, 0, sizeof(mbstate2));
1084  buflen--;
1085  char *p = buf;
1086  for (; n && (k = mbrtowc(&wc, s, n, &mbstate1)); s += k, n -= k)
1087  {
1088  if ((k == (size_t)(-1)) || (k == (size_t)(-2)))
1089  {
1090  if ((k == (size_t)(-1)) && (errno == EILSEQ))
1091  memset(&mbstate1, 0, sizeof(mbstate1));
1092 
1093  k = (k == (size_t)(-1)) ? 1 : n;
1094  wc = ReplacementChar;
1095  }
1096  if (escaped)
1097  {
1098  escaped = false;
1099  w = 0;
1100  }
1101  else if (arboreal && (wc == MUTT_SPECIAL_INDEX))
1102  {
1103  escaped = true;
1104  w = 0;
1105  }
1106  else if (arboreal && (wc < MUTT_TREE_MAX))
1107  {
1108  w = 1; /* hack */
1109  }
1110  else
1111  {
1112 #ifdef HAVE_ISWBLANK
1113  if (iswblank(wc))
1114  wc = ' ';
1115  else
1116 #endif
1117  if (!IsWPrint(wc))
1118  wc = '?';
1119  w = wcwidth(wc);
1120  }
1121  if (w >= 0)
1122  {
1123  if ((w > max_width) || ((k2 = wcrtomb(scratch, wc, &mbstate2)) > buflen))
1124  continue;
1125  min_width -= w;
1126  max_width -= w;
1127  strncpy(p, scratch, k2);
1128  p += k2;
1129  buflen -= k2;
1130  }
1131  }
1132  w = ((int) buflen < min_width) ? buflen : min_width;
1133  if (w <= 0)
1134  *p = '\0';
1135  else if (justify == JUSTIFY_RIGHT) /* right justify */
1136  {
1137  p[w] = '\0';
1138  while (--p >= buf)
1139  p[w] = *p;
1140  while (--w >= 0)
1141  buf[w] = pad_char;
1142  }
1143  else if (justify == JUSTIFY_CENTER) /* center */
1144  {
1145  char *savedp = p;
1146  int half = (w + 1) / 2; /* half of cushion space */
1147 
1148  p[w] = '\0';
1149 
1150  /* move str to center of buffer */
1151  while (--p >= buf)
1152  p[half] = *p;
1153 
1154  /* fill rhs */
1155  p = savedp + half;
1156  while (--w >= half)
1157  *p++ = pad_char;
1158 
1159  /* fill lhs */
1160  while (half--)
1161  buf[half] = pad_char;
1162  }
1163  else /* left justify */
1164  {
1165  while (--w >= 0)
1166  *p++ = pad_char;
1167  *p = '\0';
1168  }
1169 }
1170 
1185 void mutt_format_s_x(char *buf, size_t buflen, const char *prec, const char *s, bool arboreal)
1186 {
1187  enum FormatJustify justify = JUSTIFY_RIGHT;
1188  char *p = NULL;
1189  int min_width;
1190  int max_width = INT_MAX;
1191 
1192  if (*prec == '-')
1193  {
1194  prec++;
1195  justify = JUSTIFY_LEFT;
1196  }
1197  else if (*prec == '=')
1198  {
1199  prec++;
1200  justify = JUSTIFY_CENTER;
1201  }
1202  min_width = strtol(prec, &p, 10);
1203  if (*p == '.')
1204  {
1205  prec = p + 1;
1206  max_width = strtol(prec, &p, 10);
1207  if (p <= prec)
1208  max_width = INT_MAX;
1209  }
1210 
1211  mutt_simple_format(buf, buflen, min_width, max_width, justify, ' ', s,
1212  mutt_str_strlen(s), arboreal);
1213 }
1214 
1222 void mutt_format_s(char *buf, size_t buflen, const char *prec, const char *s)
1223 {
1224  mutt_format_s_x(buf, buflen, prec, s, false);
1225 }
1226 
1234 void mutt_format_s_tree(char *buf, size_t buflen, const char *prec, const char *s)
1235 {
1236  mutt_format_s_x(buf, buflen, prec, s, true);
1237 }
1238 
1244 void mutt_paddstr(int n, const char *s)
1245 {
1246  wchar_t wc;
1247  size_t k;
1248  size_t len = mutt_str_strlen(s);
1249  mbstate_t mbstate;
1250 
1251  memset(&mbstate, 0, sizeof(mbstate));
1252  for (; len && (k = mbrtowc(&wc, s, len, &mbstate)); s += k, len -= k)
1253  {
1254  if ((k == (size_t)(-1)) || (k == (size_t)(-2)))
1255  {
1256  if (k == (size_t)(-1))
1257  memset(&mbstate, 0, sizeof(mbstate));
1258  k = (k == (size_t)(-1)) ? 1 : len;
1259  wc = ReplacementChar;
1260  }
1261  if (!IsWPrint(wc))
1262  wc = '?';
1263  const int w = wcwidth(wc);
1264  if (w >= 0)
1265  {
1266  if (w > n)
1267  break;
1268  mutt_window_addnstr((char *) s, k);
1269  n -= w;
1270  }
1271  }
1272  while (n-- > 0)
1273  mutt_window_addch(' ');
1274 }
1275 
1287 size_t mutt_wstr_trunc(const char *src, size_t maxlen, size_t maxwid, size_t *width)
1288 {
1289  wchar_t wc;
1290  size_t n, w = 0, l = 0, cl;
1291  int cw;
1292  mbstate_t mbstate;
1293 
1294  if (!src)
1295  goto out;
1296 
1297  n = mutt_str_strlen(src);
1298 
1299  memset(&mbstate, 0, sizeof(mbstate));
1300  for (w = 0; n && (cl = mbrtowc(&wc, src, n, &mbstate)); src += cl, n -= cl)
1301  {
1302  if ((cl == (size_t)(-1)) || (cl == (size_t)(-2)))
1303  {
1304  if (cl == (size_t)(-1))
1305  memset(&mbstate, 0, sizeof(mbstate));
1306  cl = (cl == (size_t)(-1)) ? 1 : n;
1307  wc = ReplacementChar;
1308  }
1309  cw = wcwidth(wc);
1310  /* hack because MUTT_TREE symbols aren't turned into characters
1311  * until rendered by print_enriched_string() */
1312  if ((cw < 0) && (src[0] == MUTT_SPECIAL_INDEX))
1313  {
1314  cl = 2; /* skip the index coloring sequence */
1315  cw = 0;
1316  }
1317  else if ((cw < 0) && (cl == 1) && (src[0] != '\0') && (src[0] < MUTT_TREE_MAX))
1318  cw = 1;
1319  else if (cw < 0)
1320  cw = 0; /* unprintable wchar */
1321  if ((cl + l > maxlen) || (cw + w > maxwid))
1322  break;
1323  l += cl;
1324  w += cw;
1325  }
1326 out:
1327  if (width)
1328  *width = w;
1329  return l;
1330 }
1331 
1337 int mutt_strwidth(const char *s)
1338 {
1339  if (!s)
1340  return 0;
1341  return mutt_strnwidth(s, mutt_str_strlen(s));
1342 }
1343 
1350 int mutt_strnwidth(const char *s, size_t n)
1351 {
1352  if (!s)
1353  return 0;
1354 
1355  wchar_t wc;
1356  int w;
1357  size_t k;
1358  mbstate_t mbstate;
1359 
1360  memset(&mbstate, 0, sizeof(mbstate));
1361  for (w = 0; n && (k = mbrtowc(&wc, s, n, &mbstate)); s += k, n -= k)
1362  {
1363  if (*s == MUTT_SPECIAL_INDEX)
1364  {
1365  s += 2; /* skip the index coloring sequence */
1366  k = 0;
1367  continue;
1368  }
1369 
1370  if ((k == (size_t)(-1)) || (k == (size_t)(-2)))
1371  {
1372  if (k == (size_t)(-1))
1373  memset(&mbstate, 0, sizeof(mbstate));
1374  k = (k == (size_t)(-1)) ? 1 : n;
1375  wc = ReplacementChar;
1376  }
1377  if (!IsWPrint(wc))
1378  wc = '?';
1379  w += wcwidth(wc);
1380  }
1381  return w;
1382 }
void mutt_perror_debug(const char *s)
Show the user an &#39;errno&#39; message.
Definition: curs_lib.c:566
WHERE bool C_StatusOnTop
Config: Display the status bar at the top.
Definition: globals.h:252
struct MuttWindow * win_index
Definition: pager.h:74
#define CI_is_return(ch)
Definition: mutt_curses.h:71
Manage keymappings.
Define wrapper functions around Curses/Slang.
void mutt_buffer_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:79
void mutt_window_get_coords(struct MuttWindow *win, int *row, int *col)
Get the cursor position in the Window.
Definition: mutt_window.c:220
Left justify the text.
Definition: curs_lib.h:47
#define MUTT_CLEAR
Clear input if printable character is pressed.
Definition: mutt.h:62
FormatJustify
Alignment for mutt_simple_format()
Definition: curs_lib.h:45
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
#define TAILQ_FIRST(head)
Definition: queue.h:716
#define MIN(a, b)
Definition: memory.h:31
#define IsWPrint(wc)
Definition: mbyte.h:40
Data passed to a notification function.
Definition: observer.h:39
Window management.
GUI miscellaneous curses (window drawing) routines.
uint16_t CompletionFlags
Flags for mutt_enter_string_full(), e.g. MUTT_ALIAS.
Definition: mutt.h:55
Informational message.
Definition: color.h:76
void mutt_buffer_select_file(struct Buffer *file, SelectFileFlags flags, char ***files, int *numfiles)
Let the user select a file.
Definition: browser.c:1185
static struct KeyEvent * MacroEvents
Definition: curs_lib.c:83
Pager Bar containing status info about the Pager.
Definition: mutt_window.h:77
Dialog (nested Windows) displayed to the user.
Definition: mutt_window.h:70
User aborted the question (with Ctrl-G)
Definition: quad.h:38
Window uses all available vertical space.
Definition: mutt_window.h:35
User answered &#39;Yes&#39;, or assume &#39;Yes&#39;.
Definition: quad.h:40
void mutt_push_macro_event(int ch, int op)
Add the character/operation to the macro buffer.
Definition: curs_lib.c:849
static size_t MacroBufferCount
Definition: curs_lib.c:81
WHERE SIG_ATOMIC_VOLATILE_T SigInt
true after SIGINT is received
Definition: globals.h:79
void mutt_curses_set_color(enum ColorId color)
Set the current colour for text.
Definition: mutt_curses.c:55
void dialog_pop(void)
Hide a Window from the user.
Definition: mutt_window.c:628
int * defs
Array of all fixed colours, see enum ColorId.
Definition: color.h:132
void mutt_flushinp(void)
Empty all the keyboard buffers.
Definition: curs_lib.c:897
void mutt_window_clrtoeol(struct MuttWindow *win)
Clear to the end of the line.
Definition: mutt_window.c:134
void mutt_resize_screen(void)
Update NeoMutt&#39;s opinion about the window size (CURSES)
Definition: resize.c:101
NeoMutt Logging.
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
void dialog_push(struct MuttWindow *dlg)
Display a Window to the user.
Definition: mutt_window.c:605
Right justify the text.
Definition: curs_lib.h:49
void mutt_file_unlink(const char *s)
Delete a file, carefully.
Definition: file.c:195
A config-change event.
Definition: subset.h:70
String manipulation buffer.
Definition: buffer.h:33
void mutt_unget_event(int ch, int op)
Return a keystroke to the input buffer.
Definition: curs_lib.c:812
#define _(a)
Definition: message.h:28
WHERE bool OptNoCurses
(pseudo) when sending in batch mode
Definition: options.h:49
int mutt_enter_string_full(char *buf, size_t buflen, int col, CompletionFlags flags, bool multiple, char ***files, int *numfiles, struct EnterState *state)
Ask the user for a string.
Definition: enter.c:177
int op
function op
Definition: keymap.h:63
int ch
raw key pressed
Definition: keymap.h:62
#define MUTT_SEL_NO_FLAGS
No flags are set.
Definition: browser.h:44
WHERE bool OptIgnoreMacroEvents
(pseudo) don&#39;t process macro/push/exec events while set
Definition: options.h:38
A division of the screen.
Definition: mutt_window.h:88
size_t mutt_str_strlen(const char *a)
Calculate the length of a string, safely.
Definition: string.c:689
void mutt_query_exit(void)
Ask the user if they want to leave NeoMutt.
Definition: curs_lib.c:515
An email being displayed.
Definition: pager.h:65
All user-callable functions.
Container for Accounts, Notifications.
Definition: neomutt.h:35
void mutt_sig_allow_interrupt(bool allow)
Allow/disallow Ctrl-C (SIGINT)
Definition: signal.c:238
#define mutt_get_field(field, buf, buflen, complete)
Definition: curs_lib.h:90
Convenience wrapper for the config headers.
void mutt_paddstr(int n, const char *s)
Display a string on screen, padded if necessary.
Definition: curs_lib.c:1244
GUI component for displaying/selecting items from a list.
#define MUTT_SEL_FOLDER
Select a local directory.
Definition: browser.h:47
Hundreds of global variables to back the user variables.
wchar_t ReplacementChar
When a Unicode character can&#39;t be displayed, use this instead.
Definition: charset.c:59
void mutt_window_free(struct MuttWindow **ptr)
Free a Window and its children.
Definition: mutt_window.c:74
static size_t UngetCount
Definition: curs_lib.c:88
void mutt_beep(bool force)
Irritate the user.
Definition: curs_lib.c:98
enum NotifyType event_type
Send: Event type, e.g. NT_ACCOUNT.
Definition: observer.h:41
#define MAX(a, b)
Definition: memory.h:30
size_t dsize
Length of data.
Definition: buffer.h:37
int mutt_window_addnstr(const char *str, int num)
Write a partial string to a Window.
Definition: mutt_window.c:412
void mutt_curses_set_cursor(enum MuttCursorState state)
Set the cursor state.
Definition: mutt_curses.c:76
enum QuadOption mutt_yesorno(const char *msg, enum QuadOption def)
Ask the user a Yes/No question.
Definition: curs_lib.c:378
Many unsorted constants and some structs.
void mutt_flush_macro_to_endcond(void)
Drop a macro from the input buffer.
Definition: curs_lib.c:868
Centre the text.
Definition: curs_lib.h:48
void mutt_window_clearline(struct MuttWindow *win, int row)
Clear a row of a Window.
Definition: mutt_window.c:112
Display a normal cursor.
Definition: mutt_curses.h:81
Convenience wrapper for the core headers.
#define REG_COMP(preg, regex, cflags)
Compile a regular expression.
Definition: regex3.h:52
WHERE SIG_ATOMIC_VOLATILE_T SigWinch
true after SIGWINCH is received
Definition: globals.h:80
Struct to store the cursor position when entering text.
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:113
int mutt_monitor_poll(void)
Check for filesystem changes.
Definition: monitor.c:396
static int mutt_dlg_dopager_observer(struct NotifyCallback *nc)
Listen for config changes affecting the dopager menus - Implements observer_t.
Definition: curs_lib.c:628
void * global_data
Data from notify_observer_add()
Definition: observer.h:44
void mutt_buffer_fix_dptr(struct Buffer *buf)
Move the dptr to end of the Buffer.
Definition: buffer.c:181
Window has a fixed size.
Definition: mutt_window.h:44
Plain text.
Definition: color.h:78
void mutt_mem_realloc(void *ptr, size_t size)
Resize a block of memory on the heap.
Definition: memory.c:114
struct MuttWindow * win_pager
Definition: pager.h:76
#define TAILQ_REMOVE(head, elm, field)
Definition: queue.h:834
int mutt_buffer_enter_fname_full(const char *prompt, struct Buffer *fname, bool mailbox, bool multiple, char ***files, int *numfiles, SelectFileFlags flags)
Ask the user to select a file.
Definition: curs_lib.c:746
void mutt_window_reflow_message_rows(int mw_rows)
Resize the Message Window.
Definition: mutt_window.c:367
Keep our place when entering a string.
Definition: enter_state.h:32
short cols
Number of columns, can be MUTT_WIN_SIZE_UNLIMITED.
Definition: mutt_window.h:58
#define mutt_b2s(buf)
Definition: buffer.h:41
int mutt_multi_choice(const char *prompt, const char *letters)
Offer the user a multiple choice question.
Definition: curs_lib.c:911
void mutt_refresh(void)
Force a refresh of the screen.
Definition: curs_lib.c:107
WHERE bool OptForceRefresh
(pseudo) refresh even during macros
Definition: options.h:37
Prototypes for many functions.
struct WindowState state
Current state of the Window.
Definition: mutt_window.h:93
void mutt_endwin(void)
Shutdown curses/slang.
Definition: curs_lib.c:547
static struct KeyEvent * UngetKeyEvents
Definition: curs_lib.c:90
struct MuttWindow * mutt_window_new(enum MuttWindowOrientation orient, enum MuttWindowSize size, int rows, int cols)
Create a new Window.
Definition: mutt_window.c:56
int mutt_buffer_get_field_full(const char *field, struct Buffer *buf, CompletionFlags complete, bool multiple, char ***files, int *numfiles)
Ask the user for a string.
Definition: curs_lib.c:258
int mutt_strwidth(const char *s)
Measure a string&#39;s width in screen cells.
Definition: curs_lib.c:1337
void mutt_format_s_x(char *buf, size_t buflen, const char *prec, const char *s, bool arboreal)
Format a string like snprintf()
Definition: curs_lib.c:1185
User answered &#39;No&#39;, or assume &#39;No&#39;.
Definition: quad.h:39
#define MUTT_WIN_SIZE_UNLIMITED
Use as much space as possible.
Definition: mutt_window.h:49
short rows
Number of rows, can be MUTT_WIN_SIZE_UNLIMITED.
Definition: mutt_window.h:57
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:90
void mutt_enter_state_free(struct EnterState **ptr)
Free an EnterState.
Definition: enter.c:821
WHERE char ErrorBuf[256]
Copy of the last error message.
Definition: globals.h:45
char * data
Pointer to data.
Definition: buffer.h:35
WHERE short C_Timeout
Config: Time to wait for user input in menus.
Definition: globals.h:152
uint16_t PagerFlags
Flags for mutt_pager(), e.g. MUTT_SHOWFLAT.
Definition: pager.h:42
static int mutt_monitor_getch(void)
Get a character and poll the filesystem monitor.
Definition: curs_lib.c:157
size_t mutt_wstr_trunc(const char *src, size_t maxlen, size_t maxwid, size_t *width)
Work out how to truncate a widechar string.
Definition: curs_lib.c:1287
WHERE bool ErrorBufMessage
true if the last message was an error
Definition: globals.h:44
GUI present the user with a selectable list.
#define TAILQ_INSERT_TAIL(head, elm, field)
Definition: queue.h:802
An event such as a keypress.
Definition: keymap.h:60
struct KeyEvent mutt_getch(void)
Read a character from the input buffer.
Definition: curs_lib.c:188
struct Notify * notify
Notifications handler.
Definition: neomutt.h:37
Definition: color.h:130
Color and attribute parsing.
int mutt_strnwidth(const char *s, size_t n)
Measure a string&#39;s width in screen cells.
Definition: curs_lib.c:1350
#define MUTT_SEL_MULTI
Multi-selection is enabled.
Definition: browser.h:46
keycode_t AbortKey
code of key to abort prompts, normally Ctrl-G
Definition: keymap.c:147
int mutt_window_mvaddstr(struct MuttWindow *win, int row, int col, const char *str)
Move the cursor and write a fixed string to a Window.
Definition: mutt_window.c:292
bool notify_observer_add(struct Notify *notify, observer_t callback, void *global_data)
Add an observer to an object.
Definition: notify.c:153
#define MUTT_FILE
Do file completion.
Definition: mutt.h:58
int mutt_window_move(struct MuttWindow *win, int row, int col)
Move the cursor in a Window.
Definition: mutt_window.c:278
int mutt_get_field_unbuffered(const char *msg, char *buf, size_t buflen, CompletionFlags flags)
Ask the user for a string (ignoring macro buffer)
Definition: curs_lib.c:333
void * event_data
Data from notify_send()
Definition: observer.h:43
void mutt_window_add_child(struct MuttWindow *parent, struct MuttWindow *child)
Add a child to Window.
Definition: mutt_window.c:473
Restore the previous cursor state.
Definition: mutt_curses.h:79
Config has changed.
Definition: notify_type.h:34
#define MUTT_SEL_MAILBOX
Select a mailbox.
Definition: browser.h:45
void mutt_exit(int code)
Leave NeoMutt NOW.
Definition: main.c:137
int mutt_any_key_to_continue(const char *s)
Prompt the user to &#39;press any key&#39; and wait.
Definition: curs_lib.c:580
Window containing paged free-form text.
Definition: mutt_window.h:76
static size_t MacroBufferLen
Definition: curs_lib.c:82
Colour indicator.
Definition: mutt_menu.h:76
GUI display a file/email/help in a viewport with paging.
int mutt_window_addch(int ch)
Write one character to a Window.
Definition: mutt_window.c:400
#define MUTT_EFILE
Do file completion, plus incoming folders.
Definition: mutt.h:59
void mutt_format_s(char *buf, size_t buflen, const char *prec, const char *s)
Format a simple string.
Definition: curs_lib.c:1222
Error message.
Definition: color.h:71
Log at debug level 1.
Definition: logging.h:40
int n
Definition: acutest.h:477
int mutt_do_pager(const char *banner, const char *tempfile, PagerFlags do_color, struct Pager *info)
Display some page-able text to the user.
Definition: curs_lib.c:666
void mutt_window_reflow(struct MuttWindow *win)
Resize a Window and its children.
Definition: mutt_window.c:345
#define mutt_error(...)
Definition: logging.h:84
void mutt_flush_unget_to_endcond(void)
Clear entries from UngetKeyEvents.
Definition: curs_lib.c:885
void mutt_getch_timeout(int delay)
Set the getch() timeout.
Definition: curs_lib.c:145
void mutt_buffer_file_expand_fmt_quote(struct Buffer *dest, const char *fmt, const char *src)
Replace s in a string with a filename.
Definition: file.c:1426
#define FREE(x)
Definition: memory.h:40
WHERE bool OptMsgErr
(pseudo) used by mutt_error/mutt_message
Definition: options.h:42
WHERE bool C_Beep
Config: Make a noise when an error occurs.
Definition: globals.h:205
Monitor files for changes.
struct MuttWindowList children
Children Windows.
Definition: mutt_window.h:101
#define EILSEQ
Definition: charset.c:50
void mutt_unget_string(const char *s)
Return a string to the input buffer.
Definition: curs_lib.c:831
bool notify_observer_remove(struct Notify *notify, observer_t callback, void *global_data)
Remove an observer from an object.
Definition: notify.c:185
void mutt_show_error(void)
Show the user an error message.
Definition: curs_lib.c:533
struct MuttWindow * win_ibar
Definition: pager.h:73
WHERE char * C_Pager
Config: External command for viewing messages, or &#39;builtin&#39; to use NeoMutt&#39;s.
Definition: globals.h:133
struct MuttWindow * MuttMessageWindow
Message Window.
Definition: mutt_window.c:46
int mutt_window_addstr(const char *str)
Write a string to a Window.
Definition: mutt_window.c:430
struct EnterState * mutt_enter_state_new(void)
Create a new EnterState.
Definition: enter.c:126
Options in prompt.
Definition: color.h:79
Handling of global boolean variables.
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
int const char * file
Definition: acutest.h:602
int mutt_str_asprintf(char **strp, const char *fmt,...)
Definition: string.c:1217
int mutt_pager(const char *banner, const char *fname, PagerFlags flags, struct Pager *extra)
Display a file, or help, in a window.
Definition: pager.c:2206
Convenience wrapper for the library headers.
Window wants as much space as possible.
Definition: mutt_window.h:45
WHERE bool OptKeepQuiet
(pseudo) shut up the message and refresh functions while we are executing an external program ...
Definition: options.h:39
bool mutt_buffer_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:252
void mutt_need_hard_redraw(void)
Force a hard refresh.
Definition: curs_lib.c:129
enum WindowType type
Window type, e.g. WT_SIDEBAR.
Definition: mutt_window.h:103
const char * name
Name of config item that changed.
Definition: subset.h:73
void mutt_edit_file(const char *editor, const char *file)
Let the user edit a file.
Definition: curs_lib.c:354
bool C_MetaKey
Config: Interpret &#39;ALT-x&#39; as &#39;ESC-x&#39;.
Definition: curs_lib.c:71
int mutt_str_strcmp(const char *a, const char *b)
Compare two strings, safely.
Definition: string.c:638
int mutt_system(const char *cmd)
Run an external command.
Definition: system.c:51
QuadOption
Possible values for a quad-option.
Definition: quad.h:36
Question/user input.
Definition: color.h:81
int MuttGetchTimeout
Timeout in ms for mutt_getch()
Definition: curs_lib.c:92
void mutt_format_s_tree(char *buf, size_t buflen, const char *prec, const char *s)
Format a simple string with tree characters.
Definition: curs_lib.c:1234
static size_t UngetLen
Definition: curs_lib.c:89
void mutt_simple_format(char *buf, size_t buflen, int min_width, int max_width, enum FormatJustify justify, char pad_char, const char *s, size_t n, bool arboreal)
Format a string, like snprintf()
Definition: curs_lib.c:1071
int mutt_addwch(wchar_t wc)
addwch would be provided by an up-to-date curses library
Definition: curs_lib.c:1037
void mutt_buffer_alloc(struct Buffer *buf, size_t new_size)
Make sure a buffer can store at least new_size bytes.
Definition: buffer.c:265
int mutt_get_field_full(const char *field, char *buf, size_t buflen, CompletionFlags complete, bool multiple, char ***files, int *numfiles)
Ask the user for a string.
Definition: curs_lib.c:309
struct MuttWindow * win_pbar
Definition: pager.h:75
uint8_t SelectFileFlags
Flags for mutt_select_file(), e.g. MUTT_SEL_MAILBOX.
Definition: browser.h:43