2002-07-03 Marcus Brinkmann <marcus@g10code.de>
authorMarcus Brinkmann <mb@g10code.com>
Wed, 3 Jul 2002 01:57:03 +0000 (01:57 +0000)
committerMarcus Brinkmann <mb@g10code.com>
Wed, 3 Jul 2002 01:57:03 +0000 (01:57 +0000)
* gpgme.c (gpgme_set_io_cbs): Deal with CTX being NULL.

* gpgme.c (_gpgme_op_event_cb_user): New function.
* op-support.c (_gpgme_op_reset): Support a new mode of operation
for private or user event loop.  Use new user event callback
wrapper.
* trustlist.c (gpgme_op_trustlist_start): Use this new mode.
* keylist.c (gpgme_op_keylist_start): Likewise.

* rungpg.c (_gpgme_gpg_io_event): New function.
* rungpg.h (_gpgme_gpg_io_event): New prototype.
* engine-gpgsm.c (_gpgme_gpg_io_event): New function.
* engine-gpgsm.h (_gpgme_gpgsm_io_event): New prototype.
* engine.c (_gpgme_engine_io_event): New function.
* engine.h (_gpgme_engine_io_event): New prototype.
* keylist.c (finish_key): Call _gpgme_engine_io_event, and move
the real work for the default IO callback routines to ...
(_gpgme_op_keylist_event_cb): ... here.  New function.
* trustlist.c (trustlist_colon_handler): Signal
GPGME_EVENT_NEXT_TRUSTITEM.  Move queue manipulation to ...
(_gpgme_op_trustlist_event_cb): ... here.  New function.
* gpgme.c (_gpgme_op_event_cb): Call _gpgme_op_keylist_event_cb
and _gpgme_op_trustlist_event_cb when appropriate.
* ops.h (_gpgme_op_keylist_event_cb): New prototype.
(_gpgme_op_trustlist_event_cb): Likewise.
* op-support.c (_gpgme_op_reset): Add comment why we don't use the
user provided event handler directly.
* gpgme.h (GpgmeRegisterIOCb): Return GpgmeError value, and TAG in
a pointer argument.
* wait.c (_gpgme_add_io_cb): Likewise.
* wait.h (_gpgme_add_io_cb): Likewise for prototype.
* rungpg.c (_gpgme_gpg_add_io_cb): Call IO_CBS->add with new
argument.  Fix up error handling.
* engine-gpgsm.c (_gpgme_gpgsm_add_io_cb): Call IO_CBS->add with
new argument, fix up error handling.

15 files changed:
gpgme/ChangeLog
gpgme/engine-gpgsm.c
gpgme/engine-gpgsm.h
gpgme/engine.c
gpgme/engine.h
gpgme/gpgme.c
gpgme/gpgme.h
gpgme/keylist.c
gpgme/op-support.c
gpgme/ops.h
gpgme/rungpg.c
gpgme/rungpg.h
gpgme/trustlist.c
gpgme/wait.c
gpgme/wait.h

