Switched to GPLv3.
[gnupg.git] / util / ttyio.c
1 /* ttyio.c -  tty i/O functions
2  * Copyright (C) 1998, 1999, 2000, 2001, 2002,
3  *               2004 Free Software Foundation, Inc.
4  *
5  * This file is part of GnuPG.
6  *
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.
11  *
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.
16  *
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/>.
19  */
20
21 #include <config.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <stdarg.h>
26 #include <unistd.h>
27 #ifdef HAVE_TCGETATTR
28 #include <termios.h>
29 #else
30 #ifdef HAVE_TERMIO_H
31 /* simulate termios with termio */
32 #include <termio.h>
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
38 #endif
39 #endif
40 #ifdef _WIN32 /* use the odd Win32 functions */
41 #include <windows.h>
42 #ifdef HAVE_TCGETATTR
43 #error windows and termios
44 #endif
45 #endif
46 #include <errno.h>
47 #include <ctype.h>
48 #ifdef HAVE_LIBREADLINE
49 #include <readline/readline.h>
50 #include <readline/history.h>
51 #endif
52
53 #include "util.h"
54 #include "memory.h"
55 #include "ttyio.h"
56
57 #define CONTROL_D ('D' - 'A' + 1)
58
59 #ifdef _WIN32 /* use the odd Win32 functions */
60 static struct {
61     HANDLE in, out;
62 } con;
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)
67
68 #else /* yeah, we have a real OS */
69 static FILE *ttyfp = NULL;
70 #endif
71
72 static int initialized;
73 static int last_prompt_len;
74 static int batchmode;
75 static int no_terminal;
76
77 #ifdef HAVE_TCGETATTR
78     static struct termios termsave;
79     static int restore_termios;
80 #endif
81
82
83
84 /* This is a wrapper around ttyname so that we can use it even when
85    the standard streams are redirected.  It figures the name out the
86    first time and returns it in a statically allocated buffer. */
87 const char *
88 tty_get_ttyname (void)
89 {
90   static char *name;
91
92   /* On a GNU system ctermid() always return /dev/tty, so this does
93      not make much sense - however if it is ever changed we do the
94      Right Thing now. */
95 #ifdef HAVE_CTERMID
96   static int got_name;
97
98   if (!got_name)
99     {
100       const char *s;
101       s = ctermid (NULL);
102       if (s)
103         name = strdup (s);
104       got_name = 1;
105     }
106 #endif
107   /* Assume the standard tty on memory error or when there is no
108      ctermid. */
109   return name? name : "/dev/tty";
110 }
111
112
113 #ifdef HAVE_TCGETATTR
114 static void
115 cleanup(void)
116 {
117     if( restore_termios ) {
118         restore_termios = 0; /* do it prios in case it is interrupted again */
119         if( tcsetattr(fileno(ttyfp), TCSAFLUSH, &termsave) )
120             log_error("tcsetattr() failed: %s\n", strerror(errno) );
121     }
122 }
123 #endif
124
125 static void
126 init_ttyfp(void)
127 {
128     if( initialized )
129         return;
130
131 #if defined(_WIN32)
132     {
133         SECURITY_ATTRIBUTES sa;
134
135         memset(&sa, 0, sizeof(sa));
136         sa.nLength = sizeof(sa);
137         sa.bInheritHandle = TRUE;
138         con.out = CreateFileA( "CONOUT$", GENERIC_READ|GENERIC_WRITE,
139                                FILE_SHARE_READ|FILE_SHARE_WRITE,
140                                &sa, OPEN_EXISTING, 0, 0 );
141         if( con.out == INVALID_HANDLE_VALUE )
142             log_fatal ("open(CONOUT$) failed: %s", w32_strerror (0));
143         memset(&sa, 0, sizeof(sa));
144         sa.nLength = sizeof(sa);
145         sa.bInheritHandle = TRUE;
146         con.in = CreateFileA( "CONIN$", GENERIC_READ|GENERIC_WRITE,
147                                FILE_SHARE_READ|FILE_SHARE_WRITE,
148                                &sa, OPEN_EXISTING, 0, 0 );
149         if (con.in == INVALID_HANDLE_VALUE)
150             log_fatal ("open(CONIN$) failed: %s", w32_strerror (0));
151     }
152     SetConsoleMode(con.in, DEF_INPMODE );
153     SetConsoleMode(con.out, DEF_OUTMODE );
154
155 #elif defined(__EMX__)
156     ttyfp = stdout; /* Fixme: replace by the real functions: see wklib */
157 #else
158     ttyfp = batchmode? stderr : fopen( tty_get_ttyname (), "r+");
159     if( !ttyfp ) {
160         log_error("cannot open `%s': %s\n",
161                   tty_get_ttyname (), strerror(errno) );
162         exit(2);
163     }
164 #ifdef HAVE_LIBREADLINE
165     rl_catch_signals = 0;
166     rl_instream = rl_outstream = ttyfp;
167     rl_inhibit_completion = 1;
168 #endif
169 #endif
170 #ifdef HAVE_TCGETATTR
171     atexit( cleanup );
172 #endif
173     initialized = 1;
174 }
175
176 #ifdef HAVE_LIBREADLINE
177 void
178 tty_enable_completion(rl_completion_func_t *completer)
179 {
180   if( no_terminal )
181     return;
182
183   if( !initialized )
184     init_ttyfp();
185
186   rl_attempted_completion_function=completer;
187   rl_inhibit_completion=0;
188 }
189
190 void
191 tty_disable_completion(void)
192 {
193   if( no_terminal )
194     return;
195
196   if( !initialized )
197     init_ttyfp();
198
199   rl_inhibit_completion=1;
200 }
201 #endif /*HAVE_LIBREADLINE*/
202
203 int
204 tty_batchmode( int onoff )
205 {
206     int old = batchmode;
207     if( onoff != -1 )
208         batchmode = onoff;
209     return old;
210 }
211
212 int
213 tty_no_terminal(int onoff)
214 {
215     int old = no_terminal;
216     no_terminal = onoff ? 1 : 0;
217     return old;
218 }
219
220 void
221 tty_printf( const char *fmt, ... )
222 {
223     va_list arg_ptr;
224
225     if (no_terminal)
226         return;
227
228     if( !initialized )
229         init_ttyfp();
230
231     va_start( arg_ptr, fmt ) ;
232 #ifdef _WIN32
233     {   
234         char *buf = NULL;
235         int n;
236         DWORD nwritten;
237
238         n = vasprintf(&buf, fmt, arg_ptr);
239         if( !buf )
240             log_bug("vasprintf() failed\n");
241         
242         if (!WriteConsoleA (con.out, buf, n, &nwritten, NULL))
243             log_fatal ("WriteConsole failed: %s", w32_strerror (0));
244         if( n != nwritten )
245             log_fatal ("WriteConsole failed: %d != %d\n", n, (int)nwritten );
246         last_prompt_len += n;
247         xfree (buf);
248     }
249 #else
250     last_prompt_len += vfprintf(ttyfp,fmt,arg_ptr) ;
251     fflush(ttyfp);
252 #endif
253     va_end(arg_ptr);
254 }
255
256
257 /* Same as tty_printf but if FP is not NULL, behave like the standard
258    fprintf. */
259 void
260 tty_fprintf (FILE *fp, const char *fmt, ... )
261 {
262   va_list arg_ptr;
263
264   if (fp)
265     {
266       va_start (arg_ptr, fmt) ;
267       vfprintf (fp, fmt, arg_ptr );
268       va_end (arg_ptr);
269       return;
270     }
271
272   if (no_terminal)
273     return;
274
275   if( !initialized )
276     init_ttyfp();
277
278     va_start( arg_ptr, fmt ) ;
279 #ifdef _WIN32
280     {   
281         char *buf = NULL;
282         int n;
283         DWORD nwritten;
284
285         n = vasprintf(&buf, fmt, arg_ptr);
286         if( !buf )
287             log_bug("vasprintf() failed\n");
288         
289         if (!WriteConsoleA (con.out, buf, n, &nwritten, NULL))
290             log_fatal ("WriteConsole failed: %s", w32_strerror (0));
291         if (n != nwritten)
292             log_fatal ("WriteConsole failed: %d != %d\n", n, (int)nwritten);
293         last_prompt_len += n;
294         xfree (buf);
295     }
296 #else
297     last_prompt_len += vfprintf(ttyfp,fmt,arg_ptr) ;
298     fflush(ttyfp);
299 #endif
300     va_end(arg_ptr);
301 }
302
303
304 /****************
305  * Print a string, but filter all control characters out.
306  */
307 void
308 tty_print_string( const byte *p, size_t n )
309 {
310     if (no_terminal)
311         return;
312
313     if( !initialized )
314         init_ttyfp();
315
316 #ifdef _WIN32
317     /* not so effective, change it if you want */
318     for( ; n; n--, p++ )
319         if( iscntrl( *p ) ) {
320             if( *p == '\n' )
321                 tty_printf("\\n");
322             else if( !*p )
323                 tty_printf("\\0");
324             else
325                 tty_printf("\\x%02x", *p);
326         }
327         else
328             tty_printf("%c", *p);
329 #else
330     for( ; n; n--, p++ )
331         if( iscntrl( *p ) ) {
332             putc('\\', ttyfp);
333             if( *p == '\n' )
334                 putc('n', ttyfp);
335             else if( !*p )
336                 putc('0', ttyfp);
337             else
338                 fprintf(ttyfp, "x%02x", *p );
339         }
340         else
341             putc(*p, ttyfp);
342 #endif
343 }
344
345 void
346 tty_print_utf8_string2 (const byte *p, size_t n, size_t max_n )
347 {
348     size_t i;
349     char *buf;
350
351     if (no_terminal)
352         return;
353
354     /* we can handle plain ascii simpler, so check for it first */
355     for(i=0; i < n; i++ ) {
356         if( p[i] & 0x80 )
357             break;
358     }
359     if( i < n ) {
360         buf = utf8_to_native( p, n, 0 );
361         if( max_n && (strlen( buf ) > max_n )) {
362             buf[max_n] = 0;
363         }
364         /*(utf8 conversion already does the control character quoting)*/
365         tty_printf("%s", buf );
366         xfree( buf );
367     }
368     else {
369         if( max_n && (n > max_n) ) {
370             n = max_n;
371         }
372         tty_print_string( p, n );
373     }
374 }
375
376 void
377 tty_print_utf8_string( const byte *p, size_t n )
378 {
379     tty_print_utf8_string2( p, n, 0 );
380 }
381
382
383 static char *
384 do_get( const char *prompt, int hidden )
385 {
386     char *buf;
387 #ifndef __riscos__
388     byte cbuf[1];
389 #endif
390     int c, n, i;
391
392     if( batchmode ) {
393         log_error("Sorry, we are in batchmode - can't get input\n");
394         exit(2);
395     }
396
397     if (no_terminal) {
398         log_error("Sorry, no terminal at all requested - can't get input\n");
399         exit(2);
400     }
401
402     if( !initialized )
403         init_ttyfp();
404
405     last_prompt_len = 0;
406     n = 50;
407     buf = hidden ? xmalloc_secure(n) : xmalloc(n);
408     i = 0;
409
410 #ifdef _WIN32 /* windoze version */
411     if( hidden )
412         SetConsoleMode(con.in, HID_INPMODE );
413
414     tty_printf( "%s", prompt );
415
416     for(;;) {
417         DWORD nread;
418
419         if (!ReadConsoleA (con.in, cbuf, 1, &nread, NULL))
420             log_fatal ("ReadConsole failed: %s", w32_strerror (0));
421         if( !nread )
422             continue;
423         if( *cbuf == '\n' )
424             break;
425
426         if( !hidden )
427             last_prompt_len++;
428         c = *cbuf;
429         if( c == '\t' )
430             c = ' ';
431         else if( c > 0xa0 )
432             ; /* we don't allow 0xa0, as this is a protected blank which may
433                * confuse the user */
434         else if( iscntrl(c) )
435             continue;
436         if( !(i < n-1) ) {
437             n += 50;
438             buf = xrealloc( buf, n );
439         }
440         buf[i++] = c;
441     }
442
443     if( hidden )
444         SetConsoleMode(con.in, DEF_INPMODE );
445
446 #elif defined(__riscos__)
447     tty_printf( "%s", prompt );
448     do {
449         c = riscos_getchar();
450         if (c == 0xa || c == 0xd) { /* Return || Enter */
451             c = (int) '\n';
452         } else if (c == 0x8 || c == 0x7f) { /* Backspace || Delete */
453             if (i>0) {
454                 i--;
455                 if (!hidden) {
456                     last_prompt_len--;
457                     fputc(8, ttyfp);
458                     fputc(32, ttyfp);
459                     fputc(8, ttyfp);
460                     fflush(ttyfp);
461                 }
462             } else {
463                 fputc(7, ttyfp);
464                 fflush(ttyfp);
465             }
466             continue;
467         } else if (c == (int) '\t') { /* Tab */
468             c = ' ';
469         } else if (c > 0xa0) {
470             ; /* we don't allow 0xa0, as this is a protected blank which may
471                * confuse the user */
472         } else if (iscntrl(c)) {
473             continue;
474         }
475         if(!(i < n-1)) {
476             n += 50;
477             buf = xrealloc(buf, n);
478         }
479         buf[i++] = c;
480         if (!hidden) {
481             last_prompt_len++;
482             fputc(c, ttyfp);
483             fflush(ttyfp);
484         }
485     } while (c != '\n');
486     i = (i>0) ? i-1 : 0;
487 #else /* unix version */
488     if( hidden ) {
489 #ifdef HAVE_TCGETATTR
490         struct termios term;
491
492         if( tcgetattr(fileno(ttyfp), &termsave) )
493             log_fatal("tcgetattr() failed: %s\n", strerror(errno) );
494         restore_termios = 1;
495         term = termsave;
496         term.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
497         if( tcsetattr( fileno(ttyfp), TCSAFLUSH, &term ) )
498             log_fatal("tcsetattr() failed: %s\n", strerror(errno) );
499 #endif
500     }
501
502     tty_printf( "%s", prompt );
503
504     /* fixme: How can we avoid that the \n is echoed w/o disabling
505      * canonical mode - w/o this kill_prompt can't work */
506     while( read(fileno(ttyfp), cbuf, 1) == 1 && *cbuf != '\n' ) {
507         if( !hidden )
508             last_prompt_len++;
509         c = *cbuf;
510         if( c == CONTROL_D )
511             log_info("control d found\n");
512         if( c == '\t' )
513             c = ' ';
514         else if( c > 0xa0 )
515             ; /* we don't allow 0xa0, as this is a protected blank which may
516                * confuse the user */
517         else if( iscntrl(c) )
518             continue;
519         if( !(i < n-1) ) {
520             n += 50;
521             buf = xrealloc( buf, n );
522         }
523         buf[i++] = c;
524     }
525     if( *cbuf != '\n' ) {
526         buf[0] = CONTROL_D;
527         i = 1;
528     }
529
530
531     if( hidden ) {
532 #ifdef HAVE_TCGETATTR
533         if( tcsetattr(fileno(ttyfp), TCSAFLUSH, &termsave) )
534             log_error("tcsetattr() failed: %s\n", strerror(errno) );
535         restore_termios = 0;
536 #endif
537     }
538 #endif /* end unix version */
539     buf[i] = 0;
540     return buf;
541 }
542
543
544 char *
545 tty_get( const char *prompt )
546 {
547 #ifdef HAVE_LIBREADLINE
548     if (!batchmode && !no_terminal) {
549       char *line;
550       char *buf;
551
552       if( !initialized )
553         init_ttyfp();
554
555       last_prompt_len = 0;
556
557       line = readline (prompt?prompt:"");
558
559       /* We need to copy it to memory controlled by our malloc
560          implementations; further we need to convert an EOF to our
561          convention. */
562       buf = xmalloc(line? strlen(line)+1:2);
563       if (line)
564         {
565           strcpy (buf, line);
566           trim_spaces (buf);
567           if (strlen (buf) > 2 )
568             add_history (line); /* Note that we test BUF but add LINE. */
569           free (line);
570         }
571       else
572         {
573           buf[0] = CONTROL_D;
574           buf[1] = 0;
575         }
576       return buf;
577     }
578     else
579 #endif /* HAVE_LIBREADLINE */
580       return do_get( prompt, 0 );
581 }
582
583 char *
584 tty_get_hidden( const char *prompt )
585 {
586     return do_get( prompt, 1 );
587 }
588
589
590 void
591 tty_kill_prompt()
592 {
593     if ( no_terminal )
594         return;
595
596     if( !initialized )
597         init_ttyfp();
598
599     if( batchmode )
600         last_prompt_len = 0;
601     if( !last_prompt_len )
602         return;
603 #ifdef _WIN32
604     tty_printf("\r%*s\r", last_prompt_len, "");
605 #else
606     {
607         int i;
608         putc('\r', ttyfp);
609         for(i=0; i < last_prompt_len; i ++ )
610             putc(' ', ttyfp);
611         putc('\r', ttyfp);
612         fflush(ttyfp);
613     }
614 #endif
615     last_prompt_len = 0;
616 }
617
618
619 int
620 tty_get_answer_is_yes( const char *prompt )
621 {
622     int yes;
623     char *p = tty_get( prompt );
624     tty_kill_prompt();
625     yes = answer_is_yes(p);
626     xfree(p);
627     return yes;
628 }