gpg: Introduce magic value 25519 to switch a card to ECC.
[gnupg.git] / g10 / cpr.c
index 72d23b9..1548720 100644 (file)
--- a/g10/cpr.c
+++ b/g10/cpr.c
@@ -1,4 +1,4 @@
-/* status.c - Status message and command-fd interface 
+/* status.c - Status message and command-fd interface
  * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003,
  *               2004, 2005, 2006, 2010 Free Software Foundation, Inc.
  *
@@ -15,7 +15,7 @@
  * 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, see <http://www.gnu.org/licenses/>.
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
  */
 
 #include <config.h>
 #endif
 
 #include "gpg.h"
-#include "util.h"
-#include "status.h"
-#include "ttyio.h"
+#include "../common/util.h"
+#include "../common/status.h"
+#include "../common/ttyio.h"
 #include "options.h"
 #include "main.h"
-#include "i18n.h"
-#include "cipher.h" /* for progress functions */
+#include "../common/i18n.h"
 
 #define CONTROL_D ('D' - 'A' + 1)
 
@@ -54,9 +53,9 @@ progress_cb (void *ctx, const char *what, int printchar,
   (void)ctx;
 
   if ( printchar == '\n' && !strcmp (what, "primegen") )
-    snprintf (buf, sizeof buf -1, "%.20s X 100 100", what );
+    snprintf (buf, sizeof buf, "%.20s X 100 100", what );
   else
-    snprintf (buf, sizeof buf -1, "%.20s %c %d %d",
+    snprintf (buf, sizeof buf, "%.20s %c %d %d",
               what, printchar=='\n'?'X':printchar, current, total );
   write_status_text (STATUS_PROGRESS, buf);
 }
@@ -74,17 +73,17 @@ status_currently_allowed (int no)
     return 1; /* Yes. */
 
   /* We allow some statis anyway, so that import statistics are
-     correct and to avoid problems if the retriebval subsystem will
+     correct and to avoid problems if the retrieval subsystem will
      prompt the user. */
   switch (no)
     {
-    case STATUS_GET_BOOL:       
-    case STATUS_GET_LINE:       
-    case STATUS_GET_HIDDEN:     
-    case STATUS_GOT_IT:         
+    case STATUS_GET_BOOL:
+    case STATUS_GET_LINE:
+    case STATUS_GET_HIDDEN:
+    case STATUS_GOT_IT:
     case STATUS_IMPORTED:
-    case STATUS_IMPORT_OK:     
-    case STATUS_IMPORT_CHECK:  
+    case STATUS_IMPORT_OK:
+    case STATUS_IMPORT_CHECK:
     case STATUS_IMPORT_RES:
       return 1; /* Yes. */
     default:
@@ -98,16 +97,19 @@ void
 set_status_fd (int fd)
 {
   static int last_fd = -1;
-  
+
   if (fd != -1 && last_fd == fd)
     return;
 
   if (statusfp && statusfp != es_stdout && statusfp != es_stderr )
     es_fclose (statusfp);
   statusfp = NULL;
-  if (fd == -1) 
+  if (fd == -1)
     return;
-  
+
+  if (! gnupg_fd_valid (fd))
+    log_fatal ("status-fd is invalid: %s\n", strerror (errno));
+
   if (fd == 1)
     statusfp = es_stdout;
   else if (fd == 2)
@@ -139,26 +141,38 @@ write_status ( int no )
 }
 
 
+/* Write a status line with code NO followed by the string TEXT and
+   directly followed by the remaining strings up to a NULL. */
 void
-write_status_text (int no, const char *text)
+write_status_strings (int no, const char *text, ...)
 {
+  va_list arg_ptr;
+  const char *s;
+
   if (!statusfp || !status_currently_allowed (no) )
     return;  /* Not enabled or allowed. */
 
   es_fputs ("[GNUPG:] ", statusfp);
   es_fputs (get_status_string (no), statusfp);
-  if ( text ) 
+  if ( text )
     {
       es_putc ( ' ', statusfp);
-      for (; *text; text++)
+      va_start (arg_ptr, text);
+      s = text;
+      do
         {
-          if (*text == '\n')
-            es_fputs ("\\n", statusfp);
-          else if (*text == '\r')
-            es_fputs ("\\r", statusfp);
-          else 
-            es_fputc ( *(const byte *)text, statusfp);
+          for (; *s; s++)
+            {
+              if (*s == '\n')
+                es_fputs ("\\n", statusfp);
+              else if (*s == '\r')
+                es_fputs ("\\r", statusfp);
+              else
+                es_fputc (*(const byte *)s, statusfp);
+            }
         }
+      while ((s = va_arg (arg_ptr, const char*)));
+      va_end (arg_ptr);
     }
   es_putc ('\n', statusfp);
   if (es_fflush (statusfp) && opt.exit_on_status_write_error)
@@ -166,14 +180,47 @@ write_status_text (int no, const char *text)
 }
 
 
-/* Wrte an ERROR status line using a full gpg-error error value.  */
+void
+write_status_text (int no, const char *text)
+{
+  write_status_strings (no, text, NULL);
+}
+
+
+/* Write a status line with code NO followed by the outout of the
+ * printf style FORMAT.  The caller needs to make sure that LFs and
+ * CRs are not printed.  */
+void
+write_status_printf (int no, const char *format, ...)
+{
+  va_list arg_ptr;
+
+  if (!statusfp || !status_currently_allowed (no) )
+    return;  /* Not enabled or allowed. */
+
+  es_fputs ("[GNUPG:] ", statusfp);
+  es_fputs (get_status_string (no), statusfp);
+  if (format)
+    {
+      es_putc ( ' ', statusfp);
+      va_start (arg_ptr, format);
+      es_vfprintf (statusfp, format, arg_ptr);
+      va_end (arg_ptr);
+    }
+  es_putc ('\n', statusfp);
+  if (es_fflush (statusfp) && opt.exit_on_status_write_error)
+    g10_exit (0);
+}
+
+
+/* Write an ERROR status line using a full gpg-error error value.  */
 void
 write_status_error (const char *where, gpg_error_t err)
 {
   if (!statusfp || !status_currently_allowed (STATUS_ERROR))
     return;  /* Not enabled or allowed. */
 
-  es_fprintf (statusfp, "[GNUPG:] %s %s %u\n", 
+  es_fprintf (statusfp, "[GNUPG:] %s %s %u\n",
               get_status_string (STATUS_ERROR), where, err);
   if (es_fflush (statusfp) && opt.exit_on_status_write_error)
     g10_exit (0);
@@ -187,13 +234,27 @@ write_status_errcode (const char *where, int errcode)
   if (!statusfp || !status_currently_allowed (STATUS_ERROR))
     return;  /* Not enabled or allowed. */
 
-  es_fprintf (statusfp, "[GNUPG:] %s %s %u\n", 
+  es_fprintf (statusfp, "[GNUPG:] %s %s %u\n",
               get_status_string (STATUS_ERROR), where, gpg_err_code (errcode));
   if (es_fflush (statusfp) && opt.exit_on_status_write_error)
     g10_exit (0);
 }
 
 
+/* Write a FAILURE status line.  */
+void
+write_status_failure (const char *where, gpg_error_t err)
+{
+  if (!statusfp || !status_currently_allowed (STATUS_FAILURE))
+    return;  /* Not enabled or allowed. */
+
+  es_fprintf (statusfp, "[GNUPG:] %s %s %u\n",
+              get_status_string (STATUS_FAILURE), where, err);
+  if (es_fflush (statusfp) && opt.exit_on_status_write_error)
+    g10_exit (0);
+}
+
+
 /*
  * Write a status line with a buffer using %XX escapes.  If WRAP is >
  * 0 wrap the line after this length.  If STRING is not NULL it will
@@ -211,7 +272,7 @@ write_status_text_and_buffer (int no, const char *string,
 
   if (!statusfp || !status_currently_allowed (no))
     return;  /* Not enabled or allowed. */
-    
+
   if (wrap == -1)
     {
       lower_limit--;
@@ -220,7 +281,7 @@ write_status_text_and_buffer (int no, const char *string,
 
   text = get_status_string (no);
   count = dowrap = first = 1;
-  do 
+  do
     {
       if (dowrap)
         {
@@ -241,8 +302,8 @@ write_status_text_and_buffer (int no, const char *string,
         }
       for (esc=0, s=buffer, n=len; n && !esc; s++, n--)
         {
-          if (*s == '%' || *(const byte*)s <= lower_limit 
-              || *(const byte*)s == 127 ) 
+          if (*s == '%' || *(const byte*)s <= lower_limit
+              || *(const byte*)s == 127 )
             esc = 1;
           if (wrap && ++count > wrap)
             {
@@ -250,13 +311,13 @@ write_status_text_and_buffer (int no, const char *string,
               break;
             }
         }
-      if (esc) 
+      if (esc)
         {
           s--; n++;
         }
-      if (s != buffer) 
+      if (s != buffer)
         es_fwrite (buffer, s-buffer, 1, statusfp);
-      if ( esc ) 
+      if ( esc )
         {
           es_fprintf (statusfp, "%%%02X", *(const byte*)s );
           s++; n--;
@@ -265,7 +326,7 @@ write_status_text_and_buffer (int no, const char *string,
       len = n;
       if (dowrap && len)
         es_putc ('\n', statusfp);
-    } 
+    }
   while (len);
 
   es_putc ('\n',statusfp);
@@ -290,24 +351,19 @@ write_status_begin_signing (gcry_md_hd_t md)
     {
       char buf[100];
       size_t buflen;
-      int i;
-      
-      /* We use a hard coded list of possible algorithms.  Using other
-         algorithms than specified by OpenPGP does not make sense
-         anyway.  We do this out of performance reasons: Walking all
-         the 110 allowed Ids is not a good idea given the way the
-         check is implemented in libgcrypt.  Recall that the only use
-         of this status code is to create the micalg algorithm for
-         PGP/MIME. */
+      int i, ga;
+
       buflen = 0;
-      for (i=1; i <= 11; i++)
-        if (i < 4 || i > 7)
-          if (gcry_md_is_enabled (md, i) && buflen < DIM(buf))
+      for (i=1; i <= 110; i++)
+        {
+          ga = map_md_openpgp_to_gcry (i);
+          if (ga && gcry_md_is_enabled (md, ga) && buflen+10 < DIM(buf))
             {
-              snprintf (buf+buflen, DIM(buf) - buflen - 1, 
+              snprintf (buf+buflen, DIM(buf) - buflen,
                         "%sH%d", buflen? " ":"",i);
               buflen += strlen (buf+buflen);
             }
+        }
       write_status_text (STATUS_BEGIN_SIGNING, buf);
     }
   else
@@ -319,10 +375,10 @@ static int
 myread(int fd, void *buf, size_t count)
 {
   int rc;
-  do 
+  do
     {
       rc = read( fd, buf, count );
-    } 
+    }
   while (rc == -1 && errno == EINTR);
 
   if (!rc && count)
@@ -335,7 +391,7 @@ myread(int fd, void *buf, size_t count)
           eof_emmited++;
         }
       else /* Ctrl-D not caught - do something reasonable */
-        { 
+        {
 #ifdef HAVE_DOSISH_SYSTEM
 #ifndef HAVE_W32CE_SYSTEM
           raise (SIGINT); /* Nothing to hangup under DOS.  */
@@ -344,7 +400,7 @@ myread(int fd, void *buf, size_t count)
           raise (SIGHUP); /* No more input data.  */
 #endif
         }
-    }    
+    }
   return rc;
 }
 
@@ -352,22 +408,22 @@ myread(int fd, void *buf, size_t count)
 
 /* Request a string from the client over the command-fd.  If GETBOOL
    is set the function returns a static string (do not free) if the
-   netered value was true or NULL if the entered value was false.  */
+   entered value was true or NULL if the entered value was false.  */
 static char *
 do_get_from_fd ( const char *keyword, int hidden, int getbool )
 {
   int i, len;
   char *string;
-  
+
   if (statusfp != es_stdout)
     es_fflush (es_stdout);
-  
+
   write_status_text (getbool? STATUS_GET_BOOL :
                      hidden? STATUS_GET_HIDDEN : STATUS_GET_LINE, keyword);
 
-  for (string = NULL, i = len = 200; ; i++ ) 
+  for (string = NULL, i = len = 200; ; i++ )
     {
-      if (i >= len-1 ) 
+      if (i >= len-1 )
         {
           char *save = string;
           len += 100;
@@ -380,7 +436,7 @@ do_get_from_fd ( const char *keyword, int hidden, int getbool )
       /* Fixme: why not use our read_line function here? */
       if ( myread( opt.command_fd, string+i, 1) != 1 || string[i] == '\n'  )
         break;
-      else if ( string[i] == CONTROL_D ) 
+      else if ( string[i] == CONTROL_D )
         {
           /* Found ETX - Cancel the line and return a sole ETX.  */
           string[0] = CONTROL_D;
@@ -481,7 +537,7 @@ cpr_kill_prompt(void)
 }
 
 int
-cpr_get_answer_is_yes( const char *keyword, const char *prompt )
+cpr_get_answer_is_yes_def (const char *keyword, const char *prompt, int def_yes)
 {
     int yes;
     char *p;
@@ -497,7 +553,7 @@ cpr_get_answer_is_yes( const char *keyword, const char *prompt )
        }
        else {
            tty_kill_prompt();
-           yes = answer_is_yes(p);
+           yes = answer_is_yes_no_default (p, def_yes);
            xfree(p);
            return yes;
        }
@@ -505,6 +561,12 @@ cpr_get_answer_is_yes( const char *keyword, const char *prompt )
 }
 
 int
+cpr_get_answer_is_yes (const char *keyword, const char *prompt)
+{
+  return cpr_get_answer_is_yes_def (keyword, prompt, 0);
+}
+
+int
 cpr_get_answer_yes_no_quit( const char *keyword, const char *prompt )
 {
     int yes;