g10: Prefer to available card keys for decryption.
[gnupg.git] / common / ttyio.c
index 5b10915..c7c9d85 100644 (file)
@@ -1,23 +1,31 @@
 /* ttyio.c -  tty i/O functions
- * Copyright (C) 1998,1999,2000,2001,2002,2003,
- *               2004, 2006 Free Software Foundation, Inc.
+ * Copyright (C) 1998,1999,2000,2001,2002,2003,2004,2006,2007,
+ *               2009, 2010 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
- * GnuPG is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
  *
- * GnuPG is distributed in the hope that it will be useful,
+ *   - the GNU Lesser General Public License as published by the Free
+ *     Software Foundation; either version 3 of the License, or (at
+ *     your option) any later version.
+ *
+ * or
+ *
+ *   - the GNU General Public License as published by the Free
+ *     Software Foundation; either version 2 of the License, or (at
+ *     your option) any later version.
+ *
+ * or both in parallel, as here.
+ *
+ * This file is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
- * USA.
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
  */
 
 #include <config.h>
 #include <string.h>
 #include <stdarg.h>
 #include <unistd.h>
+
+#if defined(HAVE_W32_SYSTEM) && !defined(HAVE_W32CE_SYSTEM)
+# define USE_W32_CONSOLE 1
+#endif
+
 #ifdef HAVE_TCGETATTR
 #include <termios.h>
 #else
 #define HAVE_TCGETATTR
 #endif
 #endif
-#ifdef _WIN32 /* use the odd Win32 functions */
-#include <windows.h>
-#ifdef HAVE_TCGETATTR
-#error mingw32 and termios
-#endif
+#ifdef USE_W32_CONSOLE
+# ifdef HAVE_WINSOCK2_H
+#  include <winsock2.h>
+# endif
+# include <windows.h>
+# ifdef HAVE_TCGETATTR
+#  error mingw32 and termios
+# endif
 #endif
 #include <errno.h>
 #include <ctype.h>
 
 #include "util.h"
 #include "ttyio.h"
-#include "estream-printf.h"
 #include "common-defs.h"
 
 #define CONTROL_D ('D' - 'A' + 1)
 
-#ifdef _WIN32 /* use the odd Win32 functions */
+
+#ifdef USE_W32_CONSOLE
 static struct {
     HANDLE in, out;
 } con;
@@ -118,8 +134,8 @@ tty_get_ttyname (void)
       got_name = 1;
     }
 #endif /*HAVE_CTERMID*/
-  /* Assume the standard tty on memory error or when tehre is no
-     certmid. */
+  /* Assume the standard tty on memory error or when there is no
+     ctermid. */
   return name? name : "/dev/tty";
 }
 
@@ -143,7 +159,7 @@ init_ttyfp(void)
     if( initialized )
        return;
 