index ebae975..86df1c7 100644 (file)
@@ -1,3 +1,41 @@
+2002-07-03  Marcus Brinkmann  <marcus@g10code.de>
+
+       * gpgme.c (gpgme_set_io_cbs): Deal with CTX being NULL.
+
+       * gpgme.c (_gpgme_op_event_cb_user): New function.
+       * op-support.c (_gpgme_op_reset): Support a new mode of operation
+       for private or user event loop.  Use new user event callback
+       wrapper.
+       * trustlist.c (gpgme_op_trustlist_start): Use this new mode.
+       * keylist.c (gpgme_op_keylist_start): Likewise.
+
+       * rungpg.c (_gpgme_gpg_io_event): New function.
+       * rungpg.h (_gpgme_gpg_io_event): New prototype.
+       * engine-gpgsm.c (_gpgme_gpg_io_event): New function.
+       * engine-gpgsm.h (_gpgme_gpgsm_io_event): New prototype.
+       * engine.c (_gpgme_engine_io_event): New function.
+       * engine.h (_gpgme_engine_io_event): New prototype.
+       * keylist.c (finish_key): Call _gpgme_engine_io_event, and move
+       the real work for the default IO callback routines to ...
+       (_gpgme_op_keylist_event_cb): ... here.  New function.
+       * trustlist.c (trustlist_colon_handler): Signal
+       GPGME_EVENT_NEXT_TRUSTITEM.  Move queue manipulation to ...
+       (_gpgme_op_trustlist_event_cb): ... here.  New function.
+       * gpgme.c (_gpgme_op_event_cb): Call _gpgme_op_keylist_event_cb
+       and _gpgme_op_trustlist_event_cb when appropriate.
+       * ops.h (_gpgme_op_keylist_event_cb): New prototype.
+       (_gpgme_op_trustlist_event_cb): Likewise.
+       * op-support.c (_gpgme_op_reset): Add comment why we don't use the
+       user provided event handler directly.
+       * gpgme.h (GpgmeRegisterIOCb): Return GpgmeError value, and TAG in
+       a pointer argument.
+       * wait.c (_gpgme_add_io_cb): Likewise.
+       * wait.h (_gpgme_add_io_cb): Likewise for prototype.
+       * rungpg.c (_gpgme_gpg_add_io_cb): Call IO_CBS->add with new
+       argument.  Fix up error handling.
+       * engine-gpgsm.c (_gpgme_gpgsm_add_io_cb): Call IO_CBS->add with
+       new argument, fix up error handling.
+
 2002-06-28  Marcus Brinkmann  <marcus@g10code.de>
 
        * keylist.c (gpgme_op_keylist_ext_start): Always use our own FD
index 67f1e7c..5dd28f9 100644 (file)
@@ -1290,14 +1290,14 @@ static GpgmeError
 _gpgme_gpgsm_add_io_cb (GpgsmObject gpgsm, iocb_data_t *iocbd,
                        GpgmeIOCb handler)
 {
-  GpgmeError err = 0;
+  GpgmeError err;
 
-  iocbd->tag = (*gpgsm->io_cbs.add) (gpgsm->io_cbs.add_priv,
-                                    iocbd->fd, iocbd->dir,
-                                    handler, iocbd->data);
-  if (!iocbd->tag)
-    err = mk_error (General_Error);
-  if (!err && !iocbd->dir)
+  err = (*gpgsm->io_cbs.add) (gpgsm->io_cbs.add_priv,
+                             iocbd->fd, iocbd->dir,
+                             handler, iocbd->data, &iocbd->tag);
+  if (err)
+    return err;
+  if (!iocbd->dir)
     /* FIXME Kludge around poll() problem.  */
     err = _gpgme_io_set_nonblocking (iocbd->fd);
   return err;
@@ -1338,6 +1338,12 @@ _gpgme_gpgsm_set_io_cbs (GpgsmObject gpgsm, struct GpgmeIOCbs *io_cbs)
   gpgsm->io_cbs = *io_cbs;
 }
 
+void
+_gpgme_gpgsm_io_event (GpgsmObject gpgsm, GpgmeEventIO type, void *type_data)
+{
+  if (gpgsm->io_cbs.event)
+    (*gpgsm->io_cbs.event) (gpgsm->io_cbs.event_priv, type, type_data);
+}
 
 #else  /* ENABLE_GPGSM */
 
@@ -1486,4 +1492,9 @@ _gpgme_gpgsm_set_io_cbs (GpgsmObject gpgsm, struct GpgmeIOCbs *io_cbs)
 {
 }
 
+void
+_gpgme_gpgsm_io_event (GpgsmObject gpgsm, GpgmeEventIO type, void *type_data)
+{
+}
+
 #endif /* ! ENABLE_GPGSM */
