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.
This commit is contained in:
Marcus Brinkmann 2002-06-10 14:13:55 +00:00
parent 7b8ab474d3
commit 5b75138331
29 changed files with 1767 additions and 1299 deletions

View 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> 2002-06-04 Marcus Brinkmann <marcus@g10code.de>
* Makefile.am (libgpgme_la_SOURCES): Remove mutex.h. * Makefile.am (libgpgme_la_SOURCES): Remove mutex.h.

View File

@ -59,6 +59,7 @@ libgpgme_la_SOURCES = \
context.h ops.h \ context.h ops.h \
data.c recipient.c signers.c \ data.c recipient.c signers.c \
wait.c wait.h \ wait.c wait.h \
op-support.c \
encrypt.c \ encrypt.c \
encrypt-sign.c \ encrypt-sign.c \
decrypt.c \ decrypt.c \

View File

@ -25,12 +25,16 @@
#include "gpgme.h" #include "gpgme.h"
#include "types.h" #include "types.h"
#include "engine.h" #include "engine.h"
#include "wait.h"
struct key_queue_item_s { struct key_queue_item_s
{
struct key_queue_item_s *next; struct key_queue_item_s *next;
GpgmeKey key; GpgmeKey key;
}; };
struct trust_queue_item_s {
struct trust_queue_item_s
{
struct trust_queue_item_s *next; struct trust_queue_item_s *next;
GpgmeTrustItem item; GpgmeTrustItem item;
}; };
@ -98,6 +102,11 @@ struct gpgme_context_s
GpgmeProgressCb progress_cb; GpgmeProgressCb progress_cb;
void *progress_cb_value; 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; GpgmeData help_data_1;
}; };

View File

@ -874,8 +874,8 @@ _gpgme_data_append_percentstring_for_xml (GpgmeData dh, const char *string)
/* Functions to support the wait interface. */ /* Functions to support the wait interface. */
int void
_gpgme_data_inbound_handler (void *opaque, int pid, int fd) _gpgme_data_inbound_handler (void *opaque, int fd)
{ {
GpgmeData dh = opaque; GpgmeData dh = opaque;
GpgmeError err; 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", DEBUG3 ("read_mem_data: read failed on fd %d (n=%d): %s",
fd, nread, strerror (errno) ); fd, nread, strerror (errno) );
return 1; _gpgme_io_close (fd); /* XXX ??? */
return;
} }
else if (!nread) else if (!nread)
return 1; /* eof */ {
_gpgme_io_close (fd);
return; /* eof */
}
/* We could improve this with a GpgmeData function which takes /* We could improve this with a GpgmeData function which takes
* the read function or provides a memory area for writing to it. * 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)); gpgme_strerror(err));
/* Fixme: we should close the pipe or read it to /dev/null in /* Fixme: we should close the pipe or read it to /dev/null in
* this case. Returnin EOF is not sufficient */ * this case. Returnin EOF is not sufficient */
return 1; _gpgme_io_close (fd); /* XXX ??? */
return;
} }
return 0; return;
} }
static int static int
@ -920,7 +924,6 @@ write_mem_data (GpgmeData dh, int fd)
nbytes = dh->len - dh->readpos; nbytes = dh->len - dh->readpos;
if (!nbytes) if (!nbytes)
{ {
_gpgme_io_close (fd);
return 1; return 1;
} }
@ -938,7 +941,6 @@ write_mem_data (GpgmeData dh, int fd)
{ {
DEBUG3 ("write_mem_data(%d): write failed (n=%d): %s", DEBUG3 ("write_mem_data(%d): write failed (n=%d): %s",
fd, nwritten, strerror (errno)); fd, nwritten, strerror (errno));
_gpgme_io_close (fd);
return 1; return 1;
} }
@ -956,7 +958,6 @@ write_cb_data (GpgmeData dh, int fd)
err = gpgme_data_read (dh, buffer, DIM(buffer), &nbytes); err = gpgme_data_read (dh, buffer, DIM(buffer), &nbytes);
if (err == GPGME_EOF) if (err == GPGME_EOF)
{ {
_gpgme_io_close (fd);
return 1; return 1;
} }
@ -967,7 +968,6 @@ write_cb_data (GpgmeData dh, int fd)
{ {
DEBUG3 ("write_cb_data(%d): write failed (n=%d): %s", DEBUG3 ("write_cb_data(%d): write failed (n=%d): %s",
fd, nwritten, strerror (errno)); fd, nwritten, strerror (errno));
_gpgme_io_close (fd);
return 1; return 1;
} }
@ -977,15 +977,14 @@ write_cb_data (GpgmeData dh, int fd)
if (_gpgme_data_unread (dh, buffer + nwritten, nbytes - nwritten)) if (_gpgme_data_unread (dh, buffer + nwritten, nbytes - nwritten))
DEBUG1 ("wite_cb_data: unread of %d bytes failed\n", DEBUG1 ("wite_cb_data: unread of %d bytes failed\n",
nbytes - nwritten); nbytes - nwritten);
_gpgme_io_close (fd);
return 1; return 1;
} }
return 0; return 0;
} }
int void
_gpgme_data_outbound_handler (void *opaque, int pid, int fd) _gpgme_data_outbound_handler (void *opaque, int fd)
{ {
GpgmeData dh = opaque; GpgmeData dh = opaque;
@ -994,15 +993,13 @@ _gpgme_data_outbound_handler (void *opaque, int pid, int fd)
{ {
case GPGME_DATA_TYPE_MEM: case GPGME_DATA_TYPE_MEM:
if (write_mem_data (dh, fd)) if (write_mem_data (dh, fd))
return 1; /* ready */ _gpgme_io_close (fd);
break; break;
case GPGME_DATA_TYPE_CB: case GPGME_DATA_TYPE_CB:
if (write_cb_data (dh, fd)) if (write_cb_data (dh, fd))
return 1; /* ready */ _gpgme_io_close (fd);
break; break;
default: default:
assert (0); assert (0);
} }
return 0;
} }

View File

@ -41,7 +41,7 @@ decrypt_verify_status_handler (GpgmeCtx ctx, GpgStatusCode code, char *args)
GpgmeError GpgmeError
gpgme_op_decrypt_verify_start (GpgmeCtx ctx, GpgmeData ciph, GpgmeData plain) 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); decrypt_verify_status_handler);
} }
@ -69,10 +69,11 @@ gpgme_op_decrypt_verify (GpgmeCtx ctx,
ctx->notation = NULL; ctx->notation = NULL;
*r_stat = GPGME_SIG_STAT_NONE; *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) if (!err)
{ {
gpgme_wait (ctx, &err, 1); err = _gpgme_wait_one (ctx);
if (!err) if (!err)
*r_stat = _gpgme_intersect_stati (ctx->result.verify); *r_stat = _gpgme_intersect_stati (ctx->result.verify);
} }

View File

@ -80,20 +80,12 @@ _gpgme_decrypt_status_handler (GpgmeCtx ctx, GpgStatusCode code, char *args)
GpgmeError GpgmeError
_gpgme_decrypt_start (GpgmeCtx ctx, GpgmeData ciph, GpgmeData plain, _gpgme_decrypt_start (GpgmeCtx ctx, int synchronous,
void *status_handler) GpgmeData ciph, GpgmeData plain, void *status_handler)
{ {
GpgmeError err = 0; GpgmeError err = 0;
fail_on_pending_request (ctx); err = _gpgme_op_reset (ctx, synchronous);
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);
if (err) if (err)
goto leave; goto leave;
@ -138,7 +130,7 @@ _gpgme_decrypt_start (GpgmeCtx ctx, GpgmeData ciph, GpgmeData plain,
GpgmeError GpgmeError
gpgme_op_decrypt_start (GpgmeCtx ctx, GpgmeData ciph, GpgmeData plain) 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); _gpgme_decrypt_status_handler);
} }
@ -158,8 +150,9 @@ gpgme_op_decrypt_start (GpgmeCtx ctx, GpgmeData ciph, GpgmeData plain)
GpgmeError GpgmeError
gpgme_op_decrypt (GpgmeCtx ctx, GpgmeData in, GpgmeData out) 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) if (!err)
gpgme_wait (ctx, &err, 1); err = _gpgme_wait_one (ctx);
return err; return err;
} }

View File

@ -91,30 +91,13 @@ delete_status_handler (GpgmeCtx ctx, GpgStatusCode code, char *args)
} }
GpgmeError static GpgmeError
gpgme_op_delete_start (GpgmeCtx ctx, const GpgmeKey key, int allow_secret) _gpgme_op_delete_start (GpgmeCtx ctx, int synchronous,
const GpgmeKey key, int allow_secret)
{ {
GpgmeError err = 0; GpgmeError err = 0;
fail_on_pending_request (ctx); err = _gpgme_op_reset (ctx, synchronous);
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);
if (err) if (err)
goto leave; goto leave;
@ -135,6 +118,12 @@ gpgme_op_delete_start (GpgmeCtx ctx, const GpgmeKey key, int allow_secret)
return err; 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: * gpgme_op_delete:
@ -150,8 +139,8 @@ gpgme_op_delete_start (GpgmeCtx ctx, const GpgmeKey key, int allow_secret)
GpgmeError GpgmeError
gpgme_op_delete (GpgmeCtx ctx, const GpgmeKey key, int allow_secret) 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) if (!err)
gpgme_wait (ctx, &err, 1); err = _gpgme_wait_one (ctx);
return err; return err;
} }

View File

