Fix last change.
[gpgme.git] / gpgme / rungpg.c
index c89e39e..fb5b737 100644 (file)
@@ -70,11 +70,10 @@ struct fd_data_map_s
 };
 
 
-struct gpg_object_s
+struct engine_gpg
 {
   struct arg_and_data_s *arglist;
   struct arg_and_data_s **argtail;
-  int arg_error;
 
   struct
   {
@@ -83,7 +82,7 @@ struct gpg_object_s
     char *buffer;
     size_t readpos;
     int eof;
-    EngineStatusHandler fnc;
+    engine_status_handler_t fnc;
     void *fnc_value;
     void *tag;
   } status;
@@ -96,7 +95,7 @@ struct gpg_object_s
     char *buffer;
     size_t readpos;
     int eof;
-    EngineColonLineHandler fnc;  /* this indicate use of this structrue */
+    engine_colon_line_handler_t fnc;  /* this indicate use of this structrue */
     void *fnc_value;
     void *tag;
   } colon;
@@ -109,11 +108,11 @@ struct gpg_object_s
   {
     int used;
     int fd;
+    void *cb_data;
     int idx;           /* Index in fd_data_map */
-    gpgme_data_t cb_data;   /* hack to get init the above idx later */
     gpgme_status_code_t code;  /* last code */
     char *keyword;       /* what has been requested (malloced) */
-    EngineCommandHandler fnc; 
+    engine_command_handler_t fnc; 
     void *fnc_value;
     /* The kludges never end.  This is used to couple command handlers
        with output data in edit key mode.  */
@@ -124,13 +123,13 @@ struct gpg_object_s
   struct gpgme_io_cbs io_cbs;
 };
 
