2002-06-10 Marcus Brinkmann <marcus@g10code.de>
authorMarcus Brinkmann <mb@g10code.com>
Mon, 10 Jun 2002 14:13:55 +0000 (14:13 +0000)
committerMarcus Brinkmann <mb@g10code.com>
Mon, 10 Jun 2002 14:13:55 +0000 (14:13 +0000)
* engine-gpgsm.c (_gpgme_gpgsm_start): Move the code that sets the
close notification for the status fd to ...
(_gpgme_gpgsm_new): ... here.
* wait.h: Include "sema.h".  Remove prototypes of
_gpgme_remove_proc_from_wait_queue and
_gpgme_register_pipe_handler.  Add prototypes of
_gpgme_fd_table_init, _gpgme_fd_table_deinit, _gpgme_fd_table_put,
_gpgme_add_io_cb, _gpgme_remove_io_cb, _gpgme_wait_event_cb and
_gpgme_wait_one..
* wait.c: Remove global variables PROC_QUEUE, PROC_QUEUE_LOCK,
FD_TABLE_SIZE, FD_TABLE, FD_TABLE_LOCK.  New global variables
FDT_GLOBAL, CTX_DONE_LIST, CTX_DONE_LIST_SIZE,
CTX_DONE_LIST_LENGTH and CTX_DONE_LIST_LOCK.  Remove struct
proc_s.  Replace struct wait_item_s.
(_gpgme_fd_table_init): New function.
(_gpgme_fd_table_deinit): Likewise.
(_gpgme_fd_table_put): Likewise.
(set_process_done): Remove function.
(do_select): Take argument FDT.  Use that to decide which fds to
select on.
(_gpgme_remove_proc_from_wait_queue): Remove function.
(_gpgme_wait_event_cb): New function.
(_gpgme_wait_one): Likewise.
(_gpgme_register_pipe_hanldler): Remove function.
(_gpgme_add_io_cb): New function.
(_gpgme_remove_io_cb): Likewise.
(_gpgme_freeze_fd): Remove function.
(_gpgme_thaw_fd): Remove function.
* rungpg.c (struct fd_data_map_s): Add new member TAG.
(struct gpg_object_s): Likewise for STATUS and COLON.  Add member
IDX to CMD.  Add new member IO_CBS.
(close_notify_handler): New variables POSSIBLY_DONE and NOT_DONE.
For each I/O callback, check if it should be unregistered.  If all
callbacks have been unregistered, trigger GPGME_EVENT_DONE.
Remove member RUNNING.
(_gpgme_gpg_new): Initialize new members.
(_gpgme_gpg_release): Check PID not RUNNING.  Don't call
_gpgme_remove_proc_from_wait_queue.  Close GPG->CMD.FD if set.
(build_argv): Store away the index instead the file descriptor for
CMD.
(_gpgme_gpg_add_io_cb): New function.
(_gpgme_gpg_spawn): Use _gpgme_gpg_add_io_cb to register IO
callbacks.
(gpg_status_handler): Change return type to void, remove PID
argument, close filedescriptor if EOF or error occurs.
(read_status): Use _gpgme_gpg_add_io_cb instead _gpgme_thaw_fd.
Use IO_CBS->remove instead _gpgme_freeze_fd.
(gpg_colon_line_handler): Change return type to void, remove PID
argument, close filedescriptor if EOF or error occurs.
(command_cb): Use IO_CBS->remove instead _gpgme_freeze_fd.
(_gpgme_gpg_set_io_cbs): New function.
* rungpg.h (_gpgme_gpg_set_io_cbs): Prototype for
_gpgme_gpg_set_io_cbs.
* gpgme.h (GpgmeIOCb): New type.
(GpgmeRegisterIOCb): Likewise.
(GpgmeRemoveIOCb): Likewise.
(GpgmeEventIO): Likewise.
(GpgmeEventIOCb): Likewise.
(struct GpgmeIOCbs): New structure to hold I/O callbacks.
(gpgme_set_op_io_cbs): New prototype.
(gpgme_get_op_io_cbs): Likewise.
* ops.h: New prototype for _gpgme_op_event_cb.  Remove prototypes
for _gpgme_freeze_fd and _gpgme_thaw_fd.  Remove PID argument from
_gpgme_data_inbound_handler and _gpgme_data_outbound_handler
prototype.  Add prototype for _gpgme_op_reset.
Add synchronous argument to _gpgme_decrypt_start prototype.
* io.h: Beautification.
* gpgme.c: Include "wait.h".
(gpgme_new): Initialize FDT.
(gpgme_set_io_cbs): New function.
(gpgme_get_io_cbs): Likewise.
(_gpgme_op_event_cb): Likewise.
* data.c (_gpgme_data_inbound_handler): Change return type to
void.  Drop PID argument.  Close FD on error and EOF.
(write_mem_data): Don't close FD here ...
(write_cb_data): ... or here ...
(_gpgme_data_outbound_handler): ... but here.  Change return type
to void.  Drop PID argument.
* context.h: Include "wait.h".
(struct gpgme_context_s): New members FDT and IO_CBS.
* op-support.c: New file.
* Makefile.am (libgpgme_la_SOURCES): Add op-support.c.
* ops.h: Add prototype for _gpgme_op_reset().
* decrypt.c (_gpgme_decrypt_start): New argument SYNCHRONOUS.  Use
_gpgme_op_reset.
(gpgme_op_decrypt_start): Add synchronous argument.
(gpgme_op_decrypt): Likewise.  Use _gpgme_wait_one instead
gpgme_wait.
* delete.c (gpgme_op_delete_start): Rename to ...
(_gpgme_op_delete_start): ... this.  New argument SYNCHRONOUS.
Use _gpgme_op_reset.  Make function static.
(gpgme_op_delete_start): Just a wrapper around
_gpgme_op_delete_start now.
(gpgme_op_delete): Add synchronous argument.  Use _gpgme_wait_one
instead gpgme_wait.
* encrypt.c: Include "wait.h".
(ggpgme_op_encrypt_start): Rename to ...
(_gpgme_op_encrypt_start): ... this.  New argument SYNCHRONOUS.
Use _gpgme_op_reset.  Make function static.
(gpgme_op_encrypt_start): Just a wrapper around
_gpgme_op_encrypt_start now.
(gpgme_op_encrypt): Add synchronous argument.  Use _gpgme_wait_one
instead gpgme_wait.
* encrypt_sign.c (gpgme_op_encrypt_sign_start): Rename to ...
(_gpgme_op_encrypt_sign_start): ... this.  New argument
SYNCHRONOUS.  Use _gpgme_op_reset.  Make function static.
(gpgme_op_encrypt_sign_start): Just a wrapper around
_gpgme_op_encrypt_sign_start now.
(gpgme_op_encrypt_sign): Add synchronous argument.  Use
_gpgme_wait_one instead gpgme_wait.
* export.c (gpgme_op_export_start): Rename to ...
(_gpgme_op_export_start): ... this.  New argument SYNCHRONOUS.
Use _gpgme_op_reset.  Make function static.
(gpgme_op_export_start): Just a wrapper around
_gpgme_op_export_start now.
(gpgme_op_export): Add synchronous argument.  Use _gpgme_wait_one
instead gpgme_wait.
* genkey.c (gpgme_op_genkey_start): Rename to ...
(_gpgme_op_genkey_start): ... this.  New argument SYNCHRONOUS.
Use _gpgme_op_reset.  Make function static.
(gpgme_op_genkey_start): Just a wrapper around
_gpgme_op_genkey_start now.
(gpgme_op_genkey): Add synchronous argument.  Use _gpgme_wait_one
instead gpgme_wait.
* import.c (gpgme_op_import_start): Rename to ...
(_gpgme_op_import_start): ... this.  New argument SYNCHRONOUS.
Use _gpgme_op_reset.  Make function static.
(gpgme_op_import_start): Just a wrapper around
_gpgme_op_import_start now.
(gpgme_op_import): Add synchronous argument.  Use _gpgme_wait_one
instead gpgme_wait.
* keylist.c (gpgme_op_keylist_start): Use _gpgme_op_reset.
(gpgme_op_keylist_ext_start): Likewise.
* sign.c (gpgme_op_sign_start): Rename to ...
(_gpgme_op_sign_start): ... this.  New argument SYNCHRONOUS.  Use
_gpgme_op_reset.  Make function static.
(gpgme_op_sign_start): Just a wrapper around _gpgme_op_sign_start
now.
(gpgme_op_sign): Add synchronous argument.  Use _gpgme_wait_one
instead gpgme_wait.
* trustlist.c (gpgme_op_trustlist_start): Use _gpgme_op_reset.
* verify.c (gpgme_op_verify_start): Rename to ...
(_gpgme_op_verify_start): ... this.  New argument SYNCHRONOUS.
Use _gpgme_op_reset.  Make function static.
(gpgme_op_verify_start): Just a wrapper around
_gpgme_op_verify_start now.
(gpgme_op_verify): Add synchronous argument.  Use _gpgme_wait_one
instead gpgme_wait.
* engine-gpgsm.c (iocb_data_t): New type.
(struct gpgsm_object_s): New member status_cb.  Replace input_fd
and input_data with input_cb.  Replace output_fd and output_data
with output_cb.  Replace message_fd and message_data with
message_cb.  New member io_cbs.
(_gpgme_gpgsm_new): Initialize all new members (and drop the old
ones).
(close_notify_handler): New variable POSSIBLY_DONE.  For each I/O
callback, check if it should be unregistered.  If all callbacks
have been unregistered, trigger GPGME_EVENT_DONE.
(_gpgme_gpgsm_release): Remove variable PID.  Use new variable
names to close the file descriptors.
(_gpgme_gpgsm_op_decrypt): Use new variable names,
(_gpgme_gpgsm_op_encrypt): Likewise.
(_gpgme_gpgsm_op_genkey): Likewise.
(_gpgme_gpgsm_op_import): Likewise.
(_gpgme_gpgsm_op_keylist): Likewise.
(_gpgme_gpgsm_op_keylist_ext): Likewise.
(_gpgme_gpgsm_op_sign): Likewise.
(_gpgme_gpgsm_op_verify): Likewise.
(gpgsm_status_handler): Drop argument PID.  Change return type to
void.  Close status pipe before returning because of EOF or error.
(_gpgme_gpgsm_add_io_cb): New function.
(_gpgme_gpgsm_start): Use _gpgme_gpgsm_add_io_cb to register
callback function.
(_gpgme_gpgsm_set_io_cbs): New function.
* engine-gpgsm.h: New prototype for _gpgme_gpgsm_set_io_cbs.
* engine.c (_gpgme_engine_set_io_cbs): New function.
* engine.h: New prototype for _gpgme_engine_set_io_cbs.

29 files changed:
gpgme/ChangeLog
gpgme/Makefile.am
gpgme/context.h
gpgme/data.c
gpgme/decrypt-verify.c
gpgme/decrypt.c
gpgme/delete.c
gpgme/encrypt-sign.c
gpgme/encrypt.c
gpgme/engine-gpgsm.c
gpgme/engine-gpgsm.h
gpgme/engine.c
gpgme/engine.h
gpgme/export.c
gpgme/genkey.c
gpgme/gpgme.c
gpgme/gpgme.h
gpgme/import.c
gpgme/io.h
gpgme/keylist.c
gpgme/op-support.c [new file with mode: 0644]
gpgme/ops.h
gpgme/rungpg.c
gpgme/rungpg.h
gpgme/sign.c
gpgme/trustlist.c
gpgme/verify.c
gpgme/wait.c
gpgme/wait.h

index 6c4dc51..1c65289 100644 (file)
@@ -1,3 +1,183 @@
+2002-06-10  Marcus Brinkmann  <marcus@g10code.de>
+
+       * engine-gpgsm.c (_gpgme_gpgsm_start): Move the code that sets the
+       close notification for the status fd to ...
+       (_gpgme_gpgsm_new): ... here.
+       * wait.h: Include "sema.h".  Remove prototypes of
+       _gpgme_remove_proc_from_wait_queue and
+       _gpgme_register_pipe_handler.  Add prototypes of
+       _gpgme_fd_table_init, _gpgme_fd_table_deinit, _gpgme_fd_table_put,
+       _gpgme_add_io_cb, _gpgme_remove_io_cb, _gpgme_wait_event_cb and
+       _gpgme_wait_one..
+       * wait.c: Remove global variables PROC_QUEUE, PROC_QUEUE_LOCK,
+       FD_TABLE_SIZE, FD_TABLE, FD_TABLE_LOCK.  New global variables
+       FDT_GLOBAL, CTX_DONE_LIST, CTX_DONE_LIST_SIZE,
+       CTX_DONE_LIST_LENGTH and CTX_DONE_LIST_LOCK.  Remove struct
+       proc_s.  Replace struct wait_item_s.
+       (_gpgme_fd_table_init): New function.
+       (_gpgme_fd_table_deinit): Likewise.
+       (_gpgme_fd_table_put): Likewise.
+       (set_process_done): Remove function.
+       (do_select): Take argument FDT.  Use that to decide which fds to
+       select on.
+       (_gpgme_remove_proc_from_wait_queue): Remove function.
+       (_gpgme_wait_event_cb): New function.
+       (_gpgme_wait_one): Likewise.
+       (_gpgme_register_pipe_hanldler): Remove function.
+       (_gpgme_add_io_cb): New function.
+       (_gpgme_remove_io_cb): Likewise.
+       (_gpgme_freeze_fd): Remove function.
+       (_gpgme_thaw_fd): Remove function.
+       * rungpg.c (struct fd_data_map_s): Add new member TAG.
+       (struct gpg_object_s): Likewise for STATUS and COLON.  Add member
+       IDX to CMD.  Add new member IO_CBS.
+       (close_notify_handler): New variables POSSIBLY_DONE and NOT_DONE.
+       For each I/O callback, check if it should be unregistered.  If all
+       callbacks have been unregistered, trigger GPGME_EVENT_DONE.
+       Remove member RUNNING.
+       (_gpgme_gpg_new): Initialize new members.
+       (_gpgme_gpg_release): Check PID not RUNNING.  Don't call
+       _gpgme_remove_proc_from_wait_queue.  Close GPG->CMD.FD if set.
+       (build_argv): Store away the index instead the file descriptor for
+       CMD.
+       (_gpgme_gpg_add_io_cb): New function.
+       (_gpgme_gpg_spawn): Use _gpgme_gpg_add_io_cb to register IO
+       callbacks.
+       (gpg_status_handler): Change return type to void, remove PID
+       argument, close filedescriptor if EOF or error occurs.
+       (read_status): Use _gpgme_gpg_add_io_cb instead _gpgme_thaw_fd.
+       Use IO_CBS->remove instead _gpgme_freeze_fd.
+       (gpg_colon_line_handler): Change return type to void, remove PID
+       argument, close filedescriptor if EOF or error occurs.
+       (command_cb): Use IO_CBS->remove instead _gpgme_freeze_fd.
+       (_gpgme_gpg_set_io_cbs): New function.
+       * rungpg.h (_gpgme_gpg_set_io_cbs): Prototype for
+       _gpgme_gpg_set_io_cbs.
+       * gpgme.h (GpgmeIOCb): New type.
+       (GpgmeRegisterIOCb): Likewise.
+       (GpgmeRemoveIOCb): Likewise.
+       (GpgmeEventIO): Likewise.
+       (GpgmeEventIOCb): Likewise.
+       (struct GpgmeIOCbs): New structure to hold I/O callbacks.
+       (gpgme_set_op_io_cbs): New prototype.
+       (gpgme_get_op_io_cbs): Likewise.
+       * ops.h: New prototype for _gpgme_op_event_cb.  Remove prototypes
+       for _gpgme_freeze_fd and _gpgme_thaw_fd.  Remove PID argument from
+       _gpgme_data_inbound_handler and _gpgme_data_outbound_handler
+       prototype.  Add prototype for _gpgme_op_reset.
+       Add synchronous argument to _gpgme_decrypt_start prototype.
+       * io.h: Beautification.
+       * gpgme.c: Include "wait.h".
+       (gpgme_new): Initialize FDT.
+       (gpgme_set_io_cbs): New function.
+       (gpgme_get_io_cbs): Likewise.
+       (_gpgme_op_event_cb): Likewise.
+       * data.c (_gpgme_data_inbound_handler): Change return type to
+       void.  Drop PID argument.  Close FD on error and EOF.
+       (write_mem_data): Don't close FD here ...
+       (write_cb_data): ... or here ...
+       (_gpgme_data_outbound_handler): ... but here.  Change return type
+       to void.  Drop PID argument.
+       * context.h: Include "wait.h".
+       (struct gpgme_context_s): New members FDT and IO_CBS.
+       * op-support.c: New file.
+       * Makefile.am (libgpgme_la_SOURCES): Add op-support.c.
+       * ops.h: Add prototype for _gpgme_op_reset().
+       * decrypt.c (_gpgme_decrypt_start): New argument SYNCHRONOUS.  Use
+       _gpgme_op_reset.
+       (gpgme_op_decrypt_start): Add synchronous argument.
+       (gpgme_op_decrypt): Likewise.  Use _gpgme_wait_one instead
+       gpgme_wait.
+       * delete.c (gpgme_op_delete_start): Rename to ...
+       (_gpgme_op_delete_start): ... this.  New argument SYNCHRONOUS.
+       Use _gpgme_op_reset.  Make function static.
+       (gpgme_op_delete_start): Just a wrapper around
+       _gpgme_op_delete_start now.
+       (gpgme_op_delete): Add synchronous argument.  Use _gpgme_wait_one
+       instead gpgme_wait.
+       * encrypt.c: Include "wait.h".
+       (ggpgme_op_encrypt_start): Rename to ...
+       (_gpgme_op_encrypt_start): ... this.  New argument SYNCHRONOUS.
+       Use _gpgme_op_reset.  Make function static.
+       (gpgme_op_encrypt_start): Just a wrapper around
+       _gpgme_op_encrypt_start now.
+       (gpgme_op_encrypt): Add synchronous argument.  Use _gpgme_wait_one
+       instead gpgme_wait.
+       * encrypt_sign.c (gpgme_op_encrypt_sign_start): Rename to ...
+       (_gpgme_op_encrypt_sign_start): ... this.  New argument
+       SYNCHRONOUS.  Use _gpgme_op_reset.  Make function static.
+       (gpgme_op_encrypt_sign_start): Just a wrapper around
+       _gpgme_op_encrypt_sign_start now.
+       (gpgme_op_encrypt_sign): Add synchronous argument.  Use
+       _gpgme_wait_one instead gpgme_wait.
+       * export.c (gpgme_op_export_start): Rename to ...
+       (_gpgme_op_export_start): ... this.  New argument SYNCHRONOUS.
+       Use _gpgme_op_reset.  Make function static.
+       (gpgme_op_export_start): Just a wrapper around
+       _gpgme_op_export_start now.
+       (gpgme_op_export): Add synchronous argument.  Use _gpgme_wait_one
+       instead gpgme_wait.
+       * genkey.c (gpgme_op_genkey_start): Rename to ...
+       (_gpgme_op_genkey_start): ... this.  New argument SYNCHRONOUS.
+       Use _gpgme_op_reset.  Make function static.
+       (gpgme_op_genkey_start): Just a wrapper around
+       _gpgme_op_genkey_start now.
+       (gpgme_op_genkey): Add synchronous argument.  Use _gpgme_wait_one
+       instead gpgme_wait.
+       * import.c (gpgme_op_import_start): Rename to ...
+       (_gpgme_op_import_start): ... this.  New argument SYNCHRONOUS.
+       Use _gpgme_op_reset.  Make function static.
+       (gpgme_op_import_start): Just a wrapper around
+       _gpgme_op_import_start now.
+       (gpgme_op_import): Add synchronous argument.  Use _gpgme_wait_one
+       instead gpgme_wait.
+       * keylist.c (gpgme_op_keylist_start): Use _gpgme_op_reset.
+       (gpgme_op_keylist_ext_start): Likewise.
+       * sign.c (gpgme_op_sign_start): Rename to ...
+       (_gpgme_op_sign_start): ... this.  New argument SYNCHRONOUS.  Use
+       _gpgme_op_reset.  Make function static.
+       (gpgme_op_sign_start): Just a wrapper around _gpgme_op_sign_start
+       now.
+       (gpgme_op_sign): Add synchronous argument.  Use _gpgme_wait_one
+       instead gpgme_wait.
+       * trustlist.c (gpgme_op_trustlist_start): Use _gpgme_op_reset.
+       * verify.c (gpgme_op_verify_start): Rename to ...
+       (_gpgme_op_verify_start): ... this.  New argument SYNCHRONOUS.
+       Use _gpgme_op_reset.  Make function static.
+       (gpgme_op_verify_start): Just a wrapper around
+       _gpgme_op_verify_start now.
+       (gpgme_op_verify): Add synchronous argument.  Use _gpgme_wait_one
+       instead gpgme_wait.
+       * engine-gpgsm.c (iocb_data_t): New type.
+       (struct gpgsm_object_s): New member status_cb.  Replace input_fd
+       and input_data with input_cb.  Replace output_fd and output_data
+       with output_cb.  Replace message_fd and message_data with
+       message_cb.  New member io_cbs.
+       (_gpgme_gpgsm_new): Initialize all new members (and drop the old
+       ones).
+       (close_notify_handler): New variable POSSIBLY_DONE.  For each I/O
+       callback, check if it should be unregistered.  If all callbacks
+       have been unregistered, trigger GPGME_EVENT_DONE.
+       (_gpgme_gpgsm_release): Remove variable PID.  Use new variable
+       names to close the file descriptors.
+       (_gpgme_gpgsm_op_decrypt): Use new variable names,
+       (_gpgme_gpgsm_op_encrypt): Likewise.
+       (_gpgme_gpgsm_op_genkey): Likewise.
+       (_gpgme_gpgsm_op_import): Likewise.
+       (_gpgme_gpgsm_op_keylist): Likewise.
+       (_gpgme_gpgsm_op_keylist_ext): Likewise.
+       (_gpgme_gpgsm_op_sign): Likewise.
+       (_gpgme_gpgsm_op_verify): Likewise.
+       (gpgsm_status_handler): Drop argument PID.  Change return type to
+       void.  Close status pipe before returning because of EOF or error.
+       (_gpgme_gpgsm_add_io_cb): New function.
+       (_gpgme_gpgsm_start): Use _gpgme_gpgsm_add_io_cb to register
+       callback function.
+       (_gpgme_gpgsm_set_io_cbs): New function.
+       * engine-gpgsm.h: New prototype for _gpgme_gpgsm_set_io_cbs.
+       * engine.c (_gpgme_engine_set_io_cbs): New function.
+       * engine.h: New prototype for _gpgme_engine_set_io_cbs.
+
 2002-06-04  Marcus Brinkmann  <marcus@g10code.de>
 
        * Makefile.am (libgpgme_la_SOURCES): Remove mutex.h.
