core: New function gpgme_op_tofu_policy
[gpgme.git] / src / engine-gpgconf.c
index b50b635..90f32c7 100644 (file)
@@ -1,6 +1,7 @@
 /* engine-gpgconf.c - gpg-conf engine.
    Copyright (C) 2000 Werner Koch (dd9jn)
-   Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007, 2008 g10 Code GmbH
+   Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007, 2008,
+                 2013 g10 Code GmbH
 
    This file is part of GPGME.
 
@@ -60,14 +61,14 @@ static char *
 gpgconf_get_version (const char *file_name)
 {
   return _gpgme_get_program_version (file_name ? file_name
-                                    : _gpgme_get_gpgconf_path ());
+                                    : _gpgme_get_default_gpgconf_name ());
 }
 
 
 static const char *
 gpgconf_get_req_version (void)
 {
-  return NEED_GPGCONF_VERSION;
+  return "2.0.4";
 }
 
 \f
@@ -89,17 +90,20 @@ gpgconf_release (void *engine)
 
 
 static gpgme_error_t
-gpgconf_new (void **engine, const char *file_name, const char *home_dir)
+gpgconf_new (void **engine, const char *file_name, const char *home_dir,
+             const char *version)
 {
   gpgme_error_t err = 0;
   engine_gpgconf_t gpgconf;
 
+  (void)version; /* Not yet used.  */
+
   gpgconf = calloc (1, sizeof *gpgconf);
   if (!gpgconf)
-    return gpg_error_from_errno (errno);
+    return gpg_error_from_syserror ();
 
   gpgconf->file_name = strdup (file_name ? file_name
-                              : _gpgme_get_gpgconf_path ());
+                              : _gpgme_get_default_gpgconf_name ());
   if (!gpgconf->file_name)
     err = gpg_error_from_syserror ();
 
@@ -191,17 +195,20 @@ gpgconf_config_release (gpgme_conf_comp_t conf)
     }
 }
 
-
+/* Read from gpgconf and pass line after line to the hook function.
+   We put a limit of 64 k on the maximum size for a line.  This should
+   allow for quite a long "group" line, which is usually the longest
+   line (mine is currently ~3k).  */
 static gpgme_error_t
