/* GNU Mailutils -- a suite of utilities for electronic mail Copyright (C) 2010-2019 Free Software Foundation, Inc. GNU Mailutils is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNU Mailutils is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Mailutils. If not, see . */ /* MH prompter - traditional tty/termios support */ #include #include "prompter.h" #include "muaux.h" #include #if HAVE_TERMIOS_H # include #endif mu_stream_t strin; #if HAVE_TCGETATTR struct termios tios; #endif static int decode_key (const char *keyseq) { if (keyseq[0] == '^' && keyseq[1]) { if (keyseq[2]) { mu_error (_("invalid keysequence (%s near %d)"), keyseq, 2); exit (1); } return keyseq[1] + 0100; } else if (keyseq[0] == '\\') { int i; int c = 0; for (i = 1; i <= 3; i++) { int n; switch (keyseq[i]) { case '0': n = 0; break; case '1': n = 1; break; case '2': n = 2; break; case '3': n = 3; break; case '4': n = 4; break; case '5': n = 5; break; case '6': n = 6; break; case '7': n = 7; break; default: mu_error (_("invalid keysequence (%s near %d)"), keyseq, i); exit (1); } c = (c << 3) + n; } if (keyseq[i]) { mu_error (_("invalid keysequence (%s near %d)"), keyseq, i); exit (1); } return c; } else if (keyseq[1]) { mu_error (_("invalid keysequence (%s near %d)"), keyseq, 2); exit (1); } return keyseq[0]; } static RETSIGTYPE sighan (int signo) { prompter_done (); exit (0); } void prompter_init () { int rc; if ((rc = mu_stdio_stream_create (&strin, MU_STDIN_FD, MU_STREAM_READ))) { mu_error (_("cannot open stdout: %s"), mu_strerror (rc)); exit (1); } #if HAVE_TCGETATTR rc = tcgetattr (MU_STDOUT_FD, &tios); if (rc) { mu_error (_("tcgetattr failed: %s"), mu_strerror (rc)); exit (1); } else { static int sigtab[] = { SIGPIPE, SIGABRT, SIGINT, SIGQUIT, SIGTERM }; mu_set_signals (sighan, sigtab, MU_ARRAY_SIZE (sigtab)); } #endif } void prompter_done () { #if HAVE_TCGETATTR int rc = tcsetattr (MU_STDOUT_FD, TCSANOW, &tios); if (rc) mu_error (_("tcsetattr failed: %s"), mu_strerror (rc)); #endif } void prompter_set_erase (const char *keyseq) { #if HAVE_TCGETATTR int rc; struct termios t = tios; t.c_lflag |= ICANON; t.c_cc[VERASE] = decode_key (keyseq); rc = tcsetattr (MU_STDOUT_FD, TCSANOW, &t); if (rc) mu_error (_("tcsetattr failed: %s"), mu_strerror (rc)); #endif } void prompter_set_kill (const char *keyseq) { #if HAVE_TCGETATTR int rc; struct termios t = tios; t.c_lflag |= ICANON; t.c_cc[VKILL] = decode_key (keyseq); rc = tcsetattr (MU_STDOUT_FD, TCSANOW, &t); if (rc) mu_error (_("tcsetattr failed: %s"), mu_strerror (rc)); #endif } char * prompter_get_value (const char *name) { size_t size = 0, n; char *buf = NULL; mu_stream_printf (strout, "%s: ", name); mu_stream_flush (strout); if (mu_stream_getline (strin, &buf, &size, &n) || n == 0) return NULL; mu_rtrim_cset (buf, "\n"); return buf; } char * prompter_get_line () { size_t size = 0, n; char *buf = NULL; if (mu_stream_getline (strin, &buf, &size, &n) || n == 0) return NULL; mu_rtrim_cset (buf, "\n"); return doteof_filter (buf); }