index 6103594..382e452 100644 (file)
@@ -58,7 +58,8 @@ libgpgme_la_SOURCES = \
        util.h util.c \
        context.h ops.h \
        data.c recipient.c signers.c \
-        wait.c wait.h \
+       wait.c wait.h \
+       op-support.c \
        encrypt.c \
        encrypt-sign.c \
        decrypt.c \
index 34ca9d4..590d8e1 100644 (file)
 #include "gpgme.h"
 #include "types.h"
 #include "engine.h"
+#include "wait.h"
 
-struct key_queue_item_s {
-    struct key_queue_item_s *next;
-    GpgmeKey key;
+struct key_queue_item_s
+{
+  struct key_queue_item_s *next;
+  GpgmeKey key;
 };
-struct trust_queue_item_s {
-    struct trust_queue_item_s *next;
-    GpgmeTrustItem item;
+
+struct trust_queue_item_s
+{
+  struct trust_queue_item_s *next;
+  GpgmeTrustItem item;
 };
 
 
@@ -98,6 +102,11 @@ struct gpgme_context_s
   GpgmeProgressCb progress_cb;
   void *progress_cb_value;
 
+  /* A list of file descriptors in active use by the current
+     (synchronous) operation.  */
+  struct fd_table fdt;
+  struct GpgmeIOCbs io_cbs;
+  
   GpgmeData help_data_1;
 };
 
index fb94f32..35bf802 100644 (file)
@@ -874,8 +874,8 @@ _gpgme_data_append_percentstring_for_xml (GpgmeData dh, const char *string)
 
 /* Functions to support the wait interface.  */
 
-int
-_gpgme_data_inbound_handler (void *opaque, int pid, int fd)
+void
+_gpgme_data_inbound_handler (void *opaque, int fd)
 {
   GpgmeData dh = opaque;
   GpgmeError err;
@@ -889,11 +889,14 @@ _gpgme_data_inbound_handler (void *opaque, int pid, int fd)
     {
       DEBUG3 ("read_mem_data: read failed on fd %d (n=%d): %s",
              fd, nread, strerror (errno) );
-      return 1;
+      _gpgme_io_close (fd);    /* XXX ??? */
+      return;
     }
   else if (!nread)
-    return 1; /* eof */
-
+    {
+      _gpgme_io_close (fd);
+      return; /* eof */
+    }
   /* We could improve this with a GpgmeData function which takes
    * the read function or provides a memory area for writing to it.
    */
@@ -905,10 +908,11 @@ _gpgme_data_inbound_handler (void *opaque, int pid, int fd)
              gpgme_strerror(err));
       /* Fixme: we should close the pipe or read it to /dev/null in
        * this case. Returnin EOF is not sufficient */
-      return 1;
+      _gpgme_io_close (fd);    /* XXX ??? */
+      return;
     }
 
-  return 0;
+  return;
 }
 
 static int
@@ -920,7 +924,6 @@ write_mem_data (GpgmeData dh, int fd)
   nbytes = dh->len - dh->readpos;
   if (!nbytes)
     {
-      _gpgme_io_close (fd);
       return 1;
     }
     
@@ -938,7 +941,6 @@ write_mem_data (GpgmeData dh, int fd)
     {
       DEBUG3 ("write_mem_data(%d): write failed (n=%d): %s",
              fd, nwritten, strerror (errno));
-      _gpgme_io_close (fd);
       return 1;
     }
 
@@ -956,7 +958,6 @@ write_cb_data (GpgmeData dh, int fd)
   err = gpgme_data_read (dh, buffer, DIM(buffer), &nbytes);
   if (err == GPGME_EOF)
     {
-      _gpgme_io_close (fd);
       return 1;
     }
     
@@ -967,7 +968,6 @@ write_cb_data (GpgmeData dh, int fd)
     {
       DEBUG3 ("write_cb_data(%d): write failed (n=%d): %s",
              fd, nwritten, strerror (errno));
-      _gpgme_io_close (fd);
       return 1;
     }
 
@@ -977,15 +977,14 @@ write_cb_data (GpgmeData dh, int fd)
       if (_gpgme_data_unread (dh, buffer + nwritten, nbytes - nwritten))
        DEBUG1 ("wite_cb_data: unread of %d bytes failed\n",
                nbytes - nwritten);
-      _gpgme_io_close (fd);
       return 1;
     }
   
   return 0;
 }
 
-int
-_gpgme_data_outbound_handler (void *opaque, int pid, int fd)
+void
+_gpgme_data_outbound_handler (void *opaque, int fd)
 {
   GpgmeData dh = opaque;
 
@@ -994,15 +993,13 @@ _gpgme_data_outbound_handler (void *opaque, int pid, int fd)
     {
     case GPGME_DATA_TYPE_MEM:
       if (write_mem_data (dh, fd))
-       return 1; /* ready */
+       _gpgme_io_close (fd);
       break;
     case GPGME_DATA_TYPE_CB:
       if (write_cb_data (dh, fd))
-       return 1; /* ready */
+       _gpgme_io_close (fd);
       break;
     default:
       assert (0);
     }
-  
-  return 0;
 }
index b309408..e458b01 100644 (file)
@@ -41,7 +41,7 @@ decrypt_verify_status_handler (GpgmeCtx ctx, GpgStatusCode code, char *args)
 GpgmeError
 gpgme_op_decrypt_verify_start (GpgmeCtx ctx, GpgmeData ciph, GpgmeData plain)
 {
-  return _gpgme_decrypt_start (ctx, ciph, plain,
+  return _gpgme_decrypt_start (ctx, 0, ciph, plain,
                               decrypt_verify_status_handler);
 }
 
@@ -69,10 +69,11 @@ gpgme_op_decrypt_verify (GpgmeCtx ctx,
   ctx->notation = NULL;
     
   *r_stat = GPGME_SIG_STAT_NONE;
-  err = gpgme_op_decrypt_verify_start (ctx, in, out);
+  err = _gpgme_decrypt_start (ctx, 1, in, out,
+                             decrypt_verify_status_handler);
   if (!err)
     {
-      gpgme_wait (ctx, &err, 1);
+      err = _gpgme_wait_one (ctx);
       if (!err)
        *r_stat = _gpgme_intersect_stati (ctx->result.verify);
     }
index 7eacece..421ddbc 100644 (file)
@@ -80,20 +80,12 @@ _gpgme_decrypt_status_handler (GpgmeCtx ctx, GpgStatusCode code, char *args)
 
 
 GpgmeError
-_gpgme_decrypt_start (GpgmeCtx ctx, GpgmeData ciph, GpgmeData plain,
-                     void *status_handler)
+_gpgme_decrypt_start (GpgmeCtx ctx, int synchronous,
+                     GpgmeData ciph, GpgmeData plain, void *status_handler)
 {
   GpgmeError err = 0;
 
-  fail_on_pending_request (ctx);
-  ctx->pending = 1;
-
-  _gpgme_release_result (ctx);
-
-  /* Create a process object.  */
-  _gpgme_engine_release (ctx->engine);
-  err = _gpgme_engine_new (ctx->use_cms ? GPGME_PROTOCOL_CMS
-                          : GPGME_PROTOCOL_OpenPGP, &ctx->engine);
+  err = _gpgme_op_reset (ctx, synchronous);
   if (err)
     goto leave;
 
@@ -138,7 +130,7 @@ _gpgme_decrypt_start (GpgmeCtx ctx, GpgmeData ciph, GpgmeData plain,
 GpgmeError
 gpgme_op_decrypt_start (GpgmeCtx ctx, GpgmeData ciph, GpgmeData plain)
 {
-  return _gpgme_decrypt_start (ctx, ciph, plain,
+  return _gpgme_decrypt_start (ctx, 0, ciph, plain,
                               _gpgme_decrypt_status_handler);
 }
 
@@ -158,8 +150,9 @@ gpgme_op_decrypt_start (GpgmeCtx ctx, GpgmeData ciph, GpgmeData plain)
 GpgmeError
 gpgme_op_decrypt (GpgmeCtx ctx, GpgmeData in, GpgmeData out)
 {
-  GpgmeError err = gpgme_op_decrypt_start (ctx, in, out);
+  GpgmeError err = _gpgme_decrypt_start (ctx, 1, in, out,
+                                        _gpgme_decrypt_status_handler);
   if (!err)
-    gpgme_wait (ctx, &err, 1);
+    err = _gpgme_wait_one (ctx);
   return err;
 }
index 9b2735a..5a08a12 100644 (file)
@@ -91,30 +91,13 @@ delete_status_handler (GpgmeCtx ctx, GpgStatusCode code, char *args)
 }
 
 
-GpgmeError
-gpgme_op_delete_start (GpgmeCtx ctx, const GpgmeKey key, int allow_secret)
+static GpgmeError
+_gpgme_op_delete_start (GpgmeCtx ctx, int synchronous,
+                       const GpgmeKey key, int allow_secret)
 {
   GpgmeError err = 0;
 
-  fail_on_pending_request (ctx);
-  ctx->pending = 1;
-
-  if (!key)
-    {
-      err = mk_error (Invalid_Value);
-      goto leave;
-    }
-
-  if (ctx->engine)
-    {
-      _gpgme_engine_release (ctx->engine); 
-      ctx->engine = NULL;
-    }
-
-  _gpgme_release_result (ctx);
-    
-  err = _gpgme_engine_new (ctx->use_cms ? GPGME_PROTOCOL_CMS
-                          : GPGME_PROTOCOL_OpenPGP, &ctx->engine);
+  err = _gpgme_op_reset (ctx, synchronous);
   if (err)
     goto leave;
 
@@ -135,6 +118,12 @@ gpgme_op_delete_start (GpgmeCtx ctx, const GpgmeKey key, int allow_secret)
   return err;
 }
 
+GpgmeError
+gpgme_op_delete_start (GpgmeCtx ctx, const GpgmeKey key, int allow_secret)
+{
+  return _gpgme_op_delete_start (ctx, 0, key, allow_secret);
+}
+
 
 /**
  * gpgme_op_delete:
@@ -150,8 +139,8 @@ gpgme_op_delete_start (GpgmeCtx ctx, const GpgmeKey key, int allow_secret)
 GpgmeError
 gpgme_op_delete (GpgmeCtx ctx, const GpgmeKey key, int allow_secret)
 {
-  GpgmeError err = gpgme_op_delete_start (ctx, key, allow_secret);
+  GpgmeError err = _gpgme_op_delete_start (ctx, 1, key, allow_secret);
   if (!err)
-    gpgme_wait (ctx, &err, 1);
+    err = _gpgme_wait_one (ctx);
   return err;
 }
index 1c8e596..e7e36d7 100644 (file)
@@ -50,30 +50,14 @@ encrypt_sign_status_handler (GpgmeCtx ctx, GpgStatusCode code, char *args)
 }
 
 
-GpgmeError
-gpgme_op_encrypt_sign_start (GpgmeCtx ctx, GpgmeRecipients recp,
-                            GpgmeData plain, GpgmeData cipher)
+static GpgmeError
+_gpgme_op_encrypt_sign_start (GpgmeCtx ctx, int synchronous,
+                             GpgmeRecipients recp,
+                             GpgmeData plain, GpgmeData cipher)
 {
-  int err = 0;
-
-  fail_on_pending_request (ctx);
-  ctx->pending = 1;
-
-  _gpgme_release_result (ctx);
+  GpgmeError err = 0;
 
-  /* Do some checks.  */
-  if (!gpgme_recipients_count (recp))
-    {
-      /* FIXME: In this case we should do symmetric encryption.  */
-      err = mk_error (No_Recipients);
-      goto leave;
-    }
-
-  /* Create an engine object.  */
-  _gpgme_engine_release (ctx->engine);
-  ctx->engine = NULL;
-  err = _gpgme_engine_new (ctx->use_cms ? GPGME_PROTOCOL_CMS
-                          : GPGME_PROTOCOL_OpenPGP, &ctx->engine);
+  err = _gpgme_op_reset (ctx, synchronous);
   if (err)
     goto leave;
 
@@ -115,6 +99,13 @@ gpgme_op_encrypt_sign_start (GpgmeCtx ctx, GpgmeRecipients recp,
   return err;
 }
 
+GpgmeError
+gpgme_op_encrypt_sign_start (GpgmeCtx ctx, GpgmeRecipients recp,
+                             GpgmeData plain, GpgmeData cipher)
+{
+  return _gpgme_op_encrypt_sign_start (ctx, 0, recp, plain, cipher);
+}
+
 
 /**
  * gpgme_op_encrypt_sign:
@@ -133,11 +124,11 @@ GpgmeError
 gpgme_op_encrypt_sign (GpgmeCtx ctx, GpgmeRecipients recp,
                       GpgmeData plain, GpgmeData cipher)
 {
-  GpgmeError err = gpgme_op_encrypt_sign_start (ctx, recp, plain, cipher);
+  GpgmeError err = _gpgme_op_encrypt_sign_start (ctx, 1, recp, plain, cipher);
 
   if (!err)
     {
-      gpgme_wait (ctx, &err, 1);
+      err = _gpgme_wait_one (ctx);
       /* Old gpg versions don't return status info for invalid
          recipients, so we simply check whether we got any output at
          all, and if not we assume that we don't have valid
index 0a3970c..52bd713 100644 (file)
@@ -28,6 +28,7 @@
 #include "util.h"
 #include "context.h"
 #include "ops.h"
+#include "wait.h"
 
 #define SKIP_TOKEN_OR_RETURN(a) do { \
     while (*(a) && *(a) != ' ') (a)++; \
@@ -142,18 +143,13 @@ _gpgme_encrypt_sym_status_handler (GpgmeCtx ctx, GpgStatusCode code, char *args)
 }
 
 
-GpgmeError
-gpgme_op_encrypt_start (GpgmeCtx ctx, GpgmeRecipients recp, GpgmeData plain,
-                       GpgmeData ciph)
+static GpgmeError
+_gpgme_op_encrypt_start (GpgmeCtx ctx, int synchronous,
+                        GpgmeRecipients recp, GpgmeData plain, GpgmeData ciph)
 {
-  int err = 0;
+  GpgmeError err = 0;
   int symmetric = 0;
 
-  fail_on_pending_request (ctx);
-  ctx->pending = 1;
-
-  _gpgme_release_result (ctx);
-
   /* Do some checks.  */
   if (!recp)
     symmetric = 1;
@@ -163,11 +159,7 @@ gpgme_op_encrypt_start (GpgmeCtx ctx, GpgmeRecipients recp, GpgmeData plain,
       goto leave;
     }
 
-  /* Create an engine object.  */
-  _gpgme_engine_release (ctx->engine);
-  ctx->engine = NULL;
-  err = _gpgme_engine_new (ctx->use_cms ? GPGME_PROTOCOL_CMS
-                          : GPGME_PROTOCOL_OpenPGP, &ctx->engine);
+  err = _gpgme_op_reset (ctx, synchronous);
   if (err)
     goto leave;
 
@@ -216,6 +208,14 @@ gpgme_op_encrypt_start (GpgmeCtx ctx, GpgmeRecipients recp, GpgmeData plain,
 }
 
 
+GpgmeError
+gpgme_op_encrypt_start (GpgmeCtx ctx, GpgmeRecipients recp, GpgmeData plain,
+                       GpgmeData ciph)
+{
+  return _gpgme_op_encrypt_start (ctx, 0, recp, plain, ciph);
+}
+
+
 /**
  * gpgme_op_encrypt:
  * @c: The context
@@ -233,10 +233,10 @@ GpgmeError
 gpgme_op_encrypt (GpgmeCtx ctx, GpgmeRecipients recp,
                  GpgmeData plain, GpgmeData cipher)
 {
-  int err = gpgme_op_encrypt_start (ctx, recp, plain, cipher);
+  int err = _gpgme_op_encrypt_start (ctx, 1, recp, plain, cipher);
   if (!err)
     {
-      gpgme_wait (ctx, &err, 1);
+      err = _gpgme_wait_one (ctx);
       /* Old gpg versions don't return status info for invalid
         recipients, so we simply check whether we got any output at
         all, and if not we assume that we don't have valid
index 3a38815..0fdd07d 100644 (file)
 #define xtoi_2(p)   ((xtoi_1(p) * 16) + xtoi_1((p)+1))
 
 
+
+typedef struct
+{
+  int fd;      /* FD we talk about.  */
+  int dir;     /* Inbound/Outbound, maybe given implicit?  */
+  void *data;  /* Handler-specific data.  */
+  void *tag;   /* ID from the user for gpgme_remove_io_callback.  */
+} iocb_data_t;
+
 struct gpgsm_object_s
 {
   ASSUAN_CONTEXT assuan_ctx;
 
+  iocb_data_t status_cb;
+
   /* Input, output etc are from the servers perspective.  */
-  int input_fd;
+  iocb_data_t input_cb;
   int input_fd_server;
-  GpgmeData input_data;
-  int output_fd;
+
+  iocb_data_t output_cb;
   int output_fd_server;
-  GpgmeData output_data;
-  int message_fd;
+
+  iocb_data_t message_cb;
   int message_fd_server;
-  GpgmeData message_data;
 
   char *command;
 
@@ -93,6 +103,8 @@ struct gpgsm_object_s
       int linelen;
     } attic;
   } colon; 
+
+  struct GpgmeIOCbs io_cbs;
 };
 
 
@@ -124,14 +136,49 @@ static void
 close_notify_handler (int fd, void *opaque)
 {
   GpgsmObject gpgsm = opaque;
+  int possibly_done = 0;
 
   assert (fd != -1);
-  if (gpgsm->input_fd == fd)
-    gpgsm->input_fd = -1;
-  else if (gpgsm->output_fd == fd)
-    gpgsm->output_fd = -1;
-  else if (gpgsm->message_fd == fd)
-    gpgsm->message_fd = -1;
+  if (gpgsm->status_cb.fd == fd)
+    {
+      if (gpgsm->status_cb.tag)
+       {
+         (*gpgsm->io_cbs.remove) (gpgsm->status_cb.tag);
+         possibly_done = 1;
+       }
+      gpgsm->status_cb.fd = -1;
+    }
+  else if (gpgsm->input_cb.fd == fd)
+    {
+      if (gpgsm->input_cb.tag)
+       {
+         (*gpgsm->io_cbs.remove) (gpgsm->input_cb.tag);
+         possibly_done = 1;
+       }
+      gpgsm->input_cb.fd = -1;
+    }
+  else if (gpgsm->output_cb.fd == fd)
+    {
+      if (gpgsm->output_cb.tag)
+       {      
+         (*gpgsm->io_cbs.remove) (gpgsm->output_cb.tag);
+         possibly_done = 1;
+       }
+      gpgsm->output_cb.fd = -1;
+    }
+  else if (gpgsm->message_cb.fd == fd)
+    {
+      if (gpgsm->message_cb.tag)
+       {
+         (*gpgsm->io_cbs.remove) (gpgsm->message_cb.tag);
+         possibly_done = 1;
+       }
+      gpgsm->message_cb.fd = -1;
+    }
+  if (possibly_done && gpgsm->io_cbs.event
+      && gpgsm->status_cb.fd == -1 && gpgsm->input_cb.fd == -1
+      && gpgsm->output_cb.fd == -1 && gpgsm->message_cb.fd == -1)
+    (*gpgsm->io_cbs.event) (gpgsm->io_cbs.event_priv, GPGME_EVENT_DONE, NULL);
 }
 
 
@@ -248,6 +295,8 @@ _gpgme_gpgsm_new (GpgsmObject *r_gpgsm)
   char *old_lc = NULL;
   char *dft_lc = NULL;
   char *optstr;
+  int fdlist[5];
+  int nfds;
 
   *r_gpgsm = NULL;
   gpgsm = xtrycalloc (1, sizeof *gpgsm);
@@ -257,11 +306,17 @@ _gpgme_gpgsm_new (GpgsmObject *r_gpgsm)
       return err;
     }
 
