NeoMutt  2020-11-20
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 <stdbool.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <termios.h>
42 #include <unistd.h>
43 #include <wchar.h>
44 #include "mutt/lib.h"
45 #include "config/lib.h"
46 #include "core/lib.h"
47 #include "mutt.h"
48 #include "curs_lib.h"
49 #include "browser.h"
50 #include "color.h"
51 #include "dialog.h"
52 #include "enter_state.h"
53 #include "keymap.h"
54 #include "mutt_curses.h"
55 #include "mutt_globals.h"
56 #include "mutt_logging.h"
57 #include "mutt_menu.h"
58 #include "mutt_thread.h"
59 #include "mutt_window.h"
60 #include "opcodes.h"
61 #include "options.h"
62 #include "pager.h"
63 #include "protos.h"
64 #ifdef HAVE_ISWBLANK
65 #include <wctype.h>
66 #endif
67 #ifdef USE_INOTIFY
68 #include "monitor.h"
69 #endif
70 
71 /* These Config Variables are only used in curs_lib.c */
72 bool C_MetaKey;
73 
74 /* not possible to unget more than one char under some curses libs, and it
75  * is impossible to unget function keys in SLang, so roll our own input
76  * buffering routines.
77  */
78 
79 /* These are used for macros and exec/push commands.
80  * They can be temporarily ignored by setting OptIgnoreMacroEvents
81  */
82 static size_t MacroBufferCount = 0;
83 static size_t MacroBufferLen = 0;
84 static struct KeyEvent *MacroEvents;
85 
86 /* These are used in all other "normal" situations, and are not
87  * ignored when setting OptIgnoreMacroEvents
88  */
89 static size_t UngetCount = 0;
90 static size_t UngetLen = 0;
91 static struct KeyEvent *UngetKeyEvents;
92 
94 
99 void mutt_beep(bool force)
100 {
101  if (force || C_Beep)
102  beep();
103 }
104 
108 void mutt_refresh(void)
109 {
110  /* don't refresh when we are waiting for a child. */
111  if (OptKeepQuiet)
112  return;
113 
114  /* don't refresh in the middle of macros unless necessary */
116  return;
117 
118  /* else */
119  refresh();
120 }
121 
131 {
132  keypad(stdscr, true);
133  clearok(stdscr, true);
135 }
136 
146 void mutt_getch_timeout(int delay)
147 {
148  MuttGetchTimeout = delay;
149  timeout(delay);
150 }
151 
152 #ifdef USE_INOTIFY
153 
158 static int mutt_monitor_getch(void)
159 {
160  /* ncurses has its own internal buffer, so before we perform a poll,
161  * we need to make sure there isn't a character waiting */
162  timeout(0);
163  int ch = getch();
164  timeout(MuttGetchTimeout);
165  if (ch == ERR)
166  {
167  if (mutt_monitor_poll() != 0)
168  ch = ERR;
169  else
170  ch = getch();
171  }
172  return ch;
173 }
174 #endif /* USE_INOTIFY */
175 
189 struct KeyEvent mutt_getch(void)
190 {
191  int ch;
192  struct KeyEvent err = { -1, OP_NULL }, ret;
193  struct KeyEvent timeout = { -2, OP_NULL };
194 
195  if (UngetCount)
196  return UngetKeyEvents[--UngetCount];
197 
199  return MacroEvents[--MacroBufferCount];
200 
201  SigInt = 0;
202 
204 #ifdef KEY_RESIZE
205  /* ncurses 4.2 sends this when the screen is resized */
206  ch = KEY_RESIZE;
207  while (ch == KEY_RESIZE)
208 #endif /* KEY_RESIZE */
209 #ifdef USE_INOTIFY
210  ch = mutt_monitor_getch();
211 #else
212  ch = getch();
213 #endif /* USE_INOTIFY */
215 
216  if (SigInt)
217  {
218  mutt_query_exit();
219  return err;
220  }
221 
222  /* either timeout, a sigwinch (if timeout is set), or the terminal
223  * has been lost */
224  if (ch == ERR)
225  {
226  if (!isatty(0))
227  mutt_exit(1);
228 
229  return timeout;
230  }
231 
232  if ((ch & 0x80) && C_MetaKey)
233  {
234  /* send ALT-x as ESC-x */
235  ch &= ~0x80;
236  mutt_unget_event(ch, 0);
237  ret.ch = '\033'; // Escape
238  ret.op = 0;
239  return ret;
240  }
241 
242  ret.ch = ch;
243  ret.op = 0;
244  return (ch == AbortKey) ? err : ret;
245 }
246 
259 int mutt_buffer_get_field_full(const char *field, struct Buffer *buf, CompletionFlags complete,
260  bool multiple, char ***files, int *numfiles)
261 {
262  int ret;
263  int col;
264 
265  struct EnterState *es = mutt_enter_state_new();
266 
267  do
268  {
269  if (SigWinch)
270  {
271  SigWinch = 0;
273  clearok(stdscr, true);
275  }
278  mutt_window_addstr(field);
280  mutt_refresh();
282  ret = mutt_enter_string_full(buf->data, buf->dsize, col, complete, multiple,
283  files, numfiles, es);
284  } while (ret == 1);
285 
286  if (ret == 0)
288  else
289  mutt_buffer_reset(buf);
290 
293 
294  return ret;
295 }
296 
310 int mutt_get_field_full(const char *field, char *buf, size_t buflen, CompletionFlags complete,
311  bool multiple, char ***files, int *numfiles)
312 {
313  if (!buf)
314  return -1;
315 
316  struct Buffer tmp = {
317  .data = buf,
318  .dptr = buf + mutt_str_len(buf),
319  .dsize = buflen,
320  };
321  return mutt_buffer_get_field_full(field, &tmp, complete, multiple, files, numfiles);
322 }
323 
334 int mutt_get_field_unbuffered(const char *msg, char *buf, size_t buflen, CompletionFlags flags)
335 {
336  bool reset_ignoremacro = false;
337 
339  {
340  OptIgnoreMacroEvents = true;
341  reset_ignoremacro = true;
342  }
343  int rc = mutt_get_field(msg, buf, buflen, flags);
344  if (reset_ignoremacro)
345  OptIgnoreMacroEvents = false;
346 
347  return rc;
348 }
349 
355 void mutt_edit_file(const char *editor, const char *file)
356 {
357  struct Buffer *cmd = mutt_buffer_pool_get();
358 
359  mutt_endwin();
360  mutt_buffer_file_expand_fmt_quote(cmd, editor, file);
361  if (mutt_system(mutt_b2s(cmd)) != 0)
362  {
363  mutt_error(_("Error running \"%s\""), mutt_b2s(cmd));
364  }
365  /* the terminal may have been resized while the editor owned it */
367  keypad(stdscr, true);
368  clearok(stdscr, true);
369 
371 }
372 
379 enum QuadOption mutt_yesorno(const char *msg, enum QuadOption def)
380 {
381  struct KeyEvent ch;
382  char *yes = _("yes");
383  char *no = _("no");
384  char *answer_string = NULL;
385  int answer_string_wid, msg_wid;
386  size_t trunc_msg_len;
387  bool redraw = true;
388  int prompt_lines = 1;
389 
390  char *expr = NULL;
391  regex_t reyes;
392  regex_t reno;
393  char answer[2];
394 
395  answer[1] = '\0';
396 
397  bool reyes_ok = (expr = nl_langinfo(YESEXPR)) && (expr[0] == '^') &&
398  (REG_COMP(&reyes, expr, REG_NOSUB) == 0);
399  bool reno_ok = (expr = nl_langinfo(NOEXPR)) && (expr[0] == '^') &&
400  (REG_COMP(&reno, expr, REG_NOSUB) == 0);
401 
402  /* In order to prevent the default answer to the question to wrapped
403  * around the screen in the even the question is wider than the screen,
404  * ensure there is enough room for the answer and truncate the question
405  * to fit. */
406  mutt_str_asprintf(&answer_string, " ([%s]/%s): ", (def == MUTT_YES) ? yes : no,
407  (def == MUTT_YES) ? no : yes);
408  answer_string_wid = mutt_strwidth(answer_string);
409  msg_wid = mutt_strwidth(msg);
410 
411  while (true)
412  {
413  if (redraw || SigWinch)
414  {
415  redraw = false;
416  if (SigWinch)
417  {
418  SigWinch = 0;
420  clearok(stdscr, true);
422  }
423  if (MessageWindow->state.cols)
424  {
425  prompt_lines = (msg_wid + answer_string_wid + MessageWindow->state.cols - 1) /
427  prompt_lines = MAX(1, MIN(3, prompt_lines));
428  }
429  if (prompt_lines != MessageWindow->state.rows)
430  {
431  mutt_window_reflow_message_rows(prompt_lines);
433  }
434 
435  /* maxlen here is sort of arbitrary, so pick a reasonable upper bound */
436  trunc_msg_len = mutt_wstr_trunc(
437  msg, (size_t) 4 * prompt_lines * MessageWindow->state.cols,
438  ((size_t) prompt_lines * MessageWindow->state.cols) - answer_string_wid, NULL);
439 
442  mutt_window_addnstr(msg, trunc_msg_len);
443  mutt_window_addstr(answer_string);
446  }
447 
448  mutt_refresh();
449  /* SigWinch is not processed unless timeout is set */
450  mutt_getch_timeout(30 * 1000);
451  ch = mutt_getch();
452  mutt_getch_timeout(-1);
453  if (ch.ch == -2)
454  continue;
455  if (CI_is_return(ch.ch))
456  break;
457  if (ch.ch < 0)
458  {
459  def = MUTT_ABORT;
460  break;
461  }
462 
463  answer[0] = ch.ch;
464  if (reyes_ok ? (regexec(&reyes, answer, 0, 0, 0) == 0) : (tolower(ch.ch) == 'y'))
465  {
466  def = MUTT_YES;
467  break;
468  }
469  else if (reno_ok ? (regexec(&reno, answer, 0, 0, 0) == 0) : (tolower(ch.ch) == 'n'))
470  {
471  def = MUTT_NO;
472  break;
473  }
474  else
475  {
476  mutt_beep(false);
477  }
478  }
479 
480  FREE(&answer_string);
481 
482  if (reyes_ok)
483  regfree(&reyes);
484  if (reno_ok)
485  regfree(&reno);
486 
487  if (MessageWindow->state.rows == 1)
488  {
490  }
491  else
492  {
495  }
496 
497  if (def == MUTT_ABORT)
498  {
499  /* when the users cancels with ^G, clear the message stored with
500  * mutt_message() so it isn't displayed when the screen is refreshed. */
502  }
503  else
504  {
505  mutt_window_addstr((char *) ((def == MUTT_YES) ? yes : no));
506  mutt_refresh();
507  }
508  return def;
509 }
510 
517 enum QuadOption query_quadoption(enum QuadOption opt, const char *prompt)
518 {
519  switch (opt)
520  {
521  case MUTT_YES:
522  case MUTT_NO:
523  return opt;
524 
525  default:
526  opt = mutt_yesorno(prompt, (opt == MUTT_ASKYES) ? MUTT_YES : MUTT_NO);
528  return opt;
529  }
530 
531  /* not reached */
532 }
533 
539 void mutt_query_exit(void)
540 {
541  mutt_flushinp();
543  if (C_Timeout)
544  mutt_getch_timeout(-1); /* restore blocking operation */
545  if (mutt_yesorno(_("Exit NeoMutt?"), MUTT_YES) == MUTT_YES)
546  {
547  mutt_exit(1);
548  }
551  SigInt = 0;
552 }
553 
557 void mutt_show_error(void)
558 {
560  return;
561 
566 }
567 
571 void mutt_endwin(void)
572 {
573  if (OptNoCurses)
574  return;
575 
576  int e = errno;
577 
578  /* at least in some situations (screen + xterm under SuSE11/12) endwin()
579  * doesn't properly flush the screen without an explicit call. */
580  mutt_refresh();
581  endwin();
582 
583  errno = e;
584 }
585 
590 void mutt_perror_debug(const char *s)
591 {
592  char *p = strerror(errno);
593 
594  mutt_debug(LL_DEBUG1, "%s: %s (errno = %d)\n", s, p ? p : "unknown error", errno);
595  mutt_error("%s: %s (errno = %d)", s, p ? p : _("unknown error"), errno);
596 }
597 
604 int mutt_any_key_to_continue(const char *s)
605 {
606  struct termios term;
607  struct termios old;
608 
609  int fd = open("/dev/tty", O_RDONLY);
610  if (fd < 0)
611  return EOF;
612 
613  tcgetattr(fd, &old); // Save the current tty settings
614 
615  term = old;
616  term.c_lflag &= ~(ICANON | ECHO); // Canonical (not line-buffered), don't echo the characters
617  term.c_cc[VMIN] = 1; // Wait for at least one character
618  term.c_cc[VTIME] = 255; // Wait for 25.5s
619  tcsetattr(fd, TCSANOW, &term);
620 
621  if (s)
622  fputs(s, stdout);
623  else
624  fputs(_("Press any key to continue..."), stdout);
625  fflush(stdout);
626 
627  char ch = '\0';
628  // Wait for a character. This might timeout, so loop.
629  while (read(fd, &ch, 1) == 0)
630  ; // do nothing
631 
632  // Change the tty settings to be non-blocking
633  term.c_cc[VMIN] = 0; // Returning with zero characters is acceptable
634  term.c_cc[VTIME] = 0; // Don't wait
635  tcsetattr(fd, TCSANOW, &term);
636 
637  char buf[64];
638  while (read(fd, buf, sizeof(buf)) > 0)
639  ; // Mop up any remaining chars
640 
641  tcsetattr(fd, TCSANOW, &old); // Restore the previous tty settings
642  close(fd);
643 
644  fputs("\r\n", stdout);
646  return (ch >= 0) ? ch : EOF;
647 }
648 
653 {
654  if (!nc->event_data || !nc->global_data)
655  return -1;
656  if (nc->event_type != NT_CONFIG)
657  return 0;
658 
659  struct EventConfig *ec = nc->event_data;
660  struct MuttWindow *dlg = nc->global_data;
661 
662  if (!mutt_str_equal(ec->name, "status_on_top"))
663  return 0;
664 
665  struct MuttWindow *win_first = TAILQ_FIRST(&dlg->children);
666  if (!win_first)
667  return -1;
668 
669  if ((C_StatusOnTop && (win_first->type == WT_PAGER)) ||
670  (!C_StatusOnTop && (win_first->type != WT_PAGER)))
671  {
672  // Swap the Index and the IndexBar Windows
673  TAILQ_REMOVE(&dlg->children, win_first, entries);
674  TAILQ_INSERT_TAIL(&dlg->children, win_first, entries);
675  }
676 
677  mutt_window_reflow(dlg);
678  return 0;
679 }
680 
690 int mutt_do_pager(const char *banner, const char *tempfile, PagerFlags do_color,
691  struct Pager *info)
692 {
693  struct Pager info2 = { 0 };
694  if (!info)
695  info = &info2;
696 
697  struct MuttWindow *dlg =
700 
701  struct MuttWindow *pager =
704  dlg->focus = pager;
705 
706  struct MuttWindow *pbar =
709 
710  if (C_StatusOnTop)
711  {
712  mutt_window_add_child(dlg, pbar);
713  mutt_window_add_child(dlg, pager);
714  }
715  else
716  {
717  mutt_window_add_child(dlg, pager);
718  mutt_window_add_child(dlg, pbar);
719  }
720 
722  dialog_push(dlg);
723 
724  info->win_ibar = NULL;
725  info->win_index = NULL;
726  info->win_pbar = pbar;
727  info->win_pager = pager;
728 
729  int rc;
730 
731  if (!C_Pager || mutt_str_equal(C_Pager, "builtin"))
732  rc = mutt_pager(banner, tempfile, do_color, info);
733  else
734  {
735  struct Buffer *cmd = mutt_buffer_pool_get();
736 
737  mutt_endwin();
739  if (mutt_system(mutt_b2s(cmd)) == -1)
740  {
741  mutt_error(_("Error running \"%s\""), mutt_b2s(cmd));
742  rc = -1;
743  }
744  else
745  rc = 0;
746  mutt_file_unlink(tempfile);
748  }
749 
750  dialog_pop();
752  mutt_window_free(&dlg);
753  return rc;
754 }
755 
768 int mutt_buffer_enter_fname_full(const char *prompt, struct Buffer *fname,
769  bool mailbox, bool multiple, char ***files,
770  int *numfiles, SelectFileFlags flags)
771 {
772  struct KeyEvent ch;
773 
775  mutt_window_mvaddstr(MessageWindow, 0, 0, prompt);
776  mutt_window_addstr(_(" ('?' for list): "));
778  if (!mutt_buffer_is_empty(fname))
781  mutt_refresh();
782 
783  do
784  {
785  ch = mutt_getch();
786  } while (ch.ch == -2);
787  if (ch.ch < 0)
788  {
790  return -1;
791  }
792  else if (ch.ch == '?')
793  {
794  mutt_refresh();
795  mutt_buffer_reset(fname);
796 
797  if (flags == MUTT_SEL_NO_FLAGS)
798  flags = MUTT_SEL_FOLDER;
799  if (multiple)
800  flags |= MUTT_SEL_MULTI;
801  if (mailbox)
802  flags |= MUTT_SEL_MAILBOX;
803  mutt_buffer_select_file(fname, flags, files, numfiles);
804  }
805  else
806  {
807  char *pc = mutt_mem_malloc(mutt_str_len(prompt) + 3);
808 
809  sprintf(pc, "%s: ", prompt);
810  if (ch.op == OP_NULL)
811  mutt_unget_event(ch.ch, 0);
812  else
813  mutt_unget_event(0, ch.op);
814 
815  mutt_buffer_alloc(fname, 1024);
816  if (mutt_buffer_get_field_full(pc, fname, (mailbox ? MUTT_EFILE : MUTT_FILE) | MUTT_CLEAR,
817  multiple, files, numfiles) != 0)
818  {
819  mutt_buffer_reset(fname);
820  }
821  FREE(&pc);
822  }
823 
824  return 0;
825 }
826 
834 void mutt_unget_event(int ch, int op)
835 {
836  struct KeyEvent tmp;
837 
838  tmp.ch = ch;
839  tmp.op = op;
840 
841  if (UngetCount >= UngetLen)
842  mutt_mem_realloc(&UngetKeyEvents, (UngetLen += 16) * sizeof(struct KeyEvent));
843 
844  UngetKeyEvents[UngetCount++] = tmp;
845 }
846 
853 void mutt_unget_string(const char *s)
854 {
855  const char *p = s + mutt_str_len(s) - 1;
856 
857  while (p >= s)
858  {
859  mutt_unget_event((unsigned char) *p--, 0);
860  }
861 }
862 
872 {
873  struct KeyEvent tmp;
874 
875  tmp.ch = ch;
876  tmp.op = op;
877 
879  mutt_mem_realloc(&MacroEvents, (MacroBufferLen += 128) * sizeof(struct KeyEvent));
880 
881  MacroEvents[MacroBufferCount++] = tmp;
882 }
883 
891 {
892  UngetCount = 0;
893  while (MacroBufferCount > 0)
894  {
895  if (MacroEvents[--MacroBufferCount].op == OP_END_COND)
896  return;
897  }
898 }
899 
908 {
909  while (UngetCount > 0)
910  {
911  if (UngetKeyEvents[--UngetCount].op == OP_END_COND)
912  return;
913  }
914 }
915 
919 void mutt_flushinp(void)
920 {
921  UngetCount = 0;
922  MacroBufferCount = 0;
923  flushinp();
924 }
925 
933 int mutt_multi_choice(const char *prompt, const char *letters)
934 {
935  struct KeyEvent ch;
936  int choice;
937  bool redraw = true;
938  int prompt_lines = 1;
939 
940  bool opt_cols = ((Colors->defs[MT_COLOR_OPTIONS] != 0) &&
942 
943  while (true)
944  {
945  if (redraw || SigWinch)
946  {
947  redraw = false;
948  if (SigWinch)
949  {
950  SigWinch = 0;
952  clearok(stdscr, true);
954  }
955  if (MessageWindow->state.cols)
956  {
957  int width = mutt_strwidth(prompt) + 2; // + '?' + space
958  /* If we're going to colour the options,
959  * make an assumption about the modified prompt size. */
960  if (opt_cols)
961  width -= 2 * mutt_str_len(letters);
962 
963  prompt_lines =
964  (width + MessageWindow->state.cols - 1) / MessageWindow->state.cols;
965  prompt_lines = MAX(1, MIN(3, prompt_lines));
966  }
967  if (prompt_lines != MessageWindow->state.rows)
968  {
969  mutt_window_reflow_message_rows(prompt_lines);
971  }
972 
974 
975  if ((Colors->defs[MT_COLOR_OPTIONS] != 0) &&
977  {
978  char *cur = NULL;
979 
980  while ((cur = strchr(prompt, '(')))
981  {
982  // write the part between prompt and cur using MT_COLOR_PROMPT
984  mutt_window_addnstr(prompt, cur - prompt);
985 
986  if (isalnum(cur[1]) && (cur[2] == ')'))
987  {
988  // we have a single letter within parentheses
990  mutt_window_addch(cur[1]);
991  prompt = cur + 3;
992  }
993  else
994  {
995  // we have a parenthesis followed by something else
996  mutt_window_addch(cur[0]);
997  prompt = cur + 1;
998  }
999  }
1000  }
1001 
1003  mutt_window_addstr(prompt);
1005 
1006  mutt_window_addch(' ');
1008  }
1009 
1010  mutt_refresh();
1011  /* SigWinch is not processed unless timeout is set */
1012  mutt_getch_timeout(30 * 1000);
1013  ch = mutt_getch();
1014  mutt_getch_timeout(-1);
1015  if (ch.ch == -2)
1016  continue;
1017  /* (ch.ch == 0) is technically possible. Treat the same as < 0 (abort) */
1018  if ((ch.ch <= 0) || CI_is_return(ch.ch))
1019  {
1020  choice = -1;
1021  break;
1022  }
1023  else
1024  {
1025  char *p = strchr(letters, ch.ch);
1026  if (p)
1027  {
1028  choice = p - letters + 1;
1029  break;
1030  }
1031  else if ((ch.ch <= '9') && (ch.ch > '0'))
1032  {
1033  choice = ch.ch - '0';
1034  if (choice <= mutt_str_len(letters))
1035  break;
1036  }
1037  }
1038  mutt_beep(false);
1039  }
1040  if (MessageWindow->state.rows == 1)
1041  {
1043  }
1044  else
1045  {
1048  }
1049  mutt_refresh();
1050  return choice;
1051 }
1052 
1059 int mutt_addwch(wchar_t wc)
1060 {
1061  char buf[MB_LEN_MAX * 2];
1062  mbstate_t mbstate;
1063  size_t n1, n2;
1064 
1065  memset(&mbstate, 0, sizeof(mbstate));
1066  if (((n1 = wcrtomb(buf, wc, &mbstate)) == (size_t)(-1)) ||
1067  ((n2 = wcrtomb(buf + n1, 0, &mbstate)) == (size_t)(-1)))
1068  {
1069  return -1; /* ERR */
1070  }
1071  else
1072  {
1073  return mutt_window_addstr(buf);
1074  }
1075 }
1076 
1093 void mutt_simple_format(char *buf, size_t buflen, int min_width, int max_width,
1094  enum FormatJustify justify, char pad_char,
1095  const char *s, size_t n, bool arboreal)
1096 {
1097  wchar_t wc;
1098  int w;
1099  size_t k, k2;
1100  char scratch[MB_LEN_MAX];
1101  mbstate_t mbstate1, mbstate2;
1102  bool escaped = false;
1103 
1104  memset(&mbstate1, 0, sizeof(mbstate1));
1105  memset(&mbstate2, 0, sizeof(mbstate2));
1106  buflen--;
1107  char *p = buf;
1108  for (; n && (k = mbrtowc(&wc, s, n, &mbstate1)); s += k, n -= k)
1109  {
1110  if ((k == (size_t)(-1)) || (k == (size_t)(-2)))
1111  {
1112  if ((k == (size_t)(-1)) && (errno == EILSEQ))
1113  memset(&mbstate1, 0, sizeof(mbstate1));
1114 
1115  k = (k == (size_t)(-1)) ? 1 : n;
1116  wc = ReplacementChar;
1117  }
1118  if (escaped)
1119  {
1120  escaped = false;
1121  w = 0;
1122  }
1123  else if (arboreal && (wc == MUTT_SPECIAL_INDEX))
1124  {
1125  escaped = true;
1126  w = 0;
1127  }
1128  else if (arboreal && (wc < MUTT_TREE_MAX))
1129  {
1130  w = 1; /* hack */
1131  }
1132  else
1133  {
1134 #ifdef HAVE_ISWBLANK
1135  if (iswblank(wc))
1136  wc = ' ';
1137  else
1138 #endif
1139  if (!IsWPrint(wc))
1140  wc = '?';
1141  w = wcwidth(wc);
1142  }
1143  if (w >= 0)
1144  {
1145  if ((w > max_width) || ((k2 = wcrtomb(scratch, wc, &mbstate2)) > buflen))
1146  continue;
1147  min_width -= w;
1148  max_width -= w;
1149  strncpy(p, scratch, k2);
1150  p += k2;
1151  buflen -= k2;
1152  }
1153  }
1154  w = ((int) buflen < min_width) ? buflen : min_width;
1155  if (w <= 0)
1156  *p = '\0';
1157  else if (justify == JUSTIFY_RIGHT) /* right justify */
1158  {
1159  p[w] = '\0';
1160  while (--p >= buf)
1161  p[w] = *p;
1162  while (--w >= 0)
1163  buf[w] = pad_char;
1164  }
1165  else if (justify == JUSTIFY_CENTER) /* center */
1166  {
1167  char *savedp = p;
1168  int half = (w + 1) / 2; /* half of cushion space */
1169 
1170  p[w] = '\0';
1171 
1172  /* move str to center of buffer */
1173  while (--p >= buf)
1174  p[half] = *p;
1175 
1176  /* fill rhs */
1177  p = savedp + half;
1178  while (--w >= half)
1179  *p++ = pad_char;
1180 
1181  /* fill lhs */
1182  while (half--)
1183  buf[half] = pad_char;
1184  }
1185  else /* left justify */
1186  {
1187  while (--w >= 0)
1188  *p++ = pad_char;
1189  *p = '\0';
1190  }
1191 }
1192 
1207 void mutt_format_s_x(char *buf, size_t buflen, const char *prec, const char *s, bool arboreal)
1208 {
1209  enum FormatJustify justify = JUSTIFY_RIGHT;
1210  char *p = NULL;
1211  int min_width;
1212  int max_width = INT_MAX;
1213 
1214  if (*prec == '-')
1215  {
1216  prec++;
1217  justify = JUSTIFY_LEFT;
1218  }
1219  else if (*prec == '=')
1220  {
1221  prec++;
1222  justify = JUSTIFY_CENTER;
1223  }
1224  min_width = strtol(prec, &p, 10);
1225  if (*p == '.')
1226  {
1227  prec = p + 1;
1228  max_width = strtol(prec, &p, 10);
1229  if (p <= prec)
1230  max_width = INT_MAX;
1231  }
1232 
1233  mutt_simple_format(buf, buflen, min_width, max_width, justify, ' ', s,
1234  mutt_str_len(s), arboreal);
1235 }
1236 
1244 void mutt_format_s(char *buf, size_t buflen, const char *prec, const char *s)
1245 {
1246  mutt_format_s_x(buf, buflen, prec, s, false);
1247 }
1248 
1256 void mutt_format_s_tree(char *buf, size_t buflen, const char *prec, const char *s)
1257 {
1258  mutt_format_s_x(buf, buflen, prec, s, true);
1259 }
1260 
1266 void mutt_paddstr(int n, const char *s)
1267 {
1268  wchar_t wc;
1269  size_t k;
1270  size_t len = mutt_str_len(s);
1271  mbstate_t mbstate;
1272 
1273  memset(&mbstate, 0, sizeof(mbstate));
1274  for (; len && (k = mbrtowc(&wc, s, len, &mbstate)); s += k, len -= k)
1275  {
1276  if ((k == (size_t)(-1)) || (k == (size_t)(-2)))
1277  {
1278  if (k == (size_t)(-1))
1279  memset(&mbstate, 0, sizeof(mbstate));
1280  k = (k == (size_t)(-1)) ? 1 : len;
1281  wc = ReplacementChar;
1282  }
1283  if (!IsWPrint(wc))
1284  wc = '?';
1285  const int w = wcwidth(wc);
1286  if (w >= 0)
1287  {
1288  if (w > n)
1289  break;
1290  mutt_window_addnstr((char *) s, k);
1291  n -= w;
1292  }
1293  }
1294  while (n-- > 0)
1295  mutt_window_addch(' ');
1296 }
1297 
1309 size_t mutt_wstr_trunc(const char *src, size_t maxlen, size_t maxwid, size_t *width)
1310 {
1311  wchar_t wc;
1312  size_t n, w = 0, l = 0, cl;
1313  int cw;
1314  mbstate_t mbstate;
1315 
1316  if (!src)
1317  goto out;
1318 
1319  n = mutt_str_len(src);
1320 
1321  memset(&mbstate, 0, sizeof(mbstate));
1322  for (w = 0; n && (cl = mbrtowc(&wc, src, n, &mbstate)); src += cl, n -= cl)
1323  {
1324  if ((cl == (size_t)(-1)) || (cl == (size_t)(-2)))
1325  {
1326  if (cl == (size_t)(-1))
1327  memset(&mbstate, 0, sizeof(mbstate));
1328  cl = (cl == (size_t)(-1)) ? 1 : n;
1329  wc = ReplacementChar;
1330  }
1331  cw = wcwidth(wc);
1332  /* hack because MUTT_TREE symbols aren't turned into characters
1333  * until rendered by print_enriched_string() */
1334  if ((cw < 0) && (src[0] == MUTT_SPECIAL_INDEX))
1335  {
1336  cl = 2; /* skip the index coloring sequence */
1337  cw = 0;
1338  }
1339  else if ((cw < 0) && (cl == 1) && (src[0] != '\0') && (src[0] < MUTT_TREE_MAX))
1340  cw = 1;
1341  else if (cw < 0)
1342  cw = 0; /* unprintable wchar */
1343  if ((cl + l > maxlen) || (cw + w > maxwid))
1344  break;
1345  l += cl;
1346  w += cw;
1347  }
1348 out:
1349  if (width)
1350  *width = w;
1351  return l;
1352 }
1353 
1359 int mutt_strwidth(const char *s)
1360 {
1361  if (!s)
1362  return 0;
1363  return mutt_strnwidth(s, mutt_str_len(s));
1364 }
1365 
1372 int mutt_strnwidth(const char *s, size_t n)
1373 {
1374  if (!s)
1375  return 0;
1376 
1377  wchar_t wc;
1378  int w;
1379  size_t k;
1380  mbstate_t mbstate;
1381 
1382  memset(&mbstate, 0, sizeof(mbstate));
1383  for (w = 0; n && (k = mbrtowc(&wc, s, n, &mbstate)); s += k, n -= k)
1384  {
1385  if (*s == MUTT_SPECIAL_INDEX)
1386  {
1387  s += 2; /* skip the index coloring sequence */
1388  k = 0;
1389  continue;
1390  }
1391 
1392  if ((k == (size_t)(-1)) || (k == (size_t)(-2)))
1393  {
1394  if (k == (size_t)(-1))
1395  memset(&mbstate, 0, sizeof(mbstate));
1396  k = (k == (size_t)(-1)) ? 1 : n;
1397  wc = ReplacementChar;
1398  }
1399  if (!IsWPrint(wc))
1400  wc = '?';
1401  w += wcwidth(wc);
1402  }
1403  return w;
1404 }
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:871
void mutt_perror_debug(const char *s)
Show the user an &#39;errno&#39; message.
Definition: curs_lib.c:590
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
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:75
void mutt_buffer_select_file(struct Buffer *file, SelectFileFlags flags, char ***files, int *numfiles)
Let the user select a file.
Definition: browser.c:1135
static struct KeyEvent * MacroEvents
Definition: curs_lib.c:84
WHERE short C_Timeout
Config: Time to wait for user input in menus.
Definition: mutt_globals.h:115
Pager Bar containing status info about the Pager.
Definition: mutt_window.h:98
WHERE SIG_ATOMIC_VOLATILE_T SigInt
true after SIGINT is received
Definition: mutt_globals.h:74
Window uses all available vertical space.
Definition: mutt_window.h:35
void mutt_push_macro_event(int ch, int op)
Add the character/operation to the macro buffer.
Definition: curs_lib.c:871
static size_t MacroBufferCount
Definition: curs_lib.c:82
void mutt_curses_set_color(enum ColorId color)
Set the current colour for text.
Definition: mutt_curses.c:57
int * defs
Array of all fixed colours, see enum ColorId.
Definition: color.h:131
void mutt_flushinp(void)
Empty all the keyboard buffers.
Definition: curs_lib.c:919
void mutt_window_clrtoeol(struct MuttWindow *win)
Clear to the end of the line.
Definition: mutt_window.c:244
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
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:834
#define _(a)
Definition: message.h:28
#define REG_COMP(preg, regex, cflags)
Compile a regular expression.
Definition: regex3.h:53
WHERE bool OptNoCurses
(pseudo) when sending in batch mode
Definition: options.h:48
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:179
int op
function op
Definition: keymap.h:66
int ch
raw key pressed
Definition: keymap.h:65
#define MUTT_SEL_NO_FLAGS
No flags are set.
Definition: browser.h:40
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:115
WHERE char ErrorBuf[256]
Copy of the last error message.
Definition: mutt_globals.h:45
void mutt_query_exit(void)
Ask the user if they want to leave NeoMutt.
Definition: curs_lib.c:539
An email being displayed.
Definition: pager.h:65
int mutt_window_mvaddstr(struct MuttWindow *win, int col, int row, const char *str)
Move the cursor and write a fixed string to a Window.
Definition: mutt_window.c:396
All user-callable functions.
Container for Accounts, Notifications.
Definition: neomutt.h:36
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:91
QuadOption
Possible values for a quad-option.
Definition: quad.h:36
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:1266
int mutt_window_move(struct MuttWindow *win, int col, int row)
Move the cursor in a Window.
Definition: mutt_window.c:382
GUI component for displaying/selecting items from a list.
#define MUTT_SEL_FOLDER
Select a local directory.
Definition: browser.h:43
void mutt_window_free(struct MuttWindow **ptr)
Free a Window and its children.
Definition: mutt_window.c:186
static size_t UngetCount
Definition: curs_lib.c:89
void mutt_beep(bool force)
Irritate the user.
Definition: curs_lib.c:99
enum NotifyType event_type
Send: Event type, e.g. NT_ACCOUNT.
Definition: observer.h:42
#define MAX(a, b)
Definition: memory.h:30
struct MuttWindow * focus
Focussed Window.
Definition: mutt_window.h:133
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:504
void mutt_curses_set_cursor(enum MuttCursorState state)
Set the cursor state.
Definition: mutt_curses.c:78
enum QuadOption mutt_yesorno(const char *msg, enum QuadOption def)
Ask the user a Yes/No question.
Definition: curs_lib.c:379
Many unsorted constants and some structs.
void mutt_flush_macro_to_endcond(void)
Drop a macro from the input buffer.
Definition: curs_lib.c:890
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:232
Display a normal cursor.
Definition: mutt_curses.h:81
Convenience wrapper for the core headers.
void dialog_push(struct MuttWindow *dlg)
Display a Window to the user.
Definition: dialog.c:66
WHERE bool C_Beep
Config: Make a noise when an error occurs.
Definition: mutt_globals.h:138
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
User aborted the question (with Ctrl-G)
Definition: quad.h:38
#define EILSEQ
Definition: charset.c:49
bool notify_observer_add(struct Notify *notify, enum NotifyType type, observer_t callback, void *global_data)
Add an observer to an object.
Definition: notify.c:169
int mutt_monitor_poll(void)
Check for filesystem changes.
Definition: monitor.c:397
static int mutt_dlg_dopager_observer(struct NotifyCallback *nc)
Listen for config changes affecting the dopager menus - Implements observer_t.
Definition: curs_lib.c:652
void * global_data
Data from notify_observer_add()
Definition: observer.h:45
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:77
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:768
void mutt_window_reflow_message_rows(int mw_rows)
Resize the Message Window.
Definition: mutt_window.c:459
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:57
#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:933
void mutt_refresh(void)
Force a refresh of the screen.
Definition: curs_lib.c:108
WHERE bool OptForceRefresh
(pseudo) refresh even during macros
Definition: options.h:37
Prototypes for many functions.
void mutt_window_get_coords(struct MuttWindow *win, int *col, int *row)
Get the cursor position in the Window.
Definition: mutt_window.c:322
struct WindowState state
Current state of the Window.
Definition: mutt_window.h:120
struct MuttWindow * MessageWindow
Message Window, ":set", etc.
Definition: mutt_window.c:47
void mutt_endwin(void)
Shutdown curses/slang.
Definition: curs_lib.c:571
static struct KeyEvent * UngetKeyEvents
Definition: curs_lib.c:91
Create/manipulate threading in emails.
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:259
int mutt_strwidth(const char *s)
Measure a string&#39;s width in screen cells.
Definition: curs_lib.c:1359
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:1207
#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:58
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:841
char * data
Pointer to data.
Definition: buffer.h:35
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:158
wchar_t ReplacementChar
When a Unicode character can&#39;t be displayed, use this instead.
Definition: charset.c:58
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:1309
GUI present the user with a selectable list.
Ask the user, defaulting to &#39;Yes&#39;.
Definition: quad.h:42
#define TAILQ_INSERT_TAIL(head, elm, field)
Definition: queue.h:802
Pager Dialog, mutt_do_pager()
Definition: mutt_window.h:81
An event such as a keypress.
Definition: keymap.h:63
struct KeyEvent mutt_getch(void)
Read a character from the input buffer.
Definition: curs_lib.c:189
struct Notify * notify
Notifications handler.
Definition: neomutt.h:38
Definition: color.h:129
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:1372
#define MUTT_SEL_MULTI
Multi-selection is enabled.
Definition: browser.h:42
keycode_t AbortKey
code of key to abort prompts, normally Ctrl-G
Definition: keymap.c:147
#define MUTT_FILE
Do file completion.
Definition: mutt.h:58
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:334
void * event_data
Data from notify_send()
Definition: observer.h:44
void mutt_window_add_child(struct MuttWindow *parent, struct MuttWindow *child)
Add a child to Window.
Definition: mutt_window.c:565
Restore the previous cursor state.
Definition: mutt_curses.h:79
Config has changed, NotifyConfig, EventConfig.
Definition: notify_type.h:37
#define MUTT_SEL_MAILBOX
Select a mailbox.
Definition: browser.h:41
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:604
Dialog Windows.
Window containing paged free-form text.
Definition: mutt_window.h:97
static size_t MacroBufferLen
Definition: curs_lib.c:83
enum QuadOption query_quadoption(enum QuadOption opt, const char *prompt)
Ask the user a quad-question.
Definition: curs_lib.c:517
GUI display a file/email/help in a viewport with paging.
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:631
int mutt_window_addch(int ch)
Write one character to a Window.
Definition: mutt_window.c:492
#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:1244
Error message.
Definition: color.h:70
Log at debug level 1.
Definition: logging.h:40
WHERE char * C_Pager
Config: External command for viewing messages, or &#39;builtin&#39; to use NeoMutt&#39;s.
Definition: mutt_globals.h:99
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:690
void mutt_window_reflow(struct MuttWindow *win)
Resize a Window and its children.
Definition: mutt_window.c:433
WHERE bool C_StatusOnTop
Config: Display the status bar at the top.
Definition: mutt_globals.h:164
#define mutt_error(...)
Definition: logging.h:84
void mutt_flush_unget_to_endcond(void)
Clear entries from UngetKeyEvents.
Definition: curs_lib.c:907
void dialog_pop(void)
Hide a Window from the user.
Definition: dialog.c:98
void mutt_getch_timeout(int delay)
Set the getch() timeout.
Definition: curs_lib.c:146
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:1432
Colour indicator.
Definition: mutt_thread.h:71
#define FREE(x)
Definition: memory.h:40
WHERE bool OptMsgErr
(pseudo) used by mutt_error/mutt_message
Definition: options.h:41
Monitor files for changes.
struct MuttWindowList children
Children Windows.
Definition: mutt_window.h:129
void mutt_unget_string(const char *s)
Return a string to the input buffer.
Definition: curs_lib.c:853
User answered &#39;No&#39;, or assume &#39;No&#39;.
Definition: quad.h:39
bool notify_observer_remove(struct Notify *notify, observer_t callback, void *global_data)
Remove an observer from an object.
Definition: notify.c:207
void mutt_show_error(void)
Show the user an error message.
Definition: curs_lib.c:557
struct MuttWindow * win_ibar
Definition: pager.h:73
int mutt_window_addstr(const char *str)
Write a string to a Window.
Definition: mutt_window.c:522
struct EnterState * mutt_enter_state_new(void)
Create a new EnterState.
Definition: enter.c:128
Options in prompt.
Definition: color.h:78
Hundreds of global variables to back the user variables.
Handling of global boolean variables.
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
WHERE bool ErrorBufMessage
true if the last message was an error
Definition: mutt_globals.h:44
struct MuttWindow * mutt_window_new(enum WindowType type, enum MuttWindowOrientation orient, enum MuttWindowSize size, int cols, int rows)
Create a new Window.
Definition: mutt_window.c:166
int mutt_str_asprintf(char **strp, const char *fmt,...)
Definition: string.c:1095
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:2239
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:130
WHERE SIG_ATOMIC_VOLATILE_T SigWinch
true after SIGWINCH is received
Definition: mutt_globals.h:75
enum WindowType type
Window type, e.g. WT_SIDEBAR.
Definition: mutt_window.h:137
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:355
bool C_MetaKey
Config: Interpret &#39;ALT-x&#39; as &#39;ESC-x&#39;.
Definition: curs_lib.c:72
int mutt_system(const char *cmd)
Run an external command.
Definition: system.c:51
Question/user input.
Definition: color.h:80
int MuttGetchTimeout
Timeout in ms for mutt_getch()
Definition: curs_lib.c:93
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:1256
static size_t UngetLen
Definition: curs_lib.c:90
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:1093
User answered &#39;Yes&#39;, or assume &#39;Yes&#39;.
Definition: quad.h:40
int mutt_addwch(wchar_t wc)
addwch would be provided by an up-to-date curses library
Definition: curs_lib.c:1059
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:310
struct MuttWindow * win_pbar
Definition: pager.h:75
uint8_t SelectFileFlags
Flags for mutt_select_file(), e.g. MUTT_SEL_MAILBOX.
Definition: browser.h:39