-gpgconf_read (void *engine, char *arg1, char *arg2,
+gpgconf_read (void *engine, const char *arg1, char *arg2,
              gpgme_error_t (*cb) (void *hook, char *line),
              void *hook)
 {
   struct engine_gpgconf *gpgconf = engine;
   gpgme_error_t err = 0;
-#define LINELENGTH 1024
-  char linebuf[LINELENGTH] = "";
-  int linelen = 0;
+  char *linebuf;
+  size_t linebufsize;
+  int linelen;
   char *argv[4] = { NULL /* file_name */, NULL, NULL, NULL };
   int rp[2];
   struct spawn_fd_item_s cfd[] = { {-1, 1 /* STDOUT_FILENO */, -1, 0},
@@ -210,7 +217,7 @@ gpgconf_read (void *engine, char *arg1, char *arg2,
   int nread;
   char *mark = NULL;
 
-  argv[1] = arg1;
+  argv[1] = (char*)arg1;
   argv[2] = arg2;
 
 
@@ -224,7 +231,8 @@ gpgconf_read (void *engine, char *arg1, char *arg2,
 
   cfd[0].fd = rp[1];
 
-  status = _gpgme_io_spawn (gpgconf->file_name, argv, 0, cfd, NULL, NULL, NULL);
+  status = _gpgme_io_spawn (gpgconf->file_name, argv,
+                            IOSPAWN_FLAG_DETACHED, cfd, NULL, NULL, NULL);
   if (status < 0)
     {
       _gpgme_io_close (rp[0]);
@@ -232,51 +240,80 @@ gpgconf_read (void *engine, char *arg1, char *arg2,
       return gpg_error_from_syserror ();
     }
 
-  do
+  linebufsize = 1024; /* Usually enough for conf lines.  */
+  linebuf = malloc (linebufsize);
+  if (!linebuf)
     {
-      nread = _gpgme_io_read (rp[0],
-                              linebuf + linelen, LINELENGTH - linelen - 1);
-      if (nread > 0)
-       {
-          char *line;
-          const char *lastmark = NULL;
-          size_t nused;
-
-         linelen += nread;
-         linebuf[linelen] = '\0';
+      err = gpg_error_from_syserror ();
+      goto leave;
+    }
+  linelen = 0;
 
-         for (line=linebuf; (mark = strchr (line, '\n')); line = mark+1 )
-           {
-              lastmark = mark;
-             if (mark > line && mark[-1] == '\r')
-               mark[-1] = '\0';
-              else
-                mark[0] = '\0';
-
-             /* Got a full line.  Due to the CR removal code (which
-                 occurs only on Windows) we might be one-off and thus
-                 would see empty lines.  Don't pass them to the
-                 callback. */
-             err = *line? (*cb) (hook, line) : 0;
-             if (err)
-               goto leave;
-           }
+  while ((nread = _gpgme_io_read (rp[0], linebuf + linelen,
+                                  linebufsize - linelen - 1)))
+    {
+      char *line;
+      const char *lastmark = NULL;
+      size_t nused;
+
+      if (nread < 0)
+        {
+          err = gpg_error_from_syserror ();
+          goto leave;
+        }
+
+      linelen += nread;
+      linebuf[linelen] = '\0';
+
+      for (line=linebuf; (mark = strchr (line, '\n')); line = mark+1 )
+        {
+          lastmark = mark;
+          if (mark > line && mark[-1] == '\r')
+            mark[-1] = '\0';
+          else
+            mark[0] = '\0';
+
+          /* Got a full line.  Due to the CR removal code (which
+             occurs only on Windows) we might be one-off and thus
+             would see empty lines.  Don't pass them to the
+             callback. */
+          err = *line? (*cb) (hook, line) : 0;
+          if (err)
+            goto leave;
+        }
+
+      nused = lastmark? (lastmark + 1 - linebuf) : 0;
+      memmove (linebuf, linebuf + nused, linelen - nused);
+      linelen -= nused;
+
+      if (!(linelen < linebufsize - 1))
+        {
+          char *newlinebuf;
+
+          if (linelen <  8 * 1024 - 1)
+            linebufsize = 8 * 1024;
+          else if (linelen < 64 * 1024 - 1)
+            linebufsize = 64 * 1024;
+          else
+            {
+              /* We reached our limit - give up.  */
+              err = gpg_error (GPG_ERR_LINE_TOO_LONG);
+              goto leave;
+            }
 
-          nused = lastmark? (lastmark + 1 - linebuf) : 0;
-          memmove (linebuf, linebuf + nused, linelen - nused);
-          linelen -= nused;
-       }
+          newlinebuf = realloc (linebuf, linebufsize);
+          if (!newlinebuf)
+            {
+              err = gpg_error_from_syserror ();
+              goto leave;
+            }
+          linebuf = newlinebuf;
+        }
     }
-  while (nread > 0 && linelen < LINELENGTH - 1);
-
-  if (!err && nread < 0)
-    err = gpg_error_from_syserror ();
-  if (!err && nread > 0)
-    err = gpg_error (GPG_ERR_LINE_TOO_LONG);
 
  leave:
+  free (linebuf);
   _gpgme_io_close (rp[0]);
-
   return err;
 }
 
@@ -641,14 +678,14 @@ _gpgme_conf_opt_change (gpgme_conf_opt_t opt, int reset, gpgme_conf_arg_t arg)
 /* FIXME: Major problem: We don't get errors from gpgconf.  */
 
 static gpgme_error_t
-gpgconf_write (void *engine, char *arg1, char *arg2, gpgme_data_t conf)
+gpgconf_write (void *engine, const char *arg1, char *arg2, gpgme_data_t conf)
 {
   struct engine_gpgconf *gpgconf = engine;
   gpgme_error_t err = 0;
 #define BUFLEN 1024
   char buf[BUFLEN];
   int buflen = 0;
-  char *argv[] = { NULL /* file_name */, arg1, arg2, 0 };
+  char *argv[] = { NULL /* file_name */, (char*)arg1, arg2, 0 };
   int rp[2];
   struct spawn_fd_item_s cfd[] = { {-1, 0 /* STDIN_FILENO */}, {-1, -1} };
   int status;
@@ -664,7 +701,8 @@ gpgconf_write (void *engine, char *arg1, char *arg2, gpgme_data_t conf)
 
   cfd[0].fd = rp[0];
 
-  status = _gpgme_io_spawn (gpgconf->file_name, argv, 0, cfd, NULL, NULL, NULL);
+  status = _gpgme_io_spawn (gpgconf->file_name, argv,
+                            IOSPAWN_FLAG_DETACHED, cfd, NULL, NULL, NULL);
   if (status < 0)
     {
       _gpgme_io_close (rp[0]);
@@ -874,6 +912,8 @@ gpgconf_conf_save (void *engine, gpgme_conf_comp_t comp)
 static void
 gpgconf_set_io_cbs (void *engine, gpgme_io_cbs_t io_cbs)
 {
+  (void)engine;
+  (void)io_cbs;
   /* Nothing to do.  */
 }
 
@@ -890,7 +930,7 @@ _gpgme_conf_release (gpgme_conf_comp_t conf)
 struct engine_ops _gpgme_engine_ops_gpgconf =
   {
     /* Static functions.  */
-    _gpgme_get_gpgconf_path,
+    _gpgme_get_default_gpgconf_name,
     NULL,
     gpgconf_get_version,
     gpgconf_get_req_version,
@@ -899,6 +939,7 @@ struct engine_ops _gpgme_engine_ops_gpgconf =
     /* Member functions.  */
     gpgconf_release,
     NULL,              /* reset */
+    NULL,               /* set_status_cb */
     NULL,              /* set_status_handler */
     NULL,              /* set_command_handler */
     NULL,              /* set_colon_line_handler */
@@ -916,6 +957,8 @@ struct engine_ops _gpgme_engine_ops_gpgconf =
     NULL,              /* import */
     NULL,              /* keylist */
     NULL,              /* keylist_ext */
+    NULL,               /* keysign */
+    NULL,               /* tofu_policy */
     NULL,              /* sign */
     NULL,              /* trustlist */
     NULL,              /* verify */
@@ -925,5 +968,9 @@ struct engine_ops _gpgme_engine_ops_gpgconf =
     gpgconf_conf_save,
     gpgconf_set_io_cbs,
     NULL,              /* io_event */
-    NULL               /* cancel */
+    NULL,              /* cancel */
+    NULL,               /* cancel_op */
+    NULL,               /* passwd */
+    NULL,               /* set_pinentry_mode */
+    NULL                /* opspawn */
   };