-  gpgsm->input_fd = -1;
+  gpgsm->status_cb.fd = -1;
+  gpgsm->status_cb.tag = 0;
+
+  gpgsm->input_cb.fd = -1;
+  gpgsm->input_cb.tag = 0;
   gpgsm->input_fd_server = -1;
-  gpgsm->output_fd = -1;
+  gpgsm->output_cb.fd = -1;
+  gpgsm->output_cb.tag = 0;
   gpgsm->output_fd_server = -1;
-  gpgsm->message_fd = -1;
+  gpgsm->message_cb.fd = -1;
+  gpgsm->message_cb.tag = 0;
   gpgsm->message_fd_server = -1;
 
   gpgsm->status.fnc = 0;
@@ -270,12 +325,19 @@ _gpgme_gpgsm_new (GpgsmObject *r_gpgsm)
   gpgsm->colon.attic.linesize = 0;
   gpgsm->colon.attic.linelen = 0;
 
+  gpgsm->io_cbs.add = NULL;
+  gpgsm->io_cbs.add_priv = NULL;
+  gpgsm->io_cbs.remove = NULL;
+  gpgsm->io_cbs.event = NULL;
+  gpgsm->io_cbs.event_priv = NULL;
+
   if (_gpgme_io_pipe (fds, 0) < 0)
     {
       err = mk_error (Pipe_Error);
       goto leave;
     }
-  gpgsm->input_fd = fds[1];
+  gpgsm->input_cb.fd = fds[1];
+  gpgsm->input_cb.dir = 0;
   gpgsm->input_fd_server = fds[0];
 
   if (_gpgme_io_pipe (fds, 1) < 0)
@@ -283,7 +345,8 @@ _gpgme_gpgsm_new (GpgsmObject *r_gpgsm)
       err = mk_error (Pipe_Error);
       goto leave;
     }
-  gpgsm->output_fd = fds[0];
+  gpgsm->output_cb.fd = fds[0];
+  gpgsm->output_cb.dir = 1;
   gpgsm->output_fd_server = fds[1];
 
   if (_gpgme_io_pipe (fds, 0) < 0)
@@ -291,7 +354,8 @@ _gpgme_gpgsm_new (GpgsmObject *r_gpgsm)
       err = mk_error (Pipe_Error);
       goto leave;
     }
-  gpgsm->message_fd = fds[1];
+  gpgsm->message_cb.fd = fds[1];
+  gpgsm->message_cb.dir = 0;
   gpgsm->message_fd_server = fds[0];
 
   child_fds[0] = gpgsm->input_fd_server;
@@ -307,6 +371,20 @@ _gpgme_gpgsm_new (GpgsmObject *r_gpgsm)
                               _gpgme_get_gpgsm_path (), argv, child_fds,
                               1 /* dup stderr to /dev/null */);
 
+  /* 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 (gpgsm->assuan_ctx, 0 /* read fds */,
+                                fdlist, DIM (fdlist));
+  if (nfds < 1)
+    {
+      err = mk_error (General_Error);  /* FIXME */
+      goto leave;
+    }
+  gpgsm->status_cb.fd = fdlist[0];
+  gpgsm->status_cb.dir = 1;
+  gpgsm->status_cb.data = gpgsm;
+
   dft_display = getenv ("DISPLAY");
   if (dft_display)
     {
@@ -315,8 +393,8 @@ _gpgme_gpgsm_new (GpgsmObject *r_gpgsm)
          err = mk_error (Out_Of_Core);
          goto leave;
        }
-      err = assuan_transact (gpgsm->assuan_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
-                            NULL);
+      err = assuan_transact (gpgsm->assuan_ctx, optstr, NULL, NULL, NULL,
+                            NULL, NULL, NULL);
       free (optstr);
       if (err)
        {
@@ -400,11 +478,13 @@ _gpgme_gpgsm_new (GpgsmObject *r_gpgsm)
     }
 
   if (!err &&
-      (_gpgme_io_set_close_notify (gpgsm->input_fd,
+      (_gpgme_io_set_close_notify (gpgsm->status_cb.fd,
                                   close_notify_handler, gpgsm)
-       || _gpgme_io_set_close_notify (gpgsm->output_fd,
+       || _gpgme_io_set_close_notify (gpgsm->input_cb.fd,
+                                  close_notify_handler, gpgsm)
+       || _gpgme_io_set_close_notify (gpgsm->output_cb.fd,
                                      close_notify_handler, gpgsm)
-       || _gpgme_io_set_close_notify (gpgsm->message_fd,
+       || _gpgme_io_set_close_notify (gpgsm->message_cb.fd,
                                      close_notify_handler, gpgsm)))
     {
       err = mk_error (General_Error);
@@ -433,21 +513,15 @@ _gpgme_gpgsm_new (GpgsmObject *r_gpgsm)
 void
 _gpgme_gpgsm_release (GpgsmObject gpgsm)
 {
-  pid_t pid;
-
   if (!gpgsm)
     return;
 
-  pid = assuan_get_pid (gpgsm->assuan_ctx);
-  if (pid != -1)
-    _gpgme_remove_proc_from_wait_queue (pid);
-
-  if (gpgsm->input_fd != -1)
-    _gpgme_io_close (gpgsm->input_fd);
-  if (gpgsm->output_fd != -1)
-    _gpgme_io_close (gpgsm->output_fd);
-  if (gpgsm->message_fd != -1)
-    _gpgme_io_close (gpgsm->message_fd);
+  if (gpgsm->input_cb.fd != -1)
+    _gpgme_io_close (gpgsm->input_cb.fd);
+  if (gpgsm->output_cb.fd != -1)
+    _gpgme_io_close (gpgsm->output_cb.fd);
+  if (gpgsm->message_cb.fd != -1)
+    _gpgme_io_close (gpgsm->message_cb.fd);
 
   assuan_disconnect (gpgsm->assuan_ctx);
 
@@ -512,12 +586,17 @@ map_input_enc (GpgmeData d)
 {
   switch (gpgme_data_get_encoding (d))
     {
-    case GPGME_DATA_ENCODING_NONE: break;
-    case GPGME_DATA_ENCODING_BINARY: return "--binary";
-    case GPGME_DATA_ENCODING_BASE64: return "--base64";
-    case GPGME_DATA_ENCODING_ARMOR: return "--armor";
+    case GPGME_DATA_ENCODING_NONE:
+      break;
+    case GPGME_DATA_ENCODING_BINARY:
+      return "--binary";
+    case GPGME_DATA_ENCODING_BASE64:
+      return "--base64";
+    case GPGME_DATA_ENCODING_ARMOR:
+      return "--armor";
+    default:
+      break;
     }
-
   return NULL;
 }
 
@@ -534,16 +613,16 @@ _gpgme_gpgsm_op_decrypt (GpgsmObject gpgsm, GpgmeData ciph, GpgmeData plain)
   if (!gpgsm->command)
     return mk_error (Out_Of_Core);
 
-  gpgsm->input_data = ciph;
+  gpgsm->input_cb.data = ciph;
   err = gpgsm_set_fd (gpgsm->assuan_ctx, "INPUT", gpgsm->input_fd_server, 
-                      map_input_enc (gpgsm->input_data));
+                      map_input_enc (gpgsm->input_cb.data));
   if (err)
     return mk_error (General_Error);   /* FIXME */
-  gpgsm->output_data = plain;
+  gpgsm->output_cb.data = plain;
   err = gpgsm_set_fd (gpgsm->assuan_ctx, "OUTPUT", gpgsm->output_fd_server, 0);
   if (err)
     return mk_error (General_Error);   /* FIXME */
-  _gpgme_io_close (gpgsm->message_fd);
+  _gpgme_io_close (gpgsm->message_cb.fd);
 
   return 0;
 }
@@ -626,17 +705,17 @@ _gpgme_gpgsm_op_encrypt (GpgsmObject gpgsm, GpgmeRecipients recp,
   if (!gpgsm->command)
     return mk_error (Out_Of_Core);
 
-  gpgsm->input_data = plain;
+  gpgsm->input_cb.data = plain;
   err = gpgsm_set_fd (gpgsm->assuan_ctx, "INPUT", gpgsm->input_fd_server,
-                      map_input_enc (gpgsm->input_data));
+                      map_input_enc (gpgsm->input_cb.data));
   if (err)
     return err;
-  gpgsm->output_data = ciph;
+  gpgsm->output_cb.data = ciph;
   err = gpgsm_set_fd (gpgsm->assuan_ctx, "OUTPUT", gpgsm->output_fd_server,
                      use_armor ? "--armor" : 0);
   if (err)
     return err;
-  _gpgme_io_close (gpgsm->message_fd);
+  _gpgme_io_close (gpgsm->message_cb.fd);
 
   err = gpgsm_set_recipients (gpgsm, recp);
   if (err)
@@ -668,17 +747,17 @@ _gpgme_gpgsm_op_genkey (GpgsmObject gpgsm, GpgmeData help_data, int use_armor,
   if (!gpgsm->command)
     return mk_error (Out_Of_Core);
 
-  gpgsm->input_data = help_data;
+  gpgsm->input_cb.data = help_data;
   err = gpgsm_set_fd (gpgsm->assuan_ctx, "INPUT", gpgsm->input_fd_server,
-                      map_input_enc (gpgsm->input_data));
+                      map_input_enc (gpgsm->input_cb.data));
   if (err)
     return err;
-  gpgsm->output_data = pubkey;
+  gpgsm->output_cb.data = pubkey;
   err = gpgsm_set_fd (gpgsm->assuan_ctx, "OUTPUT", gpgsm->output_fd_server,
                      use_armor ? "--armor" : 0);
   if (err)
     return err;
-  _gpgme_io_close (gpgsm->message_fd);
+  _gpgme_io_close (gpgsm->message_cb.fd);
 
   return 0;
 }
@@ -696,13 +775,13 @@ _gpgme_gpgsm_op_import (GpgsmObject gpgsm, GpgmeData keydata)
   if (!gpgsm->command)
     return mk_error (Out_Of_Core);
 
-  gpgsm->input_data = keydata;
+  gpgsm->input_cb.data = keydata;
   err = gpgsm_set_fd (gpgsm->assuan_ctx, "INPUT", gpgsm->input_fd_server,
-                      map_input_enc (gpgsm->input_data));
+                      map_input_enc (gpgsm->input_cb.data));
   if (err)
     return err;
-  _gpgme_io_close (gpgsm->output_fd);
-  _gpgme_io_close (gpgsm->message_fd);
+  _gpgme_io_close (gpgsm->output_cb.fd);
+  _gpgme_io_close (gpgsm->message_cb.fd);
 
   return 0;
 }
@@ -740,9 +819,9 @@ _gpgme_gpgsm_op_keylist (GpgsmObject gpgsm, const char *pattern,
       strcpy (&line[9], pattern);
     }
 
-  _gpgme_io_close (gpgsm->input_fd);
-  _gpgme_io_close (gpgsm->output_fd);
-  _gpgme_io_close (gpgsm->message_fd);
+  _gpgme_io_close (gpgsm->input_cb.fd);
+  _gpgme_io_close (gpgsm->output_cb.fd);
+  _gpgme_io_close (gpgsm->message_cb.fd);
 
   gpgsm->command = line;
   return 0;
@@ -839,9 +918,9 @@ _gpgme_gpgsm_op_keylist_ext (GpgsmObject gpgsm, const char *pattern[],
     }
   *linep = '\0';
 
-  _gpgme_io_close (gpgsm->input_fd);
-  _gpgme_io_close (gpgsm->output_fd);
-  _gpgme_io_close (gpgsm->message_fd);
+  _gpgme_io_close (gpgsm->input_cb.fd);
+  _gpgme_io_close (gpgsm->output_cb.fd);
+  _gpgme_io_close (gpgsm->message_cb.fd);
 
   gpgsm->command = line;
   return 0;
@@ -872,17 +951,17 @@ _gpgme_gpgsm_op_sign (GpgsmObject gpgsm, GpgmeData in, GpgmeData out,
   if (err)
     return err;
 
-  gpgsm->input_data = in;
+  gpgsm->input_cb.data = in;
   err = gpgsm_set_fd (gpgsm->assuan_ctx, "INPUT", gpgsm->input_fd_server,
-                      map_input_enc (gpgsm->input_data));
+                      map_input_enc (gpgsm->input_cb.data));
   if (err)
     return err;
-  gpgsm->output_data = out;
+  gpgsm->output_cb.data = out;
   err = gpgsm_set_fd (gpgsm->assuan_ctx, "OUTPUT", gpgsm->output_fd_server,
                      use_armor ? "--armor" : 0);
   if (err)
     return err;
-  _gpgme_io_close (gpgsm->message_fd);
+  _gpgme_io_close (gpgsm->message_cb.fd);
 
   return 0;
 }
@@ -908,26 +987,26 @@ _gpgme_gpgsm_op_verify (GpgsmObject gpgsm, GpgmeData sig, GpgmeData text)
   if (!gpgsm->command)
     return mk_error (Out_Of_Core);
 
-  gpgsm->input_data = sig;
+  gpgsm->input_cb.data = sig;
   err = gpgsm_set_fd (gpgsm->assuan_ctx, "INPUT", gpgsm->input_fd_server,
-                      map_input_enc (gpgsm->input_data));
+                      map_input_enc (gpgsm->input_cb.data));
   if (err)
     return err;
   if (_gpgme_data_get_mode (text) == GPGME_DATA_MODE_IN)
     {
       /* Normal or cleartext signature.  */
-      gpgsm->output_data = text;
+      gpgsm->output_cb.data = text;
       err = gpgsm_set_fd (gpgsm->assuan_ctx, "OUTPUT", gpgsm->output_fd_server,
                          0);
-      _gpgme_io_close (gpgsm->message_fd);
+      _gpgme_io_close (gpgsm->message_cb.fd);
     }
   else
     {
       /* Detached signature.  */
-      gpgsm->message_data = text;
+      gpgsm->message_cb.data = text;
       err = gpgsm_set_fd (gpgsm->assuan_ctx, "MESSAGE",
                          gpgsm->message_fd_server, 0);
-      _gpgme_io_close (gpgsm->output_fd);
+      _gpgme_io_close (gpgsm->output_cb.fd);
     }
   if (err)
     return err;
@@ -946,8 +1025,8 @@ status_cmp (const void *ap, const void *bp)
 }
 
 
-static int
-gpgsm_status_handler (void *opaque, int pid, int fd)
+static void
+gpgsm_status_handler (void *opaque, int fd)
 {
   AssuanError err;
   GpgsmObject gpgsm = opaque;
@@ -966,8 +1045,9 @@ gpgsm_status_handler (void *opaque, int pid, int fd)
              && line[0] == 'E' && line[1] == 'R' && line[2] == 'R'
              && (line[3] == '\0' || line[3] == ' ')))
        {
-         /* XXX: If an error occured, find out what happened, then save the error value
-            before running the status handler (so it takes precedence).  */
+         /* XXX: If an error occured, find out what happened, then
+            save the error value before running the status handler
+            (so it takes precedence).  */
          if (!err && line[0] == 'E' && line[3] == ' ')
            {
              err = map_assuan_error (atoi (&line[4]));
@@ -990,7 +1070,8 @@ gpgsm_status_handler (void *opaque, int pid, int fd)
          if (err)
            assuan_write_line (gpgsm->assuan_ctx, "BYE");
 
-         return 1;
+         _gpgme_io_close (gpgsm->status_cb.fd);
+         return;
        }
 
       if (linelen > 2
@@ -1015,7 +1096,10 @@ gpgsm_status_handler (void *opaque, int pid, int fd)
              unsigned char *newline = xtryrealloc (*aline,
                                                    *alinelen + linelen + 1);
              if (!newline)
-               return mk_error (Out_Of_Core);
+               {
+                 _gpgme_io_close (gpgsm->status_cb.fd);
+                 return;
+               }
              *aline = newline;
              gpgsm->colon.attic.linesize += linelen + 1;
            }
@@ -1082,8 +1166,6 @@ gpgsm_status_handler (void *opaque, int pid, int fd)
        }
     }
   while (assuan_pending_line (gpgsm->assuan_ctx));
-  
-  return 0;
 }
 
 
@@ -1109,50 +1191,45 @@ _gpgme_gpgsm_set_colon_line_handler (GpgsmObject gpgsm,
 }
 
 
+static GpgmeError
+_gpgme_gpgsm_add_io_cb (GpgsmObject gpgsm, iocb_data_t *iocbd,
+                       GpgmeIOCb handler)
+{
+  GpgmeError err = 0;
+
+  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)
+    /* FIXME Kludge around poll() problem.  */
+    err = _gpgme_io_set_nonblocking (iocbd->fd);
+  return err;
+}
+
 GpgmeError
 _gpgme_gpgsm_start (GpgsmObject gpgsm, void *opaque)
 {
   GpgmeError err = 0;
   pid_t pid;
-  int fdlist[5];
-  int nfds;
 
   if (!gpgsm)
     return mk_error (Invalid_Value);
 
   pid = assuan_get_pid (gpgsm->assuan_ctx);
 
-  /* 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 (gpgsm->assuan_ctx, 0 /* read fds */,
-                                fdlist, DIM (fdlist));
-  if (nfds < 1)
-    return mk_error (General_Error);  /* FIXME */
-  err = _gpgme_register_pipe_handler (opaque, gpgsm_status_handler, gpgsm, pid,
-                                      fdlist[0], 1);
-
-
-  if (gpgsm->input_fd != -1)
-    {
-      err = _gpgme_register_pipe_handler (opaque, _gpgme_data_outbound_handler,
-                                         gpgsm->input_data, pid,
-                                         gpgsm->input_fd, 0);
-      if (!err)        /* FIXME Kludge around poll() problem.  */
-       err = _gpgme_io_set_nonblocking (gpgsm->input_fd);
-    }
-  if (!err && gpgsm->output_fd != -1)
-    err = _gpgme_register_pipe_handler (opaque, _gpgme_data_inbound_handler,
-                                       gpgsm->output_data, pid,
-                                       gpgsm->output_fd, 1);
-  if (!err && gpgsm->message_fd != -1)
-    {
-      err = _gpgme_register_pipe_handler (opaque, _gpgme_data_outbound_handler,
-                                         gpgsm->message_data, pid,
-                                         gpgsm->message_fd, 0);
-      if (!err)        /* FIXME Kludge around poll() problem.  */
-       err = _gpgme_io_set_nonblocking (gpgsm->message_fd);
-    }
+  err = _gpgme_gpgsm_add_io_cb (gpgsm, &gpgsm->status_cb,
+                               gpgsm_status_handler);
+  if (gpgsm->input_cb.fd != -1)
+    err = _gpgme_gpgsm_add_io_cb (gpgsm, &gpgsm->input_cb,
+                                 _gpgme_data_outbound_handler);
+  if (!err && gpgsm->output_cb.fd != -1)
+    err = _gpgme_gpgsm_add_io_cb (gpgsm, &gpgsm->output_cb,
+                                 _gpgme_data_inbound_handler);
+  if (!err && gpgsm->message_cb.fd != -1)
+    err = _gpgme_gpgsm_add_io_cb (gpgsm, &gpgsm->message_cb,
+                                 _gpgme_data_outbound_handler);
 
   if (!err)
     err = assuan_write_line (gpgsm->assuan_ctx, gpgsm->command);
