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