gpgconf: Add access to --list-dirs for non-default engine.
[gpgme.git] / src / engine-g13.c
index 34c6ac1..f8f3178 100644 (file)
@@ -1,19 +1,19 @@
 /* engine-g13.c - G13 engine.
    Copyright (C) 2000 Werner Koch (dd9jn)
    Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007, 2009 g10 Code GmbH
+
    This file is part of GPGME.
 
    GPGME is free software; you can redistribute it and/or modify it
    under the terms of the GNU Lesser General Public License as
    published by the Free Software Foundation; either version 2.1 of
    the License, or (at your option) any later version.
-   
+
    GPGME 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
    Lesser General Public License for more details.
-   
+
    You should have received a copy of the GNU Lesser General Public
    License along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 
 #include <stdlib.h>
 #include <string.h>
-#include <sys/types.h>
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
 #include <assert.h>
-#include <unistd.h>
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+#ifdef HAVE_LOCALE_H
 #include <locale.h>
+#endif
 #include <fcntl.h> /* FIXME */
 #include <errno.h>
 
@@ -69,10 +75,6 @@ struct engine_g13
 
   struct gpgme_io_cbs io_cbs;
 
-  /* Internal callbacks.  */
-  engine_assuan_result_cb_t result_cb;
-  void *result_cb_value; 
-
   /* User provided callbacks.  */
   struct {
     gpgme_assuan_data_cb_t data_cb;
@@ -89,7 +91,7 @@ struct engine_g13
 typedef struct engine_g13 *engine_g13_t;
 
 
-static void g13_io_event (void *engine, 
+static void g13_io_event (void *engine,
                             gpgme_event_io_t type, void *type_data);
 
 
@@ -98,14 +100,14 @@ static char *
 g13_get_version (const char *file_name)
 {
   return _gpgme_get_program_version (file_name ? file_name
-                                    : _gpgme_get_g13_path ());
+                                    : _gpgme_get_default_g13_name ());
 }
 
 
 static const char *
 g13_get_req_version (void)
 {
-  return NEED_G13_VERSION;
+  return "2.1.0";
 }
 
 \f
@@ -210,28 +212,34 @@ g13_release (void *engine)
 
 
 static gpgme_error_t
-g13_new (void **engine, const char *file_name, const char *home_dir)
+g13_new (void **engine, const char *file_name, const char *home_dir,
+         const char *version)
 {
   gpgme_error_t err = 0;
   engine_g13_t g13;
+  const char *pgmname;
   int argc;
-  char *argv[5];
+  const char *argv[5];
   char *dft_display = NULL;
   char dft_ttyname[64];
+  char *env_tty = NULL;
   char *dft_ttytype = NULL;
   char *optstr;
 
+  (void)version; /* Not yet used.  */
+
   g13 = calloc (1, sizeof *g13);
   if (!g13)
-    return gpg_error_from_errno (errno);
+    return gpg_error_from_syserror ();
 
   g13->status_cb.fd = -1;
   g13->status_cb.dir = 1;
   g13->status_cb.tag = 0;
   g13->status_cb.data = g13;
 
+  pgmname = file_name ? file_name : _gpgme_get_default_g13_name ();
   argc = 0;
-  argv[argc++] = "g13";
+  argv[argc++] = _gpgme_get_basename (pgmname);
   if (home_dir)
     {
       argv[argc++] = "--homedir";
@@ -248,13 +256,11 @@ g13_new (void **engine, const char *file_name, const char *home_dir)
   assuan_ctx_set_system_hooks (g13->assuan_ctx, &_gpgme_assuan_system_hooks);
 
 #if USE_DESCRIPTOR_PASSING
-  err = assuan_pipe_connect_ext
-    (g13->assuan_ctx, file_name ? file_name : _gpgme_get_g13_path (),
-     argv, NULL, NULL, NULL, 1);
+  err = assuan_pipe_connect (g13->assuan_ctx, pgmname, argv,
+                             NULL, NULL, NULL, ASSUAN_PIPE_CONNECT_FDPASSING);
 #else
-  err = assuan_pipe_connect
-    (g13->assuan_ctx, file_name ? file_name : _gpgme_get_g13_path (),
-     argv, NULL);
+  err = assuan_pipe_connect (g13->assuan_ctx, pgmname, argv,
+                             NULL, NULL, NULL, 0);
 #endif
   if (err)
     goto leave;
@@ -264,41 +270,48 @@ g13_new (void **engine, const char *file_name, const char *home_dir)
     goto leave;
   if (dft_display)
     {
-      if (asprintf (&optstr, "OPTION display=%s", dft_display) < 0)
+      if (gpgrt_asprintf (&optstr, "OPTION display=%s", dft_display) < 0)
         {
          free (dft_display);
-         err = gpg_error_from_errno (errno);
+         err = gpg_error_from_syserror ();
          goto leave;
        }
       free (dft_display);
 
       err = assuan_transact (g13->assuan_ctx, optstr, NULL, NULL, NULL,
                             NULL, NULL, NULL);
-      free (optstr);
+      gpgrt_free (optstr);
       if (err)
        goto leave;
     }
 
-  if (isatty (1))
+  err = _gpgme_getenv ("GPG_TTY", &env_tty);
+  if (isatty (1) || env_tty || err)
     {
-      int rc;
+      int rc = 0;
 
-      rc = ttyname_r (1, dft_ttyname, sizeof (dft_ttyname));
-      if (rc)
-       {
-         err = gpg_error_from_errno (rc);
-         goto leave;
-       }
+      if (err)
+        goto leave;
+      else if (env_tty)
+        {
+          snprintf (dft_ttyname, sizeof (dft_ttyname), "%s", env_tty);
+          free (env_tty);
+        }
       else
+        rc = ttyname_r (1, dft_ttyname, sizeof (dft_ttyname));
+
+      /* Even though isatty() returns 1, ttyname_r() may fail in many
+        ways, e.g., when /dev/pts is not accessible under chroot.  */
+      if (!rc)
        {
-         if (asprintf (&optstr, "OPTION ttyname=%s", dft_ttyname) < 0)
+         if (gpgrt_asprintf (&optstr, "OPTION ttyname=%s", dft_ttyname) < 0)
            {
-             err = gpg_error_from_errno (errno);
+             err = gpg_error_from_syserror ();
              goto leave;
            }
          err = assuan_transact (g13->assuan_ctx, optstr, NULL, NULL, NULL,
                                 NULL, NULL, NULL);
-         free (optstr);
+         gpgrt_free (optstr);
          if (err)
            goto leave;
 
@@ -307,17 +320,17 @@ g13_new (void **engine, const char *file_name, const char *home_dir)
            goto leave;
          if (dft_ttytype)
            {
-             if (asprintf (&optstr, "OPTION ttytype=%s", dft_ttytype) < 0)
+             if (gpgrt_asprintf (&optstr, "OPTION ttytype=%s", dft_ttytype)< 0)
                {
                  free (dft_ttytype);
-                 err = gpg_error_from_errno (errno);
+                 err = gpg_error_from_syserror ();
                  goto leave;
                }
              free (dft_ttytype);
 
              err = assuan_transact (g13->assuan_ctx, optstr, NULL, NULL,
                                     NULL, NULL, NULL, NULL);
-             free (optstr);
+             gpgrt_free (optstr);
              if (err)
                goto leave;
            }
@@ -353,12 +366,15 @@ g13_set_locale (void *engine, int category, const char *value)
   engine_g13_t g13 = engine;
   gpgme_error_t err;
   char *optstr;
-  char *catstr;
+  const char *catstr;
 
   /* FIXME: If value is NULL, we need to reset the option to default.
      But we can't do this.  So we error out here.  G13 needs support
      for this.  */
-  if (category == LC_CTYPE)
+  if (0)
+    ;
+#ifdef LC_CTYPE
+  else if (category == LC_CTYPE)
     {
       catstr = "lc-ctype";
       if (!value && g13->lc_ctype_set)
@@ -366,6 +382,7 @@ g13_set_locale (void *engine, int category, const char *value)
       if (value)
        g13->lc_ctype_set = 1;
     }
+#endif
 #ifdef LC_MESSAGES
   else if (category == LC_MESSAGES)
     {
@@ -380,31 +397,35 @@ g13_set_locale (void *engine, int category, const char *value)
     return gpg_error (GPG_ERR_INV_VALUE);
 
   /* FIXME: Reset value to default.  */
-  if (!value) 
+  if (!value)
     return 0;
 
-  if (asprintf (&optstr, "OPTION %s=%s", catstr, value) < 0)
-    err = gpg_error_from_errno (errno);
+  if (gpgrt_asprintf (&optstr, "OPTION %s=%s", catstr, value) < 0)
+    err = gpg_error_from_syserror ();
   else
     {
       err = assuan_transact (g13->assuan_ctx, optstr, NULL, NULL,
                             NULL, NULL, NULL, NULL);
-      free (optstr);
+      gpgrt_free (optstr);
     }
 
   return err;
 }
 
 
+#if USE_DESCRIPTOR_PASSING
 static gpgme_error_t
-g13_assuan_simple_command (assuan_context_t ctx, char *cmd,
-                            engine_status_handler_t status_fnc,
-                            void *status_fnc_value)
+g13_assuan_simple_command (assuan_context_t ctx, const char *cmd,
+                          engine_status_handler_t status_fnc,
+                          void *status_fnc_value)
 {
   gpg_error_t err;
   char *line;
   size_t linelen;
 
+  (void)status_fnc;
+  (void)status_fnc_value;
+
   err = assuan_write_line (ctx, cmd);
   if (err)
     return err;
@@ -446,6 +467,7 @@ g13_assuan_simple_command (assuan_context_t ctx, char *cmd,
 
   return err;
 }
+#endif
 
 
 static gpgme_error_t
@@ -479,18 +501,14 @@ status_handler (void *opaque, int fd)
           TRACE2 (DEBUG_CTX, "gpgme:status_handler", g13,
                  "fd 0x%x: ERR line: %s",
                   fd, err ? gpg_strerror (err) : "ok");
-         
-         /* In g13, command execution errors are not fatal, as we use
+
+         /* Command execution errors are not fatal, as we use
             a session based protocol.  */
-          if (g13->result_cb)
-            err = g13->result_cb (g13->result_cb_value, err);
-          else
-            err = 0;
-          if (!err)
-            {
-              _gpgme_io_close (g13->status_cb.fd);
-              return 0;
-           }
+         data->op_err = err;
+
+         /* The caller will do the rest (namely, call cancel_op,
+            which closes status_fd).  */
+         return 0;
        }
       else if (linelen >= 2
               && line[0] == 'O' && line[1] == 'K'
@@ -498,15 +516,9 @@ status_handler (void *opaque, int fd)
        {
           TRACE1 (DEBUG_CTX, "gpgme:status_handler", g13,
                  "fd 0x%x: OK line", fd);
-          if (g13->result_cb)
-            err = g13->result_cb (g13->result_cb_value, 0);
-          else
-            err = 0;
-         if (!err)
-            {
-              _gpgme_io_close (g13->status_cb.fd);
-              return 0;
-            }
+
+         _gpgme_io_close (g13->status_cb.fd);
+         return 0;
        }
       else if (linelen > 2
               && line[0] == 'D' && line[1] == ' ')
@@ -559,7 +571,7 @@ status_handler (void *opaque, int fd)
          src = line + 2;
           while (*src == ' ')
             src++;
-         
+
          args = strchr (line + 2, ' ');
          if (!args)
            args = line + linelen; /* set to an empty string */
@@ -583,12 +595,12 @@ status_handler (void *opaque, int fd)
       else if (linelen >= 7
                && line[0] == 'I' && line[1] == 'N' && line[2] == 'Q'
                && line[3] == 'U' && line[4] == 'I' && line[5] == 'R'
-               && line[6] == 'E' 
+               && line[6] == 'E'
                && (line[7] == '\0' || line[7] == ' '))
         {
           char *src;
          char *args;
-         
+
           for (src=line+7; *src == ' '; src++)
             ;
 
@@ -602,7 +614,7 @@ status_handler (void *opaque, int fd)
             args++;
 
           err = default_inq_cb (g13, src, args);
-          if (!err) 
+          if (!err)
             {
               /* Flush and send END.  */
               err = assuan_send_data (g13->assuan_ctx, NULL, 0);
@@ -616,10 +628,10 @@ status_handler (void *opaque, int fd)
         }
     }
   while (!err && assuan_pending_line (g13->assuan_ctx));
-  
+
   return err;
 }
-  
+
 
 static gpgme_error_t
 add_io_cb (engine_g13_t g13, iocb_data_t *iocbd, gpgme_io_cb_t handler)
@@ -644,16 +656,21 @@ static gpgme_error_t
 start (engine_g13_t g13, const char *command)
 {
   gpgme_error_t err;
+  assuan_fd_t afdlist[5];
   int fdlist[5];
   int nfds;
+  int i;
 
   /* We need to know the fd used by assuan for reads.  We do this by
      using the assumption that the first returned fd from
      assuan_get_active_fds() is always this one.  */
   nfds = assuan_get_active_fds (g13->assuan_ctx, 0 /* read fds */,
-                                fdlist, DIM (fdlist));
+                                afdlist, DIM (afdlist));
   if (nfds < 1)
     return gpg_error (GPG_ERR_GENERAL);        /* FIXME */
+  /* For now... */
+  for (i = 0; i < nfds; i++)
+    fdlist[i] = (int) afdlist[i];
 
   /* We "duplicate" the file descriptor, so we can close it here (we
      can't close fdlist[0], as that is closed by libassuan, and
@@ -704,8 +721,6 @@ g13_reset (void *engine)
 static gpgme_error_t
 g13_transact (void *engine,
                 const char *command,
-                engine_assuan_result_cb_t result_cb,
-                void *result_cb_value,
                 gpgme_assuan_data_cb_t data_cb,
                 void *data_cb_value,
                 gpgme_assuan_inquire_cb_t inq_cb,
@@ -719,8 +734,6 @@ g13_transact (void *engine,
   if (!g13 || !command || !*command)
     return gpg_error (GPG_ERR_INV_VALUE);
 
-  g13->result_cb = result_cb;
-  g13->result_cb_value = result_cb_value;
   g13->user.data_cb = data_cb;
   g13->user.data_cb_value = data_cb_value;
   g13->user.inq_cb = inq_cb;
@@ -758,7 +771,7 @@ g13_io_event (void *engine, gpgme_event_io_t type, void *type_data)
 struct engine_ops _gpgme_engine_ops_g13 =
   {
     /* Static functions.  */
-    _gpgme_get_g13_path,
+    _gpgme_get_default_g13_name,
     NULL,
     g13_get_version,
     g13_get_req_version,
@@ -771,10 +784,12 @@ struct engine_ops _gpgme_engine_ops_g13 =
 #else
     NULL,                      /* reset */
 #endif
+    NULL,               /* set_status_cb */
     NULL,               /* set_status_handler */
     NULL,              /* set_command_handler */
     NULL,               /* set_colon_line_handler */
     g13_set_locale,
+    NULL,              /* set_protocol */
     NULL,               /* decrypt */
     NULL,               /* delete */
     NULL,              /* edit */
@@ -786,6 +801,9 @@ struct engine_ops _gpgme_engine_ops_g13 =
     NULL,               /* import */
     NULL,               /* keylist */
     NULL,               /* keylist_ext */
+    NULL,               /* keylist_data */
+    NULL,               /* keysign */
+    NULL,               /* tofu_policy */
     NULL,               /* sign */
     NULL,              /* trustlist */
     NULL,               /* verify */
@@ -793,8 +811,13 @@ struct engine_ops _gpgme_engine_ops_g13 =
     g13_transact,
     NULL,              /* conf_load */
     NULL,              /* conf_save */
+    NULL,              /* conf_dir */
+    NULL,               /* query_swdb */
     g13_set_io_cbs,
     g13_io_event,
     g13_cancel,
     g13_cancel_op,
+    NULL,               /* passwd */
+    NULL,               /* set_pinentry_mode */
+    NULL                /* opspawn */
   };