-typedef struct gpg_object_s *GpgObject;
+typedef struct engine_gpg *engine_gpg_t;
 
 \f
 static void
 gpg_io_event (void *engine, gpgme_event_io_t type, void *type_data)
 {
-  GpgObject gpg = engine;
+  engine_gpg_t gpg = engine;
 
   if (gpg->io_cbs.event)
     (*gpg->io_cbs.event) (gpg->io_cbs.event_priv, type, type_data);
@@ -140,7 +139,7 @@ gpg_io_event (void *engine, gpgme_event_io_t type, void *type_data)
 static void
 close_notify_handler (int fd, void *opaque)
 {
-  GpgObject gpg = opaque;
+  engine_gpg_t gpg = opaque;
   assert (fd != -1);
 
   if (gpg->status.fd[0] == fd)
@@ -182,7 +181,7 @@ close_notify_handler (int fd, void *opaque)
 }
 
 static gpgme_error_t
-add_arg (GpgObject gpg, const char *arg)
+add_arg (engine_gpg_t gpg, const char *arg)
 {
   struct arg_and_data_s *a;
 
@@ -191,10 +190,7 @@ add_arg (GpgObject gpg, const char *arg)
 
   a = malloc (sizeof *a + strlen (arg));
   if (!a)
-    {
-      gpg->arg_error = 1;
-      return GPGME_Out_Of_Core;
-    }
+    return gpg_error_from_errno (errno);
   a->next = NULL;
   a->data = NULL;
   a->dup_to = -1;
@@ -205,7 +201,7 @@ add_arg (GpgObject gpg, const char *arg)
 }
 
 static gpgme_error_t
-add_data (GpgObject gpg, gpgme_data_t data, int dup_to, int inbound)
+add_data (engine_gpg_t gpg, gpgme_data_t data, int dup_to, int inbound)
 {
   struct arg_and_data_s *a;
 
@@ -214,10 +210,7 @@ add_data (GpgObject gpg, gpgme_data_t data, int dup_to, int inbound)
 
   a = malloc (sizeof *a - 1);
   if (!a)
-    {
-      gpg->arg_error = 1;
-      return GPGME_Out_Of_Core;
-    }
+    return gpg_error_from_errno (errno);
   a->next = NULL;
   a->data = data;
   a->inbound = inbound;
@@ -292,7 +285,7 @@ free_fd_data_map (struct fd_data_map_s *fd_data_map)
 static void
 gpg_release (void *engine)
 {
-  GpgObject gpg = engine;
+  engine_gpg_t gpg = engine;
 
   if (!gpg)
     return;
@@ -301,16 +294,19 @@ gpg_release (void *engine)
     {
       struct arg_and_data_s *next = gpg->arglist->next;
 
-      free (gpg->arglist);
+      if (gpg->arglist)
+       free (gpg->arglist);
       gpg->arglist = next;
     }
 
-  free (gpg->status.buffer);
-  free (gpg->colon.buffer);
+  if (gpg->status.buffer)
+    free (gpg->status.buffer);
+  if (gpg->colon.buffer)
+    free (gpg->colon.buffer);
   if (gpg->argv)
     free_argv (gpg->argv);
-  gpgme_data_release (gpg->cmd.cb_data);
-  free (gpg->cmd.keyword);
+  if (gpg->cmd.keyword)
+    free (gpg->cmd.keyword);
 
   if (gpg->status.fd[0] != -1)
     _gpgme_io_close (gpg->status.fd[0]);
@@ -320,7 +316,8 @@ gpg_release (void *engine)
     _gpgme_io_close (gpg->colon.fd[0]);
   if (gpg->colon.fd[1] != -1)
     _gpgme_io_close (gpg->colon.fd[1]);
-  free_fd_data_map (gpg->fd_data_map);
+  if (gpg->fd_data_map)
+    free_fd_data_map (gpg->fd_data_map);
   if (gpg->cmd.fd != -1)
     _gpgme_io_close (gpg->cmd.fd);
   free (gpg);
@@ -330,17 +327,14 @@ gpg_release (void *engine)
 static gpgme_error_t
 gpg_new (void **engine)
 {
-  GpgObject gpg;
-  int rc = 0;
+  engine_gpg_t gpg;
+  gpgme_error_t rc = 0;
 
   gpg = calloc (1, sizeof *gpg);
   if (!gpg)
-    {
-      rc = GPGME_Out_Of_Core;
-      goto leave;
-    }
-  gpg->argtail = &gpg->arglist;
+    return gpg_error_from_errno (errno);
 
+  gpg->argtail = &gpg->arglist;
   gpg->status.fd[0] = -1;
   gpg->status.fd[1] = -1;
   gpg->colon.fd[0] = -1;
@@ -356,14 +350,14 @@ gpg_new (void **engine)
   gpg->status.buffer = malloc (gpg->status.bufsize);
   if (!gpg->status.buffer)
     {
-      rc = GPGME_Out_Of_Core;
+      rc = gpg_error_from_errno (errno);
       goto leave;
     }
   /* In any case we need a status pipe - create it right here and
      don't handle it with our generic gpgme_data_t mechanism.  */
   if (_gpgme_io_pipe (gpg->status.fd, 1) == -1)
     {
-      rc = GPGME_Pipe_Error;
+      rc = gpg_error_from_errno (errno);
       goto leave;
     }
   if (_gpgme_io_set_close_notify (gpg->status.fd[0],
@@ -371,20 +365,29 @@ gpg_new (void **engine)
       || _gpgme_io_set_close_notify (gpg->status.fd[1],
                                     close_notify_handler, gpg))
     {
-      rc = GPGME_General_Error;
+      rc = gpg_error (GPG_ERR_GENERAL);
       goto leave;
     }
   gpg->status.eof = 0;
-  add_arg (gpg, "--status-fd");
+  rc = add_arg (gpg, "--status-fd");
+  if (rc)
+    goto leave;
+
   {
     char buf[25];
     sprintf (buf, "%d", gpg->status.fd[1]);
-    add_arg (gpg, buf);
+    rc = add_arg (gpg, buf);
+    if (rc)
+      goto leave;
   }
-  add_arg (gpg, "--no-tty");
-  add_arg (gpg, "--charset");
-  add_arg (gpg, "utf8");
-  add_arg (gpg, "--enable-progress-filter");
+
+  rc = add_arg (gpg, "--no-tty");
+  if (!rc)
+    rc = add_arg (gpg, "--charset");
+  if (!rc)
+    rc = add_arg (gpg, "utf8");
+  if (!rc)
+    rc = add_arg (gpg, "--enable-progress-filter");
 
  leave:
   if (rc)
@@ -398,9 +401,10 @@ gpg_new (void **engine)
 /* Note, that the status_handler is allowed to modifiy the args
    value.  */
 static void
-gpg_set_status_handler (void *engine, EngineStatusHandler fnc, void *fnc_value)
+gpg_set_status_handler (void *engine, engine_status_handler_t fnc,
+                       void *fnc_value)
 {
-  GpgObject gpg = engine;
+  engine_gpg_t gpg = engine;
 
   gpg->status.fnc = fnc;
   gpg->status.fnc_value = fnc_value;
@@ -408,27 +412,28 @@ gpg_set_status_handler (void *engine, EngineStatusHandler fnc, void *fnc_value)
 
 /* Kludge to process --with-colon output.  */
 static gpgme_error_t
-gpg_set_colon_line_handler (void *engine, EngineColonLineHandler fnc,
+gpg_set_colon_line_handler (void *engine, engine_colon_line_handler_t fnc,
                            void *fnc_value)
 {
-  GpgObject gpg = engine;
+  engine_gpg_t gpg = engine;
 
   gpg->colon.bufsize = 1024;
   gpg->colon.readpos = 0;
   gpg->colon.buffer = malloc (gpg->colon.bufsize);
   if (!gpg->colon.buffer)
-    return GPGME_Out_Of_Core;
+    return gpg_error_from_errno (errno);
 
   if (_gpgme_io_pipe (gpg->colon.fd, 1) == -1) 
     {
+      int saved_errno = errno;
       free (gpg->colon.buffer);
       gpg->colon.buffer = NULL;
-      return GPGME_Pipe_Error;
+      return gpg_error_from_errno (saved_errno);
     }
   if (_gpgme_io_set_close_notify (gpg->colon.fd[0], close_notify_handler, gpg)
       || _gpgme_io_set_close_notify (gpg->colon.fd[1],
                                     close_notify_handler, gpg))
-    return GPGME_General_Error;
+    return gpg_error (GPG_ERR_GENERAL);
   gpg->colon.eof = 0;
   gpg->colon.fnc = fnc;
   gpg->colon.fnc_value = fnc_value;
@@ -436,60 +441,20 @@ gpg_set_colon_line_handler (void *engine, EngineColonLineHandler fnc,
 }
 
 
-/* Here we handle --command-fd.  This works closely together with the
-   status handler.  */
 static gpgme_error_t
-command_cb (void *opaque, char *buffer, size_t length, size_t *nread)
+command_handler (void *opaque, int fd)
 {
   gpgme_error_t err;
-  GpgObject gpg = opaque;
-  const char *value;
-  int value_len;
+  engine_gpg_t gpg = (engine_gpg_t) opaque;
 
-  DEBUG0 ("command_cb: enter\n");
   assert (gpg->cmd.used);
-  if (!buffer || !length || !nread)
-    return 0; /* These values are reserved for extensions.  */
-  *nread = 0;
-  if (!gpg->cmd.code)
-    {
-      DEBUG0 ("command_cb: no code\n");
-      return -1;
-    }
-    
-  if (!gpg->cmd.fnc)
-    {
-      DEBUG0 ("command_cb: no user cb\n");
-      return -1;
-    }
+  assert (gpg->cmd.code);
+  assert (gpg->cmd.fnc);
 
-  /* FIXME catch error */
-  err = gpg->cmd.fnc (gpg->cmd.fnc_value, 
-                     gpg->cmd.code, gpg->cmd.keyword, &value);
+  err = gpg->cmd.fnc (gpg->cmd.fnc_value, gpg->cmd.code, gpg->cmd.keyword, fd);
   if (err)
     return err;
 
-  if (!value)
-    {
-      DEBUG0 ("command_cb: no data from user cb\n");
-      gpg->cmd.fnc (gpg->cmd.fnc_value, 0, value, &value);
-      return -1;
-    }
-
-  value_len = strlen (value);
-  if (value_len + 1 > length)
-    {
-      DEBUG0 ("command_cb: too much data from user cb\n");
-      gpg->cmd.fnc (gpg->cmd.fnc_value, 0, value, &value);
-      return -1;
-    }
-
-  memcpy (buffer, value, value_len);
-  if (!value_len || (value_len && value[value_len-1] != '\n')) 
-    buffer[value_len++] = '\n';
-  *nread = value_len;
-    
-  gpg->cmd.fnc (gpg->cmd.fnc_value, 0, value, &value);
   gpg->cmd.code = 0;
   /* And sleep again until read_status will wake us up again.  */
   /* XXX We must check if there are any more fds active after removing
@@ -502,27 +467,32 @@ command_cb (void *opaque, char *buffer, size_t length, size_t *nread)
 }
 
 
+
 /* The Fnc will be called to get a value for one of the commands with
    a key KEY.  If the Code pssed to FNC is 0, the function may release
    resources associated with the returned value from another call.  To
    match such a second call to a first call, the returned value from
    the first call is passed as keyword.  */
 static gpgme_error_t
-gpg_set_command_handler (void *engine, EngineCommandHandler fnc,
+gpg_set_command_handler (void *engine, engine_command_handler_t fnc,
                         void *fnc_value, gpgme_data_t linked_data)
 {
-  GpgObject gpg = engine;
-  gpgme_data_t tmp;
-  gpgme_error_t err;
+  engine_gpg_t gpg = engine;
+  gpgme_error_t rc;
+
+  rc = add_arg (gpg, "--command-fd");
+  if (rc)
+    return rc;
+
+  /* This is a hack.  We don't have a real data object.  The only
+     thing that matters is that we use something unique, so we use the
+     address of the cmd structure in the gpg object.  */
+  rc = add_data (gpg, (void *) &gpg->cmd, -2, 0);
+  if (rc)
+    return rc;
 
-  err = gpgme_data_new_with_read_cb (&tmp, command_cb, gpg);
-  if (err)
-    return err;
-        
-  add_arg (gpg, "--command-fd");
-  add_data (gpg, tmp, -2, 0);
-  gpg->cmd.cb_data = tmp;
   gpg->cmd.fnc = fnc;
+  gpg->cmd.cb_data = (void *) &gpg->cmd;
   gpg->cmd.fnc_value = fnc_value;
   gpg->cmd.linked_data = linked_data;
   gpg->cmd.used = 1;
@@ -531,7 +501,7 @@ gpg_set_command_handler (void *engine, EngineCommandHandler fnc,
 
 
 static gpgme_error_t
-build_argv (GpgObject gpg)
+build_argv (engine_gpg_t gpg)
 {
   struct arg_and_data_s *a;
   struct fd_data_map_s *fd_data_map;
@@ -579,26 +549,28 @@ build_argv (GpgObject gpg)
   if (use_agent)
     argc++;
   if (!gpg->cmd.used)
-    argc++;
+    argc++;    /* --batch */
   argc += 2; /* --comment */
 
   argv = calloc (argc + 1, sizeof *argv);
   if (!argv)
-    return GPGME_Out_Of_Core;
+    return gpg_error_from_errno (errno);
   fd_data_map = calloc (datac + 1, sizeof *fd_data_map);
   if (!fd_data_map)
     {
+      int saved_errno = errno;
       free_argv (argv);
-      return GPGME_Out_Of_Core;
+      return gpg_error_from_errno (saved_errno);
     }
 
   argc = datac = 0;
   argv[argc] = strdup ("gpg"); /* argv[0] */
   if (!argv[argc])
     {
+      int saved_errno = errno;
       free (fd_data_map);
       free_argv (argv);
-      return GPGME_Out_Of_Core;
+      return gpg_error_from_errno (saved_errno);
     }
   argc++;
   if (need_special)
@@ -606,9 +578,10 @@ build_argv (GpgObject gpg)
       argv[argc] = strdup ("--enable-special-filenames");
       if (!argv[argc])
        {
+         int saved_errno = errno;
          free (fd_data_map);
          free_argv (argv);
-         return GPGME_Out_Of_Core;
+         return gpg_error_from_errno (saved_errno);
         }
       argc++;
     }
@@ -617,9 +590,10 @@ build_argv (GpgObject gpg)
       argv[argc] = strdup ("--use-agent");
       if (!argv[argc])
        {
+         int saved_errno = errno;
          free (fd_data_map);
          free_argv (argv);
-         return GPGME_Out_Of_Core;
+         return gpg_error_from_errno (saved_errno);
         }
       argc++;
     }
@@ -628,26 +602,29 @@ build_argv (GpgObject gpg)
       argv[argc] = strdup ("--batch");
       if (!argv[argc])
        {
+         int saved_errno = errno;
          free (fd_data_map);
          free_argv (argv);
-         return GPGME_Out_Of_Core;
+         return gpg_error_from_errno (saved_errno);
         }
       argc++;
     }
   argv[argc] = strdup ("--comment");
   if (!argv[argc])
     {
+      int saved_errno = errno;
       free (fd_data_map);
       free_argv (argv);
-      return GPGME_Out_Of_Core;
+      return gpg_error_from_errno (saved_errno);
     }
   argc++;
   argv[argc] = strdup ("");
   if (!argv[argc])
     {
+      int saved_errno = errno;
       free (fd_data_map);
       free_argv (argv);
-      return GPGME_Out_Of_Core;
+      return gpg_error_from_errno (saved_errno);
     }
   argc++;
   for (a = gpg->arglist; a; a = a->next)
@@ -664,9 +641,10 @@ build_argv (GpgObject gpg)
            if (_gpgme_io_pipe (fds, fd_data_map[datac].inbound ? 1 : 0)
                == -1)
              {
+               int saved_errno = errno;
                free (fd_data_map);
                free_argv (argv);
-               return GPGME_Pipe_Error;
+               return gpg_error (saved_errno);
              }
            if (_gpgme_io_set_close_notify (fds[0],
                                            close_notify_handler, gpg)
@@ -674,7 +652,7 @@ build_argv (GpgObject gpg)
                                               close_notify_handler,
                                               gpg))
              {
-               return GPGME_General_Error;
+               return gpg_error (GPG_ERR_GENERAL);
              }
            /* If the data_type is FD, we have to do a dup2 here.  */
            if (fd_data_map[datac].inbound)
@@ -711,9 +689,10 @@ build_argv (GpgObject gpg)
              argv[argc] = malloc (25);
              if (!argv[argc])
                {
+                 int saved_errno = errno;
                  free (fd_data_map);
                  free_argv (argv);
-                 return GPGME_Out_Of_Core;
+                 return gpg_error_from_errno (saved_errno);
                 }
              sprintf (argv[argc], 
                       a->print_fd ? "%d" : "-&%d",
@@ -727,9 +706,10 @@ build_argv (GpgObject gpg)
          argv[argc] = strdup (a->arg);
          if (!argv[argc])
            {
+             int saved_errno = errno;
              free (fd_data_map);
              free_argv (argv);
-             return GPGME_Out_Of_Core;
+             return gpg_error_from_errno (saved_errno);
             }
             argc++;
         }
@@ -742,7 +722,7 @@ build_argv (GpgObject gpg)
 
 
 static gpgme_error_t
-add_io_cb (GpgObject gpg, int fd, int dir, gpgme_io_cb_t handler, void *data,
+add_io_cb (engine_gpg_t gpg, int fd, int dir, gpgme_io_cb_t handler, void *data,
           void **tag)
 {
   gpgme_error_t err;
@@ -775,7 +755,7 @@ status_cmp (const void *ap, const void *bp)
    with status line code we know about and skip all other stuff
    without buffering (i.e. without extending the buffer).  */
 static gpgme_error_t
-read_status (GpgObject gpg)
+read_status (engine_gpg_t gpg)
 {
   char *p;
   int nread;
@@ -790,13 +770,13 @@ read_status (GpgObject gpg)
       bufsize += 1024;
       buffer = realloc (buffer, bufsize);
       if (!buffer)
-       return GPGME_Out_Of_Core;
+       return gpg_error_from_errno (errno);
     }
 
   nread = _gpgme_io_read (gpg->status.fd[0],
                          buffer + readpos, bufsize-readpos);
   if (nread == -1)
-    return GPGME_Read_Error;
+    return gpg_error_from_errno (errno);
 
   if (!nread)
     {
@@ -843,10 +823,11 @@ read_status (GpgObject gpg)
                              || r->code == GPGME_STATUS_GET_HIDDEN))
                        {
                          gpg->cmd.code = r->code;
-                         free (gpg->cmd.keyword);
+                         if (gpg->cmd.keyword)
+                           free (gpg->cmd.keyword);
                          gpg->cmd.keyword = strdup (rest);
                          if (!gpg->cmd.keyword)
-                           return GPGME_Out_Of_Core;
+                           return gpg_error_from_errno (errno);
                          /* This should be the last thing we have
                             received and the next thing will be that
                             the command handler does its action.  */
@@ -877,8 +858,7 @@ read_status (GpgObject gpg)
                            }
 
                          add_io_cb (gpg, gpg->cmd.fd, 0,
-                                    _gpgme_data_outbound_handler,
-                                    gpg->fd_data_map[gpg->cmd.idx].data,
+                                    command_handler, gpg,
                                     &gpg->fd_data_map[gpg->cmd.idx].tag);
                          gpg->fd_data_map[gpg->cmd.idx].fd = gpg->cmd.fd;
                          gpg->cmd.fd = -1;
@@ -935,7 +915,7 @@ read_status (GpgObject gpg)
 static gpgme_error_t
 status_handler (void *opaque, int fd)
 {
-  GpgObject gpg = opaque;
+  engine_gpg_t gpg = opaque;
   int err;
 
   assert (fd == gpg->status.fd[0]);
@@ -949,7 +929,7 @@ status_handler (void *opaque, int fd)
 
 
 static gpgme_error_t
-read_colon_line (GpgObject gpg)
+read_colon_line (engine_gpg_t gpg)
 {
   char *p;
   int nread;
@@ -964,12 +944,12 @@ read_colon_line (GpgObject gpg)
       bufsize += 1024;
       buffer = realloc (buffer, bufsize);
       if (!buffer) 
-       return GPGME_Out_Of_Core;
+       return gpg_error_from_errno (errno);
     }
 
   nread = _gpgme_io_read (gpg->colon.fd[0], buffer+readpos, bufsize-readpos);
   if (nread == -1)
-    return GPGME_Read_Error;
+    return gpg_error_from_errno (errno);
 
   if (!nread)
     {
@@ -1029,7 +1009,7 @@ read_colon_line (GpgObject gpg)
 static gpgme_error_t
 colon_line_handler (void *opaque, int fd)
 {
-  GpgObject gpg = opaque;
+  engine_gpg_t gpg = opaque;
   gpgme_error_t rc = 0;
 
   assert (fd == gpg->colon.fd[0]);
@@ -1043,23 +1023,19 @@ colon_line_handler (void *opaque, int fd)
 
 
 static gpgme_error_t
-start (GpgObject gpg)
+start (engine_gpg_t gpg)
 {
   gpgme_error_t rc;
+  int saved_errno;
   int i, n;
   int status;
   struct spawn_fd_item_s *fd_child_list, *fd_parent_list;
 
   if (!gpg)
-    return GPGME_Invalid_Value;
+    return gpg_error (GPG_ERR_INV_VALUE);
 
   if (! _gpgme_get_gpg_path ())
-    return GPGME_Invalid_Engine;
-
-  /* Kludge, so that we don't need to check the return code of all the
-     add_arg ().  We bail out here instead.  */
-  if (gpg->arg_error)
-    return GPGME_Out_Of_Core;
+    return gpg_error (GPG_ERR_INV_ENGINE);
 
   rc = build_argv (gpg);
   if (rc)
@@ -1070,7 +1046,7 @@ start (GpgObject gpg)
     n++;
   fd_child_list = calloc (n + n, sizeof *fd_child_list);
   if (!fd_child_list)
-    return GPGME_Out_Of_Core;
+    return gpg_error_from_errno (errno);
   fd_parent_list = fd_child_list + n;
 
   /* build the fd list for the child */
@@ -1118,9 +1094,10 @@ start (GpgObject gpg)
 
   status = _gpgme_io_spawn (_gpgme_get_gpg_path (),
                            gpg->argv, fd_child_list, fd_parent_list);
+  saved_errno = errno;
   free (fd_child_list);
   if (status == -1)
-    return GPGME_Exec_Error;
+    return gpg_error_from_errno (errno);
 
   /*_gpgme_register_term_handler ( closure, closure_value, pid );*/
 
@@ -1173,7 +1150,7 @@ start (GpgObject gpg)
 static gpgme_error_t
 gpg_decrypt (void *engine, gpgme_data_t ciph, gpgme_data_t plain)
 {
-  GpgObject gpg = engine;
+  engine_gpg_t gpg = engine;
   gpgme_error_t err;
 
   err = add_arg (gpg, "--decrypt");
@@ -1196,7 +1173,7 @@ gpg_decrypt (void *engine, gpgme_data_t ciph, gpgme_data_t plain)
 static gpgme_error_t
 gpg_delete (void *engine, gpgme_key_t key, int allow_secret)
 {
-  GpgObject gpg = engine;
+  engine_gpg_t gpg = engine;
   gpgme_error_t err;
 
   err = add_arg (gpg, allow_secret ? "--delete-secret-and-public-key"
@@ -1206,7 +1183,7 @@ gpg_delete (void *engine, gpgme_key_t key, int allow_secret)
   if (!err)
     {
       if (!key->subkeys || !key->subkeys->fpr)
-       err = GPGME_Invalid_Key;
+       return gpg_error (GPG_ERR_INV_VALUE);
       else
        err = add_arg (gpg, key->subkeys->fpr);
     }
@@ -1218,7 +1195,7 @@ gpg_delete (void *engine, gpgme_key_t key, int allow_secret)
 
 
 static gpgme_error_t
-append_args_from_signers (GpgObject gpg, gpgme_ctx_t ctx /* FIXME */)
+append_args_from_signers (engine_gpg_t gpg, gpgme_ctx_t ctx /* FIXME */)
 {
   gpgme_error_t err = 0;
   int i;
@@ -1245,7 +1222,7 @@ static gpgme_error_t
 gpg_edit (void *engine, gpgme_key_t key, gpgme_data_t out,
          gpgme_ctx_t ctx /* FIXME */)
 {
-  GpgObject gpg = engine;
+  engine_gpg_t gpg = engine;
   gpgme_error_t err;
 
   err = add_arg (gpg, "--with-colons");
@@ -1261,7 +1238,7 @@ gpg_edit (void *engine, gpgme_key_t key, gpgme_data_t out,
     {
       const char *s = key->subkeys ? key->subkeys->fpr : NULL;
       if (!s)
-       err = GPGME_Invalid_Key;
+       err = gpg_error (GPG_ERR_INV_VALUE);
       else
        err = add_arg (gpg, s);
     }
@@ -1273,29 +1250,32 @@ gpg_edit (void *engine, gpgme_key_t key, gpgme_data_t out,
 
 
 static gpgme_error_t
-append_args_from_recipients (GpgObject gpg, const gpgme_recipients_t rset)
+append_args_from_recipients (engine_gpg_t gpg, gpgme_key_t recp[])
 {
   gpgme_error_t err = 0;
-  gpgme_user_id_t uid;
+  int i = 0;
 
-  assert (rset);
-  for (uid = rset->list; uid; uid = uid->next)
+  while (recp[i])
     {
-      err = add_arg (gpg, "-r");
+      if (!recp[i]->subkeys || !recp[i]->subkeys->fpr)
+       err = gpg_error (GPG_ERR_INV_VALUE);
+      if (!err)
+       err = add_arg (gpg, "-r");
       if (!err)
-       err = add_arg (gpg, uid->uid);
+       err = add_arg (gpg, recp[i]->subkeys->fpr);
       if (err)
        break;
+      i++;
     }    
   return err;
 }
 
 
 static gpgme_error_t
-gpg_encrypt (void *engine, gpgme_recipients_t recp, gpgme_data_t plain,
-            gpgme_data_t ciph, int use_armor)
+gpg_encrypt (void *engine, gpgme_key_t recp[], gpgme_encrypt_flags_t flags,
+            gpgme_data_t plain, gpgme_data_t ciph, int use_armor)
 {
-  GpgObject gpg = engine;
+  engine_gpg_t gpg = engine;
   gpgme_error_t err;
   int symmetric = !recp;
 
@@ -1308,7 +1288,7 @@ gpg_encrypt (void *engine, gpgme_recipients_t recp, gpgme_data_t plain,
     {
       /* If we know that all recipients are valid (full or ultimate trust)
         we can suppress further checks.  */
-      if (!err && !symmetric && _gpgme_recipients_all_valid (recp))
+      if (!err && !symmetric && (flags & GPGME_ENCRYPT_ALWAYS_TRUST))
        err = add_arg (gpg, "--always-trust");
 
       if (!err)
@@ -1335,11 +1315,12 @@ gpg_encrypt (void *engine, gpgme_recipients_t recp, gpgme_data_t plain,
 
 
 static gpgme_error_t
-gpg_encrypt_sign (void *engine, gpgme_recipients_t recp, gpgme_data_t plain,
+gpg_encrypt_sign (void *engine, gpgme_key_t recp[],
+                 gpgme_encrypt_flags_t flags, gpgme_data_t plain,
                  gpgme_data_t ciph, int use_armor,
                  gpgme_ctx_t ctx /* FIXME */)
 {
-  GpgObject gpg = engine;
+  engine_gpg_t gpg = engine;
   gpgme_error_t err;
 
   err = add_arg (gpg, "--encrypt");
@@ -1349,8 +1330,8 @@ gpg_encrypt_sign (void *engine, gpgme_recipients_t recp, gpgme_data_t plain,
     err = add_arg (gpg, "--armor");
 
   /* If we know that all recipients are valid (full or ultimate trust)
-   * we can suppress further checks */
-  if (!err && _gpgme_recipients_all_valid (recp))
+     we can suppress further checks.  */
+  if (!err && (flags & GPGME_ENCRYPT_ALWAYS_TRUST))
     err = add_arg (gpg, "--always-trust");
 
   if (!err)
@@ -1379,12 +1360,15 @@ gpg_encrypt_sign (void *engine, gpgme_recipients_t recp, gpgme_data_t plain,
 
 
 static gpgme_error_t
-gpg_export (void *engine, gpgme_recipients_t recp, gpgme_data_t keydata,
-           int use_armor)
+gpg_export (void *engine, const char *pattern, unsigned int reserved,
+           gpgme_data_t keydata, int use_armor)
 {
-  GpgObject gpg = engine;
+  engine_gpg_t gpg = engine;
   gpgme_error_t err;
 
+  if (reserved)
+    return gpg_error (GPG_ERR_INV_VALUE);
+
   err = add_arg (gpg, "--export");
   if (!err && use_armor)
     err = add_arg (gpg, "--armor");
@@ -1393,16 +1377,38 @@ gpg_export (void *engine, gpgme_recipients_t recp, gpgme_data_t keydata,
   if (!err)
     err = add_arg (gpg, "--");
 
+  if (!err && pattern && *pattern)
+    err = add_arg (gpg, pattern);
+
   if (!err)
-    {
-      void *ec;
-      const char *s;
+    err = start (gpg);
 
-      err = gpgme_recipients_enum_open (recp, &ec);
-      while (!err && (s = gpgme_recipients_enum_read (recp, &ec)))
-       err = add_arg (gpg, s);
-      if (!err)
-       err = gpgme_recipients_enum_close (recp, &ec);
+  return err;
+}
+
+
+static gpgme_error_t
+gpg_export_ext (void *engine, const char *pattern[], unsigned int reserved,
+               gpgme_data_t keydata, int use_armor)
+{
+  engine_gpg_t gpg = engine;
+  gpgme_error_t err;
+
+  if (reserved)
+    return gpg_error (GPG_ERR_INV_VALUE);
+
+  err = add_arg (gpg, "--export");
+  if (!err && use_armor)
+    err = add_arg (gpg, "--armor");
+  if (!err)
+    err = add_data (gpg, keydata, 1, 1);
+  if (!err)
+    err = add_arg (gpg, "--");
+
+  if (pattern)
+    {
+      while (!err && *pattern && **pattern)
+       err = add_arg (gpg, *(pattern++));
     }
 
   if (!err)
@@ -1416,18 +1422,18 @@ static gpgme_error_t
 gpg_genkey (void *engine, gpgme_data_t help_data, int use_armor,
            gpgme_data_t pubkey, gpgme_data_t seckey)
 {
-  GpgObject gpg = engine;
+  engine_gpg_t gpg = engine;
   gpgme_error_t err;
 
   if (!gpg)
-    return GPGME_Invalid_Value;
+    return gpg_error (GPG_ERR_INV_VALUE);
 
   /* We need a special mechanism to get the fd of a pipe here, so that
      we can use this for the %pubring and %secring parameters.  We
      don't have this yet, so we implement only the adding to the
      standard keyrings.  */
   if (pubkey || seckey)
-    return err = GPGME_Not_Implemented;
+    return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
 
   err = add_arg (gpg, "--gen-key");
   if (!err && use_armor)
@@ -1445,7 +1451,7 @@ gpg_genkey (void *engine, gpgme_data_t help_data, int use_armor,
 static gpgme_error_t
 gpg_import (void *engine, gpgme_data_t keydata)
 {
-  GpgObject gpg = engine;
+  engine_gpg_t gpg = engine;
   gpgme_error_t err;
 
   err = add_arg (gpg, "--import");
@@ -1461,9 +1467,9 @@ gpg_import (void *engine, gpgme_data_t keydata)
 
 static gpgme_error_t
 gpg_keylist (void *engine, const char *pattern, int secret_only,
-            int keylist_mode)
+            gpgme_keylist_mode_t mode)
 {
-  GpgObject gpg = engine;
+  engine_gpg_t gpg = engine;
   gpgme_error_t err;
 
   err = add_arg (gpg, "--with-colons");
@@ -1475,7 +1481,7 @@ gpg_keylist (void *engine, const char *pattern, int secret_only,
     err = add_arg (gpg, "--with-fingerprint");
   if (!err)
     err = add_arg (gpg, secret_only ? "--list-secret-keys"
-                  : ((keylist_mode & GPGME_KEYLIST_MODE_SIGS)
+                  : ((mode & GPGME_KEYLIST_MODE_SIGS)
                      ? "--check-sigs" : "--list-keys"));
   
   /* Tell the gpg object about the data.  */
@@ -1493,13 +1499,13 @@ gpg_keylist (void *engine, const char *pattern, int secret_only,
 
 static gpgme_error_t
 gpg_keylist_ext (void *engine, const char *pattern[], int secret_only,
-                int reserved, int keylist_mode)
+                int reserved, gpgme_keylist_mode_t mode)
 {
-  GpgObject gpg = engine;
+  engine_gpg_t gpg = engine;
   gpgme_error_t err;
 
   if (reserved)
-    return GPGME_Invalid_Value;
+    return gpg_error (GPG_ERR_INV_VALUE);
 
   err = add_arg (gpg, "--with-colons");
   if (!err)
@@ -1510,15 +1516,14 @@ gpg_keylist_ext (void *engine, const char *pattern[], int secret_only,
     err = add_arg (gpg, "--with-fingerprint");
   if (!err)
     err = add_arg (gpg, secret_only ? "--list-secret-keys"
-                  : ((keylist_mode & GPGME_KEYLIST_MODE_SIGS)
+                  : ((mode & GPGME_KEYLIST_MODE_SIGS)
                      ? "--check-sigs" : "--list-keys"));
-
-  /* Tell the gpg object about the data.  */
   if (!err)
     err = add_arg (gpg, "--");
-  if (!err && pattern && *pattern)
+
+  if (pattern)
     {
-      while (*pattern && **pattern)
+      while (!err && *pattern && **pattern)
        err = add_arg (gpg, *(pattern++));
     }
 
@@ -1534,7 +1539,7 @@ gpg_sign (void *engine, gpgme_data_t in, gpgme_data_t out,
          gpgme_sig_mode_t mode, int use_armor, int use_textmode,
          int include_certs, gpgme_ctx_t ctx /* FIXME */)
 {
-  GpgObject gpg = engine;
+  engine_gpg_t gpg = engine;
   gpgme_error_t err;
 
   if (mode == GPGME_SIG_MODE_CLEAR)
@@ -1547,7 +1552,7 @@ gpg_sign (void *engine, gpgme_data_t in, gpgme_data_t out,
       if (!err && use_armor)
        err = add_arg (gpg, "--armor");
       if (!err && use_textmode)
-       add_arg (gpg, "--textmode");
+       err = add_arg (gpg, "--textmode");
     }
 
   if (!err)
@@ -1568,7 +1573,7 @@ gpg_sign (void *engine, gpgme_data_t in, gpgme_data_t out,
 static gpgme_error_t
 gpg_trustlist (void *engine, const char *pattern)
 {
-  GpgObject gpg = engine;
+  engine_gpg_t gpg = engine;
   gpgme_error_t err;
 
   err = add_arg (gpg, "--with-colons");
@@ -1592,7 +1597,7 @@ static gpgme_error_t
 gpg_verify (void *engine, gpgme_data_t sig, gpgme_data_t signed_text,
            gpgme_data_t plaintext)
 {
-  GpgObject gpg = engine;
+  engine_gpg_t gpg = engine;
   gpgme_error_t err = 0;
 
   if (plaintext)
@@ -1635,7 +1640,7 @@ gpg_verify (void *engine, gpgme_data_t sig, gpgme_data_t signed_text,
 static void
 gpg_set_io_cbs (void *engine, gpgme_io_cbs_t io_cbs)
 {
-  GpgObject gpg = engine;
+  engine_gpg_t gpg = engine;
 
   gpg->io_cbs = *io_cbs;
 }
@@ -1660,6 +1665,7 @@ struct engine_ops _gpgme_engine_ops_gpg =
     gpg_encrypt,
     gpg_encrypt_sign,
     gpg_export,
+    gpg_export_ext,
     gpg_genkey,
     gpg_import,
     gpg_keylist,