1 /* ttyio.c - tty i/O functions
2 * Copyright (C) 1998,1999,2000,2001,2002,2003,2004,2006,2007,
3 * 2009 Free Software Foundation, Inc.
5 * This file is part of GnuPG.
7 * GnuPG is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
12 * GnuPG is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, see <http://www.gnu.org/licenses/>.
31 /* Simulate termios with termio. */
33 # define termios termio
34 # define tcsetattr ioctl
35 # define TCSAFLUSH TCSETAF
36 # define tcgetattr(A,B) ioctl(A,TCGETA,B)
37 # define HAVE_TCGETATTR
40 #ifdef _WIN32 /* use the odd Win32 functions */
41 # ifdef HAVE_WINSOCK2_H
42 # include <winsock2.h>
45 # ifdef HAVE_TCGETATTR
46 # error mingw32 and termios
54 #include "estream-printf.h"
55 #include "common-defs.h"
57 #define CONTROL_D ('D' - 'A' + 1)
59 #ifdef _WIN32 /* use the odd Win32 functions */
63 #define DEF_INPMODE (ENABLE_LINE_INPUT|ENABLE_ECHO_INPUT \
64 |ENABLE_PROCESSED_INPUT )
65 #define HID_INPMODE (ENABLE_LINE_INPUT|ENABLE_PROCESSED_INPUT )
66 #define DEF_OUTMODE (ENABLE_WRAP_AT_EOL_OUTPUT|ENABLE_PROCESSED_OUTPUT)
68 #else /* yeah, we have a real OS */
69 static FILE *ttyfp = NULL;
72 static int initialized;
73 static int last_prompt_len;
75 static int no_terminal;
78 static struct termios termsave;
79 static int restore_termios;
82 /* Hooks set by gpgrlhelp.c if required. */
83 static void (*my_rl_set_completer) (rl_completion_func_t *);
84 static void (*my_rl_inhibit_completion) (int);
85 static void (*my_rl_cleanup_after_signal) (void);
86 static void (*my_rl_init_stream) (FILE *);
87 static char *(*my_rl_readline) (const char*);
88 static void (*my_rl_add_history) (const char*);
91 /* This is a wrapper around ttyname so that we can use it even when
92 the standard streams are redirected. It figures the name out the
93 first time and returns it in a statically allocated buffer. */
95 tty_get_ttyname (void)
99 /* On a GNU system ctermid() always return /dev/tty, so this does
100 not make much sense - however if it is ever changed we do the
108 /* Note that despite our checks for these macros the function is
109 not necessarily thread save. We mainly do this for
110 portability reasons, in case L_ctermid is not defined. */
111 # if defined(_POSIX_THREAD_SAFE_FUNCTIONS) || defined(_POSIX_TRHEADS)
112 char buffer[L_ctermid];
113 s = ctermid (buffer);
121 #endif /*HAVE_CTERMID*/
122 /* Assume the standard tty on memory error or when tehre is no
124 return name? name : "/dev/tty";
129 #ifdef HAVE_TCGETATTR
133 if( restore_termios ) {
134 restore_termios = 0; /* do it prios in case it is interrupted again */
135 if( tcsetattr(fileno(ttyfp), TCSAFLUSH, &termsave) )
136 log_error("tcsetattr() failed: %s\n", strerror(errno) );
149 SECURITY_ATTRIBUTES sa;
151 memset(&sa, 0, sizeof(sa));
152 sa.nLength = sizeof(sa);
153 sa.bInheritHandle = TRUE;
154 con.out = CreateFileA( "CONOUT$", GENERIC_READ|GENERIC_WRITE,
155 FILE_SHARE_READ|FILE_SHARE_WRITE,
156 &sa, OPEN_EXISTING, 0, 0 );
157 if( con.out == INVALID_HANDLE_VALUE )
158 log_fatal("open(CONOUT$) failed: rc=%d", (int)GetLastError() );
159 memset(&sa, 0, sizeof(sa));
160 sa.nLength = sizeof(sa);
161 sa.bInheritHandle = TRUE;
162 con.in = CreateFileA( "CONIN$", GENERIC_READ|GENERIC_WRITE,
163 FILE_SHARE_READ|FILE_SHARE_WRITE,
164 &sa, OPEN_EXISTING, 0, 0 );
165 if( con.in == INVALID_HANDLE_VALUE )
166 log_fatal("open(CONIN$) failed: rc=%d", (int)GetLastError() );
168 SetConsoleMode(con.in, DEF_INPMODE );
169 SetConsoleMode(con.out, DEF_OUTMODE );
171 #elif defined(__EMX__)
172 ttyfp = stdout; /* Fixme: replace by the real functions: see wklib */
173 if (my_rl_init_stream)
174 my_rl_init_stream (ttyfp);
176 ttyfp = batchmode? stderr : fopen (tty_get_ttyname (), "r+");
178 log_error("cannot open `%s': %s\n", tty_get_ttyname (),
182 if (my_rl_init_stream)
183 my_rl_init_stream (ttyfp);
187 #ifdef HAVE_TCGETATTR
195 tty_batchmode( int onoff )
204 tty_no_terminal(int onoff)
206 int old = no_terminal;
207 no_terminal = onoff ? 1 : 0;
212 tty_printf( const char *fmt, ... )
222 va_start( arg_ptr, fmt ) ;
229 n = vasprintf(&buf, fmt, arg_ptr);
231 log_bug("vasprintf() failed\n");
233 if( !WriteConsoleA( con.out, buf, n, &nwritten, NULL ) )
234 log_fatal("WriteConsole failed: rc=%d", (int)GetLastError() );
236 log_fatal("WriteConsole failed: %d != %d\n", n, (int)nwritten );
237 last_prompt_len += n;
241 last_prompt_len += vfprintf(ttyfp,fmt,arg_ptr) ;
248 /* Same as tty_printf but if FP is not NULL, behave like a regular
251 tty_fprintf (FILE *fp, const char *fmt, ... )
257 va_start (arg_ptr, fmt) ;
258 vfprintf (fp, fmt, arg_ptr );
269 va_start( arg_ptr, fmt ) ;
276 n = vasprintf(&buf, fmt, arg_ptr);
278 log_bug("vasprintf() failed\n");
280 if( !WriteConsoleA( con.out, buf, n, &nwritten, NULL ) )
281 log_fatal("WriteConsole failed: rc=%d", (int)GetLastError() );
283 log_fatal("WriteConsole failed: %d != %d\n", n, (int)nwritten );
284 last_prompt_len += n;
288 last_prompt_len += vfprintf(ttyfp,fmt,arg_ptr) ;
296 * Print a string, but filter all control characters out.
299 tty_print_string ( const byte *p, size_t n )
308 /* not so effective, change it if you want */
310 if( iscntrl( *p ) ) {
316 tty_printf("\\x%02x", *p);
319 tty_printf("%c", *p);
322 if( iscntrl( *p ) ) {
329 fprintf(ttyfp, "x%02x", *p );
337 tty_print_utf8_string2( const byte *p, size_t n, size_t max_n )
345 /* we can handle plain ascii simpler, so check for it first */
346 for(i=0; i < n; i++ ) {
351 buf = utf8_to_native( (const char *)p, n, 0 );
352 if( max_n && (strlen( buf ) > max_n )) {
355 /*(utf8 conversion already does the control character quoting)*/
356 tty_printf("%s", buf );
360 if( max_n && (n > max_n) ) {
363 tty_print_string( p, n );
368 tty_print_utf8_string( const byte *p, size_t n )
370 tty_print_utf8_string2( p, n, 0 );
375 do_get( const char *prompt, int hidden )
384 log_error("Sorry, we are in batchmode - can't get input\n");
389 log_error("Sorry, no terminal at all requested - can't get input\n");
397 tty_printf( "%s", prompt );
398 buf = xmalloc((n=50));
401 #ifdef _WIN32 /* windoze version */
403 SetConsoleMode(con.in, HID_INPMODE );
408 if( !ReadConsoleA( con.in, cbuf, 1, &nread, NULL ) )
409 log_fatal("ReadConsole failed: rc=%d", (int)GetLastError() );
421 ; /* we don't allow 0xa0, as this is a protected blank which may
422 * confuse the user */
423 else if( iscntrl(c) )
427 buf = xrealloc (buf, n);
433 SetConsoleMode(con.in, DEF_INPMODE );
435 #elif defined(__riscos__)
437 c = riscos_getchar();
438 if (c == 0xa || c == 0xd) { /* Return || Enter */
440 } else if (c == 0x8 || c == 0x7f) { /* Backspace || Delete */
455 } else if (c == (int) '\t') { /* Tab */
457 } else if (c > 0xa0) {
458 ; /* we don't allow 0xa0, as this is a protected blank which may
459 * confuse the user */
460 } else if (iscntrl(c)) {
465 buf = xrealloc (buf, n);
475 #else /* unix version */
477 #ifdef HAVE_TCGETATTR
480 if( tcgetattr(fileno(ttyfp), &termsave) )
481 log_fatal("tcgetattr() failed: %s\n", strerror(errno) );
484 term.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
485 if( tcsetattr( fileno(ttyfp), TCSAFLUSH, &term ) )
486 log_fatal("tcsetattr() failed: %s\n", strerror(errno) );
490 /* fixme: How can we avoid that the \n is echoed w/o disabling
491 * canonical mode - w/o this kill_prompt can't work */
492 while( read(fileno(ttyfp), cbuf, 1) == 1 && *cbuf != '\n' ) {
497 log_info("control d found\n");
501 ; /* we don't allow 0xa0, as this is a protected blank which may
502 * confuse the user */
503 else if( iscntrl(c) )
507 buf = xrealloc (buf, n );
511 if( *cbuf != '\n' ) {
518 #ifdef HAVE_TCGETATTR
519 if( tcsetattr(fileno(ttyfp), TCSAFLUSH, &termsave) )
520 log_error("tcsetattr() failed: %s\n", strerror(errno) );
524 #endif /* end unix version */
531 tty_get( const char *prompt )
533 if (!batchmode && !no_terminal && my_rl_readline && my_rl_add_history)
543 line = my_rl_readline (prompt?prompt:"");
545 /* We need to copy it to memory controlled by our malloc
546 implementations; further we need to convert an EOF to our
548 buf = xmalloc(line? strlen(line)+1:2);
553 if (strlen (buf) > 2 )
554 my_rl_add_history (line); /* Note that we test BUF but add LINE. */
565 return do_get ( prompt, 0 );
568 /* Variable argument version of tty_get. The prompt is is actually a
569 format string with arguments. */
571 tty_getf (const char *promptfmt, ... )
577 va_start (arg_ptr, promptfmt);
578 if (estream_vasprintf (&prompt, promptfmt, arg_ptr) < 0)
579 log_fatal ("estream_vasprintf failed: %s\n", strerror (errno));
581 answer = tty_get (prompt);
589 tty_get_hidden( const char *prompt )
591 return do_get( prompt, 1 );
606 if( !last_prompt_len )
609 tty_printf("\r%*s\r", last_prompt_len, "");
614 for(i=0; i < last_prompt_len; i ++ )
625 tty_get_answer_is_yes( const char *prompt )
628 char *p = tty_get( prompt );
630 yes = answer_is_yes(p);
636 /* Called by gnupg_rl_initialize to setup the readline support. */
638 tty_private_set_rl_hooks (void (*init_stream) (FILE *),
639 void (*set_completer) (rl_completion_func_t*),
640 void (*inhibit_completion) (int),
641 void (*cleanup_after_signal) (void),
642 char *(*readline_fun) (const char*),
643 void (*add_history_fun) (const char*))
645 my_rl_init_stream = init_stream;
646 my_rl_set_completer = set_completer;
647 my_rl_inhibit_completion = inhibit_completion;
648 my_rl_cleanup_after_signal = cleanup_after_signal;
649 my_rl_readline = readline_fun;
650 my_rl_add_history = add_history_fun;
654 #ifdef HAVE_LIBREADLINE
656 tty_enable_completion (rl_completion_func_t *completer)
658 if (no_terminal || !my_rl_set_completer )
664 my_rl_set_completer (completer);
668 tty_disable_completion (void)
670 if (no_terminal || !my_rl_inhibit_completion)
676 my_rl_inhibit_completion (1);
681 tty_cleanup_after_signal (void)
683 #ifdef HAVE_TCGETATTR
689 tty_cleanup_rl_after_signal (void)
691 if (my_rl_cleanup_after_signal)
692 my_rl_cleanup_after_signal ();