@@ -1160,6 +1237,12 @@ _gpgme_gpgsm_start (GpgsmObject gpgsm, void *opaque)
   return err;
 }
 
+void
+_gpgme_gpgsm_set_io_cbs (GpgsmObject gpgsm, struct GpgmeIOCbs *io_cbs)
+{
+  gpgsm->io_cbs = *io_cbs;
+}
+
 
 #else  /* ENABLE_GPGSM */
 
@@ -1303,5 +1386,8 @@ _gpgme_gpgsm_start (GpgsmObject gpgsm, void *opaque)
   return mk_error (Invalid_Engine);
 }
 
+void _gpgme_gpgsm_set_io_cbs (GpgsmObject gpgsm, GpgmeIOCbs io_cbs)
+{
+}
 
 #endif /* ! ENABLE_GPGSM */
index ecd80b4..cbfc4d9 100644 (file)
@@ -63,5 +63,6 @@ GpgmeError _gpgme_gpgsm_op_trustlist (GpgsmObject gpgsm, const char *pattern);
 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);
 
 #endif /* ENGINE_GPGSM_H */
index ce5164b..91d10c0 100644 (file)
@@ -567,6 +567,26 @@ _gpgme_engine_start (EngineObject engine, void *opaque)
   return 0;
 }
 
+void
+_gpgme_engine_set_io_cbs (EngineObject engine,
+                         struct GpgmeIOCbs *io_cbs)
+{
+  if (!engine)
+    return;
+
+  switch (engine->protocol)
+    {
+    case GPGME_PROTOCOL_OpenPGP:
+      _gpgme_gpg_set_io_cbs (engine->engine.gpg, io_cbs);
+      break;
+    case GPGME_PROTOCOL_CMS:
+      _gpgme_gpgsm_set_io_cbs (engine->engine.gpgsm, io_cbs);
+      break;
+    default:
+      break;
+    }
+}
+
 \f
 void
 _gpgme_engine_add_child_to_reap_list (void *buf, int buflen, pid_t pid)
index f684021..a364031 100644 (file)
@@ -76,6 +76,9 @@ GpgmeError _gpgme_engine_op_verify (EngineObject engine, GpgmeData sig,
                                    GpgmeData text);
 GpgmeError _gpgme_engine_start (EngineObject engine, void *opaque);
 
+void _gpgme_engine_set_io_cbs (EngineObject engine,
+                              struct GpgmeIOCbs *io_cbs);
+
 void _gpgme_engine_add_child_to_reap_list (void *buf, int buflen, pid_t pid);
 void _gpgme_engine_housecleaning (void);
 
index bbee68d..c222861 100644 (file)
@@ -41,21 +41,13 @@ export_status_handler (GpgmeCtx ctx, GpgStatusCode code, char *args)
 }
 
 
-GpgmeError
-gpgme_op_export_start (GpgmeCtx ctx, GpgmeRecipients recp, GpgmeData keydata)
+static GpgmeError
+_gpgme_op_export_start (GpgmeCtx ctx, int synchronous,
+                       GpgmeRecipients recp, GpgmeData keydata)
 {
   GpgmeError err = 0;
 
-  fail_on_pending_request (ctx);
-  ctx->pending = 1;
-
-  _gpgme_engine_release (ctx->engine);
-  ctx->engine = NULL;
-
-  _gpgme_release_result (ctx);
-
-  err = _gpgme_engine_new (ctx->use_cms ? GPGME_PROTOCOL_CMS
-                          : GPGME_PROTOCOL_OpenPGP, &ctx->engine);
+  err = _gpgme_op_reset (ctx, synchronous);
   if (err)
     goto leave;
 
@@ -83,6 +75,11 @@ gpgme_op_export_start (GpgmeCtx ctx, GpgmeRecipients recp, GpgmeData keydata)
   return err;
 }
 
+GpgmeError
+gpgme_op_export_start (GpgmeCtx ctx, GpgmeRecipients recp, GpgmeData keydata)
+{
+  return _gpgme_op_export_start (ctx, 0, recp, keydata);
+}
 
 /**
  * gpgme_op_export:
@@ -100,8 +97,8 @@ gpgme_op_export_start (GpgmeCtx ctx, GpgmeRecipients recp, GpgmeData keydata)
 GpgmeError
 gpgme_op_export (GpgmeCtx ctx, GpgmeRecipients recipients, GpgmeData keydata)
 {
-  GpgmeError err = gpgme_op_export_start (ctx, recipients, keydata);
+  GpgmeError err = _gpgme_op_export_start (ctx, 1, recipients, keydata);
   if (!err)
-    gpgme_wait (ctx, &err, 1);
+    err = _gpgme_wait_one (ctx);
   return err;
 }
index e8017f2..9f42cb7 100644 (file)
@@ -78,66 +78,20 @@ genkey_status_handler (GpgmeCtx ctx, GpgStatusCode code, char *args)
     }
 }
 
-
-/**
- * gpgme_op_genkey:
- * @c: the context
- * @parms: XML string with the key parameters
- * @pubkey: Returns the public key
- * @seckey: Returns the secret key
- * 
- * Generate a new key and store the key in the default keyrings if
- * both @pubkey and @seckey are NULL.  If @pubkey and @seckey are
- * given, the newly created key will be returned in these data
- * objects.  This function just starts the gheneration and does not
- * wait for completion.
- *
- * Here is an example on how @parms should be formatted; for deatils
- * see the file doc/DETAILS from the GnuPG distribution.
- *
- * <literal>
- * <![CDATA[
- * <GnupgKeyParms format="internal">
- * Key-Type: DSA
- * Key-Length: 1024
- * Subkey-Type: ELG-E
- * Subkey-Length: 1024
- * Name-Real: Joe Tester
- * Name-Comment: with stupid passphrase
- * Name-Email: joe@foo.bar
- * Expire-Date: 0
- * Passphrase: abc
- * </GnupgKeyParms>
- * ]]>
- * </literal> 
- *
- * Strings should be given in UTF-8 encoding.  The format we support
- * for now is only "internal".  The content of the
- * &lt;GnupgKeyParms&gt; container is passed verbatim to GnuPG.
- * Control statements are not allowed.
- * 
- * Return value: 0 for success or an error code
- **/
-GpgmeError
-gpgme_op_genkey_start (GpgmeCtx ctx, const char *parms,
-                      GpgmeData pubkey, GpgmeData seckey)
+static GpgmeError
+_gpgme_op_genkey_start (GpgmeCtx ctx, int synchronous, const char *parms,
+                       GpgmeData pubkey, GpgmeData seckey)
 {
   int err = 0;
   const char *s, *s2, *sx;
 
-  fail_on_pending_request (ctx);
-  ctx->pending = 1;
+  err = _gpgme_op_reset (ctx, synchronous);
+  if (err)
+    goto leave;
 
   gpgme_data_release (ctx->help_data_1);
   ctx->help_data_1 = NULL;
 
-  _gpgme_engine_release (ctx->engine);
-  ctx->engine = NULL;
-  err = _gpgme_engine_new (ctx->use_cms ? GPGME_PROTOCOL_CMS
-                          : GPGME_PROTOCOL_OpenPGP, &ctx->engine);
-  if (err)
-    goto leave;
-
   if (!pubkey && !seckey)
     ; /* okay: Add key to the keyrings */
   else if (pubkey && gpgme_data_get_type (pubkey) != GPGME_DATA_TYPE_NONE)
@@ -206,6 +160,53 @@ gpgme_op_genkey_start (GpgmeCtx ctx, const char *parms,
  * @pubkey: Returns the public key
  * @seckey: Returns the secret key
  * 
+ * Generate a new key and store the key in the default keyrings if
+ * both @pubkey and @seckey are NULL.  If @pubkey and @seckey are
+ * given, the newly created key will be returned in these data
+ * objects.  This function just starts the gheneration and does not
+ * wait for completion.
+ *
+ * Here is an example on how @parms should be formatted; for deatils
+ * see the file doc/DETAILS from the GnuPG distribution.
+ *
+ * <literal>
+ * <![CDATA[
+ * <GnupgKeyParms format="internal">
+ * Key-Type: DSA
+ * Key-Length: 1024
+ * Subkey-Type: ELG-E
+ * Subkey-Length: 1024
+ * Name-Real: Joe Tester
+ * Name-Comment: with stupid passphrase
+ * Name-Email: joe@foo.bar
+ * Expire-Date: 0
+ * Passphrase: abc
+ * </GnupgKeyParms>
+ * ]]>
+ * </literal> 
+ *
+ * Strings should be given in UTF-8 encoding.  The format we support
+ * for now is only "internal".  The content of the
+ * &lt;GnupgKeyParms&gt; container is passed verbatim to GnuPG.
+ * Control statements are not allowed.
+ * 
+ * Return value: 0 for success or an error code
+ **/
+GpgmeError
+gpgme_op_genkey_start (GpgmeCtx ctx, const char *parms,
+                      GpgmeData pubkey, GpgmeData seckey)
+{
+  return _gpgme_op_genkey_start (ctx, 0, parms, pubkey, seckey);
+}
+
+
+/**
+ * gpgme_op_genkey:
+ * @c: the context
+ * @parms: XML string with the key parameters
+ * @pubkey: Returns the public key
+ * @seckey: Returns the secret key
+ * 
  * Generate a new key and store the key in the default keyrings if both
  * @pubkey and @seckey are NULL.  If @pubkey and @seckey are given, the newly
  * created key will be returned in these data objects.
@@ -217,8 +218,8 @@ GpgmeError
 gpgme_op_genkey (GpgmeCtx ctx, const char *parms,
                  GpgmeData pubkey, GpgmeData seckey)
 {
-  GpgmeError err = gpgme_op_genkey_start (ctx, parms, pubkey, seckey);
+  GpgmeError err = _gpgme_op_genkey_start (ctx, 1, parms, pubkey, seckey);
   if (!err)
-    gpgme_wait (ctx, &err, 1);
+    err = _gpgme_wait_one (ctx);
   return err;
 }
index 50546de..04ec986 100644 (file)
@@ -28,7 +28,7 @@
 #include "util.h"
 #include "context.h"
 #include "ops.h"
-
+#include "wait.h"
 
 /**
  * gpgme_new:
@@ -53,8 +53,8 @@ gpgme_new (GpgmeCtx *r_ctx)
   ctx->keylist_mode = GPGME_KEYLIST_MODE_LOCAL;
   ctx->verbosity = 1;
   ctx->include_certs = 1;
+  _gpgme_fd_table_init (&ctx->fdt);
   *r_ctx = ctx;
-
   return 0;
 }
 
@@ -71,6 +71,7 @@ gpgme_release (GpgmeCtx ctx)
   if (!ctx)
     return;
   _gpgme_engine_release (ctx->engine);
+  _gpgme_fd_table_deinit (&ctx->fdt);
   _gpgme_release_result (ctx);
   gpgme_key_release (ctx->tmp_key);
   gpgme_data_release (ctx->help_data_1);
@@ -471,7 +472,8 @@ gpgme_set_progress_cb (GpgmeCtx ctx, GpgmeProgressCb cb, void *cb_value)
  * @r_cb: The current callback function
  * @r_cb_value: The current value passed to the callback function
  *
- * This function returns the callback function to be used as a progress indicator.
+ * This function returns the callback function to be used as a
+ * progress indicator.
  **/
 void
 gpgme_get_progress_cb (GpgmeCtx ctx, GpgmeProgressCb *r_cb, void **r_cb_value)
@@ -491,3 +493,59 @@ gpgme_get_progress_cb (GpgmeCtx ctx, GpgmeProgressCb *r_cb, void **r_cb_value)
        *r_cb_value = NULL;
     }
 }
+
+
+/**
+ * gpgme_set_io_cbs:
+ * @ctx: the context
+ * @register_io_cb: A callback function
+ * @register_hook_value: The value passed to the callback function
+ * @remove_io_cb: Another callback function
+ *
+ **/
+void
+gpgme_set_io_cbs (GpgmeCtx ctx, struct GpgmeIOCbs *io_cbs)
+{
+  if (ctx && io_cbs)
+    ctx->io_cbs = *io_cbs;
+  else
+    {
+      ctx->io_cbs.add = NULL;
+      ctx->io_cbs.add_priv = NULL;
+      ctx->io_cbs.remove = NULL;
+      ctx->io_cbs.event = NULL;
+      ctx->io_cbs.event_priv = NULL;
+    }
+}
+
+
+/**
+ * gpgme_get_io_cbs:
+ * @ctx: the context
+ * @r_register_cb: The current register callback function
+ * @r_register_cb_value: The current value passed to the
+ * register callback function
+ * @r_remove_cb: The current remove callback function
+ *
+ * This function returns the callback function to be used to pass a passphrase
+ * to the crypto engine.
+ **/
+void
+gpgme_get_io_cbs (GpgmeCtx ctx, struct GpgmeIOCbs *io_cbs)
+{
+  if (ctx && io_cbs)
+    *io_cbs = ctx->io_cbs;
+}
+
+
+void
+_gpgme_op_event_cb (void *data, GpgmeEventIO type, void *type_data)
+{
+  GpgmeCtx ctx = data;
+
+  if (type == GPGME_EVENT_DONE)
+    ctx->pending = 0;
+
+  if (ctx->io_cbs.add && ctx->io_cbs.event)
+    (*ctx->io_cbs.event) (ctx->io_cbs.event_priv, type, type_data);
+}
index 74487c8..1648431 100644 (file)
@@ -43,7 +43,7 @@ extern "C" {
    AM_PATH_GPGME macro) check that this header matches the installed
    library.  Warning: Do not edit the next line.  configure will do
    that for you!  */
-#define GPGME_VERSION "0.3.7-cvs"
+#define GPGME_VERSION "0.3.8-cvs"
 
 
 /* The opaque data types used by GPGME.  */
@@ -316,6 +316,46 @@ char *gpgme_get_op_info (GpgmeCtx ctx, int reserved);
 
 /* Run control.  */
 
+/* The type of an I/O callback function.  */
+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 should return a TAG suitable for the corresponding
+   GpgmeRemoveIOCb.  */
+typedef void *(*GpgmeRegisterIOCb) (void *data, int fd, int dir,
+                                   GpgmeIOCb fnc, void *fnc_data);
+
+/* The type of a function that can remove a previously registered I/O
+   callback function given TAG as returned by the register
+   function.  */
+typedef void (*GpgmeRemoveIOCb) (void *tag);
+
+typedef enum { GPGME_EVENT_DONE,
+              GPGME_EVENT_NEXT_KEY,
+              GPGME_EVENT_NEXT_TRUSTITEM } GpgmeEventIO;
+
+/* The type of a function that is called when a context finished an
+   operation.  */
+typedef void (*GpgmeEventIOCb) (void *data, GpgmeEventIO type,
+                               void *type_data);
+
+struct GpgmeIOCbs
+{
+  GpgmeRegisterIOCb add;
+  void *add_priv;
+  GpgmeRemoveIOCb remove;
+  GpgmeEventIOCb event;
+  void *event_priv;
+};
+
+/* Set the I/O callback functions in CTX to IO_CBS.  */
+void gpgme_set_op_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);
+
 /* Cancel a pending operation in CTX.  */
 void       gpgme_cancel (GpgmeCtx ctx);
 
index 338cc1d..493b301 100644 (file)
@@ -162,18 +162,12 @@ import_status_handler (GpgmeCtx ctx, GpgStatusCode code, char *args)
 }
 
 
-GpgmeError
-gpgme_op_import_start (GpgmeCtx ctx, GpgmeData keydata)
+static GpgmeError
+_gpgme_op_import_start (GpgmeCtx ctx, int synchronous, GpgmeData keydata)
 {
   int err = 0;
 
-  fail_on_pending_request (ctx);
-  ctx->pending = 1;
-
-  _gpgme_engine_release (ctx->engine);
-  ctx->engine = NULL;
-  err = _gpgme_engine_new (ctx->use_cms ? GPGME_PROTOCOL_CMS
-                          : GPGME_PROTOCOL_OpenPGP, &ctx->engine);
+  err = _gpgme_op_reset (ctx, synchronous);
   if (err)
     goto leave;
 
@@ -204,6 +198,12 @@ gpgme_op_import_start (GpgmeCtx ctx, GpgmeData keydata)
 }
 
 
+GpgmeError
+gpgme_op_import_start (GpgmeCtx ctx, GpgmeData keydata)
+{
+  return _gpgme_op_import_start (ctx, 0, keydata);
+}
+
 /**
  * gpgme_op_import:
  * @c: Context 
@@ -216,8 +216,8 @@ gpgme_op_import_start (GpgmeCtx ctx, GpgmeData keydata)
 GpgmeError
 gpgme_op_import (GpgmeCtx ctx, GpgmeData keydata)
 {
-  GpgmeError err = gpgme_op_import_start (ctx, keydata);
+  GpgmeError err = _gpgme_op_import_start (ctx, 1, keydata);
   if (!err)
-    gpgme_wait (ctx, &err, 1);
+    err = _gpgme_wait_one (ctx);
   return err;
 }
index 0965a1d..ca3eba2 100644 (file)
@@ -1,6 +1,6 @@
-/* io.h - I/O functions 
+/* io.h - Interface to the I/O functions.
  *     Copyright (C) 2000 Werner Koch (dd9jn)
- *      Copyright (C) 2001 g10 Code GmbH
+ *      Copyright (C) 2001, 2002 g10 Code GmbH
  *
  * This file is part of GPGME.
  *
 
 #include "types.h"
 
-struct spawn_fd_item_s {
-    int fd;
-    int dup_to;
+/* A single file descriptor passed to spawn.  For child fds, dup_to
+   specifies the fd it should become in the child.  */
+struct spawn_fd_item_s
+{
+  int fd;
+  int dup_to;
 };
 
