* 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)
+2003-01-29 Marcus Brinkmann <marcus@g10code.de>
+
+ * 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 <marcus@g10code.de>
+
+ * gpgme.texi (Hooking Up Into Idle Time): Section removed.
+
2002-12-24 Marcus Brinkmann <marcus@g10code.de>
* gpgme.texi (Verify): Drop R_STAT argument in gpgme_op_verify.
* 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
* 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
@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.
* 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
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
@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
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
@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
@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
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}})}
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
2003-01-29 Marcus Brinkmann <marcus@g10code.de>
+ * 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 <assert.h>.
+ (_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 <stdio.h>, <string.h> and <assert.h>.
+ (_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 <stdio.h>, <string.h>, <time.h> and
+ <assert.h>.
+ (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 <stdio.h> and <string.h>.
+ (_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 <stdio.h>, <string.h> and <assert.h>.
+ (export_status_handler): Change return type to GpgmeError. Don't
+ check ctx->error.
+ * genkey.c: Do not include <stdio.h> and <assert.h>.
+ (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 <stdio.h>, <string.h> and <assert.h>.
+ (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 <stdio.h>.
+ (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.
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 \
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;
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;
#endif
#include <stdlib.h>
+#include <assert.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
\f
/* 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;
}
#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);
}
#if HAVE_CONFIG_H
#include <config.h>
#endif
-#include <stdio.h>
#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
#include "util.h"
#include "context.h"
}
-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:
}
}
break;
-
default:
- /* Ignore all other codes. */
break;
}
+
+ return 0;
}
_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;
}
-/* delete.c - delete a key
+/* delete.c - Delete a key.
Copyright (C) 2001, 2002 g10 Code GmbH
This file is part of GPGME.
#if HAVE_CONFIG_H
#include <config.h>
#endif
-#include <stdio.h>
#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <assert.h>
#include "util.h"
#include "context.h"
}
-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)
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;
break;
default:
- /* Ignore all other codes. */
break;
}
+ return 0;
}
return err;
}
+
GpgmeError
gpgme_op_delete_start (GpgmeCtx ctx, const GpgmeKey key, int allow_secret)
{
-/* edit.c - key edit functions
+/* edit.c - Key edit functions.
Copyright (C) 2002 g10 Code GmbH
This file is part of GPGME.
#if HAVE_CONFIG_H
#include <config.h>
#endif
-#include <stdio.h>
#include <stdlib.h>
-#include <string.h>
#include <assert.h>
#include "util.h"
free (result);
}
-void
-_gpgme_edit_status_handler (GpgmeCtx ctx, GpgmeStatusCode status, char *args)
-{
- _gpgme_passphrase_status_handler (ctx, status, args);
- if (ctx->error)
- return;
+static GpgmeError
+edit_status_handler (GpgmeCtx ctx, GpgmeStatusCode status, char *args)
+{
+ GpgmeError err = _gpgme_passphrase_status_handler (ctx, status, args);
+ if (err)
+ return err;
- 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)
+
+static GpgmeError
+command_handler (void *opaque, GpgmeStatusCode status, const char *args,
+ const char **result)
{
+ GpgmeError err;
GpgmeCtx ctx = opaque;
- const char *result;
- result = _gpgme_passphrase_command_handler (ctx, status, args);
+ 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,
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);
#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);
}
-/* encrypt.c - encrypt functions
+/* encrypt.c - Encrypt functions.
Copyright (C) 2000 Werner Koch (dd9jn)
Copyright (C) 2001, 2002 g10 Code GmbH
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)
{
}
-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:
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);
}
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)
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);
}
}
-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
< *alinelen + linelen + 1)
{
unsigned char *newline = realloc (*aline,
- *alinelen + linelen + 1);
+ *alinelen + linelen + 1);
if (!newline)
+ err = mk_error (Out_Of_Core);
+ else
{
- _gpgme_io_close (gpgsm->status_cb.fd);
- return;
+ *aline = newline;
+ gpgsm->colon.attic.linesize += linelen + 1;
}
- *aline = newline;
- gpgsm->colon.attic.linesize += linelen + 1;
}
+ if (!err)
+ {
+ dst = *aline + *alinelen;
- 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')
+ while (!err && src < end)
{
- /* 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;
+ 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
- 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 */
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;
}
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;
}
(*engine->ops->set_io_cbs) (engine->engine, io_cbs);
}
+
void
_gpgme_engine_io_event (EngineObject engine,
GpgmeEventIO type, void *type_data)
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,
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);
-/* export.c - encrypt functions
+/* export.c - Encrypt functions.
Copyright (C) 2000 Werner Koch (dd9jn)
Copyright (C) 2001, 2002 g10 Code GmbH
#if HAVE_CONFIG_H
#include <config.h>
#endif
-#include <stdio.h>
#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
#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;
}
#if HAVE_CONFIG_H
#include <config.h>
#endif
-#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <assert.h>
#include "util.h"
#include "context.h"
}
-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)
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;
/* 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;
}
-/* gpgme.c - GnuPG Made Easy
+/* gpgme.c - GnuPG Made Easy.
Copyright (C) 2000 Werner Koch (dd9jn)
Copyright (C) 2001, 2002 g10 Code GmbH
_gpgme_release_edit_result (ctx->result.edit);
memset (&ctx->result, 0, sizeof (ctx->result));
_gpgme_set_op_info (ctx, NULL);
- ctx->error = 0;
}
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);
- }
-}
/* 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,
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;
/* 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. */
-/* import.c - encrypt functions
+/* import.c - Import functions.
Copyright (C) 2000 Werner Koch (dd9jn)
Copyright (C) 2001, 2002 g10 Code GmbH
#if HAVE_CONFIG_H
#include <config.h>
#endif
-#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <assert.h>
#include "util.h"
#include "context.h"
}
-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)
default:
break;
}
+ return 0;
}
}
-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;
break;
default:
- /* Ignore all other codes. */
break;
}
+ return 0;
}
\f
/* Note: We are allowed to modify LINE. */
-static void
+static GpgmeError
keylist_colon_handler (GpgmeCtx ctx, char *line)
{
enum
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)
/* 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);
{
/* 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);
{
/* 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);
{
/* 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);
{
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:
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])
{
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). */
{
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)
/* Unknown record. */
break;
}
+ return 0;
}
if (!q)
{
gpgme_key_release (key);
- ctx->error = mk_error (Out_Of_Core);
+ /* FIXME return mk_error (Out_Of_Core); */
return;
}
q->key = key;
return mk_error (Invalid_Value);
if (!ctx->pending)
return mk_error (No_Request);
- if (ctx->error)
- return ctx->error;
if (!ctx->key_queue)
{
return mk_error (Invalid_Value);
if (!ctx->pending)
return mk_error (No_Request);
- if (ctx->error)
- return ctx->error;
ctx->pending = 0;
return 0;
/* 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 <config.h>
+#endif
#include "gpgme.h"
#include "context.h"
{
/* 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);
/* 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);
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 );
/*-- 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);
/*-- 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);
}
-void
+GpgmeError
_gpgme_passphrase_status_handler (GpgmeCtx ctx, GpgmeStatusCode code, char *args)
{
- if (ctx->error)
- return;
test_and_allocate_result (ctx, passphrase);
switch (code)
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:
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:
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;
{
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)
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"))
{
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)
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;
}
/* 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 <config.h>
#include "context.h"
-void
+GpgmeError
_gpgme_progress_status_handler (GpgmeCtx ctx, GpgmeStatusCode code, char *args)
{
char *p;
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)
ctx->progress_cb (ctx->progress_cb_value, args_cpy, type, current, total);
free (args_cpy);
+ return 0;
}
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)
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)
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;
}
}
}
}
- 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
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;
}
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;
}
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
}
-static void
+static GpgmeError
status_handler (void *opaque, int fd)
{
GpgObject gpg = opaque;
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;
}
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;
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;
}
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;
_gpgme_data_append_string (dh, "</fpr>\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)
_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:
default:
break;
}
+ return 0;
}
static GpgmeError
-/* trustlist.c - key listing
+/* trustlist.c - Trust item listing.
Copyright (C) 2000 Werner Koch (dd9jn)
Copyright (C) 2001, 2002 g10 Code GmbH
}
-static void
+static GpgmeError
trustlist_status_handler (GpgmeCtx ctx, GpgmeStatusCode code, char *args)
{
- if (ctx->error)
- return;
-
switch (code)
{
case GPGME_STATUS_EOF:
default:
break;
}
+ return 0;
}
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)
{
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 */
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;
}
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;
return mk_error (Invalid_Value);
if (!ctx->pending)
return mk_error (No_Request);
- if (ctx->error)
- return ctx->error;
if (!ctx->trust_queue)
{
return mk_error (Invalid_Value);
if (!ctx->pending)
return mk_error (No_Request);
- if (ctx->error)
- return ctx->error;
ctx->pending = 0;
return 0;
* 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 --*/
/* 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;
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, " <notation>\n");
}
_gpgme_data_append_string (dh, " <data>");
_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)
}
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)
{
/* 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
|| 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)
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:
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)
/* Ignore all other codes. */
break;
}
+ return 0;
}
--- /dev/null
+/* 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 <config.h>
+#endif
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+
+#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;
+
+\f
+/* 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;
+}
+
+\f
+/* 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;
+ }
+}
+
+
+\f
+/* 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;
+}
+
+
--- /dev/null
+/* 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 <config.h>
+#endif
+#include <assert.h>
+
+#include "gpgme.h"
+#include "context.h"
+#include "wait.h"
+#include "ops.h"
+#include "io.h"
+#include "util.h"
+
+\f
+/* 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. */
+
+\f
+/* 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;
+ }
+}
+
+\f
+/* 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);
+}
--- /dev/null
+/* 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 <config.h>
+#endif
+#include <assert.h>
+
+#include "gpgme.h"
+#include "context.h"
+#include "io.h"
+#include "wait.h"
+
+\f
+/* The user event loops are used for all asynchronous operations for
+ which a user callback is defined. */
+
+\f
+/* 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);
+}
/* 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 <config.h>
-#include <stdio.h>
+#endif
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#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;
-};
-
\f
void
_gpgme_fd_table_init (fd_table_t fdt)
{
- INIT_LOCK (fdt->lock);
fdt->fds = NULL;
fdt->size = 0;
}
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)
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;
fdt->fds[i].frozen = 0;
fdt->fds[i].signaled = 0;
fdt->fds[i].opaque = opaque;
- UNLOCK (fdt->lock);
*idx = i;
return 0;
}
\f
-/**
- * gpgme_register_idle:
- * @fnc: Callers idle function
- *
- * Register a function with GPGME called by GPGME whenever it feels
- * that is is idle. NULL may be used to remove this function.
- *
- * Return value: The idle function pointer that was passed to the
- * function at the last time it was invoked, or NULL if the function
- * is invoked the first time.
- **/
-GpgmeIdleFunc
-gpgme_register_idle (GpgmeIdleFunc idle)
-{
- GpgmeIdleFunc old_idle = idle_function;
-
- idle_function = idle;
- return old_idle;
-}
-
-\f
-/* 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;
-}
-
-
-\f
-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;
-}
-
-
-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;
-}
-
-\f
-struct tag
-{
- fd_table_t fdt;
- int idx;
-};
-
+/* 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_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);
fdt->fds[idx].for_read = 0;
fdt->fds[idx].for_write = 0;
fdt->fds[idx].opaque = NULL;
- UNLOCK (fdt->lock);
}
-
/* 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
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);