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