index cbfc4d9..6092829 100644 (file)
@@ -64,5 +64,6 @@ GpgmeError _gpgme_gpgsm_op_verify (GpgsmObject gpgsm, GpgmeData sig,
                                   GpgmeData text);
 GpgmeError _gpgme_gpgsm_start (GpgsmObject gpgsm, void *opaque);
 void _gpgme_gpgsm_set_io_cbs (GpgsmObject gpgsm, struct GpgmeIOCbs *io_cbs);
+void _gpgme_gpgsm_io_event (GpgsmObject gpgsm, GpgmeEventIO type, void *type_data);
 
 #endif /* ENGINE_GPGSM_H */
index 91d10c0..52d00e1 100644 (file)
@@ -587,6 +587,26 @@ _gpgme_engine_set_io_cbs (EngineObject engine,
     }
 }
 
+void
+_gpgme_engine_io_event (EngineObject engine,
+                       GpgmeEventIO type, void *type_data)
+{
+  if (!engine)
+    return;
+
+  switch (engine->protocol)
+    {
+    case GPGME_PROTOCOL_OpenPGP:
+      _gpgme_gpg_io_event (engine->engine.gpg, type, type_data);
+      break;
+    case GPGME_PROTOCOL_CMS:
+      _gpgme_gpgsm_io_event (engine->engine.gpgsm, type, type_data);
+      break;
+    default:
+      break;
+    }
+}
+
 \f
 void
 _gpgme_engine_add_child_to_reap_list (void *buf, int buflen, pid_t pid)
index a364031..5f23d2f 100644 (file)
@@ -78,6 +78,8 @@ GpgmeError _gpgme_engine_start (EngineObject engine, void *opaque);
 
 void _gpgme_engine_set_io_cbs (EngineObject engine,
                               struct GpgmeIOCbs *io_cbs);
+void _gpgme_engine_io_event (EngineObject engine,
+                            GpgmeEventIO type, void *type_data);
 
 void _gpgme_engine_add_child_to_reap_list (void *buf, int buflen, pid_t pid);
 void _gpgme_engine_housecleaning (void);