@ -50,30 +50,14 @@ encrypt_sign_status_handler (GpgmeCtx ctx, GpgStatusCode code, char *args)
} }
GpgmeError static GpgmeError
gpgme_op_encrypt_sign_start (GpgmeCtx ctx, GpgmeRecipients recp, _gpgme_op_encrypt_sign_start (GpgmeCtx ctx, int synchronous,
GpgmeRecipients recp,
GpgmeData plain, GpgmeData cipher) GpgmeData plain, GpgmeData cipher)
{ {
int err = 0; GpgmeError err = 0;
fail_on_pending_request (ctx); err = _gpgme_op_reset (ctx, synchronous);
ctx->pending = 1;
_gpgme_release_result (ctx);
/* 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);
if (err) if (err)
goto leave; goto leave;
@ -115,6 +99,13 @@ gpgme_op_encrypt_sign_start (GpgmeCtx ctx, GpgmeRecipients recp,
return err; 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: * gpgme_op_encrypt_sign:
@ -133,11 +124,11 @@ GpgmeError
gpgme_op_encrypt_sign (GpgmeCtx ctx, GpgmeRecipients recp, gpgme_op_encrypt_sign (GpgmeCtx ctx, GpgmeRecipients recp,
GpgmeData plain, GpgmeData cipher) 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) if (!err)
{ {
gpgme_wait (ctx, &err, 1); err = _gpgme_wait_one (ctx);
/* Old gpg versions don't return status info for invalid /* Old gpg versions don't return status info for invalid
recipients, so we simply check whether we got any output at recipients, so we simply check whether we got any output at
all, and if not we assume that we don't have valid all, and if not we assume that we don't have valid

View File

@ -28,6 +28,7 @@
#include "util.h" #include "util.h"
#include "context.h" #include "context.h"
#include "ops.h" #include "ops.h"
#include "wait.h"
#define SKIP_TOKEN_OR_RETURN(a) do { \ #define SKIP_TOKEN_OR_RETURN(a) do { \
while (*(a) && *(a) != ' ') (a)++; \ while (*(a) && *(a) != ' ') (a)++; \
@ -142,18 +143,13 @@ _gpgme_encrypt_sym_status_handler (GpgmeCtx ctx, GpgStatusCode code, char *args)
} }
GpgmeError static GpgmeError
gpgme_op_encrypt_start (GpgmeCtx ctx, GpgmeRecipients recp, GpgmeData plain, _gpgme_op_encrypt_start (GpgmeCtx ctx, int synchronous,
GpgmeData ciph) GpgmeRecipients recp, GpgmeData plain, GpgmeData ciph)
{ {
int err = 0; GpgmeError err = 0;
int symmetric = 0; int symmetric = 0;
fail_on_pending_request (ctx);
ctx->pending = 1;
_gpgme_release_result (ctx);
/* Do some checks. */ /* Do some checks. */
if (!recp) if (!recp)
symmetric = 1; symmetric = 1;
@ -163,11 +159,7 @@ gpgme_op_encrypt_start (GpgmeCtx ctx, GpgmeRecipients recp, GpgmeData plain,
goto leave; goto leave;
} }
/* Create an engine object. */ err = _gpgme_op_reset (ctx, synchronous);
_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) if (err)
goto leave; 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: * gpgme_op_encrypt:
* @c: The context * @c: The context
@ -233,10 +233,10 @@ GpgmeError
gpgme_op_encrypt (GpgmeCtx ctx, GpgmeRecipients recp, gpgme_op_encrypt (GpgmeCtx ctx, GpgmeRecipients recp,
GpgmeData plain, GpgmeData cipher) 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) if (!err)
{ {
gpgme_wait (ctx, &err, 1); err = _gpgme_wait_one (ctx);
/* Old gpg versions don't return status info for invalid /* Old gpg versions don't return status info for invalid
recipients, so we simply check whether we got any output at recipients, so we simply check whether we got any output at
all, and if not we assume that we don't have valid all, and if not we assume that we don't have valid

View File

@ -59,20 +59,30 @@
#define xtoi_2(p) ((xtoi_1(p) * 16) + xtoi_1((p)+1)) #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 struct gpgsm_object_s
{ {
ASSUAN_CONTEXT assuan_ctx; ASSUAN_CONTEXT assuan_ctx;
iocb_data_t status_cb;
/* Input, output etc are from the servers perspective. */ /* Input, output etc are from the servers perspective. */
int input_fd; iocb_data_t input_cb;
int input_fd_server; int input_fd_server;
GpgmeData input_data;
int output_fd; iocb_data_t output_cb;
int output_fd_server; int output_fd_server;
GpgmeData output_data;
int message_fd; iocb_data_t message_cb;
int message_fd_server; int message_fd_server;
GpgmeData message_data;
char *command; char *command;
@ -93,6 +103,8 @@ struct gpgsm_object_s
int linelen; int linelen;
} attic; } attic;
} colon; } colon;
struct GpgmeIOCbs io_cbs;
}; };
@ -124,14 +136,49 @@ static void
close_notify_handler (int fd, void *opaque) close_notify_handler (int fd, void *opaque)
{ {
GpgsmObject gpgsm = opaque; GpgsmObject gpgsm = opaque;
int possibly_done = 0;
assert (fd != -1); assert (fd != -1);
if (gpgsm->input_fd == fd) if (gpgsm->status_cb.fd == fd)
gpgsm->input_fd = -1; {
else if (gpgsm->output_fd == fd) if (gpgsm->status_cb.tag)
gpgsm->output_fd = -1; {
else if (gpgsm->message_fd == fd) (*gpgsm->io_cbs.remove) (gpgsm->status_cb.tag);
gpgsm->message_fd = -1; 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 *old_lc = NULL;
char *dft_lc = NULL; char *dft_lc = NULL;
char *optstr; char *optstr;
int fdlist[5];
int nfds;
*r_gpgsm = NULL; *r_gpgsm = NULL;
gpgsm = xtrycalloc (1, sizeof *gpgsm); gpgsm = xtrycalloc (1, sizeof *gpgsm);
@ -257,11 +306,17 @@ _gpgme_gpgsm_new (GpgsmObject *r_gpgsm)
return err; 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->input_fd_server = -1;
gpgsm->output_fd = -1; gpgsm->output_cb.fd = -1;
gpgsm->output_cb.tag = 0;
gpgsm->output_fd_server = -1; 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->message_fd_server = -1;
gpgsm->status.fnc = 0; gpgsm->status.fnc = 0;
@ -270,12 +325,19 @@ _gpgme_gpgsm_new (GpgsmObject *r_gpgsm)
gpgsm->colon.attic.linesize = 0; gpgsm->colon.attic.linesize = 0;
gpgsm->colon.attic.linelen = 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) if (_gpgme_io_pipe (fds, 0) < 0)
{ {
err = mk_error (Pipe_Error); err = mk_error (Pipe_Error);
goto leave; goto leave;
} }
gpgsm->input_fd = fds[1]; gpgsm->input_cb.fd = fds[1];
gpgsm->input_cb.dir = 0;
gpgsm->input_fd_server = fds[0]; gpgsm->input_fd_server = fds[0];
if (_gpgme_io_pipe (fds, 1) < 0) if (_gpgme_io_pipe (fds, 1) < 0)
@ -283,7 +345,8 @@ _gpgme_gpgsm_new (GpgsmObject *r_gpgsm)
err = mk_error (Pipe_Error); err = mk_error (Pipe_Error);
goto leave; goto leave;
} }
gpgsm->output_fd = fds[0]; gpgsm->output_cb.fd = fds[0];
gpgsm->output_cb.dir = 1;
gpgsm->output_fd_server = fds[1]; gpgsm->output_fd_server = fds[1];
if (_gpgme_io_pipe (fds, 0) < 0) if (_gpgme_io_pipe (fds, 0) < 0)
@ -291,7 +354,8 @@ _gpgme_gpgsm_new (GpgsmObject *r_gpgsm)
err = mk_error (Pipe_Error); err = mk_error (Pipe_Error);
goto leave; goto leave;
} }
gpgsm->message_fd = fds[1]; gpgsm->message_cb.fd = fds[1];
gpgsm->message_cb.dir = 0;
gpgsm->message_fd_server = fds[0]; gpgsm->message_fd_server = fds[0];
child_fds[0] = gpgsm->input_fd_server; child_fds[0] = gpgsm->input_fd_server;
@ -307,6 +371,20 @@ _gpgme_gpgsm_new (GpgsmObject *r_gpgsm)
_gpgme_get_gpgsm_path (), argv, child_fds, _gpgme_get_gpgsm_path (), argv, child_fds,
1 /* dup stderr to /dev/null */); 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"); dft_display = getenv ("DISPLAY");
if (dft_display) if (dft_display)
{ {
@ -315,8 +393,8 @@ _gpgme_gpgsm_new (GpgsmObject *r_gpgsm)
err = mk_error (Out_Of_Core); err = mk_error (Out_Of_Core);
goto leave; goto leave;
} }
err = assuan_transact (gpgsm->assuan_ctx, optstr, NULL, NULL, NULL, NULL, NULL, err = assuan_transact (gpgsm->assuan_ctx, optstr, NULL, NULL, NULL,
NULL); NULL, NULL, NULL);
free (optstr); free (optstr);
if (err) if (err)
{ {
@ -400,11 +478,13 @@ _gpgme_gpgsm_new (GpgsmObject *r_gpgsm)
} }
if (!err && if (!err &&
(_gpgme_io_set_close_notify (gpgsm->input_fd, (_gpgme_io_set_close_notify (gpgsm->status_cb.fd,
close_notify_handler, gpgsm) 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) close_notify_handler, gpgsm)
|| _gpgme_io_set_close_notify (gpgsm->message_fd, || _gpgme_io_set_close_notify (gpgsm->output_cb.fd,
close_notify_handler, gpgsm)
|| _gpgme_io_set_close_notify (gpgsm->message_cb.fd,
close_notify_handler, gpgsm))) close_notify_handler, gpgsm)))
{ {
err = mk_error (General_Error); err = mk_error (General_Error);
@ -433,21 +513,15 @@ _gpgme_gpgsm_new (GpgsmObject *r_gpgsm)
void void
_gpgme_gpgsm_release (GpgsmObject gpgsm) _gpgme_gpgsm_release (GpgsmObject gpgsm)
{ {
pid_t pid;
if (!gpgsm) if (!gpgsm)
return; return;
pid = assuan_get_pid (gpgsm->assuan_ctx); if (gpgsm->input_cb.fd != -1)
if (pid != -1) _gpgme_io_close (gpgsm->input_cb.fd);
_gpgme_remove_proc_from_wait_queue (pid); if (gpgsm->output_cb.fd != -1)
_gpgme_io_close (gpgsm->output_cb.fd);
if (gpgsm->input_fd != -1) if (gpgsm->message_cb.fd != -1)
_gpgme_io_close (gpgsm->input_fd); _gpgme_io_close (gpgsm->message_cb.fd);
if (gpgsm->output_fd != -1)
_gpgme_io_close (gpgsm->output_fd);
if (gpgsm->message_fd != -1)
_gpgme_io_close (gpgsm->message_fd);
assuan_disconnect (gpgsm->assuan_ctx); assuan_disconnect (gpgsm->assuan_ctx);
@ -512,12 +586,17 @@ map_input_enc (GpgmeData d)
{ {
switch (gpgme_data_get_encoding (d)) switch (gpgme_data_get_encoding (d))
{ {
case GPGME_DATA_ENCODING_NONE: break; case GPGME_DATA_ENCODING_NONE:
case GPGME_DATA_ENCODING_BINARY: return "--binary"; break;
case GPGME_DATA_ENCODING_BASE64: return "--base64"; case GPGME_DATA_ENCODING_BINARY:
case GPGME_DATA_ENCODING_ARMOR: return "--armor"; return "--binary";
case GPGME_DATA_ENCODING_BASE64:
return "--base64";
case GPGME_DATA_ENCODING_ARMOR:
return "--armor";
default:
break;
} }
return NULL; return NULL;
} }
@ -534,16 +613,16 @@ _gpgme_gpgsm_op_decrypt (GpgsmObject gpgsm, GpgmeData ciph, GpgmeData plain)
if (!gpgsm->command) if (!gpgsm->command)
return mk_error (Out_Of_Core); 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, 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) if (err)
return mk_error (General_Error); /* FIXME */ 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); err = gpgsm_set_fd (gpgsm->assuan_ctx, "OUTPUT", gpgsm->output_fd_server, 0);
if (err) if (err)
return mk_error (General_Error); /* FIXME */ return mk_error (General_Error); /* FIXME */
_gpgme_io_close (gpgsm->message_fd); _gpgme_io_close (gpgsm->message_cb.fd);
return 0; return 0;
} }
@ -626,17 +705,17 @@ _gpgme_gpgsm_op_encrypt (GpgsmObject gpgsm, GpgmeRecipients recp,
if (!gpgsm->command) if (!gpgsm->command)
return mk_error (Out_Of_Core); 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, 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) if (err)
return err; return err;
gpgsm->output_data = ciph; gpgsm->output_cb.data = ciph;
err = gpgsm_set_fd (gpgsm->assuan_ctx, "OUTPUT", gpgsm->output_fd_server, err = gpgsm_set_fd (gpgsm->assuan_ctx, "OUTPUT", gpgsm->output_fd_server,
use_armor ? "--armor" : 0); use_armor ? "--armor" : 0);
if (err) if (err)
return err; return err;
_gpgme_io_close (gpgsm->message_fd); _gpgme_io_close (gpgsm->message_cb.fd);
err = gpgsm_set_recipients (gpgsm, recp); err = gpgsm_set_recipients (gpgsm, recp);
if (err) if (err)
@ -668,17 +747,17 @@ _gpgme_gpgsm_op_genkey (GpgsmObject gpgsm, GpgmeData help_data, int use_armor,
if (!gpgsm->command) if (!gpgsm->command)
return mk_error (Out_Of_Core); 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, 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) if (err)
return err; return err;
gpgsm->output_data = pubkey; gpgsm->output_cb.data = pubkey;
err = gpgsm_set_fd (gpgsm->assuan_ctx, "OUTPUT", gpgsm->output_fd_server, err = gpgsm_set_fd (gpgsm->assuan_ctx, "OUTPUT", gpgsm->output_fd_server,
use_armor ? "--armor" : 0); use_armor ? "--armor" : 0);
if (err) if (err)
return err; return err;
_gpgme_io_close (gpgsm->message_fd); _gpgme_io_close (gpgsm->message_cb.fd);
return 0; return 0;
} }
@ -696,13 +775,13 @@ _gpgme_gpgsm_op_import (GpgsmObject gpgsm, GpgmeData keydata)
if (!gpgsm->command) if (!gpgsm->command)
return mk_error (Out_Of_Core); 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, 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) if (err)
return err; return err;
_gpgme_io_close (gpgsm->output_fd); _gpgme_io_close (gpgsm->output_cb.fd);
_gpgme_io_close (gpgsm->message_fd); _gpgme_io_close (gpgsm->message_cb.fd);
return 0; return 0;
} }
@ -740,9 +819,9 @@ _gpgme_gpgsm_op_keylist (GpgsmObject gpgsm, const char *pattern,
strcpy (&line[9], pattern); strcpy (&line[9], pattern);
} }
_gpgme_io_close (gpgsm->input_fd); _gpgme_io_close (gpgsm->input_cb.fd);
_gpgme_io_close (gpgsm->output_fd); _gpgme_io_close (gpgsm->output_cb.fd);
_gpgme_io_close (gpgsm->message_fd); _gpgme_io_close (gpgsm->message_cb.fd);
gpgsm->command = line; gpgsm->command = line;
return 0; return 0;
@ -839,9 +918,9 @@ _gpgme_gpgsm_op_keylist_ext (GpgsmObject gpgsm, const char *pattern[],
} }
*linep = '\0'; *linep = '\0';
_gpgme_io_close (gpgsm->input_fd); _gpgme_io_close (gpgsm->input_cb.fd);
_gpgme_io_close (gpgsm->output_fd); _gpgme_io_close (gpgsm->output_cb.fd);
_gpgme_io_close (gpgsm->message_fd); _gpgme_io_close (gpgsm->message_cb.fd);
gpgsm->command = line; gpgsm->command = line;
return 0; return 0;
@ -872,17 +951,17 @@ _gpgme_gpgsm_op_sign (GpgsmObject gpgsm, GpgmeData in, GpgmeData out,
if (err) if (err)
return err; return err;
gpgsm->input_data = in; gpgsm->input_cb.data = in;
err = gpgsm_set_fd (gpgsm->assuan_ctx, "INPUT", gpgsm->input_fd_server, 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) if (err)
return err; return err;
gpgsm->output_data = out; gpgsm->output_cb.data = out;
err = gpgsm_set_fd (gpgsm->assuan_ctx, "OUTPUT", gpgsm->output_fd_server, err = gpgsm_set_fd (gpgsm->assuan_ctx, "OUTPUT", gpgsm->output_fd_server,
use_armor ? "--armor" : 0); use_armor ? "--armor" : 0);
if (err) if (err)
return err; return err;
_gpgme_io_close (gpgsm->message_fd); _gpgme_io_close (gpgsm->message_cb.fd);
return 0; return 0;
} }
@ -908,26 +987,26 @@ _gpgme_gpgsm_op_verify (GpgsmObject gpgsm, GpgmeData sig, GpgmeData text)
if (!gpgsm->command) if (!gpgsm->command)
return mk_error (Out_Of_Core); 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, 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) if (err)
return err; return err;
if (_gpgme_data_get_mode (text) == GPGME_DATA_MODE_IN) if (_gpgme_data_get_mode (text) == GPGME_DATA_MODE_IN)
{ {
/* Normal or cleartext signature. */ /* 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, err = gpgsm_set_fd (gpgsm->assuan_ctx, "OUTPUT", gpgsm->output_fd_server,
0); 0);
_gpgme_io_close (gpgsm->message_fd); _gpgme_io_close (gpgsm->message_cb.fd);
} }
else else
{ {
/* Detached signature. */ /* Detached signature. */
gpgsm->message_data = text; gpgsm->message_cb.data = text;
err = gpgsm_set_fd (gpgsm->assuan_ctx, "MESSAGE", err = gpgsm_set_fd (gpgsm->assuan_ctx, "MESSAGE",
gpgsm->message_fd_server, 0); gpgsm->message_fd_server, 0);
_gpgme_io_close (gpgsm->output_fd); _gpgme_io_close (gpgsm->output_cb.fd);
} }
if (err) if (err)
return err; return err;
@ -946,8 +1025,8 @@ status_cmp (const void *ap, const void *bp)
} }
static int static void
gpgsm_status_handler (void *opaque, int pid, int fd) gpgsm_status_handler (void *opaque, int fd)
{ {
AssuanError err; AssuanError err;
GpgsmObject gpgsm = opaque; 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[0] == 'E' && line[1] == 'R' && line[2] == 'R'
&& (line[3] == '\0' || line[3] == ' '))) && (line[3] == '\0' || line[3] == ' ')))
{ {
/* XXX: If an error occured, find out what happened, then save the error value /* XXX: If an error occured, find out what happened, then
before running the status handler (so it takes precedence). */ save the error value before running the status handler
(so it takes precedence). */
if (!err && line[0] == 'E' && line[3] == ' ') if (!err && line[0] == 'E' && line[3] == ' ')
{ {
err = map_assuan_error (atoi (&line[4])); err = map_assuan_error (atoi (&line[4]));
@ -990,7 +1070,8 @@ gpgsm_status_handler (void *opaque, int pid, int fd)
if (err) if (err)
assuan_write_line (gpgsm->assuan_ctx, "BYE"); assuan_write_line (gpgsm->assuan_ctx, "BYE");
return 1; _gpgme_io_close (gpgsm->status_cb.fd);
return;
} }
if (linelen > 2 if (linelen > 2
@ -1015,7 +1096,10 @@ gpgsm_status_handler (void *opaque, int pid, int fd)
unsigned char *newline = xtryrealloc (*aline, unsigned char *newline = xtryrealloc (*aline,
*alinelen + linelen + 1); *alinelen + linelen + 1);
if (!newline) if (!newline)
return mk_error (Out_Of_Core); {
_gpgme_io_close (gpgsm->status_cb.fd);
return;
}
*aline = newline; *aline = newline;
gpgsm->colon.attic.linesize += linelen + 1; 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)); 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 GpgmeError
_gpgme_gpgsm_start (GpgsmObject gpgsm, void *opaque) _gpgme_gpgsm_start (GpgsmObject gpgsm, void *opaque)
{ {
GpgmeError err = 0; GpgmeError err = 0;
pid_t pid; pid_t pid;
int fdlist[5];
int nfds;
if (!gpgsm) if (!gpgsm)
return mk_error (Invalid_Value); return mk_error (Invalid_Value);
pid = assuan_get_pid (gpgsm->assuan_ctx); pid = assuan_get_pid (gpgsm->assuan_ctx);
/* We need to know the fd used by assuan for reads. We do this by err = _gpgme_gpgsm_add_io_cb (gpgsm, &gpgsm->status_cb,
using the assumption that the first returned fd from gpgsm_status_handler);
assuan_get_active_fds() is always this one. */ if (gpgsm->input_cb.fd != -1)
nfds = assuan_get_active_fds (gpgsm->assuan_ctx, 0 /* read fds */, err = _gpgme_gpgsm_add_io_cb (gpgsm, &gpgsm->input_cb,
fdlist, DIM (fdlist)); _gpgme_data_outbound_handler);
if (nfds < 1) if (!err && gpgsm->output_cb.fd != -1)
return mk_error (General_Error); /* FIXME */ err = _gpgme_gpgsm_add_io_cb (gpgsm, &gpgsm->output_cb,
err = _gpgme_register_pipe_handler (opaque, gpgsm_status_handler, gpgsm, pid, _gpgme_data_inbound_handler);
fdlist[0], 1); if (!err && gpgsm->message_cb.fd != -1)
err = _gpgme_gpgsm_add_io_cb (gpgsm, &gpgsm->message_cb,
_gpgme_data_outbound_handler);
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);
}
if (!err) if (!err)
err = assuan_write_line (gpgsm->assuan_ctx, gpgsm->command); err = assuan_write_line (gpgsm->assuan_ctx, gpgsm->command);
@ -1160,6 +1237,12 @@ _gpgme_gpgsm_start (GpgsmObject gpgsm, void *opaque)
return err; return err;
} }
void
_gpgme_gpgsm_set_io_cbs (GpgsmObject gpgsm, struct GpgmeIOCbs *io_cbs)
{
gpgsm->io_cbs = *io_cbs;
}
#else /* ENABLE_GPGSM */ #else /* ENABLE_GPGSM */
@ -1303,5 +1386,8 @@ _gpgme_gpgsm_start (GpgsmObject gpgsm, void *opaque)
return mk_error (Invalid_Engine); return mk_error (Invalid_Engine);
} }
void _gpgme_gpgsm_set_io_cbs (GpgsmObject gpgsm, GpgmeIOCbs io_cbs)
{
}
#endif /* ! ENABLE_GPGSM */ #endif /* ! ENABLE_GPGSM */