-#if defined(_WIN32)
+#if defined(USE_W32_CONSOLE)
     {
        SECURITY_ATTRIBUTES sa;
 
@@ -171,17 +187,19 @@ init_ttyfp(void)
     ttyfp = stdout; /* Fixme: replace by the real functions: see wklib */
     if (my_rl_init_stream)
       my_rl_init_stream (ttyfp);
+#elif defined (HAVE_W32CE_SYSTEM)
+    ttyfp = stderr;
 #else
     ttyfp = batchmode? stderr : fopen (tty_get_ttyname (), "r+");
     if( !ttyfp ) {
-       log_error("cannot open `%s': %s\n", tty_get_ttyname (),
+       log_error("cannot open '%s': %s\n", tty_get_ttyname (),
                   strerror(errno) );
        exit(2);
     }
     if (my_rl_init_stream)
       my_rl_init_stream (ttyfp);
 #endif
-    
+
 
 #ifdef HAVE_TCGETATTR
     atexit( cleanup );
@@ -219,8 +237,8 @@ tty_printf( const char *fmt, ... )
        init_ttyfp();
 
     va_start( arg_ptr, fmt ) ;
-#ifdef _WIN32
-    {   
+#ifdef USE_W32_CONSOLE
+    {
         char *buf = NULL;
         int n;
        DWORD nwritten;
@@ -228,7 +246,7 @@ tty_printf( const char *fmt, ... )
        n = vasprintf(&buf, fmt, arg_ptr);
        if( !buf )
            log_bug("vasprintf() failed\n");
-        
+
        if( !WriteConsoleA( con.out, buf, n, &nwritten, NULL ) )
            log_fatal("WriteConsole failed: rc=%d", (int)GetLastError() );
        if( n != nwritten )
@@ -247,14 +265,14 @@ tty_printf( const char *fmt, ... )
 /* Same as tty_printf but if FP is not NULL, behave like a regular
    fprintf. */
 void
-tty_fprintf (FILE *fp, const char *fmt, ... )
+tty_fprintf (estream_t fp, const char *fmt, ... )
 {
   va_list arg_ptr;
 
   if (fp)
     {
       va_start (arg_ptr, fmt) ;
-      vfprintf (fp, fmt, arg_ptr );
+      es_vfprintf (fp, fmt, arg_ptr );
       va_end (arg_ptr);
       return;
     }
@@ -262,83 +280,95 @@ tty_fprintf (FILE *fp, const char *fmt, ... )
   if (no_terminal)
     return;
 
-  if( !initialized )
-    init_ttyfp();
-
-    va_start( arg_ptr, fmt ) ;
-#ifdef _WIN32
-    {   
-        char *buf = NULL;
-        int n;
-       DWORD nwritten;
-
-       n = vasprintf(&buf, fmt, arg_ptr);
-       if( !buf )
-           log_bug("vasprintf() failed\n");
-        
-       if( !WriteConsoleA( con.out, buf, n, &nwritten, NULL ) )
-           log_fatal("WriteConsole failed: rc=%d", (int)GetLastError() );
-       if( n != nwritten )
-           log_fatal("WriteConsole failed: %d != %d\n", n, (int)nwritten );
-       last_prompt_len += n;
-        xfree (buf);
-    }
+  if (!initialized)
+    init_ttyfp ();
+
+  va_start (arg_ptr, fmt);
+#ifdef USE_W32_CONSOLE
+  {
+    char *buf = NULL;
+    int n;
+    DWORD nwritten;
+
+    n = vasprintf(&buf, fmt, arg_ptr);
+    if (!buf)
+      log_bug("vasprintf() failed\n");
+
+    if (!WriteConsoleA( con.out, buf, n, &nwritten, NULL ))
+      log_fatal("WriteConsole failed: rc=%d", (int)GetLastError() );
+    if (n != nwritten)
+      log_fatal("WriteConsole failed: %d != %d\n", n, (int)nwritten );
+    last_prompt_len += n;
+    xfree (buf);
+  }
 #else
-    last_prompt_len += vfprintf(ttyfp,fmt,arg_ptr) ;
-    fflush(ttyfp);
+  last_prompt_len += vfprintf(ttyfp,fmt,arg_ptr) ;
+  fflush(ttyfp);
 #endif
-    va_end(arg_ptr);
+  va_end(arg_ptr);
 }
 
 
-/****************
- * Print a string, but filter all control characters out.
- */
-void
-tty_print_string ( const byte *p, size_t n )
+/* Print a string, but filter all control characters out.  If FP is
+ * not NULL print to that stream instead to the tty.  */
+static void
+do_print_string (estream_t fp, const byte *p, size_t n )
 {
-    if (no_terminal)
-       return;
+  if (no_terminal && !fp)
+    return;
 
-    if( !initialized )
-       init_ttyfp();
+  if (!initialized && !fp)
+    init_ttyfp();
 
-#ifdef _WIN32
-    /* not so effective, change it if you want */
-    for( ; n; n--, p++ )
-       if( iscntrl( *p ) ) {
-           if( *p == '\n' )
-               tty_printf("\\n");
-           else if( !*p )
-               tty_printf("\\0");
-           else
-               tty_printf("\\x%02x", *p);
-       }
-       else
-           tty_printf("%c", *p);
+  if (fp)
+    {
+      print_utf8_buffer (fp, p, n);
+      return;
+    }
+
+#ifdef USE_W32_CONSOLE
+  /* Not so effective, change it if you want */
+  for (; n; n--, p++)
+    {
+      if (iscntrl (*p))
+        {
+          if( *p == '\n' )
+            tty_printf ("\\n");
+          else if( !*p )
+            tty_printf ("\\0");
+          else
+            tty_printf ("\\x%02x", *p);
+        }
+      else
+        tty_printf ("%c", *p);
+    }
 #else
-    for( ; n; n--, p++ )
-       if( iscntrl( *p ) ) {
-           putc('\\', ttyfp);
-           if( *p == '\n' )
-               putc('n', ttyfp);
-           else if( !*p )
-               putc('0', ttyfp);
-           else
-               fprintf(ttyfp, "x%02x", *p );
-       }
-       else
-           putc(*p, ttyfp);
+  for (; n; n--, p++)
+    {
+      if (iscntrl (*p))
+        {
+          putc ('\\', ttyfp);
+          if ( *p == '\n' )
+            putc ('n', ttyfp);
+          else if ( !*p )
+            putc ('0', ttyfp);
+          else
+            fprintf (ttyfp, "x%02x", *p );
+        }
+      else
+        putc (*p, ttyfp);
+    }
 #endif
 }
 
+
 void
-tty_print_utf8_string2( const byte *p, size_t n, size_t max_n )
+tty_print_utf8_string2 (estream_t fp, const byte *p, size_t n, size_t max_n)
 {
     size_t i;
     char *buf;
 
-    if (no_terminal)
+    if (no_terminal && !fp)
        return;
 
     /* we can handle plain ascii simpler, so check for it first */
@@ -352,21 +382,22 @@ tty_print_utf8_string2( const byte *p, size_t n, size_t max_n )
            buf[max_n] = 0;
        }
        /*(utf8 conversion already does the control character quoting)*/
-       tty_printf("%s", buf );
-       xfree( buf );
+       tty_fprintf (fp, "%s", buf);
+       xfree (buf);
     }
     else {
        if( max_n && (n > max_n) ) {
            n = max_n;
        }
-       tty_print_string( p, n );
+       do_print_string (fp, p, n );
     }
 }
 
+
 void
 tty_print_utf8_string( const byte *p, size_t n )
 {
-    tty_print_utf8_string2( p, n, 0 );
+  tty_print_utf8_string2 (NULL, p, n, 0);
 }
 
 
@@ -397,7 +428,7 @@ do_get( const char *prompt, int hidden )
     buf = xmalloc((n=50));
     i = 0;
 
-#ifdef _WIN32 /* windoze version */
+#ifdef USE_W32_CONSOLE
     if( hidden )
        SetConsoleMode(con.in, HID_INPMODE );
 
@@ -431,9 +462,17 @@ do_get( const char *prompt, int hidden )
     if( hidden )
        SetConsoleMode(con.in, DEF_INPMODE );
 
-#elif defined(__riscos__)
+#elif defined(__riscos__) || defined(HAVE_W32CE_SYSTEM)
     do {
+#ifdef HAVE_W32CE_SYSTEM
+      /* Using getchar is not a correct solution but for now it
+         doesn't matter because we have no real console at all.  We
+         should rework this as soon as we have switched this entire
+         module to estream.  */
+        c = getchar();
+#else
         c = riscos_getchar();
+#endif
         if (c == 0xa || c == 0xd) { /* Return || Enter */
             c = (int) '\n';
         } else if (c == 0x8 || c == 0x7f) { /* Backspace || Delete */
@@ -471,7 +510,7 @@ do_get( const char *prompt, int hidden )
         }
     } while (c != '\n');
     i = (i>0) ? i-1 : 0;
-#else /* unix version */
+#else /* Other systems. */
     if( hidden ) {
 #ifdef HAVE_TCGETATTR
        struct termios term;
@@ -512,7 +551,6 @@ do_get( const char *prompt, int hidden )
        i = 1;
     }
 
-
     if( hidden ) {
 #ifdef HAVE_TCGETATTR
        if( tcsetattr(fileno(ttyfp), TCSAFLUSH, &termsave) )
@@ -533,7 +571,7 @@ tty_get( const char *prompt )
     {
       char *line;
       char *buf;
-      
+
       if (!initialized)
        init_ttyfp();
 
@@ -564,7 +602,7 @@ tty_get( const char *prompt )
     return do_get ( prompt, 0 );
 }
 
-/* Variable argument version of tty_get.  The prompt is is actually a
+/* Variable argument version of tty_get.  The prompt is actually a
    format string with arguments.  */
 char *
 tty_getf (const char *promptfmt, ... )
@@ -574,7 +612,7 @@ tty_getf (const char *promptfmt, ... )
   char *answer;
 
   va_start (arg_ptr, promptfmt);
-  if (estream_vasprintf (&prompt, promptfmt, arg_ptr) < 0)
+  if (gpgrt_vasprintf (&prompt, promptfmt, arg_ptr) < 0)
     log_fatal ("estream_vasprintf failed: %s\n", strerror (errno));
   va_end (arg_ptr);
   answer = tty_get (prompt);
@@ -604,7 +642,7 @@ tty_kill_prompt()
        last_prompt_len = 0;
     if( !last_prompt_len )
        return;
-#ifdef _WIN32
+#ifdef USE_W32_CONSOLE
     tty_printf("\r%*s\r", last_prompt_len, "");
 #else
     {
@@ -650,6 +688,7 @@ tty_private_set_rl_hooks (void (*init_stream) (FILE *),
 }
 
 
+#ifdef HAVE_LIBREADLINE
 void
 tty_enable_completion (rl_completion_func_t *completer)
 {
@@ -673,7 +712,15 @@ tty_disable_completion (void)
 
   my_rl_inhibit_completion (1);
 }
+#endif
 
+void
+tty_cleanup_after_signal (void)
+{
+#ifdef HAVE_TCGETATTR
+  cleanup ();
+#endif
+}
 
 void
 tty_cleanup_rl_after_signal (void)