index ed14996..2caa737 100644 (file)
@@ -507,7 +507,10 @@ gpgme_get_progress_cb (GpgmeCtx ctx, GpgmeProgressCb *r_cb, void **r_cb_value)
 void
 gpgme_set_io_cbs (GpgmeCtx ctx, struct GpgmeIOCbs *io_cbs)
 {
-  if (ctx && io_cbs)
+  if (!ctx)
+    return;
+
+  if (io_cbs)
     ctx->io_cbs = *io_cbs;
   else
     {
@@ -544,9 +547,36 @@ _gpgme_op_event_cb (void *data, GpgmeEventIO type, void *type_data)
 {
   GpgmeCtx ctx = data;
 
-  if (type == GPGME_EVENT_DONE)
-    ctx->pending = 0;
+  switch (type)
+    {
+    case GPGME_EVENT_DONE:
+      ctx->pending = 0;
+      break;
+
+    case GPGME_EVENT_NEXT_KEY:
+      _gpgme_op_keylist_event_cb (data, type, type_data);
+      break;
 
-  if (ctx->io_cbs.add && ctx->io_cbs.event)
-    (*ctx->io_cbs.event) (ctx->io_cbs.event_priv, type, type_data);
+    case GPGME_EVENT_NEXT_TRUSTITEM:
+      _gpgme_op_trustlist_event_cb (data, type, type_data);
+      break;
+    }
+}
+
+void
+_gpgme_op_event_cb_user (void *data, GpgmeEventIO type, void *type_data)
+{
+  GpgmeCtx ctx = data;
+
+  if (type == GPGME_EVENT_DONE)
+    {
+      ctx->pending = 0;
+      if (ctx->io_cbs.event)
+       (*ctx->io_cbs.event) (ctx->io_cbs.event_priv, type, &ctx->error);
+    }
+  else
+    {
+      if (ctx->io_cbs.event)
+       (*ctx->io_cbs.event) (ctx->io_cbs.event_priv, type, type_data);
+    }
 }
index a4afc92..7f0a9bf 100644 (file)
@@ -339,12 +339,13 @@ char *gpgme_get_op_info (GpgmeCtx ctx, int reserved);
 typedef void (*GpgmeIOCb) (void *data, int fd);
 
 /* The type of a function that can register FNC as the I/O callback
-   function for the file descriptor FD with direction dir (0: inbound,
-   1: outbound).  FNC_DATA should be passed as DATA to FNC.  The
+   function for the file descriptor FD with direction dir (0: for writing,
+   1: for reading).  FNC_DATA should be passed as DATA to FNC.  The
    function should return a TAG suitable for the corresponding
-   GpgmeRemoveIOCb.  */
-typedef void *(*GpgmeRegisterIOCb) (void *data, int fd, int dir,
-                                   GpgmeIOCb fnc, void *fnc_data);
+   GpgmeRemoveIOCb, and an error value.  */
+typedef GpgmeError (*GpgmeRegisterIOCb) (void *data, int fd, int dir,
+                                        GpgmeIOCb fnc, void *fnc_data,
+                                        void **tag);
 
 /* The type of a function that can remove a previously registered I/O
    callback function given TAG as returned by the register
@@ -370,13 +371,13 @@ struct GpgmeIOCbs
 };
 
 /* Set the I/O callback functions in CTX to IO_CBS.  */
-void gpgme_set_op_io_cbs (GpgmeCtx ctx, struct GpgmeIOCbs *io_cbs);
+void gpgme_set_io_cbs (GpgmeCtx ctx, struct GpgmeIOCbs *io_cbs);
 
 /* Get the current I/O callback functions.  */
-void gpgme_get_op_io_cbs (GpgmeCtx ctx, struct GpgmeIOCbs *io_cbs);
+void gpgme_get_io_cbs (GpgmeCtx ctx, struct GpgmeIOCbs *io_cbs);
 
 /* Cancel a pending operation in CTX.  */
-void       gpgme_cancel (GpgmeCtx ctx);
+void gpgme_cancel (GpgmeCtx ctx);
 
 /* Process the pending operation and, if HANG is non-zero, wait for
    the pending operation to finish.  */
index 5fe3701..baf1efc 100644 (file)
@@ -514,35 +514,45 @@ static void
 finish_key (GpgmeCtx ctx)
 {
   GpgmeKey key = ctx->tmp_key;
-  struct key_queue_item_s *q, *q2;
+
+  ctx->tmp_key = NULL;
 
   if (key)
+    _gpgme_engine_io_event (ctx->engine, GPGME_EVENT_NEXT_KEY, key);
+}
+
+
+void
+_gpgme_op_keylist_event_cb (void *data, GpgmeEventIO type, void *type_data)
+{
+  GpgmeCtx ctx = (GpgmeCtx) data;
+  GpgmeKey key = (GpgmeKey) type_data;
+  struct key_queue_item_s *q, *q2;
+
+  assert (type == GPGME_EVENT_NEXT_KEY);
+
+  _gpgme_key_cache_add (key);
+
+  q = xtrymalloc (sizeof *q);
+  if (!q)
     {
-      ctx->tmp_key = NULL;
-        
-      _gpgme_key_cache_add (key);
-        
-      q = xtrymalloc (sizeof *q);
-      if (!q)
-       {
-         gpgme_key_release (key);
-         ctx->error = mk_error (Out_Of_Core);
-         return;
-        }
-      q->key = key;
-      q->next = NULL;
-      /* FIXME: Lock queue.  Use a tail pointer?  */
-      if (!(q2 = ctx->key_queue))
-       ctx->key_queue = q;
-      else
-       {
-         for (; q2->next; q2 = q2->next)
-           ;
-         q2->next = q;
-        }
-      ctx->key_cond = 1;
-      /* FIXME: Unlock queue.  */
+      gpgme_key_release (key);
+      ctx->error = mk_error (Out_Of_Core);
+      return;
     }
+  q->key = key;
+  q->next = NULL;
+  /* FIXME: Lock queue.  Use a tail pointer?  */
+  if (!(q2 = ctx->key_queue))
+    ctx->key_queue = q;
+  else
+    {
+      for (; q2->next; q2 = q2->next)
+       ;
+      q2->next = q;
+    }
+  ctx->key_cond = 1;
+  /* FIXME: Unlock queue.  */
 }
 
 
@@ -563,9 +573,7 @@ gpgme_op_keylist_start (GpgmeCtx ctx, const char *pattern, int secret_only)
 {
   GpgmeError err = 0;
 
-  /* Keylist operations are always "synchronous" in the sense that we
-     don't add ourself to the global FD table.  */
-  err = _gpgme_op_reset (ctx, 1);
+  err = _gpgme_op_reset (ctx, 2);
   if (err)
     goto leave;
 
index bf61c72..125b723 100644 (file)
 #include "context.h"
 #include "ops.h"
 
+/* type is: 0: asynchronous operation (use global or user event loop).
+            1: synchronous operation (always use private event loop).
+            2: asynchronous private operation (use private or user
+            event loop).  */
 GpgmeError
-_gpgme_op_reset (GpgmeCtx ctx, int synchronous)
+_gpgme_op_reset (GpgmeCtx ctx, int type)
 {
   GpgmeError err = 0;
   struct GpgmeIOCbs io_cbs;
@@ -43,8 +47,9 @@ _gpgme_op_reset (GpgmeCtx ctx, int synchronous)
   if (err)
     return err;
 
-  if (synchronous)
+  if (type == 1 || (type == 2 && !ctx->io_cbs.add))
     {
+      /* Use private event loop.  */
       io_cbs.add = _gpgme_add_io_cb;
       io_cbs.add_priv = &ctx->fdt;
       io_cbs.remove = _gpgme_remove_io_cb;
@@ -53,6 +58,7 @@ _gpgme_op_reset (GpgmeCtx ctx, int synchronous)
     }
   else if (! ctx->io_cbs.add)
     {
+      /* Use global event loop.  */
       io_cbs.add = _gpgme_add_io_cb;
       io_cbs.add_priv = NULL;
       io_cbs.remove = _gpgme_remove_io_cb;
@@ -61,8 +67,12 @@ _gpgme_op_reset (GpgmeCtx ctx, int synchronous)
     }
   else
     {
+      /* Use user event loop.  */
       io_cbs = ctx->io_cbs;
-      io_cbs.event = _gpgme_op_event_cb;
+      /* We have to make sure that we notice the termination of the
+        operation ourself, so we stack another event handler on top
+        of the user-provided one.  */
+      io_cbs.event = _gpgme_op_event_cb_user;
       io_cbs.event_priv = ctx;
     }
   _gpgme_engine_set_io_cbs (ctx->engine, &io_cbs);
index 56da5d3..8eebfb5 100644 (file)
@@ -47,6 +47,7 @@ void _gpgme_release_result ( GpgmeCtx c );
 void _gpgme_set_op_info (GpgmeCtx c, GpgmeData info);
 
 void _gpgme_op_event_cb (void *data, GpgmeEventIO type, void *type_data);
+void _gpgme_op_event_cb_user (void *data, GpgmeEventIO type, void *type_data);
 
 /*-- wait.c --*/
 GpgmeError _gpgme_wait_one (GpgmeCtx ctx);
@@ -131,6 +132,10 @@ void _gpgme_release_genkey_result (GenKeyResult res);
 
 /*-- keylist.c --*/
 void _gpgme_release_keylist_result (KeylistResult res);
+void _gpgme_op_keylist_event_cb (void *data, GpgmeEventIO type, void *type_data);
+
+/*-- trustlist.c --*/
+void _gpgme_op_trustlist_event_cb (void *data, GpgmeEventIO type, void *type_data);
 
 /*-- version.c --*/
 const char *_gpgme_compare_versions (const char *my_version,
index dcc96bf..f200d08 100644 (file)
@@ -212,8 +212,8 @@ close_notify_handler (int fd, void *opaque)
            break;
          }
     }
-  if (!not_done && gpg->io_cbs.event)
-    (*gpg->io_cbs.event) (gpg->io_cbs.event_priv, GPGME_EVENT_DONE, NULL);
+  if (!not_done)
+    _gpgme_gpg_io_event (gpg, GPGME_EVENT_DONE, NULL);
 }
 
 const char *
@@ -807,12 +807,12 @@ static GpgmeError
 _gpgme_gpg_add_io_cb (GpgObject gpg, int fd, int dir,
                      GpgmeIOCb handler, void *data, void **tag)
 {
-  GpgmeError err = 0;
+  GpgmeError err;
 
-  *tag = (*gpg->io_cbs.add) (gpg->io_cbs.add_priv, fd, dir, handler, data);
-  if (!tag)
-    err = mk_error (General_Error);
-  if (!err && !dir)
+  err = (*gpg->io_cbs.add) (gpg->io_cbs.add_priv, fd, dir, handler, data, tag);
+  if (err)
+    return err;
+  if (!dir)
     /* FIXME Kludge around poll() problem.  */
     err = _gpgme_io_set_nonblocking (fd);
   return err;
@@ -1749,3 +1749,11 @@ _gpgme_gpg_set_io_cbs (GpgObject gpg, struct GpgmeIOCbs *io_cbs)
 {
   gpg->io_cbs = *io_cbs;
 }
+
+
+void
+_gpgme_gpg_io_event (GpgObject gpg, GpgmeEventIO type, void *type_data)
+{
+  if (gpg->io_cbs.event)
+    (*gpg->io_cbs.event) (gpg->io_cbs.event_priv, type, type_data);
+}
index a798caf..2c6fcb7 100644 (file)
@@ -162,5 +162,6 @@ GpgmeError _gpgme_gpg_op_trustlist (GpgObject gpg, const char *pattern);
 GpgmeError _gpgme_gpg_op_verify (GpgObject gpg, GpgmeData sig, GpgmeData text);
 GpgmeError _gpgme_gpg_spawn (GpgObject gpg, void *opaque);
 void _gpgme_gpg_set_io_cbs (GpgObject gpg, struct GpgmeIOCbs *io_cbs);
+void _gpgme_gpg_io_event (GpgObject gpg, GpgmeEventIO type, void *type_data);
 
 #endif /* RUNGPG_H */
index 3d10e51..2fd4b9c 100644 (file)
@@ -87,7 +87,6 @@ trustlist_colon_handler (GpgmeCtx ctx, char *line)
   char *p, *pend;
   int field = 0;
   GpgmeTrustItem item = NULL;
-  struct trust_queue_item_s *q, *q2;
 
   if (ctx->error)
     return;
@@ -104,31 +103,12 @@ trustlist_colon_handler (GpgmeCtx ctx, char *line)
       switch (field)
        {
        case 1: /* level */
-         q = xtrymalloc (sizeof *q);
-         if (!q)
-           {
-             ctx->error = mk_error (Out_Of_Core);
-             return;
-            }
-         q->next = NULL;
-         q->item = item = trust_item_new ();
-         if (!q->item)
+         item = trust_item_new ();
+         if (!item)
            {
-             xfree (q);
              ctx->error = mk_error (Out_Of_Core);
              return;
             }
-         /* fixme: lock queue, keep a tail pointer */
-         q2 = ctx->trust_queue;
-         if (!q2)
-           ctx->trust_queue = q;
-         else
-           {
-             while (q2->next)
-               q2 = q2->next;
-             q2->next = q;
-            }
-         /* fixme: unlock queue */
          item->level = atoi (p);
          break;
        case 2: /* long keyid */
@@ -154,8 +134,41 @@ trustlist_colon_handler (GpgmeCtx ctx, char *line)
         }
     }
 
-  if (field)
-    ctx->key_cond = 1;
+  if (item)
+    _gpgme_engine_io_event (ctx->engine, GPGME_EVENT_NEXT_TRUSTITEM, item);
+}
+
+
+void
+_gpgme_op_trustlist_event_cb (void *data, GpgmeEventIO type, void *type_data)
+{
+  GpgmeCtx ctx = (GpgmeCtx) data;
+  GpgmeTrustItem item = (GpgmeTrustItem) type_data;
+  struct trust_queue_item_s *q, *q2;
+
+  assert (type == GPGME_EVENT_NEXT_KEY);
+
+  q = xtrymalloc (sizeof *q);
+  if (!q)
+    {
+      gpgme_trust_item_release (item);
+      ctx->error = mk_error (Out_Of_Core);
+      return;
+    }
+  q->item = item;
+  q->next = NULL;
+  /* FIXME: lock queue, keep a tail pointer */
+  q2 = ctx->trust_queue;
+  if (!q2)
+    ctx->trust_queue = q;
+  else
+    {
+      while (q2->next)
+       q2 = q2->next;
+      q2->next = q;
+    }
+  /* FIXME: unlock queue */
+  ctx->key_cond = 1;
 }
 
 
@@ -167,9 +180,7 @@ gpgme_op_trustlist_start (GpgmeCtx ctx, const char *pattern, int max_level)
   if (!pattern || !*pattern)
     return mk_error (Invalid_Value);
 
-  /* Trustlist operations are always "synchronous" in the sense that
-     we don't add ourself to the global FD table.  */
-  err = _gpgme_op_reset (ctx, 1);
+  err = _gpgme_op_reset (ctx, 2);
   if (err)
     goto leave;
 
index 79f3ca7..c73f486 100644 (file)
@@ -332,9 +332,9 @@ struct tag
   int idx;
 };
 