View File

@ -63,5 +63,6 @@ GpgmeError _gpgme_gpgsm_op_trustlist (GpgsmObject gpgsm, const char *pattern);
GpgmeError _gpgme_gpgsm_op_verify (GpgsmObject gpgsm, GpgmeData sig, GpgmeError _gpgme_gpgsm_op_verify (GpgsmObject gpgsm, GpgmeData sig,
GpgmeData text); GpgmeData text);
GpgmeError _gpgme_gpgsm_start (GpgsmObject gpgsm, void *opaque); GpgmeError _gpgme_gpgsm_start (GpgsmObject gpgsm, void *opaque);
void _gpgme_gpgsm_set_io_cbs (GpgsmObject gpgsm, struct GpgmeIOCbs *io_cbs);
#endif /* ENGINE_GPGSM_H */ #endif /* ENGINE_GPGSM_H */

View File

@ -567,6 +567,26 @@ _gpgme_engine_start (EngineObject engine, void *opaque)
return 0; 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;
}
}
void void
_gpgme_engine_add_child_to_reap_list (void *buf, int buflen, pid_t pid) _gpgme_engine_add_child_to_reap_list (void *buf, int buflen, pid_t pid)

View File

@ -76,6 +76,9 @@ GpgmeError _gpgme_engine_op_verify (EngineObject engine, GpgmeData sig,
GpgmeData text); GpgmeData text);
GpgmeError _gpgme_engine_start (EngineObject engine, void *opaque); 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_add_child_to_reap_list (void *buf, int buflen, pid_t pid);
void _gpgme_engine_housecleaning (void); void _gpgme_engine_housecleaning (void);

View File

@ -41,21 +41,13 @@ export_status_handler (GpgmeCtx ctx, GpgStatusCode code, char *args)
} }
GpgmeError static GpgmeError
gpgme_op_export_start (GpgmeCtx ctx, GpgmeRecipients recp, GpgmeData keydata) _gpgme_op_export_start (GpgmeCtx ctx, int synchronous,
GpgmeRecipients recp, GpgmeData keydata)
{ {
GpgmeError err = 0; GpgmeError err = 0;
fail_on_pending_request (ctx); err = _gpgme_op_reset (ctx, synchronous);
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);
if (err) if (err)
goto leave; goto leave;
@ -83,6 +75,11 @@ gpgme_op_export_start (GpgmeCtx ctx, GpgmeRecipients recp, GpgmeData keydata)
return err; 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: * gpgme_op_export:
@ -100,8 +97,8 @@ gpgme_op_export_start (GpgmeCtx ctx, GpgmeRecipients recp, GpgmeData keydata)
GpgmeError GpgmeError
gpgme_op_export (GpgmeCtx ctx, GpgmeRecipients recipients, GpgmeData keydata) 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) if (!err)
gpgme_wait (ctx, &err, 1); err = _gpgme_wait_one (ctx);
return err; return err;
} }