-
-struct io_select_fd_s {
-    int fd;
-    int is_closed;
-    int for_read;
-    int for_write;
-    int signaled;
-    int frozen;
-    void *opaque;
+struct io_select_fd_s
+{
+  int fd;
+  int for_read;
+  int for_write;
+  int signaled;
+  int frozen;
+  void *opaque;
 };
 
-
-/* These function are either defined in posix-io.c or w32-io.c */
-
-int _gpgme_io_read ( int fd, void *buffer, size_t count );
-int _gpgme_io_write ( int fd, const void *buffer, size_t count );
-int _gpgme_io_pipe ( int filedes[2], int inherit_idx );
-int _gpgme_io_close ( int fd );
-int _gpgme_io_set_close_notify (int fd,
-                                void (*handler)(int, void*), void *value);
-int _gpgme_io_set_nonblocking ( int fd );
-int _gpgme_io_spawn ( const char *path, char **argv,
-                      struct spawn_fd_item_s *fd_child_list,
-                      struct spawn_fd_item_s *fd_parent_list );
-int _gpgme_io_waitpid ( int pid, int hang, int *r_status, int *r_signal );
-int _gpgme_io_kill ( int pid, int hard );
-int _gpgme_io_select ( struct io_select_fd_s *fds, size_t nfds);
-
-
-
-
-
-
+/* These function are either defined in posix-io.c or w32-io.c.  */
+int _gpgme_io_read (int fd, void *buffer, size_t count);
+int _gpgme_io_write (int fd, const void *buffer, size_t count);
+int _gpgme_io_pipe (int filedes[2], int inherit_idx);
+int _gpgme_io_close (int fd);
+int _gpgme_io_set_close_notify (int fd, void (*handler) (int, void *),
+                               void *value);
+int _gpgme_io_set_nonblocking (int fd);
+
+/* Spawn the executable PATH with ARGV as arguments, after forking
+   close all fds in FD_PARENT_LIST in the parent and close or dup all
+   fds in FD_CHILD_LIST in the child.  */
+int _gpgme_io_spawn (const char *path, char **argv,
+                    struct spawn_fd_item_s *fd_child_list,
+                    struct spawn_fd_item_s *fd_parent_list);
+int _gpgme_io_waitpid (int pid, int hang, int *r_status, int *r_signal);
+int _gpgme_io_kill (int pid, int hard);
+int _gpgme_io_select (struct io_select_fd_s *fds, size_t nfds);
 
 #endif /* IO_H */
 
 
 
-
-
index a04300a..7c014cd 100644 (file)
@@ -236,47 +236,51 @@ keylist_colon_handler (GpgmeCtx ctx, char *line)
              /* Start a new keyblock.  */
              if (_gpgme_key_new (&key))
                {
-                 ctx->error = mk_error (Out_Of_Core);  /* the only kind of error we can get*/
+                 /* The only kind of error we can get.  */
+                 ctx->error = mk_error (Out_Of_Core);
                  return;
                 }
-                rectype = RT_PUB;
-                finish_key (ctx);
-                assert (!ctx->tmp_key);
-                ctx->tmp_key = key;
+             rectype = RT_PUB;
+             finish_key (ctx);
+             assert (!ctx->tmp_key);
+             ctx->tmp_key = key;
             }