-void *
+GpgmeError
 _gpgme_add_io_cb (void *data, int fd, int dir,
-                 GpgmeIOCb fnc, void *fnc_data)
+                 GpgmeIOCb fnc, void *fnc_data, void **r_tag)
 {
   GpgmeError err;
   fd_table_t fdt = (fd_table_t) (data ? data : &fdt_global);
@@ -344,9 +344,10 @@ _gpgme_add_io_cb (void *data, int fd, int dir,
   assert (fdt);
   assert (fnc);
 
+  *r_tag = NULL;
   tag = xtrymalloc (sizeof *tag);
   if (!tag)
-    return NULL;
+    return mk_error (Out_Of_Core);
   tag->fdt = fdt;
 
   /* Allocate a structure to hold info about the handler.  */
@@ -354,7 +355,7 @@ _gpgme_add_io_cb (void *data, int fd, int dir,
   if (!item)
     {
       xfree (tag);
-      return NULL;
+      return mk_error (Out_Of_Core);
     }
   item->dir = dir;
   item->handler = fnc;
@@ -365,11 +366,11 @@ _gpgme_add_io_cb (void *data, int fd, int dir,
     {
       xfree (tag);
       xfree (item);
-      errno = ENOMEM;
-      return 0;
+      return mk_error (Out_Of_Core);
     }
-  
-  return tag;
+
+  *r_tag = tag;
+  return 0;
 }
 
 void
index b782876..de459cc 100644 (file)
@@ -36,8 +36,8 @@ typedef struct fd_table *fd_table_t;
 void _gpgme_fd_table_init (fd_table_t fdt);
 void _gpgme_fd_table_deinit (fd_table_t fdt);
 
-void *_gpgme_add_io_cb (void *data, int fd, int dir,
-                       GpgmeIOCb fnc, void *fnc_data);
+GpgmeError _gpgme_add_io_cb (void *data, int fd, int dir,
+                            GpgmeIOCb fnc, void *fnc_data, void **r_tag);
 void _gpgme_remove_io_cb (void *tag);
 void _gpgme_wait_event_cb (void *data, GpgmeEventIO type, void *type_data);