View File

@ -78,66 +78,20 @@ genkey_status_handler (GpgmeCtx ctx, GpgStatusCode code, char *args)
} }
} }
static GpgmeError
/** _gpgme_op_genkey_start (GpgmeCtx ctx, int synchronous, const char *parms,
* 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) GpgmeData pubkey, GpgmeData seckey)
{ {
int err = 0; int err = 0;
const char *s, *s2, *sx; const char *s, *s2, *sx;
fail_on_pending_request (ctx); err = _gpgme_op_reset (ctx, synchronous);
ctx->pending = 1; if (err)
goto leave;
gpgme_data_release (ctx->help_data_1); gpgme_data_release (ctx->help_data_1);
ctx->help_data_1 = NULL; 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) if (!pubkey && !seckey)
; /* okay: Add key to the keyrings */ ; /* okay: Add key to the keyrings */
else if (pubkey && gpgme_data_get_type (pubkey) != GPGME_DATA_TYPE_NONE) else if (pubkey && gpgme_data_get_type (pubkey) != GPGME_DATA_TYPE_NONE)
@ -199,6 +153,53 @@ gpgme_op_genkey_start (GpgmeCtx ctx, const char *parms,
} }
/**
* 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)
{
return _gpgme_op_genkey_start (ctx, 0, parms, pubkey, seckey);
}
/** /**
* gpgme_op_genkey: * gpgme_op_genkey:
* @c: the context * @c: the context
@ -217,8 +218,8 @@ GpgmeError
gpgme_op_genkey (GpgmeCtx ctx, const char *parms, gpgme_op_genkey (GpgmeCtx ctx, const char *parms,
GpgmeData pubkey, GpgmeData seckey) 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) if (!err)
gpgme_wait (ctx, &err, 1); err = _gpgme_wait_one (ctx);
return err; return err;
} }

View File

@ -28,7 +28,7 @@
#include "util.h" #include "util.h"
#include "context.h" #include "context.h"
#include "ops.h" #include "ops.h"
#include "wait.h"
/** /**
* gpgme_new: * gpgme_new:
@ -53,8 +53,8 @@ gpgme_new (GpgmeCtx *r_ctx)
ctx->keylist_mode = GPGME_KEYLIST_MODE_LOCAL; ctx->keylist_mode = GPGME_KEYLIST_MODE_LOCAL;
ctx->verbosity = 1; ctx->verbosity = 1;
ctx->include_certs = 1; ctx->include_certs = 1;
_gpgme_fd_table_init (&ctx->fdt);
*r_ctx = ctx; *r_ctx = ctx;
return 0; return 0;
} }
@ -71,6 +71,7 @@ gpgme_release (GpgmeCtx ctx)
if (!ctx) if (!ctx)
return; return;
_gpgme_engine_release (ctx->engine); _gpgme_engine_release (ctx->engine);
_gpgme_fd_table_deinit (&ctx->fdt);
_gpgme_release_result (ctx); _gpgme_release_result (ctx);
gpgme_key_release (ctx->tmp_key); gpgme_key_release (ctx->tmp_key);
gpgme_data_release (ctx->help_data_1); 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: The current callback function
* @r_cb_value: The current value passed to the 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 void
gpgme_get_progress_cb (GpgmeCtx ctx, GpgmeProgressCb *r_cb, void **r_cb_value) 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; *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);
}

View File

@ -43,7 +43,7 @@ extern "C" {
AM_PATH_GPGME macro) check that this header matches the installed AM_PATH_GPGME macro) check that this header matches the installed
library. Warning: Do not edit the next line. configure will do library. Warning: Do not edit the next line. configure will do
that for you! */ that for you! */
#define GPGME_VERSION "0.3.7-cvs" #define GPGME_VERSION "0.3.8-cvs"
/* The opaque data types used by GPGME. */ /* The opaque data types used by GPGME. */
@ -316,6 +316,46 @@ char *gpgme_get_op_info (GpgmeCtx ctx, int reserved);
/* Run control. */ /* 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. */ /* Cancel a pending operation in CTX. */
void gpgme_cancel (GpgmeCtx ctx); void gpgme_cancel (GpgmeCtx ctx);

View File

@ -162,18 +162,12 @@ import_status_handler (GpgmeCtx ctx, GpgStatusCode code, char *args)
} }
GpgmeError static GpgmeError
gpgme_op_import_start (GpgmeCtx ctx, GpgmeData keydata) _gpgme_op_import_start (GpgmeCtx ctx, int synchronous, GpgmeData keydata)
{ {
int err = 0; int err = 0;
fail_on_pending_request (ctx); err = _gpgme_op_reset (ctx, synchronous);
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);
if (err) if (err)
goto leave; 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: * gpgme_op_import:
* @c: Context * @c: Context
@ -216,8 +216,8 @@ gpgme_op_import_start (GpgmeCtx ctx, GpgmeData keydata)
GpgmeError GpgmeError
gpgme_op_import (GpgmeCtx ctx, GpgmeData keydata) 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) if (!err)
gpgme_wait (ctx, &err, 1); err = _gpgme_wait_one (ctx);
return err; return err;
} }

