* g10u.c: Dead code. Remove.
[gnupg.git] / util / ttyio.c
1 /* ttyio.c -  tty i/O functions
2  * Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
3  *
4  * This file is part of GnuPG.
5  *
6  * GnuPG is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * GnuPG is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
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 #include "util.h"
49 #include "memory.h"
50 #include "ttyio.h"
51
52 #define CONTROL_D ('D' - 'A' + 1)
53
54 #ifdef _WIN32 /* use the odd Win32 functions */
55 static struct {
56     HANDLE in, out;
57 } con;
58 #define DEF_INPMODE  (ENABLE_LINE_INPUT|ENABLE_ECHO_INPUT    \
59                                         |ENABLE_PROCESSED_INPUT )
60 #define HID_INPMODE  (ENABLE_LINE_INPUT|ENABLE_PROCESSED_INPUT )
61 #define DEF_OUTMODE  (ENABLE_WRAP_AT_EOL_OUTPUT|ENABLE_PROCESSED_OUTPUT)
62
63 #else /* yeah, we have a real OS */
64 static FILE *ttyfp = NULL;
65 #endif
66
67 static int initialized;
68 static int last_prompt_len;
69 static int batchmode;
70 static int no_terminal;
71
72 #ifdef HAVE_TCGETATTR
73     static struct termios termsave;
74     static int restore_termios;
75 #endif
76
77
78
79 /* This is a wrapper around ttyname so that we can use it even when
80    the standard streams are redirected.  It figures the name out the
81    first time and returns it in a statically allocated buffer. */
82 const char *
83 tty_get_ttyname (void)
84 {
85   static char *name;
86
87   /* On a GNU system ctermid() always return /dev/tty, so this does
88      not make much sense - however if it is ever changed we do the
89      Right Thing now. */
90 #ifdef HAVE_CTERMID
91   static int got_name;
92
93   if (!got_name)
94     {
95       const char *s;
96       s = ctermid (NULL);
97       if (s)
98         name = strdup (s);
99       got_name = 1;
100     }
101 #endif
102   /* Assume the standard tty on memory error or when there is no
103      ctermid. */
104   return name? name : "/dev/tty";
105 }
106
107
108 #ifdef HAVE_TCGETATTR
109 static void
110 cleanup(void)
111 {
112     if( restore_termios ) {
113         restore_termios = 0; /* do it prios in case it is interrupted again */
114         if( tcsetattr(fileno(ttyfp), TCSAFLUSH, &termsave) )
115             log_error("tcsetattr() failed: %s\n", strerror(errno) );
116     }
117 }
118 #endif
119
120 static void
121 init_ttyfp(void)
122 {
123     if( initialized )
124         return;
125
126 #if defined(_WIN32)
127     {
128         SECURITY_ATTRIBUTES sa;
129
130         memset(&sa, 0, sizeof(sa));
131         sa.nLength = sizeof(sa);
132         sa.bInheritHandle = TRUE;
133         con.out = CreateFileA( "CONOUT$", GENERIC_READ|GENERIC_WRITE,
134                                FILE_SHARE_READ|FILE_SHARE_WRITE,
135                                &sa, OPEN_EXISTING, 0, 0 );
136         if( con.out == INVALID_HANDLE_VALUE )
137             log_fatal("open(CONOUT$) failed: rc=%d", (int)GetLastError() );
138         memset(&sa, 0, sizeof(sa));
139         sa.nLength = sizeof(sa);
140         sa.bInheritHandle = TRUE;
141         con.in = CreateFileA( "CONIN$", GENERIC_READ|GENERIC_WRITE,
142                                FILE_SHARE_READ|FILE_SHARE_WRITE,
143                                &sa, OPEN_EXISTING, 0, 0 );
144         if( con.in == INVALID_HANDLE_VALUE )
145             log_fatal("open(CONIN$) failed: rc=%d", (int)GetLastError() );
146     }
147     SetConsoleMode(con.in, DEF_INPMODE );
148     SetConsoleMode(con.out, DEF_OUTMODE );
149
150 #elif defined(__EMX__)
151     ttyfp = stdout; /* Fixme: replace by the real functions: see wklib */
152 #else
153     ttyfp = batchmode? stderr : fopen( tty_get_ttyname (), "r+");
154     if( !ttyfp ) {
155         log_error("cannot open `%s': %s\n",
156                   tty_get_ttyname (), strerror(errno) );
157         exit(2);
158     }
159 #endif
160 #ifdef HAVE_TCGETATTR
161     atexit( cleanup );
162 #endif
163     initialized = 1;
164 }
165
166 int
167 tty_batchmode( int onoff )
168 {
169     int old = batchmode;
170     if( onoff != -1 )
171         batchmode = onoff;
172     return old;
173 }
174
175 int
176 tty_no_terminal(int onoff)
177 {
178     int old = no_terminal;
179     no_terminal = onoff ? 1 : 0;
180     return old;
181 }
182
183 void
184 tty_printf( const char *fmt, ... )
185 {
186     va_list arg_ptr;
187
188     if (no_terminal)
189         return;
190
191     if( !initialized )
192         init_ttyfp();
193
194     va_start( arg_ptr, fmt ) ;
195 #ifdef _WIN32
196     {   
197         char *buf = NULL;
198         int n;
199         DWORD nwritten;
200
201         n = vasprintf(&buf, fmt, arg_ptr);
202         if( !buf )
203             log_bug("vasprintf() failed\n");
204         
205         if( !WriteConsoleA( con.out, buf, n, &nwritten, NULL ) )
206             log_fatal("WriteConsole failed: rc=%d", (int)GetLastError() );
207         if( n != nwritten )
208             log_fatal("WriteConsole failed: %d != %d\n", n, (int)nwritten );
209         last_prompt_len += n;
210         m_free (buf);
211     }
212 #else
213     last_prompt_len += vfprintf(ttyfp,fmt,arg_ptr) ;
214     fflush(ttyfp);
215 #endif
216     va_end(arg_ptr);
217 }
218
219
220 /* Same as tty_printf but if FP is not NULL, behave like the standard
221    fprintf. */
222 void
223 tty_fprintf (FILE *fp, const char *fmt, ... )
224 {
225   va_list arg_ptr;
226
227   if (fp)
228     {
229       va_start (arg_ptr, fmt) ;
230       vfprintf (fp, fmt, arg_ptr );
231       va_end (arg_ptr);
232       return;
233     }
234
235   if (no_terminal)
236     return;
237
238   if( !initialized )
239     init_ttyfp();
240
241     va_start( arg_ptr, fmt ) ;
242 #ifdef _WIN32
243     {   
244         char *buf = NULL;
245         int n;
246         DWORD nwritten;
247
248         n = vasprintf(&buf, fmt, arg_ptr);
249         if( !buf )
250             log_bug("vasprintf() failed\n");
251         
252         if( !WriteConsoleA( con.out, buf, n, &nwritten, NULL ) )
253             log_fatal("WriteConsole failed: rc=%d", (int)GetLastError() );
254         if( n != nwritten )
255             log_fatal("WriteConsole failed: %d != %d\n", n, (int)nwritten );
256         last_prompt_len += n;
257         xfree (buf);
258     }
259 #else
260     last_prompt_len += vfprintf(ttyfp,fmt,arg_ptr) ;
261     fflush(ttyfp);
262 #endif
263     va_end(arg_ptr);
264 }
265
266
267 /****************
268  * Print a string, but filter all control characters out.
269  */
270 void
271 tty_print_string( const byte *p, size_t n )
272 {
273     if (no_terminal)
274         return;
275
276     if( !initialized )
277         init_ttyfp();
278
279 #ifdef _WIN32
280     /* not so effective, change it if you want */
281     for( ; n; n--, p++ )
282         if( iscntrl( *p ) ) {
283             if( *p == '\n' )
284                 tty_printf("\\n");
285             else if( !*p )
286                 tty_printf("\\0");
287             else
288                 tty_printf("\\x%02x", *p);
289         }
290         else
291             tty_printf("%c", *p);
292 #else
293     for( ; n; n--, p++ )
294         if( iscntrl( *p ) ) {
295             putc('\\', ttyfp);
296             if( *p == '\n' )
297                 putc('n', ttyfp);
298             else if( !*p )
299                 putc('0', ttyfp);
300             else
301                 fprintf(ttyfp, "x%02x", *p );
302         }
303         else
304             putc(*p, ttyfp);
305 #endif
306 }
307
308 void
309 tty_print_utf8_string2 (const byte *p, size_t n, size_t max_n )
310 {
311     size_t i;
312     char *buf;
313
314     if (no_terminal)
315         return;
316
317     /* we can handle plain ascii simpler, so check for it first */
318     for(i=0; i < n; i++ ) {
319         if( p[i] & 0x80 )
320             break;
321     }
322     if( i < n ) {
323         buf = utf8_to_native( p, n, 0 );
324         if( max_n && (strlen( buf ) > max_n )) {
325             buf[max_n] = 0;
326         }
327         /*(utf8 conversion already does the control character quoting)*/
328         tty_printf("%s", buf );
329         m_free( buf );
330     }
331     else {
332         if( max_n && (n > max_n) ) {
333             n = max_n;
334         }
335         tty_print_string( p, n );
336     }
337 }
338
339 void
340 tty_print_utf8_string( const byte *p, size_t n )
341 {
342     tty_print_utf8_string2( p, n, 0 );
343 }
344
345
346 static char *
347 do_get( const char *prompt, int hidden )
348 {
349     char *buf;
350 #ifndef __riscos__
351     byte cbuf[1];
352 #endif
353     int c, n, i;
354
355     if( batchmode ) {
356         log_error("Sorry, we are in batchmode - can't get input\n");
357         exit(2);
358     }
359
360     if (no_terminal) {
361         log_error("Sorry, no terminal at all requested - can't get input\n");
362         exit(2);
363     }
364
365     if( !initialized )
366         init_ttyfp();
367
368     last_prompt_len = 0;
369     tty_printf( "%s", prompt );
370     buf = m_alloc(n=50);
371     i = 0;
372
373 #ifdef _WIN32 /* windoze version */
374     if( hidden )
375         SetConsoleMode(con.in, HID_INPMODE );
376
377     for(;;) {
378         DWORD nread;
379
380         if( !ReadConsoleA( con.in, cbuf, 1, &nread, NULL ) )
381             log_fatal("ReadConsole failed: rc=%d", (int)GetLastError() );
382         if( !nread )
383             continue;
384         if( *cbuf == '\n' )
385             break;
386
387         if( !hidden )
388             last_prompt_len++;
389         c = *cbuf;
390         if( c == '\t' )
391             c = ' ';
392         else if( c > 0xa0 )
393             ; /* we don't allow 0xa0, as this is a protected blank which may
394                * confuse the user */
395         else if( iscntrl(c) )
396             continue;
397         if( !(i < n-1) ) {
398             n += 50;
399             buf = m_realloc( buf, n );
400         }
401         buf[i++] = c;
402     }
403
404     if( hidden )
405         SetConsoleMode(con.in, DEF_INPMODE );
406
407 #elif defined(__riscos__)
408     do {
409         c = riscos_getchar();
410         if (c == 0xa || c == 0xd) { /* Return || Enter */
411             c = (int) '\n';
412         } else if (c == 0x8 || c == 0x7f) { /* Backspace || Delete */
413             if (i>0) {
414                 i--;
415                 if (!hidden) {
416                     last_prompt_len--;
417                     fputc(8, ttyfp);
418                     fputc(32, ttyfp);
419                     fputc(8, ttyfp);
420                     fflush(ttyfp);
421                 }
422             } else {
423                 fputc(7, ttyfp);
424                 fflush(ttyfp);
425             }
426             continue;
427         } else if (c == (int) '\t') { /* Tab */
428             c = ' ';
429         } else if (c > 0xa0) {
430             ; /* we don't allow 0xa0, as this is a protected blank which may
431                * confuse the user */
432         } else if (iscntrl(c)) {
433             continue;
434         }
435         if(!(i < n-1)) {
436             n += 50;
437             buf = m_realloc(buf, n);
438         }
439         buf[i++] = c;
440         if (!hidden) {
441             last_prompt_len++;
442             fputc(c, ttyfp);
443             fflush(ttyfp);
444         }
445     } while (c != '\n');
446     i = (i>0) ? i-1 : 0;
447 #else /* unix version */
448     if( hidden ) {
449 #ifdef HAVE_TCGETATTR
450         struct termios term;
451
452         if( tcgetattr(fileno(ttyfp), &termsave) )
453             log_fatal("tcgetattr() failed: %s\n", strerror(errno) );
454         restore_termios = 1;
455         term = termsave;
456         term.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
457         if( tcsetattr( fileno(ttyfp), TCSAFLUSH, &term ) )
458             log_fatal("tcsetattr() failed: %s\n", strerror(errno) );
459 #endif
460     }
461
462     /* fixme: How can we avoid that the \n is echoed w/o disabling
463      * canonical mode - w/o this kill_prompt can't work */
464     while( read(fileno(ttyfp), cbuf, 1) == 1 && *cbuf != '\n' ) {
465         if( !hidden )
466             last_prompt_len++;
467         c = *cbuf;
468         if( c == CONTROL_D )
469             log_info("control d found\n");
470         if( c == '\t' )
471             c = ' ';
472         else if( c > 0xa0 )
473             ; /* we don't allow 0xa0, as this is a protected blank which may
474                * confuse the user */
475         else if( iscntrl(c) )
476             continue;
477         if( !(i < n-1) ) {
478             n += 50;
479             buf = m_realloc( buf, n );
480         }
481         buf[i++] = c;
482     }
483     if( *cbuf != '\n' ) {
484         buf[0] = CONTROL_D;
485         i = 1;
486     }
487
488
489     if( hidden ) {
490 #ifdef HAVE_TCGETATTR
491         if( tcsetattr(fileno(ttyfp), TCSAFLUSH, &termsave) )
492             log_error("tcsetattr() failed: %s\n", strerror(errno) );
493         restore_termios = 0;
494 #endif
495     }
496 #endif /* end unix version */
497     buf[i] = 0;
498     return buf;
499 }
500
501
502 char *
503 tty_get( const char *prompt )
504 {
505     return do_get( prompt, 0 );
506 }
507
508 char *
509 tty_get_hidden( const char *prompt )
510 {
511     return do_get( prompt, 1 );
512 }
513
514
515 void
516 tty_kill_prompt()
517 {
518     if ( no_terminal )
519         return;
520
521     if( !initialized )
522         init_ttyfp();
523
524     if( batchmode )
525         last_prompt_len = 0;
526     if( !last_prompt_len )
527         return;
528 #ifdef _WIN32
529     tty_printf("\r%*s\r", last_prompt_len, "");
530 #else
531     {
532         int i;
533         putc('\r', ttyfp);
534         for(i=0; i < last_prompt_len; i ++ )
535             putc(' ', ttyfp);
536         putc('\r', ttyfp);
537         fflush(ttyfp);
538     }
539 #endif
540     last_prompt_len = 0;
541 }
542
543
544 int
545 tty_get_answer_is_yes( const char *prompt )
546 {
547     int yes;
548     char *p = tty_get( prompt );
549     tty_kill_prompt();
550     yes = answer_is_yes(p);
551     m_free(p);
552     return yes;
553 }