-            else if (!strcmp (p, "sec"))
-             {
-                /* Start a new keyblock,  */
-                if (_gpgme_key_new_secret (&key))
-                 {
-                    ctx->error = mk_error (Out_Of_Core);  /* The only kind of error we can get*/
-                    return;
-                }
-                rectype = RT_SEC;
-                finish_key (ctx);
-                assert (!ctx->tmp_key);
-                ctx->tmp_key = key;
+         else if (!strcmp (p, "sec"))
+           {
+             /* Start a new keyblock,  */
+             if (_gpgme_key_new_secret (&key))
+               {
+                 /* The only kind of error we can get.  */
+                 ctx->error = mk_error (Out_Of_Core);
+                 return;
+               }
+             rectype = RT_SEC;
+             finish_key (ctx);
+             assert (!ctx->tmp_key);
+             ctx->tmp_key = key;
             }
-            else if (!strcmp (p, "crt"))
-             {
-                /* Start a new certificate. */
-                if (_gpgme_key_new (&key))
-                 {
-                    ctx->error = mk_error (Out_Of_Core);  /* The only kind of error we can get*/
-                    return;
-                }
-                key->x509 = 1;
-                rectype = RT_CRT;
-                finish_key (ctx);
-                assert (!ctx->tmp_key);
-                ctx->tmp_key = key;
+         else if (!strcmp (p, "crt"))
+           {
+             /* Start a new certificate. */
+             if (_gpgme_key_new (&key))
+               {
+                 /* The only kind of error we can get.  */
+                 ctx->error = mk_error (Out_Of_Core);
+                 return;
+               }
+             key->x509 = 1;
+             rectype = RT_CRT;
+             finish_key (ctx);
+             assert (!ctx->tmp_key);
+             ctx->tmp_key = key;
             }
          else if (!strcmp (p, "crs"))
            {
              /* Start a new certificate.  */
              if (_gpgme_key_new_secret (&key))
                {
-                 ctx->error = mk_error (Out_Of_Core);  /* The only kind of error we can get*/
+                 /* The only kind of error we can get.  */
+                 ctx->error = mk_error (Out_Of_Core);
                  return;
                 }
              key->x509 = 1;
@@ -289,7 +293,6 @@ keylist_colon_handler (GpgmeCtx ctx, char *line)
            rectype = RT_FPR;
          else 
            rectype = RT_NONE;
-            
         }
       else if (rectype == RT_PUB || rectype == RT_SEC
               || rectype == RT_CRT || rectype == RT_CRS)
@@ -401,7 +404,8 @@ keylist_colon_handler (GpgmeCtx ctx, char *line)
              break;
            case 10: /* user ID */
              if (_gpgme_key_append_name (key, p))
-               ctx->error = mk_error (Out_Of_Core);  /* The only kind of error we can get*/
+               /* The only kind of error we can get*/
+               ctx->error = mk_error (Out_Of_Core);
              else
                {
                  if (trust_info)
@@ -495,25 +499,13 @@ gpgme_op_keylist_start (GpgmeCtx ctx, const char *pattern, int secret_only)
 {
   GpgmeError err = 0;
 
-  if (!ctx)
-    return mk_error (Invalid_Value);
-  ctx->pending = 1;
-
-  _gpgme_release_result (ctx);
+  err = _gpgme_op_reset (ctx, 0);
+  if (err)
+    goto leave;
 
-  if (ctx->engine)
-    {
-      _gpgme_engine_release (ctx->engine); 
-      ctx->engine = NULL;
-    }
   gpgme_key_release (ctx->tmp_key);
   ctx->tmp_key = NULL;
   /* Fixme: Release key_queue.  */
-    
-  err = _gpgme_engine_new (ctx->use_cms ? GPGME_PROTOCOL_CMS
-                          : GPGME_PROTOCOL_OpenPGP, &ctx->engine);
-  if (err)
-    goto leave;
 
   _gpgme_engine_set_status_handler (ctx->engine, keylist_status_handler, ctx);
   err = _gpgme_engine_set_colon_line_handler (ctx->engine,
@@ -526,7 +518,8 @@ gpgme_op_keylist_start (GpgmeCtx ctx, const char *pattern, int secret_only)
      just ignore those lines - This should speed up things */
   _gpgme_engine_set_verbosity (ctx->engine, 0);
 
-  err = _gpgme_engine_op_keylist (ctx->engine, pattern, secret_only, ctx->keylist_mode);
+  err = _gpgme_engine_op_keylist (ctx->engine, pattern, secret_only,
+                                 ctx->keylist_mode);
 
   if (!err)    /* And kick off the process.  */
     err = _gpgme_engine_start (ctx->engine, ctx);
@@ -561,26 +554,12 @@ gpgme_op_keylist_ext_start (GpgmeCtx ctx, const char *pattern[],
 {
   GpgmeError err = 0;
 
-  if (!ctx)
-    return mk_error (Invalid_Value);
-  ctx->pending = 1;
-
-  _gpgme_release_result (ctx);
-
-  if (ctx->engine)
-    {
-      _gpgme_engine_release (ctx->engine); 
-      ctx->engine = NULL;
-    }
-  gpgme_key_release (ctx->tmp_key);
-  ctx->tmp_key = NULL;
-  /* Fixme: Release key_queue.  */
-    
-  err = _gpgme_engine_new (ctx->use_cms ? GPGME_PROTOCOL_CMS
-                          : GPGME_PROTOCOL_OpenPGP, &ctx->engine);
+  err = _gpgme_op_reset (ctx, 0);
   if (err)
     goto leave;
 
+  gpgme_key_release (ctx->tmp_key);
+
   _gpgme_engine_set_status_handler (ctx->engine, keylist_status_handler, ctx);
   err = _gpgme_engine_set_colon_line_handler (ctx->engine,
                                              keylist_colon_handler, ctx);
diff --git a/gpgme/op-support.c b/gpgme/op-support.c
new file mode 100644 (file)
index 0000000..bf61c72
--- /dev/null
@@ -0,0 +1,70 @@
+/* op-support.c 
+ *      Copyright (C) 2002 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 General Public License as published by
+ * the Free Software Foundation; either version 2 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+
+#include "gpgme.h"
+#include "context.h"
+#include "ops.h"
+
+GpgmeError
+_gpgme_op_reset (GpgmeCtx ctx, int synchronous)
+{
+  GpgmeError err = 0;
+  struct GpgmeIOCbs io_cbs;
+
+  fail_on_pending_request (ctx);
+  ctx->pending = 1;
+
+  _gpgme_release_result (ctx);
+
+  /* Create an engine object.  */
+  _gpgme_engine_release (ctx->engine);
+  ctx->engine = NULL;
+  err = _gpgme_engine_new (ctx->use_cms ? GPGME_PROTOCOL_CMS
+                          : GPGME_PROTOCOL_OpenPGP, &ctx->engine);
+  if (err)
+    return err;
+
+  if (synchronous)
+    {
+      io_cbs.add = _gpgme_add_io_cb;
+      io_cbs.add_priv = &ctx->fdt;
+      io_cbs.remove = _gpgme_remove_io_cb;
+      io_cbs.event = _gpgme_op_event_cb;
+      io_cbs.event_priv = ctx;
+    }
+  else if (! ctx->io_cbs.add)
+    {
+      io_cbs.add = _gpgme_add_io_cb;
+      io_cbs.add_priv = NULL;
+      io_cbs.remove = _gpgme_remove_io_cb;
+      io_cbs.event = _gpgme_wait_event_cb;
+      io_cbs.event_priv = ctx;
+    }
+  else
+    {
+      io_cbs = ctx->io_cbs;
+      io_cbs.event = _gpgme_op_event_cb;
+      io_cbs.event_priv = ctx;
+    }
+  _gpgme_engine_set_io_cbs (ctx->engine, &io_cbs);
+  return err;
+}
index 2ff8b55..bf5bb46 100644 (file)
 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);
+
 /*-- wait.c --*/
 GpgmeCtx _gpgme_wait_on_condition ( GpgmeCtx c,
                                     int hang, volatile int *cond );
-void _gpgme_freeze_fd ( int fd );
-void _gpgme_thaw_fd ( int fd );
-
 
 /*-- recipient.c --*/
 int _gpgme_recipients_all_valid ( const GpgmeRecipients rset );
@@ -76,14 +75,15 @@ GpgmeError    _gpgme_data_append_percentstring_for_xml ( GpgmeData dh,
 GpgmeError    _gpgme_data_unread (GpgmeData dh,
                                   const char *buffer, size_t length );
 
-int _gpgme_data_inbound_handler (void *opaque, int pid, int fd);
-int _gpgme_data_outbound_handler (void *opaque, int pid, int fd);
-
+void _gpgme_data_inbound_handler (void *opaque, int fd);
+void _gpgme_data_outbound_handler (void *opaque, int fd);
 
 /*-- key.c --*/
 GpgmeError _gpgme_key_new ( GpgmeKey *r_key );
 GpgmeError _gpgme_key_new_secret ( GpgmeKey *r_key );
 
+/*-- op-support.c --*/
+GpgmeError _gpgme_op_reset (GpgmeCtx ctx, int synchronous);
 
 /*-- verify.c --*/
 void _gpgme_release_verify_result (VerifyResult result);
@@ -95,7 +95,8 @@ void _gpgme_verify_status_handler (GpgmeCtx ctx, GpgStatusCode code,
 void _gpgme_release_decrypt_result (DecryptResult result);
 void _gpgme_decrypt_status_handler (GpgmeCtx ctx, GpgStatusCode code,
                                    char *args);
-GpgmeError _gpgme_decrypt_start (GpgmeCtx ctx, GpgmeData ciph, GpgmeData plain,
+GpgmeError _gpgme_decrypt_start (GpgmeCtx ctx, int synchronous,
+                                GpgmeData ciph, GpgmeData plain,
                                 void *status_handler);
 GpgmeError _gpgme_decrypt_result (GpgmeCtx ctx);
 
index 1d6aa2b..318e99d 100644 (file)
@@ -54,113 +54,166 @@ struct arg_and_data_s {
     char arg[1];     /* .. this is used */
 };
 
-struct fd_data_map_s {
-    GpgmeData data;
-    int inbound;  /* true if this is used for reading from gpg */
-    int dup_to;
-    int fd;       /* the fd to use */
-    int peer_fd;  /* the outher side of the pipe */
+struct fd_data_map_s
+{
+  GpgmeData data;
+  int inbound;  /* true if this is used for reading from gpg */
+  int dup_to;
+  int fd;       /* the fd to use */
+  int peer_fd;  /* the outher side of the pipe */
+  void *tag;
 };
 
 
-struct gpg_object_s {
-    struct arg_and_data_s *arglist;
-    struct arg_and_data_s **argtail;
-    int arg_error;  
-
-    struct {
-        int fd[2];  
-        size_t bufsize;
-        char *buffer;
-        size_t readpos;
-        int eof;
-        GpgStatusHandler fnc;
-        void *fnc_value;
-    } status;
-
-    /* This is a kludge - see the comment at gpg_colon_line_handler */
-    struct {
-        int fd[2];  
-        size_t bufsize;
-        char *buffer;
-        size_t readpos;
-        int eof;
-        GpgColonLineHandler fnc;  /* this indicate use of this structrue */
-        void *fnc_value;
-        int simple;
-    } colon;
-
-    char **argv;  
-    struct fd_data_map_s *fd_data_map;
-
-    int pid; /* we can't use pid_t because we don't use it in Windoze */
-
-    int running;
-    
-    /* stuff needed for pipemode */
-    struct {
-        int used;
-        int active;
-        GpgmeData sig;
-        GpgmeData text;
-        int stream_started;
-    } pm;
-
-    /* stuff needed for interactive (command) mode */
-    struct {
-        int used;
-        int fd;
-        GpgmeData cb_data;   /* hack to get init the above fd later */
-        GpgStatusCode code;  /* last code */
-        char *keyword;       /* what has been requested (malloced) */
-        GpgCommandHandler fnc; 
-        void *fnc_value;
-    } cmd;
+struct gpg_object_s
+{
+  struct arg_and_data_s *arglist;
+  struct arg_and_data_s **argtail;
+  int arg_error;  
+
+  struct
+  {
+    int fd[2];  
+    size_t bufsize;
+    char *buffer;
+    size_t readpos;
+    int eof;
+    GpgStatusHandler fnc;
+    void *fnc_value;
+    void *tag;
+  } status;
+
+  /* This is a kludge - see the comment at gpg_colon_line_handler */
+  struct
+  {
+    int fd[2];  
+    size_t bufsize;
+    char *buffer;
+    size_t readpos;
+    int eof;
+    GpgColonLineHandler fnc;  /* this indicate use of this structrue */
+    void *fnc_value;
+    void *tag;
+    int simple;
+  } colon;
+
+  char **argv;  
+  struct fd_data_map_s *fd_data_map;
+
+  int pid; /* we can't use pid_t because we don't use it in Windoze */
+
+  /* stuff needed for pipemode */
+  struct
+  {
+    int used;
+    int active;
+    GpgmeData sig;
+    GpgmeData text;
+    int stream_started;
+  } pm;
+
+  /* stuff needed for interactive (command) mode */
+  struct
+  {
+    int used;
+    int fd;
+    int idx;           /* Index in fd_data_map */
+    GpgmeData cb_data;   /* hack to get init the above idx later */
+    GpgStatusCode code;  /* last code */
+    char *keyword;       /* what has been requested (malloced) */
+    GpgCommandHandler fnc; 
+    void *fnc_value;
+  } cmd;
+
+  struct GpgmeIOCbs io_cbs;
 };
 
-static void free_argv ( char **argv );
-static void free_fd_data_map ( struct fd_data_map_s *fd_data_map );
-
-static int gpg_status_handler ( void *opaque, int pid, int fd );
-static GpgmeError read_status ( GpgObject gpg );
+static void free_argv (char **argv);
+static void free_fd_data_map (struct fd_data_map_s *fd_data_map);
 
-static int gpg_colon_line_handler ( void *opaque, int pid, int fd );
-static GpgmeError read_colon_line ( GpgObject gpg );
+static void gpg_status_handler (void *opaque, int fd);
+static GpgmeError read_status (GpgObject gpg);
 
-static int pipemode_cb ( void *opaque,
-                         char *buffer, size_t length, size_t *nread );
-static int command_cb ( void *opaque,
-                        char *buffer, size_t length, size_t *nread );
+static void gpg_colon_line_handler (void *opaque, int fd);
+static GpgmeError read_colon_line (GpgObject gpg);
 
+static int pipemode_cb (void *opaque, char *buffer, size_t length,
+                       size_t *nread);
+static int command_cb (void *opaque, char *buffer, size_t length,
+                      size_t *nread);
 
 static void
-close_notify_handler ( int fd, void *opaque )
+close_notify_handler (int fd, void *opaque)
 {
-    GpgObject gpg = opaque;
+  GpgObject gpg = opaque;
+  int possibly_done = 0;
+  int not_done = 0;
+  assert (fd != -1);
 
-    assert (fd != -1);
-    if (gpg->status.fd[0] == fd )
-        gpg->status.fd[0] = -1;
-    else if (gpg->status.fd[1] == fd )
-        gpg->status.fd[1] = -1;
-    else if (gpg->colon.fd[0] == fd )
-        gpg->colon.fd[0] = -1;
-    else if (gpg->colon.fd[1] == fd )
-        gpg->colon.fd[1] = -1;
-    else if (gpg->fd_data_map) {
-        int i;
-
-        for (i=0; gpg->fd_data_map[i].data; i++ ) {
-            if ( gpg->fd_data_map[i].fd == fd ) {
-                gpg->fd_data_map[i].fd = -1;
-                break;
+  if (gpg->status.fd[0] == fd)
+    {
+      if (gpg->status.tag)
+       {
+         (*gpg->io_cbs.remove) (gpg->status.tag);
+         possibly_done = 1;
+       }
+      gpg->status.fd[0] = -1;
+    }
+  else if (gpg->status.fd[1] == fd)
+    gpg->status.fd[1] = -1;
+  else if (gpg->colon.fd[0] == fd)
+    {
+      if (gpg->colon.tag)
+       {
+         (*gpg->io_cbs.remove) (gpg->colon.tag);
+         possibly_done = 1;
+       }
+      gpg->colon.fd[0] = -1;
+    }
+  else if (gpg->colon.fd[1] == fd)
+    gpg->colon.fd[1] = -1;
+  else if (gpg->fd_data_map)
+    {
+      int i;
+
+      for (i = 0; gpg->fd_data_map[i].data; i++)
+       {
+         if (gpg->fd_data_map[i].fd == fd)
+           {
+             if (gpg->fd_data_map[i].tag)
+               {
+                 (*gpg->io_cbs.remove) (gpg->fd_data_map[i].tag);
+                 possibly_done = 1;
+               }
+             gpg->fd_data_map[i].fd = -1;
+             break;
             }
-            if ( gpg->fd_data_map[i].peer_fd == fd ) {
-                gpg->fd_data_map[i].peer_fd = -1;
-                break;
+         if (gpg->fd_data_map[i].peer_fd == fd)
+           {
+             gpg->fd_data_map[i].peer_fd = -1;
+             break;
             }
         }
     }
+  if (!possibly_done)
+    not_done = 1;
+  else if (gpg->status.fd[0] != -1)
+    not_done = 1;
+  else if (gpg->colon.fd[0] != -1)
+    not_done = 1;
+  else if (gpg->fd_data_map)
+    {
+      int i;
+
+      for (i = 0; gpg->fd_data_map[i].data; i++)
+       if (gpg->fd_data_map[i].fd != -1)
+         {
+           not_done = 1;
+           break;
+         }
+    }
+  if (!not_done && gpg->io_cbs.event)
+    (*gpg->io_cbs.event) (gpg->io_cbs.event_priv, GPGME_EVENT_DONE, NULL);
 }
 
 const char *
@@ -185,65 +238,70 @@ _gpgme_gpg_check_version (void)
 }
 
 GpgmeError
-_gpgme_gpg_new ( GpgObject *r_gpg )
+_gpgme_gpg_new (GpgObject *r_gpg)
 {
-    GpgObject gpg;
-    int rc = 0;
-
-    gpg = xtrycalloc ( 1, sizeof *gpg );
-    if ( !gpg ) {
-        rc = mk_error (Out_Of_Core);
-        goto leave;
-    }
-    gpg->argtail = &gpg->arglist;
+  GpgObject gpg;
+  int rc = 0;
 
-    gpg->status.fd[0] = -1;
-    gpg->status.fd[1] = -1;
-    gpg->colon.fd[0] = -1;
-    gpg->colon.fd[1] = -1;
-    gpg->cmd.fd = -1;
-
-    gpg->pid = -1;
-
-    /* allocate the read buffer for the status pipe */
-    gpg->status.bufsize = 1024;
-    gpg->status.readpos = 0;
-    gpg->status.buffer = xtrymalloc (gpg->status.bufsize);
-    if (!gpg->status.buffer) {
-        rc = mk_error (Out_Of_Core);
-        goto leave;
+  gpg = xtrycalloc (1, sizeof *gpg);
+  if (!gpg)
+    {
+      rc = mk_error (Out_Of_Core);
+      goto leave;
     }
-    /* In any case we need a status pipe - create it right here  and
-     * don't handle it with our generic GpgmeData mechanism */
-    if (_gpgme_io_pipe (gpg->status.fd, 1) == -1) {
-        rc = mk_error (Pipe_Error);
-        goto leave;
+  gpg->argtail = &gpg->arglist;
+
+  gpg->status.fd[0] = -1;
+  gpg->status.fd[1] = -1;
+  gpg->colon.fd[0] = -1;
+  gpg->colon.fd[1] = -1;
+  gpg->cmd.fd = -1;
+  gpg->cmd.idx = -1;
+
+  gpg->pid = -1;
+
+  /* Allocate the read buffer for the status pipe.  */
+  gpg->status.bufsize = 1024;
+  gpg->status.readpos = 0;
+  gpg->status.buffer = xtrymalloc (gpg->status.bufsize);
+  if (!gpg->status.buffer)
+    {
+      rc = mk_error (Out_Of_Core);
+      goto leave;
     }
-    if ( _gpgme_io_set_close_notify (gpg->status.fd[0],
-                                     close_notify_handler, gpg)
-         || _gpgme_io_set_close_notify (gpg->status.fd[1],
-                                        close_notify_handler, gpg) ) {
-        rc = mk_error (General_Error);
-        goto leave;
+  /* In any case we need a status pipe - create it right here and
+     don't handle it with our generic GpgmeData mechanism.  */
+  if (_gpgme_io_pipe (gpg->status.fd, 1) == -1)
+    {
+      rc = mk_error (Pipe_Error);
+      goto leave;
     }
-    gpg->status.eof = 0;
-    _gpgme_gpg_add_arg ( gpg, "--status-fd" );
+  if (_gpgme_io_set_close_notify (gpg->status.fd[0],
+                                 close_notify_handler, gpg)
+      || _gpgme_io_set_close_notify (gpg->status.fd[1],
+                                    close_notify_handler, gpg))
     {
-        char buf[25];
-        sprintf ( buf, "%d", gpg->status.fd[1]);
-        _gpgme_gpg_add_arg ( gpg, buf );
+      rc = mk_error (General_Error);
+      goto leave;
     }
-    _gpgme_gpg_add_arg ( gpg, "--no-tty" );
-
+  gpg->status.eof = 0;
+  _gpgme_gpg_add_arg (gpg, "--status-fd");
+  {
+    char buf[25];
+    sprintf (buf, "%d", gpg->status.fd[1]);
+    _gpgme_gpg_add_arg (gpg, buf);
+  }
+  _gpgme_gpg_add_arg (gpg, "--no-tty");
 
  leave:
-    if (rc) {
-        _gpgme_gpg_release (gpg);
-        *r_gpg = NULL;
+  if (rc)
+    {
+      _gpgme_gpg_release (gpg);
+      *r_gpg = NULL;
     }
-    else
-        *r_gpg = gpg;
-    return rc;
+  else
+    *r_gpg = gpg;
+  return rc;
 }
 
 
@@ -268,8 +326,6 @@ _gpgme_gpg_release (GpgObject gpg)
   gpgme_data_release (gpg->cmd.cb_data);
   xfree (gpg->cmd.keyword);
 
-  if (gpg->pid != -1) 
-    _gpgme_remove_proc_from_wait_queue (gpg->pid);
   if (gpg->status.fd[0] != -1)
     _gpgme_io_close (gpg->status.fd[0]);
   if (gpg->status.fd[1] != -1)
@@ -279,7 +335,9 @@ _gpgme_gpg_release (GpgObject gpg)
   if (gpg->colon.fd[1] != -1)
     _gpgme_io_close (gpg->colon.fd[1]);
   free_fd_data_map (gpg->fd_data_map);
-  if (gpg->running)
+  if (gpg->cmd.fd != -1)
+    _gpgme_io_close (gpg->cmd.fd);
+  if (gpg->pid != -1)
     _gpgme_engine_add_child_to_reap_list (gpg, sizeof *gpg, gpg->pid);
   else
     xfree (gpg);
@@ -512,341 +570,387 @@ free_fd_data_map ( struct fd_data_map_s *fd_data_map )
 
 
 static GpgmeError
-build_argv ( GpgObject gpg )
+build_argv (GpgObject gpg)
 {
-    struct arg_and_data_s *a;
-    struct fd_data_map_s *fd_data_map;
-    size_t datac=0, argc=0;  
-    char **argv;
-    int need_special = 0;
-    int use_agent = !!getenv ("GPG_AGENT_INFO");
+  struct arg_and_data_s *a;
+  struct fd_data_map_s *fd_data_map;
+  size_t datac=0, argc=0;  
+  char **argv;
+  int need_special = 0;
+  int use_agent = !!getenv ("GPG_AGENT_INFO");
        
-    if ( gpg->argv ) {
-        free_argv ( gpg->argv );
-        gpg->argv = NULL;
+  if (gpg->argv)
+    {
+      free_argv (gpg->argv);
+      gpg->argv = NULL;
     }
-    if (gpg->fd_data_map) {
-        free_fd_data_map (gpg->fd_data_map);
-        gpg->fd_data_map = NULL;
+  if (gpg->fd_data_map)
+    {
+      free_fd_data_map (gpg->fd_data_map);
+      gpg->fd_data_map = NULL;
     }
 
-    argc++; /* for argv[0] */
-    for ( a=gpg->arglist; a; a = a->next ) {
-        argc++;
-        if (a->data) {
-            /*fprintf (stderr, "build_argv: data\n" );*/
-            datac++;
-            if ( a->dup_to == -1 && !a->print_fd )
-                need_special = 1;
+  argc++;      /* For argv[0].  */
+  for (a = gpg->arglist; a; a = a->next)
+    {
+      argc++;
+      if (a->data)
+       {
+         /*fprintf (stderr, "build_argv: data\n" );*/
+         datac++;
+         if (a->dup_to == -1 && !a->print_fd)
+           need_special = 1;
         }
-        else {
-            /*   fprintf (stderr, "build_argv: arg=`%s'\n", a->arg );*/
+      else
+       {
+         /*   fprintf (stderr, "build_argv: arg=`%s'\n", a->arg );*/
         }
     }
-    if ( need_special )
-        argc++;
-    if (use_agent)
-        argc++;
-    if (!gpg->cmd.used)
-        argc++;
-    argc += 2; /* --comment */
-
-    argv = xtrycalloc ( argc+1, sizeof *argv );
-    if (!argv)
-        return mk_error (Out_Of_Core);
-    fd_data_map = xtrycalloc ( datac+1, sizeof *fd_data_map );
-    if (!fd_data_map) {
-        free_argv (argv);
-        return mk_error (Out_Of_Core);
+  if (need_special)
+    argc++;
+  if (use_agent)
+    argc++;
+  if (!gpg->cmd.used)
+    argc++;
+  argc += 2; /* --comment */
+
+  argv = xtrycalloc (argc + 1, sizeof *argv);
+  if (!argv)
+    return mk_error (Out_Of_Core);
+  fd_data_map = xtrycalloc (datac + 1, sizeof *fd_data_map);
+  if (!fd_data_map)
+    {
+      free_argv (argv);
+      return mk_error (Out_Of_Core);
     }
 
-    argc = datac = 0;
-    argv[argc] = xtrystrdup ( "gpg" ); /* argv[0] */
-    if (!argv[argc]) {
-        xfree (fd_data_map);
-        free_argv (argv);
-        return mk_error (Out_Of_Core);
+  argc = datac = 0;
+  argv[argc] = xtrystrdup ("gpg"); /* argv[0] */
+  if (!argv[argc])
+    {
+      xfree (fd_data_map);
+      free_argv (argv);
+      return mk_error (Out_Of_Core);
     }
-    argc++;
-    if ( need_special ) {
-        argv[argc] = xtrystrdup ( "--enable-special-filenames" );
-        if (!argv[argc]) {
-            xfree (fd_data_map);
-            free_argv (argv);
-            return mk_error (Out_Of_Core);
+  argc++;
+  if (need_special)
+    {
+      argv[argc] = xtrystrdup ("--enable-special-filenames");
+      if (!argv[argc])
+       {
+         xfree (fd_data_map);
+         free_argv (argv);
+         return mk_error (Out_Of_Core);
         }
-        argc++;
+      argc++;
     }
-    if ( use_agent ) {
-        argv[argc] = xtrystrdup ( "--use-agent" );
-        if (!argv[argc]) {
-            xfree (fd_data_map);
-            free_argv (argv);
-            return mk_error (Out_Of_Core);
+  if (use_agent)
+    {
+      argv[argc] = xtrystrdup ("--use-agent");
+      if (!argv[argc])
+       {
+         xfree (fd_data_map);
+         free_argv (argv);
+         return mk_error (Out_Of_Core);
         }
-        argc++;
+      argc++;
     }
-    if ( !gpg->cmd.used ) {
-        argv[argc] = xtrystrdup ( "--batch" );
-        if (!argv[argc]) {
-            xfree (fd_data_map);
-            free_argv (argv);
-            return mk_error (Out_Of_Core);
+  if (!gpg->cmd.used)
+    {
+      argv[argc] = xtrystrdup ("--batch");
+      if (!argv[argc])
+       {
+         xfree (fd_data_map);
+         free_argv (argv);
+         return mk_error (Out_Of_Core);
         }
-        argc++;
+      argc++;
     }
-    argv[argc] = xtrystrdup ( "--comment" );
-    if (!argv[argc]) {
-        xfree (fd_data_map);
-        free_argv (argv);
-        return mk_error (Out_Of_Core);
+  argv[argc] = xtrystrdup ("--comment");
+  if (!argv[argc])
+    {
+      xfree (fd_data_map);
+      free_argv (argv);
+      return mk_error (Out_Of_Core);
     }
-    argc++;
-    argv[argc] = xtrystrdup ( "" );
-    if (!argv[argc]) {
-        xfree (fd_data_map);
-        free_argv (argv);
-        return mk_error (Out_Of_Core);
+  argc++;
+  argv[argc] = xtrystrdup ("");
+  if (!argv[argc])
+    {
+      xfree (fd_data_map);
+      free_argv (argv);
+      return mk_error (Out_Of_Core);
     }
-    argc++;
-    for ( a=gpg->arglist; a; a = a->next ) {
-        if ( a->data ) {
-            switch ( _gpgme_data_get_mode (a->data) ) {
-              case GPGME_DATA_MODE_NONE:
-              case GPGME_DATA_MODE_INOUT:
-                xfree (fd_data_map);
-                free_argv (argv);
-                return mk_error (Invalid_Mode);
-              case GPGME_DATA_MODE_IN:
-                /* create a pipe to read from gpg */
-                fd_data_map[datac].inbound = 1;
-                break;
-              case GPGME_DATA_MODE_OUT:
-                /* create a pipe to pass it down to gpg */
-                fd_data_map[datac].inbound = 0;
-                break;
+  argc++;
+  for (a = gpg->arglist; a; a = a->next)
+    {
+      if (a->data)
+       {
+         switch (_gpgme_data_get_mode (a->data))
+           {
+           case GPGME_DATA_MODE_NONE:
+           case GPGME_DATA_MODE_INOUT:
+             xfree (fd_data_map);
+             free_argv (argv);
+             return mk_error (Invalid_Mode);
+           case GPGME_DATA_MODE_IN:
+             /* Create a pipe to read from gpg.  */
+             fd_data_map[datac].inbound = 1;
+             break;
+           case GPGME_DATA_MODE_OUT:
+             /* Create a pipe to pass it down to gpg.  */
+             fd_data_map[datac].inbound = 0;
+             break;
             }
 
-            switch ( gpgme_data_get_type (a->data) ) {
-              case GPGME_DATA_TYPE_NONE:
-                if ( fd_data_map[datac].inbound )
-                    break;  /* allowed */
-                xfree (fd_data_map);
-                free_argv (argv);
-                return mk_error (Invalid_Type);
-              case GPGME_DATA_TYPE_MEM:
-              case GPGME_DATA_TYPE_CB:
-                break;
-              case GPGME_DATA_TYPE_FD:
-              case GPGME_DATA_TYPE_FILE:
-                xfree (fd_data_map);
-                free_argv (argv);
-                return mk_error (Not_Implemented);
+         switch (gpgme_data_get_type (a->data))
+           {
+           case GPGME_DATA_TYPE_NONE:
+             if (fd_data_map[datac].inbound)
+               break;  /* Allowed.  */
+             xfree (fd_data_map);
+             free_argv (argv);
+             return mk_error (Invalid_Type);
+           case GPGME_DATA_TYPE_MEM:
+           case GPGME_DATA_TYPE_CB:
+             break;
+           case GPGME_DATA_TYPE_FD:
+           case GPGME_DATA_TYPE_FILE:
+             xfree (fd_data_map);
+             free_argv (argv);
+             return mk_error (Not_Implemented);
             }
   
-            /* create a pipe */
-            {   
-                int fds[2];
-                
-                if (_gpgme_io_pipe (fds, fd_data_map[datac].inbound?1:0 )
-                    == -1) {
-                    xfree (fd_data_map);
-                    free_argv (argv);
-                    return mk_error (Pipe_Error);
-                }
-                if ( _gpgme_io_set_close_notify (fds[0],
-                                                 close_notify_handler, gpg)
-                     || _gpgme_io_set_close_notify (fds[1],
-                                                    close_notify_handler,
-                                                    gpg)) {
-                    return mk_error (General_Error);
-                }
-                /* if the data_type is FD, we have to do a dup2 here */
-                if (fd_data_map[datac].inbound) {
-                    fd_data_map[datac].fd       = fds[0];
-                    fd_data_map[datac].peer_fd  = fds[1];
-                }
-                else {
-                    fd_data_map[datac].fd       = fds[1];
-                    fd_data_map[datac].peer_fd  = fds[0];
-                }
-            }
-
-            /* Hack to get hands on the fd later */
-            if ( gpg->cmd.used && gpg->cmd.cb_data == a->data ) {
-                assert (gpg->cmd.fd == -1);
-                gpg->cmd.fd = fd_data_map[datac].fd;
-            }
+         /* Create a pipe.  */
+         {   
+           int fds[2];
+           
+           if (_gpgme_io_pipe (fds, fd_data_map[datac].inbound ? 1 : 0)
+               == -1)
+             {
+               xfree (fd_data_map);
+               free_argv (argv);
+               return mk_error (Pipe_Error);
+             }
+           if (_gpgme_io_set_close_notify (fds[0],
+                                           close_notify_handler, gpg)
+               || _gpgme_io_set_close_notify (fds[1],
+                                              close_notify_handler,
+                                              gpg))
+             {
+               return mk_error (General_Error);
+             }
+           /* If the data_type is FD, we have to do a dup2 here.  */
+           if (fd_data_map[datac].inbound)
+             {
+               fd_data_map[datac].fd       = fds[0];
+               fd_data_map[datac].peer_fd  = fds[1];
+             }
+           else
+             {
+               fd_data_map[datac].fd       = fds[1];
+               fd_data_map[datac].peer_fd  = fds[0];
+             }
+         }
+
+         /* Hack to get hands on the fd later.  */
+         if (gpg->cmd.used && gpg->cmd.cb_data == a->data)
+           {
+             assert (gpg->cmd.idx == -1);
+             gpg->cmd.idx = datac;
+           }
 
-            fd_data_map[datac].data = a->data;
-            fd_data_map[datac].dup_to = a->dup_to;
-            if ( a->dup_to == -1 ) {
-                argv[argc] = xtrymalloc ( 25 );
-                if (!argv[argc]) {
-                    xfree (fd_data_map);
-                    free_argv (argv);
-                    return mk_error (Out_Of_Core);
+         fd_data_map[datac].data = a->data;
+         fd_data_map[datac].dup_to = a->dup_to;
+         if (a->dup_to == -1)
+           {
+             argv[argc] = xtrymalloc (25);
+             if (!argv[argc])
+               {
+                 xfree (fd_data_map);
+                 free_argv (argv);
+                 return mk_error (Out_Of_Core);
                 }
-                sprintf ( argv[argc], 
-                          a->print_fd? "%d" : "-&%d",
-                          fd_data_map[datac].peer_fd );
-                argc++;
+             sprintf (argv[argc], 
+                      a->print_fd ? "%d" : "-&%d",
+                      fd_data_map[datac].peer_fd);
+             argc++;
             }
-            datac++;
+         datac++;
         }
-        else {
-            argv[argc] = xtrystrdup ( a->arg );
-            if (!argv[argc]) {
-                xfree (fd_data_map);
-                free_argv (argv);
-                return mk_error (Out_Of_Core);
+      else
+       {
+         argv[argc] = xtrystrdup (a->arg);
+         if (!argv[argc])
+           {
+             xfree (fd_data_map);
+             free_argv (argv);
+             return mk_error (Out_Of_Core);
             }
             argc++;
         }
     }
 
-    gpg->argv = argv;
-    gpg->fd_data_map = fd_data_map;
-    return 0;
+  gpg->argv = argv;
+  gpg->fd_data_map = fd_data_map;
+  return 0;
+}
+
+static GpgmeError
+_gpgme_gpg_add_io_cb (GpgObject gpg, int fd, int dir,
+                     GpgmeIOCb handler, void *data, void **tag)
+{
+  GpgmeError err = 0;
+
+  *tag = (*gpg->io_cbs.add) (gpg->io_cbs.add_priv, fd, dir, handler, data);
+  if (!tag)
+    err = mk_error (General_Error);
+  if (!err && !dir)
+    /* FIXME Kludge around poll() problem.  */
+    err = _gpgme_io_set_nonblocking (fd);
+  return err;
 }
 
 GpgmeError
-_gpgme_gpg_spawn( GpgObject gpg, void *opaque )
+_gpgme_gpg_spawn (GpgObject gpg, void *opaque)
 {
-    int rc;
-    int i, n;
-    int pid;
-    struct spawn_fd_item_s *fd_child_list, *fd_parent_list;
+  GpgmeError rc;
+  int i, n;
+  int pid;
+  struct spawn_fd_item_s *fd_child_list, *fd_parent_list;
 
-    if (!gpg)
-      return mk_error (Invalid_Value);
+  if (!gpg)
+    return mk_error (Invalid_Value);
 
-    if (! _gpgme_get_gpg_path ())
-      return mk_error (Invalid_Engine);
+  if (! _gpgme_get_gpg_path ())
+    return mk_error (Invalid_Engine);
 
-    /* Kludge, so that we don't need to check the return code of
-     * all the gpgme_gpg_add_arg().  we bail out here instead */
-    if ( gpg->arg_error )
-        return mk_error (Out_Of_Core);
+  /* Kludge, so that we don't need to check the return code of all the
+     gpgme_gpg_add_arg().  we bail out here instead */
+  if (gpg->arg_error)
+    return mk_error (Out_Of_Core);
 
-    if (gpg->pm.active)
-        return 0;
+  if (gpg->pm.active)
+    return 0;
 
-    rc = build_argv ( gpg );
-    if ( rc )
-        return rc;
+  rc = build_argv (gpg);
+  if (rc)
+    return rc;
 
-    n = 3; /* status_fd, colon_fd and end of list */
-    for (i=0; gpg->fd_data_map[i].data; i++ ) 
-        n++;
-    fd_child_list = xtrycalloc ( n+n, sizeof *fd_child_list );
-    if (!fd_child_list)
-        return mk_error (Out_Of_Core);
-    fd_parent_list = fd_child_list + n;
-
-    /* build the fd list for the child */
-    n=0;
-    if ( gpg->colon.fnc ) {
-        fd_child_list[n].fd = gpg->colon.fd[1]; 
-        fd_child_list[n].dup_to = 1; /* dup to stdout */
-        n++;
+  n = 3; /* status_fd, colon_fd and end of list */
+  for (i = 0; gpg->fd_data_map[i].data; i++) 
+    n++;
+  fd_child_list = xtrycalloc (n + n, sizeof *fd_child_list);
+  if (!fd_child_list)
+    return mk_error (Out_Of_Core);
+  fd_parent_list = fd_child_list + n;
+
+  /* build the fd list for the child */
+  n = 0;
+  if (gpg->colon.fnc)
+    {
+      fd_child_list[n].fd = gpg->colon.fd[1]; 
+      fd_child_list[n].dup_to = 1; /* dup to stdout */
+      n++;
     }
-    for (i=0; gpg->fd_data_map[i].data; i++ ) {
-        if (gpg->fd_data_map[i].dup_to != -1) {
-            fd_child_list[n].fd = gpg->fd_data_map[i].peer_fd;
-            fd_child_list[n].dup_to = gpg->fd_data_map[i].dup_to;
-            n++;
+  for (i = 0; gpg->fd_data_map[i].data; i++)
+    {
+      if (gpg->fd_data_map[i].dup_to != -1)
+       {
+         fd_child_list[n].fd = gpg->fd_data_map[i].peer_fd;
+         fd_child_list[n].dup_to = gpg->fd_data_map[i].dup_to;
+         n++;
         }
     }
-    fd_child_list[n].fd = -1;
-    fd_child_list[n].dup_to = -1;
-
-    /* build the fd list for the parent */
-    n=0;
-    if ( gpg->status.fd[1] != -1 ) {
-        fd_parent_list[n].fd = gpg->status.fd[1];
-        fd_parent_list[n].dup_to = -1;
-        n++;
-        gpg->status.fd[1] = -1;
+  fd_child_list[n].fd = -1;
+  fd_child_list[n].dup_to = -1;
+
+  /* Build the fd list for the parent.  */
+  n = 0;
+  if (gpg->status.fd[1] != -1)
+    {
+      fd_parent_list[n].fd = gpg->status.fd[1];
+      fd_parent_list[n].dup_to = -1;
+      n++;
+      gpg->status.fd[1] = -1;
     }
-    if ( gpg->colon.fd[1] != -1 ) {
-        fd_parent_list[n].fd = gpg->colon.fd[1];
-        fd_parent_list[n].dup_to = -1;
-        n++;
-        gpg->colon.fd[1] = -1;
+  if (gpg->colon.fd[1] != -1)
+    {
+      fd_parent_list[n].fd = gpg->colon.fd[1];
+      fd_parent_list[n].dup_to = -1;
+      n++;
+      gpg->colon.fd[1] = -1;
     }
-    for (i=0; gpg->fd_data_map[i].data; i++ ) {
-        fd_parent_list[n].fd = gpg->fd_data_map[i].peer_fd;
-        fd_parent_list[n].dup_to = -1;
-        n++;
-        gpg->fd_data_map[i].peer_fd = -1;
+  for (i = 0; gpg->fd_data_map[i].data; i++)
+    {
+      fd_parent_list[n].fd = gpg->fd_data_map[i].peer_fd;
+      fd_parent_list[n].dup_to = -1;
+      n++;
+      gpg->fd_data_map[i].peer_fd = -1;
     }        
-    fd_parent_list[n].fd = -1;
-    fd_parent_list[n].dup_to = -1;
-
+  fd_parent_list[n].fd = -1;
+  fd_parent_list[n].dup_to = -1;
 
-    pid = _gpgme_io_spawn (_gpgme_get_gpg_path (),
-                           gpg->argv, fd_child_list, fd_parent_list);
-    xfree (fd_child_list);
-    if (pid == -1) {
-        return mk_error (Exec_Error);
-    }
+  pid = _gpgme_io_spawn (_gpgme_get_gpg_path (),
+                        gpg->argv, fd_child_list, fd_parent_list);
+  xfree (fd_child_list);
+  if (pid == -1)
+    return mk_error (Exec_Error);
 
-    gpg->pid = pid;
-    if (gpg->pm.used)
-        gpg->pm.active = 1;
+  gpg->pid = pid;
+  if (gpg->pm.used)
+    gpg->pm.active = 1;
 
-    /*_gpgme_register_term_handler ( closure, closure_value, pid );*/
-
-    if ( _gpgme_register_pipe_handler ( opaque, gpg_status_handler,
-                                        gpg, pid, gpg->status.fd[0], 1 ) ) {
-        /* FIXME: kill the child */
-        return mk_error (General_Error);
+  /*_gpgme_register_term_handler ( closure, closure_value, pid );*/
 
-    }
+  rc = _gpgme_gpg_add_io_cb (gpg, gpg->status.fd[0], 1,
+                            gpg_status_handler, gpg, &gpg->status.tag);
+  if (rc)
+    /* FIXME: kill the child */
+    return rc;
 
-    if ( gpg->colon.fnc ) {
-        assert ( gpg->colon.fd[0] != -1 );
-        if ( _gpgme_register_pipe_handler ( opaque, gpg_colon_line_handler,
-                                            gpg, pid, gpg->colon.fd[0], 1 ) ) {
-            /* FIXME: kill the child */
-            return mk_error (General_Error);
-            
-        }
+  if (gpg->colon.fnc)
+    {
+      assert (gpg->colon.fd[0] != -1);
+      rc = _gpgme_gpg_add_io_cb (gpg, gpg->colon.fd[0], 1,
+                                gpg_colon_line_handler, gpg,
+                                &gpg->colon.tag);
+      if (rc)
+       /* FIXME: kill the child */
+       return rc;
     }
 
-    for (i=0; gpg->fd_data_map[i].data; i++ ) {
-        /* Due to problems with select and write we set outbound pipes
-         * to non-blocking */
-        if (!gpg->fd_data_map[i].inbound) {
-            _gpgme_io_set_nonblocking (gpg->fd_data_map[i].fd);
-        }
-
-        if ( _gpgme_register_pipe_handler (
-                 opaque, 
-                 gpg->fd_data_map[i].inbound?
-                _gpgme_data_inbound_handler:_gpgme_data_outbound_handler,
-                 gpg->fd_data_map[i].data,
-                 pid, gpg->fd_data_map[i].fd,
-                 gpg->fd_data_map[i].inbound )
-           ) {
-            /* FIXME: kill the child */
-            return mk_error (General_Error);
-        }
+  for (i = 0; gpg->fd_data_map[i].data; i++)
+    {
+      if (gpg->cmd.used && i == gpg->cmd.idx)
+       {
+         /* Park the cmd fd.  */
+         gpg->cmd.fd = gpg->fd_data_map[i].fd;
+         gpg->fd_data_map[i].fd = -1;
+       }
+      else
+       {
+         rc = _gpgme_gpg_add_io_cb (gpg, gpg->fd_data_map[i].fd,
+                                    gpg->fd_data_map[i].inbound,
+                                    gpg->fd_data_map[i].inbound
+                                    ? _gpgme_data_inbound_handler
+                                    : _gpgme_data_outbound_handler,
+                                    gpg->fd_data_map[i].data,
+                                    &gpg->fd_data_map[i].tag);
+         
+         if (rc)
+           /* FIXME: kill the child */
+           return rc;
+       }
     }
-
-    if ( gpg->cmd.used )
-        _gpgme_freeze_fd ( gpg->cmd.fd );
-
-    /* fixme: check what data we can release here */
-    
-    gpg->running = 1;
-    return 0;
+  
+  /* fixme: check what data we can release here */
+  return 0;
 }
 
 
-static int
-gpg_status_handler (void *opaque, int pid, int fd)
+static void
+gpg_status_handler (void *opaque, int fd)
 {
   GpgObject gpg = opaque;
   int err;
@@ -860,9 +964,11 @@ gpg_status_handler (void *opaque, int pid, int fd)
       GpgmeCtx ctx = (GpgmeCtx) gpg->status.fnc_value;
       ctx->error = err;
       DEBUG1 ("gpg_handler: read_status problem %d\n - stop", err);
-      return 1;
+      _gpgme_io_close (fd);
+      return;
     }
-  return gpg->status.eof;
+  if (gpg->status.eof)
+    _gpgme_io_close (fd);
 }
 
 
@@ -951,7 +1057,14 @@ read_status ( GpgObject gpg )
                              * handler does its action */
                             if ( nread > 1 )
                                 DEBUG0 ("ERROR, unexpected data in read_status");
-                            _gpgme_thaw_fd (gpg->cmd.fd);
+
+                           _gpgme_gpg_add_io_cb
+                             (gpg, gpg->cmd.fd,
+                              0, _gpgme_data_outbound_handler,
+                              gpg->fd_data_map[gpg->cmd.idx].data,
+                              &gpg->fd_data_map[gpg->cmd.idx].tag);
+                           gpg->fd_data_map[gpg->cmd.idx].fd = gpg->cmd.fd;
+                           gpg->cmd.fd = -1;
                         }
                         else if ( gpg->status.fnc ) {
                             gpg->status.fnc ( gpg->status.fnc_value, 
@@ -959,8 +1072,13 @@ read_status ( GpgObject gpg )
                         }
                     
                         if ( r->code == STATUS_END_STREAM ) {
-                            if ( gpg->cmd.used )
-                                _gpgme_freeze_fd ( gpg->cmd.fd );
+                         if (gpg->cmd.used)
+                           {
+                             (*gpg->io_cbs.remove)
+                               (gpg->fd_data_map[gpg->cmd.idx].tag);
+                             gpg->cmd.fd = gpg->fd_data_map[gpg->cmd.idx].fd;
+                             gpg->fd_data_map[gpg->cmd.idx].fd = -1;
+                           }
                         }
                     }
                 }
@@ -995,21 +1113,23 @@ read_status ( GpgObject gpg )
  * a wrapper for a callback.  Same goes for the status thing.
  * For now we use this thing here becuase it is easier to implement.
  */
-static int
-gpg_colon_line_handler ( void *opaque, int pid, int fd )
+static void
+gpg_colon_line_handler (void *opaque, int fd)
 {
-    GpgObject gpg = opaque;
-    GpgmeError rc = 0;
-
-    assert ( fd == gpg->colon.fd[0] );
-    rc = read_colon_line ( gpg );
-    if ( rc ) {
-        DEBUG1 ("gpg_colon_line_handler: "
-                 "read problem %d\n - stop", rc);
-        return 1;
-    }
+  GpgObject gpg = opaque;
+  GpgmeError rc = 0;
 
-    return gpg->colon.eof;
+  assert (fd == gpg->colon.fd[0]);
+  rc = read_colon_line (gpg);
+  if (rc)
+    {
+      DEBUG1 ("gpg_colon_line_handler: "
+             "read problem %d\n - stop", rc);
+      _gpgme_io_close (fd);
+      return;
+    }
+  if (gpg->colon.eof)
+    _gpgme_io_close (fd);
 }
 
 static GpgmeError
@@ -1167,52 +1287,59 @@ pipemode_cb ( void *opaque, char *buffer, size_t length, size_t *nread )
  */
 
 static int
-command_cb ( void *opaque, char *buffer, size_t length, size_t *nread )
+command_cb (void *opaque, char *buffer, size_t length, size_t *nread)
 {
-    GpgObject gpg = opaque;
-    const char *value;
-    int value_len;
-
-    DEBUG0 ("command_cb: enter\n");
-    assert (gpg->cmd.used);
-    if ( !buffer || !length || !nread )
-        return 0; /* those values are reserved for extensions */
-    *nread =0;
-    if ( !gpg->cmd.code ) {
-        DEBUG0 ("command_cb: no code\n");
-        return -1;
+  GpgObject gpg = opaque;
+  const char *value;
+  int value_len;
+
+  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;
+  if (!gpg->cmd.fnc)
+    {
+      DEBUG0 ("command_cb: no user cb\n");
+      return -1;
     }
 
-    value = gpg->cmd.fnc ( gpg->cmd.fnc_value, 
-                           gpg->cmd.code, gpg->cmd.keyword );
-    if ( !value ) {
-        DEBUG0 ("command_cb: no data from user cb\n");
-        gpg->cmd.fnc ( gpg->cmd.fnc_value, 0, value);
-        return -1;
+  value = gpg->cmd.fnc (gpg->cmd.fnc_value, 
+                       gpg->cmd.code, gpg->cmd.keyword);
+  if (!value)
+    {
+      DEBUG0 ("command_cb: no data from user cb\n");
+      gpg->cmd.fnc (gpg->cmd.fnc_value, 0, 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);
-        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);
+      return -1;
     }
 
-    memcpy ( buffer, value, value_len );
-    if ( !value_len || (value_len && value[value_len-1] != '\n') 
-        buffer[value_len++] = '\n';
-    *nread = value_len;
+  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);
-    gpg->cmd.code = 0;
-    /* and sleep again until read_status will wake us up again */
-    _gpgme_freeze_fd ( gpg->cmd.fd );
-    return 0;
+  gpg->cmd.fnc (gpg->cmd.fnc_value, 0, value);
+  gpg->cmd.code = 0;
+  /* And sleep again until read_status will wake us up again.  */
+  (*gpg->io_cbs.remove) (gpg->fd_data_map[gpg->cmd.idx].tag);
+  gpg->cmd.fd = gpg->fd_data_map[gpg->cmd.idx].fd;
+  gpg->fd_data_map[gpg->cmd.idx].fd = -1;
+
+  return 0;
 }
 
 GpgmeError
@@ -1603,3 +1730,10 @@ _gpgme_gpg_op_verify (GpgObject gpg, GpgmeData sig, GpgmeData text)
     }
   return err;
 }
+
+
+void
+_gpgme_gpg_set_io_cbs (GpgObject gpg, struct GpgmeIOCbs *io_cbs)
+{
+  gpg->io_cbs = *io_cbs;
+}
index 3388d06..20fffe6 100644 (file)
@@ -159,5 +159,6 @@ GpgmeError _gpgme_gpg_op_sign (GpgObject gpg, GpgmeData in, GpgmeData out,
 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);
 
 #endif /* RUNGPG_H */
index 494eed8..8f2fc71 100644 (file)
@@ -168,27 +168,19 @@ _gpgme_sign_status_handler (GpgmeCtx ctx, GpgStatusCode code, char *args)
     }
 }
 
-GpgmeError
-gpgme_op_sign_start (GpgmeCtx ctx, GpgmeData in, GpgmeData out,
-                    GpgmeSigMode mode)
+static GpgmeError
+_gpgme_op_sign_start (GpgmeCtx ctx, int synchronous,
+                     GpgmeData in, GpgmeData out,
+                     GpgmeSigMode mode)
 {
   GpgmeError err = 0;
 
-  fail_on_pending_request (ctx);
-  ctx->pending = 1;
-
-  _gpgme_release_result (ctx);
-
   if (mode != GPGME_SIG_MODE_NORMAL
       && mode != GPGME_SIG_MODE_DETACH
       && mode != GPGME_SIG_MODE_CLEAR)
     return mk_error (Invalid_Value);
-        
-  /* Create a process object.  */
-  _gpgme_engine_release (ctx->engine);
-  ctx->engine = NULL;
-  err = _gpgme_engine_new (ctx->use_cms ? GPGME_PROTOCOL_CMS
-                          : GPGME_PROTOCOL_OpenPGP, &ctx->engine);
+
+  err = _gpgme_op_reset (ctx, synchronous);
   if (err)
     goto leave;
 
@@ -231,6 +223,13 @@ gpgme_op_sign_start (GpgmeCtx ctx, GpgmeData in, GpgmeData out,
   return err;
 }
 
+GpgmeError
+gpgme_op_sign_start (GpgmeCtx ctx, GpgmeData in, GpgmeData out,
+                    GpgmeSigMode mode)
+{
+  return _gpgme_op_sign_start (ctx, 0, in, out, mode);
+}
+
 /**
  * gpgme_op_sign:
  * @ctx: The context
@@ -255,8 +254,8 @@ gpgme_op_sign_start (GpgmeCtx ctx, GpgmeData in, GpgmeData out,
 GpgmeError
 gpgme_op_sign (GpgmeCtx ctx, GpgmeData in, GpgmeData out, GpgmeSigMode mode)
 {
-  GpgmeError err = gpgme_op_sign_start (ctx, in, out, mode);
+  GpgmeError err = _gpgme_op_sign_start (ctx, 1, in, out, mode);
   if (!err)
-    gpgme_wait (ctx, &err, 1);
+    err = _gpgme_wait_one (ctx);
   return err;
 }
index fd704a1..7270e1c 100644 (file)
@@ -164,26 +164,13 @@ gpgme_op_trustlist_start (GpgmeCtx ctx, const char *pattern, int max_level)
 {
   GpgmeError err = 0;
 
-  fail_on_pending_request (ctx);
   if (!pattern || !*pattern)
     return mk_error (Invalid_Value);
 
-  ctx->pending = 1;
-
-  if (ctx->engine)
-    {
-      _gpgme_engine_release (ctx->engine); 
-      ctx->engine = NULL;
-    }
-
-  _gpgme_release_result (ctx);
-
-  err = _gpgme_engine_new (ctx->use_cms ? GPGME_PROTOCOL_CMS
-                          : GPGME_PROTOCOL_OpenPGP, &ctx->engine);
+  err = _gpgme_op_reset (ctx, 0);
   if (err)
     goto leave;
 
-  _gpgme_engine_set_status_handler (ctx->engine, trustlist_status_handler, ctx);
   err = _gpgme_engine_set_colon_line_handler (ctx->engine,
                                              trustlist_colon_handler, ctx);
   if (err)
index d00800f..dc71dbd 100644 (file)
@@ -282,26 +282,18 @@ _gpgme_verify_status_handler (GpgmeCtx ctx, GpgStatusCode code, char *args)
     }
 }
 
-GpgmeError
-gpgme_op_verify_start (GpgmeCtx ctx, GpgmeData sig, GpgmeData text)
+static GpgmeError
+_gpgme_op_verify_start (GpgmeCtx ctx, int synchronous,
+                       GpgmeData sig, GpgmeData text)
 {
   int err = 0;
   int pipemode = 0;     /* !!text; use pipemode for detached sigs.  */
 
-  fail_on_pending_request (ctx);
-  ctx->pending = 1;
-
-  _gpgme_release_result (ctx);
-    
   if (!pipemode)
-    {
-      _gpgme_engine_release (ctx->engine);
-      ctx->engine = NULL;
-    }
+    ;  /* XXX I am not sure what should happen/not happen in
+          pipemode.  */
 
-  if (!ctx->engine)
-    err = _gpgme_engine_new (ctx->use_cms ? GPGME_PROTOCOL_CMS
-                            : GPGME_PROTOCOL_OpenPGP, &ctx->engine);
+  err = _gpgme_op_reset (ctx, synchronous);
   if (err)
     goto leave;
 
@@ -347,6 +339,12 @@ gpgme_op_verify_start (GpgmeCtx ctx, GpgmeData sig, GpgmeData text)
   return err;
 }
 
+GpgmeError
+gpgme_op_verify_start (GpgmeCtx ctx, GpgmeData sig, GpgmeData text)
+{
+  return _gpgme_op_verify_start (ctx, 0, sig, text);
+}
+
 /* 
  * Figure out a common status value for all signatures 
  */
@@ -408,10 +406,10 @@ gpgme_op_verify (GpgmeCtx ctx, GpgmeData sig, GpgmeData text,
   ctx->notation = NULL;
     
   *r_stat = GPGME_SIG_STAT_NONE;
-  err = gpgme_op_verify_start (ctx, sig, text);
+  err = _gpgme_op_verify_start (ctx, 1, sig, text);
   if (!err)
     {
-      gpgme_wait (ctx, &err, 1);
+      err = _gpgme_wait_one (ctx);
       if (!err)
        *r_stat = _gpgme_intersect_stati (ctx->result.verify);
     }
index 6292bde..9f849fd 100644 (file)
 #include "io.h"
 #include "engine.h"
 
-struct wait_item_s;
-struct proc_s;
+struct fd_table fdt_global;
 
-static struct proc_s *proc_queue;
-DEFINE_STATIC_LOCK (proc_queue_lock);
-
-static int fd_table_size;
-static struct io_select_fd_s *fd_table;
-DEFINE_STATIC_LOCK (fd_table_lock);
+static GpgmeCtx *ctx_done_list;
+static int ctx_done_list_size;
+static int ctx_done_list_length;
+DEFINE_STATIC_LOCK (ctx_done_list_lock);
 
 static GpgmeIdleFunc idle_function;
 
-
-struct proc_s
+struct wait_item_s
 {
-  struct proc_s *next;
-  int pid;
-  GpgmeCtx ctx;
-  struct wait_item_s *handler_list;
-  /* Non-zero if the process has been completed.  */
-  int done;
-  /* Non-zero if the status for this process has been returned
-     already.  */
-  int reported;
-};
-
-struct wait_item_s {
-    struct wait_item_s *next;
-    int (*handler)(void*,int,int);
-    void *handler_value;
-    int inbound;       /* this is an inbound data handler fd */
-    struct proc_s *proc; /* backlink */
-    int done;
-    int frozen; /* copy of the frozen flag from the fd_table */
+  struct wait_item_s *next;
+  GpgmeIOCb handler;
+  void *handler_value;
+  int dir;
 };
 
-
-
-static int do_select ( void );
 static void run_idle (void);
 
+\f
+void
+_gpgme_fd_table_init (fd_table_t fdt)
+{
+  INIT_LOCK (fdt->lock);
+  fdt->fds = NULL;
+  fdt->size = 0;
+}
 
-/* only to be called with a locked proc_queue */
-static int
-count_running_fds (struct proc_s *proc)
+void
+_gpgme_fd_table_deinit (fd_table_t fdt)
 {
-  struct wait_item_s *q;
-  int count = 0;
+  DESTROY_LOCK (fdt->lock);
+  if (fdt->fds)
+    xfree (fdt->fds);
+}
 
-  for (q = proc->handler_list; q; q=q->next)
+/* XXX We should keep a marker and roll over for speed.  */
+GpgmeError
+_gpgme_fd_table_put (fd_table_t fdt, int fd, int dir, void *opaque, int *idx)
+{
+  int i, j;
+  struct io_select_fd_s *new_fds;
+
+  LOCK (fdt->lock);
+  for (i = 0; i < fdt->size; i++)
+    {
+      if (fdt->fds[i].fd == -1)
+       break;
+    }
+  if (i == fdt->size)
     {
-      if (!q->frozen && !q->done)
-       count++;
+#define FDT_ALLOCSIZE 10
+      new_fds = xtryrealloc (fdt->fds, (fdt->size + FDT_ALLOCSIZE)
+                            * sizeof (*new_fds));
+      if (!new_fds)
+       {
+         UNLOCK (fdt->lock);
+         return mk_error (Out_Of_Core);
+       }
+      
+      fdt->fds = new_fds;
+      fdt->size += FDT_ALLOCSIZE;
+      for (j = 0; j < FDT_ALLOCSIZE; j++)
+       fdt->fds[i + j].fd = -1;
     }
-  return count;
+
+  fdt->fds[i].fd = fd;
+  fdt->fds[i].for_read = (dir == 1);
+  fdt->fds[i].for_write = (dir == 0);
+  fdt->fds[i].frozen = 0;
+  fdt->fds[i].signaled = 0;
+  fdt->fds[i].opaque = opaque;
+  UNLOCK (fdt->lock);
+  *idx = i;
+  return 0;
+}
+
+\f
+/**
+ * gpgme_register_idle:
+ * @fnc: Callers idle function
+ * 
+ * Register a function with GPGME called by GPGME whenever it feels
+ * that is is idle.  NULL may be used to remove this function.
+ *
+ * Return value: The idle function pointer that was passed to the
+ * function at the last time it was invoked, or NULL if the function
+ * is invoked the first time.
+ **/
+GpgmeIdleFunc
+gpgme_register_idle (GpgmeIdleFunc idle)
+{
+  GpgmeIdleFunc old_idle = idle_function;
+
+  idle_function = idle;
+  return old_idle;
 }
 
-/* only to be called with a locked proc_queue */
 static void
-set_process_done (struct proc_s *proc)
+run_idle ()
 {
-  struct wait_item_s *q, *q2;
-  int i;
+  _gpgme_engine_housecleaning ();
+  if (idle_function)
+    idle_function ();
+}
 
-  assert (proc);
-  DEBUG2 ("set_process_done(%p) pid=%d", proc, proc->pid);
-  LOCK (fd_table_lock);
-  for (q = proc->handler_list; q; q=q2)
+\f
+/* Wait on all file descriptors listed in FDT and process them using
+   the registered callbacks.  Returns 0 if nothing to run and 1 if it
+   did run something.  */
+static int
+do_select (fd_table_t fdt)
+{
+  int i, n;
+  int any = 0;
+
+  LOCK (fdt->lock);
+  n = _gpgme_io_select (fdt->fds, fdt->size);
+
+  if (n <= 0) 
     {
-      q2 = q->next;
-      for (i = 0; i < fd_table_size; i++)
+      UNLOCK (fdt->lock);
+      return 0;        /* Error or timeout.  */
+    }
+
+  for (i = 0; i < fdt->size && n; i++)
+    {
+      if (fdt->fds[i].fd != -1 && fdt->fds[i].signaled)
        {
-         if (fd_table[i].fd != -1 && q == fd_table[i].opaque)
-           {
-             fd_table[i].opaque = NULL;
-             fd_table[i].fd = -1;
-            }
+         struct wait_item_s *item;
+
+         assert (n);
+         n--;
+            
+         item = (struct wait_item_s *) fdt->fds[i].opaque;
+         assert (item);
+         any = 1;
+
+         fdt->fds[i].signaled = 0;
+         UNLOCK (fdt->lock);
+         item->handler (item->handler_value, fdt->fds[i].fd);
+         LOCK (fdt->lock);
         }
-      xfree (q);
     }
-  UNLOCK (fd_table_lock);
-  proc->handler_list = NULL;
-  proc->done = 1;
+  UNLOCK (fdt->lock);
+    
+  return any;
 }
 
+
+\f
 void
-_gpgme_remove_proc_from_wait_queue (int pid)
+_gpgme_wait_event_cb (void *data, GpgmeEventIO type, void *type_data)
 {
-    struct proc_s *proc, *last;
-
-    DEBUG1 ("removing process %d", pid);
-    LOCK (proc_queue_lock);
-    for (last = NULL, proc = proc_queue; proc; last = proc, proc = proc->next)
-      {
-        if (proc->pid == pid)
-         {
-            set_process_done (proc);
-            if (!last) 
-             proc_queue = proc->next;
-            else 
-             last->next = proc->next;
-            xfree (proc);
-            break;
-         }
-      }
-    UNLOCK (proc_queue_lock);
+  if (type != GPGME_EVENT_DONE)
+    return;
+
+  if (ctx_done_list_size == ctx_done_list_length)
+    {
+#define CTX_DONE_LIST_SIZE_INITIAL 8
+      int new_size = ctx_done_list_size ? 2 * ctx_done_list_size
+       : CTX_DONE_LIST_SIZE_INITIAL;
+      GpgmeCtx *new_list = xtryrealloc (ctx_done_list,
+                                       new_size * sizeof (GpgmeCtx *));
+      assert (new_list);
+#if 0
+      if (!new_list)
+       return mk_error (Out_Of_Core);
+#endif
+      ctx_done_list = new_list;
+      ctx_done_list_size = new_size;
+    }
+  ctx_done_list[ctx_done_list_length++] = (GpgmeCtx) data;
 }
 
 
@@ -155,65 +222,73 @@ _gpgme_remove_proc_from_wait_queue (int pid)
  * it will return immediately when there is no pending finished request.
  * 
  * Return value: Context of the finished request or NULL if @hang is false
- *  and no (or the given) request has finished.
+ *  and no (or not the given) request has finished.
  **/
 GpgmeCtx 
 gpgme_wait (GpgmeCtx ctx, GpgmeError *status, int hang)
 {
-  GpgmeCtx retctx = _gpgme_wait_on_condition (ctx, hang, NULL);
-  if (status)
-    *status = retctx->error;
-  return retctx;
+  ctx = _gpgme_wait_on_condition (ctx, hang, NULL);
+  if (ctx && status)
+    *status = ctx->error;
+  return ctx;
+}
+
+GpgmeError
+_gpgme_wait_one (GpgmeCtx ctx)
+{
+  int hang = 1;
+  DEBUG1 ("waiting... ctx=%p", ctx);
+  do
+    {
+      if (! do_select (&ctx->fdt))
+       hang = 0;
+    }
+  while (hang && !ctx->cancel);
+  if (ctx->cancel)
+    {
+      /* FIXME: Paranoia?  */
+      ctx->cancel = 0;
+      ctx->pending = 0;
+      ctx->error = mk_error (Canceled);
+    }
+  return ctx->error;
 }
 
+
 GpgmeCtx 
 _gpgme_wait_on_condition (GpgmeCtx ctx, int hang, volatile int *cond)
 {
   DEBUG3 ("waiting... ctx=%p hang=%d cond=%p", ctx, hang, cond);
   do
     {
-      int any = 0;
-      struct proc_s *proc;
-
-      do_select ();
+      if (! do_select (&fdt_global))
+       hang = 0;
 
       if (cond && *cond)
        hang = 0;
       else
        {
-         LOCK (proc_queue_lock);
-         for (proc = proc_queue; proc; proc = proc->next)
+         int i;
+
+         LOCK (ctx_done_list_lock);
+         /* A process that is done is eligible for election if it is
+            the requested context or if it was not yet reported.  */
+         for (i = 0; i < ctx_done_list_length; i++)
+           if (!ctx || ctx == ctx_done_list[i])
+             break;
+         if (i < ctx_done_list_length)
            {
-             /* A process is done if it has completed voluntarily, or
-                if the context it lived in was canceled.  */
-             if (!proc->done && !count_running_fds (proc))
-               set_process_done (proc);
-             else if (!proc->done && proc->ctx->cancel)
-               {
-                 set_process_done (proc);
-                 proc->ctx->cancel = 0;
-                 proc->ctx->error = mk_error (Canceled);
-               }
-             /* A process that is done is eligible for election if it
-                is in the requested context or if it was not yet
-                reported.  */
-             if (proc->done && (proc->ctx == ctx || (!ctx && !proc->reported)))
-               {
-                 if (!ctx)
-                   ctx = proc->ctx;
-                 hang = 0;
-                 ctx->pending = 0;
-                 proc->reported = 1;
-               }
-             if (!proc->done)
-               any = 1;
-            }
-         UNLOCK (proc_queue_lock);
-         if (!any)
-           hang = 0;
+             if (!ctx)
+               ctx = ctx_done_list[i];
+             hang = 0;
+             ctx->pending = 0;
+             if (--ctx_done_list_length)
+               memcpy (&ctx_done_list[i],
+                       &ctx_done_list[i + 1],
+                       (ctx_done_list_length - i) * sizeof (GpgmeCtx *));
+           }
+         UNLOCK (ctx_done_list_lock);
         }
-      /* fixme: We should check here for hanging processes.  */
-
       if (hang)
        run_idle ();
     }
@@ -228,221 +303,70 @@ _gpgme_wait_on_condition (GpgmeCtx ctx, int hang, volatile int *cond)
   return ctx;
 }
 
-
-/*
- * We use this function to do the select stuff for all running
- * gpgs.  A future version might provide a facility to delegate
- * those selects to the GDK select stuff.
- * This function must be called only by one thread!!
- * Returns: 0 = nothing to run
- *          1 = did run something 
- */
-
-static int
-do_select (void)
+\f
+struct tag
 {
-  int i, n;
-  int any = 0;
-    
-  n = _gpgme_io_select (fd_table, fd_table_size);
-  if (n <= 0) 
-    return 0; /* error or timeout */
-
-  for (i = 0; i < fd_table_size && n; i++)
-    {
-      if (fd_table[i].fd != -1 && fd_table[i].signaled 
-         && !fd_table[i].frozen)
-       {
-         struct wait_item_s *q;
-
-         assert (n);
-         n--;
-            
-         q = fd_table[i].opaque;
-         assert (q);
-         assert (q->proc);
-         assert (!q->done);
-         any = 1;
-         if (q->handler (q->handler_value,
-                         q->proc->pid, fd_table[i].fd))
-           {
-             DEBUG2 ("setting fd %d (q=%p) done", fd_table[i].fd, q);
-             q->done = 1;
-             /* Free the table entry.  */
-             LOCK (fd_table_lock);
-             fd_table[i].for_read = 0;
-             fd_table[i].for_write = 0;
-             fd_table[i].fd = -1;
-             fd_table[i].opaque = NULL;
-             UNLOCK (fd_table_lock);
-            }
-        }
-    }
-    
-  return any;
-}
-
+  fd_table_t fdt;
+  int idx;
+};
 
-/* 
- * called by rungpg.c to register something for select()
- */
-GpgmeError
-_gpgme_register_pipe_handler (void *opaque, 
-                              int (*handler)(void*,int,int),
-                              void *handler_value,
-                              int pid, int fd, int inbound)
+void *
+_gpgme_add_io_cb (void *data, int fd, int dir,
+                 GpgmeIOCb fnc, void *fnc_data)
 {
-  GpgmeCtx ctx = opaque;
-  struct wait_item_s *q;
-  struct proc_s *proc;
-  int i;
+  GpgmeError err;
+  fd_table_t fdt = (fd_table_t) (data ? data : &fdt_global);
+  struct wait_item_s *item;
+  struct tag *tag;
 
-  assert (opaque);
-  assert (handler);
+  assert (fdt);
+  assert (fnc);
+
+  tag = xtrymalloc (sizeof *tag);
+  if (!tag)
+    return NULL;
+  tag->fdt = fdt;
 
   /* Allocate a structure to hold info about the handler.  */
-  q = xtrycalloc (1, sizeof *q);
-  if (!q)
-    return mk_error (Out_Of_Core);
-  q->inbound = inbound;
-  q->handler = handler;
-  q->handler_value = handler_value;
-
-  /* Put this into the process queue.  */
-  LOCK (proc_queue_lock);
-  for (proc = proc_queue; proc && proc->pid != pid; proc = proc->next)
-    ;
-  if (!proc)
-    {
-      /* A new process.  */
-      proc = xtrycalloc (1, sizeof *proc);
-      if (!proc)
-       {
-         UNLOCK (proc_queue_lock);
-         return mk_error (Out_Of_Core);
-        }
-      proc->pid = pid;
-      proc->ctx = ctx;
-      proc->next = proc_queue;
-      proc_queue = proc;
-    }
-  assert (proc->ctx == ctx);
-  q->proc = proc;
-  q->next = proc->handler_list;
-  proc->handler_list = q;
-  UNLOCK (proc_queue_lock);
-    
-  LOCK (fd_table_lock);
- again:  
-  for (i=0; i < fd_table_size; i++)
+  item = xtrycalloc (1, sizeof *item);
+  if (!item)
     {
-      if (fd_table[i].fd == -1)
-       {
-         fd_table[i].fd = fd;
-         fd_table[i].for_read = inbound;    
-         fd_table[i].for_write = !inbound;    
-         fd_table[i].signaled = 0;
-         fd_table[i].frozen = 0;
-         fd_table[i].opaque = q;
-         UNLOCK (fd_table_lock);
-         return 0;
-        }
+      xfree (tag);
+      return NULL;
     }
-  if ( fd_table_size < 50 ) {
-    /* FIXME: We have to wait until there are no other readers of the 
-     * table, i.e that the io_select is not active in another thread */
-    struct io_select_fd_s *tmp;
-    
-    tmp = xtryrealloc (fd_table, (fd_table_size + 10) * sizeof *tmp);
-    if (tmp)
-      {
-       for (i = 0; i < 10; i++)
-         tmp[fd_table_size+i].fd = -1;
-       fd_table_size += i;
-       fd_table = tmp;
-       goto again;
-      }
-  }
-
-  UNLOCK (fd_table_lock);
-  xfree (q);
-  /* FIXME: Remove the proc table entry.  */
-  return mk_error (Too_Many_Procs);
-}
-
-
-void
-_gpgme_freeze_fd (int fd)
-{
-  int i;
+  item->dir = dir;
+  item->handler = fnc;
+  item->handler_value = fnc_data;
 
-  LOCK (fd_table_lock);
-  for (i = 0; i < fd_table_size; i++)
+  err = _gpgme_fd_table_put (fdt, fd, dir, item, &tag->idx);
+  if (err)
     {
-      if (fd_table[i].fd == fd)
-       {
-         struct wait_item_s *q;
-
-         fd_table[i].frozen = 1;
-         q = fd_table[i].opaque;
-         if (q)
-           q->frozen = 1;
-         DEBUG2 ("fd %d frozen (q=%p)", fd, q);
-         break;
-        }
+      xfree (tag);
+      xfree (item);
+      errno = ENOMEM;
+      return 0;
     }
-  UNLOCK (fd_table_lock);
+  
+  return tag;
 }
 
 void
-_gpgme_thaw_fd (int fd)
+_gpgme_remove_io_cb (void *data)
 {
-  int i;
-
-  LOCK (fd_table_lock);
-  for (i = 0; i < fd_table_size; i++)
-    {
-      if (fd_table[i].fd == fd)
-       {
-         struct wait_item_s *q;
-
-         fd_table[i].frozen = 0;
-         q = fd_table[i].opaque;
-         if (q)
-           q->frozen = 0;
-         DEBUG2 ("fd %d thawed (q=%p)", fd, q);
-         break;
-        }
-    }
-  UNLOCK (fd_table_lock);
+  struct tag *tag = data;
+  fd_table_t fdt = tag->fdt;
+  int idx = tag->idx;
+
+  LOCK (fdt->lock);
+  DEBUG2 ("setting fd %d (item=%p) done", fdt->fds[idx].fd,
+         fdt->fds[idx].opaque);
+  xfree (fdt->fds[idx].opaque);
+  xfree (tag);
+
+  /* Free the table entry.  */
+  fdt->fds[idx].fd = -1;
+  fdt->fds[idx].for_read = 0;
+  fdt->fds[idx].for_write = 0;
+  fdt->fds[idx].opaque = NULL;
 }
 
-
-/**
- * gpgme_register_idle:
- * @fnc: Callers idle function
- * 
- * Register a function with GPGME called by GPGME whenever it feels
- * that is is idle.  NULL may be used to remove this function.
- *
- * Return value: The idle function pointer that was passed to the
- * function at the last time it was invoked, or NULL if the function
- * is invoked the first time.
- **/
-GpgmeIdleFunc
-gpgme_register_idle (GpgmeIdleFunc idle)
-{
-  GpgmeIdleFunc old_idle = idle_function;
-
-  idle_function = idle;
-  return old_idle;
-}
-
-
-static void
-run_idle ()
-{
-  _gpgme_engine_housecleaning ();
-  if (idle_function)
-    idle_function ();
-}
index 49737d6..b782876 100644 (file)
 #define WAIT_H
 
 #include "gpgme.h"
+#include "sema.h"
 
-void _gpgme_remove_proc_from_wait_queue (int pid);
+struct fd_table
+{
+  DECLARE_LOCK (lock);
+  struct io_select_fd_s *fds;
+  size_t size;
+};
+typedef struct fd_table *fd_table_t;
 
-GpgmeError _gpgme_register_pipe_handler (void *opaque,
-                                        int (*handler) (void*, int, int),
-                                        void *handler_value,
-                                        int pid, int fd, int inbound);
+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);
+void _gpgme_remove_io_cb (void *tag);
+void _gpgme_wait_event_cb (void *data, GpgmeEventIO type, void *type_data);
+
+GpgmeError _gpgme_wait_one (GpgmeCtx ctx);
 
 #endif /* WAIT_H */