View 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) 2000 Werner Koch (dd9jn)
* Copyright (C) 2001 g10 Code GmbH * Copyright (C) 2001, 2002 g10 Code GmbH
* *
* This file is part of GPGME. * This file is part of GPGME.
* *
@ -24,15 +24,17 @@
#include "types.h" #include "types.h"
struct spawn_fd_item_s { /* 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 fd;
int dup_to; int dup_to;
}; };
struct io_select_fd_s
struct io_select_fd_s { {
int fd; int fd;
int is_closed;
int for_read; int for_read;
int for_write; int for_write;
int signaled; int signaled;
@ -40,32 +42,26 @@ struct io_select_fd_s {
void *opaque; 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);
/* These function are either defined in posix-io.c or w32-io.c */ /* 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
int _gpgme_io_read ( int fd, void *buffer, size_t count ); fds in FD_CHILD_LIST in the child. */
int _gpgme_io_write ( int fd, const void *buffer, size_t count ); int _gpgme_io_spawn (const char *path, char **argv,
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_child_list,
struct spawn_fd_item_s *fd_parent_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_waitpid (int pid, int hang, int *r_status, int *r_signal);
int _gpgme_io_kill ( int pid, int hard ); int _gpgme_io_kill (int pid, int hard);
int _gpgme_io_select ( struct io_select_fd_s *fds, size_t nfds); int _gpgme_io_select (struct io_select_fd_s *fds, size_t nfds);
#endif /* IO_H */ #endif /* IO_H */

View File

@ -236,7 +236,8 @@ keylist_colon_handler (GpgmeCtx ctx, char *line)
/* Start a new keyblock. */ /* Start a new keyblock. */
if (_gpgme_key_new (&key)) 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; return;
} }
rectype = RT_PUB; rectype = RT_PUB;
@ -249,7 +250,8 @@ keylist_colon_handler (GpgmeCtx ctx, char *line)
/* Start a new keyblock, */ /* Start a new keyblock, */
if (_gpgme_key_new_secret (&key)) 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; return;
} }
rectype = RT_SEC; rectype = RT_SEC;
@ -262,7 +264,8 @@ keylist_colon_handler (GpgmeCtx ctx, char *line)
/* Start a new certificate. */ /* Start a new certificate. */
if (_gpgme_key_new (&key)) 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; return;
} }
key->x509 = 1; key->x509 = 1;
@ -276,7 +279,8 @@ keylist_colon_handler (GpgmeCtx ctx, char *line)
/* Start a new certificate. */ /* Start a new certificate. */
if (_gpgme_key_new_secret (&key)) 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; return;
} }
key->x509 = 1; key->x509 = 1;
@ -289,7 +293,6 @@ keylist_colon_handler (GpgmeCtx ctx, char *line)
rectype = RT_FPR; rectype = RT_FPR;
else else
rectype = RT_NONE; rectype = RT_NONE;
} }
else if (rectype == RT_PUB || rectype == RT_SEC else if (rectype == RT_PUB || rectype == RT_SEC
|| rectype == RT_CRT || rectype == RT_CRS) || rectype == RT_CRT || rectype == RT_CRS)
@ -401,7 +404,8 @@ keylist_colon_handler (GpgmeCtx ctx, char *line)
break; break;
case 10: /* user ID */ case 10: /* user ID */
if (_gpgme_key_append_name (key, p)) 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 else
{ {
if (trust_info) if (trust_info)
@ -495,26 +499,14 @@ gpgme_op_keylist_start (GpgmeCtx ctx, const char *pattern, int secret_only)
{ {
GpgmeError err = 0; GpgmeError err = 0;
if (!ctx) err = _gpgme_op_reset (ctx, 0);
return mk_error (Invalid_Value); if (err)
ctx->pending = 1; goto leave;
_gpgme_release_result (ctx);
if (ctx->engine)
{
_gpgme_engine_release (ctx->engine);
ctx->engine = NULL;
}
gpgme_key_release (ctx->tmp_key); gpgme_key_release (ctx->tmp_key);
ctx->tmp_key = NULL; ctx->tmp_key = NULL;
/* Fixme: Release key_queue. */ /* 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); _gpgme_engine_set_status_handler (ctx->engine, keylist_status_handler, ctx);
err = _gpgme_engine_set_colon_line_handler (ctx->engine, err = _gpgme_engine_set_colon_line_handler (ctx->engine,
keylist_colon_handler, ctx); keylist_colon_handler, ctx);
@ -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 */ just ignore those lines - This should speed up things */
_gpgme_engine_set_verbosity (ctx->engine, 0); _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. */ if (!err) /* And kick off the process. */
err = _gpgme_engine_start (ctx->engine, ctx); err = _gpgme_engine_start (ctx->engine, ctx);
@ -561,26 +554,12 @@ gpgme_op_keylist_ext_start (GpgmeCtx ctx, const char *pattern[],
{ {
GpgmeError err = 0; GpgmeError err = 0;
if (!ctx) err = _gpgme_op_reset (ctx, 0);
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);
if (err) if (err)
goto leave; goto leave;
gpgme_key_release (ctx->tmp_key);
_gpgme_engine_set_status_handler (ctx->engine, keylist_status_handler, ctx); _gpgme_engine_set_status_handler (ctx->engine, keylist_status_handler, ctx);
err = _gpgme_engine_set_colon_line_handler (ctx->engine, err = _gpgme_engine_set_colon_line_handler (ctx->engine,
keylist_colon_handler, ctx); keylist_colon_handler, ctx);

70
gpgme/op-support.c Normal file
View File

@ -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;
}

View File

@ -46,12 +46,11 @@
void _gpgme_release_result ( GpgmeCtx c ); void _gpgme_release_result ( GpgmeCtx c );
void _gpgme_set_op_info (GpgmeCtx c, GpgmeData info); void _gpgme_set_op_info (GpgmeCtx c, GpgmeData info);
void _gpgme_op_event_cb (void *data, GpgmeEventIO type, void *type_data);
/*-- wait.c --*/ /*-- wait.c --*/
GpgmeCtx _gpgme_wait_on_condition ( GpgmeCtx c, GpgmeCtx _gpgme_wait_on_condition ( GpgmeCtx c,
int hang, volatile int *cond ); int hang, volatile int *cond );
void _gpgme_freeze_fd ( int fd );
void _gpgme_thaw_fd ( int fd );
/*-- recipient.c --*/ /*-- recipient.c --*/
int _gpgme_recipients_all_valid ( const GpgmeRecipients rset ); 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, GpgmeError _gpgme_data_unread (GpgmeData dh,
const char *buffer, size_t length ); const char *buffer, size_t length );
int _gpgme_data_inbound_handler (void *opaque, int pid, int fd); void _gpgme_data_inbound_handler (void *opaque, int fd);
int _gpgme_data_outbound_handler (void *opaque, int pid, int fd); void _gpgme_data_outbound_handler (void *opaque, int fd);
/*-- key.c --*/ /*-- key.c --*/
GpgmeError _gpgme_key_new ( GpgmeKey *r_key ); GpgmeError _gpgme_key_new ( GpgmeKey *r_key );
GpgmeError _gpgme_key_new_secret ( GpgmeKey *r_key ); GpgmeError _gpgme_key_new_secret ( GpgmeKey *r_key );
/*-- op-support.c --*/
GpgmeError _gpgme_op_reset (GpgmeCtx ctx, int synchronous);
/*-- verify.c --*/ /*-- verify.c --*/
void _gpgme_release_verify_result (VerifyResult result); 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_release_decrypt_result (DecryptResult result);
void _gpgme_decrypt_status_handler (GpgmeCtx ctx, GpgStatusCode code, void _gpgme_decrypt_status_handler (GpgmeCtx ctx, GpgStatusCode code,
char *args); 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); void *status_handler);
GpgmeError _gpgme_decrypt_result (GpgmeCtx ctx); GpgmeError _gpgme_decrypt_result (GpgmeCtx ctx);

View File

@ -54,21 +54,25 @@ struct arg_and_data_s {
char arg[1]; /* .. this is used */ char arg[1]; /* .. this is used */
}; };
struct fd_data_map_s { struct fd_data_map_s
{
GpgmeData data; GpgmeData data;
int inbound; /* true if this is used for reading from gpg */ int inbound; /* true if this is used for reading from gpg */
int dup_to; int dup_to;
int fd; /* the fd to use */ int fd; /* the fd to use */
int peer_fd; /* the outher side of the pipe */ int peer_fd; /* the outher side of the pipe */
void *tag;
}; };
struct gpg_object_s { struct gpg_object_s
{
struct arg_and_data_s *arglist; struct arg_and_data_s *arglist;
struct arg_and_data_s **argtail; struct arg_and_data_s **argtail;
int arg_error; int arg_error;
struct { struct
{
int fd[2]; int fd[2];
size_t bufsize; size_t bufsize;
char *buffer; char *buffer;
@ -76,10 +80,12 @@ struct gpg_object_s {
int eof; int eof;
GpgStatusHandler fnc; GpgStatusHandler fnc;
void *fnc_value; void *fnc_value;
void *tag;
} status; } status;
/* This is a kludge - see the comment at gpg_colon_line_handler */ /* This is a kludge - see the comment at gpg_colon_line_handler */
struct { struct
{
int fd[2]; int fd[2];
size_t bufsize; size_t bufsize;
char *buffer; char *buffer;
@ -87,6 +93,7 @@ struct gpg_object_s {
int eof; int eof;
GpgColonLineHandler fnc; /* this indicate use of this structrue */ GpgColonLineHandler fnc; /* this indicate use of this structrue */
void *fnc_value; void *fnc_value;
void *tag;
int simple; int simple;
} colon; } colon;
@ -95,10 +102,9 @@ struct gpg_object_s {
int pid; /* we can't use pid_t because we don't use it in Windoze */ int pid; /* we can't use pid_t because we don't use it in Windoze */
int running;
/* stuff needed for pipemode */ /* stuff needed for pipemode */
struct { struct
{
int used; int used;
int active; int active;
GpgmeData sig; GpgmeData sig;
@ -107,60 +113,107 @@ struct gpg_object_s {
} pm; } pm;
/* stuff needed for interactive (command) mode */ /* stuff needed for interactive (command) mode */
struct { struct
{
int used; int used;
int fd; int fd;
GpgmeData cb_data; /* hack to get init the above fd later */ int idx; /* Index in fd_data_map */
GpgmeData cb_data; /* hack to get init the above idx later */
GpgStatusCode code; /* last code */ GpgStatusCode code; /* last code */
char *keyword; /* what has been requested (malloced) */ char *keyword; /* what has been requested (malloced) */
GpgCommandHandler fnc; GpgCommandHandler fnc;
void *fnc_value; void *fnc_value;
} cmd; } cmd;
struct GpgmeIOCbs io_cbs;
}; };
static void free_argv ( char **argv ); static void free_argv (char **argv);
static void free_fd_data_map ( struct fd_data_map_s *fd_data_map ); 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 void gpg_status_handler (void *opaque, int fd);
static GpgmeError read_status ( GpgObject gpg ); static GpgmeError read_status (GpgObject gpg);
static int gpg_colon_line_handler ( void *opaque, int pid, int fd ); static void gpg_colon_line_handler (void *opaque, int fd);
static GpgmeError read_colon_line ( GpgObject gpg ); 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 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 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 )
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; gpg->status.fd[0] = -1;
else if (gpg->status.fd[1] == fd ) }
else if (gpg->status.fd[1] == fd)
gpg->status.fd[1] = -1; gpg->status.fd[1] = -1;
else if (gpg->colon.fd[0] == fd ) 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; gpg->colon.fd[0] = -1;
else if (gpg->colon.fd[1] == fd ) }
else if (gpg->colon.fd[1] == fd)
gpg->colon.fd[1] = -1; gpg->colon.fd[1] = -1;
else if (gpg->fd_data_map) { else if (gpg->fd_data_map)
{
int i; int i;
for (i=0; gpg->fd_data_map[i].data; 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].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; gpg->fd_data_map[i].fd = -1;
break; break;
} }
if ( gpg->fd_data_map[i].peer_fd == fd ) { if (gpg->fd_data_map[i].peer_fd == fd)
{
gpg->fd_data_map[i].peer_fd = -1; gpg->fd_data_map[i].peer_fd = -1;
break; 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 * const char *
@ -185,13 +238,14 @@ _gpgme_gpg_check_version (void)
} }
GpgmeError GpgmeError
_gpgme_gpg_new ( GpgObject *r_gpg ) _gpgme_gpg_new (GpgObject *r_gpg)
{ {
GpgObject gpg; GpgObject gpg;
int rc = 0; int rc = 0;
gpg = xtrycalloc ( 1, sizeof *gpg ); gpg = xtrycalloc (1, sizeof *gpg);
if ( !gpg ) { if (!gpg)
{
rc = mk_error (Out_Of_Core); rc = mk_error (Out_Of_Core);
goto leave; goto leave;
} }
@ -202,42 +256,46 @@ _gpgme_gpg_new ( GpgObject *r_gpg )
gpg->colon.fd[0] = -1; gpg->colon.fd[0] = -1;
gpg->colon.fd[1] = -1; gpg->colon.fd[1] = -1;
gpg->cmd.fd = -1; gpg->cmd.fd = -1;
gpg->cmd.idx = -1;
gpg->pid = -1; gpg->pid = -1;
/* allocate the read buffer for the status pipe */ /* Allocate the read buffer for the status pipe. */
gpg->status.bufsize = 1024; gpg->status.bufsize = 1024;
gpg->status.readpos = 0; gpg->status.readpos = 0;
gpg->status.buffer = xtrymalloc (gpg->status.bufsize); gpg->status.buffer = xtrymalloc (gpg->status.bufsize);
if (!gpg->status.buffer) { if (!gpg->status.buffer)
{
rc = mk_error (Out_Of_Core); rc = mk_error (Out_Of_Core);
goto leave; goto leave;
} }
/* In any case we need a status pipe - create it right here and /* In any case we need a status pipe - create it right here and
* don't handle it with our generic GpgmeData mechanism */ don't handle it with our generic GpgmeData mechanism. */
if (_gpgme_io_pipe (gpg->status.fd, 1) == -1) { if (_gpgme_io_pipe (gpg->status.fd, 1) == -1)
{
rc = mk_error (Pipe_Error); rc = mk_error (Pipe_Error);
goto leave; goto leave;
} }
if ( _gpgme_io_set_close_notify (gpg->status.fd[0], if (_gpgme_io_set_close_notify (gpg->status.fd[0],
close_notify_handler, gpg) close_notify_handler, gpg)
|| _gpgme_io_set_close_notify (gpg->status.fd[1], || _gpgme_io_set_close_notify (gpg->status.fd[1],
close_notify_handler, gpg) ) { close_notify_handler, gpg))
{
rc = mk_error (General_Error); rc = mk_error (General_Error);
goto leave; goto leave;
} }
gpg->status.eof = 0; gpg->status.eof = 0;
_gpgme_gpg_add_arg ( gpg, "--status-fd" ); _gpgme_gpg_add_arg (gpg, "--status-fd");
{ {
char buf[25]; char buf[25];
sprintf ( buf, "%d", gpg->status.fd[1]); sprintf (buf, "%d", gpg->status.fd[1]);
_gpgme_gpg_add_arg ( gpg, buf ); _gpgme_gpg_add_arg (gpg, buf);
} }
_gpgme_gpg_add_arg ( gpg, "--no-tty" ); _gpgme_gpg_add_arg (gpg, "--no-tty");
leave: leave:
if (rc) { if (rc)
{
_gpgme_gpg_release (gpg); _gpgme_gpg_release (gpg);
*r_gpg = NULL; *r_gpg = NULL;
} }
@ -268,8 +326,6 @@ _gpgme_gpg_release (GpgObject gpg)
gpgme_data_release (gpg->cmd.cb_data); gpgme_data_release (gpg->cmd.cb_data);
xfree (gpg->cmd.keyword); xfree (gpg->cmd.keyword);
if (gpg->pid != -1)
_gpgme_remove_proc_from_wait_queue (gpg->pid);
if (gpg->status.fd[0] != -1) if (gpg->status.fd[0] != -1)
_gpgme_io_close (gpg->status.fd[0]); _gpgme_io_close (gpg->status.fd[0]);
if (gpg->status.fd[1] != -1) if (gpg->status.fd[1] != -1)
@ -279,7 +335,9 @@ _gpgme_gpg_release (GpgObject gpg)
if (gpg->colon.fd[1] != -1) if (gpg->colon.fd[1] != -1)
_gpgme_io_close (gpg->colon.fd[1]); _gpgme_io_close (gpg->colon.fd[1]);
free_fd_data_map (gpg->fd_data_map); 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); _gpgme_engine_add_child_to_reap_list (gpg, sizeof *gpg, gpg->pid);
else else
xfree (gpg); xfree (gpg);
@ -512,7 +570,7 @@ free_fd_data_map ( struct fd_data_map_s *fd_data_map )
static GpgmeError static GpgmeError
build_argv ( GpgObject gpg ) build_argv (GpgObject gpg)
{ {
struct arg_and_data_s *a; struct arg_and_data_s *a;
struct fd_data_map_s *fd_data_map; struct fd_data_map_s *fd_data_map;
@ -521,29 +579,34 @@ build_argv ( GpgObject gpg )
int need_special = 0; int need_special = 0;
int use_agent = !!getenv ("GPG_AGENT_INFO"); int use_agent = !!getenv ("GPG_AGENT_INFO");
if ( gpg->argv ) { if (gpg->argv)
free_argv ( gpg->argv ); {
free_argv (gpg->argv);
gpg->argv = NULL; gpg->argv = NULL;
} }
if (gpg->fd_data_map) { if (gpg->fd_data_map)
{
free_fd_data_map (gpg->fd_data_map); free_fd_data_map (gpg->fd_data_map);
gpg->fd_data_map = NULL; gpg->fd_data_map = NULL;
} }
argc++; /* for argv[0] */ argc++; /* For argv[0]. */
for ( a=gpg->arglist; a; a = a->next ) { for (a = gpg->arglist; a; a = a->next)
{
argc++; argc++;
if (a->data) { if (a->data)
{
/*fprintf (stderr, "build_argv: data\n" );*/ /*fprintf (stderr, "build_argv: data\n" );*/
datac++; datac++;
if ( a->dup_to == -1 && !a->print_fd ) if (a->dup_to == -1 && !a->print_fd)
need_special = 1; need_special = 1;
} }
else { else
{
/* fprintf (stderr, "build_argv: arg=`%s'\n", a->arg );*/ /* fprintf (stderr, "build_argv: arg=`%s'\n", a->arg );*/
} }
} }
if ( need_special ) if (need_special)
argc++; argc++;
if (use_agent) if (use_agent)
argc++; argc++;
@ -551,86 +614,100 @@ build_argv ( GpgObject gpg )
argc++; argc++;
argc += 2; /* --comment */ argc += 2; /* --comment */
argv = xtrycalloc ( argc+1, sizeof *argv ); argv = xtrycalloc (argc + 1, sizeof *argv);
if (!argv) if (!argv)
return mk_error (Out_Of_Core); return mk_error (Out_Of_Core);
fd_data_map = xtrycalloc ( datac+1, sizeof *fd_data_map ); fd_data_map = xtrycalloc (datac + 1, sizeof *fd_data_map);
if (!fd_data_map) { if (!fd_data_map)
{
free_argv (argv); free_argv (argv);
return mk_error (Out_Of_Core); return mk_error (Out_Of_Core);
} }
argc = datac = 0; argc = datac = 0;
argv[argc] = xtrystrdup ( "gpg" ); /* argv[0] */ argv[argc] = xtrystrdup ("gpg"); /* argv[0] */
if (!argv[argc]) { if (!argv[argc])
{
xfree (fd_data_map); xfree (fd_data_map);
free_argv (argv); free_argv (argv);
return mk_error (Out_Of_Core); return mk_error (Out_Of_Core);
} }
argc++; argc++;
if ( need_special ) { if (need_special)
argv[argc] = xtrystrdup ( "--enable-special-filenames" ); {
if (!argv[argc]) { argv[argc] = xtrystrdup ("--enable-special-filenames");
if (!argv[argc])
{
xfree (fd_data_map); xfree (fd_data_map);
free_argv (argv); free_argv (argv);
return mk_error (Out_Of_Core); return mk_error (Out_Of_Core);
} }
argc++; argc++;
} }
if ( use_agent ) { if (use_agent)
argv[argc] = xtrystrdup ( "--use-agent" ); {
if (!argv[argc]) { argv[argc] = xtrystrdup ("--use-agent");
if (!argv[argc])
{
xfree (fd_data_map); xfree (fd_data_map);
free_argv (argv); free_argv (argv);
return mk_error (Out_Of_Core); return mk_error (Out_Of_Core);
} }
argc++; argc++;
} }
if ( !gpg->cmd.used ) { if (!gpg->cmd.used)
argv[argc] = xtrystrdup ( "--batch" ); {
if (!argv[argc]) { argv[argc] = xtrystrdup ("--batch");
if (!argv[argc])
{
xfree (fd_data_map); xfree (fd_data_map);
free_argv (argv); free_argv (argv);
return mk_error (Out_Of_Core); return mk_error (Out_Of_Core);
} }
argc++; argc++;
} }
argv[argc] = xtrystrdup ( "--comment" ); argv[argc] = xtrystrdup ("--comment");
if (!argv[argc]) { if (!argv[argc])
{
xfree (fd_data_map); xfree (fd_data_map);
free_argv (argv); free_argv (argv);
return mk_error (Out_Of_Core); return mk_error (Out_Of_Core);
} }
argc++; argc++;
argv[argc] = xtrystrdup ( "" ); argv[argc] = xtrystrdup ("");
if (!argv[argc]) { if (!argv[argc])
{
xfree (fd_data_map); xfree (fd_data_map);
free_argv (argv); free_argv (argv);
return mk_error (Out_Of_Core); return mk_error (Out_Of_Core);
} }
argc++; argc++;
for ( a=gpg->arglist; a; a = a->next ) { for (a = gpg->arglist; a; a = a->next)
if ( a->data ) { {
switch ( _gpgme_data_get_mode (a->data) ) { if (a->data)
{
switch (_gpgme_data_get_mode (a->data))
{
case GPGME_DATA_MODE_NONE: case GPGME_DATA_MODE_NONE:
case GPGME_DATA_MODE_INOUT: case GPGME_DATA_MODE_INOUT:
xfree (fd_data_map); xfree (fd_data_map);
free_argv (argv); free_argv (argv);
return mk_error (Invalid_Mode); return mk_error (Invalid_Mode);
case GPGME_DATA_MODE_IN: case GPGME_DATA_MODE_IN:
/* create a pipe to read from gpg */ /* Create a pipe to read from gpg. */
fd_data_map[datac].inbound = 1; fd_data_map[datac].inbound = 1;
break; break;
case GPGME_DATA_MODE_OUT: case GPGME_DATA_MODE_OUT:
/* create a pipe to pass it down to gpg */ /* Create a pipe to pass it down to gpg. */
fd_data_map[datac].inbound = 0; fd_data_map[datac].inbound = 0;
break; break;
} }
switch ( gpgme_data_get_type (a->data) ) { switch (gpgme_data_get_type (a->data))
{
case GPGME_DATA_TYPE_NONE: case GPGME_DATA_TYPE_NONE:
if ( fd_data_map[datac].inbound ) if (fd_data_map[datac].inbound)
break; /* allowed */ break; /* Allowed. */
xfree (fd_data_map); xfree (fd_data_map);
free_argv (argv); free_argv (argv);
return mk_error (Invalid_Type); return mk_error (Invalid_Type);
@ -644,59 +721,68 @@ build_argv ( GpgObject gpg )
return mk_error (Not_Implemented); return mk_error (Not_Implemented);
} }
/* create a pipe */ /* Create a pipe. */
{ {
int fds[2]; int fds[2];
if (_gpgme_io_pipe (fds, fd_data_map[datac].inbound?1:0 ) if (_gpgme_io_pipe (fds, fd_data_map[datac].inbound ? 1 : 0)
== -1) { == -1)
{
xfree (fd_data_map); xfree (fd_data_map);
free_argv (argv); free_argv (argv);
return mk_error (Pipe_Error); return mk_error (Pipe_Error);
} }
if ( _gpgme_io_set_close_notify (fds[0], if (_gpgme_io_set_close_notify (fds[0],
close_notify_handler, gpg) close_notify_handler, gpg)
|| _gpgme_io_set_close_notify (fds[1], || _gpgme_io_set_close_notify (fds[1],
close_notify_handler, close_notify_handler,
gpg)) { gpg))
{
return mk_error (General_Error); return mk_error (General_Error);
} }
/* if the data_type is FD, we have to do a dup2 here */ /* If the data_type is FD, we have to do a dup2 here. */
if (fd_data_map[datac].inbound) { if (fd_data_map[datac].inbound)
{
fd_data_map[datac].fd = fds[0]; fd_data_map[datac].fd = fds[0];
fd_data_map[datac].peer_fd = fds[1]; fd_data_map[datac].peer_fd = fds[1];
} }
else { else
{
fd_data_map[datac].fd = fds[1]; fd_data_map[datac].fd = fds[1];
fd_data_map[datac].peer_fd = fds[0]; fd_data_map[datac].peer_fd = fds[0];
} }
} }
/* Hack to get hands on the fd later */ /* Hack to get hands on the fd later. */
if ( gpg->cmd.used && gpg->cmd.cb_data == a->data ) { if (gpg->cmd.used && gpg->cmd.cb_data == a->data)
assert (gpg->cmd.fd == -1); {
gpg->cmd.fd = fd_data_map[datac].fd; assert (gpg->cmd.idx == -1);
gpg->cmd.idx = datac;
} }
fd_data_map[datac].data = a->data; fd_data_map[datac].data = a->data;
fd_data_map[datac].dup_to = a->dup_to; fd_data_map[datac].dup_to = a->dup_to;
if ( a->dup_to == -1 ) { if (a->dup_to == -1)
argv[argc] = xtrymalloc ( 25 ); {
if (!argv[argc]) { argv[argc] = xtrymalloc (25);
if (!argv[argc])
{
xfree (fd_data_map); xfree (fd_data_map);
free_argv (argv); free_argv (argv);
return mk_error (Out_Of_Core); return mk_error (Out_Of_Core);
} }
sprintf ( argv[argc], sprintf (argv[argc],
a->print_fd? "%d" : "-&%d", a->print_fd ? "%d" : "-&%d",
fd_data_map[datac].peer_fd ); fd_data_map[datac].peer_fd);
argc++; argc++;
} }
datac++; datac++;
} }
else { else
argv[argc] = xtrystrdup ( a->arg ); {
if (!argv[argc]) { argv[argc] = xtrystrdup (a->arg);
if (!argv[argc])
{
xfree (fd_data_map); xfree (fd_data_map);
free_argv (argv); free_argv (argv);
return mk_error (Out_Of_Core); return mk_error (Out_Of_Core);
@ -710,10 +796,25 @@ build_argv ( GpgObject gpg )
return 0; return 0;
} }
GpgmeError static GpgmeError
_gpgme_gpg_spawn( GpgObject gpg, void *opaque ) _gpgme_gpg_add_io_cb (GpgObject gpg, int fd, int dir,
GpgmeIOCb handler, void *data, void **tag)
{ {
int rc; 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)
{
GpgmeError rc;
int i, n; int i, n;
int pid; int pid;
struct spawn_fd_item_s *fd_child_list, *fd_parent_list; struct spawn_fd_item_s *fd_child_list, *fd_parent_list;
@ -724,35 +825,38 @@ _gpgme_gpg_spawn( GpgObject gpg, void *opaque )
if (! _gpgme_get_gpg_path ()) if (! _gpgme_get_gpg_path ())
return mk_error (Invalid_Engine); return mk_error (Invalid_Engine);
/* Kludge, so that we don't need to check the return code of /* Kludge, so that we don't need to check the return code of all the
* all the gpgme_gpg_add_arg(). we bail out here instead */ gpgme_gpg_add_arg(). we bail out here instead */
if ( gpg->arg_error ) if (gpg->arg_error)
return mk_error (Out_Of_Core); return mk_error (Out_Of_Core);
if (gpg->pm.active) if (gpg->pm.active)
return 0; return 0;
rc = build_argv ( gpg ); rc = build_argv (gpg);
if ( rc ) if (rc)
return rc; return rc;
n = 3; /* status_fd, colon_fd and end of list */ n = 3; /* status_fd, colon_fd and end of list */
for (i=0; gpg->fd_data_map[i].data; i++ ) for (i = 0; gpg->fd_data_map[i].data; i++)
n++; n++;
fd_child_list = xtrycalloc ( n+n, sizeof *fd_child_list ); fd_child_list = xtrycalloc (n + n, sizeof *fd_child_list);
if (!fd_child_list) if (!fd_child_list)
return mk_error (Out_Of_Core); return mk_error (Out_Of_Core);
fd_parent_list = fd_child_list + n; fd_parent_list = fd_child_list + n;
/* build the fd list for the child */ /* build the fd list for the child */
n=0; n = 0;
if ( gpg->colon.fnc ) { if (gpg->colon.fnc)
{
fd_child_list[n].fd = gpg->colon.fd[1]; fd_child_list[n].fd = gpg->colon.fd[1];
fd_child_list[n].dup_to = 1; /* dup to stdout */ fd_child_list[n].dup_to = 1; /* dup to stdout */
n++; n++;
} }
for (i=0; gpg->fd_data_map[i].data; i++ ) { for (i = 0; gpg->fd_data_map[i].data; i++)
if (gpg->fd_data_map[i].dup_to != -1) { {
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].fd = gpg->fd_data_map[i].peer_fd;
fd_child_list[n].dup_to = gpg->fd_data_map[i].dup_to; fd_child_list[n].dup_to = gpg->fd_data_map[i].dup_to;
n++; n++;
@ -761,21 +865,24 @@ _gpgme_gpg_spawn( GpgObject gpg, void *opaque )
fd_child_list[n].fd = -1; fd_child_list[n].fd = -1;
fd_child_list[n].dup_to = -1; fd_child_list[n].dup_to = -1;
/* build the fd list for the parent */ /* Build the fd list for the parent. */
n=0; n = 0;
if ( gpg->status.fd[1] != -1 ) { if (gpg->status.fd[1] != -1)
{
fd_parent_list[n].fd = gpg->status.fd[1]; fd_parent_list[n].fd = gpg->status.fd[1];
fd_parent_list[n].dup_to = -1; fd_parent_list[n].dup_to = -1;
n++; n++;
gpg->status.fd[1] = -1; gpg->status.fd[1] = -1;
} }
if ( gpg->colon.fd[1] != -1 ) { if (gpg->colon.fd[1] != -1)
{
fd_parent_list[n].fd = gpg->colon.fd[1]; fd_parent_list[n].fd = gpg->colon.fd[1];
fd_parent_list[n].dup_to = -1; fd_parent_list[n].dup_to = -1;
n++; n++;
gpg->colon.fd[1] = -1; gpg->colon.fd[1] = -1;
} }
for (i=0; gpg->fd_data_map[i].data; i++ ) { 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].fd = gpg->fd_data_map[i].peer_fd;
fd_parent_list[n].dup_to = -1; fd_parent_list[n].dup_to = -1;
n++; n++;
@ -784,13 +891,11 @@ _gpgme_gpg_spawn( GpgObject gpg, void *opaque )
fd_parent_list[n].fd = -1; fd_parent_list[n].fd = -1;
fd_parent_list[n].dup_to = -1; fd_parent_list[n].dup_to = -1;
pid = _gpgme_io_spawn (_gpgme_get_gpg_path (), pid = _gpgme_io_spawn (_gpgme_get_gpg_path (),
gpg->argv, fd_child_list, fd_parent_list); gpg->argv, fd_child_list, fd_parent_list);
xfree (fd_child_list); xfree (fd_child_list);
if (pid == -1) { if (pid == -1)
return mk_error (Exec_Error); return mk_error (Exec_Error);
}
gpg->pid = pid; gpg->pid = pid;
if (gpg->pm.used) if (gpg->pm.used)
@ -798,55 +903,54 @@ _gpgme_gpg_spawn( GpgObject gpg, void *opaque )
/*_gpgme_register_term_handler ( closure, closure_value, pid );*/ /*_gpgme_register_term_handler ( closure, closure_value, pid );*/
if ( _gpgme_register_pipe_handler ( opaque, gpg_status_handler, rc = _gpgme_gpg_add_io_cb (gpg, gpg->status.fd[0], 1,
gpg, pid, gpg->status.fd[0], 1 ) ) { gpg_status_handler, gpg, &gpg->status.tag);
if (rc)
/* FIXME: kill the child */ /* FIXME: kill the child */
return mk_error (General_Error); return rc;
} if (gpg->colon.fnc)
{
if ( gpg->colon.fnc ) { assert (gpg->colon.fd[0] != -1);
assert ( gpg->colon.fd[0] != -1 ); rc = _gpgme_gpg_add_io_cb (gpg, gpg->colon.fd[0], 1,
if ( _gpgme_register_pipe_handler ( opaque, gpg_colon_line_handler, gpg_colon_line_handler, gpg,
gpg, pid, gpg->colon.fd[0], 1 ) ) { &gpg->colon.tag);
if (rc)
/* FIXME: kill the child */ /* FIXME: kill the child */
return mk_error (General_Error); return rc;
}
} }
for (i=0; gpg->fd_data_map[i].data; i++ ) { 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->cmd.used && i == gpg->cmd.idx)
if (!gpg->fd_data_map[i].inbound) { {
_gpgme_io_set_nonblocking (gpg->fd_data_map[i].fd); /* Park the cmd fd. */
gpg->cmd.fd = gpg->fd_data_map[i].fd;
gpg->fd_data_map[i].fd = -1;
} }
else
if ( _gpgme_register_pipe_handler ( {
opaque, 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].inbound
? _gpgme_data_inbound_handler
: _gpgme_data_outbound_handler,
gpg->fd_data_map[i].data, gpg->fd_data_map[i].data,
pid, gpg->fd_data_map[i].fd, &gpg->fd_data_map[i].tag);
gpg->fd_data_map[i].inbound )
) {
/* FIXME: kill the child */
return mk_error (General_Error);
}
}
if ( gpg->cmd.used ) if (rc)
_gpgme_freeze_fd ( gpg->cmd.fd ); /* FIXME: kill the child */
return rc;
}
}
/* fixme: check what data we can release here */ /* fixme: check what data we can release here */
gpg->running = 1;
return 0; return 0;
} }
static int static void
gpg_status_handler (void *opaque, int pid, int fd) gpg_status_handler (void *opaque, int fd)
{ {
GpgObject gpg = opaque; GpgObject gpg = opaque;
int err; int err;
@ -860,9 +964,11 @@ gpg_status_handler (void *opaque, int pid, int fd)
GpgmeCtx ctx = (GpgmeCtx) gpg->status.fnc_value; GpgmeCtx ctx = (GpgmeCtx) gpg->status.fnc_value;
ctx->error = err; ctx->error = err;
DEBUG1 ("gpg_handler: read_status problem %d\n - stop", 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 */ * handler does its action */
if ( nread > 1 ) if ( nread > 1 )
DEBUG0 ("ERROR, unexpected data in read_status"); 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 ) { else if ( gpg->status.fnc ) {
gpg->status.fnc ( gpg->status.fnc_value, gpg->status.fnc ( gpg->status.fnc_value,
@ -959,8 +1072,13 @@ read_status ( GpgObject gpg )
} }
if ( r->code == STATUS_END_STREAM ) { if ( r->code == STATUS_END_STREAM ) {
if ( gpg->cmd.used ) if (gpg->cmd.used)
_gpgme_freeze_fd ( gpg->cmd.fd ); {
(*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. * a wrapper for a callback. Same goes for the status thing.
* For now we use this thing here becuase it is easier to implement. * For now we use this thing here becuase it is easier to implement.
*/ */
static int static void
gpg_colon_line_handler ( void *opaque, int pid, int fd ) gpg_colon_line_handler (void *opaque, int fd)
{ {
GpgObject gpg = opaque; GpgObject gpg = opaque;
GpgmeError rc = 0; GpgmeError rc = 0;
assert ( fd == gpg->colon.fd[0] ); assert (fd == gpg->colon.fd[0]);
rc = read_colon_line ( gpg ); rc = read_colon_line (gpg);
if ( rc ) { if (rc)
{
DEBUG1 ("gpg_colon_line_handler: " DEBUG1 ("gpg_colon_line_handler: "
"read problem %d\n - stop", rc); "read problem %d\n - stop", rc);
return 1; _gpgme_io_close (fd);
return;
} }
if (gpg->colon.eof)
return gpg->colon.eof; _gpgme_io_close (fd);
} }
static GpgmeError static GpgmeError
@ -1167,7 +1287,7 @@ pipemode_cb ( void *opaque, char *buffer, size_t length, size_t *nread )
*/ */
static int 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; GpgObject gpg = opaque;
const char *value; const char *value;
@ -1175,43 +1295,50 @@ command_cb ( void *opaque, char *buffer, size_t length, size_t *nread )
DEBUG0 ("command_cb: enter\n"); DEBUG0 ("command_cb: enter\n");
assert (gpg->cmd.used); assert (gpg->cmd.used);
if ( !buffer || !length || !nread ) if (!buffer || !length || !nread)
return 0; /* those values are reserved for extensions */ return 0; /* These values are reserved for extensions. */
*nread =0; *nread = 0;
if ( !gpg->cmd.code ) { if (!gpg->cmd.code)
{
DEBUG0 ("command_cb: no code\n"); DEBUG0 ("command_cb: no code\n");
return -1; return -1;
} }
if ( !gpg->cmd.fnc ) { if (!gpg->cmd.fnc)
{
DEBUG0 ("command_cb: no user cb\n"); DEBUG0 ("command_cb: no user cb\n");
return -1; return -1;
} }
value = gpg->cmd.fnc ( gpg->cmd.fnc_value, value = gpg->cmd.fnc (gpg->cmd.fnc_value,
gpg->cmd.code, gpg->cmd.keyword ); gpg->cmd.code, gpg->cmd.keyword);
if ( !value ) { if (!value)
{
DEBUG0 ("command_cb: no data from user cb\n"); DEBUG0 ("command_cb: no data from user cb\n");
gpg->cmd.fnc ( gpg->cmd.fnc_value, 0, value); gpg->cmd.fnc (gpg->cmd.fnc_value, 0, value);
return -1; return -1;
} }
value_len = strlen (value); value_len = strlen (value);
if ( value_len+1 > length ) { if (value_len + 1 > length)
{
DEBUG0 ("command_cb: too much data from user cb\n"); DEBUG0 ("command_cb: too much data from user cb\n");
gpg->cmd.fnc ( gpg->cmd.fnc_value, 0, value); gpg->cmd.fnc (gpg->cmd.fnc_value, 0, value);
return -1; return -1;
} }
memcpy ( buffer, value, value_len ); memcpy (buffer, value, value_len);
if ( !value_len || (value_len && value[value_len-1] != '\n') ) if (!value_len || (value_len && value[value_len-1] != '\n'))
buffer[value_len++] = '\n'; buffer[value_len++] = '\n';
*nread = value_len; *nread = value_len;
gpg->cmd.fnc ( gpg->cmd.fnc_value, 0, value); gpg->cmd.fnc (gpg->cmd.fnc_value, 0, value);
gpg->cmd.code = 0; gpg->cmd.code = 0;
/* and sleep again until read_status will wake us up again */ /* And sleep again until read_status will wake us up again. */
_gpgme_freeze_fd ( gpg->cmd.fd ); (*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; return 0;
} }
@ -1603,3 +1730,10 @@ _gpgme_gpg_op_verify (GpgObject gpg, GpgmeData sig, GpgmeData text)
} }
return err; return err;
} }
void
_gpgme_gpg_set_io_cbs (GpgObject gpg, struct GpgmeIOCbs *io_cbs)
{
gpg->io_cbs = *io_cbs;
}

View 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_trustlist (GpgObject gpg, const char *pattern);
GpgmeError _gpgme_gpg_op_verify (GpgObject gpg, GpgmeData sig, GpgmeData text); GpgmeError _gpgme_gpg_op_verify (GpgObject gpg, GpgmeData sig, GpgmeData text);
GpgmeError _gpgme_gpg_spawn (GpgObject gpg, void *opaque); GpgmeError _gpgme_gpg_spawn (GpgObject gpg, void *opaque);
void _gpgme_gpg_set_io_cbs (GpgObject gpg, struct GpgmeIOCbs *io_cbs);
#endif /* RUNGPG_H */ #endif /* RUNGPG_H */

View File

@ -168,27 +168,19 @@ _gpgme_sign_status_handler (GpgmeCtx ctx, GpgStatusCode code, char *args)
} }
} }
GpgmeError static GpgmeError
gpgme_op_sign_start (GpgmeCtx ctx, GpgmeData in, GpgmeData out, _gpgme_op_sign_start (GpgmeCtx ctx, int synchronous,
GpgmeData in, GpgmeData out,
GpgmeSigMode mode) GpgmeSigMode mode)
{ {
GpgmeError err = 0; GpgmeError err = 0;
fail_on_pending_request (ctx);
ctx->pending = 1;
_gpgme_release_result (ctx);
if (mode != GPGME_SIG_MODE_NORMAL if (mode != GPGME_SIG_MODE_NORMAL
&& mode != GPGME_SIG_MODE_DETACH && mode != GPGME_SIG_MODE_DETACH
&& mode != GPGME_SIG_MODE_CLEAR) && mode != GPGME_SIG_MODE_CLEAR)
return mk_error (Invalid_Value); return mk_error (Invalid_Value);
/* Create a process object. */ err = _gpgme_op_reset (ctx, synchronous);
_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) if (err)
goto leave; goto leave;
@ -231,6 +223,13 @@ gpgme_op_sign_start (GpgmeCtx ctx, GpgmeData in, GpgmeData out,
return err; 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: * gpgme_op_sign:
* @ctx: The context * @ctx: The context
@ -255,8 +254,8 @@ gpgme_op_sign_start (GpgmeCtx ctx, GpgmeData in, GpgmeData out,
GpgmeError GpgmeError
gpgme_op_sign (GpgmeCtx ctx, GpgmeData in, GpgmeData out, GpgmeSigMode mode) 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) if (!err)
gpgme_wait (ctx, &err, 1); err = _gpgme_wait_one (ctx);
return err; return err;
} }

View File

@ -164,26 +164,13 @@ gpgme_op_trustlist_start (GpgmeCtx ctx, const char *pattern, int max_level)
{ {
GpgmeError err = 0; GpgmeError err = 0;
fail_on_pending_request (ctx);
if (!pattern || !*pattern) if (!pattern || !*pattern)
return mk_error (Invalid_Value); return mk_error (Invalid_Value);
ctx->pending = 1; err = _gpgme_op_reset (ctx, 0);
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);
if (err) if (err)
goto leave; goto leave;
_gpgme_engine_set_status_handler (ctx->engine, trustlist_status_handler, ctx);
err = _gpgme_engine_set_colon_line_handler (ctx->engine, err = _gpgme_engine_set_colon_line_handler (ctx->engine,
trustlist_colon_handler, ctx); trustlist_colon_handler, ctx);
if (err) if (err)

View File

@ -282,26 +282,18 @@ _gpgme_verify_status_handler (GpgmeCtx ctx, GpgStatusCode code, char *args)
} }
} }
GpgmeError static GpgmeError
gpgme_op_verify_start (GpgmeCtx ctx, GpgmeData sig, GpgmeData text) _gpgme_op_verify_start (GpgmeCtx ctx, int synchronous,
GpgmeData sig, GpgmeData text)
{ {
int err = 0; int err = 0;
int pipemode = 0; /* !!text; use pipemode for detached sigs. */ int pipemode = 0; /* !!text; use pipemode for detached sigs. */
fail_on_pending_request (ctx);
ctx->pending = 1;
_gpgme_release_result (ctx);
if (!pipemode) if (!pipemode)
{ ; /* XXX I am not sure what should happen/not happen in
_gpgme_engine_release (ctx->engine); pipemode. */
ctx->engine = NULL;
}
if (!ctx->engine) err = _gpgme_op_reset (ctx, synchronous);
err = _gpgme_engine_new (ctx->use_cms ? GPGME_PROTOCOL_CMS
: GPGME_PROTOCOL_OpenPGP, &ctx->engine);
if (err) if (err)
goto leave; goto leave;
@ -347,6 +339,12 @@ gpgme_op_verify_start (GpgmeCtx ctx, GpgmeData sig, GpgmeData text)
return err; 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 * 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; ctx->notation = NULL;
*r_stat = GPGME_SIG_STAT_NONE; *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) if (!err)
{ {
gpgme_wait (ctx, &err, 1); err = _gpgme_wait_one (ctx);
if (!err) if (!err)
*r_stat = _gpgme_intersect_stati (ctx->result.verify); *r_stat = _gpgme_intersect_stati (ctx->result.verify);
} }

View File

@ -35,389 +35,84 @@
#include "io.h" #include "io.h"
#include "engine.h" #include "engine.h"
struct wait_item_s; struct fd_table fdt_global;
struct proc_s;
static struct proc_s *proc_queue; static GpgmeCtx *ctx_done_list;
DEFINE_STATIC_LOCK (proc_queue_lock); static int ctx_done_list_size;
static int ctx_done_list_length;
static int fd_table_size; DEFINE_STATIC_LOCK (ctx_done_list_lock);
static struct io_select_fd_s *fd_table;
DEFINE_STATIC_LOCK (fd_table_lock);
static GpgmeIdleFunc idle_function; static GpgmeIdleFunc idle_function;
struct wait_item_s
struct proc_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; struct wait_item_s *next;
int (*handler)(void*,int,int); GpgmeIOCb handler;
void *handler_value; void *handler_value;
int inbound; /* this is an inbound data handler fd */ int dir;
struct proc_s *proc; /* backlink */
int done;
int frozen; /* copy of the frozen flag from the fd_table */
}; };
static int do_select ( void );
static void run_idle (void); static void run_idle (void);
/* only to be called with a locked proc_queue */ void
static int _gpgme_fd_table_init (fd_table_t fdt)
count_running_fds (struct proc_s *proc)
{ {
struct wait_item_s *q; INIT_LOCK (fdt->lock);
int count = 0; fdt->fds = NULL;
fdt->size = 0;
for (q = proc->handler_list; q; q=q->next)
{
if (!q->frozen && !q->done)
count++;
}
return count;
}
/* only to be called with a locked proc_queue */
static void
set_process_done (struct proc_s *proc)
{
struct wait_item_s *q, *q2;
int i;
assert (proc);
DEBUG2 ("set_process_done(%p) pid=%d", proc, proc->pid);
LOCK (fd_table_lock);
for (q = proc->handler_list; q; q=q2)
{
q2 = q->next;
for (i = 0; i < fd_table_size; i++)
{
if (fd_table[i].fd != -1 && q == fd_table[i].opaque)
{
fd_table[i].opaque = NULL;
fd_table[i].fd = -1;
}
}
xfree (q);
}
UNLOCK (fd_table_lock);
proc->handler_list = NULL;
proc->done = 1;
} }
void void
_gpgme_remove_proc_from_wait_queue (int pid) _gpgme_fd_table_deinit (fd_table_t fdt)
{ {
struct proc_s *proc, *last; DESTROY_LOCK (fdt->lock);
if (fdt->fds)
DEBUG1 ("removing process %d", pid); xfree (fdt->fds);
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);
} }
/* XXX We should keep a marker and roll over for speed. */
/**
* gpgme_wait:
* @c:
* @hang:
*
* Wait for a finished request, if @c is given the function does only
* wait on a finished request for that context, otherwise it will return
* on any request. When @hang is true the function will wait, otherwise
* 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.
**/
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;
}
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 (cond && *cond)
hang = 0;
else
{
LOCK (proc_queue_lock);
for (proc = proc_queue; proc; proc = proc->next)
{
/* 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;
}
/* fixme: We should check here for hanging processes. */
if (hang)
run_idle ();
}
while (hang && (!ctx || !ctx->cancel));
if (ctx && ctx->cancel)
{
/* FIXME: Paranoia? */
ctx->cancel = 0;
ctx->pending = 0;
ctx->error = mk_error (Canceled);
}
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)
{
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;
}
/*
* called by rungpg.c to register something for select()
*/
GpgmeError GpgmeError
_gpgme_register_pipe_handler (void *opaque, _gpgme_fd_table_put (fd_table_t fdt, int fd, int dir, void *opaque, int *idx)
int (*handler)(void*,int,int),
void *handler_value,
int pid, int fd, int inbound)
{ {
GpgmeCtx ctx = opaque; int i, j;
struct wait_item_s *q; struct io_select_fd_s *new_fds;
struct proc_s *proc;
int i;
assert (opaque); LOCK (fdt->lock);
assert (handler); for (i = 0; i < fdt->size; i++)
/* 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. */ if (fdt->fds[i].fd == -1)
proc = xtrycalloc (1, sizeof *proc); break;
if (!proc) }
if (i == fdt->size)
{ {
UNLOCK (proc_queue_lock); #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); 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); fdt->fds = new_fds;
again: fdt->size += FDT_ALLOCSIZE;
for (i=0; i < fd_table_size; i++) for (j = 0; j < FDT_ALLOCSIZE; j++)
{ fdt->fds[i + j].fd = -1;
if (fd_table[i].fd == -1) }
{
fd_table[i].fd = fd; fdt->fds[i].fd = fd;
fd_table[i].for_read = inbound; fdt->fds[i].for_read = (dir == 1);
fd_table[i].for_write = !inbound; fdt->fds[i].for_write = (dir == 0);
fd_table[i].signaled = 0; fdt->fds[i].frozen = 0;
fd_table[i].frozen = 0; fdt->fds[i].signaled = 0;
fd_table[i].opaque = q; fdt->fds[i].opaque = opaque;
UNLOCK (fd_table_lock); UNLOCK (fdt->lock);
*idx = i;
return 0; return 0;
}
}
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;
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 = 1;
q = fd_table[i].opaque;
if (q)
q->frozen = 1;
DEBUG2 ("fd %d frozen (q=%p)", fd, q);
break;
}
}
UNLOCK (fd_table_lock);
}
void
_gpgme_thaw_fd (int fd)
{
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);
}
/** /**
* gpgme_register_idle: * gpgme_register_idle:
* @fnc: Callers idle function * @fnc: Callers idle function
@ -438,7 +133,6 @@ gpgme_register_idle (GpgmeIdleFunc idle)
return old_idle; return old_idle;
} }
static void static void
run_idle () run_idle ()
{ {
@ -446,3 +140,233 @@ run_idle ()
if (idle_function) if (idle_function)
idle_function (); idle_function ();
} }
/* 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)
{
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)
{
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);
}
}
UNLOCK (fdt->lock);
return any;
}
void
_gpgme_wait_event_cb (void *data, GpgmeEventIO type, void *type_data)
{
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;
}
/**
* gpgme_wait:
* @c:
* @hang:
*
* Wait for a finished request, if @c is given the function does only
* wait on a finished request for that context, otherwise it will return
* on any request. When @hang is true the function will wait, otherwise
* 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 not the given) request has finished.
**/
GpgmeCtx
gpgme_wait (GpgmeCtx ctx, GpgmeError *status, int hang)
{
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
{
if (! do_select (&fdt_global))
hang = 0;
if (cond && *cond)
hang = 0;
else
{
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)
{
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);
}
if (hang)
run_idle ();
}
while (hang && (!ctx || !ctx->cancel));
if (ctx && ctx->cancel)
{
/* FIXME: Paranoia? */
ctx->cancel = 0;
ctx->pending = 0;
ctx->error = mk_error (Canceled);
}
return ctx;
}
struct tag
{
fd_table_t fdt;
int idx;
};
void *
_gpgme_add_io_cb (void *data, int fd, int dir,
GpgmeIOCb fnc, void *fnc_data)
{
GpgmeError err;
fd_table_t fdt = (fd_table_t) (data ? data : &fdt_global);
struct wait_item_s *item;
struct tag *tag;
assert (fdt);
assert (fnc);
tag = xtrymalloc (sizeof *tag);
if (!tag)
return NULL;
tag->fdt = fdt;
/* Allocate a structure to hold info about the handler. */
item = xtrycalloc (1, sizeof *item);
if (!item)
{
xfree (tag);
return NULL;
}
item->dir = dir;
item->handler = fnc;
item->handler_value = fnc_data;
err = _gpgme_fd_table_put (fdt, fd, dir, item, &tag->idx);
if (err)
{
xfree (tag);
xfree (item);
errno = ENOMEM;
return 0;
}
return tag;
}
void
_gpgme_remove_io_cb (void *data)
{
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;
}

View File

@ -23,12 +23,24 @@
#define WAIT_H #define WAIT_H
#include "gpgme.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, void _gpgme_fd_table_init (fd_table_t fdt);
int (*handler) (void*, int, int), void _gpgme_fd_table_deinit (fd_table_t fdt);
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);
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 */ #endif /* WAIT_H */