From 2c543f6a86969e6437289471975a3e3d333b4d3c Mon Sep 17 00:00:00 2001 From: Marcus Brinkmann Date: Wed, 29 Jan 2003 15:20:58 +0000 Subject: [PATCH] doc/ 2003-01-29 Marcus Brinkmann * gpgme.texi (I/O Callback Interface): Document new even GPGME_EVENT_START. (Waiting For Completion): Document new possible return values. (I/O Callback Interface): Document return type of GpgmeIOCb. gpgme/ 2003-01-29 Marcus Brinkmann * context.h (gpgme_context_s): Remove member ERROR. * types.h (GpgmeStatusHandler): Change return type to GpgmeError. (GpgmeCommandHandler): Change return type to GpgmeError and add new argument RESULT. * gpgme.h (GpgmeIOCb): Change return type to GpgmeError. (GpgmeEventIO): New event GPGME_EVENT_START. (GpgmeIdleFunc): Remove type. (gpgme_register_idle): Remove prototype. * data.c: Include . (_gpgme_data_inbound_handler): Change return type to GpgmeError. Return any error instead ignoring it, don't close file descriptor on error. (_gpgme_data_outbound_handler): Likewise. * decrypt.c: Do not include , and . (_gpgme_decrypt_status_handler): Change return type to GpgmeError. Return error instead setting ctx->error. Return success at end of function. (gpgme_op_decrypt): Don't work around the old kludge anymore. * decrypt-verify.c (decrypt_verify_status_handler): Change return type to GpgmeError. Return possible errors. * delete.c: Do not include , , and . (delete_status_handler): Change return type to GpgmeError. Return error instead setting ctx->error. Return success at end of function. * edit.c: Do not include and . (_gpgme_edit_status_handler): Change type to GpgmeError, make static and rename to ... (edit_status_handler): ... this. Return error directly. (command_handler): Change return type to GpgmeError, add result argument. Return error directly. * encrypt.c (status_handler_finish): Remove function. (_gpgme_encrypt_status_handler): Change return type to GpgmeError. Return error directly. (_gpgme_encrypt_sym_status_handler): Likewise. * encrypt-sign.c (encrypt_sign_status_handler): Likewise. * engine-gpgsm.c (close_notify_handler): Do not signal done event anymore. (status_handler): Change return type to GpgmeError. Diddle things around a bit to return errors directly. (start): Send start event. * export.c: Do not include , and . (export_status_handler): Change return type to GpgmeError. Don't check ctx->error. * genkey.c: Do not include and . (genkey_status_handler): Change return type to GpgmeError. Don't check ctx->error. Return errors directly. * gpgme.c (_gpgme_release_result): Do not initialize ctx->error. (_gpgme_op_event_cb): Function removed. (_gpgme_op_event_cb_user): Likewise. * import.c: Do not include , and . (import_status_handler): Change return type to GpgmeError. Don't check ctx->error. * keylist.c (keylist_colon_handler, keylist_status_handler, finish_key): Change return type to GpgmeError, return error directly. * Makefile (libgpgme_la_SOURCES): Add wait-global.c, wait-private.c and wait-user.c * ops.h (test_and_allocate_result): Return error instead setting ctx->error. (_gpgme_data_inbound_handler, _gpgme_data_outbound_handler, _gpgme_verify_status_handler, _gpgme_decrypt_status_handler, _gpgme_sign_status_handler, _gpgme_encrypt_staus_handler, _gpgme_passphrase_status_handler, _gpgme_progress_status_handler): Change return type to GpgmeError. (_gpgme_passphease_command_handler): Change return type to GpgmeError and add new argument RESULT. * op-support.c: Use new callback functions, and change private data to ctx everywhere. * passphrase.c (_gpgme_passphrase_status_handler): Change return type to GpgmeError, return error directly. (_gpgme_passphrase_command_handler): Change return type to GpgmeError, add result argument. Return results accordingly. * progress.c (_gpgme_progress_status_handler): Change return type to GpgmeError, return errors directly. * rungpg.c (status_handler): Change return type to GpgmeError. Return error directly. (close_notify_handler): Don't send done event. (colon_line_handler): Change return type to GpgmeError, return errors directly. * rungpg.c (start): Send start event. * sign.c (_gpgme_sign_status_handler): Change return type to GpgmeError, return errors directly. * trustlist.c (trustlist_status_handler): Change return type to GpgmeError. Return 0. (trustlist_colon_handler): Change return type GpgmeError. Return errors directly. * verify.c (add_notation): Change return type to GpgmeError, return errors directly. (_gpgme_verify_status_handler): Likewise. * wait.h (struct fd_table): Remove lock member. (struct wait_item_s): Moved here from wait.c. (struct tag): New structure. (_gpgme_wait_event_cb): Remove prototype. (_gpgme_wait_private_event_cb, _gpgme_wait_global_event_cb, _gpgme_wait_user_add_io_cb, _gpgme_wait_user_remove_io_cb, _gpgme_wait_user_event_io_cb): New prototypes. * wait.c: Don't include . (ftd_global, ctx_done_list, ctx_done_list_size, ctx_done_list_length, ctx_done_list_lock, idle_function): Remove global variable. (gpgme_register_idle, do_select, _gpgme_wait_event_cb): Remove function. (gpgme_wait): Move to file wait-global.c. (_gpgme_add_io_cb): Take ctx as private argument, initialize ctx member in wait item and tag. (_gpgme_remove_io_cb): Take ctx from tag. Don't use FDT lock. (_gpgme_wait_one, _gpgme_wait_on_condition): Move to wait-private.c. (gpgme_fd_table_init): Don't initialize FDT->lock. (gpgme_fd_table_deinit): Don't destroy FDT->lock. (_gpgme_fd_table_put): Make static and rename to ... (fd_table_put): ... this function. Don't use FDT->lock. (struct wait_item_s): Move to wait.h. * wait-global.c: New file. * wait-private.c: New file. * wait-user.c: New file. --- NEWS | 27 ++++ doc/ChangeLog | 11 ++ doc/gpgme.texi | 56 +++---- gpgme/ChangeLog | 117 ++++++++++++++ gpgme/Makefile.am | 4 +- gpgme/context.h | 5 +- gpgme/data.c | 48 +++--- gpgme/decrypt-verify.c | 8 +- gpgme/decrypt.c | 30 ++-- gpgme/delete.c | 19 +-- gpgme/edit.c | 44 ++--- gpgme/encrypt-sign.c | 8 +- gpgme/encrypt.c | 56 +++---- gpgme/engine-gpgsm.c | 206 +++++++++++------------- gpgme/engine.c | 1 + gpgme/engine.h | 6 +- gpgme/export.c | 11 +- gpgme/genkey.c | 15 +- gpgme/gpgme.c | 43 +---- gpgme/gpgme.h | 9 +- gpgme/import.c | 9 +- gpgme/keylist.c | 74 +++------ gpgme/op-support.c | 54 +++---- gpgme/ops.h | 59 ++++--- gpgme/passphrase.c | 44 +++-- gpgme/progress.c | 47 +++--- gpgme/rungpg.c | 68 ++------ gpgme/sign.c | 13 +- gpgme/trustlist.c | 31 ++-- gpgme/types.h | 10 +- gpgme/verify.c | 40 ++--- gpgme/wait-global.c | 356 +++++++++++++++++++++++++++++++++++++++++ gpgme/wait-private.c | 153 ++++++++++++++++++ gpgme/wait-user.c | 127 +++++++++++++++ gpgme/wait.c | 324 ++++++------------------------------- gpgme/wait.h | 71 +++++--- 36 files changed, 1306 insertions(+), 898 deletions(-) create mode 100644 gpgme/wait-global.c create mode 100644 gpgme/wait-private.c create mode 100644 gpgme/wait-user.c diff --git a/NEWS b/NEWS index 8a7299b4..2e2c0e9f 100644 --- a/NEWS +++ b/NEWS @@ -6,11 +6,38 @@ Noteworthy changes in version 0.4.1 (unreleased) * gpgme_op_verify and gpgme_op_decrypt_verify don't return a status summary anymore. Use gpgme_get_sig_status to retrieve the individual stati. + * GpgmeIOCb changed from a void function to a function returning a + GpgmeError value. However, it will always return 0, so you can + safely ignore the return value. + + * A new I/O callback event GPGME_EVENT_START has been added. The new + requirement is that you must wait until this event until you are + allowed to call the I/O callback handlers previously registered for + this context operation. Calling I/O callback functions for this + context operation before the start event happened is unsafe because + it can lead to race conditions in a multi-threaded environment. + + * The idle function feature has been removed. It was not precisely + defined in a multi-threaded environment and is obsoleted by the + user I/O callback functions. If you still need a simple way to + call something while waiting on one or multiple asynchronous + operations to complete, don't set the HANG flag in gpgme_wait (note + that this will return to your program more often than the idle + function did). + + * gpgme_wait can return NULL even if hang is true, if an error + occurs. In that case *status contains the error code. + * Interface changes relative to the 0.4.0 release: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +GpgmeIOCb CHANGED: Return type from void to GpgmeError. +GpgmeEventIO CHANGED: New event type (all numbers changed). gpgme_key_get_string_attr CHANGED: Don't handle GPGME_ATTR_IS_SECRET. gpgme_op_verify CHANGED: Drop R_STAT argument. gpgme_op_decrypt_verify CHANGED: Drop R_STAT argument. +gpgme_wait CHANGED: Can return NULL even if hang is true. +GpgmeIdleFunc REMOVED +gpgme_register_idle REMOVED ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Noteworthy changes in version 0.4.0 (2002-12-23) diff --git a/doc/ChangeLog b/doc/ChangeLog index 8a652714..9edc0bc7 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -1,3 +1,14 @@ +2003-01-29 Marcus Brinkmann + + * gpgme.texi (I/O Callback Interface): Document new even + GPGME_EVENT_START. + (Waiting For Completion): Document new possible return values. + (I/O Callback Interface): Document return type of GpgmeIOCb. + +2003-01-29 Marcus Brinkmann + + * gpgme.texi (Hooking Up Into Idle Time): Section removed. + 2002-12-24 Marcus Brinkmann * gpgme.texi (Verify): Drop R_STAT argument in gpgme_op_verify. diff --git a/doc/gpgme.texi b/doc/gpgme.texi index d3c02be8..6b822983 100644 --- a/doc/gpgme.texi +++ b/doc/gpgme.texi @@ -105,7 +105,7 @@ Preparation * Building the Source:: Compiler options to be used. * Using Automake:: Compiler options to be used the easy way. * Library Version Check:: Getting and verifying the library version. -* Multi Threading:: How GPGME can be used in an MT environment. +* Multi Threading:: How @acronym{GPGME} can be used in an MT environment. Protocols and Engines @@ -191,7 +191,6 @@ Run Control * Waiting For Completion:: Waiting until an operation is completed. * Cancelling an Operation:: Interrupting a running operation. -* Hooking Up Into Idle Time:: Doing something when nothing has to be done. * Using External Event Loops:: Advanced control over what happens when. Using External Event Loops @@ -228,7 +227,7 @@ OpenPGP and the Cryptographic Message Syntax (CMS). @node Getting Started @section Getting Started -This library documents the @acronym{GPGME} library programming +This manual documents the @acronym{GPGME} library programming interface. All functions and data types provided by the library are explained. @@ -315,7 +314,7 @@ of the library are verified. * Building the Source:: Compiler options to be used. * Using Automake:: Compiler options to be used the easy way. * Library Version Check:: Getting and verifying the library version. -* Multi Threading:: How GPGME can be used in an MT environment. +* Multi Threading:: How @acronym{GPGME} can be used in an MT environment. @end menu @@ -541,12 +540,13 @@ initialize_gpgme (void) Any @code{GpgmeData}, @code{GpgmeCtx} and @code{GpgmeRecipients} object must only be accessed by one thread at a time. If multiple threads want to deal with the same object, the caller has to make sure -that operations on this object are fully synchronized. +that operations on that object are fully synchronized. @item Only one thread at any time is allowed to call @code{gpgme_wait}. If multiple threads call this function, the caller must make sure that -all invocations are fully synchronized. +all invocations are fully synchronized. It is safe to start +asynchronous operations while a thread is running in gpgme_wait. @end itemize @@ -3012,7 +3012,6 @@ time. @menu * Waiting For Completion:: Waiting until an operation is completed. * Cancelling an Operation:: Interrupting a running operation. -* Hooking Up Into Idle Time:: Doing something when nothing has to be done. * Using External Event Loops:: Advanced control over what happens when. @end menu @@ -3050,10 +3049,14 @@ and trust item list operations, do not affect @code{gpgme_wait}. In a multi-threaded environment, only one thread should ever call @code{gpgme_wait} at any time, irregardless if @var{ctx} is specified or not. This means that all calls to this function should be fully -synchronized by locking primitives. +synchronized by locking primitives. It is safe to start asynchronous +operations while a thread is running in @code{gpgme_wait}. The function returns the @var{ctx} of the context which has finished -the operation. +the operation. If @var{hang} is false, and the timeout expires, +@code{NULL} is returned and @code{*status} will be set to 0. If an +error occurs, @code{NULL} is returned and the error is returned in +@code{*status}. @end deftypefun @@ -3073,30 +3076,6 @@ callback. @end deftypefun -@node Hooking Up Into Idle Time -@subsection Hooking Up Into Idle Time -@cindex idle time -@cindex idle function - -@deftp {Data type} {void (*GpgmeIdleFunc) (void)} -@tindex GpgmeIdleFunc -The @code{GpgmeIdleFunc} type is the type of functions usable as -an idle function that can be registered with @code{gpgme_register_idle}. -@end deftp - -@deftypefun GpgmeIdleFunc gpgme_register_idle (@w{GpgmeIdleFunc @var{idle}}) -The function @code{gpgme_register_idle} can be used to register -@var{idle} as the idle function. - -@var{idle} will be called whenever @acronym{GPGME} thinks that it is -idle and time can better be spent elsewhere. Setting @var{idle} to -@code{NULL} disables use of the idle function (this is the default). - -The function returns the old idle function, or @code{NULL} if none was -registered yet. -@end deftypefun - - @node Using External Event Loops @subsection Using External Event Loops @cindex event loop, external @@ -3139,7 +3118,7 @@ programs. @node I/O Callback Interface @subsubsection I/O Callback Interface -@deftp {Data type} {void (*GpgmeIOCb) (@w{void *@var{data}}, @w{int @var{fd}})} +@deftp {Data type} {GpgmeError (*GpgmeIOCb) (@w{void *@var{data}}, @w{int @var{fd}})} @tindex GpgmeIOCb The @code{GpgmeIOCb} type is the type of functions which @acronym{GPGME} wants to register as I/O callback handlers using the @@ -3149,6 +3128,9 @@ The @code{GpgmeIOCb} type is the type of functions which callback handler is registered, and should be passed through to the handler when it is invoked by the user because it noticed activity on the file descriptor @var{fd}. + +The callback handler always returns @code{0}, but you should consider +the return value to be reserved for later use. @end deftp @deftp {Data type} {GpgmeError (*GpgmeRegisterIOCb) (@w{void *@var{data}}, @w{int @var{fd}}, @w{int @var{dir}}, @w{GpgmeIOCb @var{fnc}}, @w{void *@var{fnc_data}}, @w{void **@var{tag}})} @@ -3198,6 +3180,12 @@ reported to the user by @acronym{GPGME} as a consequence of an I/O operation. The following events are defined: @table @code +@item GPGME_EVENT_START +The operation is fully initialized now, and you can start to run the +registered I/O callback handlers now. Note that registered I/O +callback handlers must not be run before this event is signalled. +@var{type_data} is @code{NULL} and reserved for later use. + @item GPGME_EVENT_DONE The operation is finished, the last I/O callback for this operation was removed. The accompanying @var{type_data} points to a diff --git a/gpgme/ChangeLog b/gpgme/ChangeLog index df950b09..11498b19 100644 --- a/gpgme/ChangeLog +++ b/gpgme/ChangeLog @@ -1,5 +1,122 @@ 2003-01-29 Marcus Brinkmann + * context.h (gpgme_context_s): Remove member ERROR. + * types.h (GpgmeStatusHandler): Change return type to GpgmeError. + (GpgmeCommandHandler): Change return type to GpgmeError and add + new argument RESULT. + * gpgme.h (GpgmeIOCb): Change return type to GpgmeError. + (GpgmeEventIO): New event GPGME_EVENT_START. + (GpgmeIdleFunc): Remove type. + (gpgme_register_idle): Remove prototype. + * data.c: Include . + (_gpgme_data_inbound_handler): Change return type to GpgmeError. + Return any error instead ignoring it, don't close file descriptor + on error. + (_gpgme_data_outbound_handler): Likewise. + * decrypt.c: Do not include , and . + (_gpgme_decrypt_status_handler): Change return type to GpgmeError. + Return error instead setting ctx->error. Return success at end of + function. + (gpgme_op_decrypt): Don't work around the old kludge anymore. + * decrypt-verify.c (decrypt_verify_status_handler): Change return + type to GpgmeError. Return possible errors. + * delete.c: Do not include , , and + . + (delete_status_handler): Change return type to GpgmeError. Return + error instead setting ctx->error. Return success at end of + function. + * edit.c: Do not include and . + (_gpgme_edit_status_handler): Change type to GpgmeError, + make static and rename to ... + (edit_status_handler): ... this. Return error directly. + (command_handler): Change return type to GpgmeError, add result + argument. Return error directly. + * encrypt.c (status_handler_finish): Remove function. + (_gpgme_encrypt_status_handler): Change return type to GpgmeError. + Return error directly. + (_gpgme_encrypt_sym_status_handler): Likewise. + * encrypt-sign.c (encrypt_sign_status_handler): Likewise. + * engine-gpgsm.c (close_notify_handler): Do not signal done event + anymore. + (status_handler): Change return type to GpgmeError. Diddle things + around a bit to return errors directly. + (start): Send start event. + * export.c: Do not include , and . + (export_status_handler): Change return type to GpgmeError. Don't + check ctx->error. + * genkey.c: Do not include and . + (genkey_status_handler): Change return type to GpgmeError. Don't + check ctx->error. Return errors directly. + * gpgme.c (_gpgme_release_result): Do not initialize ctx->error. + (_gpgme_op_event_cb): Function removed. + (_gpgme_op_event_cb_user): Likewise. + * import.c: Do not include , and . + (import_status_handler): Change return type to GpgmeError. Don't + check ctx->error. + * keylist.c (keylist_colon_handler, keylist_status_handler, finish_key): + Change return type to GpgmeError, return error directly. + * Makefile (libgpgme_la_SOURCES): Add wait-global.c, + wait-private.c and wait-user.c + * ops.h (test_and_allocate_result): Return error instead setting + ctx->error. + (_gpgme_data_inbound_handler, _gpgme_data_outbound_handler, + _gpgme_verify_status_handler, _gpgme_decrypt_status_handler, + _gpgme_sign_status_handler, _gpgme_encrypt_staus_handler, + _gpgme_passphrase_status_handler, _gpgme_progress_status_handler): + Change return type to GpgmeError. + (_gpgme_passphease_command_handler): Change return type to + GpgmeError and add new argument RESULT. + * op-support.c: Use new callback functions, and change private + data to ctx everywhere. + * passphrase.c (_gpgme_passphrase_status_handler): Change return + type to GpgmeError, return error directly. + (_gpgme_passphrase_command_handler): Change return type to + GpgmeError, add result argument. Return results accordingly. + * progress.c (_gpgme_progress_status_handler): Change return type + to GpgmeError, return errors directly. + * rungpg.c (status_handler): Change return type to GpgmeError. + Return error directly. + (close_notify_handler): Don't send done event. + (colon_line_handler): Change return type to GpgmeError, return + errors directly. + * rungpg.c (start): Send start event. + * sign.c (_gpgme_sign_status_handler): Change return type to + GpgmeError, return errors directly. + * trustlist.c (trustlist_status_handler): Change return type to + GpgmeError. Return 0. + (trustlist_colon_handler): Change return type GpgmeError. Return + errors directly. + * verify.c (add_notation): Change return type to GpgmeError, + return errors directly. + (_gpgme_verify_status_handler): Likewise. + * wait.h (struct fd_table): Remove lock member. + (struct wait_item_s): Moved here from wait.c. + (struct tag): New structure. + (_gpgme_wait_event_cb): Remove prototype. + (_gpgme_wait_private_event_cb, _gpgme_wait_global_event_cb, + _gpgme_wait_user_add_io_cb, _gpgme_wait_user_remove_io_cb, + _gpgme_wait_user_event_io_cb): New prototypes. + * wait.c: Don't include . + (ftd_global, ctx_done_list, ctx_done_list_size, + ctx_done_list_length, ctx_done_list_lock, idle_function): Remove + global variable. + (gpgme_register_idle, do_select, _gpgme_wait_event_cb): Remove + function. + (gpgme_wait): Move to file wait-global.c. + (_gpgme_add_io_cb): Take ctx as private argument, initialize ctx + member in wait item and tag. + (_gpgme_remove_io_cb): Take ctx from tag. Don't use FDT lock. + (_gpgme_wait_one, _gpgme_wait_on_condition): Move to + wait-private.c. + (gpgme_fd_table_init): Don't initialize FDT->lock. + (gpgme_fd_table_deinit): Don't destroy FDT->lock. + (_gpgme_fd_table_put): Make static and rename to ... + (fd_table_put): ... this function. Don't use FDT->lock. + (struct wait_item_s): Move to wait.h. + * wait-global.c: New file. + * wait-private.c: New file. + * wait-user.c: New file. + * key.c (gpgme_key_sig_get_string_attr): Use validity_to_string instead otrust_to_string to calculate validity. diff --git a/gpgme/Makefile.am b/gpgme/Makefile.am index aa9d33d0..12d05f1b 100644 --- a/gpgme/Makefile.am +++ b/gpgme/Makefile.am @@ -72,7 +72,9 @@ libgpgme_la_SOURCES = \ gpgme.h types.h util.h conversion.c context.h ops.h \ data.h data.c data-fd.c data-stream.c data-mem.c data-user.c \ data-compat.c \ - recipient.c signers.c wait.c wait.h op-support.c \ + recipient.c signers.c \ + wait.c wait-global.c wait-private.c wait-user.c wait.h \ + op-support.c \ encrypt.c encrypt-sign.c decrypt.c decrypt-verify.c verify.c \ sign.c passphrase.c progress.c \ key.h key.c keylist.c trustlist.c \ diff --git a/gpgme/context.h b/gpgme/context.h index ced7a793..f16af04d 100644 --- a/gpgme/context.h +++ b/gpgme/context.h @@ -49,9 +49,6 @@ struct gpgme_context_s int use_cms; - /* At some points we need to remember an error which we can't report - immediately. */ - GpgmeError error; /* Cancel operation requested. */ int cancel; @@ -105,7 +102,7 @@ struct gpgme_context_s void *progress_cb_value; /* A list of file descriptors in active use by the current - (synchronous) operation. */ + operation. */ struct fd_table fdt; struct GpgmeIOCbs io_cbs; diff --git a/gpgme/data.c b/gpgme/data.c index b1e83074..ccec8132 100644 --- a/gpgme/data.c +++ b/gpgme/data.c @@ -22,6 +22,7 @@ #endif #include +#include #include #include #include @@ -158,65 +159,58 @@ gpgme_data_set_encoding (GpgmeData dh, GpgmeDataEncoding enc) /* Functions to support the wait interface. */ -void +GpgmeError _gpgme_data_inbound_handler (void *opaque, int fd) { - GpgmeData dh = opaque; - GpgmeError err; + GpgmeData dh = (GpgmeData) opaque; char buffer[BUFFER_SIZE]; ssize_t buflen; + assert (dh); + buflen = read (fd, buffer, BUFFER_SIZE); - if (buflen <= 0) + if (buflen < 0) + return mk_error (File_Error); + if (buflen == 0) { _gpgme_io_close (fd); - return; + return 0; } - err = _gpgme_data_append (dh, buffer, buflen); - if (err) - { - DEBUG1 ("_gpgme_data_append failed: %s\n", gpgme_strerror (err)); - /* Fixme: we should close the pipe or read it to /dev/null in - * this case. Returning EOF is not sufficient */ - _gpgme_io_close (fd); /* XXX ??? */ - return; - } - return; + return _gpgme_data_append (dh, buffer, buflen); } -void +GpgmeError _gpgme_data_outbound_handler (void *opaque, int fd) { - GpgmeData dh = opaque; + GpgmeData dh = (GpgmeData) opaque; ssize_t nwritten; + assert (dh); + if (!dh->pending_len) { ssize_t amt = gpgme_data_read (dh, dh->pending, BUFFER_SIZE); - if (amt <= 0) + if (amt < 0) + return mk_error (File_Error); + if (amt == 0) { _gpgme_io_close (fd); - return; + return 0; } dh->pending_len = amt; } nwritten = _gpgme_io_write (fd, dh->pending, dh->pending_len); if (nwritten == -1 && errno == EAGAIN ) - return; + return 0; if (nwritten <= 0) - { - DEBUG3 ("_gpgme_data_outbound_handler (%d): write failed (n=%d): %s", - fd, nwritten, strerror (errno)); - _gpgme_io_close (fd); - return; - } + return mk_error (File_Error); if (nwritten < dh->pending_len) memmove (dh->pending, dh->pending + nwritten, dh->pending_len - nwritten); dh->pending_len -= nwritten; - return; + return 0; } diff --git a/gpgme/decrypt-verify.c b/gpgme/decrypt-verify.c index f49bb726..8a93f1e7 100644 --- a/gpgme/decrypt-verify.c +++ b/gpgme/decrypt-verify.c @@ -31,11 +31,13 @@ #include "ops.h" -static void +static GpgmeError decrypt_verify_status_handler (GpgmeCtx ctx, GpgmeStatusCode code, char *args) { - _gpgme_decrypt_status_handler (ctx, code, args); - _gpgme_verify_status_handler (ctx, code, args); + GpgmeError err = _gpgme_decrypt_status_handler (ctx, code, args); + if (err) + return err; + return _gpgme_verify_status_handler (ctx, code, args); } diff --git a/gpgme/decrypt.c b/gpgme/decrypt.c index 7438b374..7f3189eb 100644 --- a/gpgme/decrypt.c +++ b/gpgme/decrypt.c @@ -21,10 +21,7 @@ #if HAVE_CONFIG_H #include #endif -#include #include -#include -#include #include "util.h" #include "context.h" @@ -87,24 +84,25 @@ skip_token (const char *string, size_t *next) } -void +GpgmeError _gpgme_decrypt_status_handler (GpgmeCtx ctx, GpgmeStatusCode code, char *args) { + GpgmeError err; size_t n; - _gpgme_passphrase_status_handler (ctx, code, args); + err = _gpgme_passphrase_status_handler (ctx, code, args); + if (err) + return err; - if (ctx->error) - return; test_and_allocate_result (ctx, decrypt); switch (code) { case GPGME_STATUS_EOF: if (ctx->result.decrypt->failed) - ctx->error = mk_error (Decryption_Failed); + return mk_error (Decryption_Failed); else if (!ctx->result.decrypt->okay) - ctx->error = mk_error (No_Data); + return mk_error (No_Data); break; case GPGME_STATUS_DECRYPTION_OKAY: @@ -152,12 +150,12 @@ _gpgme_decrypt_status_handler (GpgmeCtx ctx, GpgmeStatusCode code, char *args) } } break; - default: - /* Ignore all other codes. */ break; } + + return 0; } @@ -230,15 +228,5 @@ gpgme_op_decrypt (GpgmeCtx ctx, GpgmeData in, GpgmeData out) _gpgme_decrypt_status_handler); if (!err) err = _gpgme_wait_one (ctx); - - /* Work around the kludge in engine-gpgsm.c */ - if (err == GPGME_Invalid_Engine && ctx->error) - { - if (ctx->result.decrypt->failed) - err = mk_error (Decryption_Failed); - else if (!ctx->result.decrypt->okay) - err = mk_error (No_Data); - } - return err; } diff --git a/gpgme/delete.c b/gpgme/delete.c index a3ed47c5..e29ad8e0 100644 --- a/gpgme/delete.c +++ b/gpgme/delete.c @@ -1,4 +1,4 @@ -/* delete.c - delete a key +/* delete.c - Delete a key. Copyright (C) 2001, 2002 g10 Code GmbH This file is part of GPGME. @@ -20,11 +20,7 @@ #if HAVE_CONFIG_H #include #endif -#include #include -#include -#include -#include #include "util.h" #include "context.h" @@ -56,11 +52,9 @@ _gpgme_release_delete_result (DeleteResult result) } -static void +static GpgmeError delete_status_handler (GpgmeCtx ctx, GpgmeStatusCode code, char *args) { - if (ctx->error) - return; test_and_allocate_result (ctx, delete); switch (code) @@ -71,15 +65,15 @@ delete_status_handler (GpgmeCtx ctx, GpgmeStatusCode code, char *args) case DELETE_No_Problem: break; case DELETE_No_Such_Key: - ctx->error = mk_error(Invalid_Key); + return mk_error(Invalid_Key); break; case DELETE_Must_Delete_Secret_Key: - ctx->error = mk_error(Conflict); + return mk_error(Conflict); break; case DELETE_Ambiguous_Specification: /* XXX Need better error value. Fall through. */ default: - ctx->error = mk_error(General_Error); + return mk_error(General_Error); break; } break; @@ -89,9 +83,9 @@ delete_status_handler (GpgmeCtx ctx, GpgmeStatusCode code, char *args) break; default: - /* Ignore all other codes. */ break; } + return 0; } @@ -120,6 +114,7 @@ _gpgme_op_delete_start (GpgmeCtx ctx, int synchronous, return err; } + GpgmeError gpgme_op_delete_start (GpgmeCtx ctx, const GpgmeKey key, int allow_secret) { diff --git a/gpgme/edit.c b/gpgme/edit.c index a12486c6..219e657e 100644 --- a/gpgme/edit.c +++ b/gpgme/edit.c @@ -1,4 +1,4 @@ -/* edit.c - key edit functions +/* edit.c - Key edit functions. Copyright (C) 2002 g10 Code GmbH This file is part of GPGME. @@ -20,9 +20,7 @@ #if HAVE_CONFIG_H #include #endif -#include #include -#include #include #include "util.h" @@ -44,31 +42,38 @@ _gpgme_release_edit_result (EditResult result) free (result); } -void -_gpgme_edit_status_handler (GpgmeCtx ctx, GpgmeStatusCode status, char *args) + +static GpgmeError +edit_status_handler (GpgmeCtx ctx, GpgmeStatusCode status, char *args) { - _gpgme_passphrase_status_handler (ctx, status, args); + GpgmeError err = _gpgme_passphrase_status_handler (ctx, status, args); + if (err) + return err; - if (ctx->error) - return; - - ctx->error = (*ctx->result.edit->fnc) (ctx->result.edit->fnc_value, status, args, NULL); + return (*ctx->result.edit->fnc) (ctx->result.edit->fnc_value, status, + args, NULL); } -static const char * -command_handler (void *opaque, GpgmeStatusCode status, const char *args) -{ - GpgmeCtx ctx = opaque; - const char *result; - result = _gpgme_passphrase_command_handler (ctx, status, args); +static GpgmeError +command_handler (void *opaque, GpgmeStatusCode status, const char *args, + const char **result) +{ + GpgmeError err; + GpgmeCtx ctx = opaque; + + err = _gpgme_passphrase_command_handler (ctx, status, args, result); + if (err) + return err; if (!result) - ctx->error = (*ctx->result.edit->fnc) (ctx->result.edit->fnc_value, status, args, &result); + err = (*ctx->result.edit->fnc) (ctx->result.edit->fnc_value, status, + args, result); - return result; + return err; } + static GpgmeError _gpgme_op_edit_start (GpgmeCtx ctx, int synchronous, GpgmeKey key, @@ -106,8 +111,7 @@ _gpgme_op_edit_start (GpgmeCtx ctx, int synchronous, if (err) goto leave; - _gpgme_engine_set_status_handler (ctx->engine, _gpgme_edit_status_handler, - ctx); + _gpgme_engine_set_status_handler (ctx->engine, edit_status_handler, ctx); _gpgme_engine_set_verbosity (ctx->engine, ctx->verbosity); diff --git a/gpgme/encrypt-sign.c b/gpgme/encrypt-sign.c index 2ce43f05..cc55a146 100644 --- a/gpgme/encrypt-sign.c +++ b/gpgme/encrypt-sign.c @@ -32,11 +32,13 @@ #include "ops.h" -static void +static GpgmeError encrypt_sign_status_handler (GpgmeCtx ctx, GpgmeStatusCode code, char *args) { - _gpgme_encrypt_status_handler (ctx, code, args); - _gpgme_sign_status_handler (ctx, code, args); + GpgmeError err = _gpgme_encrypt_status_handler (ctx, code, args); + if (err) + return err; + return _gpgme_sign_status_handler (ctx, code, args); } diff --git a/gpgme/encrypt.c b/gpgme/encrypt.c index 03131fa4..98e08fd8 100644 --- a/gpgme/encrypt.c +++ b/gpgme/encrypt.c @@ -1,4 +1,4 @@ -/* encrypt.c - encrypt functions +/* encrypt.c - Encrypt functions. Copyright (C) 2000 Werner Koch (dd9jn) Copyright (C) 2001, 2002 g10 Code GmbH @@ -54,11 +54,8 @@ _gpgme_release_encrypt_result (EncryptResult result) free (result); } -/* - * Parse the args and save the information - * in an XML structure. - * With args of NULL the xml structure is closed. - */ +/* Parse the args and save the information in an XML structure. With + args of NULL the xml structure is closed. */ static void append_xml_encinfo (GpgmeData *rdh, char *args) { @@ -100,38 +97,24 @@ append_xml_encinfo (GpgmeData *rdh, char *args) } -static void -status_handler_finish (GpgmeCtx ctx) -{ - if (ctx->result.encrypt->xmlinfo) - { - append_xml_encinfo (&ctx->result.encrypt->xmlinfo, NULL); - _gpgme_set_op_info (ctx, ctx->result.encrypt->xmlinfo); - ctx->result.encrypt->xmlinfo = NULL; - } - if (ctx->error) - ; /* already set by kludge in engine-gpgsm */ - else if (ctx->result.encrypt->no_valid_recipients) - ctx->error = mk_error (No_Recipients); - else if (ctx->result.encrypt->invalid_recipients) - ctx->error = mk_error (Invalid_Recipients); -} - -void +GpgmeError _gpgme_encrypt_status_handler (GpgmeCtx ctx, GpgmeStatusCode code, char *args) { - if (ctx->error) - { - if (ctx->result.encrypt) /* check that we have allocated it. */ - status_handler_finish (ctx); - return; - } test_and_allocate_result (ctx, encrypt); switch (code) { case GPGME_STATUS_EOF: - status_handler_finish (ctx); + if (ctx->result.encrypt->xmlinfo) + { + append_xml_encinfo (&ctx->result.encrypt->xmlinfo, NULL); + _gpgme_set_op_info (ctx, ctx->result.encrypt->xmlinfo); + ctx->result.encrypt->xmlinfo = NULL; + } + if (ctx->result.encrypt->no_valid_recipients) + return mk_error (No_Recipients); + else if (ctx->result.encrypt->invalid_recipients) + return mk_error (Invalid_Recipients); break; case GPGME_STATUS_INV_RECP: @@ -146,13 +129,15 @@ _gpgme_encrypt_status_handler (GpgmeCtx ctx, GpgmeStatusCode code, char *args) default: break; } + return 0; } -void -_gpgme_encrypt_sym_status_handler (GpgmeCtx ctx, GpgmeStatusCode code, char *args) +GpgmeError +_gpgme_encrypt_sym_status_handler (GpgmeCtx ctx, GpgmeStatusCode code, + char *args) { - _gpgme_passphrase_status_handler (ctx, code, args); + return _gpgme_passphrase_status_handler (ctx, code, args); } @@ -202,7 +187,8 @@ _gpgme_op_encrypt_start (GpgmeCtx ctx, int synchronous, goto leave; } - err = _gpgme_engine_op_encrypt (ctx->engine, recp, plain, ciph, ctx->use_armor); + err = _gpgme_engine_op_encrypt (ctx->engine, recp, plain, ciph, + ctx->use_armor); leave: if (err) diff --git a/gpgme/engine-gpgsm.c b/gpgme/engine-gpgsm.c index 6b29de7e..f286af92 100644 --- a/gpgme/engine-gpgsm.c +++ b/gpgme/engine-gpgsm.c @@ -125,49 +125,32 @@ static void close_notify_handler (int fd, void *opaque) { GpgsmObject gpgsm = opaque; - int possibly_done = 0; assert (fd != -1); if (gpgsm->status_cb.fd == fd) { if (gpgsm->status_cb.tag) - { - (*gpgsm->io_cbs.remove) (gpgsm->status_cb.tag); - possibly_done = 1; - } + (*gpgsm->io_cbs.remove) (gpgsm->status_cb.tag); 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->io_cbs.remove) (gpgsm->input_cb.tag); 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->io_cbs.remove) (gpgsm->output_cb.tag); 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->io_cbs.remove) (gpgsm->message_cb.tag); 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); } @@ -677,68 +660,57 @@ parse_status (const char *name) } -static void +static GpgmeError status_handler (void *opaque, int fd) { - AssuanError err; + AssuanError assuan_err; + GpgmeError err = 0; GpgsmObject gpgsm = opaque; char *line; size_t linelen; do { - err = assuan_read_line (gpgsm->assuan_ctx, &line, &linelen); - - if (err - || (linelen >= 2 - && line[0] == 'O' && line[1] == 'K' - && (line[2] == '\0' || line[2] == ' ')) - || (linelen >= 3 - && line[0] == 'E' && line[1] == 'R' && line[2] == 'R' - && (line[3] == '\0' || line[3] == ' '))) + assuan_err = assuan_read_line (gpgsm->assuan_ctx, &line, &linelen); + if (assuan_err) + { + /* Try our best to terminate the connection friendly. */ + assuan_write_line (gpgsm->assuan_ctx, "BYE"); + err = map_assuan_error (assuan_err); + } + else if (linelen >= 3 + && line[0] == 'E' && line[1] == 'R' && line[2] == 'R' + && (line[3] == '\0' || line[3] == ' ')) + { + if (line[3] == ' ') + err = map_assuan_error (atoi (&line[4])); + else + err = mk_error (General_Error); + } + else if (linelen >= 2 + && line[0] == 'O' && line[1] == 'K' + && (line[2] == '\0' || line[2] == ' ')) { - /* XXX: If an error occured, find out what happened, then - save the error value before running the status handler - (so it takes precedence). */ - if (!err && line[0] == 'E' && line[3] == ' ') - { - err = map_assuan_error (atoi (&line[4])); - if (!err) - err = mk_error (General_Error); - } - if (err) - { - /* XXX Kludge ahead. We really, really, really must not - make use of status.fnc_value. */ - GpgmeCtx ctx = (GpgmeCtx) gpgsm->status.fnc_value; - if (!ctx->error) - ctx->error = err; - } - if (gpgsm->status.fnc) - gpgsm->status.fnc (gpgsm->status.fnc_value, GPGME_STATUS_EOF, ""); - if (gpgsm->colon.fnc && gpgsm->colon.any ) + err = gpgsm->status.fnc (gpgsm->status.fnc_value, + GPGME_STATUS_EOF, ""); + + if (!err && gpgsm->colon.fnc && gpgsm->colon.any ) { - /* We must tell a colon fucntion about the EOF. We do + /* We must tell a colon function about the EOF. We do this only when we have seen any data lines. Note that this inlined use of colon data lines will eventually be changed into using a regular data channel. */ gpgsm->colon.any = 0; - gpgsm->colon.fnc (gpgsm->colon.fnc_value, NULL); + err = gpgsm->colon.fnc (gpgsm->colon.fnc_value, NULL); } - - /* XXX: Try our best to terminate the connection. */ - if (err) - assuan_write_line (gpgsm->assuan_ctx, "BYE"); - _gpgme_io_close (gpgsm->status_cb.fd); - return; + return err; } - - if (linelen > 2 - && line[0] == 'D' && line[1] == ' ' - && gpgsm->colon.fnc) + else if (linelen > 2 + && line[0] == 'D' && line[1] == ' ' + && gpgsm->colon.fnc) { /* We are using the colon handler even for plain inline data - strange name for that function but for historic reasons @@ -756,59 +728,64 @@ status_handler (void *opaque, int fd) < *alinelen + linelen + 1) { unsigned char *newline = realloc (*aline, - *alinelen + linelen + 1); + *alinelen + linelen + 1); if (!newline) - { - _gpgme_io_close (gpgsm->status_cb.fd); - return; - } - *aline = newline; - gpgsm->colon.attic.linesize += linelen + 1; - } - - dst = *aline + *alinelen; - - while (src < end) - { - if (*src == '%' && src + 2 < end) - { - /* Handle escaped characters. */ - ++src; - *dst = xtoi_2 (src); - (*alinelen)++; - src += 2; - } - else - { - *dst = *src++; - (*alinelen)++; - } - - if (*dst == '\n') - { - /* Terminate the pending line, pass it to the colon - handler and reset it. */ - - gpgsm->colon.any = 1; - if (*alinelen > 1 && *(dst - 1) == '\r') - dst--; - *dst = '\0'; - - /* FIXME How should we handle the return code? */ - gpgsm->colon.fnc (gpgsm->colon.fnc_value, *aline); - dst = *aline; - *alinelen = 0; - } + err = mk_error (Out_Of_Core); else - dst++; - } + { + *aline = newline; + gpgsm->colon.attic.linesize += linelen + 1; + } + } + if (!err) + { + dst = *aline + *alinelen; + + while (!err && src < end) + { + if (*src == '%' && src + 2 < end) + { + /* Handle escaped characters. */ + ++src; + *dst = xtoi_2 (src); + (*alinelen)++; + src += 2; + } + else + { + *dst = *src++; + (*alinelen)++; + } + + if (*dst == '\n') + { + /* Terminate the pending line, pass it to the colon + handler and reset it. */ + + gpgsm->colon.any = 1; + if (*alinelen > 1 && *(dst - 1) == '\r') + dst--; + *dst = '\0'; + + /* FIXME How should we handle the return code? */ + err = gpgsm->colon.fnc (gpgsm->colon.fnc_value, *aline); + if (!err) + { + dst = *aline; + *alinelen = 0; + } + } + else + dst++; + } + } } else if (linelen > 2 - && line[0] == 'S' && line[1] == ' ') + && line[0] == 'S' && line[1] == ' ') { char *rest; GpgmeStatusCode r; - + rest = strchr (line + 2, ' '); if (!rest) rest = line + linelen; /* set to an empty string */ @@ -820,13 +797,16 @@ status_handler (void *opaque, int fd) if (r >= 0) { if (gpgsm->status.fnc) - gpgsm->status.fnc (gpgsm->status.fnc_value, r, rest); + err = gpgsm->status.fnc (gpgsm->status.fnc_value, r, rest); } else fprintf (stderr, "[UNKNOWN STATUS]%s %s", line + 2, rest); } } - while (assuan_pending_line (gpgsm->assuan_ctx)); + while (!err && assuan_pending_line (gpgsm->assuan_ctx)); + + _gpgme_io_close (gpgsm->status_cb.fd); + return err; } @@ -863,6 +843,8 @@ start (GpgsmObject gpgsm, const char *command) if (!err) err = assuan_write_line (gpgsm->assuan_ctx, command); + (*gpgsm->io_cbs.event) (gpgsm->io_cbs.event_priv, GPGME_EVENT_START, NULL); + return err; } diff --git a/gpgme/engine.c b/gpgme/engine.c index e96af138..dff6e544 100644 --- a/gpgme/engine.c +++ b/gpgme/engine.c @@ -436,6 +436,7 @@ _gpgme_engine_set_io_cbs (EngineObject engine, (*engine->ops->set_io_cbs) (engine->engine, io_cbs); } + void _gpgme_engine_io_event (EngineObject engine, GpgmeEventIO type, void *type_data) diff --git a/gpgme/engine.h b/gpgme/engine.h index 54af330c..82baedc7 100644 --- a/gpgme/engine.h +++ b/gpgme/engine.h @@ -35,7 +35,8 @@ const char *_gpgme_engine_get_info (GpgmeProtocol proto); GpgmeError _gpgme_engine_new (GpgmeProtocol proto, EngineObject *r_engine); void _gpgme_engine_release (EngineObject engine); void _gpgme_engine_set_status_handler (EngineObject engine, - GpgmeStatusHandler fnc, void *fnc_value); + GpgmeStatusHandler fnc, + void *fnc_value); GpgmeError _gpgme_engine_set_command_handler (EngineObject engine, GpgmeCommandHandler fnc, void *fnc_value, @@ -80,7 +81,8 @@ GpgmeError _gpgme_engine_op_sign (EngineObject engine, GpgmeData in, GpgmeError _gpgme_engine_op_trustlist (EngineObject engine, const char *pattern); GpgmeError _gpgme_engine_op_verify (EngineObject engine, GpgmeData sig, - GpgmeData signed_text, GpgmeData plaintext); + GpgmeData signed_text, + GpgmeData plaintext); void _gpgme_engine_set_io_cbs (EngineObject engine, struct GpgmeIOCbs *io_cbs); diff --git a/gpgme/export.c b/gpgme/export.c index 93cd098c..796ae12b 100644 --- a/gpgme/export.c +++ b/gpgme/export.c @@ -1,4 +1,4 @@ -/* export.c - encrypt functions +/* export.c - Encrypt functions. Copyright (C) 2000 Werner Koch (dd9jn) Copyright (C) 2001, 2002 g10 Code GmbH @@ -21,24 +21,19 @@ #if HAVE_CONFIG_H #include #endif -#include #include -#include -#include #include "util.h" #include "context.h" #include "ops.h" -static void +static GpgmeError export_status_handler (GpgmeCtx ctx, GpgmeStatusCode code, char *args) { - if (ctx->error) - return; - DEBUG2 ("export_status: code=%d args=`%s'\n", code, args); /* FIXME: Need to do more */ + return 0; } diff --git a/gpgme/genkey.c b/gpgme/genkey.c index a4633da8..9ac85959 100644 --- a/gpgme/genkey.c +++ b/gpgme/genkey.c @@ -21,10 +21,8 @@ #if HAVE_CONFIG_H #include #endif -#include #include #include -#include #include "util.h" #include "context.h" @@ -50,13 +48,13 @@ _gpgme_release_genkey_result (GenKeyResult result) } -static void +static GpgmeError genkey_status_handler (GpgmeCtx ctx, GpgmeStatusCode code, char *args) { - _gpgme_progress_status_handler (ctx, code, args); + GpgmeError err = _gpgme_progress_status_handler (ctx, code, args); + if (err) + return err; - if (ctx->error) - return; test_and_allocate_result (ctx, genkey); switch (code) @@ -74,7 +72,7 @@ genkey_status_handler (GpgmeCtx ctx, GpgmeStatusCode code, char *args) free (ctx->result.genkey->fpr); ctx->result.genkey->fpr = strdup (&args[2]); if (!ctx->result.genkey->fpr) - ctx->error = mk_error (Out_Of_Core); + return mk_error (Out_Of_Core); } } break; @@ -83,12 +81,13 @@ genkey_status_handler (GpgmeCtx ctx, GpgmeStatusCode code, char *args) /* FIXME: Should return some more useful error value. */ if (!ctx->result.genkey->created_primary && !ctx->result.genkey->created_sub) - ctx->error = mk_error (General_Error); + return mk_error (General_Error); break; default: break; } + return 0; } diff --git a/gpgme/gpgme.c b/gpgme/gpgme.c index aaa8e944..b4fc0366 100644 --- a/gpgme/gpgme.c +++ b/gpgme/gpgme.c @@ -1,4 +1,4 @@ -/* gpgme.c - GnuPG Made Easy +/* gpgme.c - GnuPG Made Easy. Copyright (C) 2000 Werner Koch (dd9jn) Copyright (C) 2001, 2002 g10 Code GmbH @@ -99,7 +99,6 @@ _gpgme_release_result (GpgmeCtx ctx) _gpgme_release_edit_result (ctx->result.edit); memset (&ctx->result, 0, sizeof (ctx->result)); _gpgme_set_op_info (ctx, NULL); - ctx->error = 0; } @@ -546,43 +545,3 @@ 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; - - switch (type) - { - case GPGME_EVENT_DONE: - ctx->pending = 0; - break; - - case GPGME_EVENT_NEXT_KEY: - _gpgme_op_keylist_event_cb (data, type, type_data); - break; - - case GPGME_EVENT_NEXT_TRUSTITEM: - _gpgme_op_trustlist_event_cb (data, type, type_data); - break; - } -} - -void -_gpgme_op_event_cb_user (void *data, GpgmeEventIO type, void *type_data) -{ - GpgmeCtx ctx = data; - - if (type == GPGME_EVENT_DONE) - { - ctx->pending = 0; - if (ctx->io_cbs.event) - (*ctx->io_cbs.event) (ctx->io_cbs.event_priv, type, &ctx->error); - } - else - { - if (ctx->io_cbs.event) - (*ctx->io_cbs.event) (ctx->io_cbs.event_priv, type, type_data); - } -} diff --git a/gpgme/gpgme.h b/gpgme/gpgme.h index 9546c7a1..eeb24b4c 100644 --- a/gpgme/gpgme.h +++ b/gpgme/gpgme.h @@ -424,7 +424,7 @@ char *gpgme_get_op_info (GpgmeCtx ctx, int reserved); /* Run control. */ /* The type of an I/O callback function. */ -typedef void (*GpgmeIOCb) (void *data, int fd); +typedef GpgmeError (*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: for writing, @@ -440,7 +440,8 @@ typedef GpgmeError (*GpgmeRegisterIOCb) (void *data, int fd, int dir, function. */ typedef void (*GpgmeRemoveIOCb) (void *tag); -typedef enum { GPGME_EVENT_DONE, +typedef enum { GPGME_EVENT_START, + GPGME_EVENT_DONE, GPGME_EVENT_NEXT_KEY, GPGME_EVENT_NEXT_TRUSTITEM } GpgmeEventIO; @@ -802,10 +803,6 @@ const char *gpgme_get_engine_info (void); /* Return a string describing ERR. */ const char *gpgme_strerror (GpgmeError err); -/* Register an idle function. */ -typedef void (*GpgmeIdleFunc)(void); -GpgmeIdleFunc gpgme_register_idle (GpgmeIdleFunc idle); - /* Engine support functions. */ diff --git a/gpgme/import.c b/gpgme/import.c index 9776cb7e..b08c8857 100644 --- a/gpgme/import.c +++ b/gpgme/import.c @@ -1,4 +1,4 @@ -/* import.c - encrypt functions +/* import.c - Import functions. Copyright (C) 2000 Werner Koch (dd9jn) Copyright (C) 2001, 2002 g10 Code GmbH @@ -21,10 +21,8 @@ #if HAVE_CONFIG_H #include #endif -#include #include #include -#include #include "util.h" #include "context.h" @@ -142,11 +140,9 @@ append_xml_impinfo (GpgmeData *rdh, GpgmeStatusCode code, char *args) } -static void +static GpgmeError import_status_handler (GpgmeCtx ctx, GpgmeStatusCode code, char *args) { - if (ctx->error) - return; test_and_allocate_result (ctx, import); switch (code) @@ -174,6 +170,7 @@ import_status_handler (GpgmeCtx ctx, GpgmeStatusCode code, char *args) default: break; } + return 0; } diff --git a/gpgme/keylist.c b/gpgme/keylist.c index ed753414..1076d267 100644 --- a/gpgme/keylist.c +++ b/gpgme/keylist.c @@ -83,14 +83,12 @@ append_xml_keylistinfo (GpgmeData *rdh, char *args) } -static void +static GpgmeError keylist_status_handler (GpgmeCtx ctx, GpgmeStatusCode code, char *args) { - if (ctx->error) - return; test_and_allocate_result (ctx, keylist); - switch (code) + switch (code) { case GPGME_STATUS_TRUNCATED: ctx->result.keylist->truncated = 1; @@ -108,9 +106,9 @@ keylist_status_handler (GpgmeCtx ctx, GpgmeStatusCode code, char *args) break; default: - /* Ignore all other codes. */ break; } + return 0; } @@ -341,7 +339,7 @@ finish_key (GpgmeCtx ctx) /* Note: We are allowed to modify LINE. */ -static void +static GpgmeError keylist_colon_handler (GpgmeCtx ctx, char *line) { enum @@ -360,14 +358,11 @@ keylist_colon_handler (GpgmeCtx ctx, char *line) DEBUG3 ("keylist_colon_handler ctx = %p, key = %p, line = %s\n", ctx, key, line ? line : "(null)"); - if (ctx->error) - return; - if (!line) { /* End Of File. */ finish_key (ctx); - return; + return 0; } while (line && fields < NR_FIELDS) @@ -389,30 +384,21 @@ keylist_colon_handler (GpgmeCtx ctx, char *line) /* Start a new subkey. */ rectype = RT_SUB; if (!(subkey = _gpgme_key_add_subkey (key))) - { - ctx->error = mk_error (Out_Of_Core); - return; - } + return mk_error (Out_Of_Core); } else if (!strcmp (field[0], "ssb") && key) { /* Start a new secret subkey. */ rectype = RT_SSB; if (!(subkey = _gpgme_key_add_secret_subkey (key))) - { - ctx->error = mk_error (Out_Of_Core); - return; - } + return mk_error (Out_Of_Core); } else if (!strcmp (field[0], "pub")) { /* Start a new keyblock. */ if (_gpgme_key_new (&key)) - { - /* The only kind of error we can get. */ - ctx->error = mk_error (Out_Of_Core); - return; - } + /* The only kind of error we can get. */ + return mk_error (Out_Of_Core); rectype = RT_PUB; finish_key (ctx); assert (!ctx->tmp_key); @@ -422,11 +408,7 @@ keylist_colon_handler (GpgmeCtx ctx, char *line) { /* Start a new keyblock, */ if (_gpgme_key_new_secret (&key)) - { - /* The only kind of error we can get. */ - ctx->error = mk_error (Out_Of_Core); - return; - } + return mk_error (Out_Of_Core); rectype = RT_SEC; finish_key (ctx); assert (!ctx->tmp_key); @@ -436,11 +418,7 @@ keylist_colon_handler (GpgmeCtx ctx, char *line) { /* Start a new certificate. */ if (_gpgme_key_new (&key)) - { - /* The only kind of error we can get. */ - ctx->error = mk_error (Out_Of_Core); - return; - } + return mk_error (Out_Of_Core); key->x509 = 1; rectype = RT_CRT; finish_key (ctx); @@ -451,11 +429,7 @@ keylist_colon_handler (GpgmeCtx ctx, char *line) { /* Start a new certificate. */ if (_gpgme_key_new_secret (&key)) - { - /* The only kind of error we can get. */ - ctx->error = mk_error (Out_Of_Core); - return; - } + return mk_error (Out_Of_Core); key->x509 = 1; rectype = RT_CRS; finish_key (ctx); @@ -482,14 +456,14 @@ keylist_colon_handler (GpgmeCtx ctx, char *line) { key->issuer_serial = strdup (field[7]); if (!key->issuer_serial) - ctx->error = mk_error (Out_Of_Core); + return mk_error (Out_Of_Core); } /* Field 10 is not used for gpg due to --fixed-list-mode option but GPGSM stores the issuer name. */ if (fields >= 10 && _gpgme_decode_c_string (field[9], &key->issuer_name, 0)) - ctx->error = mk_error (Out_Of_Core); + return mk_error (Out_Of_Core); /* Fall through! */ case RT_PUB: @@ -589,7 +563,7 @@ keylist_colon_handler (GpgmeCtx ctx, char *line) if (fields >= 10) { if (_gpgme_key_append_name (key, field[9])) - ctx->error = mk_error (Out_Of_Core); + return mk_error (Out_Of_Core); else { if (field[1]) @@ -605,7 +579,7 @@ keylist_colon_handler (GpgmeCtx ctx, char *line) { key->keys.fingerprint = strdup (field[9]); if (!key->keys.fingerprint) - ctx->error = mk_error (Out_Of_Core); + return mk_error (Out_Of_Core); } /* Field 13 has the gpgsm chain ID (take only the first one). */ @@ -613,23 +587,20 @@ keylist_colon_handler (GpgmeCtx ctx, char *line) { key->chain_id = strdup (field[12]); if (!key->chain_id) - ctx->error = mk_error (Out_Of_Core); + return mk_error (Out_Of_Core); } break; case RT_SIG: case RT_REV: if (!ctx->tmp_uid) - return; + return 0; /* Start a new (revoked) signature. */ assert (ctx->tmp_uid == key->last_uid); certsig = _gpgme_key_add_certsig (key, (fields >= 10) ? field[9] : NULL); if (!certsig) - { - ctx->error = mk_error (Out_Of_Core); - return; - } + return mk_error (Out_Of_Core); /* Field 2 has the calculated trust ('!', '-', '?', '%'). */ if (fields >= 2) @@ -696,6 +667,7 @@ keylist_colon_handler (GpgmeCtx ctx, char *line) /* Unknown record. */ break; } + return 0; } @@ -714,7 +686,7 @@ _gpgme_op_keylist_event_cb (void *data, GpgmeEventIO type, void *type_data) if (!q) { gpgme_key_release (key); - ctx->error = mk_error (Out_Of_Core); + /* FIXME return mk_error (Out_Of_Core); */ return; } q->key = key; @@ -859,8 +831,6 @@ gpgme_op_keylist_next (GpgmeCtx ctx, GpgmeKey *r_key) return mk_error (Invalid_Value); if (!ctx->pending) return mk_error (No_Request); - if (ctx->error) - return ctx->error; if (!ctx->key_queue) { @@ -912,8 +882,6 @@ gpgme_op_keylist_end (GpgmeCtx ctx) return mk_error (Invalid_Value); if (!ctx->pending) return mk_error (No_Request); - if (ctx->error) - return ctx->error; ctx->pending = 0; return 0; diff --git a/gpgme/op-support.c b/gpgme/op-support.c index bcaf8327..14fb6c80 100644 --- a/gpgme/op-support.c +++ b/gpgme/op-support.c @@ -1,24 +1,25 @@ /* 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 - */ + Copyright (C) 2002, 2003 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 GPGME; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#if HAVE_CONFIG_H #include +#endif #include "gpgme.h" #include "context.h" @@ -50,28 +51,27 @@ _gpgme_op_reset (GpgmeCtx ctx, int type) { /* Use private event loop. */ io_cbs.add = _gpgme_add_io_cb; - io_cbs.add_priv = &ctx->fdt; + io_cbs.add_priv = ctx; io_cbs.remove = _gpgme_remove_io_cb; - io_cbs.event = _gpgme_op_event_cb; + io_cbs.event = _gpgme_wait_private_event_cb; io_cbs.event_priv = ctx; } else if (! ctx->io_cbs.add) { /* Use global event loop. */ io_cbs.add = _gpgme_add_io_cb; - io_cbs.add_priv = NULL; + io_cbs.add_priv = ctx; io_cbs.remove = _gpgme_remove_io_cb; - io_cbs.event = _gpgme_wait_event_cb; + io_cbs.event = _gpgme_wait_global_event_cb; io_cbs.event_priv = ctx; } else { /* Use user event loop. */ - io_cbs = ctx->io_cbs; - /* We have to make sure that we notice the termination of the - operation ourself, so we stack another event handler on top - of the user-provided one. */ - io_cbs.event = _gpgme_op_event_cb_user; + io_cbs.add = _gpgme_wait_user_add_io_cb; + io_cbs.add_priv = ctx; + io_cbs.remove = _gpgme_wait_user_remove_io_cb; + io_cbs.event = _gpgme_wait_user_event_cb; io_cbs.event_priv = ctx; } _gpgme_engine_set_io_cbs (ctx->engine, &io_cbs); diff --git a/gpgme/ops.h b/gpgme/ops.h index 022eef52..602b4ea1 100644 --- a/gpgme/ops.h +++ b/gpgme/ops.h @@ -25,23 +25,20 @@ /* Support macros. */ -#define test_and_allocate_result(ctx,field) \ - do \ - { \ - if (!ctx->result.field) \ - { \ - ctx->result.field = calloc (1, sizeof *ctx->result.field); \ - if (!ctx->result.field) \ - { \ - ctx->error = mk_error (Out_Of_Core); \ - return; \ - } \ - } \ - } \ +#define test_and_allocate_result(ctx,field) \ + do \ + { \ + if (!ctx->result.field) \ + { \ + ctx->result.field = calloc (1, sizeof *ctx->result.field); \ + if (!ctx->result.field) \ + return mk_error (Out_Of_Core); \ + } \ + } \ while (0) /*-- gpgme.c --*/ -void _gpgme_release_result ( GpgmeCtx c ); +void _gpgme_release_result (GpgmeCtx ctx); void _gpgme_set_op_info (GpgmeCtx c, GpgmeData info); void _gpgme_op_event_cb (void *data, GpgmeEventIO type, void *type_data); @@ -72,8 +69,8 @@ GpgmeError _gpgme_data_append_percentstring_for_xml ( GpgmeData dh, GpgmeError _gpgme_data_unread (GpgmeData dh, const char *buffer, size_t length ); -void _gpgme_data_inbound_handler (void *opaque, int fd); -void _gpgme_data_outbound_handler (void *opaque, int fd); +GpgmeError _gpgme_data_inbound_handler (void *opaque, int fd); +GpgmeError _gpgme_data_outbound_handler (void *opaque, int fd); /*-- key.c --*/ GpgmeError _gpgme_key_new ( GpgmeKey *r_key ); @@ -84,13 +81,13 @@ GpgmeError _gpgme_op_reset (GpgmeCtx ctx, int synchronous); /*-- verify.c --*/ void _gpgme_release_verify_result (VerifyResult result); -void _gpgme_verify_status_handler (GpgmeCtx ctx, GpgmeStatusCode code, - char *args); +GpgmeError _gpgme_verify_status_handler (GpgmeCtx ctx, GpgmeStatusCode code, + char *args); /*-- decrypt.c --*/ void _gpgme_release_decrypt_result (DecryptResult result); -void _gpgme_decrypt_status_handler (GpgmeCtx ctx, GpgmeStatusCode code, - char *args); +GpgmeError _gpgme_decrypt_status_handler (GpgmeCtx ctx, GpgmeStatusCode code, + char *args); GpgmeError _gpgme_decrypt_start (GpgmeCtx ctx, int synchronous, GpgmeData ciph, GpgmeData plain, void *status_handler); @@ -98,26 +95,26 @@ GpgmeError _gpgme_decrypt_result (GpgmeCtx ctx); /*-- sign.c --*/ void _gpgme_release_sign_result ( SignResult res ); -void _gpgme_sign_status_handler (GpgmeCtx ctx, GpgmeStatusCode code, - char *args); +GpgmeError _gpgme_sign_status_handler (GpgmeCtx ctx, GpgmeStatusCode code, + char *args); /*-- encrypt.c --*/ void _gpgme_release_encrypt_result ( EncryptResult res ); -void _gpgme_encrypt_status_handler (GpgmeCtx ctx, GpgmeStatusCode code, - char *args); +GpgmeError _gpgme_encrypt_status_handler (GpgmeCtx ctx, GpgmeStatusCode code, + char *args); /*-- passphrase.c --*/ void _gpgme_release_passphrase_result (PassphraseResult result); -void _gpgme_passphrase_status_handler (GpgmeCtx ctx, GpgmeStatusCode code, - char *args); -const char * _gpgme_passphrase_command_handler (void *opaque, - GpgmeStatusCode code, - const char *key); +GpgmeError _gpgme_passphrase_status_handler (GpgmeCtx ctx, GpgmeStatusCode code, + char *args); +GpgmeError _gpgme_passphrase_command_handler (void *opaque, + GpgmeStatusCode code, + const char *key, const char **result); GpgmeError _gpgme_passphrase_start (GpgmeCtx ctx); /*-- progress.c --*/ -void _gpgme_progress_status_handler (GpgmeCtx ctx, GpgmeStatusCode code, - char *args); +GpgmeError _gpgme_progress_status_handler (GpgmeCtx ctx, GpgmeStatusCode code, + char *args); /*-- import.c --*/ void _gpgme_release_import_result (ImportResult res); diff --git a/gpgme/passphrase.c b/gpgme/passphrase.c index a8900a7b..9bcbd17b 100644 --- a/gpgme/passphrase.c +++ b/gpgme/passphrase.c @@ -52,11 +52,9 @@ _gpgme_release_passphrase_result (PassphraseResult result) } -void +GpgmeError _gpgme_passphrase_status_handler (GpgmeCtx ctx, GpgmeStatusCode code, char *args) { - if (ctx->error) - return; test_and_allocate_result (ctx, passphrase); switch (code) @@ -64,7 +62,7 @@ _gpgme_passphrase_status_handler (GpgmeCtx ctx, GpgmeStatusCode code, char *args case GPGME_STATUS_USERID_HINT: free (ctx->result.passphrase->userid_hint); if (!(ctx->result.passphrase->userid_hint = strdup (args))) - ctx->error = mk_error (Out_Of_Core); + return mk_error (Out_Of_Core); break; case GPGME_STATUS_BAD_PASSPHRASE: @@ -82,7 +80,7 @@ _gpgme_passphrase_status_handler (GpgmeCtx ctx, GpgmeStatusCode code, char *args free (ctx->result.passphrase->passphrase_info); ctx->result.passphrase->passphrase_info = strdup (args); if (!ctx->result.passphrase->passphrase_info) - ctx->error = mk_error (Out_Of_Core); + return mk_error (Out_Of_Core); break; case GPGME_STATUS_MISSING_PASSPHRASE: @@ -93,18 +91,20 @@ _gpgme_passphrase_status_handler (GpgmeCtx ctx, GpgmeStatusCode code, char *args case GPGME_STATUS_EOF: if (ctx->result.passphrase->no_passphrase || ctx->result.passphrase->bad_passphrase) - ctx->error = mk_error (No_Passphrase); + return mk_error (No_Passphrase); break; default: /* Ignore all other codes. */ break; } + return 0; } -const char * -_gpgme_passphrase_command_handler (void *opaque, GpgmeStatusCode code, const char *key) +GpgmeError +_gpgme_passphrase_command_handler (void *opaque, GpgmeStatusCode code, + const char *key, const char **result) { GpgmeCtx ctx = opaque; @@ -112,10 +112,7 @@ _gpgme_passphrase_command_handler (void *opaque, GpgmeStatusCode code, const cha { ctx->result.passphrase = calloc (1, sizeof *ctx->result.passphrase); if (!ctx->result.passphrase) - { - ctx->error = mk_error (Out_Of_Core); - return NULL; - } + return mk_error (Out_Of_Core); } if (!code) @@ -127,11 +124,15 @@ _gpgme_passphrase_command_handler (void *opaque, GpgmeStatusCode code, const cha ctx->passphrase_cb (ctx->passphrase_cb_value, NULL, &ctx->result.passphrase->last_pw_handle); } - return NULL; + *result = NULL; + return 0; } if (!key || !ctx->passphrase_cb) - return NULL; + { + *result = NULL; + return 0; + } if (code == GPGME_STATUS_GET_HIDDEN && !strcmp (key, "passphrase.enter")) { @@ -139,7 +140,6 @@ _gpgme_passphrase_command_handler (void *opaque, GpgmeStatusCode code, const cha const char *passphrase_info = ctx->result.passphrase->passphrase_info; int bad_passphrase = ctx->result.passphrase->bad_passphrase; char *buf; - const char *s; ctx->result.passphrase->bad_passphrase = 0; if (!userid_hint) @@ -149,21 +149,19 @@ _gpgme_passphrase_command_handler (void *opaque, GpgmeStatusCode code, const cha buf = malloc (20 + strlen (userid_hint) + strlen (passphrase_info) + 3); if (!buf) - { - ctx->error = mk_error (Out_Of_Core); - return NULL; - } + return mk_error (Out_Of_Core); sprintf (buf, "%s\n%s\n%s", bad_passphrase ? "TRY_AGAIN":"ENTER", userid_hint, passphrase_info); - s = ctx->passphrase_cb (ctx->passphrase_cb_value, - buf, &ctx->result.passphrase->last_pw_handle); + *result = ctx->passphrase_cb (ctx->passphrase_cb_value, buf, + &ctx->result.passphrase->last_pw_handle); free (buf); - return s; + return 0; } - return NULL; + *result = NULL; + return 0; } diff --git a/gpgme/progress.c b/gpgme/progress.c index fd3eba63..7d5fc976 100644 --- a/gpgme/progress.c +++ b/gpgme/progress.c @@ -1,23 +1,22 @@ /* progress.c - status handler for progress status - * Copyright (C) 2000 Werner Koch (dd9jn) - * Copyright (C) 2001, 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 - */ + Copyright (C) 2000 Werner Koch (dd9jn) + Copyright (C) 2001, 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 GPGME; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifdef HAVE_CONFIG_H #include @@ -29,7 +28,7 @@ #include "context.h" -void +GpgmeError _gpgme_progress_status_handler (GpgmeCtx ctx, GpgmeStatusCode code, char *args) { char *p; @@ -39,14 +38,11 @@ _gpgme_progress_status_handler (GpgmeCtx ctx, GpgmeStatusCode code, char *args) int total = 0; if (code != GPGME_STATUS_PROGRESS || !*args || !ctx->progress_cb) - return; + return 0; args_cpy = strdup (args); if (!args_cpy) - { - ctx->error = mk_error (Out_Of_Core); - return; - } + return mk_error (Out_Of_Core); p = strchr (args_cpy, ' '); if (p) @@ -77,4 +73,5 @@ _gpgme_progress_status_handler (GpgmeCtx ctx, GpgmeStatusCode code, char *args) ctx->progress_cb (ctx->progress_cb_value, args_cpy, type, current, total); free (args_cpy); + return 0; } diff --git a/gpgme/rungpg.c b/gpgme/rungpg.c index 7677941f..fd83e69a 100644 --- a/gpgme/rungpg.c +++ b/gpgme/rungpg.c @@ -138,17 +138,12 @@ static void close_notify_handler (int fd, void *opaque) { GpgObject gpg = opaque; - int possibly_done = 0; - int not_done = 0; assert (fd != -1); if (gpg->status.fd[0] == fd) { if (gpg->status.tag) - { - (*gpg->io_cbs.remove) (gpg->status.tag); - possibly_done = 1; - } + (*gpg->io_cbs.remove) (gpg->status.tag); gpg->status.fd[0] = -1; } else if (gpg->status.fd[1] == fd) @@ -156,10 +151,7 @@ close_notify_handler (int fd, void *opaque) else if (gpg->colon.fd[0] == fd) { if (gpg->colon.tag) - { - (*gpg->io_cbs.remove) (gpg->colon.tag); - possibly_done = 1; - } + (*gpg->io_cbs.remove) (gpg->colon.tag); gpg->colon.fd[0] = -1; } else if (gpg->colon.fd[1] == fd) @@ -173,10 +165,7 @@ close_notify_handler (int fd, void *opaque) 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->io_cbs.remove) (gpg->fd_data_map[i].tag); gpg->fd_data_map[i].fd = -1; break; } @@ -187,25 +176,6 @@ close_notify_handler (int fd, void *opaque) } } } - 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_event (gpg, GPGME_EVENT_DONE, NULL); } static GpgmeError @@ -500,12 +470,13 @@ command_cb (void *opaque, char *buffer, size_t length, size_t *nread) return -1; } - value = gpg->cmd.fnc (gpg->cmd.fnc_value, - gpg->cmd.code, gpg->cmd.keyword); + /* FIXME catch error */ + gpg->cmd.fnc (gpg->cmd.fnc_value, + gpg->cmd.code, gpg->cmd.keyword, &value); if (!value) { 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, &value); return -1; } @@ -513,7 +484,7 @@ command_cb (void *opaque, char *buffer, size_t length, size_t *nread) if (value_len + 1 > length) { 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, &value); return -1; } @@ -522,7 +493,7 @@ command_cb (void *opaque, char *buffer, size_t length, size_t *nread) buffer[value_len++] = '\n'; *nread = value_len; - gpg->cmd.fnc (gpg->cmd.fnc_value, 0, value); + gpg->cmd.fnc (gpg->cmd.fnc_value, 0, value, &value); gpg->cmd.code = 0; /* And sleep again until read_status will wake us up again. */ /* XXX We must check if there are any more fds active after removing @@ -957,7 +928,7 @@ read_status (GpgObject gpg) } -static void +static GpgmeError status_handler (void *opaque, int fd) { GpgObject gpg = opaque; @@ -967,16 +938,13 @@ status_handler (void *opaque, int fd) err = read_status (gpg); if (err) { - /* XXX Horrible kludge. We really must not make use of - fnc_value. */ - GpgmeCtx ctx = (GpgmeCtx) gpg->status.fnc_value; - ctx->error = err; DEBUG1 ("gpg_handler: read_status problem %d\n - stop", err); _gpgme_io_close (fd); - return; + return err; } if (gpg->status.eof) _gpgme_io_close (fd); + return 0; } @@ -1058,7 +1026,7 @@ read_colon_line (GpgObject gpg) might be better to enhance the GpgmeData object to act as a wrapper for a callback. Same goes for the status thing. For now we use this thing here because it is easier to implement. */ -static void +static GpgmeError colon_line_handler (void *opaque, int fd) { GpgObject gpg = opaque; @@ -1067,14 +1035,10 @@ colon_line_handler (void *opaque, int fd) assert (fd == gpg->colon.fd[0]); rc = read_colon_line (gpg); if (rc) - { - DEBUG1 ("gpg_colon_line_handler: " - "read problem %d\n - stop", rc); - _gpgme_io_close (fd); - return; - } + return rc; if (gpg->colon.eof) _gpgme_io_close (fd); + return 0; } @@ -1198,6 +1162,8 @@ start (GpgObject gpg) return rc; } } + + (*gpg->io_cbs.event) (gpg->io_cbs.event_priv, GPGME_EVENT_START, NULL); /* fixme: check what data we can release here */ return 0; diff --git a/gpgme/sign.c b/gpgme/sign.c index d45699b0..0fc5e82a 100644 --- a/gpgme/sign.c +++ b/gpgme/sign.c @@ -136,13 +136,13 @@ append_xml_siginfo (GpgmeData *rdh, char *args) _gpgme_data_append_string (dh, "\n"); } -void +GpgmeError _gpgme_sign_status_handler (GpgmeCtx ctx, GpgmeStatusCode code, char *args) { - _gpgme_passphrase_status_handler (ctx, code, args); + GpgmeError err = _gpgme_passphrase_status_handler (ctx, code, args); + if (err) + return err; - if (ctx->error) - return; test_and_allocate_result (ctx, sign); switch (code) @@ -154,8 +154,8 @@ _gpgme_sign_status_handler (GpgmeCtx ctx, GpgmeStatusCode code, char *args) _gpgme_set_op_info (ctx, ctx->result.sign->xmlinfo); ctx->result.sign->xmlinfo = NULL; } - if (!ctx->error && !ctx->result.sign->okay) - ctx->error = mk_error (No_Data); /* Hmmm: choose a better error? */ + if (!ctx->result.sign->okay) + return mk_error (No_Data); /* Hmmm: choose a better error? */ break; case GPGME_STATUS_SIG_CREATED: @@ -167,6 +167,7 @@ _gpgme_sign_status_handler (GpgmeCtx ctx, GpgmeStatusCode code, char *args) default: break; } + return 0; } static GpgmeError diff --git a/gpgme/trustlist.c b/gpgme/trustlist.c index 5c4a8489..11860322 100644 --- a/gpgme/trustlist.c +++ b/gpgme/trustlist.c @@ -1,4 +1,4 @@ -/* trustlist.c - key listing +/* trustlist.c - Trust item listing. Copyright (C) 2000 Werner Koch (dd9jn) Copyright (C) 2001, 2002 g10 Code GmbH @@ -52,12 +52,9 @@ trust_item_new (void) } -static void +static GpgmeError trustlist_status_handler (GpgmeCtx ctx, GpgmeStatusCode code, char *args) { - if (ctx->error) - return; - switch (code) { case GPGME_STATUS_EOF: @@ -66,6 +63,7 @@ trustlist_status_handler (GpgmeCtx ctx, GpgmeStatusCode code, char *args) default: break; } + return 0; } @@ -80,17 +78,15 @@ trustlist_status_handler (GpgmeCtx ctx, GpgmeStatusCode code, char *args) counter and only available on U lines CC is the same for the complete count NAME ist the username and only printed on U lines. */ -static void +static GpgmeError trustlist_colon_handler (GpgmeCtx ctx, char *line) { char *p, *pend; int field = 0; GpgmeTrustItem item = NULL; - if (ctx->error) - return; if (!line) - return; /* EOF */ + return 0; /* EOF */ for (p = line; p; p = pend) { @@ -104,10 +100,7 @@ trustlist_colon_handler (GpgmeCtx ctx, char *line) case 1: /* level */ item = trust_item_new (); if (!item) - { - ctx->error = mk_error (Out_Of_Core); - return; - } + return mk_error (Out_Of_Core); item->level = atoi (p); break; case 2: /* long keyid */ @@ -128,13 +121,14 @@ trustlist_colon_handler (GpgmeCtx ctx, char *line) case 9: /* user ID */ item->name = strdup (p); if (!item->name) - ctx->error = mk_error (Out_Of_Core); + return mk_error (Out_Of_Core); break; } } if (item) _gpgme_engine_io_event (ctx->engine, GPGME_EVENT_NEXT_TRUSTITEM, item); + return 0; } @@ -145,13 +139,14 @@ _gpgme_op_trustlist_event_cb (void *data, GpgmeEventIO type, void *type_data) GpgmeTrustItem item = (GpgmeTrustItem) type_data; struct trust_queue_item_s *q, *q2; - assert (type == GPGME_EVENT_NEXT_KEY); + assert (type == GPGME_EVENT_NEXT_TRUSTITEM); q = malloc (sizeof *q); if (!q) { gpgme_trust_item_release (item); - ctx->error = mk_error (Out_Of_Core); + /* FIXME */ + /* ctx->error = mk_error (Out_Of_Core); */ return; } q->item = item; @@ -215,8 +210,6 @@ gpgme_op_trustlist_next (GpgmeCtx ctx, GpgmeTrustItem *r_item) return mk_error (Invalid_Value); if (!ctx->pending) return mk_error (No_Request); - if (ctx->error) - return ctx->error; if (!ctx->trust_queue) { @@ -266,8 +259,6 @@ gpgme_op_trustlist_end (GpgmeCtx ctx) return mk_error (Invalid_Value); if (!ctx->pending) return mk_error (No_Request); - if (ctx->error) - return ctx->error; ctx->pending = 0; return 0; diff --git a/gpgme/types.h b/gpgme/types.h index 71fca56b..90feecf0 100644 --- a/gpgme/types.h +++ b/gpgme/types.h @@ -35,11 +35,11 @@ typedef unsigned long ulong; * Declaration of internal objects */ -typedef void (*GpgmeStatusHandler) (GpgmeCtx, GpgmeStatusCode code, - char *args); -typedef void (*GpgmeColonLineHandler) (GpgmeCtx, char *line); -typedef const char *(*GpgmeCommandHandler) (void*, GpgmeStatusCode code, - const char *keyword); +typedef GpgmeError (*GpgmeStatusHandler) (GpgmeCtx, GpgmeStatusCode code, + char *args); +typedef GpgmeError (*GpgmeColonLineHandler) (GpgmeCtx, char *line); +typedef GpgmeError (*GpgmeCommandHandler) (void*, GpgmeStatusCode code, + const char *keyword, const char **result); /*-- engine.c --*/ diff --git a/gpgme/verify.c b/gpgme/verify.c index a510d398..921d727e 100644 --- a/gpgme/verify.c +++ b/gpgme/verify.c @@ -119,7 +119,7 @@ copy_token (const char *string, char *buffer, size_t length) /* FIXME: Check that we are adding this to the correct signature. */ -static void +static GpgmeError add_notation (GpgmeCtx ctx, GpgmeStatusCode code, const char *data) { GpgmeData dh = ctx->result.verify->notation; @@ -127,10 +127,7 @@ add_notation (GpgmeCtx ctx, GpgmeStatusCode code, const char *data) if (!dh) { if (gpgme_data_new (&dh)) - { - ctx->error = mk_error (Out_Of_Core); - return; - } + return mk_error (Out_Of_Core); ctx->result.verify->notation = dh; _gpgme_data_append_string (dh, " \n"); } @@ -141,7 +138,7 @@ add_notation (GpgmeCtx ctx, GpgmeStatusCode code, const char *data) _gpgme_data_append_string (dh, " "); _gpgme_data_append_percentstring_for_xml (dh, data); ctx->result.verify->notation_in_data = 1; - return; + return 0; } if (ctx->result.verify->notation_in_data) @@ -164,19 +161,20 @@ add_notation (GpgmeCtx ctx, GpgmeStatusCode code, const char *data) } else assert (0); + return 0; } /* Finish a pending signature info collection and prepare for a new signature info collection. */ -static void +static GpgmeError finish_sig (GpgmeCtx ctx, int stop) { if (ctx->result.verify->status == GPGME_SIG_STAT_GOOD) ctx->result.verify->status = ctx->result.verify->expstatus; if (stop) - return; /* nothing to do */ + return 0; /* nothing to do */ if (ctx->result.verify->collecting) { @@ -186,28 +184,25 @@ finish_sig (GpgmeCtx ctx, int stop) /* Create a new result structure. */ res2 = calloc (1, sizeof *res2); if (!res2) - { - ctx->error = mk_error (Out_Of_Core); - return; - } + return mk_error (Out_Of_Core); res2->next = ctx->result.verify; ctx->result.verify = res2; } ctx->result.verify->collecting = 1; + return 0; } -void +GpgmeError _gpgme_verify_status_handler (GpgmeCtx ctx, GpgmeStatusCode code, char *args) { + GpgmeError err; char *p; size_t n; int i; - if (ctx->error) - return; test_and_allocate_result (ctx, verify); if (code == GPGME_STATUS_GOODSIG @@ -216,9 +211,9 @@ _gpgme_verify_status_handler (GpgmeCtx ctx, GpgmeStatusCode code, char *args) || code == GPGME_STATUS_BADSIG || code == GPGME_STATUS_ERRSIG) { - finish_sig (ctx,0); - if (ctx->error) - return; + err = finish_sig (ctx,0); + if (err) + return err; } switch (code) @@ -284,7 +279,9 @@ _gpgme_verify_status_handler (GpgmeCtx ctx, GpgmeStatusCode code, char *args) case GPGME_STATUS_NOTATION_NAME: case GPGME_STATUS_NOTATION_DATA: case GPGME_STATUS_POLICY_URL: - add_notation (ctx, code, args); + err = add_notation (ctx, code, args); + if (err) + return err; break; case GPGME_STATUS_TRUST_UNDEFINED: @@ -333,7 +330,9 @@ _gpgme_verify_status_handler (GpgmeCtx ctx, GpgmeStatusCode code, char *args) break; case GPGME_STATUS_EOF: - finish_sig (ctx,1); + err = finish_sig (ctx,1); + if (err) + return err; /* FIXME: Put all notation data into one XML fragment. */ if (ctx->result.verify->notation) @@ -355,6 +354,7 @@ _gpgme_verify_status_handler (GpgmeCtx ctx, GpgmeStatusCode code, char *args) /* Ignore all other codes. */ break; } + return 0; } diff --git a/gpgme/wait-global.c b/gpgme/wait-global.c new file mode 100644 index 00000000..074d98c5 --- /dev/null +++ b/gpgme/wait-global.c @@ -0,0 +1,356 @@ +/* wait-global.c + Copyright (C) 2000 Werner Koch (dd9jn) + Copyright (C) 2001, 2002, 2003 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 GPGME; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#if HAVE_CONFIG_H +#include +#endif +#include +#include +#include + +#include "gpgme.h" +#include "sema.h" +#include "util.h" +#include "context.h" +#include "wait.h" +#include "io.h" + +/* The global event loop is used for all asynchronous operations + (except key listing) for which no user I/O callbacks are specified. + + A context sets up its initial I/O callbacks and then sends the + GPGME_EVENT_START event. After that, it is added to the global + list of active contexts. + + The gpgme_wait function contains a select() loop over all file + descriptors in all active contexts. If an error occurs, it closes + all fds in that context and moves the context to the global done + list. Likewise, if a context has removed all I/O callbacks, it is + moved to the global done list. + + All contexts in the global done list are eligible for being + returned by gpgme_wait if requested by the caller. */ + +/* The ctx_list_lock protects the list of active and done contexts. + Insertion into any of these lists is only allowed when the lock is + held. This allows a muli-threaded program to loop over gpgme_wait + and in parallel start asynchronous gpgme operations. + + However, the fd tables in the contexts are not protected by this + lock. They are only allowed to change either before the context is + added to the active list (ie, before the start event is signalled) + or in a callback handler. */ +DEFINE_STATIC_LOCK (ctx_list_lock); + +/* A ctx_list_item is an item in the global list of active or done + contexts. */ +struct ctx_list_item +{ + /* Every ctx_list_item is an element in a doubly linked list. The + list pointers are protected by the ctx_list_lock. */ + struct ctx_list_item *next; + struct ctx_list_item *prev; + + GpgmeCtx ctx; + /* The status is set when the ctx is moved to the done list. */ + GpgmeError status; +}; + +/* The active list contains all contexts that are in the global event + loop, have active I/O callbacks, and have already seen the start + event. */ +static struct ctx_list_item *ctx_active_list; + +/* The done list contains all contexts that have previously been +active but now are not active any longer, either because they finished +successfully or an I/O callback returned an error. The status field +in the list item contains the error value (or 0 if successful). */ +static struct ctx_list_item *ctx_done_list; + + +/* Enter the context CTX into the active list. */ +static GpgmeError +ctx_active (GpgmeCtx ctx) +{ + struct ctx_list_item *li = malloc (sizeof (struct ctx_list_item)); + if (!li) + return mk_error (Out_Of_Core); + li->ctx = ctx; + + LOCK (ctx_list_lock); + /* Add LI to active list. */ + li->next = ctx_active_list; + li->prev = NULL; + if (ctx_active_list) + ctx_active_list->prev = li; + ctx_active_list = li; + UNLOCK (ctx_list_lock); + return 0; +} + + +/* Enter the context CTX into the done list with status STATUS. */ +static void +ctx_done (GpgmeCtx ctx, GpgmeError status) +{ + struct ctx_list_item *li; + + LOCK (ctx_list_lock); + li = ctx_active_list; + while (li && li->ctx != ctx) + li = li->next; + assert (li); + + /* Remove LI from active list. */ + if (li->next) + li->next->prev = li->prev; + if (li->prev) + li->prev->next = li->next; + else + ctx_active_list = li->next; + + li->status = status; + + /* Add LI to done list. */ + li->next = ctx_done_list; + li->prev = NULL; + if (ctx_done_list) + ctx_done_list->prev = li; + ctx_done_list = li; + UNLOCK (ctx_list_lock); +} + + +/* Find finished context CTX (or any context if CTX is NULL) and + return its status in STATUS after removing it from the done list. + If a matching context could be found, return it. Return NULL if no + context could be found. */ +static GpgmeCtx +ctx_wait (GpgmeCtx ctx, GpgmeError *status) +{ + struct ctx_list_item *li; + + LOCK (ctx_list_lock); + li = ctx_done_list; + if (ctx) + { + /* A specific context is requested. */ + while (li && li->ctx != ctx) + li = li->next; + } + if (li) + { + ctx = li->ctx; + if (status) + *status = li->status; + + /* Remove LI from done list. */ + if (li->next) + li->next->prev = li->prev; + if (li->prev) + li->prev->next = li->next; + else + ctx_done_list = li->next; + free (li); + } + else + ctx = NULL; + UNLOCK (ctx_list_lock); + return ctx; +} + + +/* Internal I/O callback functions. */ + +/* The add_io_cb and remove_io_cb handlers are shared with the private + event loops. */ + +void +_gpgme_wait_global_event_cb (void *data, GpgmeEventIO type, void *type_data) +{ + GpgmeCtx ctx = (GpgmeCtx) data; + + assert (ctx); + + switch (type) + { + case GPGME_EVENT_START: + { + GpgmeError err = ctx_active (ctx); + + if (err) + { + /* An error occured. Close all fds in this context, and + send the error in a done event. */ + int idx; + + for (idx = 0; idx <= ctx->fdt.size; idx++) + if (ctx->fdt.fds[idx].fd != -1) + _gpgme_io_close (ctx->fdt.fds[idx].fd); + _gpgme_engine_io_event (ctx->engine, GPGME_EVENT_DONE, &err); + } + } + break; + + case GPGME_EVENT_DONE: + { + GpgmeError *errp = (GpgmeError *) type_data; + assert (errp); + ctx_done (ctx, *errp); + } + break; + + case GPGME_EVENT_NEXT_KEY: + assert (!"Unexpected event GPGME_EVENT_NEXT_KEY"); + break; + + case GPGME_EVENT_NEXT_TRUSTITEM: + assert (!"Unexpected event GPGME_EVENT_NEXT_TRUSTITEM"); + break; + + default: + assert (!"Unexpected event"); + break; + } +} + + + +/* Perform asynchronous operations in the global event loop (ie, any + asynchronous operation except key listing and trustitem listing + operations). If CTX is not a null pointer, the function will + return if the asynchronous operation in the context CTX finished. + Otherwise the function will return if any asynchronous operation + finished. If HANG is zero, the function will not block for a long + time. Otherwise the function does not return until an operation + matching CTX finished. + + If a matching context finished, it is returned, and *STATUS is set + to the error value of the operation in that context. Otherwise, if + the timeout expires, NULL is returned and *STATUS is 0. If an + error occurs, NULL is returned and *STATUS is set to the error + value. */ +GpgmeCtx +gpgme_wait (GpgmeCtx ctx, GpgmeError *status, int hang) +{ + do + { + int i = 0; + struct ctx_list_item *li; + struct fd_table fdt; + int nr; + + /* Collect the active file descriptors. */ + LOCK (ctx_list_lock); + for (li = ctx_active_list; li; li = li->next) + i += li->ctx->fdt.size; + fdt.fds = malloc (i * sizeof (struct io_select_fd_s)); + if (!fdt.fds) + { + UNLOCK (ctx_list_lock); + if (status) + *status = mk_error (Out_Of_Core); + return NULL; + } + fdt.size = i; + i = 0; + for (li = ctx_active_list; li; li = li->next) + { + memcpy (&fdt.fds[i], li->ctx->fdt.fds, + li->ctx->fdt.size * sizeof (struct io_select_fd_s)); + i += li->ctx->fdt.size; + } + UNLOCK (ctx_list_lock); + + nr = _gpgme_io_select (fdt.fds, fdt.size, 0); + if (nr < 0) + { + free (fdt.fds); + if (status) + *status = mk_error (File_Error); + return NULL; + } + + for (i = 0; i < fdt.size && nr; i++) + { + if (fdt.fds[i].fd != -1 && fdt.fds[i].signaled) + { + GpgmeCtx ictx; + GpgmeError err; + struct wait_item_s *item; + + assert (nr); + nr--; + + item = (struct wait_item_s *) fdt.fds[i].opaque; + assert (item); + ictx = item->ctx; + assert (ictx); + + err = item->handler (item->handler_value, fdt.fds[i].fd); + if (!err && ictx->cancel) + err = mk_error (Canceled); + if (err) + { + /* An error occured. Close all fds in this context, + and signal it. */ + int idx; + + for (idx = 0; idx < ictx->fdt.size; idx++) + if (ictx->fdt.fds[idx].fd != -1) + _gpgme_io_close (ictx->fdt.fds[idx].fd); + _gpgme_engine_io_event (ictx->engine, GPGME_EVENT_DONE, &err); + } + } + } + free (fdt.fds); + + /* Now some contexts might have finished successfully. */ + LOCK (ctx_list_lock); + for (li = ctx_active_list; li; li = li->next) + { + for (i = 0; i < ctx->fdt.size; i++) + if (ctx->fdt.fds[i].fd != -1) + break; + if (i == ctx->fdt.size) + { + GpgmeError err = 0; + _gpgme_engine_io_event (ctx->engine, GPGME_EVENT_DONE, &err); + } + } + UNLOCK (ctx_list_lock); + + { + GpgmeCtx dctx = ctx_wait (ctx, status); + + if (dctx) + { + ctx = dctx; + hang = 0; + ctx->pending = 0; + } + } + } + while (hang); + + return ctx; +} + + diff --git a/gpgme/wait-private.c b/gpgme/wait-private.c new file mode 100644 index 00000000..d0f801d4 --- /dev/null +++ b/gpgme/wait-private.c @@ -0,0 +1,153 @@ +/* wait-private.c + Copyright (C) 2000 Werner Koch (dd9jn) + Copyright (C) 2001, 2002, 2003 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 GPGME; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#if HAVE_CONFIG_H +#include +#endif +#include + +#include "gpgme.h" +#include "context.h" +#include "wait.h" +#include "ops.h" +#include "io.h" +#include "util.h" + + +/* The private event loops are used for all blocking operations, and + for the key and trust item listing operations. They are completely + separated from each other. */ + + +/* Internal I/O callback functions. */ + +/* The add_io_cb and remove_io_cb handlers are shared with the global + event loops. */ + +void +_gpgme_wait_private_event_cb (void *data, GpgmeEventIO type, void *type_data) +{ + GpgmeCtx ctx = data; + + switch (type) + { + case GPGME_EVENT_START: + /* Nothing to do here, as the wait routine is called after the + initialization is finished. */ + break; + + case GPGME_EVENT_DONE: + ctx->pending = 0; + break; + + case GPGME_EVENT_NEXT_KEY: + _gpgme_op_keylist_event_cb (data, type, type_data); + break; + + case GPGME_EVENT_NEXT_TRUSTITEM: + _gpgme_op_trustlist_event_cb (data, type, type_data); + break; + } +} + + +/* If COND is a null pointer, wait until the blocking operation in CTX + finished and return its error value. Otherwise, wait until COND is + satisfied or the operation finished. */ +GpgmeError +_gpgme_wait_on_condition (GpgmeCtx ctx, volatile int *cond) +{ + GpgmeError err = 0; + int hang = 1; + + do + { + int nr = _gpgme_io_select (ctx->fdt.fds, ctx->fdt.size, 0); + int i; + + if (nr < 0) + { + /* An error occured. Close all fds in this context, and + signal it. */ + int idx; + + err = mk_error (File_Error); + for (idx = 0; idx < ctx->fdt.size; idx++) + if (ctx->fdt.fds[idx].fd != -1) + _gpgme_io_close (ctx->fdt.fds[idx].fd); + _gpgme_engine_io_event (ctx->engine, GPGME_EVENT_DONE, &err); + + return err; + } + + for (i = 0; i < ctx->fdt.size && nr; i++) + { + if (ctx->fdt.fds[i].fd != -1 && ctx->fdt.fds[i].signaled) + { + struct wait_item_s *item; + + ctx->fdt.fds[i].signaled = 0; + assert (nr); + nr--; + + item = (struct wait_item_s *) ctx->fdt.fds[i].opaque; + + err = item->handler (item->handler_value, ctx->fdt.fds[i].fd); + if (!err && ctx->cancel) + err = mk_error (Canceled); + if (err) + { + /* An error occured. Close all fds in this context, + and signal it. */ + int idx; + + for (idx = 0; idx < ctx->fdt.size; idx++) + if (ctx->fdt.fds[idx].fd != -1) + _gpgme_io_close (ctx->fdt.fds[idx].fd); + _gpgme_engine_io_event (ctx->engine, GPGME_EVENT_DONE, &err); + return err; + } + } + } + + for (i = 0; i < ctx->fdt.size; i++) + if (ctx->fdt.fds[i].fd != -1) + break; + if (i == ctx->fdt.size) + { + _gpgme_engine_io_event (ctx->engine, GPGME_EVENT_DONE, &err); + hang = 0; + } + if (cond && *cond) + hang = 0; + } + while (hang); + + return 0; +} + + +/* Wait until the blocking operation in context CTX has finished and + return the error value. */ +GpgmeError +_gpgme_wait_one (GpgmeCtx ctx) +{ + return _gpgme_wait_on_condition (ctx, NULL); +} diff --git a/gpgme/wait-user.c b/gpgme/wait-user.c new file mode 100644 index 00000000..e148491b --- /dev/null +++ b/gpgme/wait-user.c @@ -0,0 +1,127 @@ +/* wait.c + Copyright (C) 2000 Werner Koch (dd9jn) + Copyright (C) 2001, 2002, 2003 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 GPGME; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#if HAVE_CONFIG_H +#include +#endif +#include + +#include "gpgme.h" +#include "context.h" +#include "io.h" +#include "wait.h" + + +/* The user event loops are used for all asynchronous operations for + which a user callback is defined. */ + + +/* Internal I/O Callbacks. */ + +GpgmeError +_gpgme_user_io_cb_handler (void *data, int fd) +{ + GpgmeError err; + struct tag *tag = (struct tag *) data; + GpgmeCtx ctx; + struct wait_item_s *item; + + assert (data); + ctx = tag->ctx; + assert (ctx); + item = (struct wait_item_s *) ctx->fdt.fds[tag->idx].opaque; + assert (item); + + err = (*item->handler) (item->handler_value, fd); + if (err) + { + int idx; + + for (idx = 0; idx < ctx->fdt.size; idx++) + if (ctx->fdt.fds[idx].fd != -1) + _gpgme_io_close (ctx->fdt.fds[idx].fd); + _gpgme_engine_io_event (ctx->engine, GPGME_EVENT_DONE, &err); + } + return 0; +} + + +/* Register the file descriptor FD with the handler FNC (which gets + FNC_DATA as its first argument) for the direction DIR. DATA should + be the context for which the fd is added. R_TAG will hold the tag + that can be used to remove the fd. */ +GpgmeError +_gpgme_wait_user_add_io_cb (void *data, int fd, int dir, GpgmeIOCb fnc, + void *fnc_data, void **r_tag) +{ + GpgmeCtx ctx = (GpgmeCtx) data; + struct tag *tag; + GpgmeError err; + + assert (ctx); + err = _gpgme_add_io_cb (data, fd, dir, fnc, fnc_data, r_tag); + if (err) + return err; + tag = *r_tag; + assert (tag); + err = (*ctx->io_cbs.add) (ctx->io_cbs.add_priv, fd, dir, + _gpgme_user_io_cb_handler, *r_tag, + &tag->user_tag); + if (err) + _gpgme_remove_io_cb (*r_tag); + return err; +} + + +void +_gpgme_wait_user_remove_io_cb (void *data) +{ + struct tag *tag = (struct tag *) data; + GpgmeCtx ctx; + int i; + + assert (tag); + ctx = tag->ctx; + + (*ctx->io_cbs.remove) (tag->user_tag); + _gpgme_remove_io_cb (data); + + for (i = 0; i < ctx->fdt.size; i++) + if (ctx->fdt.fds[i].fd != -1) + break; + if (i == ctx->fdt.size) + { + GpgmeError err = 0; + _gpgme_engine_io_event (ctx->engine, GPGME_EVENT_DONE, &err); + } +} + + +void +_gpgme_wait_user_event_cb (void *data, GpgmeEventIO type, void *type_data) +{ + GpgmeCtx ctx = data; + + if (type == GPGME_EVENT_DONE) + ctx->pending = 0; + + if (ctx->io_cbs.event) + (*ctx->io_cbs.event) (ctx->io_cbs.event_priv, type, type_data); +} diff --git a/gpgme/wait.c b/gpgme/wait.c index 4570913f..daf009b8 100644 --- a/gpgme/wait.c +++ b/gpgme/wait.c @@ -1,26 +1,26 @@ /* wait.c - * Copyright (C) 2000 Werner Koch (dd9jn) - * Copyright (C) 2001, 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 - */ + Copyright (C) 2000 Werner Koch (dd9jn) + Copyright (C) 2001, 2002, 2003 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 GPGME; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#if HAVE_CONFIG_H #include -#include +#endif #include #include #include @@ -35,28 +35,10 @@ #include "io.h" #include "engine.h" -static struct fd_table fdt_global; - -static GpgmeCtx *ctx_done_list; -static int ctx_done_list_size; -static int ctx_done_list_length; -DEFINE_STATIC_LOCK (ctx_done_list_lock); - -static GpgmeIdleFunc idle_function; - -struct wait_item_s -{ - struct wait_item_s *next; - GpgmeIOCb handler; - void *handler_value; - int dir; -}; - void _gpgme_fd_table_init (fd_table_t fdt) { - INIT_LOCK (fdt->lock); fdt->fds = NULL; fdt->size = 0; } @@ -64,19 +46,18 @@ _gpgme_fd_table_init (fd_table_t fdt) void _gpgme_fd_table_deinit (fd_table_t fdt) { - DESTROY_LOCK (fdt->lock); if (fdt->fds) free (fdt->fds); } + /* XXX We should keep a marker and roll over for speed. */ -GpgmeError -_gpgme_fd_table_put (fd_table_t fdt, int fd, int dir, void *opaque, int *idx) +static GpgmeError +fd_table_put (fd_table_t fdt, int fd, int dir, void *opaque, int *idx) { int i, j; struct io_select_fd_s *new_fds; - LOCK (fdt->lock); for (i = 0; i < fdt->size; i++) { if (fdt->fds[i].fd == -1) @@ -88,10 +69,7 @@ _gpgme_fd_table_put (fd_table_t fdt, int fd, int dir, void *opaque, int *idx) new_fds = realloc (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); fdt->fds = new_fds; fdt->size += FDT_ALLOCSIZE; @@ -105,272 +83,76 @@ _gpgme_fd_table_put (fd_table_t fdt, int fd, int dir, void *opaque, int *idx) fdt->fds[i].frozen = 0; fdt->fds[i].signaled = 0; fdt->fds[i].opaque = opaque; - UNLOCK (fdt->lock); *idx = i; return 0; } -/** - * gpgme_register_idle: - * @fnc: Callers idle function - * - * Register a function with GPGME called by GPGME whenever it feels - * that is is idle. NULL may be used to remove this function. - * - * Return value: The idle function pointer that was passed to the - * function at the last time it was invoked, or NULL if the function - * is invoked the first time. - **/ -GpgmeIdleFunc -gpgme_register_idle (GpgmeIdleFunc idle) -{ - GpgmeIdleFunc old_idle = idle_function; - - idle_function = idle; - return old_idle; -} - - -/* Wait on all file descriptors listed in FDT and process them using - the registered callbacks. Returns -1 on error (with errno set), 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, 0); - - if (n <= 0) - { - UNLOCK (fdt->lock); - return n; /* 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 = realloc (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) -{ - DEBUG2 ("waiting... ctx=%p hang=%d", ctx, hang); - do - { - int i; - - /* XXX We are ignoring all errors from select here. */ - do_select (&fdt_global); - - 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 && idle_function) - idle_function (); - } - while (hang && (!ctx || !ctx->cancel)); - - if (ctx && ctx->cancel) - { - /* FIXME: Paranoia? */ - ctx->cancel = 0; - ctx->pending = 0; - ctx->error = mk_error (Canceled); - } - - if (ctx && status) - *status = ctx->error; - return ctx; -} - - +/* Register the file descriptor FD with the handler FNC (which gets + FNC_DATA as its first argument) for the direction DIR. DATA should + be the context for which the fd is added. R_TAG will hold the tag + that can be used to remove the fd. */ GpgmeError -_gpgme_wait_one (GpgmeCtx ctx) -{ - return _gpgme_wait_on_condition (ctx, NULL); -} - - -GpgmeError -_gpgme_wait_on_condition (GpgmeCtx ctx, volatile int *cond) -{ - GpgmeError err = 0; - int hang = 1; - DEBUG1 ("waiting... ctx=%p", ctx); - do - { - if (do_select (&ctx->fdt) < 0) - { - err = mk_error (File_Error); - hang = 0; - } - else if (cond && *cond) - hang = 0; - else - { - int any = 0; - int i; - - LOCK (ctx->fdt.lock); - for (i = 0; i < ctx->fdt.size; i++) - { - if (ctx->fdt.fds[i].fd != -1) - { - any = 1; - break; - } - } - if (!any) - hang = 0; - UNLOCK (ctx->fdt.lock); - } - } - while (hang && !ctx->cancel); - if (!err && ctx->cancel) - { - /* FIXME: Paranoia? */ - ctx->cancel = 0; - ctx->pending = 0; - ctx->error = mk_error (Canceled); - } - return err ? err : ctx->error; -} - - -struct tag -{ - fd_table_t fdt; - int idx; -}; - -GpgmeError -_gpgme_add_io_cb (void *data, int fd, int dir, - GpgmeIOCb fnc, void *fnc_data, void **r_tag) +_gpgme_add_io_cb (void *data, int fd, int dir, GpgmeIOCb fnc, void *fnc_data, + void **r_tag) { GpgmeError err; - fd_table_t fdt = (fd_table_t) (data ? data : &fdt_global); + GpgmeCtx ctx = (GpgmeCtx) data; + fd_table_t fdt; struct wait_item_s *item; struct tag *tag; - assert (fdt); assert (fnc); + assert (ctx); + + fdt = &ctx->fdt; + assert (fdt); - *r_tag = NULL; tag = malloc (sizeof *tag); if (!tag) return mk_error (Out_Of_Core); - tag->fdt = fdt; + tag->ctx = ctx; - /* Allocate a structure to hold info about the handler. */ + /* Allocate a structure to hold information about the handler. */ item = calloc (1, sizeof *item); if (!item) { free (tag); return mk_error (Out_Of_Core); } + item->ctx = ctx; item->dir = dir; item->handler = fnc; item->handler_value = fnc_data; - err = _gpgme_fd_table_put (fdt, fd, dir, item, &tag->idx); + err = fd_table_put (fdt, fd, dir, item, &tag->idx); if (err) { free (tag); free (item); - return mk_error (Out_Of_Core); + return err; } *r_tag = tag; return 0; } + void _gpgme_remove_io_cb (void *data) { struct tag *tag = data; - fd_table_t fdt = tag->fdt; - int idx = tag->idx; + GpgmeCtx ctx; + fd_table_t fdt; + int idx; + + assert (tag); + ctx = tag->ctx; + assert (ctx); + fdt = &ctx->fdt; + assert (fdt); + idx = tag->idx; - LOCK (fdt->lock); DEBUG2 ("setting fd %d (item=%p) done", fdt->fds[idx].fd, fdt->fds[idx].opaque); free (fdt->fds[idx].opaque); @@ -381,6 +163,4 @@ _gpgme_remove_io_cb (void *data) fdt->fds[idx].for_read = 0; fdt->fds[idx].for_write = 0; fdt->fds[idx].opaque = NULL; - UNLOCK (fdt->lock); } - diff --git a/gpgme/wait.h b/gpgme/wait.h index de459cc7..d58dfb3d 100644 --- a/gpgme/wait.h +++ b/gpgme/wait.h @@ -1,23 +1,22 @@ /* wait.h - Definitions for the wait queue interface. - * Copyright (C) 2000 Werner Koch (dd9jn) - * Copyright (C) 2001, 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 - */ + Copyright (C) 2000 Werner Koch (dd9jn) + Copyright (C) 2001, 2002, 2003 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 GPGME; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef WAIT_H #define WAIT_H @@ -27,19 +26,49 @@ struct fd_table { - DECLARE_LOCK (lock); struct io_select_fd_s *fds; size_t size; }; typedef struct fd_table *fd_table_t; +/* Wait items are hooked into the io_select_fd_s to connect an fd with + a callback handler. */ +struct wait_item_s +{ + GpgmeCtx ctx; + GpgmeIOCb handler; + void *handler_value; + int dir; +}; + +/* A registered fd handler is removed later using the tag that + identifies it. */ +struct tag +{ + /* The context for which the fd was registered. */ + GpgmeCtx ctx; + + /* The index into the fd table for this context. */ + int idx; + + /* This is used by the wrappers for the user event loop. */ + void *user_tag; +}; + + void _gpgme_fd_table_init (fd_table_t fdt); void _gpgme_fd_table_deinit (fd_table_t fdt); GpgmeError _gpgme_add_io_cb (void *data, int fd, int dir, GpgmeIOCb fnc, void *fnc_data, void **r_tag); void _gpgme_remove_io_cb (void *tag); -void _gpgme_wait_event_cb (void *data, GpgmeEventIO type, void *type_data); +void _gpgme_wait_private_event_cb (void *data, GpgmeEventIO type, void *type_data); +void _gpgme_wait_global_event_cb (void *data, GpgmeEventIO type, void *type_data); + +GpgmeError _gpgme_wait_user_add_io_cb (void *data, int fd, int dir, + GpgmeIOCb fnc, void *fnc_data, void **r_tag); +void _gpgme_wait_user_remove_io_cb (void *tag); +void _gpgme_wait_user_event_cb (void *data, GpgmeEventIO type, void *type_data); GpgmeError _gpgme_wait_one (GpgmeCtx ctx);