Added missing file
[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 #ifdef HAVE_LIBREADLINE
51 #include <readline/readline.h>
52 #include <readline/history.h>
53 #endif
54
55
56 #include "util.h"
57 #include "memory.h"
58 #include "ttyio.h"
59
60 #define CONTROL_D ('D' - 'A' + 1)
61
62 #ifdef _WIN32 /* use the odd Win32 functions */
63 static struct {
64     HANDLE in, out;
65 } con;
66 #define DEF_INPMODE  (ENABLE_LINE_INPUT|ENABLE_ECHO_INPUT    \
67                                         |ENABLE_PROCESSED_INPUT )
68 #define HID_INPMODE  (ENABLE_LINE_INPUT|ENABLE_PROCESSED_INPUT )
69 #define DEF_OUTMODE  (ENABLE_WRAP_AT_EOL_OUTPUT|ENABLE_PROCESSED_OUTPUT)
70
71 #else /* yeah, we have a real OS */
72 static FILE *ttyfp = NULL;
73 #endif
74
75 static int initialized;
76 static int last_prompt_len;
77 static int batchmode;
78 static int no_terminal;
79
80 #ifdef HAVE_TCGETATTR
81     static struct termios termsave;
82     static int restore_termios;
83 #endif
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 #ifdef HAVE_LIBREADLINE
185 void
186 tty_enable_completion(rl_completion_func_t *completer)
187 {
188 /*   if( no_terminal ) */
189 /*     return; */
190
191 /*   if( !initialized ) */
192 /*     init_ttyfp(); */
193
194 /*   rl_attempted_completion_function=completer; */
195 /*   rl_inhibit_completion=0; */
196 }
197
198 void
199 tty_disable_completion(void)
200 {
201 /*   if( no_terminal ) */
202 /*     return; */
203
204 /*   if( !initialized ) */
205 /*     init_ttyfp(); */
206
207 /*   rl_inhibit_completion=1; */
208 }
209 #endif /*HAVE_LIBREADLINE*/
210
211
212 int
213 tty_batchmode( int onoff )
214 {
215     int old = batchmode;
216     if( onoff != -1 )
217         batchmode = onoff;
218     return old;
219 }
220
221 int
222 tty_no_terminal(int onoff)
223 {
224     int old = no_terminal;
225     no_terminal = onoff ? 1 : 0;
226     return old;
227 }
228
229 void
230 tty_printf( const char *fmt, ... )
231 {
232     va_list arg_ptr;
233
234     if (no_terminal)
235         return;
236
237     if( !initialized )
238         init_ttyfp();
239
240     va_start( arg_ptr, fmt ) ;
241 #ifdef _WIN32
242     {   
243         char *buf = NULL;
244         int n;
245         DWORD nwritten;
246
247         n = vasprintf(&buf, fmt, arg_ptr);
248         if( !buf )
249             log_bug("vasprintf() failed\n");
250         
251         if( !WriteConsoleA( con.out, buf, n, &nwritten, NULL ) )
252             log_fatal("WriteConsole failed: rc=%d", (int)GetLastError() );
253         if( n != nwritten )
254             log_fatal("WriteConsole failed: %d != %d\n", n, (int)nwritten );
255         last_prompt_len += n;
256         xfree (buf);
257     }
258 #else
259     last_prompt_len += vfprintf(ttyfp,fmt,arg_ptr) ;
260     fflush(ttyfp);
261 #endif
262     va_end(arg_ptr);
263 }
264
265
266 /* Same as tty_printf but if FP is not NULL, behave like a regualr
267    fprintf. */
268 void
269 tty_fprintf (FILE *fp, const char *fmt, ... )
270 {
271   va_list arg_ptr;
272
273   if (fp)
274     {
275       va_start (arg_ptr, fmt) ;
276       vfprintf (fp, fmt, arg_ptr );
277       va_end (arg_ptr);
278       return;
279     }
280
281   if (no_terminal)
282     return;
283
284   if( !initialized )
285     init_ttyfp();
286
287     va_start( arg_ptr, fmt ) ;
288 #ifdef _WIN32
289     {   
290         char *buf = NULL;
291         int n;
292         DWORD nwritten;
293
294         n = vasprintf(&buf, fmt, arg_ptr);
295         if( !buf )
296             log_bug("vasprintf() failed\n");
297         
298         if( !WriteConsoleA( con.out, buf, n, &nwritten, NULL ) )
299             log_fatal("WriteConsole failed: rc=%d", (int)GetLastError() );
300         if( n != nwritten )
301             log_fatal("WriteConsole failed: %d != %d\n", n, (int)nwritten );
302         last_prompt_len += n;
303         xfree (buf);
304     }
305 #else
306     last_prompt_len += vfprintf(ttyfp,fmt,arg_ptr) ;
307     fflush(ttyfp);
308 #endif
309     va_end(arg_ptr);
310 }
311
312
313 /****************
314  * Print a string, but filter all control characters out.
315  */
316 void
317 tty_print_string ( const byte *p, size_t n )
318 {
319     if (no_terminal)
320         return;
321
322     if( !initialized )
323         init_ttyfp();
324
325 #ifdef _WIN32
326     /* not so effective, change it if you want */
327     for( ; n; n--, p++ )
328         if( iscntrl( *p ) ) {
329             if( *p == '\n' )
330                 tty_printf("\\n");
331             else if( !*p )
332                 tty_printf("\\0");
333             else
334                 tty_printf("\\x%02x", *p);
335         }
336         else
337             tty_printf("%c", *p);
338 #else
339     for( ; n; n--, p++ )
340         if( iscntrl( *p ) ) {
341             putc('\\', ttyfp);
342             if( *p == '\n' )
343                 putc('n', ttyfp);
344             else if( !*p )
345                 putc('0', ttyfp);
346             else
347                 fprintf(ttyfp, "x%02x", *p );
348         }
349         else
350             putc(*p, ttyfp);
351 #endif
352 }
353
354 void
355 tty_print_utf8_string2( const byte *p, size_t n, size_t max_n )
356 {
357     size_t i;
358     char *buf;
359
360     if (no_terminal)
361         return;
362
363     /* we can handle plain ascii simpler, so check for it first */
364     for(i=0; i < n; i++ ) {
365         if( p[i] & 0x80 )
366             break;
367     }
368     if( i < n ) {
369         buf = utf8_to_native( (const char *)p, n, 0 );
370         if( max_n && (strlen( buf ) > max_n )) {
371             buf[max_n] = 0;
372         }
373         /*(utf8 conversion already does the control character quoting)*/
374         tty_printf("%s", buf );
375         xfree( buf );
376     }
377     else {
378         if( max_n && (n > max_n) ) {
379             n = max_n;
380         }
381         tty_print_string( p, n );
382     }
383 }
384
385 void
386 tty_print_utf8_string( const byte *p, size_t n )
387 {
388     tty_print_utf8_string2( p, n, 0 );
389 }
390
391
392 static char *
393 do_get( const char *prompt, int hidden )
394 {
395     char *buf;
396 #ifndef __riscos__
397     byte cbuf[1];
398 #endif
399     int c, n, i;
400
401     if( batchmode ) {
402         log_error("Sorry, we are in batchmode - can't get input\n");
403         exit(2);
404     }
405
406     if (no_terminal) {
407         log_error("Sorry, no terminal at all requested - can't get input\n");
408         exit(2);
409     }
410
411     if( !initialized )
412         init_ttyfp();
413
414     last_prompt_len = 0;
415     tty_printf( "%s", prompt );
416     buf = xmalloc((n=50));
417     i = 0;
418
419 #ifdef _WIN32 /* windoze version */
420     if( hidden )
421         SetConsoleMode(con.in, HID_INPMODE );
422
423     for(;;) {
424         DWORD nread;
425
426         if( !ReadConsoleA( con.in, cbuf, 1, &nread, NULL ) )
427             log_fatal("ReadConsole failed: rc=%d", (int)GetLastError() );
428         if( !nread )
429             continue;
430         if( *cbuf == '\n' )
431             break;
432
433         if( !hidden )
434             last_prompt_len++;
435         c = *cbuf;
436         if( c == '\t' )
437             c = ' ';
438         else if( c > 0xa0 )
439             ; /* we don't allow 0xa0, as this is a protected blank which may
440                * confuse the user */
441         else if( iscntrl(c) )
442             continue;
443         if( !(i < n-1) ) {
444             n += 50;
445             buf = xrealloc (buf, n);
446         }
447         buf[i++] = c;
448     }
449
450     if( hidden )
451         SetConsoleMode(con.in, DEF_INPMODE );
452
453 #elif defined(__riscos__)
454     do {
455         c = riscos_getchar();
456         if (c == 0xa || c == 0xd) { /* Return || Enter */
457             c = (int) '\n';
458         } else if (c == 0x8 || c == 0x7f) { /* Backspace || Delete */
459             if (i>0) {
460                 i--;
461                 if (!hidden) {
462                     last_prompt_len--;
463                     fputc(8, ttyfp);
464                     fputc(32, ttyfp);
465                     fputc(8, ttyfp);
466                     fflush(ttyfp);
467                 }
468             } else {
469                 fputc(7, ttyfp);
470                 fflush(ttyfp);
471             }
472             continue;
473         } else if (c == (int) '\t') { /* Tab */
474             c = ' ';
475         } else if (c > 0xa0) {
476             ; /* we don't allow 0xa0, as this is a protected blank which may
477                * confuse the user */
478         } else if (iscntrl(c)) {
479             continue;
480         }
481         if(!(i < n-1)) {
482             n += 50;
483             buf = xrealloc (buf, n);
484         }
485         buf[i++] = c;
486         if (!hidden) {
487             last_prompt_len++;
488             fputc(c, ttyfp);
489             fflush(ttyfp);
490         }
491     } while (c != '\n');
492     i = (i>0) ? i-1 : 0;
493 #else /* unix version */
494     if( hidden ) {
495 #ifdef HAVE_TCGETATTR
496         struct termios term;
497
498         if( tcgetattr(fileno(ttyfp), &termsave) )
499             log_fatal("tcgetattr() failed: %s\n", strerror(errno) );
500         restore_termios = 1;
501         term = termsave;
502         term.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
503         if( tcsetattr( fileno(ttyfp), TCSAFLUSH, &term ) )
504             log_fatal("tcsetattr() failed: %s\n", strerror(errno) );
505 #endif
506     }
507
508     /* fixme: How can we avoid that the \n is echoed w/o disabling
509      * canonical mode - w/o this kill_prompt can't work */
510     while( read(fileno(ttyfp), cbuf, 1) == 1 && *cbuf != '\n' ) {
511         if( !hidden )
512             last_prompt_len++;
513         c = *cbuf;
514         if( c == CONTROL_D )
515             log_info("control d found\n");
516         if( c == '\t' )
517             c = ' ';
518         else if( c > 0xa0 )
519             ; /* we don't allow 0xa0, as this is a protected blank which may
520                * confuse the user */
521         else if( iscntrl(c) )
522             continue;
523         if( !(i < n-1) ) {
524             n += 50;
525             buf = xrealloc (buf, n );
526         }
527         buf[i++] = c;
528     }
529     if( *cbuf != '\n' ) {
530         buf[0] = CONTROL_D;
531         i = 1;
532     }
533
534
535     if( hidden ) {
536 #ifdef HAVE_TCGETATTR
537         if( tcsetattr(fileno(ttyfp), TCSAFLUSH, &termsave) )
538             log_error("tcsetattr() failed: %s\n", strerror(errno) );
539         restore_termios = 0;
540 #endif
541     }
542 #endif /* end unix version */
543     buf[i] = 0;
544     return buf;
545 }
546
547
548 char *
549 tty_get( const char *prompt )
550 {
551     return do_get( prompt, 0 );
552 }
553
554 char *
555 tty_get_hidden( const char *prompt )
556 {
557     return do_get( prompt, 1 );
558 }
559
560
561 void
562 tty_kill_prompt()
563 {
564     if ( no_terminal )
565         return;
566
567     if( !initialized )
568         init_ttyfp();
569
570     if( batchmode )
571         last_prompt_len = 0;
572     if( !last_prompt_len )
573         return;
574 #ifdef _WIN32
575     tty_printf("\r%*s\r", last_prompt_len, "");
576 #else
577     {
578         int i;
579         putc('\r', ttyfp);
580         for(i=0; i < last_prompt_len; i ++ )
581             putc(' ', ttyfp);
582         putc('\r', ttyfp);
583         fflush(ttyfp);
584     }
585 #endif
586     last_prompt_len = 0;
587 }
588
589
590 int
591 tty_get_answer_is_yes( const char *prompt )
592 {
593     int yes;
594     char *p = tty_get( prompt );
595     tty_kill_prompt();
596     yes = answer_is_yes(p);
597     xfree(p);
598     return yes;
599 }